View Issue Details

IDProjectCategoryView StatusLast Update
0035667LazarusWidgetsetpublic2019-11-04 11:33
ReporterAnton Kavalenka Assigned ToZeljan Rikalo  
PrioritynormalSeverityminorReproducibilityhave not tried
Status closedResolutionfixed 
Product Version2.0.3 (SVN) 
Summary0035667: gtk3: Make toolbar buttons appear
DescriptionImplementation of native GTK3 toolbar.
TagsNo tags attached.
Fixed in Revision62164
LazTarget-
WidgetsetGTK 3
Attached Files

Relationships

related to 0035668 new lcl: Feature like Widgetset-native toolbar 
related to 0035699 closedZeljan Rikalo gtk3: Implement proper LogFont getting from pango layount 

Activities

Anton Kavalenka

2019-06-02 14:22

reporter  

gtk3widgets.diff (1,674 bytes)   
Index: gtk3widgets.pas
===================================================================
--- gtk3widgets.pas	(revision 61310)
+++ gtk3widgets.pas	(working copy)
@@ -1667,6 +1667,7 @@
   Result:=TGtkPaned.new(ornt[TPairSplitter(Self.LCLObject).SplitterType]);
 end;
 
+
 { TGtk3Widget }
 
 function TGtk3Widget.GtkEventMouseEnterLeave(Sender: PGtkWidget; Event: PGdkEvent): Boolean;
@@ -3951,14 +3952,50 @@
 
 function TGtk3ToolBar.CreateWidget(const Params: TCreateParams): PGtkWidget;
 var
+  i:integer;
   AToolBar: TToolBar;
+  btn:TToolButton;
+  gtb:PGtkToolItem;
+  wmenu:PGtkWIdget;
 begin
   AToolBar := TToolBar(LCLObject);
   FHasPaint := False;
   FWidgetType := [wtWidget, wtContainer];
   Result:=PGtkWidget(TGtkToolbar.new);
+
+  // allocate appropriate number of tool items
+  for i:=0 to AToolbar.ButtonCount-1 do
+  begin
+    btn:=AToolBar.Buttons[i];
+    if btn is TToolButton then
+    begin
+      case btn.Style of
+  	  tbsSeparator:
+    	  gtb:=TGtkSeparatorToolItem.new();
+      tbsDropDown:
+        begin
+        	gtb:=TGtkMenuToolButton.new(nil,PgChar(btn.Caption));
+          if Assigned(btn.DropdownMenu) then
+          begin
+          	wmenu:=TGtk3Menu(btn.DropdownMenu.Handle).Widget;
+          	PGtkMenuToolButton(gtb)^.set_menu(wmenu);
+          end;
+        end;
+      tbsCheck:
+        begin
+          gtb:=TGtkToggleToolButton.new();
+          PGtkToolButton(gtb)^.set_label(PgChar(btn.Caption));
+        end
+  	  else
+    	  gtb:=TGtkToolButton.new(nil,PgChar(btn.Caption));
+ 		  end;
+      PGtkToolBar(Result)^.add(gtb);
+    end;
+  end;
+
 end;
 
+
 { TGtk3Page }
 
 procedure TGtk3Page.setText(AValue: String);
gtk3widgets.diff (1,674 bytes)   

Anton Kavalenka

2019-06-02 14:32

reporter  

Anton Kavalenka

2019-10-19 16:55

reporter   ~0118701

Make GTK3 toolbar click-responsible and show button icons.
gtk3widgets-2.diff (5,789 bytes)   
Index: gtk3widgets.pas
===================================================================
--- gtk3widgets.pas	(revision 62087)
+++ gtk3widgets.pas	(working copy)
@@ -24,7 +24,7 @@
 uses
   Classes, SysUtils, types, math,
   // LCL
-  Controls, StdCtrls, ExtCtrls, ComCtrls, Graphics, Dialogs, Forms, Menus, ExtDlgs,
+  Controls, StdCtrls, ExtCtrls, Buttons, ComCtrls, Graphics, Dialogs, Forms, Menus, ExtDlgs,
   Spin, CheckLst, PairSplitter, LCLType, LCLProc, LMessages, LCLMessageGlue, LCLIntf,
   // GTK3
   LazGtk3, LazGdk3, LazGObject2, LazGLib2, LazCairo1, LazPango1, LazGdkPixbuf2,
