{ Test of creating a button toolbar.
  Trying to have a Toolbar.
  For this, bitmap has to be handeled.
  In this example, I use resources, defined in the binary file tEx048.res.
  You nee a program like "imagedit.exe" of Delphi to create it.

  For a toolbar, you need one long image, which consist of several
  parts, each will correspond to an image.
  For example, your long image can be 24 pixels high and 17x24 pixel large.
  for  X in [ 0..23], Y in [0..23] you have one button image.
  for  X in [24..47], Y in [0..23] you have a second button image.
  for  X in [48..71], Y in [0..23] you have a third button image.
  etc.
  for  X in [384..407], Y in [0..23] you have the 17th button image.

  You will give this image to the tool bar which will then select
  button images.
  You decide which button image you take and where you place it.

  I find this way of handling a toolbar is very limited.
  Thus I will not continue in this direction...

  See tEx049.pp for the birth of a much more general toolbar.
  --------------------------------------------}
program tEx048;

// 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;

// Add resources
{$R tEx048.res}

type
  PMyWindow = ^TMyWindow;
  TMyWindow = object(TWindow)
  //"""""""""""""""""""""""""
  hToolBar    : HWND; // handle on the toolbar window

  hBMap       : HBITMAP;
  // Created bitmap to put on the buttons
  // Must be memorised, to be deleted when no more necessary.

  constructor Init(strWinTitlePrm:ShortString);
  destructor Done; virtual;

  procedure Test1;
  procedure Test2;
  procedure Test3;

  procedure AddOneButton;
  procedure InsertOneButton;

  procedure DeleteToolBar;
  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);

hToolBar :=0;
hBMap    :=0;

// This line is all what is needed to have a status line.
new(poStatusLine, Init(@Self));
end;  // TMyWindow.Init

destructor TMyWindow.Done;
//========================
// It's useless to define a destructor
begin
// If the Bitmap is no longer needed, delete it.
if (hBMAP <> 0) then DeleteObject(hBMAP);

inherited Done;
end;  // TMyWindow.Done

procedure TMyWindow.Test1;
//========================
// Test to create the button bar from resources.
var
  nn          : integer;
  arButtons   : array[0..10] of TBButton;
begin
for nn:=0 to 3 do with arButtons[nn] do begin
   iBitmap:=nn;      // Zero-based index of button image.
   idCommand:=201+nn;  // Command identifier associated with the button.
   fsState:=TBSTATE_ENABLED; // Button state flags. This member can be a combination of the values listed in
   fsStyle:=TBSTYLE_BUTTON; // Button style.
                            // TBSTYLE_CHECK is another possible style
                            // TBSTYLE_CHECKGROUP also
                            // The TBSTYLE_SEP style creates a small gap between buttons. A button with this style does not receive user input.
   dwData:=0; // Application-defined value.
   iString:=0; // Zero-based index of button string. (not used here)
   end; // for ... with

// Detroy the actual toolbar, if there is one.
if (hToolBar <> 0) then DestroyWindow(hToolBar);

// If the Bitmap is no longer needed, delete it.
if (hBMAP <> 0) then DeleteObject(hBMAP);
hBMAP:=0;

// Create a ToolBar from the resources (tEx048.res),
// A bitmap 96 x 24 has been defined at number 1000.
// thus 4 buttons 24 x 24 can be created.
hToolBar:=CreateToolbarEx(
            hWin, // Handle to the parent window for the toolbar.
            WS_CHILD, // or TBSTATE_ENABLED, // Style of the toolbar window
            2222, // Control identifier for the toolbar. Here I put any number
            4, // Number of button images contained in the bitmap specified by hBMInst and wBMID.
            System.MainInstance, // Module instance with the executable file that contains the bitmap resource.
            1000, // Resource identifier for the bitmap resource. If hBMInst is NULL, this parameter must be a valid bitmap handle.
            @arButtons[0], // Pointer to an array of TBBUTTON structures that contains information about the buttons to add to the toolbar.
            4, // Number of buttons to add to the toolbar.
            24, // Width, in pixels, of the buttons to add to the toolbar.
            24, // Height, in pixels, of the buttons to add to the toolbar.
            24, // Width, in pixels, of the button images to add to the buttons in the toolbar.
            24, // Height, in pixels, of the button images to add to the buttons in the toolbar.
            SizeOf(TBButton) // Size of a TBBUTTON structure.
            );

DBW(1, 'hToolBar=' + ITS(hToolBar));

ShowWindow(hToolBar, SW_SHOWNORMAL);
SendMessage(hToolBar, TB_AUTOSIZE, 0, 0);


