
{                                                                              }
{  IB_ConnectionBar                                                            }
{                                                                              }

{***************************************************************}
{                                                               }
{          IB Objects Components and Resources Library          }
{                                                               }
{          Copyright (C) 1996-2007 Jason Wharton                }
{          and Computer Programming Solutions, Mesa, AZ         }
{                                                               }
{  This source code unit is released under the terms of the     }
{  CPS Trustware License.                                       }
{  It may be distributed or deployed as source code or in       }
{  compiled form only in compliance with the terms and          }
{  conditions of the CPS Trustware License which may be         )
{  examined at http://www.ibobjects.com/ibo_trustware.html      )
{                                                               }
{***************************************************************}

{******************************************************************************}
{  CONTRIBUTED MODIFICATIONS                                                   }
{  Additions or modifications listed below using format:                       }
{                                                                              }
{  Joe Citizen <joe@joecitizen.com>                                            }
{  mm/dd/yyyy                                                                  }
{     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                 }
{     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                 }
{     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                 }
{            Copyright (C) 2001 Joe Citizen                                    }
{                                                                              }
{------------------------------------------------------------------------------}
{  Place your credits and information in the top of the section                }
{  below with any other descriptions or explanations desired.                  }
{------------------------------------------------------------------------------}
{  Salvatore Besso <s.besso@mclink.it>                                         }
{  21-Jul-2006                                                                 }
{     Normalized procedure ResetButtonState so that it is the same in all      }
{     IB....bar.pas files. Made this change because not all bars worked with   }
{     custom glyphs                                                            }
{------------------------------------------------------------------------------}
{  Rade Vojvodic <rvojvodic@rsdef.org>                                         }
{  12/14/2005                                                                  }
{     Added propery ShowCaptions to enable Captions on the Bar                 }
{     Captions are to be read from IB_Constants.pas                            }
{            Copyright (C) 2005 Rade Vojvodic                                  }
{------------------------------------------------------------------------------}
{  Rade Vojvodic <rvojvodic@rsdef.org>                                         }
{  12/14/2005                                                                  }
{     Added protected CalcMinSize procedure and Changed AdjSize                }
{     procedure to work like in TDbNavigator. Buttons are placed               }
{     correctly in the bar                                                     }
{            Copyright (C) 2005 Rade Vojvodic                                  }
{------------------------------------------------------------------------------}
{                                                                              }
{******************************************************************************}

{$INCLUDE IB_Directives.inc}

{: This unit contains the TIB_ConnectionBar component. }
unit
  IB_ConnectionBar;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Controls, StdCtrls,
  Forms, Graphics, ExtCtrls, Menus, Buttons, Dialogs, Math,

  IB_Constants,
  IB_Components,
  IB_ConnectionSource;

type
{: These are the different button types available to this button bar.

cbCreate will create a database.
cbDrop will physically remove a database from the server.
cbConnect will connect to a database.
cbDisconnect will disconnect from the database there is a live connection with.}
TIB_ConnectionBar_ButtonType = ( cbCreate,
                                 cbDrop,
                                 cbConnect,
                                 cbDisconnect );
                                 
{: Set of button types for this button bar.}
TIB_ConnectionBar_ButtonSet = set of TIB_ConnectionBar_ButtonType;
 
{: This is the button class definition that is used internally.}  
TIB_ConnectionBar_Button = class;

{: This enables the order of the buttons on the toolbar to be customized.}  
TIB_ConnectionBar_ButtonsOrder = array[0..3] of TIB_ConnectionBar_ButtonType;

//------------------------------------------------------------------------------
// Here's where the customized stuff begins
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Here's where the customized stuff ends
//------------------------------------------------------------------------------


{: This control is used to provide an easy way to allow a user to create,
connect, disconnect or drop a database.
<br><br>
See IB_SQL sample application for an example of its usage.}  
TIB_ConnectionBar = class (TCustomPanel)
{$I IB_Bars.INT}
private
  FVisibleButtons: TIB_ConnectionBar_ButtonSet;
  FCustomGlyphsSupplied: TIB_ConnectionBar_ButtonSet;
  FFocusedButton: TIB_ConnectionBar_ButtonType;
  FButtonsOrder: TIB_ConnectionBar_ButtonsOrder;
  procedure SetVisible(Value: TIB_ConnectionBar_ButtonSet);
  procedure SetCustomGlyphsSupplied(Value: TIB_ConnectionBar_ButtonSet);
  function GetButtonsOrder(Index: Integer): TIB_ConnectionBar_ButtonType;

public

{: Storage array for the different buttons on this button bar. }
  Buttons: array[TIB_ConnectionBar_ButtonType] of TIB_ConnectionBar_Button;

{: Method used to pass the click of a single button to the owning parent.}
  procedure BtnClick(Index: TIB_ConnectionBar_ButtonType);

{: The currently selected button of the button set.
<br><br>
Use this property in the xxxxAction events to know which button was clicked.}
  property FocusedButton: TIB_ConnectionBar_ButtonType read FFocusedButton;

{: Allows for customizing the order of the buttons on the button bar.}
  property ButtonsOrder[Index: Integer]: TIB_ConnectionBar_ButtonType
      read GetButtonsOrder;

published

{: Set this property to indicate which glyphs have been supplied in the
CustomGlyphs property.}
  property CustomGlyphsSupplied: TIB_ConnectionBar_ButtonSet
      read FCustomGlyphsSupplied
     write SetCustomGlyphsSupplied;

{: Set which buttons are visible to the user.}
  property VisibleButtons: TIB_ConnectionBar_ButtonSet
      read FVisibleButtons
     write SetVisible
   default [cbConnect, cbDisconnect];
   
// -----------------------------------------------------------------------------
// This is the beginning of the area for the non-template stuff.
// -----------------------------------------------------------------------------

private
  FToggleCreate: boolean;
  FToggleConnect: boolean;
  FIB_ConnectionSource: TIB_ConnectionSource;
  function GetOnReceiveFocus: TIB_ConnectionLinkEvent;
  procedure SetOnReceiveFocus( AValue: TIB_ConnectionLinkEvent );
  function GetReceiveFocus: boolean;
  procedure SetReceiveFocus(AValue: boolean);
  function GetConnection: TIB_Connection;
  procedure SetConnection(AValue: TIB_Connection);
protected
  procedure IB_ConnectionConnectedChanged( CLink: TIB_ConnectionLink;
                                           C: TIB_Connection);


published
{: Connection for which this control will take action for.}
  property IB_Connection: TIB_Connection read GetConnection
                                         write SetConnection;

{: Determine whether or not notification should be received when a new
connection receives focus.}
  property ReceiveFocus: boolean read GetReceiveFocus write SetReceiveFocus;

{: When connected the Disconnect button will be shown; otherwise, the
Connect button will show.
<br><br>
Must also have only one of these buttons in the VisibleButtons property.}
  property ToggleConnect: boolean read FToggleConnect
                                  write FToggleConnect
                                  default false;

{: When connected the Drop button will be shown; otherwise, the
Create button will show.
<br><br>
Must also have only one of these buttons in the VisibleButtons property.}
  property ToggleCreate: boolean read FToggleCreate
                                 write FToggleCreate
                                 default false;

{: Define a custom action when a new connection focus notification is
received.
<br><br>
By default the IB_Connection property of this control is assigned to the
newly focusing connection.}
  property OnReceiveFocus: TIB_ConnectionLinkEvent read GetOnReceiveFocus
                                                   write SetOnReceiveFocus;

// -----------------------------------------------------------------------------
// This is the ending of the area for the non-template stuff.
// -----------------------------------------------------------------------------

end;

TIB_ConnectionBar_Button = class(TSpeedButton)
  private
    FIndex: TIB_ConnectionBar_ButtonType;
  protected
    procedure Paint; override;
  public
    property Index: TIB_ConnectionBar_ButtonType read FIndex write FIndex;
end;

var
  ConnectionBar_Images: TStringList;
  IB_ConnectionBar_ButtonsOrder: TIB_ConnectionBar_ButtonsOrder;
  
implementation

{$R IB_ConnectionBar.RES}

function StandardBitmap( S: String ):tBitmap;
var
  x: integer;
begin
  if ConnectionBar_Images.Find( S, x ) then
    Result := TBitmap( ConnectionBar_Images.Objects[ x ] )
  else
    Result := nil;
end;

procedure FillImages;
var
  i: integer;
  b: TBitmap;
const
  a: array[0..3] of pchar = ( 'CON_BAR_CREATE',
                              'CON_BAR_DROP',
                              'CON_BAR_CONNECT',
                              'CON_BAR_DISCONNECT' );
begin
  for i := low(a) to high(a) do
  begin
    B := TBitmap.Create;
    B.LoadFromResourceName( hinstance, strPas(a[i] ));
    B.Dormant;
{$IFDEF IBO_VCL70_OR_GREATER}
    B.FreeImage;
{$ENDIF}
    ConnectionBar_Images.AddObject( strPas( a[i] ), B );
  end;
end;

constructor TIB_ConnectionBar.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle - [csAcceptsControls, csSetCaption] + [csOpaque];
  if not NewStyleControls then
    ControlStyle := ControlStyle + [csFramed];
  FIB_ConnectionSource := TIB_ConnectionSource.Create( Self );
  with FIB_ConnectionSource do
  begin
    AfterAssignment := IB_ConnectionConnectedChanged;
    OnConnectedChanged := IB_ConnectionConnectedChanged;
  end;
  InitButtonsOrder;
  FVisibleButtons := [cbConnect, cbDisconnect];
  InitButtons;
  BevelOuter := bvNone;
  BevelInner := bvNone;
  Ctl3D := false;
  ParentCtl3D := false;
  Width := 121;
  Height := 25;
  ButtonWidth := 0;
  FFocusedButton := cbConnect;
{$IFDEF IBO_VCL30_OR_GREATER}
  Flat := true; // Hit the property.
{$ENDIF}
end;

destructor TIB_ConnectionBar.Destroy;
begin
  if FCustomGlyphs <> nil then
    FCustomGlyphs.OnChange := nil;
  with FIB_ConnectionSource do
  begin
    AfterAssignment := nil;
    OnConnectedChanged := nil;
  end;
  inherited Destroy;
end;

procedure TIB_ConnectionBar.Notification( AComponent: TComponent;
                                          Operation: TOperation );
begin
  inherited Notification( AComponent, Operation );
  if ( Operation = opRemove ) and ( CustomGlyphs <> nil ) and
     ( AComponent = CustomGlyphs ) then
    CustomGlyphs := nil;
end;

{$IFDEF IBO_VCL30_OR_GREATER}
procedure TIB_ConnectionBar.SetFlat( AValue: boolean );
begin
  if Flat <> AValue then
  begin
    FFlat := AValue;
    Buttons[ cbCreate     ].Flat := Flat;
    Buttons[ cbConnect    ].Flat := Flat;
    Buttons[ cbDisconnect ].Flat := Flat;
    Buttons[ cbDrop       ].Flat := Flat;
  end;
end;
{$ENDIF}

procedure TIB_ConnectionBar.SetShowCaptions(AValue: Boolean);
var
  W, H: Integer;
  I: TIB_ConnectionBar_ButtonType;
begin
  FShowCaptions := AValue;
  for I := Low(Buttons) to High(Buttons) do
  begin
    Buttons[i].Caption := '';
    if FShowCaptions then
    begin
      Buttons[i].Layout := blGlyphTop;
      case I of
        cbCreate:      Buttons[i].Caption := C_CB_CREATE;
        cbConnect:     Buttons[i].Caption := C_CB_CONNECT;
        cbDisconnect:  Buttons[i].Caption := C_CB_DISCONNECT;
        cbDrop:        Buttons[i].Caption := C_CB_DROP;
      end;
    end;
  end;
  W := Width;
  H := Height;
  AdjSize(W,H);
end;

procedure TIB_ConnectionBar.InitButtons;
var
  I: integer;
  Btn: TIB_ConnectionBar_Button;
  X: Integer;
begin
  MinBtnSize := Point(20, 18);
  X := 0;
  for I := Low(TIB_ConnectionBar_ButtonsOrder) to
           High(TIB_ConnectionBar_ButtonsOrder) do
  begin
    Btn := TIB_ConnectionBar_Button.Create (Self);
    Btn.Index := FButtonsOrder[I];
    Btn.Visible := Btn.Index in FVisibleButtons;
    Btn.Enabled := True;
    Btn.SetBounds( X, 0, MinBtnSize.X, MinBtnSize.Y );
    Btn.Enabled := False;
    Btn.Enabled := True;
    Btn.OnClick := BarClick;
    Btn.OnMouseDown := BtnMouseDown;
    Btn.Parent := Self;
    Buttons[Btn.Index] := Btn;
    X := X + MinBtnSize.X;
  end;
  ResetButtonState;
end;

procedure TIB_ConnectionBar.InitHints;
var
  I: TIB_ConnectionBar_ButtonType;
  Btn: TIB_ConnectionBar_Button;
begin
  for I := Low(Buttons) to High(Buttons) do
  begin
    Btn := Buttons[ I ];
    case I of
      cbCreate:     Btn.Hint := H_CB_Create_Database;
      cbConnect:    Btn.Hint := H_CB_Connect_Database;
      cbDisconnect: Btn.Hint := H_CB_Disconnect_Database;
      cbDrop:       Btn.Hint := H_CB_Drop_Database;
    end;
  end;
end;

procedure TIB_ConnectionBar.BtnMouseDown (Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  OldFocus: TIB_ConnectionBar_ButtonType;
begin
  OldFocus := FocusedButton;
  FFocusedButton := TIB_ConnectionBar_Button(Sender).Index;
  if TabStop and (GetFocus <> Handle) and CanFocus then
  begin
    SetFocus;
    if (GetFocus <> Handle) then
      Exit;
  end
  else if TabStop and (GetFocus = Handle) and (OldFocus <> FocusedButton) then
  begin
    Buttons[OldFocus].Invalidate;
    Buttons[FocusedButton].Invalidate;
  end;
end;

procedure TIB_ConnectionBar.SetVisible(Value: TIB_ConnectionBar_ButtonSet);
var
  I: TIB_ConnectionBar_ButtonType;
  W, H: Integer;
begin
  W := Width;
  H := Height;
  FVisibleButtons := Value;
  for I := Low(Buttons) to High(Buttons) do
    Buttons[I].Visible := I in FVisibleButtons;
  AdjSize (W, H);
  if (W <> Width) or (H <> Height) then
    inherited SetBounds (Left, Top, W, H);
  Invalidate;
end;

procedure TIB_ConnectionBar.CalcMinSize(var W, H: Integer);
var
  Count: Integer;
  I: TIB_ConnectionBar_ButtonType;
  t: integer;
begin
  if (csLoading in ComponentState) then Exit;
  if Buttons[cbCreate] = nil then Exit;

  Count := 0;
  for I := Low(Buttons) to High(Buttons) do
    if Buttons[I].Visible then
      Inc(Count);
  if Count = 0 then
    Inc(Count);
  t := Count * MinBtnSize.X;
  if t > W then W := t;
  t := MinBtnSize.Y;
  if t > H then H := t;
  if Align = alNone then W := (W div Count) * Count;
end;

procedure TIB_ConnectionBar.AdjSize (var W: Integer; var H: Integer);
var
  Count: Integer;
  I: TIB_ConnectionBar_ButtonType;
  Space, Temp, Remain: Integer;
  X: Integer;
begin
  if (csLoading in ComponentState) then Exit;
  if Buttons[cbCreate] = nil then Exit;

  CalcMinSize(W, H);

  Count := 0;
  for I := Low(Buttons) to High(Buttons) do
  begin
    if Buttons[I].Visible then
      Inc(Count);
  end;
  if Count = 0 then Inc(Count);

  ButtonWidth := W div Count;
  Temp := Count * ButtonWidth;
  if Align = alNone then W := Temp;

  X := 0;
  Remain := W - Temp;
  Temp := Count div 2;
  for I := Low(Buttons) to High(Buttons) do
  begin
    if Buttons[I].Visible then
    begin
      Space := 0;
      if Remain <> 0 then
      begin
        Dec (Temp, Remain);
        if Temp < 0 then
        begin
          Inc (Temp, Count);
          Space := 1;
        end;
      end;
      Buttons[I].SetBounds (X, 0, ButtonWidth + Space, Height);
      Inc (X, ButtonWidth + Space);
    end
    else
      Buttons[I].SetBounds (Width + 1, 0, ButtonWidth, Height);
  end;
end;

procedure TIB_ConnectionBar.WMSize(var Message: TWMSize);
var
  W, H: Integer;
begin
  inherited;

  { check for minimum size }
  W := Width;
  H := Height;
  AdjSize (W, H);
  if (W <> Width) or (H <> Height) then
    inherited SetBounds(Left, Top, W, H);
  Message.Result := 0;
end;

procedure TIB_ConnectionBar.WMSetFocus(var Message: TWMSetFocus);
begin
  Buttons[FocusedButton].Invalidate;
end;

procedure TIB_ConnectionBar.WMKillFocus(var Message: TWMKillFocus);
begin
  Buttons[FocusedButton].Invalidate;
end;

procedure TIB_ConnectionBar.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  Message.Result := DLGC_WANTARROWS;
end;

procedure TIB_ConnectionBar.CMEnabledChanged(var Message: TMessage);
begin
  inherited;
  if not (csLoading in ComponentState) then
    SysStateChanged;
end;

procedure TIB_ConnectionBar.SysStateChanged;
var
  NewVisibleButtons: TIB_ConnectionBar_ButtonSet;
begin
  if Assigned(IB_Connection) then with IB_Connection do
  begin
    NewVisibleButtons := VisibleButtons;
    if ToggleConnect then
    begin
      if Connected then
      begin
        if     ( cbConnect in VisibleButtons ) and
           not ( cbDisconnect in VisibleButtons ) then
        begin
          NewVisibleButtons := NewVisibleButtons + [ cbDisconnect ] -
                                                   [ cbConnect    ];
        end;
      end
      else
      begin
        if not ( cbConnect in VisibleButtons ) and
               ( cbDisconnect in VisibleButtons ) then
        begin
          NewVisibleButtons := NewVisibleButtons + [ cbConnect    ] -
                                                   [ cbDisconnect ];
        end;
      end;
    end;
    if ToggleCreate then
    begin
      if Connected then
      begin
        if     ( cbCreate in VisibleButtons ) and
           not ( cbDrop in VisibleButtons ) then
        begin
          NewVisibleButtons := NewVisibleButtons + [ cbDrop   ] -
                                                   [ cbCreate ];
        end;
      end
      else
      begin
        if not ( cbCreate in VisibleButtons ) and
               ( cbDrop in VisibleButtons ) then
        begin
          NewVisibleButtons := NewVisibleButtons + [ cbCreate ] -
                                                   [ cbDrop   ];
        end;
      end;
    end;
    VisibleButtons := NewVisibleButtons;
  end;

  if (IB_Connection <> nil) and (Enabled) then
  begin
    Buttons[ cbCreate     ].Enabled := not IB_Connection.Connected;
    Buttons[ cbConnect    ].Enabled := not IB_Connection.Connected;
    Buttons[ cbDisconnect ].Enabled :=     IB_Connection.Connected;
    Buttons[ cbDrop       ].Enabled :=     IB_Connection.Connected;
  end
  else
  begin
    Buttons[ cbCreate     ].Enabled := false;
    Buttons[ cbConnect    ].Enabled := false;
    Buttons[ cbDisconnect ].Enabled := false;
    Buttons[ cbDrop       ].Enabled := false;
  end;

  InitHints;

  if not ( csDestroying in ComponentState ) and
    Assigned( FOnButtonsStateChanged ) then
  begin
    FOnButtonsStateChanged( Self );
  end;

end;

procedure TIB_ConnectionBar.Loaded;
var
  W, H: Integer;
begin
  inherited Loaded;
  W := Width;
  H := Height;
  AdjSize (W, H);
  if (W <> Width) or (H <> Height) then
    inherited SetBounds (Left, Top, W, H);
  SysStateChanged;
end;

procedure TIB_ConnectionBar.KeyDown(var Key: Word; Shift: TShiftState);
var
  NewFocus: TIB_ConnectionBar_ButtonType;
  OldFocus: TIB_ConnectionBar_ButtonType;
begin
  OldFocus := FocusedButton;
  case Key of
    VK_RIGHT:
      begin
        NewFocus := FocusedButton;
        repeat
          if NewFocus < High(Buttons) then
            NewFocus := Succ(NewFocus);
        until (NewFocus = High(Buttons)) or (Buttons[NewFocus].Visible);
        if NewFocus <> FocusedButton then
        begin
          FFocusedButton := NewFocus;
          Buttons[OldFocus].Invalidate;
          Buttons[FocusedButton].Invalidate;
        end;
      end;
    VK_LEFT:
      begin
        NewFocus := FocusedButton;
        repeat
          if NewFocus > Low(Buttons) then
            NewFocus := Pred(NewFocus);
        until (NewFocus = Low(Buttons)) or (Buttons[NewFocus].Visible);
        if NewFocus <> FocusedButton then
        begin
          FFocusedButton := NewFocus;
          Buttons[OldFocus].Invalidate;
          Buttons[FocusedButton].Invalidate;
        end;
      end;
    VK_SPACE:
      begin
        if Buttons[FocusedButton].Enabled then
          Buttons[FocusedButton].Click;
      end;
  end;
end;

procedure TIB_ConnectionBar.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
var
  W, H: Integer;
begin
  W := AWidth;
  H := AHeight;
  AdjSize (W, H);
  inherited SetBounds (ALeft, ATop, W, H);
end;

procedure TIB_ConnectionBar.BtnClick(Index: TIB_ConnectionBar_ButtonType);
begin
  FFocusedButton := Index;
  if Assigned( FBeforeAction ) then
    FBeforeAction( Self );
  if (IB_Connection <> nil) then
  begin
    with IB_Connection do
    begin
      case Index of
        cbCreate:     CreateDatabase;
        cbConnect:    Connect;
        cbDisconnect: Disconnect;
        cbDrop:       DropDatabase;
      end;
    end;
  end;
  if Assigned( FAfterAction ) then
    FAfterAction( Self );
end;

procedure TIB_ConnectionBar.BarClick( Sender: TObject );
begin
  BtnClick(TIB_ConnectionBar_Button(Sender).Index);
end;

procedure TIB_ConnectionBar_Button.Paint;
var
  R: TRect;
begin
  inherited Paint;
  if (GetFocus = Parent.Handle) and
     (FIndex = TIB_ConnectionBar(Parent).FocusedButton) then
  begin
    R := Bounds(0, 0, Width, Height);
    InflateRect(R, -3, -3);
    if FState = bsDown then
      OffsetRect(R, 1, 1);
    DrawFocusRect(Canvas.Handle, R);
  end;
end;

procedure TIB_ConnectionBar.SetCustomGlyphs(Value: TImageList);
begin
  if Assigned( FCustomGlyphs ) then
  begin
    FCustomGlyphs.OnChange := nil;
  end;
  FCustomGlyphs := Value;
  if Assigned( FCustomGlyphs ) then
  begin
    FCustomGlyphs.OnChange := CustomGlyphsChange;
  end;
  ResetButtonState;
end;

procedure TIB_ConnectionBar.CustomGlyphsChange(Sender: TObject);
begin
  if not (csDestroying in ComponentState) then
    ResetButtonState;
end;

procedure TIB_ConnectionBar.SetCustomGlyphsSupplied(Value: TIB_ConnectionBar_ButtonSet);
begin
  if FCustomGlyphsSupplied <> Value then
  begin
    FCustomGlyphsSupplied := Value;
    ResetButtonState;
  end;
end;

procedure TIB_ConnectionBar.ResetButtonState;
var
  j: Integer;
  i: TIB_ConnectionBar_ButtonType;
  TmpGlyph: TBitmap;
begin
  j := 0;
  for i:= low( Buttons ) to high( Buttons ) do
  begin
    if Assigned( FCustomGlyphs ) and
       ( i in CustomGlyphsSupplied ) and
       ( j < FCustomGlyphs.Count ) then
    begin
      TmpGlyph := TBitmap.Create;
      try
        FCustomGlyphs.GetBitmap(j, TmpGlyph);
        Buttons[i].Glyph.Assign(TmpGlyph);
        Buttons[i].Glyph.Dormant;
        Buttons[i].Glyph.FreeImage;
        if ((( TmpGlyph.Width +
               ( TmpGlyph.Width div 3 )) div 2 ) > TmpGlyph.Height ) then
          Buttons[i].NumGlyphs := 2
        else
          Buttons[i].NumGlyphs := 1;
        Buttons[i].Caption := '';
      finally
        TmpGlyph.Free;
      end;
      inc(j);
    end
    else
    begin
      Buttons[i].NumGlyphs := 2;
      with Buttons[i].Glyph do
      begin
        case I of
          cbCreate:     Assign( StandardBitmap( 'CON_BAR_CREATE' ));
          cbDrop:       Assign( StandardBitmap( 'CON_BAR_DROP' ));
          cbConnect:    Assign( StandardBitmap( 'CON_BAR_CONNECT' ));
          cbDisconnect: Assign( StandardBitmap( 'CON_BAR_DISCONNECT' ));
        end;
        Dormant;
        FreeImage;
      end;
    end;
    case Buttons[i].Index of
      cbCreate:
      begin
        Buttons[i].Hint := H_CB_Create_Database;
        Buttons[i].Caption := '';
        if FShowCaptions then
        begin
          Buttons[i].Caption := Buttons[i].Hint;
          Buttons[i].Layout := blGlyphTop;
        end;
      end;
      cbConnect:
      begin
        Buttons[i].Hint := H_CB_Connect_Database;
        Buttons[i].Caption := '';
        if FShowCaptions then
        begin
          Buttons[i].Caption := Buttons[i].Hint;
          Buttons[i].Layout := blGlyphTop;
        end;
      end;
      cbDisconnect:
      begin
        Buttons[i].Hint := H_CB_Disconnect_Database;
        Buttons[i].Caption := '';
        if FShowCaptions then
        begin
          Buttons[i].Caption := Buttons[i].Hint;
          Buttons[i].Layout := blGlyphTop;
        end;
      end;
      cbDrop: begin
        Buttons[i].Hint := H_CB_Drop_Database;
        Buttons[i].Caption := '';
        if FShowCaptions then
        begin
          Buttons[i].Caption := Buttons[i].Hint;
          Buttons[i].Layout := blGlyphTop;
        end;
      end;
    end;
  end;
end;

procedure TIB_ConnectionBar.InitButtonsOrder;

  function GlobalOrderAssigned : boolean;
  var
    Flags: array [TIB_ConnectionBar_ButtonType] of boolean;
    i: TIB_ConnectionBar_ButtonType;
    ii: byte;
  begin
    Result := False;
    for i := Low(TIB_ConnectionBar_ButtonType) to
             High(TIB_ConnectionBar_ButtonType) do
      Flags[i] := False;
    for ii := 0 to 7 do
    begin
      if not Flags[IB_ConnectionBar_ButtonsOrder[ii]] then
        Flags[IB_ConnectionBar_ButtonsOrder[ii]] := True
      else
        Exit; // the flag can't be Searchd twice
    end;
    // All items must be true
    for i := Low(TIB_ConnectionBar_ButtonType) to
             High(TIB_ConnectionBar_ButtonType) do
      if not Flags[i] then
        Exit;
    Result := True;
  end;

begin
  if GlobalOrderAssigned then
    FButtonsOrder := IB_ConnectionBar_ButtonsOrder
  else
  begin
    FButtonsOrder[0] := cbCreate;
    FButtonsOrder[1] := cbDrop;
    FButtonsOrder[2] := cbConnect;
    FButtonsOrder[3] := cbDisconnect;
  end;
end;

function TIB_ConnectionBar.GetButtonsOrder( Index: Integer ):
                                                   TIB_ConnectionBar_ButtonType;
begin
  Result := FButtonsOrder[Index];
end;

//------------------------------------------------------------------------------
// Here's where the customized stuff begins
//------------------------------------------------------------------------------

procedure TIB_ConnectionBar.IB_ConnectionConnectedChanged(
                                                      CLink: TIB_ConnectionLink;
                                                      C: TIB_Connection);
begin
  SysStateChanged;
end;

function TIB_ConnectionBar.GetConnection: TIB_Connection;
begin
  if FIB_ConnectionSource <> nil then
    Result := FIB_ConnectionSource.IB_Connection
  else
    Result := nil;
end;

procedure TIB_ConnectionBar.SetConnection(AValue: TIB_Connection);
begin
  if FIB_ConnectionSource <> nil then
  begin
    if FIB_ConnectionSource.IB_Connection <> AValue then
    begin
      FIB_ConnectionSource.IB_Connection := AValue;
      SysStateChanged;
    end;
  end;
end;

function TIB_ConnectionBar.GetReceiveFocus: boolean;
begin
  if FIB_ConnectionSource <> nil then
    Result :=  FIB_ConnectionSource.ReceiveFocus
  else
    Result := false;
end;

procedure TIB_ConnectionBar.SetReceiveFocus(AValue: boolean);
begin
  if FIB_ConnectionSource <> nil then
    FIB_ConnectionSource.ReceiveFocus := AValue;
end;

function TIB_ConnectionBar.GetOnReceiveFocus: TIB_ConnectionLinkEvent;
begin
  Result := FIB_ConnectionSource.OnReceiveFocus;
end;

procedure TIB_ConnectionBar.SetOnReceiveFocus( AValue: TIB_ConnectionLinkEvent );
begin
  FIB_ConnectionSource.OnReceiveFocus := AValue;
end;

//------------------------------------------------------------------------------
// Here's where the customized stuff ends
//------------------------------------------------------------------------------

initialization
  ConnectionBar_Images := TIB_StringList.Create;
  ConnectionBar_Images.Sorted := true;
  FillImages;

finalization
  while ConnectionBar_Images.Count > 0 do
  begin
    TBitmap( ConnectionBar_Images.Objects[0] ).Free;
    ConnectionBar_Images.Delete( 0 );
  end;
  ConnectionBar_Images.Free;

end.