@@ -469,7 +469,11 @@
   { TGtk3ToolBar }
 
   TGtk3ToolBar = class(TGtk3Container)
+  private
+    fBmpList:TList;
+    procedure ClearGlyphs;
   protected
+    destructor Destroy;override;
     function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
   end;
 
@@ -657,6 +661,7 @@
     FMargin: Integer;
     FLayout: Integer;
     FSpacing: Integer;
+    FImage: TBitmap;
     function getLayout: Integer;
     function getMargin: Integer;
     procedure SetLayout(AValue: Integer);
@@ -663,15 +668,18 @@
     procedure SetMargin(AValue: Integer);
     procedure SetSpacing(AValue: Integer);
   protected
+    procedure SetImage(AImage:TBitmap);
     function getText: String; override;
     procedure setText(const AValue: String); override;
     function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
   public
+    destructor Destroy;override;
     function IsWidgetOk: Boolean; override;
     procedure SetDefault(const ADefault: Boolean);
     property Layout: Integer read getLayout write SetLayout;
     property Margin: Integer read getMargin write SetMargin;
     property Spacing: Integer read FSpacing write SetSpacing;
+    property Image:TBitmap read fImage write SetImage;
   end;
 
   { TGtk3ToggleButton }
@@ -817,7 +825,7 @@
 
 implementation
 
-uses gtk3int;
+uses gtk3int,imglist;
 
 const
   GDK_DEFAULT_EVENTS_MASK: TGdkEventMask =
@@ -3949,14 +3957,108 @@
 
 { TGtk3ToolBar }
 
+procedure TGtk3ToolBar.ClearGlyphs;
+var i:integer;
+begin
+  if Assigned(fBmpList) then
+  for i:=fBmpList.Count-1 downto 0 do
+    TObject(fBmpList[i]).Free;
+end;
+
+destructor TGtk3ToolBar.Destroy;
+begin
+  ClearGlyphs;
+  fBmpList.Free;
+  inherited Destroy;
+end;
+
+
+procedure tool_button_clicked(widget: PGtkWidget; data: gPointer); cdecl;
+begin
+  if TObject(data) is TToolButton then
+  TToolButton(data).Click;
+end;
+
+
 function TGtk3ToolBar.CreateWidget(const Params: TCreateParams): PGtkWidget;
 var
+  i:integer;
   AToolBar: TToolBar;
+  btn:TToolButton;
+  gtb:PGtkToolItem;
+  wmenu,wicon:PGtkWidget;
+  pb:PGdkPixBuf;
+  bmp:TBitmap;
+  resolution:TCustomImageListResolution;
+  bs:string;
 begin
   AToolBar := TToolBar(LCLObject);
   FHasPaint := False;
   FWidgetType := [wtWidget, wtContainer];
   Result:=PGtkWidget(TGtkToolbar.new);
