{ Example of program using the units
  wApplication0.pp  and  wWindow0.pp
  This example show how to create control window, like
  edit boxes, buttons, scroller, combo boxes, list boxes

  Normally they are used in a Dialog Box, but they can also be put
  in any normal window.

  To use the default behaviour, it is quit simple, but
  to change the default colors, it becomes complicate.

  The object library will simplify all this.

  Examples tEx016.pp and tEx017.pp shows it.
  Examples tEx023.pp show how to create a dialog box containing the
    controls. Simplifications will come later, end of january 2002.

  Later we will show the use of Dialog Boxes.
  --------------------------------------------}
program tEx014;

// To tell FreePascal that the application is a Graphical User Interface
// i.e. is running in windows, not in text mode.
{$APPTYPE GUI}

Uses
  Windows
 ,wGlobals2
 ,wApplication0
 ,wWindow0
 ,wDebug0;

const
  SEVEN = 7;
  THREE = 3;

type
  PMyWindow = ^TMyWindow;
  TMyWindow = object(TWindow0)
  //""""""""""""""""""""""""

  hButton1 : HWND;
  // handle on a button

  hButtonQuit : HWND;
  // handle on quit button

  ahRadioB : array[1..SEVEN] of HWND;
  // SEVEN radio buttons

  ahCheckB : array[1..THREE] of HWND;
  // THREE check boxes

  hStatic1 : HWND;
  // a static text

  hEdit1 : HWND;
  // an edit text

  hCombo1 : HWND;
  // a combo box. A DropDown one.

  hCombo2 : HWND;
  // a combo box. A DropDownList one.

  colBack : ColorRef;
  // color of the background of the window.

  constructor Init(strWinTitlePrm:ShortString);

  procedure MenuCreate; virtual;
  // Add a menu to the window

  procedure WinCreate(strWinClass:ShortString); virtual;
  // When creating the window, controls will be added.

  function WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles the menu messages

  function WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  end; // TMyWindow = object(TWindow)

// var nNotUsed : integer; // only to avoid an error message while compliling in DevPascal 1.9

constructor TMyWindow.Init(strWinTitlePrm:ShortString);
//=====================================================
begin
inherited Init(strWinTitlePrm);

// color of the background of the window.
colBack :=-2;  // default (set in this program) = desktop color,
end;  // TMyWindow.Init

procedure TMyWindow.MenuCreate;
//=============================
var
  hSubMenu    : HMenu;
begin
hMenuWin := CreateMenu;

hSubMenu := CreateMenu;
AppendMenu(hSubmenu,MF_STRING,100,'&Open debug window');
AppendMenu(hSubmenu,MF_STRING,101,'&1 A debug msg');
AppendMenu(hSubmenu,MF_SEPARATOR,0,Nil);
AppendMenu(hSubMenu,MF_String, 200, 'E&xit');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&File');

hSubMenu := CreateMenu;
AppendMenu(hSubmenu,MF_STRING, 401, '&Info...');
AppendMenu(hSubmenu,MF_STRING, 402, 'Info on the "&trans" button...');
AppendMenu(hSubmenu,MF_STRING, 403, 'Info on the check boxes...');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&Help');
end;  // TMyWindow.MenuCreate

procedure TMyWindow.WinCreate(strWinClass:ShortString);
//=====================================================
// Creates a new window.
// with controls in it.
var
  strS,       // To add strings in the combo box
  strLabel    : string[30];
  dwStyleBtn  : longint;
  rRec        : RECT;
  nn          : integer;
//  lColor      : longint;

Begin
inherited WinCreate(strWinClass);

strLabel    :='First button' + #0;  // must add the #0 to send it to window.
dwStyleBtn  :=WS_VISIBLE or WS_CHILD or BS_PUSHBUTTON;

// add a button in the window.
hButton1:=CreateWindow(
     'BUTTON',  // predefined class to create a button
     @strLabel[1],  // text shown on the button
     dwStyleBtn, // style of the button, see CreateWindow,  BS_... styles
     10, 5,  // X, Y position
     150, 25, // width, height
     hWin, // handle on the parent window
     0,    // handle on the menu, there are no menu for this little button window
     System.MainInstance, // instance of the application
     NIL  // address of window creation data, not needed for buttons
     );