{ For another methode, not tested here.
// Must be called to be sure that the  TOOLBARCLASSNAME  has been registered.
InitCommonControls;

hToolBar:=CreateWindowEx(
    0, // extended window style
    TOOLBARCLASSNAME,	// address of registered class name
    NIL, // address of window name
    WS_CHILD or TBSTYLE_TOOLTIPS or CCS_ADJUSTABLE, // window style
    0, // horizontal position of window
    0, // vertical position of window
    100, // window width
    50, // window height
    hWin, // handle of parent or owner window
    0, // handle of menu, or child-window identifier
    System.MainInstance, // handle of application instance
    NIL // address of window-creation data
    );

// Mus specity the size of the TBBUtton structure.
SendMessage(hToolBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);

This variable will be usefull to add the bitmap image. Not tested here
var tbab : TBADDBITMAP;
}
end;  // TMyWindow.Test1

procedure TMyWindow.Test2;
//========================
// Test to create the button bar from a bitmap image
var
  nn          : integer;
  arButtons   : array[0..10] of TBButton;
  hBMPL       : HBITMAP;

begin
for nn:=0 to 2 do with arButtons[nn] do begin
   iBitmap:=nn;      // Zero-based index of button image.
   idCommand:=201+nn;  // Command identifier associated with the button.
   fsState:=TBSTATE_ENABLED; // Button state flags. This member can be a combination of the values listed in
   fsStyle:=TBSTYLE_BUTTON; // Button style.
                            // TBSTYLE_CHECK is another possible style
                            // TBSTYLE_CHECKGROUP also
                            // The TBSTYLE_SEP style creates a small gap between buttons. A button with this style does not receive user input.
   dwData:=0; // Application-defined value.
   iString:=0; //??? // Zero-based index of button string.
   end; // for ... with

// The easy way to have a bitmap image. Loading it from resources.
hBMPL:=LoadBitmap(System.MainInstance, 1000);

// Detroy the actual toolbar, if there is one.
if (hToolBar <> 0) then DestroyWindow(hToolBar);

// If the Bitmap is no longer needed, delete it.
if (hBMAP <> 0) then DeleteObject(hBMAP);
hBMAP:=0;

// Create a ToolBar from the resources (tEx048.res),
// A bitmap 96 x 24 has been defined at number 1000.
// thus 4 buttons 24 x 24 can be created.
hToolBar:=CreateToolbarEx(
            hWin, // Handle to the parent window for the toolbar.
            WS_CHILD, // or TBSTATE_ENABLED, // Style of the toolbar window
            2222, // Control identifier for the toolbar. An number
            3, // Number of button images contained in the bitmap specified by hBMInst and wBMID.
            0, // 0 means that the next field is a handle on a bitmap.
            hBMPL, // Resource identifier for the bitmap resource. If hBMInst is NULL, this parameter must be a valid bitmap handle.
            @arButtons[0], // Pointer to an array of TBBUTTON structures that contains information about the buttons to add to the toolbar.
            3, // Number of buttons to add to the toolbar.
            24, // Width, in pixels, of the buttons to add to the toolbar.
            24, // Height, in pixels, of the buttons to add to the toolbar.
            24, // Width, in pixels, of the button images to add to the buttons in the toolbar.
            24, // Height, in pixels, of the button images to add to the buttons in the toolbar.
            SizeOf(TBButton) // Size of a TBBUTTON structure.
            );

DBW(1, 'hToolBar=' + ITS(hToolBar));

ShowWindow(hToolBar, SW_SHOWNORMAL);
SendMessage(hToolBar, TB_AUTOSIZE, 0, 0);
end;  // TMyWindow.Test2

procedure TMyWindow.Test3;
//========================
// Test to create the button bar from a bitmap image
// First draw the bitmap image, then put it in the button bar.
// We saw in tEx020.pp how to create a bitmap. We do it again here.
var
  nn          : integer;
  arButtons   : array[0..10] of TBButton;

  hBMapOld    : HBITMAP; // to define a new Hatch
  hDCWin,     // Device context of the window
  hDCMem      : HDC; // to draw the new pattern in a memory device context
  hBRRed,
  hBRGreen,
  hBRBlue
              : HBRUSH; // which brush style to use
  rRec        : RECT;

begin
// If the Bitmap is no longer needed, delete it.
if (hBMAP <> 0) then DeleteObject(hBMAP);
hBMAP:=0;

// Drawing a bitmap
//"""""""""""""""""
// create first a bitmap, compatible with the used device context
// of a given size. It will be created in memory.
hDCWin:=GetDC(hWin);
hBMap:=CreateCompatibleBitmap(hDCWin, 96,24); // 96,24 = width, height