+
+  if not Assigned(fBmpList) then
+    fBmpList:=TList.Create;
+
+  ClearGlyphs;
+
+  // allocate appropriate number of tool items
+  for i:=0 to AToolbar.ButtonCount-1 do
+  begin
+    btn:=AToolBar.Buttons[i];
+    bs:=StringReplace(btn.Caption,'&','_',[rfReplaceAll]);
+    wicon:=nil;
+    if btn is TToolButton then
+    begin
+      if (btn.ImageIndex>=0) and
+          assigned(AToolbar.Images) and
+          not (btn.Style in [tbsSeparator,tbsDivider]) then
+      begin
+        bmp:=TBitmap.Create; { this carries gdk pixmap }
+        resolution:=Atoolbar.Images.Resolution[16];
+        resolution.GetBitmap(btn.ImageIndex,bmp);
+        if not bmp.Empty then
+        begin
+          //wicon := TGtkImage.new;
+          pb:=TGtk3Image(bmp.Handle).Handle;
+          wicon := gtk_image_new_from_pixbuf(pb);
+        end
+        else
+          wicon := nil;
+        fBmpList.Add(bmp);
+      end;
+
+      case btn.Style of
+  	  tbsSeparator:
+    	  gtb:=TGtkSeparatorToolItem.new();
+      tbsDropDown:
+        begin
+        	gtb:=TGtkMenuToolButton.new(wicon,PgChar(bs));
+          if Assigned(btn.DropdownMenu) then
+          begin
+          	wmenu:=TGtk3Menu(btn.DropdownMenu.Handle).Widget;
+          	PGtkMenuToolButton(gtb)^.set_menu(wmenu);
+          end;
+        end;
+      tbsCheck:
+        begin
+          gtb:=TGtkToggleToolButton.new();
+          PGtkToolButton(gtb)^.set_label(PgChar(bs));
+        end
+  	  else
+    	  gtb:=TGtkToolButton.new(wicon,PgChar(bs));
+ 		  end;
+      gtb^.set_tooltip_text(PgChar(btn.Hint));
+      PgtkToolButton(gtb)^.set_use_underline(true);
+      PGtkToolBar(Result)^.add(gtb);
+
+      if not (btn.Style in [tbsSeparator,tbsDivider]) then
+      g_signal_connect_data(gtb,'clicked',
+        TGCallback(@tool_button_clicked), btn, nil, 0);
+
+    end;
+  end;
+
 end;
 
 { TGtk3Page }
@@ -6245,6 +6347,13 @@
   end;
 end;
 
+procedure TGtk3Button.SetImage(AImage: TBitmap);
+begin
+  if Assigned(fImage) then
+    fImage.free;
+  fImage:=AImage;
+end;
+
 function TGtk3Button.getText: String;
 begin
   if IsWidgetOK then
@@ -6256,17 +6365,31 @@
 procedure TGtk3Button.setText(const AValue: String);
 begin
   if IsWidgetOk then
-    PGtkButton(FWidget)^.set_label(PgChar(AValue));
+  begin
+    PGtkButton(FWidget)^.set_label(PgChar(StringReplace(AValue,'&','_',[rfReplaceAll])));
+  end;
 end;
 
 function TGtk3Button.CreateWidget(const Params: TCreateParams): PGtkWidget;
+var
+  img:PGtkImage;
+  btn:PGtkButton absolute Result;
 begin
   Result := PGtkWidget(TGtkButton.new);
+
+  btn^.set_use_underline(true);
+
   FMargin := -1;
   FLayout := GTK_POS_LEFT;
   FSpacing := 2; // default gtk3 spacing is 2
 end;
 
+destructor TGtk3Button.Destroy;
+begin
+  SetImage(nil);
+  inherited Destroy;
+end;
+
 function TGtk3Button.IsWidgetOk: Boolean;
 begin
   Result := (FWidget <> nil) and Gtk3IsButton(FWidget);
gtk3widgets-2.diff (5,789 bytes)   
laztest105.zip (5,568 bytes)

Zeljan Rikalo

2019-10-19 18:35

developer   ~0118708

@Anton, only gtk3widget-2.diff should be applied or both ?

Anton Kavalenka

2019-10-19 20:04

reporter   ~0118713

only 2-nd
mantis automatically adds numeric suffix when uploaded files have same names

Zeljan Rikalo

2019-10-19 20:06

developer   ~0118714

Please look my comment about widgetset native implementation of TToolBar at related issue.

CudaText man

2019-10-19 21:09

reporter   ~0118717

Tested this patch with the 0035699 bug- it helped, pls apply.

Anton Kavalenka

2019-10-29 16:04

reporter   ~0118915

Make toolbar buttons appear in proper colours (swap BGRA -> RGBA)
And accidentally make TGtk3Page paint TGraphicControl descendants inside
gtk3widgets-3.diff (7,529 bytes)   
Index: gtk3widgets.pas
===================================================================
--- gtk3widgets.pas	(revision 62145)
+++ gtk3widgets.pas	(working copy)
@@ -24,8 +24,9 @@
 uses
   Classes, SysUtils, types, math,
   // LCL
