|
C G D P R O G R A M M I N G Version 2006 (c) Jacques Basaldúa |
TYPE
typCGDInternalRelease = Function : longint; StdCall;
typCGDSetOptions = Function (const Opts : cgdOptions;
dlh : THandle) : longint; StdCall;
typCGDGetDefaultOptions = Procedure(var Opts : cgdOptions) StdCall;
typCGDSetCGDFileName = Procedure( fnam : pChar); StdCall;
typCGDDialog = Function ( aParent : hWnd;
Caption,
stNam : pChar;
stSize : longint;
stAddr : pointer) : longint; StdCall;
CONST
cgdInternalRelease : typCGDInternalRelease = nil;
cgdSetOptions : typCGDSetOptions = nil;
cgdGetDefaultOptions : typCGDGetDefaultOptions = nil;
cgdSetCGDFileName : typCGDSetCGDFileName = nil;
cgdDialog : typCGDDialog = nil;
Function LinkCgdLib : boolean;
var opts : cgdOptions;
dllpath : filename;
Obsolete : boolean;
begin
repeat
Obsolete := false;
LinkCgdLib := AdvanceCgdRuntime; if not result then exit;
LinkCgdLib := AdvanceSetupCGD(cgdnam); if not result then exit;
LinkCgdLib := false;
byte(dllpath[0]) := GetSystemDirectory(@dllpath[1], pred(SizeOf(dllpath)));
ValidPath(dllpath);
dllpath := dllpath + 'CgdRun20.DLL';
ZeroStr(dllpath);
SetErrorMode(sem_NoOpenFileErrorBox);
ll := LoadLibrary(@dllpath[1]); if ll=0 then exit;
cgdInternalRelease := GetProcAddress(ll, 'cgdInternalRelease');
if (longint(pointer(@cgdInternalRelease)) = 0)
or (cgdInternalRelease < 8) then Obsolete := true;
if Obsolete then begin
if (not FreeLibrary(ll))
or not WinErase(dllpath) then begin
if MessageBox(hWnd_Desktop,
'The library CGDRUN20.dll has to be replaced. ' +
'It is being used by another program.' + #13+#10 + #13+#10 +
'Close all applications and select <Retry>',
'W A R N I N G',
mb_RetryCancel + mb_IconQuestion) <> id_Retry then exit
end
end
until not Obsolete;
cgdSetOptions := GetProcAddress(ll, 'cgdSetOptions');
cgdGetDefaultOptions := GetProcAddress(ll, 'cgdGetDefaultOptions');
cgdSetCGDFileName := GetProcAddress(ll, 'cgdSetCGDFileName');
cgdDialog := GetProcAddress(ll, 'cgdDialog');
if (longint(pointer(@cgdSetOptions)) = 0)
or (longint(pointer(@cgdGetDefaultOptions)) = 0)
or (longint(pointer(@cgdSetCGDFileName)) = 0)
or (longint(pointer(@cgdDialog)) = 0) then exit
ZeroStr(cgdnam);
cgdSetCGDFileName(@cgdnam[1]);
cgdGetDefaultOptions(opts);
with opts do begin
OpeningLevel := 1;
tbButtons := 1;
txColor := $60a0e0;
bkColor := $400000;
StaticIt.name := 'Times New Roman';
StaticIt.size := 16;
StaticIt.Italic:= false;
EdPathX := 256;
boolMinX := 256;
PreV.doPreview := pvPreviewOnTop;
PreV.pvOnTimer := false;
PreV.pvX := 508;
PreV.pvY := 20;
autoAdjLength := true
end;
cgdSetOptions(opts, dlhModalDialog);
LinkCgdLib := true
end;
If the function
LinkCgdLib()
returns true, CGD has successfully been installed/updated and you can safely
call cgdDialog() to install your application.| Sources at <CGDdirectory>\Pascal\Examples\Hello\Hello.pas |
PROGRAM HELLO;
USES cgdTypes;{<STARTDLG CGD20>}
TYPE
{<DIALOG HelloDialog>}
HelloDialog = packed record
{<BLANKLINE>}
{> My first CGD dialog.} {<LBOLD>}
{<BLANKLINE>}
Speed : single;
more : single {>An other field}
end;
{<ENDDIALOGS>}
VAR aDia : HelloDialog;
BEGIN
cgdSetCGDFileName('.\hello');
aDia.speed := 100;
aDia.more := 0;
cgdDialog(0, 'My first dialog !', 'HelloDialog', SizeOf(HelloDialog), @aDia)
END.
Function cgdDialog (aParent : hWnd;
Caption,
stNam : pChar;
stSize : longint;
stAddr : pointer) : longint; StdCall;
aParent
a valid Window ID. As in many Windows API functions (e.g. MessageBox): "Identifies the owner window of the message box to be created. If this
parameter is NULL, the message box has no owner window."| Sources at <CGDdirectory>\Pascal\Examples\Controls\Controls.pas |
PROGRAM CONTROLS;
USES cgdTypes;
{<STARTDLG CGD20>}
TYPE
{<DIALOG ControlsDemo>}
Locate the following lines:
ud : cgdListBox; {>User defined}
color : cgdColor;
fil : cgdFileName;
pat : cgdPath;
Today : Date;
Now : Time;
Here : Point2;
TheMoon : Point3
This example is very
similar to the previous example, except by the types used. It uses:
enumerations,
conditionals and the following structured types:
cgdListBox = packed record
opt : byte; // The (0-based) option selected.
TextList : string [254] // The (#0-separated) descriptions, ended by a double #0.
end;
cgdColor = packed record
rgb : longint // A Windows ColorRef (as in CreatePen(), ...).
end;
cgdFileName = packed record
name, // File name.
DefDir, // Default directory.
ExtDescr : string []; // (#0-separated) extension descriptions, ended by a double #0.
fOpen, // True = open dialog, else save dialog. (GetOpenFileName() or GetSaveFileName())
cOver : boolean; // True = Prompt on overwrite (= Windows flag ofn_OverwritePrompt).
uSelFmt : integer // On return: (0-based) File format selected by the user from the ExtDescr list
end;
cgdPath = packed record
name, // Directory name.
Caption : string [] // Message displayed when the Windows dialog shows up.
end;
Four more types are used
to "concentrate" many variables in a single line:
Date = packed record
yy,mm,dd : integer
end;
Time = packed record
hh,mm,ss : integer
end;
2D and 3D
positions and vectors: (Note: Points and vectors many use unit conversion following
isMetric)
Point2 = packed record
x,y : single
end;
Point3 = packed record
x,y,z : single
end;
| Sources at <CGDdirectory>\Pascal\Examples\Options\Options.pas |
cgdGetDefaultOptions(opt);
with opt do begin
OpeningLevel := 1;
tbButtons := tbOEUDeplRetr;
txColor := $800000;
bkColor := $c0c0c0;
hasDlgFrame := false;
ColorLighter := $3f3f;
EditBkColor := $20a0c0;
EditTxColor := $80;
EditFnt.size := 16;
EditFnt.Bold := true;
RadioFnt.size:= 18;
RadioFnt.Bold:= true;
ComboFnt.name:= 'Courier New';
ComboFnt.size:= 22;
BoolMinX := 180;
RadioMinX := 180;
ComboMinX := 180;
EdStringX := 180;
EdNumberX := 180;
ColorSampX := 94;
autoAdjLength:= true
end;
cgdSetOptions(opt, dlhModalDialog);
CGDTranslateBuiltInMsgs(cgdMsgsInSpanish);
cgdDialog(0, 'Just change some options and . . .', 'ControlsDemo', SizeOf(ControlsDemo), @aDia)
Many CGD settings: fonts, colors, etc. can be changed. This is valid
for both modal and modeless dialogs. Therefore, changing options requires a dialog handle. For
modal dialogs, use the constant dlhModalDialog as a handle. Two possible ways of changing the options are:
cgdLexical = packed record
invNum : string [47]; // 'Warning : Invalid number format or range'
noSuch : string [47]; // 'Failed : No such record in the clipboard'
AnyFil : string [47]; // 'Any file'
RidNly : string [47]; // 'Record is read only!';
OkButt : string [47]; // 'Accept current values = <Enter>'
EscBtn : string [47]; // 'Escape without modifying = <Esc>'
UndoBt : string [47]; // 'Undo all changes'
DeplBt : string [47]; // 'Deploy all'
RetrBt : string [47]; // 'Retract all'
CopyBt : string [47]; // 'Copy full record'
PasteB : string [47]; // 'Paste full record'
PreviB : string [47] // 'Preview with current values'
end;
| Sources at <CGDdirectory>\Pascal\Examples\Direct\Direct.pas |
PROGRAM DIRECT;
USES cgdTypes;
{<STARTDLG CGD20>}
TYPE
{<DIALOG HelloDialog>}
HelloDialog = packed record
{<BLANKLINE>}
{> Showing the direct use of CGD via}
{> cgdSetDialogDataDirectly() } {<LBOLD>}
{<BLANKLINE>}
Speed : single;
more : single {>An other field}
{<BLANKLINE>}
end;
{<ENDDIALOGS>}
CONST DirDialog : array [0..241] of char
= 'Codeless Generic Dialog - V2.0'+#26+#0+#11+'HELLODIALOG'+#0+#0
+ #0+#0+#0+#0+#0+#0+#7+#0+#0+#0+#0+#0+#3+#0+#1+'›'+#1+'('+#0+#1
+ '›'+#1+'‡# Showing the direct use of CGD via&'+#0+#1+'‘€'+#255
+ '‰'+#1+'‡'+#30+' cgdSetDialogDataDirectly() '+#3+#0+#1+'›'+#1
+ '%'+#0+#1+'?'+#4+'?'+#6+'‡'+#5+'Speed'+#255+'£€ŠIl;€‚u€° €Ô€ŠIl;€‚'
+ 'u€°T.'+#0+#1+'?'+#4+'?'+#6+'‡'+#14+'An other field'+#255+'š€ŠIl;'
+ '€‚u€°€Ô€ŠIl;€‚u€°T'+#3+#0+#1+'›'+#1;
VAR aDia : HelloDialog;
BEGIN
aDia.speed := 100;
aDia.more := 0;
cgdSetDialogDataDirectly(@DirDialog, SizeOf(DirDialog), 'HelloDialog');
cgdDialog(0, 'No CGD file used to display this !', 'HelloDialog', SizeOf(HelloDialog), @aDia)
END.
If, for some reason
(as displaying a dialog in a setup program, displaying a dialog from inside a .dll, etc.), you think that having an external .cgd file is
annoying, you can transfer its binary image directly to the dll.| Sources at <CGDdirectory>\Pascal\Examples\Evaluate\Evaluate.pas |
PROGRAM EVALUATE;
USES WinTyp32, Win32, cgdTypes;
{<STARTDLG CGD20>}
TYPE
pGuessDialog = ^GuessDialog;
{<DIALOG GuessDialog>}
GuessDialog = packed record
{<BLANKLINE>}
{> Guess a number from 1 to 100 !} {<LBOLD>}
{> (And Press <Enter>)} {<LITALIC>}
{<BLANKLINE>}
secret : integer; {<PRIVATE>}
guess : integer {>Your guess} {<MIN 1>} {<MAX 100>}
{<BLANKLINE>}
end;
{<ENDDIALOGS>}
Function MyEvaluateCallback( myStruc : pGuessDialog;
var Help : string;
pWinObject : pointer) : boolean; StdCall;
begin
MyEvaluateCallback := false;
if myStruc^.guess > myStruc^.secret then Help := 'Guess is too high !'
else begin
if myStruc^.guess < myStruc^.secret then Help := 'Guess is too low !'
else MyEvaluateCallback := true
end
end;
VAR aDia : GuessDialog;
BEGIN
cgdSetCGDFileName('.\evaluate');
Randomize;
aDia.secret := succ(Random(100));
aDia.guess := 50;
cgdSetEvaluationCallback (@MyEvaluateCallback, dlhModalDialog);
if cgdDialog(hWnd_Desktop, '...', 'GuessDialog', SizeOf(GuessDialog), @aDia) = cgdRunOk
then MessageBox(hWnd_Desktop, 'Your guess was right!', 'Ok.', mb_Ok)
END.
| Sources at <CGDdirectory>\Pascal\Examples\Viewdemo\Viewdemo.pas |
PROGRAM VIEWDEMO;
USES WinTyp32, Win32, cgdTypes;
{<STARTDLG CGD20>}
// ... see viewdemo.pas
{<DIALOG Preview>}
// ... see viewdemo.pas
{<ENDDIALOGS>}
Procedure PreviewProc ( pStruc : pPreview;
pReason : longint;
const drs : TDrawItemStruct;
var Help : string;
pWinObject : pointer); StdCall;
begin
// ... see viewdemo.pas
end;
VAR aDia : Preview;
opt : cgdOptions;
BEGIN
cgdSetCGDFileName('.\viewdemo');
cgdGetDefaultOptions(opt);
with opt do begin
PreV.doPreview := pvPreviewOnTop;
PreV.pvOnEdChng:= true;
PreV.pvX := 512;
PreV.pvY := 320
end;
cgdSetOptions(opt, dlhModalDialog);
cgdSetViewerCallback(@PreviewProc, dlhModalDialog);
with aDia.town do begin
// ... see viewdemo.pas
end;
cgdDialog(hWnd_Desktop, 'This dialog has a preview method', 'Preview', SizeOf(Preview), @aDia)
END.
This is a
particular case of callback function which justifies an example by itself.
Procedure PreviewProc ( pStruc : pPreview;
pReason : longint;
const drs : TDrawItemStruct;
var Help : string;
pWinObject : pointer); StdCall;
pStruc Pointer to the record data.
| Sources at <CGDdirectory>\Pascal\Examples\Bitmaps\Bitmaps.pas |
{<STARTDLG CGD20>}
TYPE
{<DIALOG BitmapDemo>}
BitmapDemo = packed record
{<BLANKLINE>}
{> This bitmap is NOT conditional} {<LBOLD>}
{<CBITMAP 1001 >} {<BITMAPSHIFTX -4>}
{<BLANKLINE>}
{> This bitmap is conditional} {<LBOLD>}
{<ALIAS Selector>} {\}
sel1 : (First, Second); {>Select the} {>>case}
{<CASE Selector = 0>} {\}
{<CBITMAP 1002 >} {<BITMAPSHIFTX -4>}
{<CASE Selector = 1>} {\}
{<CBITMAP 1003 >} {<BITMAPSHIFTX -4>}
{<BLANKLINE>}
{> This bitmap is application-owned } {<LBOLD>}
{<LBITMAP APPOWNED 1004>} {<BITMAPSHIFTX 6>}
{<BLANKLINE>}
end;
{<ENDDIALOGS>}
| Sources at <CGDdirectory>\Pascal\Examples\Modeless\Modeless.pas |
PROGRAM MODELESS;
// ... see modeless.pas
Procedure mlAppWindow.SetupWindow;
begin
// 1. Initialize the record
// ... see modeless.pas
// 2. Init the dialog
GetClientRect(hWindow, dr);
dx := dr.right - dr.left;
dy := dr.bottom - dr.top;
if cgdInitModelessDlg('ControlsDemo', SizeOf(ControlsDemo), dlgHandle ) = cgdInitOk then begin
// 2.a Set the callback to let the <Ok> <Esc> buttons close the dialog (The application in this case)
cgdModelessOkEscCallback(@OkEscCallB, dlgHandle);
// 2.b A good place to change the options ( !! For the dlgHandle, not the dlhModalDialog)
cgdGetDefaultOptions(opts);
// ... see modeless.pas
cgdSetOptions(opts, dlgHandle);
// 2.c Now, show it.
if cgdModelessDlgShow(hWindow , dr.left, dr.top, dx,dy, @aDia, SizeOf(ControlsDemo), dlgHandle, hChildWin, @self)
= cgdInitOk then begin
// ... see modeless.pas
end
end
end;
Destructor mlAppWindow.Done;
begin
if dlgHandle > 0 then begin
// This is the only required part to destroy the dialog and free dlgHandle
cgdModelessDlgClose (dlgHandle, true);
// ... see modeless.pas
end;
TAppWindow.Done
end;
1. What is a modeless CGD dialog?| Sources at <CGDdirectory>\C\Examples\Hello\Hello.dsp |
hello.cpp -> hello(c).pas -> hello(c).cgd
CGD commands are the same commands as in Pascal, but written in a
remark line preceding the line to which they are applied.
//{<CASE Sel1 = 1>}{> An 8 byte real}
double y;
is the same as:
y : double; {<CASE Sel1 = 1>}{> An 8 byte real}
Other differences with the Pascal spec:
enum eSel1
{
AnInteger = 0,
AReal = 1,
ATextLine = 2
};
2.
Pascal strings can be defined as arrays of unsigned char (index zero corresponding to the length).| Sources at <CGDdirectory>\Basic\Examples\Hello\Hello.vbp |
hello.bas -> hello(b).pas -> hello(b).cgd
CGD commands are the same commands as in Pascal, but written in a
remark line preceding the line to which they are applied.
'{<CASE Sel1 = 1>}{> An 8 byte real}
y As Double
is the same as:
y : double; {<CASE Sel1 = 1>}{> An 8 byte real}
Other differences with the Pascal spec:
'{>Sky} NOTE THAT: Private, Public or none are ignored.
Private Enum enSky
Clouded
WithRainbow
ByNight
ByDay
End Enum
2.
Pascal strings can be defined as arrays of byte (index zero corresponding to the length).
You could implement conversion functions such as:
Sub BasToPas(ps() As Byte, s As String)
Dim i As Integer
On Error GoTo NoRedim
ReDim ps(0 To Len(s))
NoRedim:
ps(0) = Len(s)
For i = 1 To ps(0)
ps(i) = Asc(Mid(s, i, 1))
Next i
End Sub
(If you use VB, you
will surely write something much better than this, it is just to understand what I mean.)
Booleans are 16 bit wide
If the size of a field = 0 (MOD 4) align to 4 x i
Else, If the size of a field = 2 (MOD 4) align to 2 x i
Else, don't align
These adjustments can be done in your Basic source files directly.