- 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>
745 lines
17 KiB
C++
745 lines
17 KiB
C++
//----------------------------------------------------------------------------
|
|
// ObjectWindows
|
|
// (C) Copyright 1992, 1994 by Borland International, All Rights Reserved
|
|
//
|
|
// Implementation of class TGadgetWindow.
|
|
//----------------------------------------------------------------------------
|
|
#include <owl/owlpch.h>
|
|
#include <owl/gadget.h>
|
|
#include <owl/gadgetwi.h>
|
|
|
|
DEFINE_RESPONSE_TABLE1(TGadgetWindow, TWindow)
|
|
EV_WM_CTLCOLOR,
|
|
EV_WM_LBUTTONDOWN,
|
|
EV_WM_LBUTTONUP,
|
|
EV_WM_LBUTTONDBLCLK,
|
|
EV_WM_MOUSEMOVE,
|
|
EV_WM_SIZE,
|
|
EV_WM_SYSCOLORCHANGE,
|
|
END_RESPONSE_TABLE;
|
|
|
|
static inline int HeightInPixels(int pointSize)
|
|
{
|
|
TScreenDC dc;
|
|
return MulDiv(-pointSize, dc.GetDeviceCaps(LOGPIXELSY), 72);
|
|
}
|
|
|
|
TGadgetWindowFont::TGadgetWindowFont(int pointSize, bool bold, bool italic)
|
|
:
|
|
TFont("MS Sans Serif", HeightInPixels(pointSize), 0, 0, 0,
|
|
bold ? FW_BOLD : FW_NORMAL,
|
|
uint8(VARIABLE_PITCH | FF_SWISS), uint8(italic))
|
|
{
|
|
}
|
|
|
|
TGadgetWindow::TGadgetWindow(TWindow* parent,
|
|
TTileDirection direction,
|
|
TFont* font,
|
|
TModule* module)
|
|
:
|
|
TWindow(parent, 0, module)
|
|
{
|
|
PRECONDITION(font);
|
|
|
|
Attr.Style |= WS_BORDER;
|
|
Capture = 0;
|
|
AtMouse = 0;
|
|
Font = font;
|
|
Direction = direction;
|
|
if (Direction == Horizontal) {
|
|
ShrinkWrapWidth = false;
|
|
ShrinkWrapHeight = true;
|
|
}
|
|
else {
|
|
ShrinkWrapWidth = true;
|
|
ShrinkWrapHeight = false;
|
|
}
|
|
HintMode = PressHints;
|
|
|
|
WideAsPossible = 0; // number of gadgets with "WideAsPossible" set
|
|
DirtyLayout = true;
|
|
Gadgets = 0;
|
|
NumGadgets = 0;
|
|
|
|
//
|
|
// compute the font height
|
|
//
|
|
TScreenDC dc;
|
|
TEXTMETRIC metrics;
|
|
|
|
dc.SelectObject(*Font);
|
|
dc.GetTextMetrics(metrics);
|
|
FontHeight = metrics.tmHeight + metrics.tmExternalLeading;
|
|
|
|
//
|
|
// choose a default height based on the height of the font plus room
|
|
// for a top and bottom border
|
|
//
|
|
Attr.H = FontHeight;
|
|
|
|
if (Attr.Style & WS_BORDER)
|
|
Attr.H += 2 * GetSystemMetrics(SM_CYBORDER);
|
|
|
|
SetBkgndColor(GetSysColor(COLOR_BTNFACE));
|
|
BkgndBrush = new TBrush(GetSysColor(COLOR_BTNFACE));
|
|
}
|
|
|
|
TGadgetWindow::~TGadgetWindow()
|
|
{
|
|
TGadget* gadget = Gadgets;
|
|
|
|
while (gadget) {
|
|
TGadget* tmp = gadget;
|
|
|
|
gadget = gadget->Next;
|
|
delete tmp;
|
|
}
|
|
|
|
delete Font;
|
|
delete BkgndBrush;
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::EvSysColorChange()
|
|
{
|
|
for (TGadget* g = Gadgets; g; g = g->NextGadget())
|
|
g->SysColorChange();
|
|
SetBkgndColor(GetSysColor(COLOR_BTNFACE));
|
|
delete BkgndBrush;
|
|
BkgndBrush = new TBrush(GetSysColor(COLOR_BTNFACE));
|
|
}
|
|
|
|
bool
|
|
TGadgetWindow::IdleAction(long idleCount)
|
|
{
|
|
if (idleCount == 0) {
|
|
// See if we missed a mouse move & still need to send a MouseLeave to a
|
|
// gadget
|
|
//
|
|
if (AtMouse) {
|
|
TPoint crsPoint;
|
|
GetCursorPos(crsPoint);
|
|
if (WindowFromPoint(crsPoint) != HWindow)
|
|
HandleMessage(WM_MOUSEMOVE, 0, MAKELPARAM(-1,-1)); // nowhere
|
|
}
|
|
|
|
// Let the gadgets do command enabling if they need to
|
|
//
|
|
for (TGadget* g = Gadgets; g; g = g->NextGadget())
|
|
g->CommandEnable();
|
|
}
|
|
return TWindow::IdleAction(idleCount);
|
|
}
|
|
|
|
TGadget*
|
|
TGadgetWindow::GadgetWithId(int id) const
|
|
{
|
|
for (TGadget* g = Gadgets; g; g = g->NextGadget())
|
|
if (g->GetId() == id)
|
|
return g;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::SetShrinkWrap(bool shrinkWrapWidth, bool shrinkWrapHeight)
|
|
{
|
|
ShrinkWrapWidth = shrinkWrapWidth;
|
|
ShrinkWrapHeight = shrinkWrapHeight;
|
|
}
|
|
|
|
bool
|
|
TGadgetWindow::GadgetSetCapture(TGadget& gadget)
|
|
{
|
|
if (Capture) {
|
|
return false;
|
|
}
|
|
else {
|
|
Capture = &gadget;
|
|
SetCapture();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::GadgetReleaseCapture(TGadget& gadget)
|
|
{
|
|
if (&gadget == Capture) {
|
|
Capture = 0;
|
|
ReleaseCapture();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Simulate menu select & idle messages to our parent so that it can display
|
|
// hint text the same way it does for menu commands
|
|
//
|
|
void
|
|
TGadgetWindow::SetHintCommand(int id)
|
|
{
|
|
if (Parent) {
|
|
if (id > 0)
|
|
Parent->HandleMessage(WM_MENUSELECT, id, 0);
|
|
|
|
else
|
|
// Send a menuselect w/ flags==0xFFFF and hMenu==0 to indicate end
|
|
//
|
|
#if defined(BI_PLAT_WIN32)
|
|
Parent->HandleMessage(WM_MENUSELECT, 0xFFFF0000, 0); // flags+item, hmenu
|
|
#else
|
|
Parent->HandleMessage(WM_MENUSELECT, 0, 0x0000FFFFL);// item, hmenu+flags
|
|
#endif
|
|
|
|
Parent->HandleMessage(WM_ENTERIDLE, MSGF_MENU);
|
|
}
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::SetMargins(TMargins& margins)
|
|
{
|
|
Margins = margins;
|
|
LayoutSession();
|
|
}
|
|
|
|
int
|
|
TGadgetWindow::LayoutUnitsToPixels(int units)
|
|
{
|
|
const long UnitsPerEM = 8;
|
|
|
|
return int((long(units) * FontHeight + UnitsPerEM / 2) / UnitsPerEM);
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::GetMargins(TMargins& margins,
|
|
int& left, int& right, int& top, int& bottom)
|
|
{
|
|
switch (margins.Units) {
|
|
case TMargins::Pixels:
|
|
left = margins.Left;
|
|
top = margins.Top;
|
|
right = margins.Right;
|
|
bottom = margins.Bottom;
|
|
break;
|
|
|
|
case TMargins::LayoutUnits:
|
|
left = LayoutUnitsToPixels(margins.Left);
|
|
top = LayoutUnitsToPixels(margins.Top);
|
|
right = LayoutUnitsToPixels(margins.Right);
|
|
bottom = LayoutUnitsToPixels(margins.Bottom);
|
|
break;
|
|
|
|
case TMargins::BorderUnits:
|
|
int cxBorder = GetSystemMetrics(SM_CXBORDER);
|
|
int cyBorder = GetSystemMetrics(SM_CYBORDER);
|
|
|
|
left = margins.Left * cxBorder;
|
|
top = margins.Top * cyBorder;
|
|
right = margins.Right * cxBorder;
|
|
bottom = margins.Bottom * cyBorder;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::LayoutSession()
|
|
{
|
|
if (HWindow)
|
|
InvalidateRect(TileGadgets());
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::GetDesiredSize(TSize& size)
|
|
{
|
|
int left, right, top, bottom;
|
|
int maxWidth = 0, maxHeight = 0;
|
|
TGadget* lastGadget = 0;
|
|
|
|
GetMargins(Margins, left, right, top, bottom);
|
|
|
|
if (ShrinkWrapWidth || ShrinkWrapHeight) {
|
|
for (TGadget* gadget = Gadgets; gadget; gadget = gadget->Next) {
|
|
TSize size;
|
|
|
|
gadget->GetDesiredSize(size);
|
|
|
|
if (size.cx > maxWidth)
|
|
maxWidth = size.cx;
|
|
|
|
if (size.cy > maxHeight)
|
|
maxHeight = size.cy;
|
|
}
|
|
|
|
//
|
|
// in some cases we need to actually tile the gadgets in order to tell how
|
|
// much room is needed
|
|
//
|
|
if (Direction == Horizontal && ShrinkWrapWidth ||
|
|
Direction == Vertical && ShrinkWrapHeight) {
|
|
TileGadgets();
|
|
|
|
for (lastGadget = Gadgets; lastGadget && lastGadget->Next; lastGadget = lastGadget->Next)
|
|
;
|
|
}
|
|
}
|
|
|
|
if (!ShrinkWrapWidth)
|
|
size.cx = Attr.W;
|
|
|
|
else if (Direction == Horizontal) {
|
|
size.cx = right;
|
|
|
|
if (lastGadget)
|
|
size.cx += lastGadget->GetBounds().right;
|
|
}
|
|
else {
|
|
size.cx = left + right + maxWidth;
|
|
|
|
if (Attr.Style & WS_BORDER)
|
|
size.cx += 2 * GetSystemMetrics(SM_CXBORDER);
|
|
}
|
|
|
|
if (!ShrinkWrapHeight)
|
|
size.cy = Attr.H;
|
|
|
|
else if (Direction == Vertical) {
|
|
size.cx = bottom;
|
|
|
|
if (lastGadget)
|
|
size.cx += lastGadget->GetBounds().bottom;
|
|
}
|
|
else {
|
|
size.cy = top + bottom + maxHeight;
|
|
|
|
if (Attr.Style & WS_BORDER)
|
|
size.cy += 2 * GetSystemMetrics(SM_CYBORDER);
|
|
}
|
|
}
|
|
|
|
bool
|
|
TGadgetWindow::Create()
|
|
{
|
|
TSize size;
|
|
|
|
GetDesiredSize(size);
|
|
|
|
if (ShrinkWrapWidth)
|
|
Attr.W = size.cx;
|
|
|
|
if (ShrinkWrapHeight)
|
|
Attr.H = size.cy;
|
|
|
|
bool r = TWindow::Create();
|
|
|
|
GetDesiredSize(size);
|
|
if ((ShrinkWrapWidth && Attr.W != size.cx) || (ShrinkWrapHeight && Attr.H != size.cy)) {
|
|
if (ShrinkWrapWidth)
|
|
Attr.W = size.cx;
|
|
|
|
if (ShrinkWrapHeight)
|
|
Attr.H = size.cy;
|
|
|
|
LayoutSession();
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
//
|
|
// Set direction, & default shrink wrap flags. If already created, then also
|
|
// adjust shrink wrap dimension & re-layout
|
|
//
|
|
void
|
|
TGadgetWindow::SetDirection(TTileDirection direction)
|
|
{
|
|
if (Direction != direction) {
|
|
Direction = direction;
|
|
if (Direction == Horizontal) {
|
|
ShrinkWrapWidth = false;
|
|
ShrinkWrapHeight = true;
|
|
}
|
|
else {
|
|
ShrinkWrapWidth = true;
|
|
ShrinkWrapHeight = false;
|
|
}
|
|
//
|
|
// Swap margin's X & Y axis
|
|
//
|
|
int t = Margins.Left; Margins.Left = Margins.Top; Margins.Top = t;
|
|
t = Margins.Right; Margins.Right = Margins.Bottom; Margins.Bottom = t;
|
|
|
|
if (HWindow) {
|
|
TSize size;
|
|
GetDesiredSize(size);
|
|
|
|
if (ShrinkWrapWidth)
|
|
Attr.W = size.cx;
|
|
|
|
if (ShrinkWrapHeight)
|
|
Attr.H = size.cy;
|
|
|
|
LayoutSession();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::GetInnerRect(TRect& rect)
|
|
{
|
|
int left, right, top, bottom;
|
|
GetMargins(Margins, left, right, top, bottom);
|
|
|
|
rect.left = left;
|
|
rect.right = Attr.W - right;
|
|
rect.top = top;
|
|
rect.bottom = Attr.H - bottom;
|
|
|
|
if (Attr.Style & WS_BORDER) {
|
|
rect.right -= 2 * GetSystemMetrics(SM_CYBORDER);
|
|
rect.bottom -= 2 * GetSystemMetrics(SM_CXBORDER);
|
|
}
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::PositionGadget(TGadget*, TGadget*, TPoint&)
|
|
{
|
|
}
|
|
|
|
TRect
|
|
TGadgetWindow::TileHorizontally()
|
|
{
|
|
TRect innerRect;
|
|
TRect invalidRect;
|
|
int width = 0;
|
|
int x;
|
|
|
|
GetInnerRect(innerRect);
|
|
invalidRect.SetEmpty();
|
|
|
|
//
|
|
// first pass tally the width of all gadgets that don't have "WideAsPossible"
|
|
// set
|
|
//
|
|
// NOTE: we must also take into account any adjustments to the gadget spacing
|
|
//
|
|
for (TGadget* gadget = Gadgets; gadget; gadget = gadget->Next) {
|
|
if (!gadget->WideAsPossible) {
|
|
TSize desiredSize;
|
|
|
|
gadget->GetDesiredSize(desiredSize);
|
|
width += desiredSize.cx;
|
|
}
|
|
|
|
if (gadget->Next) {
|
|
TPoint spacing(0, 0);
|
|
|
|
PositionGadget(gadget, gadget->Next, spacing);
|
|
width += spacing.x;
|
|
}
|
|
}
|
|
|
|
//
|
|
// now tile all the gadgets
|
|
//
|
|
x = innerRect.left;
|
|
for (gadget = Gadgets; gadget; gadget = gadget->Next) {
|
|
TRect bounds = gadget->Bounds;
|
|
TRect originalBounds(bounds);
|
|
TSize desiredSize;
|
|
|
|
bounds.left = x;
|
|
gadget->GetDesiredSize(desiredSize);
|
|
bounds.top = innerRect.top + (innerRect.Height() - desiredSize.cy) / 2;
|
|
bounds.bottom = bounds.top + desiredSize.cy;
|
|
|
|
if (gadget->WideAsPossible)
|
|
bounds.right = bounds.left + (innerRect.Width() - width) / WideAsPossible;
|
|
|
|
else
|
|
bounds.right = bounds.left + desiredSize.cx;
|
|
|
|
if (bounds != originalBounds) {
|
|
gadget->SetBounds(bounds);
|
|
invalidRect |= bounds;
|
|
|
|
if (originalBounds.TopLeft() != TPoint(0, 0))
|
|
invalidRect |= originalBounds;
|
|
}
|
|
x += bounds.Width();
|
|
|
|
if (gadget->Next) {
|
|
TPoint origin(x, 0);
|
|
|
|
PositionGadget(gadget, gadget->Next, origin);
|
|
x = origin.x;
|
|
}
|
|
}
|
|
return invalidRect;
|
|
}
|
|
|
|
TRect
|
|
TGadgetWindow::TileVertically()
|
|
{
|
|
TRect innerRect;
|
|
TRect invalidRect;
|
|
int y;
|
|
|
|
GetInnerRect(innerRect);
|
|
invalidRect.SetEmpty();
|
|
|
|
//
|
|
// now tile all the gadgets
|
|
//
|
|
y = innerRect.top;
|
|
for (TGadget* gadget = Gadgets; gadget; gadget = gadget->Next) {
|
|
TRect bounds = gadget->Bounds;
|
|
TRect originalBounds(bounds);
|
|
TSize desiredSize;
|
|
|
|
gadget->GetDesiredSize(desiredSize);
|
|
bounds.top = y;
|
|
bounds.bottom = bounds.top + desiredSize.cy;
|
|
bounds.left = innerRect.left + (innerRect.Width() - desiredSize.cx) / 2;
|
|
bounds.right = bounds.left + desiredSize.cx;
|
|
|
|
if (bounds != originalBounds) {
|
|
gadget->SetBounds(bounds);
|
|
invalidRect |= bounds;
|
|
|
|
if (originalBounds.TopLeft () != TPoint (0, 0))
|
|
invalidRect |= originalBounds;
|
|
}
|
|
|
|
y += bounds.Height();
|
|
|
|
if (gadget->Next) {
|
|
TPoint origin(0, y);
|
|
|
|
PositionGadget(gadget, gadget->Next, origin);
|
|
y = origin.y;
|
|
}
|
|
}
|
|
return invalidRect;
|
|
}
|
|
|
|
TRect
|
|
TGadgetWindow::TileGadgets()
|
|
{
|
|
return (Direction == Horizontal) ? TileHorizontally() : TileVertically();
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::GadgetChangedSize(TGadget&)
|
|
{
|
|
LayoutSession();
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::Insert(TGadget& gadget, TPlacement placement, TGadget* sibling)
|
|
{
|
|
PRECONDITION(!gadget.Window);
|
|
|
|
TGadget** g = &Gadgets;
|
|
|
|
if (sibling || placement == After) {
|
|
while (*g && *g != sibling)
|
|
g = &(*g)->Next;
|
|
|
|
CHECK(*g == sibling);
|
|
}
|
|
|
|
if (placement == After && *g)
|
|
g = &(*g)->Next;
|
|
|
|
gadget.Next = *g;
|
|
*g = &gadget;
|
|
|
|
gadget.Window = this;
|
|
NumGadgets++;
|
|
gadget.Inserted();
|
|
|
|
if (gadget.WideAsPossible)
|
|
WideAsPossible++;
|
|
}
|
|
|
|
//
|
|
// remove a gadget from the gadget window's list
|
|
//
|
|
TGadget*
|
|
TGadgetWindow::Remove(TGadget& gadget)
|
|
{
|
|
if (gadget.Window != this || !Gadgets)
|
|
return 0;
|
|
|
|
//
|
|
// handle head-of-list case
|
|
//
|
|
if (&gadget == Gadgets) {
|
|
Gadgets = Gadgets->Next;
|
|
}
|
|
//
|
|
// scan for gadget, looking one link ahead
|
|
//
|
|
else {
|
|
TGadget* g = Gadgets;
|
|
|
|
while (g->Next && g->Next != &gadget)
|
|
g = g->Next;
|
|
|
|
if (!g->Next) // not found
|
|
return 0;
|
|
|
|
g->Next = g->Next->Next;
|
|
}
|
|
|
|
NumGadgets--;
|
|
|
|
//
|
|
// re-adjust gadget now that it doesn't live in a window
|
|
//
|
|
if (gadget.WideAsPossible)
|
|
WideAsPossible--;
|
|
if (&gadget == AtMouse)
|
|
AtMouse = 0;
|
|
GadgetReleaseCapture(gadget);
|
|
gadget.Removed();
|
|
gadget.Window = 0;
|
|
gadget.Next = 0;
|
|
gadget.GetBounds() -= gadget.GetBounds().TopLeft();
|
|
|
|
return &gadget;
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::EvSize(uint sizeType, TSize& size)
|
|
{
|
|
TWindow::EvSize(sizeType, size);
|
|
|
|
if (DirtyLayout || WideAsPossible > 0) {
|
|
DirtyLayout = false;
|
|
TileGadgets();
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Iterate thru the gadget list and paint each one.
|
|
//
|
|
void
|
|
TGadgetWindow::PaintGadgets(TDC& dc, bool, TRect& rect)
|
|
{
|
|
TPoint viewport = dc.GetViewportOrg();
|
|
for (TGadget* gadget = Gadgets; gadget; gadget = gadget->Next) {
|
|
if (gadget->Bounds.Touches(rect)) {
|
|
dc.SetViewportOrg((TPoint&)gadget->Bounds);
|
|
|
|
if (gadget->Clip) {
|
|
dc.SaveDC();
|
|
dc.IntersectClipRect(gadget->Bounds);
|
|
}
|
|
|
|
gadget->Paint(dc);
|
|
|
|
if (gadget->Clip)
|
|
dc.RestoreDC();
|
|
}
|
|
}
|
|
dc.SetViewportOrg(viewport);
|
|
}
|
|
|
|
void
|
|
TGadgetWindow::Paint(TDC& dc, bool erase, TRect& rect)
|
|
{
|
|
dc.SelectObject(*Font);
|
|
PaintGadgets(dc, erase, rect);
|
|
}
|
|
|
|
//
|
|
// Return gadget that a given window-relative point is in, 0 if none
|
|
//
|
|
TGadget*
|
|
TGadgetWindow::GadgetFromPoint(TPoint& point) const
|
|
{
|
|
for (TGadget* gadget = Gadgets; gadget; gadget = gadget->Next)
|
|
if (gadget->PtIn(point - *(TSize*)&gadget->Bounds.TopLeft()))
|
|
break;
|
|
|
|
return gadget;
|
|
}
|
|
|
|
HBRUSH
|
|
TGadgetWindow::EvCtlColor(HDC hDC, HWND /*hWndChild*/, uint /*ctlType*/)
|
|
{
|
|
::SetBkColor(hDC, BkgndColor);
|
|
return HBRUSH(*BkgndBrush);
|
|
}
|
|
|
|
//
|
|
// Determine if the mouse down is in an enabled gadget, & if so pass it to
|
|
// the gadget.
|
|
//
|
|
void
|
|
TGadgetWindow::EvLButtonDown(uint modKeys, TPoint& point)
|
|
{
|
|
TGadget* gadget = Capture ? Capture : GadgetFromPoint(point);
|
|
|
|
if (gadget && (gadget->GetEnabled() || Capture))
|
|
gadget->LButtonDown(modKeys, point - *(TSize*)&gadget->Bounds.TopLeft());
|
|
|
|
TWindow::EvLButtonDown(modKeys, point);
|
|
}
|
|
|
|
//
|
|
// Forward mouse ups to the gadget that has captures the mouse, if any, or
|
|
// to the gadget at the mouse pos
|
|
//
|
|
void
|
|
TGadgetWindow::EvLButtonUp(uint modKeys, TPoint& point)
|
|
{
|
|
TGadget* gadget = Capture ? Capture : GadgetFromPoint(point);
|
|
|
|
if (gadget && (gadget->GetEnabled() || Capture))
|
|
gadget->LButtonUp(modKeys, TPoint(point.x - gadget->Bounds.left,
|
|
point.y - gadget->Bounds.top));
|
|
TWindow::EvLButtonUp(modKeys, point);
|
|
}
|
|
|
|
//
|
|
// Pass double clicks thru as if they were just a second click, finish the
|
|
// first click, & begin the second. Dn + Dbl + Up -> Dn + Up+Dn + Up
|
|
//
|
|
void
|
|
TGadgetWindow::EvLButtonDblClk(uint modKeys, TPoint& point)
|
|
{
|
|
EvLButtonUp(modKeys, point);
|
|
EvLButtonDown(modKeys, point);
|
|
}
|
|
|
|
//
|
|
// Forward mouse moves to the gadget that has captures the mouse, if any.
|
|
// Otherwise checks for mouse entering & leaving gadgets
|
|
//
|
|
// Could enhance this by delaying mouse enter messages until mouse has been
|
|
// in the same area for a while, or looking ahead in queue for mouse msgs.
|
|
//
|
|
void
|
|
TGadgetWindow::EvMouseMove(uint modKeys, TPoint& point)
|
|
{
|
|
if (Capture) {
|
|
Capture->MouseMove(modKeys, TPoint(point.x - Capture->Bounds.left,
|
|
point.y - Capture->Bounds.top));
|
|
}
|
|
else {
|
|
TGadget* gadget = GadgetFromPoint(point);
|
|
if (gadget != AtMouse) {
|
|
if (AtMouse)
|
|
AtMouse->MouseLeave(modKeys, TPoint(point.x - AtMouse->Bounds.left,
|
|
point.y - AtMouse->Bounds.top));
|
|
AtMouse = gadget;
|
|
if (AtMouse)
|
|
AtMouse->MouseEnter(modKeys, TPoint(point.x - AtMouse->Bounds.left,
|
|
point.y - AtMouse->Bounds.top));
|
|
}
|
|
}
|
|
TWindow::EvMouseMove(modKeys, point);
|
|
}
|