-  Controls, StdCtrls, ExtCtrls, ComCtrls, Graphics, Dialogs, Forms, Menus, ExtDlgs,
+  Controls, StdCtrls, ExtCtrls, Buttons, ComCtrls, Graphics, Dialogs, Forms, Menus, ExtDlgs,
   Spin, CheckLst, PairSplitter, LCLType, LCLProc, LMessages, LCLMessageGlue, LCLIntf,
+  graphtype,
   // GTK3
   LazGtk3, LazGdk3, LazGObject2, LazGLib2, LazCairo1, LazPango1, LazGdkPixbuf2,
   gtk3objects, gtk3procs, gtk3private, Gtk3CellRenderer;
@@ -355,6 +356,7 @@
     function getText: String; override;
     function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
     procedure DestroyWidget; override;
+    function getClientOffset:TPoint;override;
   public
     function getClientRect: TRect; override;
   end;
@@ -469,7 +471,12 @@
   { TGtk3ToolBar }
 
   TGtk3ToolBar = class(TGtk3Container)
-  protected
+  private
+    fBmpList:TList;
+    procedure ButtonClicked(data: gPointer); cdecl;
+    procedure ClearGlyphs;
+  public
+    destructor Destroy;override;
     function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
   end;
 
@@ -657,6 +664,7 @@
     FMargin: Integer;
     FLayout: Integer;
     FSpacing: Integer;
+    FImage: TBitmap;
     function getLayout: Integer;
     function getMargin: Integer;
     procedure SetLayout(AValue: Integer);
@@ -663,15 +671,18 @@
     procedure SetMargin(AValue: Integer);
     procedure SetSpacing(AValue: Integer);
   protected
+    procedure SetImage(AImage:TBitmap);
     function getText: String; override;
     procedure setText(const AValue: String); override;
     function CreateWidget(const Params: TCreateParams):PGtkWidget; override;
   public
+    destructor Destroy;override;
     function IsWidgetOk: Boolean; override;
     procedure SetDefault(const ADefault: Boolean);
     property Layout: Integer read getLayout write SetLayout;
     property Margin: Integer read getMargin write SetMargin;
     property Spacing: Integer read FSpacing write SetSpacing;
+    property Image:TBitmap read fImage write SetImage;
   end;
 
   { TGtk3ToggleButton }
@@ -817,7 +828,7 @@
 
 implementation
 
-uses gtk3int;
+uses gtk3int,imglist;
 
 const
   GDK_DEFAULT_EVENTS_MASK: TGdkEventMask =
@@ -3926,7 +3937,7 @@
   AClass: PGTypeClass;
 begin
   inherited InitializeWidget;
-  //TODO: move hookers check variable code into Gtk3WidgetSet.
+  //TODO: move hook check variable code into Gtk3WidgetSet.
   if not AProgressClassHookInitialized then
   begin
     AProgressClassHookInitialized := True;
@@ -3949,14 +3960,110 @@
 
 { TGtk3ToolBar }
 
+procedure TGtk3ToolBar.ClearGlyphs;
+var i:integer;
+begin
+  if Assigned(fBmpList) then
+  for i:=fBmpList.Count-1 downto 0 do
+    TObject(fBmpList[i]).Free;
+end;
+
+destructor TGtk3ToolBar.Destroy;
+begin
+  ClearGlyphs;
+  fBmpList.Free;
+  inherited Destroy;
+end;
+
+procedure TGtk3ToolBar.ButtonClicked(data: gPointer);cdecl;
+begin
+  if TObject(data) is TToolButton then
+  TToolButton(data).Click;
+end;
+
 function TGtk3ToolBar.CreateWidget(const Params: TCreateParams): PGtkWidget;
 var
+  i:integer;
   AToolBar: TToolBar;