// You can set the button identifier as follow, but you are not obliged.
// You should avoid using a menu number
SetWindowLong(hButton1, GWL_ID, 111);

// Then, when this button is clicked on, it will send a WM_COMMAND to
// its parent, i.e. the main window, with
// HiWord(wPar) = BN_CLICKED
// LoWord(wPar) = button identifier = 111 in this case.
// lPar = hButton1 = the handle of the button.
// Other notification can be :
// HiWord(wPar) = BN_DBCLICK
// HiWord(wPar) = BN_KILLFOCUS
// HiWord(wPar) = BN_SETFOCUS

// Creation of a second button
//''''''''''''''''''''''''''''
// Placed at the bottom right.

// Gets the main window size
GetClientRect(hWin, @rRec);

strLabel    :='Quit' + #0;  // must add the #0 to send it to window.
dwStyleBtn  :=WS_VISIBLE or WS_CHILD or BS_PUSHBUTTON; // or BS_OWNERDRAW;

// add a button in the window.
hButtonQuit:=CreateWindow(
     'BUTTON',  // predefined class to create a button
     @strLabel[1],  // text shown on the button
     dwStyleBtn, // style of the button, see CreateWindow,  BS_... styles
     rRec.Right - 120,  // X, Y position  It will be changed in WM_SIZE
     rRec.Bottom - 35,  // be carefull to have the same positions here
     100, 25, // width, height              and in WM_SIZE
     hWin, // handle on the parent window
     0,    // handle on the menu, there are no menu for this little button window
     System.MainInstance, // instance of the application
     NIL  // address of window creation data, not needed for buttons
     );

// You can set the button identifier as follow, but you are not obliged.
// You should avoid using a menu number
SetWindowLong(hButtonQuit, GWL_ID, 121);

// Creation of SEVEN radio buttons
//''''''''''''''''''''''''''''''''
// add the SEVEN radio button button in the window.
for nn:=1 to SEVEN do begin
   case nn of
      1 : strLabel:='black' + #0;
      2 : strLabel:='Dgray' + #0;
      3 : strLabel:='gray' + #0;
      4 : strLabel:='Lgray' + #0;
      5 : strLabel:='white' + #0;
      6 : strLabel:='desk' + #0;
      7 : strLabel:='trans' + #0;
      end;

   ahRadioB[nn]:=CreateWindow(
     'BUTTON',  // predefined class to create a button
     @strLabel[1],  // text shown on the button
     WS_VISIBLE or WS_CHILD or BS_AUTORADIOBUTTON,
     70*nn - 60, 35, // X, Y position
     65, 15, // width, height
     hWin, // handle on the parent window
     0,    // handle on the menu, there are no menu for this little button window
     System.MainInstance, // instance of the application
     NIL  // address of window creation data, not needed for buttons
     );

     // You should avoid using a menu number
     SetWindowLong(ahRadioB[nn], GWL_ID, 2000 + nn);
     end;

// Creation of THREE check boxes
//''''''''''''''''''''''''''''''
for nn:=1 to THREE do begin
   case nn of
      1 : strLabel:='red' + #0;
      2 : strLabel:='green' + #0;
      3 : strLabel:='blue' + #0;
      end;

   ahCheckB[nn]:=CreateWindow(
     'BUTTON',  // predefined class to create a button
     @strLabel[1],  // text shown on the button
     WS_VISIBLE or WS_CHILD or BS_CHECKBOX,
     200, 65 + 20*nn, // X, Y position
     65, 15, // width, height
     hWin, // handle on the parent window
     0,    // handle on the menu, there are no menu for this little button window
     System.MainInstance, // instance of the application
     NIL  // address of window creation data, not needed for buttons
     );

     // You should avoid using a menu number
     SetWindowLong(ahCheckB[nn], GWL_ID, 2100 + nn);
     end;

// Creation of a static text
//''''''''''''''''''''''''''
strLabel    :='Simple text' + #0;  // must add the #0 to send it to window.
dwStyleBtn  :=WS_VISIBLE or WS_CHILD
              or SS_CENTER     // text centered in his rectangle
//              or SS_WHITERECT
//              or SS_GRAYRECT
//              or SS_GRAYFRAME // no background color ???
//              or SS_BLACKRECT; // no background color  ???
              ;
