- 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>
1116 lines
29 KiB
C++
1116 lines
29 KiB
C++
//----------------------------------------------------------------------------
|
|
// ObjectWindows - (C) Copyright 1991, 1993 by Borland International
|
|
// intldemo.cpp
|
|
//
|
|
// Program to demonstrate much of the functionality afforded with the
|
|
// setlocale function and the locale libraries. Also demonstrates programming
|
|
// a UI to be language-independent, and allow switching of the language at
|
|
// run-time.
|
|
//----------------------------------------------------------------------------
|
|
#include <owl\owlpch.h>
|
|
#include <owl\decframe.h>
|
|
#include <owl\statusba.h>
|
|
#include <owl\dialog.h>
|
|
#include <owl\mdi.h>
|
|
#include <owl\applicat.h>
|
|
#include <owl\dc.h>
|
|
#include <owl\menu.h>
|
|
#include <owl\button.h>
|
|
#include <owl\listbox.h>
|
|
#include <locale.h>
|
|
#include <io.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <dir.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <bwcc.h>
|
|
#include <cstring.h>
|
|
|
|
#include "intldemo.h"
|
|
|
|
#define ID_LOCALEWINDOW 101
|
|
// language identifiers as defined in winnt.h
|
|
#define LANG_ENGLISH 0x09
|
|
#define LANG_FRENCH 0x0c
|
|
#define LANG_GERMAN 0x07
|
|
|
|
#pragma warn -inl // functions containing ... are not expanded inline
|
|
|
|
char* formatVal(char*, long);
|
|
|
|
// override string's comparison routines
|
|
//
|
|
int string::compare(const string& s) const throw()
|
|
{
|
|
return strcoll(c_str(), s.c_str());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Class to convert a file's date/time value into a struct tm.
|
|
//
|
|
class DosTime {
|
|
private:
|
|
struct filetime
|
|
{
|
|
int ftime;
|
|
int fdate;
|
|
};
|
|
|
|
union dosfiletime
|
|
{
|
|
filetime ft;
|
|
struct ftime ftime;
|
|
};
|
|
|
|
dosfiletime dft;
|
|
struct date date;
|
|
struct time time;
|
|
|
|
public:
|
|
DosTime(int ftime, int fdate)
|
|
{
|
|
dft.ft.ftime = ftime;
|
|
dft.ft.fdate = fdate;
|
|
|
|
time.ti_sec = dft.ftime.ft_tsec * 2;
|
|
time.ti_min = dft.ftime.ft_min;
|
|
time.ti_hour = dft.ftime.ft_hour;
|
|
time.ti_hund = 0;
|
|
|
|
date.da_day = dft.ftime.ft_day;
|
|
date.da_mon = dft.ftime.ft_month;
|
|
date.da_year = dft.ftime.ft_year + 1980;
|
|
}
|
|
|
|
struct tm *tmvalue()
|
|
{
|
|
time_t t;
|
|
t = dostounix(&date, &time);
|
|
return localtime (&t);
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
// TFileViewer
|
|
//
|
|
// Simple file viewer. Displays up to 100 chars of each of the first 100 lines
|
|
// of a file in a listbox. Allows sorting by lines.
|
|
//
|
|
class TFileViewer : public TDialog {
|
|
public:
|
|
TFileViewer(TWindow* parent, TModule* module, char* fileName, TResId resourceId = ID_FILEVIEWER);
|
|
|
|
void SetupWindow()
|
|
{
|
|
TDialog::SetupWindow();
|
|
SetCaption(caption);
|
|
delete [] caption;
|
|
for (int i = 0; i < stringArray.GetItemsInContainer(); i++)
|
|
{
|
|
lBox -> AddString(stringArray[i]->c_str());
|
|
}
|
|
}
|
|
|
|
void CmSort(UINT)
|
|
{
|
|
lBox -> ClearList();
|
|
for (int i = 0; i < sStringArray.GetItemsInContainer(); i++)
|
|
{
|
|
lBox -> AddString(sStringArray[i]->c_str());
|
|
}
|
|
lBox -> SetSelIndex(0);
|
|
}
|
|
|
|
protected:
|
|
enum {maxLines = 100, maxLineLength = 100};
|
|
TListBox *lBox;
|
|
TIArrayAsVector<string> stringArray;
|
|
TISArrayAsVector<string> sStringArray;
|
|
char *caption;
|
|
int nLines;
|
|
|
|
DECLARE_RESPONSE_TABLE(TFileViewer);
|
|
};
|
|
|
|
DEFINE_RESPONSE_TABLE1(TFileViewer, TDialog)
|
|
EV_CHILD_NOTIFY_ALL_CODES(ID_SORTBUT, CmSort),
|
|
END_RESPONSE_TABLE;
|
|
|
|
|
|
TFileViewer::TFileViewer(TWindow* parent, TModule* module, char* fileName, TResId resourceId)
|
|
: TDialog(parent, resourceId, module),
|
|
stringArray(maxLines), sStringArray(maxLines)
|
|
{
|
|
sStringArray.OwnsElements(0);
|
|
ifstream f(fileName);
|
|
nLines = 0;
|
|
if (!f.fail())
|
|
{
|
|
caption = strdup(fileName);
|
|
while(!f.eof() && nLines < maxLines)
|
|
{
|
|
char buf[maxLineLength];
|
|
f.get(buf, sizeof buf - 1);
|
|
string *s = new string(buf);
|
|
stringArray.Add(s);
|
|
sStringArray.Add(s);
|
|
// if we're not at the end of the line, try to jump to the next line
|
|
if (f.get() != '\n')
|
|
f.ignore(100, '\n');
|
|
}
|
|
f.close();
|
|
}
|
|
lBox = new TListBox(this, ID_FILELISTBOX, module);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// TFileListBox
|
|
//
|
|
// Derivation of ListBox to display file information. Note we are using our own
|
|
// sort functions rather than Windows' default sorting. This allows different
|
|
// instances of the program to demonstrate the different sorting/collating
|
|
// sequences of different locales.
|
|
//
|
|
class TFileListBox : public TListBox
|
|
{
|
|
public:
|
|
TFileListBox(TWindow * parent, int ResourceId, TModule* Module) :
|
|
TListBox(parent, ResourceId, Module),
|
|
FRArray(100, 0, 10), SFRArray(100, 0, 10), currCase(upper), currSort(unsorted)
|
|
{
|
|
module = Module;
|
|
SFRArray.OwnsElements(0);
|
|
}
|
|
|
|
void SetupWindow()
|
|
{
|
|
TListBox::SetupWindow();
|
|
SetWindowFont(font, 0);
|
|
GetDirList();
|
|
FillListBox();
|
|
SetSelIndex(0);
|
|
}
|
|
|
|
void ToLower();
|
|
|
|
void FillListBox();
|
|
|
|
void GetDirList();
|
|
|
|
void EvLButtonDblClk(UINT, TPoint&);
|
|
|
|
void Sort()
|
|
{
|
|
currSort = (currSort == sorted) ? unsorted : sorted;
|
|
char buf[MAXFILE + MAXEXT + 1];
|
|
GetSelString(buf, sizeof buf);
|
|
FillListBox();
|
|
SetSelString(buf, 0);
|
|
}
|
|
|
|
void ChangeDir();
|
|
|
|
void View()
|
|
{
|
|
if (GetSelIndex() >= 0) {
|
|
char buf[100];
|
|
GetSelString(buf, sizeof buf);
|
|
|
|
if (strstr(buf, "<DIR>"))
|
|
ChangeDir();
|
|
else {
|
|
char* s = strchr(buf, ' ');
|
|
if (s)
|
|
*s = 0;
|
|
TFileViewer(Parent, module, buf).Execute();
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
// Structure containing file information to be displayed in the
|
|
// FileListBox.
|
|
//
|
|
struct FileRec
|
|
{
|
|
char name[13], datetime[100], sizeStr[30];
|
|
long fsize;
|
|
char attrib;
|
|
|
|
// functions used by sorted arrays
|
|
int operator<(const FileRec& r) const
|
|
{
|
|
return (strcoll(name, r.name) < 0) ? 1 : 0;
|
|
}
|
|
|
|
int operator==(const FileRec& r) const
|
|
{
|
|
return (strcoll(name, r.name) == 0) ? 1 : 0;
|
|
}
|
|
};
|
|
|
|
// Font to display the filelistbox - we want a non-proportional
|
|
// font for formatting reasons
|
|
class FileListFont : public TFont
|
|
{
|
|
private:
|
|
int HeightInPixels(int pointSize)
|
|
{
|
|
TScreenDC dc;
|
|
return MulDiv(-pointSize, dc.GetDeviceCaps(LOGPIXELSY), 72);
|
|
}
|
|
|
|
public:
|
|
FileListFont() : TFont ("Courier New", HeightInPixels(8)) {}
|
|
};
|
|
|
|
int isSorted;
|
|
int nFiles;
|
|
TIArrayAsVector<FileRec> FRArray;
|
|
TISArrayAsVector<FileRec> SFRArray;
|
|
enum cases {upper, lower};
|
|
cases currCase;
|
|
enum sorting {sorted, unsorted};
|
|
sorting currSort;
|
|
TModule* module;
|
|
FileListFont font;
|
|
|
|
DECLARE_RESPONSE_TABLE(TFileListBox);
|
|
};
|
|
|
|
DEFINE_RESPONSE_TABLE1(TFileListBox, TListBox)
|
|
EV_WM_LBUTTONDBLCLK,
|
|
END_RESPONSE_TABLE;
|
|
|
|
void TFileListBox::EvLButtonDblClk(UINT, TPoint&)
|
|
{
|
|
View(); // view the file or directory
|
|
}
|
|
|
|
void TFileListBox::GetDirList()
|
|
{
|
|
SFRArray.Flush();
|
|
FRArray.Flush();
|
|
struct ffblk ffblk;
|
|
struct tm *tm;
|
|
DosTime *dt;
|
|
nFiles = 0;
|
|
int done = findfirst("*.*", &ffblk, 0x3f);
|
|
while (!done)
|
|
{
|
|
FileRec* f = new FileRec;
|
|
OemToAnsiBuff(ffblk.ff_name, ffblk.ff_name, strlen(ffblk.ff_name));
|
|
if (currCase == lower)
|
|
{
|
|
strlwr(ffblk.ff_name);
|
|
}
|
|
strcpy(f->name, ffblk.ff_name);
|
|
dt = new DosTime(ffblk.ff_ftime, ffblk.ff_fdate);
|
|
tm = dt->tmvalue();
|
|
delete dt;
|
|
f->attrib = ffblk.ff_attrib;
|
|
f->fsize = ffblk.ff_fsize;
|
|
formatVal(f->sizeStr, ffblk.ff_fsize);
|
|
strftime(f->datetime, 100, "%c", tm);
|
|
FRArray.Add(f);
|
|
SFRArray.Add(f);
|
|
done = findnext(&ffblk);
|
|
}
|
|
}
|
|
|
|
void TFileListBox::ChangeDir()
|
|
{
|
|
char buf[MAXFILE + MAXEXT + 1];
|
|
if (GetSelString(buf, sizeof buf))
|
|
{
|
|
for (int i = 0; i < sizeof buf; i++)
|
|
if (buf[i] == ' ')
|
|
{
|
|
buf[i] = 0;
|
|
break;
|
|
}
|
|
if (!chdir(buf))
|
|
{
|
|
GetDirList();
|
|
FillListBox();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void TFileListBox::ToLower()
|
|
{
|
|
int selection = GetSelIndex();
|
|
if (currCase == upper)
|
|
{
|
|
for (int i = 0; i < FRArray.GetItemsInContainer(); i++)
|
|
strlwr(FRArray[i] -> name);
|
|
currCase = lower;
|
|
FillListBox();
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < FRArray.GetItemsInContainer(); i++)
|
|
strupr(FRArray[i] -> name);
|
|
currCase = upper;
|
|
FillListBox();
|
|
}
|
|
SetSelIndex(selection);
|
|
}
|
|
|
|
void TFileListBox::FillListBox()
|
|
{
|
|
char lbformat[] = "%-14.14s\t%-7s\t%10s";
|
|
char s[120];
|
|
SetRedraw(FALSE);
|
|
// Japanese Windows 3.0 repaints horribly with SETREDRAW switched on!
|
|
ClearList();
|
|
int i;
|
|
switch(currSort)
|
|
{
|
|
case sorted:
|
|
for (i = 0; i < SFRArray.GetItemsInContainer(); i++)
|
|
{
|
|
sprintf(s, lbformat, SFRArray[i]->name, SFRArray[i]->datetime,
|
|
((SFRArray[i]->attrib & FA_DIREC) ? ("<DIR>") : (SFRArray[i]->sizeStr)));
|
|
AddString(s);
|
|
}
|
|
break;
|
|
|
|
case unsorted:
|
|
for (i = 0; i < FRArray.GetItemsInContainer(); i++)
|
|
{
|
|
sprintf(s, lbformat, FRArray[i]->name, FRArray[i]->datetime,
|
|
((FRArray[i]->attrib & FA_DIREC) ? ("<DIR>") : (FRArray[i]->sizeStr)));
|
|
AddString(s);
|
|
}
|
|
break;
|
|
}
|
|
SetRedraw(TRUE);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Dialog box containing the FileListBox.
|
|
//
|
|
class TFileListDialog : public TDialog
|
|
{
|
|
public:
|
|
TFileListDialog(TWindow * parent, TModule* Module, int ResourceId = ID_FILELISTBOX)
|
|
:TDialog(parent, ResourceId, Module)
|
|
{
|
|
ListBox = new TFileListBox(this, ID_FILELISTBOX, Module);
|
|
viewButton = new TButton(this, ID_VIEWBUTTON, Module);
|
|
startDir = strdup(getcwd(0, MAXPATH));
|
|
}
|
|
|
|
virtual ~TFileListDialog()
|
|
{
|
|
chdir(startDir);
|
|
delete [] startDir;
|
|
}
|
|
|
|
void Sort(UINT)
|
|
{
|
|
ListBox -> Sort();
|
|
}
|
|
|
|
void ToLower(UINT)
|
|
{
|
|
ListBox -> ToLower();
|
|
}
|
|
|
|
void View(UINT)
|
|
{
|
|
ListBox -> View();
|
|
}
|
|
|
|
void Help(UINT)
|
|
{
|
|
}
|
|
|
|
private:
|
|
TFileListBox* ListBox;
|
|
TButton* viewButton;
|
|
char* startDir;
|
|
|
|
DECLARE_RESPONSE_TABLE(TFileListDialog);
|
|
};
|
|
|
|
DEFINE_RESPONSE_TABLE1(TFileListDialog, TDialog)
|
|
EV_CHILD_NOTIFY_ALL_CODES(ID_SORTBUT, Sort),
|
|
EV_CHILD_NOTIFY_ALL_CODES(ID_TOLOWERBUT, ToLower),
|
|
EV_CHILD_NOTIFY_ALL_CODES(ID_VIEWBUTTON, View),
|
|
EV_CHILD_NOTIFY_ALL_CODES(IDHELP, Help),
|
|
END_RESPONSE_TABLE;
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Popup window displaying the current locale values. Note that the locale or
|
|
// language can be changed from the main window while we are being displayed,
|
|
// and we will update accordingly.
|
|
//
|
|
class TLocaleValueWindow : public TFrameWindow
|
|
{
|
|
public:
|
|
TLocaleValueWindow(lconv *pconv, short cx, short cy, TModule* pResModule,
|
|
TWindow* parent, LPSTR title = 0) :
|
|
TFrameWindow(parent, title)
|
|
{
|
|
conv = pconv;
|
|
cxChar = cx;
|
|
cyChar = cy;
|
|
pResourceModule = pResModule;
|
|
|
|
Attr.H = cyChar * 22;
|
|
Attr.W = cxChar * 60;
|
|
Attr.Style = Attr.Style | WS_THICKFRAME | WS_SYSMENU;
|
|
}
|
|
|
|
void SetupWindow()
|
|
{
|
|
TFrameWindow::SetupWindow();
|
|
|
|
char szTitle[100];
|
|
pResourceModule -> LoadString(STR_LOCALETITLE, szTitle, 100);
|
|
SetCaption(szTitle);
|
|
}
|
|
|
|
// Called by the parent after the language or locale has been changed to keep
|
|
// us in synch
|
|
void ResetValues(lconv *pconv, short cx, short cy, TModule* pResModule)
|
|
{
|
|
conv = pconv;
|
|
cxChar = cx;
|
|
cyChar = cy;
|
|
pResourceModule = pResModule;
|
|
char szTitle[100];
|
|
pResourceModule -> LoadString(STR_LOCALETITLE, szTitle, 100);
|
|
SetCaption(szTitle);
|
|
}
|
|
|
|
virtual void Paint(TDC&, BOOL, TRect&);
|
|
|
|
protected:
|
|
int max(int a, int b)
|
|
{
|
|
if (a > b)
|
|
return a;
|
|
return b;
|
|
}
|
|
|
|
void EvClose()
|
|
{
|
|
// Tell the parent that we're finished.
|
|
Parent -> SendMessage(WM_VALWNDCLOSE, 0, 0);
|
|
TFrameWindow::EvClose();
|
|
}
|
|
|
|
private:
|
|
TModule* pResourceModule;
|
|
short cxChar, cyChar;
|
|
lconv *conv;
|
|
|
|
DECLARE_RESPONSE_TABLE(TLocaleValueWindow);
|
|
};
|
|
|
|
DEFINE_RESPONSE_TABLE1(TLocaleValueWindow, TFrameWindow)
|
|
EV_WM_CLOSE,
|
|
END_RESPONSE_TABLE;
|
|
|
|
|
|
void TLocaleValueWindow::Paint(TDC& hdc, BOOL, TRect&)
|
|
{
|
|
short t, i;
|
|
char buf[100];
|
|
int maxWidth = 0;
|
|
char yesStr[10], noStr[10];
|
|
|
|
hdc.SelectStockObject ( SYSTEM_FIXED_FONT );
|
|
|
|
hdc.SetTextColor(RGB(0, 0, 255));
|
|
|
|
for (t = STR_DECIMALPOINT, i = 1; t <= STR_N_SIGN_POSN; t++, i++)
|
|
{
|
|
pResourceModule -> LoadString(t, buf, 100);
|
|
hdc.TextOut(cxChar + 10, cyChar * i, buf,strlen(buf));
|
|
maxWidth = max(maxWidth, strlen(buf));
|
|
}
|
|
|
|
pResourceModule -> LoadString(STR_YES, yesStr, 9);
|
|
pResourceModule -> LoadString(STR_NO, noStr, 9);
|
|
|
|
hdc.SetTextColor(RGB(255, 0, 0));
|
|
maxWidth *= cxChar;
|
|
maxWidth += (5 * cxChar);
|
|
i = 1;
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), conv -> decimal_point, strlen(conv -> decimal_point));
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), conv -> thousands_sep, strlen(conv -> thousands_sep));
|
|
sprintf(buf, "%d", *conv -> grouping);
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), buf, strlen(buf));
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), conv -> int_curr_symbol, strlen(conv -> int_curr_symbol));
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), conv -> currency_symbol, strlen(conv -> currency_symbol));
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), conv -> mon_decimal_point, strlen(conv -> mon_decimal_point));
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), conv -> mon_thousands_sep, strlen(conv -> mon_thousands_sep));
|
|
sprintf(buf, "%d", *conv -> mon_grouping);
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), buf, strlen(buf));
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), conv -> positive_sign, strlen(conv -> positive_sign));
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), conv -> negative_sign, strlen(conv -> negative_sign));
|
|
|
|
sprintf(buf, "%d", conv -> int_frac_digits);
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), buf, strlen(buf));
|
|
sprintf(buf, "%d", conv -> frac_digits);
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), buf, strlen(buf));
|
|
|
|
char scratch[10];
|
|
sprintf(buf, "%s", (conv -> p_cs_precedes == CHAR_MAX) ? itoa(CHAR_MAX, scratch, 10) :
|
|
(conv -> p_cs_precedes == 1) ? yesStr : noStr);
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), buf, strlen(buf));
|
|
sprintf(buf, "%s", (conv -> p_sep_by_space == CHAR_MAX) ? itoa(CHAR_MAX, scratch, 10) :
|
|
(conv -> p_sep_by_space == 1) ? yesStr : noStr);
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), buf, strlen(buf));
|
|
sprintf(buf, "%s", (conv -> n_cs_precedes == CHAR_MAX) ? itoa(CHAR_MAX, scratch, 10) :
|
|
(conv -> n_cs_precedes == 1) ? yesStr : noStr);
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), buf, strlen(buf));
|
|
sprintf(buf, "%s", (conv -> n_sep_by_space == CHAR_MAX) ? itoa(CHAR_MAX, scratch, 10) :
|
|
(conv -> n_sep_by_space == 1) ? yesStr : noStr);
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), buf, strlen(buf));
|
|
sprintf(buf, "%d", conv -> p_sign_posn);
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), buf, strlen(buf));
|
|
sprintf(buf, "%d", conv -> n_sign_posn);
|
|
hdc.TextOut(maxWidth, cyChar * (i ++), buf, strlen(buf));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Main window, containing a display of all 256 ANSI chars highlighted according
|
|
// to the current classification function.
|
|
//
|
|
#define L_CHARSTRING 20
|
|
|
|
class TLocaleWindow : public TWindow
|
|
{
|
|
public:
|
|
TLocaleWindow(TWindow* parent = 0, const char* title = 0)
|
|
: TWindow(parent, title)
|
|
{
|
|
Attr.Id = ID_LOCALEWINDOW;
|
|
classification = alpha;
|
|
classificationmacros[0] = isalnum;
|
|
classificationmacros[1] = isalpha;
|
|
classificationmacros[2] = isascii;
|
|
classificationmacros[3] = iscntrl;
|
|
classificationmacros[4] = isdigit;
|
|
classificationmacros[5] = isgraph;
|
|
classificationmacros[6] = islower;
|
|
classificationmacros[7] = isprint;
|
|
classificationmacros[8] = ispunct;
|
|
classificationmacros[9] = isspace;
|
|
classificationmacros[10] = isupper;
|
|
classificationmacros[11] = isxdigit;
|
|
|
|
strcpy(macronames[0], "isalnum()");
|
|
strcpy(macronames[1], "isalpha()");
|
|
strcpy(macronames[2], "isascii()");
|
|
strcpy(macronames[3], "iscntrl()");
|
|
strcpy(macronames[4], "isdigit()");
|
|
strcpy(macronames[5], "isgraph()");
|
|
strcpy(macronames[6], "islower()");
|
|
strcpy(macronames[7], "isprint()");
|
|
strcpy(macronames[8], "ispunct()");
|
|
strcpy(macronames[9], "isspace()");
|
|
strcpy(macronames[10], "isupper()");
|
|
strcpy(macronames[11], "isxdigit()");
|
|
}
|
|
|
|
void SetupWindow()
|
|
{
|
|
TWindow::SetupWindow();
|
|
TWindowDC dc(HWindow);
|
|
dc.SelectStockObject(SYSTEM_FIXED_FONT);
|
|
TEXTMETRIC tm;
|
|
dc.GetTextMetrics (tm);
|
|
cxChar = tm.tmAveCharWidth;
|
|
cyChar = tm.tmHeight + tm.tmExternalLeading;
|
|
SetFocus();
|
|
}
|
|
|
|
enum classifications {alnum = CM_ISALNUM, alpha, ascii, cntrl, digit, graph, lower, print, punct, space, upper, xdigit};
|
|
|
|
int ChangeClassification(classifications newClassification)
|
|
{
|
|
CheckMenuItem(Parent -> GetMenu(), classification, MF_UNCHECKED);
|
|
classification = newClassification;
|
|
CheckMenuItem(Parent -> GetMenu(), classification, MF_CHECKED);
|
|
|
|
Invalidate(TRUE);
|
|
return 0;
|
|
}
|
|
|
|
void ChangeUI(TModule *pResModule)
|
|
{
|
|
CheckMenuItem(Parent -> GetMenu(), classification, MF_CHECKED);
|
|
pResModule -> LoadString(STR_CHARACTER, characterString, L_CHARSTRING);
|
|
}
|
|
|
|
void EvMouseMove(UINT /*modKeys*/, TPoint &point)
|
|
{
|
|
char buf[50];
|
|
point.x -= boxTopLeft.x;
|
|
point.y -= boxTopLeft.y;
|
|
if (((point.x > 0) && (point.x < boxBottomRight.x - 4))
|
|
&& ((point.y > 0) && (point.y < boxBottomRight.y)))
|
|
{
|
|
int ch = (((point.y / cellHeight) * 16) + (point.x /cellWidth));
|
|
sprintf(buf, "%s %4d : %4c : %#x", characterString, ch, (ch == 0) ? 1 : ch, ch, ch);
|
|
}
|
|
else
|
|
{
|
|
buf[0] = 0;
|
|
}
|
|
TYPESAFE_DOWNCAST(Parent -> ChildWithId(IDW_STATUSBAR), TStatusBar)->SetText(buf);
|
|
}
|
|
|
|
void CMIsAlnum()
|
|
{
|
|
if (classification != alnum)
|
|
ChangeClassification(alnum);
|
|
}
|
|
|
|
void CMIsAlpha()
|
|
{
|
|
if (classification != alpha)
|
|
ChangeClassification(alpha);
|
|
}
|
|
|
|
void CMIsAscii()
|
|
{
|
|
if (classification != ascii)
|
|
ChangeClassification(ascii);
|
|
}
|
|
|
|
void CMIsCntrl()
|
|
{
|
|
if (classification != cntrl)
|
|
ChangeClassification(cntrl);
|
|
}
|
|
|
|
void CMIsDigit()
|
|
{
|
|
if (classification != digit)
|
|
ChangeClassification(digit);
|
|
}
|
|
|
|
void CMIsGraph()
|
|
{
|
|
if (classification != graph)
|
|
ChangeClassification(graph);
|
|
}
|
|
|
|
void CMIsLower()
|
|
{
|
|
if (classification != lower)
|
|
ChangeClassification(lower);
|
|
}
|
|
|
|
void CMIsPrint()
|
|
{
|
|
if (classification != print)
|
|
ChangeClassification(print);
|
|
}
|
|
|
|
void CMIsPunct()
|
|
{
|
|
if (classification != punct)
|
|
ChangeClassification(punct);
|
|
}
|
|
|
|
void CMIsSpace()
|
|
{
|
|
if (classification != space)
|
|
ChangeClassification(space);
|
|
}
|
|
|
|
void CMIsUpper()
|
|
{
|
|
if (classification != upper)
|
|
ChangeClassification(upper);
|
|
}
|
|
|
|
void CMIsXDigit()
|
|
{
|
|
if (classification != xdigit)
|
|
ChangeClassification(xdigit);
|
|
}
|
|
|
|
virtual void Paint(TDC&, BOOL, TRect&);
|
|
|
|
protected:
|
|
int trueColor(TDC& hdc)
|
|
// Sets colour to display characters for which the classification function
|
|
// returns TRUE
|
|
{
|
|
hdc.SetTextColor(RGB(255, 0, 255));
|
|
hdc.SetBkColor(RGB(0, 220, 0));
|
|
return 0;
|
|
}
|
|
|
|
int falseColor(TDC& hdc)
|
|
// Sets colour to display characters for which the classification function
|
|
// returns FALSE
|
|
{
|
|
hdc.SetTextColor(RGB(200, 200, 200));
|
|
hdc.SetBkColor(RGB(255, 255, 255));
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
classifications classification;
|
|
short cxChar, cyChar;
|
|
int (*classificationmacros[12])(int);
|
|
int cellWidth, cellHeight;
|
|
char macronames[12][12];
|
|
TPoint boxTopLeft, boxBottomRight;
|
|
char characterString[L_CHARSTRING];
|
|
|
|
DECLARE_RESPONSE_TABLE(TLocaleWindow);
|
|
};
|
|
|
|
DEFINE_RESPONSE_TABLE1(TLocaleWindow, TWindow)
|
|
EV_WM_MOUSEMOVE,
|
|
EV_COMMAND(CM_ISALNUM, CMIsAlnum),
|
|
EV_COMMAND(CM_ISALPHA, CMIsAlpha),
|
|
EV_COMMAND(CM_ISASCII, CMIsAscii),
|
|
EV_COMMAND(CM_ISCNTRL, CMIsCntrl),
|
|
EV_COMMAND(CM_ISDIGIT, CMIsDigit),
|
|
EV_COMMAND(CM_ISGRAPH, CMIsGraph),
|
|
EV_COMMAND(CM_ISLOWER, CMIsLower),
|
|
EV_COMMAND(CM_ISPRINT, CMIsPrint),
|
|
EV_COMMAND(CM_ISPUNCT, CMIsPunct),
|
|
EV_COMMAND(CM_ISSPACE, CMIsSpace),
|
|
EV_COMMAND(CM_ISUPPER, CMIsUpper),
|
|
EV_COMMAND(CM_ISXDIGIT, CMIsXDigit),
|
|
END_RESPONSE_TABLE;
|
|
|
|
void TLocaleWindow::Paint(TDC& hdc, BOOL, TRect&)
|
|
{
|
|
char buf[100];
|
|
int maxWidth = 0;
|
|
|
|
hdc.SelectStockObject(SYSTEM_FIXED_FONT);
|
|
|
|
hdc.SetTextColor(RGB(0, 0, 0));
|
|
hdc.TextOut((30 * cxChar), (cyChar / 2), macronames[classification - alnum], strlen(macronames[classification - CM_ISALNUM]));
|
|
maxWidth = (10 * cxChar);
|
|
|
|
#define COLUMNS 16
|
|
#define ROWS 16
|
|
|
|
char hexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
|
|
|
//Display the codepoint values around the character set.
|
|
for (int i = 0; i < ROWS; i++)
|
|
{
|
|
sprintf(buf, "%c", hexChars[i]);
|
|
hdc.TextOut(maxWidth + ((i * 3) * cxChar), cyChar * 2 , buf, 1);
|
|
hdc.TextOut((maxWidth - (3 * cxChar)), cyChar * (i + 3), buf, 1);
|
|
}
|
|
|
|
// display the character set in a ROWS x COLUMNS grid, with colours set by
|
|
// trueColor() and falseColor() according to the return value of the current
|
|
// classification function.
|
|
for (i = 0; i < ROWS; i++)
|
|
for (int j = 0; j < COLUMNS; j++)
|
|
{
|
|
int c = ((i * COLUMNS) + j);
|
|
sprintf(buf, "%c", c);
|
|
classificationmacros[classification - alnum](c) ? trueColor(hdc) : falseColor(hdc);
|
|
if (c < 256) // in case we use different values for row/column.
|
|
hdc.TextOut(maxWidth + ((j * 3) * cxChar), cyChar * (i + 3), buf, 1);
|
|
}
|
|
|
|
|
|
// Draw a box round the characters.
|
|
#define X1 (maxWidth - 6)
|
|
#define Y1 ((3 * cyChar) - 2)
|
|
#define X2 ((maxWidth - 2) + (cxChar * (COLUMNS * 3)))
|
|
#define Y2 (((3 * cyChar) - 2) + (cyChar * ROWS))
|
|
|
|
boxTopLeft.x = X1;
|
|
boxTopLeft.y = Y1;
|
|
boxBottomRight.x = X2 - X1;
|
|
boxBottomRight.y = Y2 - Y1;
|
|
|
|
cellWidth = (boxBottomRight.x / COLUMNS);
|
|
cellHeight = (boxBottomRight.y / ROWS);
|
|
|
|
hdc.SelectObject(CreatePen(PS_SOLID, 1, RGB(0, 127, 127)));
|
|
|
|
hdc.MoveTo(X1, Y1);
|
|
hdc.LineTo(X1, Y2);
|
|
hdc.LineTo(X2, Y2);
|
|
hdc.LineTo(X2, Y1);
|
|
hdc.LineTo(X1, Y1);
|
|
|
|
for (i = 0; i < ROWS; i++)
|
|
{
|
|
hdc.MoveTo(X1, Y1 + (i * cyChar));
|
|
hdc.LineTo(X2, Y1 + (i * cyChar));
|
|
}
|
|
|
|
for (i = 0; i < COLUMNS; i++)
|
|
{
|
|
hdc.MoveTo(X1 + ((i * 3) * cxChar), Y1);
|
|
hdc.LineTo(X1 + ((i * 3) * cxChar), Y2);
|
|
}
|
|
hdc.RestorePen();
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
class TLocaleFrame : public TDecoratedFrame
|
|
{
|
|
enum languages {langEnglish = CM_LANGUAGEENGLISH, langFrench, langGerman};
|
|
enum locales {locC = CM_LOCALEC, locUS, locUK, locFrench, locGerman};
|
|
|
|
public:
|
|
TLocaleFrame(TWindow* client)
|
|
:TDecoratedFrame((TWindow*)0, (char*)0, client, TRUE)
|
|
{
|
|
pResourceModule = new TModule("APIENG.DLL");
|
|
tMenu = new TMenu(pResourceModule -> LoadMenu("MAINMENU"), AutoDelete);
|
|
valueWin = 0;
|
|
if (!HMENU(*tMenu))
|
|
throw "Error loading menu";
|
|
|
|
locale = locC;
|
|
language = langEnglish;
|
|
|
|
TWindowDC dc(HWindow);
|
|
dc.SelectStockObject(SYSTEM_FIXED_FONT);
|
|
TEXTMETRIC tm;
|
|
dc.GetTextMetrics (tm);
|
|
cxChar = tm.tmAveCharWidth;
|
|
cyChar = tm.tmHeight + tm.tmExternalLeading;
|
|
Attr.H = (cyChar * 25);
|
|
Attr.W = (cxChar * 80);
|
|
}
|
|
|
|
virtual ~TLocaleFrame()
|
|
{
|
|
delete tMenu;
|
|
delete pResourceModule;
|
|
}
|
|
|
|
void SetupWindow()
|
|
{
|
|
TDecoratedFrame::SetupWindow();
|
|
|
|
|
|
char szTitle[100];
|
|
pResourceModule -> LoadString(STR_APPNAME, szTitle, 100);
|
|
SetCaption(szTitle);
|
|
SetMenu(*tMenu);
|
|
tMenu -> CheckMenuItem(locale, MF_CHECKED);
|
|
tMenu -> CheckMenuItem(language, MF_CHECKED);
|
|
TYPESAFE_DOWNCAST(GetClientWindow(), TLocaleWindow) -> ChangeUI(pResourceModule);
|
|
conv = localeconv();
|
|
}
|
|
|
|
void EvEnterIdle(UINT source, HWND hWndDlg)
|
|
{
|
|
//TDecoratedFrame::EvEnterIdle loads the help hint string, so
|
|
// we change the instance here so it gets it from pResourceModule
|
|
TModule* module = GetModule();
|
|
SetModule(pResourceModule);
|
|
TDecoratedFrame::EvEnterIdle(source, hWndDlg);
|
|
SetModule(module);
|
|
}
|
|
|
|
void CMEnglishLanguage()
|
|
{
|
|
ChangeUI("apieng.dll", "English", langEnglish, LANG_ENGLISH);
|
|
}
|
|
|
|
void CMFrenchLanguage()
|
|
{
|
|
ChangeUI("apifra.dll", "French", langFrench, LANG_FRENCH);
|
|
}
|
|
|
|
void CMGermanLanguage()
|
|
{
|
|
ChangeUI("apiger.dll", "German", langGerman, LANG_GERMAN);
|
|
}
|
|
|
|
|
|
void CMFileList()
|
|
{
|
|
TFileListDialog(this, pResourceModule).Execute();
|
|
}
|
|
|
|
void CMCLocale()
|
|
{
|
|
if (locale != locC)
|
|
ChangeLocale(LC_ALL, "C", locC);
|
|
}
|
|
|
|
void CMUSLocale()
|
|
{
|
|
if (locale != locUS)
|
|
ChangeLocale(LC_ALL, "en_US.WIN1252", locUS);
|
|
}
|
|
|
|
void CMUKLocale()
|
|
{
|
|
if (locale != locUK)
|
|
ChangeLocale(LC_ALL, "en_GB.WIN1252", locUK);
|
|
}
|
|
|
|
void CMFrenchLocale()
|
|
{
|
|
if (locale != locFrench)
|
|
ChangeLocale(LC_ALL, "fr_FR.WIN1252", locFrench);
|
|
}
|
|
|
|
void CMGermanLocale()
|
|
{
|
|
if (locale != locGerman)
|
|
ChangeLocale(LC_ALL, "de_DE.WIN1252", locGerman);
|
|
}
|
|
|
|
void CMShowValues()
|
|
{
|
|
if (!valueWin)
|
|
{
|
|
valueWin = new TLocaleValueWindow(conv, cxChar,
|
|
cyChar, pResourceModule, this);
|
|
|
|
valueWin -> Create();
|
|
valueWin -> Show(SW_SHOW);
|
|
}
|
|
else
|
|
valueWin -> SetFocus();
|
|
}
|
|
|
|
LRESULT WMValWndClose(WPARAM, LPARAM)
|
|
{
|
|
valueWin = 0;
|
|
return 0;
|
|
}
|
|
|
|
protected:
|
|
int ChangeUI(char* DLLName, char* langName, languages newLanguage, UINT countryCode)
|
|
{
|
|
delete pResourceModule;
|
|
pResourceModule = new TModule(DLLName);
|
|
delete tMenu;
|
|
tMenu = new TMenu(pResourceModule -> LoadMenu("MAINMENU"), AutoDelete);
|
|
SetMenu(*tMenu);
|
|
tMenu -> CheckMenuItem(locale, MF_CHECKED);
|
|
TYPESAFE_DOWNCAST(GetClientWindow(), TLocaleWindow) -> ChangeUI(pResourceModule);
|
|
|
|
char szTitle[100];
|
|
pResourceModule -> LoadString(STR_APPNAME, szTitle, 100);
|
|
SetCaption(szTitle);
|
|
|
|
Invalidate(TRUE);
|
|
RedrawValueWindow();
|
|
tMenu -> CheckMenuItem(language, MF_UNCHECKED);
|
|
language = newLanguage;
|
|
tMenu -> CheckMenuItem(language, MF_CHECKED);
|
|
BWCCIntlTerm();
|
|
BWCCIntlInit(countryCode);
|
|
return 1;
|
|
}
|
|
|
|
char *ChangeLocale(int category, char *localeType, locales newLocale)
|
|
{
|
|
tMenu -> CheckMenuItem(locale, MF_UNCHECKED);
|
|
locale = newLocale;
|
|
tMenu -> CheckMenuItem(locale, MF_CHECKED);
|
|
|
|
char *c = setlocale(category, localeType);
|
|
conv = localeconv();
|
|
Invalidate(TRUE);
|
|
RedrawValueWindow();
|
|
ChildWithId(ID_LOCALEWINDOW) -> Invalidate(TRUE);
|
|
return c;
|
|
}
|
|
|
|
void RedrawValueWindow()
|
|
{
|
|
if (valueWin)
|
|
{
|
|
valueWin -> ResetValues(conv, cxChar,
|
|
cyChar, pResourceModule);
|
|
valueWin -> Invalidate(TRUE);
|
|
}
|
|
}
|
|
|
|
private:
|
|
languages language;
|
|
locales locale;
|
|
TModule* pResourceModule;
|
|
TMenu* tMenu;
|
|
TLocaleValueWindow* valueWin;
|
|
short cxChar, cyChar, scrX, scrY;
|
|
lconv* conv;
|
|
|
|
DECLARE_RESPONSE_TABLE(TLocaleFrame);
|
|
};
|
|
|
|
DEFINE_RESPONSE_TABLE1(TLocaleFrame, TDecoratedFrame)
|
|
EV_WM_ENTERIDLE,
|
|
EV_COMMAND(CM_FILELIST, CMFileList),
|
|
EV_COMMAND(CM_LOCALEC, CMCLocale),
|
|
EV_COMMAND(CM_LOCALEUS, CMUSLocale),
|
|
EV_COMMAND(CM_LOCALEUK, CMUKLocale),
|
|
EV_COMMAND(CM_LOCALEFRENCH, CMFrenchLocale),
|
|
EV_COMMAND(CM_LOCALEGERMAN, CMGermanLocale),
|
|
EV_COMMAND(CM_LANGUAGEENGLISH, CMEnglishLanguage),
|
|
EV_COMMAND(CM_LANGUAGEFRENCH, CMFrenchLanguage),
|
|
EV_COMMAND(CM_LANGUAGEGERMAN, CMGermanLanguage),
|
|
EV_COMMAND(CM_SHOWVALUES, CMShowValues),
|
|
EV_MESSAGE(WM_VALWNDCLOSE, WMValWndClose),
|
|
END_RESPONSE_TABLE;
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
class TLocaleApplication : public TApplication
|
|
{
|
|
public:
|
|
TLocaleApplication():TApplication("Intl demo program")
|
|
{
|
|
}
|
|
|
|
void InitMainWindow()
|
|
{
|
|
try
|
|
{
|
|
TLocaleFrame* frame = new TLocaleFrame(new TLocaleWindow);
|
|
TStatusBar* sb = new TStatusBar(frame, TGadget::Recessed);
|
|
frame->Insert(*sb, TDecoratedFrame::Bottom);
|
|
MainWindow = frame;
|
|
MainWindow->SetIcon(this, "World_Icon");
|
|
EnableBWCC(TRUE, LANG_ENGLISH);
|
|
}
|
|
catch(const char *s)
|
|
{
|
|
BWCCMessageBox(0, s, "Intldemo", MB_OK);
|
|
}
|
|
}
|
|
};
|
|
|
|
int OwlMain(int /*argc*/, char* /*argv*/ [])
|
|
{
|
|
return TLocaleApplication().Run();
|
|
}
|