// We don't need the window DC
ReleaseDC(hWin, hDCWin);

// you must create a memory device context, do draw in the bitmap
hDCMem:=CreateCompatibleDC(hDCWin);

// to draw on the bit map, select it in the memory device context.
// remember the original bitmap used.
hBMapOld:=SelectObject(hDCMem, hBMap);

// To fill with red, create a red brush.
hBRRed:=CreateSolidBrush(RGB(255, 0, 0));

// fill the bitmap with the red color
rRec.Left   := 0;
rRec.Top    := 0;
rRec.Right  := 24;
rRec.Bottom := 24;
FillRect(hDCMem, rRec, hBRRed);

// The created brush must be deleted.
DeleteObject(hBRRed);

// put a black text over the red color
SetTextColor(hDCMem, RGB(0,0,0)); // Not necessary, it is already black
//SetBkColor(hDCMem, RGB(255,0,0)); // one possibility
SetBkMode(hDCMem, TRANSPARENT);    // another possibility
TextOut(hDCMem, 8, 4, 'A', 1); // 1 = length of the string

// To fill with green, create a green brush.
hBRGreen:=CreateSolidBrush(RGB(0, 255, 0));

// fill the bitmap with the green color
rRec.Left   := 24;
rRec.Top    := 0;
rRec.Right  := 2*24;
rRec.Bottom := 24;
FillRect(hDCMem, rRec, hBRGreen);

// The created brush must be deleted.
DeleteObject(hBRGreen);

// put a black text over the green color
//SetTextColor(hDCMem, RGB(0,0,0)); // Not necessary, it is already black
SetBkColor(hDCMem, RGB(0,255,0)); // one possibility
//SetBkMode(hDCMem, TRANSPARENT);    // another possibility
TextOut(hDCMem, 24+8, 4, 'B', 1); // 1 = length of the string

// To fill with green, create a blue brush.
hBRBlue:=CreateSolidBrush(RGB(0, 0, 255));

// fill the bitmap with the blue color
rRec.Left   := 2*24;
rRec.Top    := 0;
rRec.Right  := 3*24;
rRec.Bottom := 24;
FillRect(hDCMem, rRec, hBRBlue);

// The created brush must be deleted.
DeleteObject(hBRBlue);

// put a white text over the blue color
SetTextColor(hDCMem, RGB(255,255,255));
//SetBkColor(hDCMem, RGB(255,0,0)); // one possibility
SetBkMode(hDCMem, TRANSPARENT);    // another possibility
TextOut(hDCMem, 2*24+8, 4, 'C', 1); // 1 = length of the string

// This last button is not used yet. It will be used in the add one button
// To fill with green, create a yellow brush.
hBRBlue:=CreateSolidBrush(RGB(255,255,0));

// fill the bitmap with the yellow color
rRec.Left   := 3*24;
rRec.Top    := 0;
rRec.Right  := 4*24;
rRec.Bottom := 24;
FillRect(hDCMem, rRec, hBRBlue);

// The created brush must be deleted.
DeleteObject(hBRBlue);

// put a black text over the yellow color
SetTextColor(hDCMem, RGB(0,0,0));
//SetBkColor(hDCMem, RGB(255,0,0)); // one possibility
SetBkMode(hDCMem, TRANSPARENT);    // another possibility
TextOut(hDCMem, 3*24+8, 4, 'D', 1); // 1 = length of the string

// You must delete the memory device when not used any more.
// But before, select the original bitmap associated with it at creation.
SelectObject(hDCMem, hBMapOld);
DeleteDC(hDCMem);

for nn:=0 to 2 do with arButtons[nn] do begin
   iBitmap:=nn;      // Zero-based index of button image.
   idCommand:=201+nn;  // Command identifier associated with the button.
   fsState:=TBSTATE_ENABLED; // Button state flags. This member can be a combination of the values listed in
   fsStyle:=TBSTYLE_BUTTON; // Button style.
                            // TBSTYLE_CHECK is another possible style
                            // TBSTYLE_CHECKGROUP also
                            // The TBSTYLE_SEP style creates a small gap between buttons. A button with this style does not receive user input.
   dwData:=0; // Application-defined value.
   iString:=0; //??? // Zero-based index of button string.
   end; // for ... with

// Detroy the actual toolbar, if there is one.
if (hToolBar <> 0) then DestroyWindow(hToolBar);

