1 {
2  *****************************************************************************
3   This file is part of the EducationLaz package
4 
5   See the file COPYING.modifiedLGPL.txt, included in this distribution,
6   for details about the license.
7  *****************************************************************************
8 
9   Author: Mattias Gaertner, Michael Kuhardt
10 
11   Abstract:
12     Frame to setup the component palette.
13 }
14 unit EduCompPalette;
15 
16 {$mode objfpc}{$H+}
17 
18 interface
19 
20 uses
21   Classes, SysUtils, Laz_AVL_Tree,
22   // LCL
23   LCLProc, LCLType, LResources, Forms, Controls, Graphics, Dialogs, ComCtrls,
24   ExtCtrls, StdCtrls,
25   // LazUtils
26   LazConfigStorage, AvgLvlTree,
27   // IdeIntf
28   FormEditingIntf, IDEOptionsIntf, IDEOptEditorIntf, ComponentReg, IDEImagesIntf,
29   // Education
30   EduOptions;
31 
32 type
33   { TEduComponentPaletteOptions }
34 
35   TEduComponentPaletteOptions = class(TEduOptionsNode)
36   private
37     fVisible: TStringToStringTree;
GetComponentVisiblenull38     function GetComponentVisible(ComponentName: string): boolean;
39     procedure SetComponentVisible(ComponentName: string; const AValue: boolean);
40     procedure VoteForVisible(AComponent: TRegisteredComponent; var Vote: integer);
41   public
42     constructor Create; override;
43     destructor Destroy; override;
Loadnull44     function Load(Config: TConfigStorage): TModalResult; override;
Savenull45     function Save(Config: TConfigStorage): TModalResult; override;
46     procedure Apply(Enable: boolean); override;
47     property ComponentVisible[ComponentName: string]: boolean read GetComponentVisible write SetComponentVisible;
48   end;
49 
50   { TEduCompPaletteFrame }
51 
52   TEduCompPaletteFrame = class(TAbstractIDEOptionsEditor)
53     ShowExtendedButton: TButton;
54     ShowMinimalButton: TButton;
55     ComponentsGroupBox: TGroupBox;
56     ComponentsTreeView: TTreeView;
57     HideAllButton: TButton;
58     LeftPanel: TPanel;
59     ShowAllButton: TButton;
60     procedure ComponentsTreeViewMouseDown(Sender: TObject;
61       Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer);
62     procedure FrameClick(Sender: TObject);
63     procedure HideAllButtonClick(Sender: TObject);
64     procedure ShowAllButtonClick(Sender: TObject);
65     procedure ShowExtendedButtonClick(Sender: TObject);
66     procedure ShowMinimalButtonClick(Sender: TObject);
67   private
68     HideImgID: LongInt;
69     ShowImgID: LongInt;
70     fCompNameToImgIndex: TStringToPointerTree; // Component.ClassName to index+1 in TreeViews.Images
71     procedure FillComponentTreeView;
72     procedure SaveFillComponentTreeView;
73     procedure ShowHideAll(aShow: boolean);
74     procedure ShowSelected(extended: boolean);
75   public
76     destructor Destroy; override;
GetTitlenull77     function GetTitle: String; override;
78     procedure ReadSettings(AOptions: TAbstractIDEOptions); override;
79     procedure Setup({%H-}ADialog: TAbstractOptionsEditorDialog); override;
SupportedOptionsClassnull80     class function SupportedOptionsClass: TAbstractIDEOptionsClass; override;
81     procedure WriteSettings(AOptions: TAbstractIDEOptions); override;
82   end;
83 
84 var
85   EduComponentPaletteOptions: TEduComponentPaletteOptions = nil;
86 
87 procedure Register;
88 
89 implementation
90 
91 procedure Register;
92 begin
93   EduComponentPaletteOptions:=TEduComponentPaletteOptions.Create;
94   EducationOptions.Root.Add(EduComponentPaletteOptions);
95   EduOptionCompPaletteID:=RegisterIDEOptionsEditor(EduOptionID,
96                             TEduCompPaletteFrame,EduOptionCompPaletteID)^.Index;
97 end;
98 
99 { TEduCompPaletteFrame }
100 
101 procedure TEduCompPaletteFrame.ComponentsTreeViewMouseDown(Sender: TObject;
102   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
103 var
104   Node: TTreeNode;
105   Hit: THitTests;
106 begin
107   if Button<>mbLeft then exit;
108   Node:=ComponentsTreeView.GetNodeAt(X,Y);
109   if (Node=nil) then exit;
110   if Node.Parent=nil then exit;
111   Hit:=ComponentsTreeView.GetHitTestInfoAt(X,Y);
112   if [htOnIcon,htOnStateIcon]*Hit<>[] then begin
113     if Node.StateIndex=ShowImgID then
114       Node.StateIndex:=HideImgID
115     else
116       Node.StateIndex:=ShowImgID;
117   end;
118 end;
119 
120 procedure TEduCompPaletteFrame.FrameClick(Sender: TObject);
121 begin
122 
123 end;
124 
125 procedure TEduCompPaletteFrame.HideAllButtonClick(Sender: TObject);
126 begin
127   ShowHideAll(false);
128 end;
129 
130 procedure TEduCompPaletteFrame.ShowAllButtonClick(Sender: TObject);
131 begin
132   ShowHideAll(true);
133 end;
134 
135 procedure TEduCompPaletteFrame.ShowExtendedButtonClick(Sender: TObject);
136 begin
137   ShowHideAll(false);
138   ShowSelected(true);
139 end;
140 
141 procedure TEduCompPaletteFrame.ShowMinimalButtonClick(Sender: TObject);
142 begin
143   ShowHideAll(false);
144   ShowSelected(false);
145 end;
146 
147 procedure TEduCompPaletteFrame.FillComponentTreeView;
148 
GetIconCopynull149   function GetIconCopy(ResName: string): TCustomBitMap;
150   var
151     ResHandle: TLResource;
152   begin
153     Result := nil;
154     // prevent raising exception and speedup a bit search/load
155     ResHandle := LazarusResources.Find(ResName);
156     if ResHandle <> nil then
157       Result := CreateBitmapFromLazarusResource(ResHandle)
158     else
159     if FindResource(HInstance, PChar(ResName), PChar(RT_BITMAP)) <> 0 then
160     begin
161       Result := TBitmap.Create;
162       Result.LoadFromResourceName(HInstance, ResName);
163       Result.Transparent := True;
164     end
165     else
166     if FindResource(HInstance, PChar(ResName), PChar(RT_RCDATA)) <> 0 then
167       Result := CreateBitmapFromResourceName(HInstance, ResName);
168   end;
169 
GetCompImgIndexnull170   function GetCompImgIndex(ResName: string): integer;
171   var
172     Img: TCustomBitmap;
173   begin
174     if fCompNameToImgIndex=nil then
175       fCompNameToImgIndex:=TStringToPointerTree.Create(false);
176     if fCompNameToImgIndex.Contains(ResName) then begin
177       Result:=PtrUInt(fCompNameToImgIndex[ResName])-1;
178     end else begin
179       // load
180       Img:=GetIconCopy(ResName);
181       if Img=nil then
182         Img:=GetIconCopy('unregisteredcomponent');
183       if Img<>nil then begin
184         Result:=ComponentsTreeView.Images.Add(Img,nil);
185         Img.Free;
186       end else begin
187         Result:=-1;
188       end;
189       fCompNameToImgIndex[ResName]:=Pointer(PtrUInt(Result+1));
190     end;
191   end;
192 
193 var
194   i: Integer;
195   Page: TBaseComponentPage;
196   PageNode: TTreeNode;
197   CompNode: TTreeNode;
198   CompName: String;
199   Comp: TRegisteredComponent;
200 begin
201   ComponentsTreeView.BeginUpdate;
202   ComponentsTreeView.Items.Clear;
203   if ComponentsTreeView.Images=nil then begin
204     ComponentsTreeView.Images:=TImageList.Create(Self);
205     ComponentsTreeView.Images.Width:=ComponentPaletteImageWidth;
206     ComponentsTreeView.Images.Height:=ComponentPaletteImageHeight;
207     ComponentsTreeView.StateImages:=IDEImages.Images_16;
208   end else
209     ComponentsTreeView.Images.Clear;
210   ShowImgID:=IDEImages.LoadImage('menu_run');
211   HideImgID:=IDEImages.LoadImage('menu_stop');
212   for i:=0 to IDEComponentPalette.Comps.Count-1 do begin
213     Comp:=IDEComponentPalette.Comps[i];
214     Page:=Comp.RealPage;
215     if (Page=nil) or (Page.PageName='') then continue;
216     PageNode:=ComponentsTreeView.Items.FindTopLvlNode(Page.PageName);
217     if PageNode=nil then
218       PageNode:=ComponentsTreeView.Items.Add(nil,Page.PageName);
219     CompName:=Comp.ComponentClass.ClassName;
220     CompNode:=ComponentsTreeView.Items.AddChild(PageNode,CompName);
221     CompNode.ImageIndex:=GetCompImgIndex(CompName);
222     CompNode.SelectedIndex:=CompNode.ImageIndex;
223     if EduComponentPaletteOptions.ComponentVisible[CompName] then
224       CompNode.StateIndex:=ShowImgID
225     else
226       CompNode.StateIndex:=HideImgID;
227     PageNode.Expanded:=true;
228   end;
229   ComponentsTreeView.EndUpdate;
230 end;
231 
232 procedure TEduCompPaletteFrame.SaveFillComponentTreeView;
233 var
234   Node: TTreeNode;
235   CompName: String;
236 begin
237   Node:=ComponentsTreeView.Items.GetFirstNode;
238   while Node<>nil do begin
239     if Node.Parent<>nil then begin
240       CompName:=Node.Text;
241       EduComponentPaletteOptions.ComponentVisible[CompName]:=
242         Node.StateIndex=ShowImgID;
243     end else begin
244 
245     end;
246     Node:=Node.GetNext;
247   end;
248 end;
249 
250 procedure TEduCompPaletteFrame.ShowHideAll(aShow: boolean);
251 var
252   Node: TTreeNode;
253   CompName: String;
254 begin
255   ComponentsTreeView.BeginUpdate;
256   Node:=ComponentsTreeView.Items.GetFirstNode;
257   while Node<>nil do begin
258     if Node.Parent<>nil then begin
259       CompName:=Node.Text;
260 
261       EduComponentPaletteOptions.ComponentVisible[CompName]:=aShow;
262       if aShow then
263         Node.StateIndex:=ShowImgID
264       else
265         Node.StateIndex:=HideImgID;
266     end
267 
268     else begin
269 
270     end;
271 
272     Node:=Node.GetNext;
273   end;
274   ComponentsTreeView.EndUpdate;
275 end;
276 
277 procedure TEduCompPaletteFrame.ShowSelected(extended: boolean);
278 var
279   Node: TTreeNode;
280   CompName: String;
281   MinimalComponents: array[0..12] of String;
282   ExtendedComponents: array[0..25] of String;
283   i,k: integer;
284 begin
285 
286   MinimalComponents[0] :=  'TEdit';
287   MinimalComponents[1] :=  'TButton';
288   MinimalComponents[2] :=  'TCheckBox';
289   MinimalComponents[3] :=  'TLabel';
290   MinimalComponents[4] :=  'TListBox';
291   MinimalComponents[5] :=  'TComboBox';
292   MinimalComponents[6] :=  'TRadioGroup';
293   MinimalComponents[7] :=  'TRadioButton';
294   MinimalComponents[8] :=  'TPanel';
295   MinimalComponents[9] :=  'TMainMenu';
296   MinimalComponents[10] :=  'TMemo';
297   MinimalComponents[11] :=  'TGroupBox';
298   MinimalComponents[12] :=  'TImage';
299 
300   ExtendedComponents[0] :=  'TBitBtn';
301   ExtendedComponents[1] :=  'TScrollBar';
302   ExtendedComponents[2] :=  'TPopupMenu';
303   ExtendedComponents[3] :=  'TCheckGroup';
304   ExtendedComponents[4] :=  'TActionList';
305   ExtendedComponents[5] :=  'TStringGrid';
306   ExtendedComponents[6] :=  'TSpeedButton';
307   ExtendedComponents[7] :=  'TTimer';
308   ExtendedComponents[8] :=  'TIdleTimer';
309   ExtendedComponents[9] :=  'TPageControl';
310   ExtendedComponents[10] :=  'TStaticText';
311   ExtendedComponents[11] :=  'TDBGrid';
312   ExtendedComponents[12] :=  'TOpenDialog';
313   ExtendedComponents[13] :=  'TSaveDialog';
314   ExtendedComponents[14] :=  'TSelectDirectoryDialog';
315   ExtendedComponents[15] :=  'TDataSource';
316   ExtendedComponents[16] :=  'TDBNavigator';
317   ExtendedComponents[17] :=  'TDBText';
318   ExtendedComponents[18] :=  'TDBEdit';
319   ExtendedComponents[19] :=  'TDBMemo';
320   ExtendedComponents[20] :=  'TDBImage';
321   ExtendedComponents[21] :=  'TDBListBox';
322   ExtendedComponents[22] :=  'TDBLookupListBox';
323   ExtendedComponents[23] :=  'TDBComboBox';
324   ExtendedComponents[24] :=  'TDBLookupComboBox';
325   ExtendedComponents[25] :=  'TDBCheckBox';
326 
327   ComponentsTreeView.BeginUpdate;
328   Node:=ComponentsTreeView.Items.GetFirstNode;
329   while Node<>nil do begin
330     if Node.Parent<>nil then begin
331       CompName:=Node.Text;
332       for i := 0 to 12 do begin
333         if (CompareText (CompName , MinimalComponents[i] )=0) then begin
334             EduComponentPaletteOptions.ComponentVisible[CompName]:=true;
335             Node.StateIndex:=ShowImgID;
336         end;
337       end;
338 
339       if extended then begin
340         for k := 0 to 25 do begin
341           if (CompareText (CompName , ExtendedComponents[k] )=0) then begin
342             EduComponentPaletteOptions.ComponentVisible[CompName]:=true;
343             Node.StateIndex:=ShowImgID;
344           end;
345         end;
346       end;
347 
348     end;
349 
350     Node:=Node.GetNext;
351   end;
352   ComponentsTreeView.EndUpdate;
353 end;
354 
355 destructor TEduCompPaletteFrame.Destroy;
356 begin
357   FreeAndNil(fCompNameToImgIndex);
358   inherited Destroy;
359 end;
360 
TEduCompPaletteFrame.GetTitlenull361 function TEduCompPaletteFrame.GetTitle: String;
362 begin
363   Result:=ersEduCompPaletteTitle;
364 end;
365 
366 procedure TEduCompPaletteFrame.ReadSettings(AOptions: TAbstractIDEOptions);
367 begin
368   if AOptions=EducationOptions then begin
369     FillComponentTreeView;
370   end;
371 end;
372 
373 procedure TEduCompPaletteFrame.Setup(ADialog: TAbstractOptionsEditorDialog);
374 begin
375   ShowAllButton.Caption:=ersShowAll;
376   HideAllButton.Caption:=ersHideAll;
377   ShowMinimalButton.Caption:=ersShowMinimal;
378   ShowExtendedButton.Caption:=ersShowExtended;
379   ComponentsGroupBox.Caption:=ersVisibleComponents;
380 end;
381 
TEduCompPaletteFrame.SupportedOptionsClassnull382 class function TEduCompPaletteFrame.SupportedOptionsClass: TAbstractIDEOptionsClass;
383 begin
384   Result:=EducationIDEOptionsClass;
385 end;
386 
387 procedure TEduCompPaletteFrame.WriteSettings(AOptions: TAbstractIDEOptions);
388 begin
389   if AOptions=EducationOptions then begin
390     SaveFillComponentTreeView;
391   end;
392 end;
393 
394 { TEduComponentPaletteOptions }
395 
GetComponentVisiblenull396 function TEduComponentPaletteOptions.GetComponentVisible(ComponentName: string): boolean;
397 begin
398   Result:=fVisible[ComponentName]='1';
399 end;
400 
401 procedure TEduComponentPaletteOptions.SetComponentVisible(
402   ComponentName: string; const AValue: boolean);
403 begin
404   if AValue then
405     fVisible[ComponentName]:='1'
406   else
407     fVisible.Remove(ComponentName);
408 end;
409 
410 procedure TEduComponentPaletteOptions.VoteForVisible(
411   AComponent: TRegisteredComponent; var Vote: integer);
412 begin
413   if not ComponentVisible[AComponent.ComponentClass.ClassName] then dec(Vote,100);
414 end;
415 
416 constructor TEduComponentPaletteOptions.Create;
417 begin
418   inherited Create;
419   Name:='ComponentPalette';
420   fVisible:=TStringToStringTree.Create(false);
421   IDEComponentPalette.AddHandlerUpdateVisible(@VoteForVisible);
422 end;
423 
424 destructor TEduComponentPaletteOptions.Destroy;
425 begin
426   if IDEComponentPalette<>nil then
427     IDEComponentPalette.RemoveHandlerUpdateVisible(@VoteForVisible);
428   FreeAndNil(fVisible);
429   inherited Destroy;
430 end;
431 
TEduComponentPaletteOptions.Loadnull432 function TEduComponentPaletteOptions.Load(Config: TConfigStorage): TModalResult;
433 var
434   Cnt: LongInt;
435   i: Integer;
436   ComponentName: String;
437 begin
438   fVisible.Clear;
439   Cnt:=Config.GetValue('Visible/Count',0);
440   for i:=1 to Cnt do begin
441     ComponentName:=Config.GetValue('Visible/Item'+IntToStr(i),'');
442     if ComponentName='' then continue;
443     fVisible[ComponentName]:='1';
444   end;
445   Result:=inherited Load(Config);
446 end;
447 
TEduComponentPaletteOptions.Savenull448 function TEduComponentPaletteOptions.Save(Config: TConfigStorage): TModalResult;
449 var
450   Node: TAvlTreeNode;
451   Item: PStringToStringItem;
452   Cnt: Integer;
453 begin
454   Cnt:=0;
455   Node:=fVisible.Tree.FindLowest;
456   while Node<>nil do begin
457     inc(Cnt);
458     Item:=PStringToStringItem(Node.Data);
459     Config.SetDeleteValue('Visible/Item'+IntToStr(Cnt),Item^.Name,'');
460     Node:=fVisible.Tree.FindSuccessor(Node);
461   end;
462   Config.SetDeleteValue('Visible/Count',Cnt,0);
463   Result:=inherited Save(Config);
464 end;
465 
466 procedure TEduComponentPaletteOptions.Apply(Enable: boolean);
467 begin
468   inherited Apply(Enable);
469   if IDEComponentPalette<>nil then
470     IDEComponentPalette.Update(False);
471 end;
472 
473 {$R *.lfm}
474 
475 end.
476