+  btn:TToolButton;
+  gtb:PGtkToolItem;
+  wmenu,wicon:PGtkWidget;
+  pb:PGdkPixBuf;
+  bmp:TBitmap;
+  resolution:TCustomImageListResolution;
+  raw:TRawImage;
+  bs:string;
 begin
   AToolBar := TToolBar(LCLObject);
   FHasPaint := False;
   FWidgetType := [wtWidget, wtContainer];
   Result:=PGtkWidget(TGtkToolbar.new);
+
+  if not Assigned(fBmpList) then
+    fBmpList:=TList.Create;
+
+  ClearGlyphs;
+
+  // allocate appropriate number of tool items
+  for i:=0 to AToolbar.ButtonCount-1 do
+  begin
+    btn:=AToolBar.Buttons[i];
+    bs:=StringReplace(btn.Caption,'&','_',[rfReplaceAll]);
+    wicon:=nil;
+    if btn is TToolButton then
+    begin
+      if (btn.ImageIndex>=0) and
+          assigned(AToolbar.Images) and
+          not (btn.Style in [tbsSeparator,tbsDivider]) then
+      begin
+        if Assigned(AToolBar.Images) and (btn.ImageIndex>=0) then
+        begin
+          bmp:=TBitmap.Create; { this carries gdk pixmap }
+          resolution:=Atoolbar.Images.Resolution[Atoolbar.Images.Width];
+          resolution.GetRawImage(btn.ImageIndex,raw);
+          { convince the bitmap it has actually another format }
+          bmp.BeginUpdate();
+          raw.Description.Init_BPP32_R8G8B8A8_BIO_TTB(resolution.Width,resolution.Height);
+          bmp.LoadFromRawImage(raw,false);
+          bmp.EndUpdate();
+          pb:=TGtk3Image(bmp.Handle).Handle;
+          wicon := TGtkImage.new_from_pixbuf(pb);
+          fBmpList.Add(bmp);
+        end
+        else
+          wicon := nil;
+      end;
+
+      case btn.Style of
+  	  tbsSeparator:
+    	  gtb:=TGtkSeparatorToolItem.new();
+      tbsDropDown:
+        begin
+        	gtb:=TGtkMenuToolButton.new(wicon,PgChar(bs));
+          if Assigned(btn.DropdownMenu) then
+          begin
+          	wmenu:=TGtk3Menu(btn.DropdownMenu.Handle).Widget;
+          	PGtkMenuToolButton(gtb)^.set_menu(wmenu);
+          end;
+        end;
+      tbsCheck:
+        begin
+          gtb:=TGtkToggleToolButton.new();
+          PGtkToolButton(gtb)^.set_label(PgChar(bs));
+        end
+  	  else
+    	  gtb:=TGtkToolButton.new(wicon,PgChar(bs));
+ 		  end;
+      gtb^.set_tooltip_text(PgChar(btn.Hint));
+      PgtkToolButton(gtb)^.set_use_underline(true);
+      PGtkToolBar(Result)^.add(gtb);
+
+      if not (btn.Style in [tbsSeparator,tbsDivider]) then
+      g_signal_connect_data(gtb,'clicked',
+        TGCallback(@TGtk3Toolbar.ButtonClicked), btn, nil, 0);
+    end;
+  end;
+
 end;
 
 { TGtk3Page }
@@ -3979,6 +4086,7 @@
 begin
   FWidgetType := FWidgetType + [wtContainer];
   FPageLabel:= TGtkLabel.new(PChar(Params.Caption));
+  Self.FHasPaint:=true;
   // ref it to save it in case TabVisble is set to false
   FPageLabel^.ref;
   Result := TGtkHBox.new(GTK_ORIENTATION_HORIZONTAL, 0);
@@ -3995,6 +4103,20 @@
   FPageLabel^.unref;
 end;
 
+function TGtk3Page.getClientOffset: TPoint;
+var
+  Allocation: TGtkAllocation;
+  R: TRect;
+begin
+  Self.Widget^.get_allocation(@Allocation);
+  Result.X := -Allocation.X;
+  Result.Y := -Allocation.Y;
+
+  R := getClientBounds;
+  Result := Point(Result.x + R.Left, Result.y + R.Top);
+end;
+
+
 function TGtk3Page.getClientRect: TRect;
 var
   AParent: PGtkWidget;