// Create a ToolBar from the resources (tEx048.res),
// A bitmap 96 x 24 has been defined at number 1000.
// thus 4 buttons 24 x 24 can be created.
hToolBar:=CreateToolbarEx(
            hWin, // Handle to the parent window for the toolbar.
            WS_CHILD, // or TBSTATE_ENABLED, // Style of the toolbar window
            2222, // Control identifier for the toolbar. Any number
            3, // Number of button images contained in the bitmap specified by hBMInst and wBMID.
            0, // 0 means that the next field is a handle on a bitmap.
            hBMAP, // bitmap handle.
            @arButtons[0], // Pointer to an array of TBBUTTON structures that contains information about the buttons to add to the toolbar.
            3, // Number of buttons to add to the toolbar.
            24, // Width, in pixels, of the buttons to add to the toolbar.
            24, // Height, in pixels, of the buttons to add to the toolbar.
            24, // Width, in pixels, of the button images to add to the buttons in the toolbar.
            24, // Height, in pixels, of the button images to add to the buttons in the toolbar.
            SizeOf(TBButton) // Size of a TBBUTTON structure.
            );

// Do not delete the bitmap. Delete it when no more used.
// DeleteObject(hBMap);

DBW(1, 'hToolBar=' + ITS(hToolBar));

// Show the toolBar, and adjust its size.
ShowWindow(hToolBar, SW_SHOWNORMAL);
SendMessage(hToolBar, TB_AUTOSIZE, 0, 0);
end;  // TMyWindow.Test3

procedure TMyWindow.AddOneButton;
//===============================
var
  rButton     : TBButton;

begin
// To add a button, the bitmap must alrady exist.

with rButton do begin
   iBitmap:=3;      // Zero-based index of button image.
   idCommand:=201+3;  // Command identifier associated with the button.
   fsState:=TBSTATE_ENABLED; // Button state flags. This member can be a combination of the values listed in
   fsStyle:=TBSTYLE_BUTTON; // Button style.
                            // TBSTYLE_CHECK is another possible style
                            // TBSTYLE_CHECKGROUP also
                            // The TBSTYLE_SEP style creates a small gap between buttons. A button with this style does not receive user input.
   dwData:=0; // Application-defined value.
   iString:=0; //??? // Zero-based index of button string.
   end; // for ... with

SendMessage(hToolBar, TB_ADDBUTTONS, 1, LPARAM(@rButton));
end;  // TMyWindow.AddOneButton

procedure TMyWindow.InsertOneButton;
//==================================
var
  rButton     : TBButton;

begin
// To add a button, the bitmap must alrady exist.

with rButton do begin
   iBitmap:=3;      // Zero-based index of button image.
   idCommand:=201+3;  // Command identifier associated with the button.
   fsState:=TBSTATE_ENABLED; // Button state flags. This member can be a combination of the values listed in
   fsStyle:=TBSTYLE_BUTTON; // Button style.
                            // TBSTYLE_CHECK is another possible style
                            // TBSTYLE_CHECKGROUP also
                            // The TBSTYLE_SEP style creates a small gap between buttons. A button with this style does not receive user input.
   dwData:=0; // Application-defined value.
   iString:=0; //??? // Zero-based index of button string.
   end; // for ... with

SendMessage(hToolBar, TB_INSERTBUTTON, 1, LPARAM(@rButton));
end;  // TMyWindow.InsertOneButton

procedure TMyWindow.DeleteToolBar;
//================================
begin
// Detroy the actual toolbar, if there is one.
if (hToolBar <> 0) then DestroyWindow(hToolBar);
hToolBar:=0;

// If the Bitmap is no longer needed, delete it.
if (hBMAP <> 0) then DeleteObject(hBMAP);
hBMAP:=0;
end;  // TMyWindow.DeleteToolBar

function TMyWindow.WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT;
//=============================================================
// Handles the menu messages
Var wNrMenu     : word;
begin
WMCommand := 0; // Default return value when processing a message

if (lPar > 0) and (lPar = hToolBar) then DBW(1, 'From Tool Bar:' + ITS(wPar));

if (lPar <> 0) then begin
   // call the parent WMCommand method.
   WMCommand:=inherited WMCommand(wPar, lPar);
   exit;
   end;

// for the menus,  lPar = 0
//=========================
wNrMenu   := LoWord(wPar);
Case wNrMenu Of
   101 : Test1;
   102 : Test2;
   103 : Test3;
   104 : AddOneButton;
   105 : InsertOneButton;

   109 : DeleteToolBar;

   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.

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

Case wMsg Of
   WM_SIZE : if (hToolBar <> 0) then SendMessage(hToolBar, TB_AUTOSIZE, 0, 0);

   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        : TApplication;
  poMyMainWin : PMyWindow;

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

// Creation of the main window
new(poMyMainWin, Init('tEx048. Test of creating a button toolbar'));

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

