- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
457 lines
9.9 KiB
C++
457 lines
9.9 KiB
C++
//----------------------------------------------------------------------------
|
|
// ObjectWindows
|
|
// (C) Copyright 1993, 1994 by Borland International, All Rights Reserved
|
|
//
|
|
// Implementation of TSlider, slider UI widget abstract base class.
|
|
//----------------------------------------------------------------------------
|
|
#pragma hdrignore SECTION
|
|
#include <owl/owlpch.h>
|
|
#include <owl/slider.h>
|
|
#include <owl/dc.h>
|
|
|
|
#if !defined(SECTION) || SECTION == 1
|
|
|
|
DEFINE_RESPONSE_TABLE1(TSlider, TScrollBar)
|
|
EV_WM_SIZE,
|
|
EV_WM_GETDLGCODE,
|
|
EV_WM_ERASEBKGND,
|
|
EV_WM_PAINT,
|
|
EV_WM_LBUTTONDOWN,
|
|
EV_WM_MOUSEMOVE,
|
|
EV_WM_LBUTTONUP,
|
|
EV_WM_LBUTTONDBLCLK,
|
|
EV_WM_KEYDOWN,
|
|
EV_WM_SETFOCUS,
|
|
EV_WM_KILLFOCUS,
|
|
END_RESPONSE_TABLE;
|
|
|
|
TSize TSlider::MouseOffset;
|
|
TDC* TSlider::SlideDC = 0;
|
|
|
|
//
|
|
// Constructor for a TSlider object
|
|
//
|
|
TSlider::TSlider(TWindow* parent,
|
|
int id,
|
|
int x, int y, int w, int h,
|
|
TResId thumbResId,
|
|
TModule* module)
|
|
:
|
|
TScrollBar(parent, id, x, y, w, h, true, module),
|
|
ThumbResId(thumbResId),
|
|
ThumbRect(0, 0, 9, 20),
|
|
CaretRect(3, 3, 3+3, 3+13)
|
|
{
|
|
SetRange(0, 100);
|
|
Pos = 0;
|
|
ThumbRgn = 0;
|
|
TicGap = Range/10;
|
|
SlotThick = 17;
|
|
Snap = true;
|
|
|
|
Sliding = false;
|
|
|
|
// get slot size from Attr.H set by TScrollBar ?
|
|
|
|
Attr.W = w;
|
|
Attr.H = h;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
TSlider::~TSlider()
|
|
{
|
|
delete ThumbRgn;
|
|
}
|
|
|
|
//
|
|
// Setup slider window
|
|
//
|
|
void
|
|
TSlider::SetupWindow()
|
|
{
|
|
TScrollBar::SetupWindow();
|
|
SetupThumbRgn();
|
|
}
|
|
|
|
//
|
|
// Check & set the slider range
|
|
//
|
|
void
|
|
TSlider::SetRange(int min, int max)
|
|
{
|
|
Min = min;
|
|
Max = max;
|
|
if (Max > Min)
|
|
Range = Max - Min;
|
|
else if (Min > Max)
|
|
Range = Min - Max;
|
|
else
|
|
Range = 1;
|
|
}
|
|
|
|
//
|
|
// Set the position of the thumb
|
|
//
|
|
void
|
|
TSlider::SetPosition(int pos)
|
|
{
|
|
//
|
|
// constrain pos to be in the range "Min .. Max" & snap to tics if enabled
|
|
//
|
|
pos = SnapPos(pos);
|
|
|
|
//
|
|
// Slide thumb to new position, converting pos to pixels
|
|
//
|
|
if (pos != Pos) {
|
|
if (HWindow) {
|
|
TDC* dc = SlideDC ? SlideDC : new TClientDC(HWindow);
|
|
SlideThumb(*dc, pos);
|
|
if (!SlideDC)
|
|
delete dc;
|
|
}
|
|
Pos = pos;
|
|
}
|
|
}
|
|
|
|
//
|
|
// setup region that defines the thumb shape for this slider class.
|
|
// default region is a simple bounding rect, but could be any shape.
|
|
//
|
|
void
|
|
TSlider::SetupThumbRgn()
|
|
{
|
|
if (!ThumbRgn)
|
|
ThumbRgn = new TRegion(ThumbRect);
|
|
}
|
|
|
|
//
|
|
// Slide the thumb & perform necessary blitting & painting.
|
|
// Assumes that Pos, Min & Max are up to date.
|
|
//
|
|
void
|
|
TSlider::SlideThumb(TDC& dc, int pos)
|
|
{
|
|
TPoint point = PosToPoint(pos);
|
|
|
|
HideCaret();
|
|
GetBkColor(dc);
|
|
if (ThumbRgn) {
|
|
TRegion oldRgn(ThumbRect);
|
|
TRect newThumbRect(point, ThumbRect.Size());
|
|
|
|
*ThumbRgn += point-ThumbRect.TopLeft();
|
|
|
|
dc.SelectClipRgn(*ThumbRgn);
|
|
dc.BitBlt(newThumbRect, dc, ThumbRect.TopLeft());
|
|
|
|
ThumbRect = newThumbRect;
|
|
|
|
oldRgn -= *ThumbRgn;
|
|
dc.SelectClipRgn(oldRgn);
|
|
PaintSlot(dc);
|
|
}
|
|
else {
|
|
ThumbRect = TRect(point, ThumbRect.Size());
|
|
PaintSlot(dc);
|
|
PaintThumb(dc);
|
|
}
|
|
SetCaretPos(ThumbRect.left+CaretRect.left, ThumbRect.top+CaretRect.top);
|
|
ShowCaret();
|
|
}
|
|
|
|
//
|
|
// Paint the thumb itself using a resource DIB translated to the current system
|
|
// button colors. Overlaps the slot.
|
|
//
|
|
void
|
|
TSlider::PaintThumb(TDC& dc)
|
|
{
|
|
TDib thumbDib(*GetModule(), ThumbResId);
|
|
thumbDib.MapUIColors(
|
|
TDib::MapFace|TDib::MapText|TDib::MapShadow|TDib::MapHighlight,
|
|
&dc.GetBkColor()
|
|
);
|
|
int dibX = (Sliding || !IsWindowEnabled()) ? thumbDib.Width()/2 : 0;
|
|
dc.SetDIBitsToDevice(ThumbRect, TPoint(dibX, 0), thumbDib);
|
|
}
|
|
|
|
//
|
|
// Constrain pos to be in the range "Min .. Max" &
|
|
// perform 'Snap'ing if enabled by rounding pos to nearest TicGap
|
|
//
|
|
int
|
|
TSlider::SnapPos(int pos)
|
|
{
|
|
if (pos > Max)
|
|
pos = Max;
|
|
|
|
else if (pos < Min)
|
|
pos = Min;
|
|
|
|
return Snap ? (((pos-Min)+TicGap/2)/TicGap)*TicGap + Min : pos;
|
|
}
|
|
|
|
//
|
|
// Get & release a brush obtained from our parent window for use in painting
|
|
// background areas in this control.
|
|
//
|
|
void
|
|
TSlider::GetBkColor(TDC& dc)
|
|
{
|
|
#if defined(BI_PLAT_WIN32)
|
|
Parent->HandleMessage(WM_CTLCOLORSTATIC,
|
|
(WPARAM)(HDC)dc,
|
|
LPARAM(HWindow));
|
|
#else
|
|
Parent->HandleMessage(WM_CTLCOLOR,
|
|
(WPARAM)(HDC)dc,
|
|
MAKELPARAM(HWindow, CTLCOLOR_STATIC));
|
|
#endif
|
|
BkColor = dc.GetBkColor();
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void
|
|
TSlider::EvSize(uint sizeType, TSize& size)
|
|
{
|
|
TScrollBar::EvSize(sizeType, size);
|
|
}
|
|
|
|
//
|
|
// Make sure we get cursor movement keys to move the thumb
|
|
//
|
|
uint
|
|
TSlider::EvGetDlgCode(MSG far*)
|
|
{
|
|
return DLGC_WANTARROWS;
|
|
}
|
|
|
|
//
|
|
// Paint the whole slider: ruler, slot & thumb
|
|
//
|
|
void
|
|
TSlider::EvPaint()
|
|
{
|
|
HideCaret();
|
|
if (ThumbRgn) { // use thumb region if avalable
|
|
TRegion updateRgn;
|
|
GetUpdateRgn(updateRgn);
|
|
|
|
TPaintDC dc(*this);
|
|
|
|
GetBkColor(dc);
|
|
|
|
TRegion thumbClip = *ThumbRgn; // set clip to intersect of update & thumb
|
|
thumbClip &= updateRgn;
|
|
dc.SelectClipRgn(thumbClip);
|
|
PaintThumb(dc);
|
|
|
|
updateRgn -= thumbClip;
|
|
dc.SelectClipRgn(updateRgn); // set clip to update minus thumb
|
|
ValidateRgn(*ThumbRgn);
|
|
PaintSlot(dc);
|
|
PaintRuler(dc);
|
|
}
|
|
else { // no region, thumb will flicker a little
|
|
TPaintDC dc(*this);
|
|
|
|
GetBkColor(dc);
|
|
PaintSlot(dc);
|
|
PaintRuler(dc);
|
|
PaintThumb(dc);
|
|
}
|
|
ShowCaret();
|
|
}
|
|
|
|
//
|
|
// We'll always erase as we paint to avoid flicker
|
|
//
|
|
bool
|
|
TSlider::EvEraseBkgnd(HDC)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// If a button down on the thumb, then enter sliding state.
|
|
// If in the slot, pg up or down. If on the ruler, jump there.
|
|
//
|
|
void
|
|
TSlider::EvLButtonDown(uint /*modKeys*/, TPoint& point)
|
|
{
|
|
if (GetFocus() != HWindow)
|
|
SetFocus();
|
|
|
|
int scrollCode = HitTest(point);
|
|
switch (scrollCode) {
|
|
case SB_THUMBPOSITION:
|
|
NotifyParent(scrollCode, SnapPos(PointToPos(point)));
|
|
break;
|
|
|
|
case SB_LINEUP:
|
|
case SB_LINEDOWN:
|
|
case SB_PAGEUP:
|
|
case SB_PAGEDOWN:
|
|
NotifyParent(scrollCode);
|
|
break;
|
|
|
|
case SB_THUMBTRACK: {
|
|
Sliding = true;
|
|
SetCapture();
|
|
HideCaret();
|
|
SlideDC = new TClientDC(HWindow); // keep this dc around while sliding
|
|
|
|
GetBkColor(*SlideDC); // repaint thumb in pressed state
|
|
PaintThumb(*SlideDC);
|
|
|
|
MouseOffset = point-ThumbRect.TopLeft();
|
|
point -= MouseOffset;
|
|
int pos = SnapPos(PointToPos(point));// keep thumb on track & on pos units
|
|
NotifyParent(9, pos); // undocumented 'begin track' code
|
|
NotifyParent(SB_THUMBTRACK, pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If sliding then either slide thumb, or detect a lost button up & simulate
|
|
// it.
|
|
//
|
|
void
|
|
TSlider::EvMouseMove(uint modKeys, TPoint& point)
|
|
{
|
|
if (Sliding && SlideDC) {
|
|
if (!(modKeys&MK_LBUTTON)) {
|
|
EvLButtonUp(modKeys, point); // we missed a lbutton up somehow...
|
|
return;
|
|
}
|
|
// keep thumb on track & on pos units
|
|
NotifyParent(SB_THUMBTRACK, SnapPos(PointToPos(point - MouseOffset)));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle button messages if we are sliding by releasing capture & ending
|
|
// sliding state
|
|
//
|
|
void
|
|
TSlider::EvLButtonUp(uint /*modKeys*/, TPoint& point)
|
|
{
|
|
int pos = SnapPos(PointToPos(point - MouseOffset));
|
|
if (Sliding) {
|
|
Sliding = false;
|
|
NotifyParent(SB_THUMBPOSITION, pos);
|
|
|
|
GetBkColor(*SlideDC); // repaint thumb in released state
|
|
if (ThumbRgn)
|
|
SlideDC->SelectClipRgn(*ThumbRgn);
|
|
PaintThumb(*SlideDC);
|
|
|
|
ReleaseCapture();
|
|
delete SlideDC;
|
|
SlideDC = 0;
|
|
|
|
ShowCaret();
|
|
}
|
|
NotifyParent(SB_ENDSCROLL, pos);
|
|
}
|
|
|
|
//
|
|
// Catch double clicks and eat them
|
|
//
|
|
void
|
|
TSlider::EvLButtonDblClk(uint /*modKeys*/, TPoint&)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Translate key messages to scroll events w/ repeat.
|
|
//
|
|
void
|
|
TSlider::EvKeyDown(uint key, uint repeatCount, uint /*flags*/)
|
|
{
|
|
static int KeyToCode[] = {
|
|
SB_PAGEUP, // VK_PRIOR
|
|
SB_PAGEDOWN, // VK_NEXT
|
|
SB_BOTTOM, // VK_END
|
|
SB_TOP, // VK_HOME
|
|
SB_LINEUP, // VK_LEFT(same as SB_LINELEFT)
|
|
SB_LINEUP, // VK_UP
|
|
SB_LINEDOWN, // VK_RIGHT(same as SB_LINERIGHT)
|
|
SB_LINEDOWN // VK_DOWN
|
|
};
|
|
|
|
if (key >= VK_PRIOR && key <= VK_DOWN) {
|
|
for (int i = 0; i < repeatCount; i++)
|
|
NotifyParent(KeyToCode[key-VK_PRIOR], Pos);
|
|
NotifyParent(SB_ENDSCROLL, Pos);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create, position & show a caret when we have focus. Remove it when we lose
|
|
// focus
|
|
//
|
|
void
|
|
TSlider::EvSetFocus(HWND /*hWndLostFocus*/)
|
|
{
|
|
CreateCaret(true, CaretRect.Width(), CaretRect.Height());
|
|
SetCaretPos(ThumbRect.left+CaretRect.left, ThumbRect.top+CaretRect.top);
|
|
ShowCaret();
|
|
|
|
// TScrollBar::EvSetFocus(hWndLostFocus); // Can't let SCROLLBAR see this
|
|
}
|
|
|
|
void
|
|
TSlider::EvKillFocus(HWND hWndGetFocus)
|
|
{
|
|
HideCaret();
|
|
DestroyCaret();
|
|
|
|
TScrollBar::EvKillFocus(hWndGetFocus); // need to let TWindow do focus save
|
|
}
|
|
|
|
#endif
|
|
#if !defined(SECTION) || SECTION == 2
|
|
|
|
IMPLEMENT_ABSTRACT_STREAMABLE1(TSlider, TScrollBar);
|
|
|
|
void*
|
|
TSlider::Streamer::Read(ipstream& is, uint32 /*version*/) const
|
|
{
|
|
TSlider* o = GetObject();
|
|
ReadBaseObject((TScrollBar*)o, is);
|
|
is >> o->Min
|
|
>> o->Max
|
|
>> o->Pos
|
|
>> o->ThumbResId
|
|
>> o->ThumbRect
|
|
>> o->TicGap
|
|
>> o->CaretRect
|
|
>> o->Snap;
|
|
o->SetRange(o->Min, o->Max); // let it calculate Range
|
|
return o;
|
|
}
|
|
|
|
void
|
|
TSlider::Streamer::Write(opstream& os) const
|
|
{
|
|
TSlider* o = GetObject();
|
|
WriteBaseObject((TScrollBar*)o, os);
|
|
os << o->Min
|
|
<< o->Max
|
|
<< o->Pos
|
|
<< o->ThumbResId
|
|
<< o->ThumbRect
|
|
<< o->CaretRect
|
|
<< o->TicGap
|
|
<< o->Snap;
|
|
}
|
|
|
|
#endif
|