1 // SPDX-License-Identifier: GPL-3.0-only
2 unit UMenu;
3 
4 {$mode objfpc}{$H+}
5 
6 interface
7 
8 uses
9   Classes, SysUtils, ActnList, Forms, Menus, UTool, LCLType, ExtCtrls, UConfig,
10   Controls, LazPaintType;
11 
12 type
13 
14   { TMainFormMenu }
15 
16   TMainFormMenu = class
17   private
18     FActionList: TActionList;
19     FDarkTheme: boolean;
20     FMainMenus: array of TMenuItem;
21     FToolsShortcuts: array[TPaintToolType] of TUTF8Char;
22     FToolbars: array of record
23                  tb: TPanel;
24                  fixed: boolean;
25                end;
26     FToolbarsHeight : integer;
27     FToolbarBackground: TPanel;
28     FImageList: TImageList;
29     procedure IconSizeItemClick(Sender: TObject);
30     procedure IconSizeMenuClick(Sender: TObject);
31     procedure Script_Click(Sender: TObject);
32     procedure SetDarkTheme(AValue: boolean);
33   protected
34     FInstance: TLazPaintCustomInstance;
35     FInstalledScripts: TStringList;
36     FTargetDPI: integer;
37     procedure AddMenus(AMenu: TMenuItem; AActionList: TActionList; AActionsCommaText: string; AIndex: integer = -1); overload;
38     procedure AddMenus(AMenuName: string; AActionsCommaText: string); overload;
39     procedure AddInstalledScripts(AMenu: TMenuItem; AIndex: integer = -1);
40     procedure ApplyShortcuts;
41     procedure ActionShortcut(AName: string; AShortcut: TUTF8Char);
42     procedure ApplyTheme;
GetIndividualToolbarHeightnull43     function GetIndividualToolbarHeight: integer;
44   public
45     constructor Create(AInstance: TLazPaintCustomInstance; AActionList: TActionList);
46     destructor Destroy; override;
47     procedure PredefinedMainMenus(const AMainMenus: array of TMenuItem);
48     procedure Toolbars(const AToolbars: array of TPanel; AToolbarBackground: TPanel);
49     procedure ScaleToolbars(ATargetDPI: integer);
50     procedure CycleTool(var ATool: TPaintToolType; var AShortCut: TUTF8Char);
51     procedure Apply;
52     procedure ArrangeToolbars(ClientWidth: integer);
53     procedure RepaintToolbar;
54     property ToolbarsHeight: integer read FToolbarsHeight;
55     property ImageList: TImageList read FImageList write FImageList;
56     property DarkTheme: boolean read FDarkTheme write SetDarkTheme;
57   end;
58 
59 implementation
60 
61 uses UResourceStrings, BGRAUTF8, LCScaleDPI, ComCtrls, Graphics,
62   StdCtrls, BGRAText, math, udarktheme,
63   ugraph, BGRABitmapTypes, LCVectorialFillControl,
64   UPython, UTranslation;
65 
66 { TMainFormMenu }
67 
68 procedure TMainFormMenu.IconSizeMenuClick(Sender: TObject);
69 var
70   menu: TMenuItem;
71   i, iconSize: Integer;
72 begin
73   menu := Sender as TMenuItem;
74   iconSize := FInstance.Config.DefaultIconSize(0);
75   for i := 0 to menu.Count-1 do
76     menu.Items[i].Checked := (menu.Items[i].Tag = iconSize);
77 end;
78 
79 procedure TMainFormMenu.Script_Click(Sender: TObject);
80 var
81   item: TMenuItem;
82   scriptIndex: integer;
83 begin
84   if Assigned(FInstalledScripts) then
85   begin
86     item := Sender as TMenuItem;
87     scriptIndex := item.Tag;
88     FInstance.RunScript(FInstalledScripts[scriptIndex], item.Caption);
89   end;
90 end;
91 
92 procedure TMainFormMenu.SetDarkTheme(AValue: boolean);
93 begin
94   if FDarkTheme=AValue then Exit;
95   FDarkTheme:=AValue;
96   ApplyTheme;
97 end;
98 
99 procedure TMainFormMenu.IconSizeItemClick(Sender: TObject);
100 var
101   item: TMenuItem;
102 begin
103   item:= Sender as TMenuItem;
104   FInstance.ChangeIconSize(item.Tag);
105 end;
106 
107 procedure TMainFormMenu.AddMenus(AMenu: TMenuItem; AActionList: TActionList;
108   AActionsCommaText: string; AIndex: integer);
109 var actions: TStringList;
110   foundAction: TBasicAction;
111   item: TMenuItem;
112   i,j: NativeInt;
113 
114   procedure AddSubItem(ACaption: string; AOnClick: TNotifyEvent; ATag: integer);
115   var
116     subItem: TMenuItem;
117   begin
118     subItem := TMenuItem.Create(item);
119     subItem.Caption := ACaption;
120     subItem.Tag := ATag;
121     subItem.OnClick := AOnClick;
122     item.Add(subItem);
123   end;
124 
125   procedure AddSubItem(AAction: TBasicAction; ATag: integer = 0);
126   var
127     subItem: TMenuItem;
128   begin
129     subItem := TMenuItem.Create(item);
130     subItem.Action := AAction;
131     subItem.Tag := ATag;
132     item.Add(subItem);
133   end;
134 
135 begin
136   actions := TStringList.Create;
137   actions.CommaText := AActionsCommaText;
138   for i := 0 to actions.Count-1 do
139     if (actions[i]='*') and (AIndex = -1) then
140       AIndex := 0;
141   for i := 0 to actions.Count-1 do
142   begin
143     if actions[i]='*' then
144     begin
145       AIndex := -1;
146       Continue;
147     end;
148     if actions[i]='InstalledScripts' then
149     begin
150       AddInstalledScripts(AMenu, AIndex);
151       continue;
152     end;
153     item := TMenuItem.Create(nil);
154     if trim(actions[i]) = '-' then
155       item.Caption := cLineCaption
156     else
157     begin
158       foundAction := AActionList.ActionByName(actions[i]);
159       if foundAction <> nil then
160         item.Action := foundAction
161       else
162       begin
163         for j := 0 to AMenu.Count-1 do
164           if UTF8CompareText(AMenu.Items[j].Name,actions[i])=0 then
165           begin
166             FreeAndNil(item);
167             AMenu.Items[j].Visible := true;
168             if (AIndex <> -1) and (AIndex < j) then
169             begin
170               item := AMenu.Items[j];
171               AMenu.Remove(item);
172               AMenu.Insert(AIndex,item);
173               item := nil;
174               inc(AIndex);
175             end else
176             if AIndex = -1 then
177             begin
178               item := AMenu.Items[j];
179               AMenu.Remove(item);
180               AMenu.Add(item);
181               item := nil;
182             end;
183             break;
184           end;
185         if Assigned(item) and (actions[i] = 'MenuIconSize') then
186         begin
187           item.Caption := rsIconSize;
188           item.OnClick:=@IconSizeMenuClick;
189           AddSubItem('16px', @IconSizeItemClick, 16);
190           AddSubItem('20px', @IconSizeItemClick, 20);
191           AddSubItem('24px', @IconSizeItemClick, 24);
192           AddSubItem('32px', @IconSizeItemClick, 32);
193           AddSubItem('40px', @IconSizeItemClick, 40);
194           AddSubItem('48px', @IconSizeItemClick, 48);
195           AddSubItem(rsAutodetect, @IconSizeItemClick, 0);
196           AMenu.Add(item);
197           item := nil;
198         end else
199         if Assigned(item) and (actions[i] = 'EditShapeAlign') then
200         begin
201           item.Caption := rsAlignShape;
202           AddSubItem(AActionList.ActionByName('EditShapeAlignLeft'));
203           AddSubItem(AActionList.ActionByName('EditShapeCenterHorizontally'));
204           AddSubItem(AActionList.ActionByName('EditShapeAlignRight'));
205           AddSubItem('-',nil,0);
206           AddSubItem(AActionList.ActionByName('EditShapeAlignTop'));
207           AddSubItem(AActionList.ActionByName('EditShapeCenterVertically'));
208           AddSubItem(AActionList.ActionByName('EditShapeAlignBottom'));
209           AMenu.Add(item);
210           item := nil;
211         end;
212         if Assigned(item) then item.Caption := trim(actions[i])+'?';
213       end;
214     end;
215     if Assigned(item) then
216     begin
217       if AIndex = -1 then
218         AMenu.Add(item)
219       else
220       begin
221         AMenu.Insert(AIndex,item);
222         inc(AIndex);
223       end;
224     end;
225   end;
226   actions.Free;
227 end;
228 
229 procedure TMainFormMenu.AddMenus(AMenuName: string; AActionsCommaText: string);
230 var i: NativeInt;
231 begin
232   for i := 0 to MenuDefinitionKeys.count-1 do
233     if UTF8CompareText(MenuDefinitionKeys[i],AMenuName)=0 then
234     begin
235       AActionsCommaText:= MenuDefinitionValues[i];
236       if AActionsCommaText = '' then exit;
237       break;
238     end;
239   for i := 0 to high(FMainMenus) do
240     if FMainMenus[i].Name = AMenuName then
241     begin
242       AddMenus(FMainMenus[i], FActionList, AActionsCommaText);
243       FMainMenus[i].Visible := true;
244     end;
245 end;
246 
247 procedure TMainFormMenu.AddInstalledScripts(AMenu: TMenuItem; AIndex: integer);
248 
249   procedure AddScriptRec(AMenu: TMenuItem; var AIndex: integer; AItem: TMenuItem);
250   var
251     posSub, j, subIndex: integer;
252     sectionName: String;
253     sectionItem: TMenuItem;
254   begin
255     posSub := pos('>', AItem.Caption);
256     if posSub > 0 then
257     begin
258       sectionName := copy(AItem.Caption, 1, posSub-1);
259       AItem.Caption := copy(AItem.Caption, posSub+1, length(AItem.Caption) - posSub);
260       subIndex := -1;
261       for j := 0 to AMenu.Count-1 do
262         if AMenu.Items[j].Caption = sectionName then
263         begin
264           AddScriptRec(AMenu.Items[j], subIndex, AItem);
265           exit;
266         end;
267       sectionItem := TMenuItem.Create(AMenu);
268       sectionItem.Caption := sectionName;
269       if AIndex = -1 then
270         AMenu.Add(sectionItem)
271       else
272       begin
273         AMenu.Insert(AIndex, sectionItem);
274         inc(AIndex);
275       end;
276       AddScriptRec(sectionItem, subIndex, AItem);
277       exit;
278     end;
279 
280     if AIndex = -1 then
281       AMenu.Add(AItem)
282     else
283     begin
284       AMenu.Insert(AIndex, AItem);
285       inc(AIndex);
286     end;
287   end;
288 
289 var
290   path, fullname, title: String;
291   searchRec: TSearchRec;
292   t: textFile;
293   item: TMenuItem;
294   items: TStringList;
295   i: Integer;
296 
297 begin
298   if FInstalledScripts = nil then FInstalledScripts := TStringList.Create;
299   path := TPythonScript.DefaultScriptDirectory;
300   if FindFirstUTF8(path+PathDelim+'*.py', faAnyFile, searchRec)=0 then
301   begin
302     items := TStringList.Create;
303     items.Sorted := true;
304     try
305       repeat
306         fullname := path+PathDelim+searchRec.Name;
307         if FileExistsUTF8(fullname) then
308         begin
309           title := GetScriptTitle(fullname);
310           if title <> '' then
311           begin
312             item := TMenuItem.Create(AMenu);
313             item.Caption := title;
314             item.Tag := FInstalledScripts.Add(fullname);
315             item.OnClick:=@Script_Click;
316             items.AddObject(title, item);
317           end;
318         end;
319       until FindNextUTF8(searchRec)<>0;
320     finally
321       FindCloseUTF8(searchRec);
322       for i := 0 to items.Count-1 do
323         AddScriptRec(AMenu, AIndex, TMenuItem(items.Objects[i]));
324       items.Free;
325     end;
326   end;
327 end;
328 
329 procedure TMainFormMenu.ActionShortcut(AName: string; AShortcut: TUTF8Char);
330 var foundAction: TBasicAction;
331   ShortcutStr: string;
332 begin
333   foundAction := FActionList.ActionByName(AName);
334   if foundAction <> nil then
335   begin
336     ShortcutStr := AShortcut;
337     if (length(AName) >= 5) and (copy(AName,1,4) = 'Tool') and
338         (AName[5] = upcase(AName[5])) then
339       FToolsShortcuts[StrToPaintToolType(copy(AName,5,length(AName)-4))] := AShortcut;
340     AppendShortcut(foundAction as TAction, ShortcutStr);
341   end;
342 end;
343 
344 procedure TMainFormMenu.ApplyTheme;
345 var
346   i, j: Integer;
347 begin
348   for i := 0 to high(FToolbars) do
349   begin
350     with FToolbars[i].tb do
351     begin
352       DarkThemeInstance.Apply(FToolbars[i].tb, DarkTheme);
353       for j := 0 to ControlCount-1 do
354         if Controls[j] is TLabel then
355         begin
356           if (Controls[j].Name = 'Label_CurrentZoom') then
357           begin
358             Controls[j].Color := DarkThemeInstance.GetColorEditableFace(FDarkTheme);
359             Controls[j].Font.Color := DarkThemeInstance.GetColorEditableText(FDarkTheme);
360           end;
361         end;
362     end;
363   end;
364   if Assigned(FToolbarBackground) then
365     FToolbarBackground.Color := DarkThemeInstance.GetColorButtonFace(FDarkTheme);
366 end;
367 
TMainFormMenu.GetIndividualToolbarHeightnull368 function TMainFormMenu.GetIndividualToolbarHeight: integer;
369 begin
370   result := DoScaleY(24,OriginalDPI,FTargetDPI);
371 end;
372 
373 constructor TMainFormMenu.Create(AInstance: TLazPaintCustomInstance; AActionList: TActionList);
374 begin
375   FInstance := AInstance;
376   FActionList := AActionList;
377   FToolbarsHeight := 0;
378   FTargetDPI := OriginalDPI;
379 end;
380 
381 destructor TMainFormMenu.Destroy;
382 begin
383   FInstalledScripts.Free;
384   inherited Destroy;
385 end;
386 
387 procedure TMainFormMenu.PredefinedMainMenus(const AMainMenus: array of TMenuItem);
388 var i: NativeInt;
389 begin
390   setlength(FMainMenus, length(AMainMenus));
391   for i := 0 to high(AMainMenus) do
392     FMainMenus[i] := AMainMenus[i];
393 end;
394 
395 procedure TMainFormMenu.Toolbars(const AToolbars: array of TPanel; AToolbarBackground: TPanel);
396 var i,j: NativeInt;
397 begin
398   setlength(FToolbars, length(AToolbars));
399   for i := 0 to high(FToolbars) do
400   begin
401     FToolbars[i].tb := AToolbars[i];
402     FToolbars[i].tb.Cursor := crArrow;
403     with FToolbars[i].tb do
404     for j := 0 to ControlCount-1 do
405     begin
406       Controls[j].Cursor := crArrow;
407       if Controls[j] is TLabel then
408       begin
409         if (Controls[j].Name = 'Label_Coordinates') or
410            (Controls[j].Name = 'Label_CurrentZoom') or
411            (Controls[j].Name = 'Label_CurrentDiff') then
412           Controls[j].Font.Height := -DoScaleY(12, OriginalDPI, FTargetDPI);
413       end;
414     end;
415   end;
416   FToolbarBackground := AToolbarBackground;
417 end;
418 
419 procedure TMainFormMenu.ScaleToolbars(ATargetDPI: integer);
420 var
421   i: Integer;
422 begin
423   FTargetDPI := ATargetDPI;
424   for i := 0 to high(FToolbars) do
425     ScaleControl(FToolbars[i].tb, OriginalDPI, ATargetDPI, ATargetDPI, true);
426 end;
427 
428 procedure TMainFormMenu.CycleTool(var ATool: TPaintToolType;
429   var AShortCut: TUTF8Char);
430 var
431   curTool: TPaintToolType;
432 begin
433   AShortCut := UTF8UpperCase(AShortCut);
434   curTool := ATool;
435   repeat
436     if curTool = high(TPaintToolType) then
437       curTool := low(TPaintToolType)
438     else
439       curTool := succ(curTool);
440 
441     if (FToolsShortcuts[curTool] = AShortCut) and not
442        ((curTool = ptHotSpot) and not FInstance.Image.IsCursor) then
443     begin
444       ATool := curTool;
445       AShortCut:= '';
446       exit;
447     end;
448   until curTool = ATool;
449 end;
450 
451 procedure TMainFormMenu.Apply;
452 const ImageBrowser = 'FileUseImageBrowser,';
453 var i,j,tbHeight,tbHeightOrig: NativeInt;
454 begin
455   for i := 0 to FActionList.ActionCount-1 do
456   with FActionList.Actions[i] as TAction do
457     if (Caption = '') and (Hint <> '') then Caption := Hint;
458 
459   AddMenus('MenuFile',   'FileNew,FileOpen,LayerFromFile,FileChooseEntry,FileReload,MenuRecentFiles,-,FileSave,FileSaveAsInSameFolder,FileSaveAs,FileExport,-,FileImport3D,-,FilePrint,-,'+ImageBrowser+'FileRememberSaveFormat,ForgetDialogAnswers,MenuLanguage,*');
460   AddMenus('MenuEdit',   'EditUndo,EditRedo,-,EditCut,EditCopy,EditPaste,EditPasteAsNew,EditPasteAsNewLayer,EditDeleteSelection,-,EditMoveUp,EditMoveToFront,EditMoveDown,EditMoveToBack,EditShapeAlign,EditShapeToCurve');
461   AddMenus('MenuSelect', 'EditSelection,FileLoadSelection,FileSaveSelectionAs,-,EditSelectAll,EditInvertSelection,EditSelectionFit,EditDeselect,-,ToolSelectRect,ToolSelectEllipse,ToolSelectPoly,ToolSelectSpline,-,ToolMoveSelection,ToolRotateSelection,SelectionHorizontalFlip,SelectionVerticalFlip,-,ToolSelectPen,ToolMagicWand');
462   AddMenus('MenuView',   'ViewGrid,ViewZoomOriginal,ViewZoomIn,ViewZoomOut,ViewZoomFit,-,ViewToolBox,ViewColors,ViewPalette,ViewLayerStack,ViewImageList,ViewStatusBar,-,*,-,ViewDarkTheme,ViewWorkspaceColor,MenuIconSize');
463   AddMenus('MenuImage',  'ImageCrop,ImageCropLayer,ImageFlatten,MenuRemoveTransparency,-,ImageNegative,ImageLinearNegative,ImageSwapRedBlue,-,ImageChangeCanvasSize,ImageRepeat,-,ImageResample,ImageSmartZoom3,-,ImageRotateCW,ImageRotateCCW,ImageRotate180,ImageHorizontalFlip,ImageVerticalFlip');
464   AddMenus('MenuRemoveTransparency', 'ImageClearAlpha,ImageFillBackground');
465   AddMenus('MenuFilter', 'MenuRadialBlur,FilterBlurMotion,FilterBlurCustom,FilterPixelate,-,FilterSharpen,FilterSmooth,FilterNoise,FilterMedian,FilterClearType,FilterClearTypeInverse,FilterFunction,-,FilterContour,FilterEmboss,FilterPhong,-,FilterSphere,FilterTwirl,FilterWaveDisplacement,FilterCylinder');
466   AddMenus('MenuRadialBlur',  'FilterBlurBox,FilterBlurFast,FilterBlurRadial,FilterBlurCorona,FilterBlurDisk');
467   AddMenus('MenuColors', 'ColorCurves,ColorPosterize,ColorColorize,ColorShiftColors,FilterComplementaryColor,ColorIntensity,-,ColorLightness,FilterNegative,FilterLinearNegative,FilterNormalize,FilterGrayscale');
468   AddMenus('MenuTool',   'ToolHand,ToolHotSpot,ToolColorPicker,-,ToolPen,ToolBrush,ToolEraser,ToolFloodFill,ToolClone,-,ToolEditShape,ToolRect,ToolEllipse,ToolPolyline,ToolOpenedCurve,ToolPolygon,ToolSpline,ToolGradient,ToolPhong,ToolText,-,ToolDeformation,ToolTextureMapping');
469   AddMenus('MenuRender', 'RenderPerlinNoise,RenderCyclicPerlinNoise,-,RenderWater,RenderCustomWater,RenderSnowPrint,RenderWood,RenderWoodVertical,RenderMetalFloor,RenderPlastik,RenderStone,RenderRoundStone,RenderMarble,RenderCamouflage,-,RenderClouds,FilterRain');
470   AddMenus('MenuScript', 'FileRunScript,-,InstalledScripts');
471   AddMenus('MenuHelp',   'HelpIndex,-,HelpAbout');
472   for i := 0 to high(FMainMenus) do
473     if FMainMenus[i].Count = 0 then FMainMenus[i].visible := false;
474 
475   ApplyShortcuts;
476 
477   if Assigned(FImageList) then
478     FActionList.Images := FImageList;
479 
480   tbHeightOrig := GetIndividualToolbarHeight;
481   tbHeight := tbHeightOrig;
482   for i := 0 to high(FToolbars) do
483   with FToolbars[i].tb do
484   begin
485     Top := 0;
486     Left := -Width;
487     Color := clBtnFace;
488     for j := 0 to ControlCount-1 do
489     begin
490       if Controls[j] is TToolBar then
491       begin
492         if assigned(FImageList) then TToolbar(Controls[j]).Images := FImageList;
493         TToolbar(Controls[j]).ButtonWidth := TToolbar(Controls[j]).Images.Width+ScaleX(6, 96);
494         TToolbar(Controls[j]).ButtonHeight := TToolbar(Controls[j]).Images.Height+ScaleY(5, 96);
495       end else
496       if Controls[j] is TLCVectorialFillControl then
497       begin
498         if assigned(FImageList) then
499           TLCVectorialFillControl(Controls[j]).ToolIconSize:= FImageList.Height;
500       end;
501     end;
502   end;
503   for i := 0 to high(FToolbars) do
504   with FToolbars[i].tb do
505   begin
506     Height := tbHeight;
507     for j := 0 to ControlCount-1 do
508       Controls[j].Top := Controls[j].Top + (tbHeight-tbHeightOrig) div 2;
509   end;
510 
511   ApplyTheme;
512 end;
513 
514 procedure TMainFormMenu.ArrangeToolbars(ClientWidth: integer);
515 var i,j,k,curx,cury,maxh, w, minNextX, delta,
516   tbNormalHeight: integer;
517   tb: TPanel;
518   vfc: TLCVectorialFillControl;
519 begin
520    tbNormalHeight := GetIndividualToolbarHeight;
521    curx := 0;
522    cury := 0;
523    maxh := 0;
524    for i := 0 to high(FToolbars) do
525    begin
526      tb := FToolbars[i].tb;
527 
528      if not FToolbars[i].fixed then
529      begin
530        for j := 0 to tb.ControlCount-1 do
531        begin
532          tb.Controls[j].Top := DoScaleY(1, OriginalDPI, FTargetDPI);
533          if tb.Controls[j] is TLCVectorialFillControl then
534          begin
535            vfc := TLCVectorialFillControl(tb.Controls[j]);
536            if tb.Height < vfc.PreferredSize.cy then
537              vfc.Height := min(vfc.ToolIconSize + vfc.VerticalPadding,
538                                tb.Height - tb.Controls[j].Top - 1)
539            else
540              vfc.Height := vfc.PreferredSize.cy;
541          end else
542          if tb.Controls[j] is TLabel then
543            tb.Controls[j].Height := tbNormalHeight - DoScaleY(3, OriginalDPI, FTargetDPI)
544          else
545            tb.Controls[j].Height := tbNormalHeight - DoScaleY(2, OriginalDPI, FTargetDPI);
546          if tb.Controls[j] is TToolBar then
547          begin
548            minNextX := MaxLongInt;
549            for k := 0 to tb.ControlCount-1 do
550              if tb.Controls[k].Left > tb.Controls[j].Left then
551                minNextX := min(minNextX, tb.Controls[k].Left);
552            delta := tb.Controls[j].Left+tb.Controls[j].Width+2-minNextX;
553            for k := 0 to tb.ControlCount-1 do
554              if tb.Controls[k].Left > tb.Controls[j].Left then
555                tb.Controls[k].Left := tb.Controls[k].Left+delta;
556          end;
557        end;
558      end;
559 
560      w := DoScaleX(4, OriginalDPI);
561      for j := 0 to tb.ControlCount-1 do
562        if tb.Controls[j].Visible then
563          w := max(w, tb.Controls[j].Left + tb.Controls[j].Width);
564      w += DoScaleX(4, OriginalDPI);
565      tb.Width := w;
566 
567      if tb.Visible then
568      begin
569        if curx+tb.Width > ClientWidth then
570        begin
571          curx := 0;
572          cury += maxh;
573          maxh := 0;
574        end;
575        tb.Left := curx;
576        tb.Top := cury;
577        inc(curx, tb.Width);
578        if tb.Height > maxh then maxh := tb.Height;
579        maxh := min(maxh, tbNormalHeight);
580      end else
581      begin
582        //hide fix for Gtk
583        tb.Top := -tb.Height;
584      end;
585    end;
586    if curx <> 0 then FToolbarsHeight := cury+maxh else FToolbarsHeight := cury;
587    if FToolbarsHeight = 0 then
588    begin
589      FToolbarBackground.Visible := false;
590    end else
591    begin
592      FToolbarBackground.Top := 0;
593      FToolbarBackground.Left := 0;
594      FToolbarBackground.width := ClientWidth;
595      FToolbarBackground.Height := FToolbarsHeight;
596      FToolbarBackground.Anchors:= [akLeft,akTop,akRight];
597      FToolbarBackground.Visible := true;
598    end;
599 end;
600 
601 procedure TMainFormMenu.RepaintToolbar;
602 var i: NativeInt;
603 begin
604   FToolbarBackground.Invalidate;
605   for i := 0 to high(FToolbars) do FToolbars[i].tb.Invalidate;
606   FToolbarBackground.Update;
607   for i := 0 to high(FToolbars) do FToolbars[i].tb.Update;
608 end;
609 
610 procedure TMainFormMenu.ApplyShortcuts;
611 begin
612   ActionShortcut('ToolHand','H');
613   ActionShortcut('ToolHotSpot','H');
614   ActionShortcut('ToolPen','P');
615   ActionShortcut('ToolBrush','B');
616   ActionShortcut('ToolColorPicker','C');
617   ActionShortcut('ToolEraser','E');
618   ActionShortcut('ToolEditShape','J');
619   ActionShortcut('ToolRect','U');
620   ActionShortcut('ToolEllipse','U');
621   ActionShortcut('ToolPolyline','L');
622   ActionShortcut('ToolOpenedCurve','N');
623   ActionShortcut('ToolPolygon','D');
624   ActionShortcut('ToolSpline','D');
625   ActionShortcut('ToolFloodfill','G');
626   ActionShortcut('ToolGradient','G');
627   ActionShortcut('ToolPhong','G');
628   ActionShortcut('ToolText','T');
629   ActionShortcut('ToolSelectRect','M');
630   ActionShortcut('ToolSelectEllipse','M');
631   ActionShortcut('ToolSelectPoly','A');
632   ActionShortcut('ToolSelectSpline','A');
633   ActionShortcut('ToolMoveSelection','V');
634   ActionShortcut('ToolRotateSelection','V');
635   ActionShortcut('ToolSelectPen','O');
636   ActionShortcut('ToolMagicWand','W');
637   ActionShortcut('ViewZoomIn','+');
638   ActionShortcut('ViewZoomOut','-');
639 end;
640 
641 end.
642 
643