// Add a static test in the window.
// It is not nice. How to have a nicer presentation ?
// With the library it is simple. see tEx017.pp
hStatic1:=CreateWindow(
     'STATIC',  // predefined class to create a button
     @strLabel[1],  // text shown on the button
     dwStyleBtn, // style of the button, see CreateWindow,  BS_... styles
     10, 65,  // X, Y position
     150, 17, // width, height
     hWin, // handle on the parent window
     0,    // handle on the menu, there are no menu for this little button window
     System.MainInstance, // instance of the application
     NIL  // address of window creation data, not needed for buttons
     );

// Creation of an Edit text
//'''''''''''''''''''''''''
strLabel    :='Edit text' + #0;  // must add the #0 to send it to window.
dwStyleBtn  :=WS_VISIBLE or WS_CHILD
                or ES_AUTOHSCROLL
//              or ES_CENTER
//              or ES_RIGHT
//              or ES_MULTILINE
//              or ES_NOHIDESEL
//              or ES_WANTRETURN;
              ;
hEdit1:=CreateWindow(
     'EDIT',  // predefined class to create a button
     @strLabel[1],  // text shown on the button
     dwStyleBtn, // style of the button, see CreateWindow,  BS_... styles
     10, 95,  // X, Y position
     120, 20, // width, height
     hWin, // handle on the parent window
     0,    // handle on the menu, there are no menu for this little button window
     System.MainInstance, // instance of the application
     NIL  // address of window creation data, not needed for buttons
     );

// Creation a combo box. . A DropDown one.
//''''''''''''''''''''''''''''''''''''''''
strLabel    :='Combo' + #0;  // must add the #0 to send it to window.
dwStyleBtn  :=WS_VISIBLE or WS_CHILD
                or CBS_AUTOHSCROLL
                or CBS_DROPDOWN
//                or CBS_SIMPLE
//                or CBS_DROPDOWNLIST
//                or CBS_SORT
//                or CBS_UPPERCASE
              ;
hCombo1:=CreateWindow(
     'COMBOBOX',  // predefined class to create a button
     @strLabel[1],  // text shown on the button
     dwStyleBtn, // style of the button, see CreateWindow,  BS_... styles
     10, 125,  // X, Y position
     120, 190, // width, height. Height only when it is opened.
     hWin, // handle on the parent window
     0,    // handle on the menu, there are no menu for this little button window
     System.MainInstance, // instance of the application
     NIL  // address of window creation data, not needed for buttons
     );

// You can set the button identifier as follow, but you are not obliged.
// You should avoid using a menu number
SetWindowLong(hCombo1, GWL_ID, 122);

// Adding strings in the combo box
strS:='first line' + #0;
SendMessage(hCombo1, CB_ADDSTRING, 0, LPARAM(@strS[1]));
strS:='second line' + #0;
SendMessage(hCombo1, CB_ADDSTRING, 0, LPARAM(@strS[1]));
strS:='third line' + #0;
SendMessage(hCombo1, CB_ADDSTRING, 0, LPARAM(@strS[1]));
strS:='fourth line' + #0;
SendMessage(hCombo1, CB_ADDSTRING, 0, LPARAM(@strS[1]));

// Sets the current selection. 2 => third line (0 = first line)
SendMessage(hCombo1, CB_SETCURSEL, 2, 0);

// Creation a combo box. . A DropDownList one.
//''''''''''''''''''''''''''''''''''''''''''''
strLabel    :='Combo' + #0;  // must add the #0 to send it to window.
dwStyleBtn  :=WS_VISIBLE or WS_CHILD
//                or CBS_AUTOHSCROLL
//                or CBS_DROPDOWN
//                or CBS_SIMPLE
                or CBS_DROPDOWNLIST
//                or CBS_SORT
//                or CBS_UPPERCASE
//                or ES_WANTRETURN;
              ;
hCombo2:=CreateWindow(
     'COMBOBOX',  // predefined class to create a button
     @strLabel[1],  // text shown on the button
     dwStyleBtn, // style of the button, see CreateWindow,  BS_... styles
      10, 155,  // X, Y position
     170, 240, // width, height. Height only when it is opened.
     hWin, // handle on the parent window
     0,    // handle on the menu, there are no menu for this little button window
     System.MainInstance, // instance of the application
     NIL  // address of window creation data, not needed for buttons
     );