@@ -6252,6 +6374,13 @@
   end;
 end;
 
+procedure TGtk3Button.SetImage(AImage: TBitmap);
+begin
+  if Assigned(fImage) then
+    fImage.free;
+  fImage:=AImage;
+end;
+
 function TGtk3Button.getText: String;
 begin
   if IsWidgetOK then
@@ -6263,17 +6392,31 @@
 procedure TGtk3Button.setText(const AValue: String);
 begin
   if IsWidgetOk then
-    PGtkButton(FWidget)^.set_label(PgChar(AValue));
+  begin
+    PGtkButton(FWidget)^.set_label(PgChar(StringReplace(AValue,'&','_',[rfReplaceAll])));
+  end;
 end;
 
 function TGtk3Button.CreateWidget(const Params: TCreateParams): PGtkWidget;
+var
+  img:PGtkImage;
+  btn:PGtkButton absolute Result;
 begin
   Result := PGtkWidget(TGtkButton.new);
+
+  btn^.set_use_underline(true);
+
   FMargin := -1;
   FLayout := GTK_POS_LEFT;
   FSpacing := 2; // default gtk3 spacing is 2
 end;
 
+destructor TGtk3Button.Destroy;
+begin
+  SetImage(nil);
+  inherited Destroy;
+end;
+
 function TGtk3Button.IsWidgetOk: Boolean;
 begin
   Result := (FWidget <> nil) and Gtk3IsButton(FWidget);
gtk3widgets-3.diff (7,529 bytes)   

Zeljan Rikalo

2019-11-03 16:09

developer   ~0119014

Please test and close if ok. Thanks for the patch.

Issue History

Date Modified Username Field Change
2019-06-02 14:22 Anton Kavalenka New Issue
2019-06-02 14:22 Anton Kavalenka File Added: gtk3widgets.diff
2019-06-02 14:32 Anton Kavalenka File Added: Здымак экрана, 2019-06-02 15-20-01.png
2019-06-03 16:11 Dmitry Boyarintsev Relationship added related to 0035668
2019-10-19 16:55 Anton Kavalenka File Added: gtk3widgets-2.diff
2019-10-19 16:55 Anton Kavalenka File Added: laztest105.zip
2019-10-19 16:55 Anton Kavalenka File Added: Здымак экрана, 2019-10-19 17-54-53.png
2019-10-19 16:55 Anton Kavalenka Note Added: 0118701
2019-10-19 18:35 Zeljan Rikalo Assigned To => Zeljan Rikalo
2019-10-19 18:35 Zeljan Rikalo Status new => assigned
2019-10-19 18:35 Zeljan Rikalo Note Added: 0118708
2019-10-19 20:04 Anton Kavalenka Note Added: 0118713
2019-10-19 20:06 Zeljan Rikalo Status assigned => feedback
2019-10-19 20:06 Zeljan Rikalo LazTarget => -
2019-10-19 20:06 Zeljan Rikalo Note Added: 0118714
2019-10-19 21:09 CudaText man Note Added: 0118717
2019-10-24 23:00 Juha Manninen Relationship added related to 0035699
2019-10-29 16:04 Anton Kavalenka File Added: gtk3widgets-3.diff
2019-10-29 16:04 Anton Kavalenka File Added: Здымак экрана, 2019-10-29 18-03-01.png
2019-10-29 16:04 Anton Kavalenka Note Added: 0118915
2019-10-29 16:04 Anton Kavalenka Status feedback => assigned
2019-11-03 16:09 Zeljan Rikalo Status assigned => resolved
2019-11-03 16:09 Zeljan Rikalo Resolution open => fixed
2019-11-03 16:09 Zeljan Rikalo Fixed in Revision => 62164
2019-11-03 16:09 Zeljan Rikalo Widgetset GTK 3 => GTK 3
2019-11-03 16:09 Zeljan Rikalo Note Added: 0119014
2019-11-04 11:33 Anton Kavalenka Status resolved => closed