- 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>
256 lines
5.9 KiB
C++
256 lines
5.9 KiB
C++
//----------------------------------------------------------------------------
|
|
// ObjectWindows
|
|
// (C) Copyright 1991, 1994 by Borland International, All Rights Reserved
|
|
//
|
|
// Implementation of Window Menu encapsulation class
|
|
//----------------------------------------------------------------------------
|
|
#include <owl/owlpch.h>
|
|
#include <owl/menu.h>
|
|
|
|
DIAG_DECLARE_GROUP(OwlWin); // General window diagnostic group
|
|
|
|
//
|
|
// Construct a menu using CreateMenu()
|
|
//
|
|
TMenu::TMenu(TAutoDelete autoDelete)
|
|
:
|
|
Handle(::CreateMenu()),
|
|
ShouldDelete(autoDelete)
|
|
{
|
|
WARNX(OwlWin, !Handle, 0, "Cannot Create Menu");
|
|
CheckValid();
|
|
}
|
|
|
|
//
|
|
// Construct a menu as a deep copy of an exisiting menu
|
|
//
|
|
TMenu::TMenu(const TMenu& original, TAutoDelete autoDelete)
|
|
:
|
|
Handle(::CreateMenu()),
|
|
ShouldDelete(autoDelete)
|
|
{
|
|
WARNX(OwlWin, !Handle, 0, "Cannot Create Menu for Copy");
|
|
CheckValid();
|
|
DeepCopy(*this, original);
|
|
}
|
|
|
|
//
|
|
// Construct a menu as an alias for an existing handle
|
|
//
|
|
TMenu::TMenu(HMENU handle, TAutoDelete autoDelete)
|
|
:
|
|
Handle(handle),
|
|
ShouldDelete(autoDelete)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Construct a menu alias for a given window's menu
|
|
//
|
|
TMenu::TMenu(HWND hWnd, TAutoDelete autoDelete)
|
|
:
|
|
Handle(::GetMenu(hWnd)),
|
|
ShouldDelete(autoDelete)
|
|
{
|
|
PRECONDITION(hWnd);
|
|
WARNX(OwlWin, !Handle, 0, "Cannot Get Menu from " << hex << (uint)hWnd);
|
|
CheckValid();
|
|
}
|
|
|
|
//
|
|
// Construct a menu from a menu template struct
|
|
//
|
|
TMenu::TMenu(const void far* menuTemplate)
|
|
{
|
|
PRECONDITION(menuTemplate);
|
|
Handle = ::LoadMenuIndirect(menuTemplate);
|
|
WARNX(OwlWin, !Handle, 0, "Cannot Load Menu Indirect " << hex <<
|
|
uint32(menuTemplate));
|
|
CheckValid();
|
|
ShouldDelete = true;
|
|
}
|
|
|
|
//
|
|
// Construct a menu by loading it from resource
|
|
//
|
|
TMenu::TMenu(HINSTANCE resInstance, TResId resId)
|
|
{
|
|
PRECONDITION(resInstance && resId);
|
|
Handle = ::LoadMenu(resInstance, resId);
|
|
WARNX(OwlWin, !Handle, 0, "Cannot Load Menu " << hex << (uint)resInstance <<
|
|
" " << resId);
|
|
CheckValid();
|
|
ShouldDelete = true;
|
|
}
|
|
|
|
//
|
|
// Copy an existing menu onto this menu, using DeepCopy
|
|
//
|
|
TMenu&
|
|
TMenu::operator =(const TMenu& original)
|
|
{
|
|
// Delete all items and submenus
|
|
// Look at possible alternatives for !ShouldDelete menus? Maybe use Remove
|
|
// then?
|
|
//
|
|
while (GetMenuItemCount())
|
|
DeleteMenu(0, MF_BYPOSITION);
|
|
DeepCopy(*this, original);
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
// Destruct the menu by destroying the handle if appropriate.
|
|
//
|
|
TMenu::~TMenu()
|
|
{
|
|
if (ShouldDelete && Handle)
|
|
::DestroyMenu(Handle);
|
|
}
|
|
|
|
//
|
|
// Get the menu ID. If it's a regular menu item just returns its id.
|
|
// Otherwise if it's a popup menu use id of the first item in the popup menu.
|
|
//
|
|
uint
|
|
TMenu::GetMenuItemID(int pos) const
|
|
{
|
|
uint id = ::GetMenuItemID(Handle, pos);
|
|
if (id != uint(-1))
|
|
return id;
|
|
|
|
// Maybe a submenu
|
|
//
|
|
TMenu subMenu(GetSubMenu(pos));
|
|
if (subMenu.Handle == 0)
|
|
return 0;
|
|
|
|
return subMenu.GetMenuItemID(0) - 1;
|
|
}
|
|
|
|
#pragma warn -par // resId param is never used in small model
|
|
void
|
|
TMenu::CheckValid(uint resId)
|
|
{
|
|
if (!Handle)
|
|
THROW( TXMenu(resId) );
|
|
}
|
|
#pragma warn .par
|
|
|
|
void
|
|
TMenu::MeasureItem(MEASUREITEMSTRUCT far&)
|
|
{
|
|
}
|
|
|
|
void
|
|
TMenu::DrawItem(DRAWITEMSTRUCT far&)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deep copy 'count' popup-menus or items from 'src' _appending_ to 'dst'
|
|
// menu starting at 'offset' position in this menu
|
|
//
|
|
void
|
|
TMenu::DeepCopy(TMenu& dst, const TMenu& src, int srcOff, int count)
|
|
{
|
|
if (count < 0)
|
|
count = src.GetMenuItemCount() - srcOff;
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
uint state = src.GetMenuState(srcOff+i, MF_BYPOSITION);
|
|
if (state == uint(-1))
|
|
return;
|
|
|
|
char str[256];
|
|
src.GetMenuString(srcOff+i, str, sizeof(str), MF_BYPOSITION);
|
|
|
|
// Currently does NOT support MF_BITMAP or MF_OWNERDRAW
|
|
//
|
|
if (state & MF_POPUP) {
|
|
state &= (MF_STRING | MF_POPUP); // strip off breaks, separators, etc
|
|
TMenu subMenu(src.GetSubMenu(srcOff+i));
|
|
TMenu newSubMenu(NoAutoDelete);
|
|
DeepCopy(newSubMenu, subMenu);
|
|
dst.AppendMenu(state, newSubMenu, str);
|
|
}
|
|
else {
|
|
dst.AppendMenu(state, src.GetMenuItemID(srcOff+i), str);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Deep copy 'count' popup-menus or items from 'src' to 'dst' menu
|
|
// starting at 'srcOff' position in src and inserting at 'dstOff' in the
|
|
// destination
|
|
//
|
|
void
|
|
TMenu::DeepCopy(TMenu& dst, int dstOff, const TMenu& src, int srcOff, int count)
|
|
{
|
|
if (count < 0)
|
|
count = src.GetMenuItemCount() - srcOff;
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
uint state = src.GetMenuState(srcOff+i, MF_BYPOSITION);
|
|
if (state == uint(-1))
|
|
return;
|
|
|
|
char str[256];
|
|
src.GetMenuString(srcOff+i, str, sizeof(str), MF_BYPOSITION);
|
|
|
|
// Currently does NOT support MF_BITMAP or MF_OWNERDRAW
|
|
//
|
|
if (state & MF_POPUP) {
|
|
state &= (MF_STRING | MF_POPUP); // strip off breaks, separators, etc
|
|
TMenu subMenu(src.GetSubMenu(srcOff+i));
|
|
TMenu newSubMenu(NoAutoDelete);
|
|
DeepCopy(newSubMenu, subMenu);
|
|
if (dstOff >= 0)
|
|
dst.InsertMenu(dstOff, state|MF_BYPOSITION, newSubMenu, str);
|
|
else
|
|
dst.AppendMenu(state, newSubMenu, str);
|
|
}
|
|
else {
|
|
if (dstOff >= 0)
|
|
dst.InsertMenu(dstOff, state|MF_BYPOSITION, src.GetMenuItemID(srcOff+i), str);
|
|
else
|
|
dst.AppendMenu(state, src.GetMenuItemID(srcOff+i), str);
|
|
}
|
|
}
|
|
}
|
|
|
|
TSystemMenu::TSystemMenu(HWND wnd, bool revert)
|
|
:
|
|
TMenu(::GetSystemMenu(wnd, revert), NoAutoDelete)
|
|
{
|
|
}
|
|
|
|
TPopupMenu::TPopupMenu(TAutoDelete autoDelete)
|
|
:
|
|
TMenu(::CreatePopupMenu(), autoDelete)
|
|
{
|
|
}
|
|
|
|
TPopupMenu::TPopupMenu(HMENU handle, TAutoDelete autoDelete)
|
|
:
|
|
TMenu(handle, autoDelete)
|
|
{
|
|
}
|
|
|
|
TMenu::TXMenu::TXMenu(unsigned resId) : TXOwl(resId)
|
|
{
|
|
}
|
|
|
|
TXOwl*
|
|
TMenu::TXMenu::Clone()
|
|
{
|
|
return new TXMenu(*this);
|
|
}
|
|
|
|
void
|
|
TMenu::TXMenu::Throw()
|
|
{
|
|
THROW( *this );
|
|
}
|