// You can set the button identifier as follow, but you are not obliged.
// You should avoid using a menu number
SetWindowLong(hCombo2, GWL_ID, 123);

// Adding strings in the combo box
strS:='Line 0' + #0;
nn:=SendMessage(hCombo2, CB_ADDSTRING, 0, LPARAM(@strS[1]));
strS:='Line 1' + #0;
nn:=SendMessage(hCombo2, CB_ADDSTRING, 0, LPARAM(@strS[1]));
strS:='Line 2' + #0;
nn:=SendMessage(hCombo2, CB_ADDSTRING, 0, LPARAM(@strS[1]));
strS:='Line 3' + #0;
nn:=SendMessage(hCombo2, CB_ADDSTRING, 0, LPARAM(@strS[1]));

// Sets the current selection. (0 = first line)
nn:=SendMessage(hCombo2, CB_SETCURSEL, 0, 0);
End;  // TMyWindow.WinCreate

function TMyWindow.WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT;
//=============================================================
// Handles the menu messages
Var
  wNoticode,  // notification code, from a child window.
  wID,        // identification of the button
  wNrMenu     : word;
  rRec        : RECT;
  nn          : integer;
  strS        : string[80];

begin
WMCommand:=0;  // default return value
wNotiCode := HiWord(wPar);
wID       := LoWord(wPar);

if (wNotiCode = BN_CLICKED) then begin
   // a button has been clicked.
   DBW0(1, 'Click on ' + ITS(wID) + '  lPar=' + ITS(lPar));

   if (wID = 111) then
      DBW0(2, 'handle  =' + ITS(lPar) + ' = ' + ITS(hButton1));

   if (wID = 121) then begin
      DBW0(2, 'handle  =' + ITS(lPar) + ' = ' + ITS(hButtonQuit));
      DBWaitSec(1); // wait one second, before quitting
      PostQuitMessage (0); // Tells the application to quit.
      end;

   if (wID >= 2001) and (wID <= 2000 + SEVEN) then begin
      // A radio button has been pressed.
      // Changes the background color
      case wID of
         2001 : colBack:=BLACK_BRUSH;
         2002 : colBack:=DKGRAY_BRUSH;
         2003 : colBack:=GRAY_BRUSH;
         2004 : colBack:=LTGRAY_BRUSH;
         2005 : colBack:=WHITE_BRUSH;
         2006 : colBack:=-2; // default.
         2007 : colBack:=-1; // transparent.
         end; // case

      // ask to redraw the background.
      GetClientRect(hWin, @rRec);
      invalidateRect(hWin, rRec, TRUE);
      end;

   if (wID >= 2101) and (wID <= 2100 + THREE) then begin
      // A radio button has been pressed.
      // Gets its state
      nn:=SendMessage(ahCheckB[wID-2100] , BM_GETCHECK, 0, 0);

      // changes its state
      if (nn = 0) then nn:=1 else nn:=0;
      SendMessage(ahCheckB[wID-2100] , BM_SETCHECK, nn, 0);
      end;
   end; // if (wNotiCode = BN_CLICKED) then begin

if (wNotiCode = CBN_DROPDOWN) then begin
   // must open here the combo box.
   if (wID = 122) then begin
//      if gglfDBInitDone then  DBW0(2, 'ComboBox cliked.' + ITS(wPar) + ITS(lPar));
      // else in this very special case, a little problem would occur
      //      if one want to write text with DBW0. Why ?
      end;
   end;

if (wNotiCode = CBN_CLOSEUP) and (wID = 122) then begin
   nn:=SendMessage(hCombo1, CB_GETCURSEL, 0, 0);
   if (nn <> CB_ERR) then begin
      SendMessage(hCombo1, CB_GETLBTEXT, nn, LPARAM(@strs[1]));
      strS[0]:=char(StrLen(@strS[1])); // convert ainsi string to pascal string
      DBW0(1, 'combo1= ' + strS);
      end;
   end;

if (wNotiCode = CBN_CLOSEUP) and (wID = 123) then begin
   nn:=SendMessage(hCombo2, CB_GETCURSEL, 0, 0);
   if (nn <> CB_ERR) then begin
      SendMessage(hCombo2, CB_GETLBTEXT, nn, LPARAM(@strs[1]));
      strS[0]:=char(StrLen(@strS[1])); // convert ainsi string to pascal string
      DBW0(1, 'combo2= ' + strS);
      end;
   end;

if (lPar <> 0) then begin
   WMCommand:=inherited WMCommand(wPar, lPar);
   exit;
   end;

// for the menu, lPar = 0
wNrMenu   := LoWord(wPar);
Case wNrMenu Of
   // these calls to DBW0 can be done from anywhere
   100 : DBW0(0, '');  // just open the debugging window
   101 : DBW0(   1,'1 -> a debugging message');

   200 : PostMessage( hWin,WM_Close,0,0);
   401 : MessageBox( hWin,'These controls uses windows to create them.',
                          'Test of some controls',
                     MB_OK Or MB_IconInformation);
   402 : MessageBox( hWin,'After selecting the "trans" radio button, resize the window...  :-)',
                          'Use of the "trans" radio button.',
                     MB_OK Or MB_IconInformation);
   403 : MessageBox( hWin,'Don''t try to see what the check boxes do. Simply nothing here.',
                          'Unused check boxes',
                     MB_OK Or MB_IconInformation);
   else WMCommand:=inherited WMCommand(wPar, lPar);
   end;  // Case NrMenu Of
end;  // TMyWindow.WMCommand

function TMyWindow.WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//=======================================================================================
// All window messages are send here.
var
  rRec        : RECT;
  hDevC       : HDC;
  hBr         : HBRUSH;  // needed to paint

Begin
WindowProc := 0; // Default return value when processing a message

Case wMsg Of
   WM_ERASEBKGND : begin
      if (colBack = word32(-2)) then begin
         WindowProc:=inherited WindowProc(hWindow, wMsg, wPar, lPar);
         exit;
         end;

      if (colBack = word32(-1)) then begin
         // If you do not call the inherited proc. then the color will be transparent.
//         WindowProc:=inherited WindowProc(hWindow, wMsg, wPar, lPar);
         exit;
         end;

      // change the color of the window background
      // It is quite complicate for a simple task !
      hDevC:=HDC(wPar);  // the handle on the device context is given.
      GetClientRect(hWindow, @rRec);

      // you must get a brush to paint.
      // you could also create a brush with CreateSolidBrush
//      hBr:=GetStockObject(BLACK_BRUSH);
//      hBr:=GetStockObject(DKGRAY_BRUSH);
//      hBr:=GetStockObject(GRAY_BRUSH);
//      hBr:=GetStockObject(LTGRAY_BRUSH);
//      hBr:=GetStockObject(WHITE_BRUSH);
      hBr:=GetStockObject(colBack);

      FillRect(hDevC, rRec, hBr);

      WindowProc:=1; // <> 0 should be returned if backgroud erased.
      end; // WM_ERASEBKGND
   WM_Command     : WindowProc:=WMCommand(wPar, lPar);
   WM_Size : begin
      // get the size of the button.
      GetClientRect(hWindow, @rRec);

      // Moves the quit button to stay in the bottom right place
      MoveWindow ( hButtonQuit, rRec.Right - 120, rRec.Bottom - 35,
                   100, 25,
                   True // True => redraw the button
                   );
      end;
   else begin // Case wMsg Of
      // Default processing of the messages.
      WindowProc:=inherited WindowProc(hWindow, wMsg, wPar, lPar);
      end; // Case wMsg Of
   End; // Case wMsg Of

End;  // TMyWindow.WindowProc

var
  oApp        : TApplication0;
  poMyMainWin : PMyWindow;

Begin // MAIN ******
// Name under which the main window is registered. Spaces are not allowed
oApp.Init('Example014');

// Change the color of the background of the main window.
// to have the desktop color
oApp.WindowClass.hbrBackground :=COLOR_BACKGROUND+1;

// Creation of the main window
new(poMyMainWin, Init('Title of the Example014 (Ex014.pp) Window'));

// The App.WindowClass can be modified here, if wanted. (Not usual)
oApp.Run;
oApp.Done;  // The main window object is disposed here.
End.

