1 unit MouseActionDialog;
2 
3 {$mode objfpc}{$H+}
4 
5 interface
6 
7 uses
8   Classes, Forms, Controls, ExtCtrls, StdCtrls, ButtonPanel, Spin, CheckLst,
9   SynEditMouseCmds, LazarusIDEStrConsts, KeyMapping, IDECommands, types, EnvironmentOpts;
10 
11 var
12   ButtonName: Array [TSynMouseButton] of String;
13   ClickName: Array [TSynMAClickCount] of String;
14   ButtonDirName: Array [TSynMAClickDir] of String;
15 
16 type
17 
18   { TMouseaActionDialog }
19 
20   TMouseaActionDialog = class(TForm)
21     ActionBox: TComboBox;
22     ActionLabel: TLabel;
23     AltCheck: TCheckBox;
24     BtnDefault: TButton;
25     BtnLabel: TLabel;
26     ButtonBox: TComboBox;
27     ButtonPanel1: TButtonPanel;
28     CaretCheck: TCheckBox;
29     chkUpRestrict: TCheckListBox;
30     ClickBox: TComboBox;
31     DirCheck: TCheckBox;
32     PaintBox1: TPaintBox;
33     PriorLabel: TLabel;
34     OptBox: TComboBox;
35     CtrlCheck: TCheckBox;
36     CapturePanel: TPanel;
37     OptLabel: TLabel;
38     Opt2Spin: TSpinEdit;
39     Opt2Label: TLabel;
40     ShiftCheck: TCheckBox;
41     PriorSpin: TSpinEdit;
42     procedure ActionBoxChange(Sender: TObject);
43     procedure BtnDefaultClick(Sender: TObject);
44     procedure ButtonBoxChange(Sender: TObject);
45     procedure CapturePanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState;
46       {%H-}X, {%H-}Y: Integer);
47     procedure DirCheckChange(Sender: TObject);
48     procedure FormCreate(Sender: TObject);
49     procedure PaintBox1MouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer;
50       {%H-}MousePos: TPoint; var {%H-}Handled: Boolean);
51     procedure PaintBox1MouseWheelHorz(Sender: TObject; Shift: TShiftState;
52       WheelDelta: Integer; {%H-}MousePos: TPoint; var {%H-}Handled: Boolean);
53   private
54     FKeyMap: TKeyCommandRelationList;
55     procedure AddMouseCmd(const S: string);
56     procedure FillListbox;
57   public
58     { public declarations }
59     Procedure ResetInputs;
60     Procedure ReadFromAction(MAct: TSynEditMouseAction);
61     Procedure WriteToAction(MAct: TSynEditMouseAction);
62     property KeyMap: TKeyCommandRelationList read FKeyMap write FKeyMap;
63   end;
64 
KeyMapIndexOfCommandnull65   function KeyMapIndexOfCommand(AKeyMap: TKeyCommandRelationList; ACmd: Word) : Integer;
66 
67 implementation
68 
69 uses Math;
70 
71 {$R *.lfm}
72 
73 const
74   BtnToIndex: array [TSynMouseButton] of Integer = (0, 1, 2, 3, 4, 5, 6, 7 ,8);
75   ClickToIndex: array [ccSingle..ccAny] of Integer = (0, 1, 2, 3, 4);
76   IndexToBtn: array [0..8] of TSynMouseButton = (mbXLeft, mbXRight, mbXMiddle, mbXExtra1, mbXExtra2, mbXWheelUp, mbXWheelDown, mbXWheelLeft, mbXWheelRight);
77   IndexToClick: array [0..4] of TSynMAClickCount = (ccSingle, ccDouble, ccTriple, ccQuad, ccAny);
78 
KeyMapIndexOfCommandnull79 function KeyMapIndexOfCommand(AKeyMap: TKeyCommandRelationList; ACmd: Word): Integer;
80 var
81   i: Integer;
82 begin
83   for i := 0 to AKeyMap.RelationCount - 1 do
84     if AKeyMap.Relations[i].Command = ACmd then
85       exit(i);
86   Result := -1;
87 end;
88 
89 { MouseaActionDialog }
90 
91 procedure TMouseaActionDialog.AddMouseCmd(const S: string);
92 var
93   i: Integer;
94   s2: String;
95 begin
96   i:=0;
97   if IdentToSynMouseCmd(S, i) then begin
98     s2 := MouseCommandName(i);
99     if s2 = '' then s2 := s;
100     ActionBox.Items.AddObject(s2, TObject(ptrint(i)));
101   end;
102 end;
103 
104 procedure TMouseaActionDialog.FillListbox;
105 const
106   cCheckSize=35;
107 var
108   r: TSynMAUpRestriction;
109   s: string;
110   i, Len: integer;
111 begin
112   for r := low(TSynMAUpRestriction) to high(TSynMAUpRestriction) do
113     case r of
114       crLastDownPos:          chkUpRestrict.AddItem(synfMatchActionPosOfMouseDown, nil);
115       crLastDownPosSameLine:  chkUpRestrict.AddItem(synfMatchActionLineOfMouseDown, nil);
116       crLastDownPosSearchAll: chkUpRestrict.AddItem(synfSearchAllActionOfMouseDown, nil);
117       crLastDownButton:       chkUpRestrict.AddItem(synfMatchActionButtonOfMouseDown, nil);
118       crLastDownShift:        chkUpRestrict.AddItem(synfMatchActionModifiersOfMouseDown, nil);
119       crAllowFallback:        chkUpRestrict.AddItem(synfContinueWithNextMouseUpAction, nil);
120       else begin
121         WriteStr(s, r);
122         chkUpRestrict.AddItem(s, nil);
123       end;
124     end;
125 
126   // update scrollbar
127   Len := 0;
128   with chkUpRestrict do
129   begin
130     for i := 0 to Items.Count-1 do
131       Len := Max(Len, Canvas.TextWidth(Items[i])+cCheckSize);
132     ScrollWidth := Len;
133   end;
134 end;
135 
136 procedure TMouseaActionDialog.FormCreate(Sender: TObject);
137 var
138   mb: TSynMouseButton;
139   cc: TSynMAClickCount;
140 begin
141   ButtonName[mbXLeft]:=dlgMouseOptBtnLeft;
142   ButtonName[mbXRight]:=dlgMouseOptBtnRight;
143   ButtonName[mbXMiddle]:=dlgMouseOptBtnMiddle;
144   ButtonName[mbXExtra1]:=dlgMouseOptBtnExtra1;
145   ButtonName[mbXExtra2]:=dlgMouseOptBtnExtra2;
146   ButtonName[mbXWheelUp]:=dlgMouseOptBtnWheelUp;
147   ButtonName[mbXWheelDown]:=dlgMouseOptBtnWheelDown;
148   ButtonName[mbXWheelLeft]:=dlgMouseOptBtnWheelLeft;
149   ButtonName[mbXWheelRight]:=dlgMouseOptBtnWheelRight;
150 
151   ClickName[ccSingle]:=dlgMouseOptBtn1;
152   ClickName[ccDouble]:=dlgMouseOptBtn2;
153   ClickName[ccTriple]:=dlgMouseOptBtn3;
154   ClickName[ccQuad]:=dlgMouseOptBtn4;
155   ClickName[ccAny]:=dlgMouseOptBtnAny;
156 
157   FillListbox;
158 
159   ButtonDirName[cdUp]:=lisUp;
160   ButtonDirName[cdDown]:=lisDown;
161 
162   Caption := dlgMouseOptDlgTitle;
163   CapturePanel.Caption := dlgMouseOptCapture;
164   CapturePanel.ControlStyle := ControlStyle + [csTripleClicks, csQuadClicks];
165   CaretCheck.Caption := dlgMouseOptCaretMove;
166   ActionBox.Clear;
167   GetEditorMouseCommandValues(@AddMouseCmd);
168   ButtonBox.Clear;
169   for mb := low(TSynMouseButton) to high(TSynMouseButton) do
170     ButtonBox.Items.add(ButtonName[mb]);
171   ClickBox.Clear;
172   for cc:= low(TSynMAClickCount) to high(TSynMAClickCount) do
173     ClickBox.Items.add(ClickName[cc]);
174   DirCheck.Caption   := dlgMouseOptCheckUpDown;
175   ShiftCheck.Caption := dlgMouseOptModShift;
176   AltCheck.Caption   := dlgMouseOptModAlt;
177   CtrlCheck.Caption  := dlgMouseOptModCtrl;
178   ActionLabel.Caption := dlgMouseOptDescAction;
179   BtnLabel.Caption := dlgMouseOptDescButton;
180   BtnDefault.Caption :=  dlgMouseOptBtnModDef;
181   PriorLabel.Caption := dlgMouseOptPriorLabel;
182   Opt2Label.Caption := dlgMouseOptOpt2Label;
183   ActionBox.DropDownCount := EnvironmentOptions.DropDownCount;
184   OptBox.DropDownCount := EnvironmentOptions.DropDownCount;
185 end;
186 
187 procedure TMouseaActionDialog.ResetInputs;
188 var
189   r: TSynMAUpRestriction;
190 begin
191   ActionBox.ItemIndex := 0;
192   ButtonBox.ItemIndex := 0;
193   ClickBox.ItemIndex  := 0;
194   DirCheck.Checked    := False;
195   ShiftCheck.State := cbGrayed;
196   AltCheck.State := cbGrayed;
197   CtrlCheck.State := cbGrayed;
198   for r := low(TSynMAUpRestriction) to high(TSynMAUpRestriction) do
199     chkUpRestrict.Checked[ord(r)] := False;
200 
201   ActionBoxChange(nil);
202   OptBox.ItemIndex := 0;
203 end;
204 
205 procedure TMouseaActionDialog.BtnDefaultClick(Sender: TObject);
206 begin
207   ShiftCheck.State := cbGrayed;
208   AltCheck.State := cbGrayed;
209   CtrlCheck.State := cbGrayed;
210 end;
211 
212 procedure TMouseaActionDialog.ButtonBoxChange(Sender: TObject);
213 begin
214   DirCheck.Enabled := not(IndexToBtn[ButtonBox.ItemIndex] in [mbXWheelUp, mbXWheelDown, mbXWheelLeft, mbXWheelRight]);
215   chkUpRestrict.Enabled := DirCheck.Enabled and DirCheck.Checked;
216 end;
217 
218 procedure TMouseaActionDialog.ActionBoxChange(Sender: TObject);
219 var
220   ACmd: TSynEditorMouseCommand;
221   i: Integer;
222 begin
223   OptBox.Items.Clear;
224   ACmd := TSynEditorMouseCommand({%H-}PtrUInt(ActionBox.items.Objects[ActionBox.ItemIndex]));
225   if ACmd =  emcSynEditCommand then begin
226     OptBox.Enabled := True;
227     OptBox.Clear;
228     for i := 0 to KeyMap.RelationCount - 1 do
229       if (KeyMap.Relations[i].Category.Scope = IDECmdScopeSrcEdit) or
230          (KeyMap.Relations[i].Category.Scope = IDECmdScopeSrcEditOnly)
231       then
232         OptBox.Items.AddObject(KeyMap.Relations[i].GetLocalizedName,
233                                TObject({%H-}Pointer(PtrUInt(KeyMap.Relations[i].Command))));
234     OptLabel.Caption := dlgMouseOptionsynCommand;
235     OptBox.ItemIndex := 0;
236   end
237   else
238   begin
239     OptBox.Items.CommaText := MouseCommandConfigName(ACmd);
240     if OptBox.Items.Count > 0 then begin
241       OptLabel.Caption := OptBox.Items[0];
242       OptBox.Items.Delete(0);
243       OptBox.Enabled := True;
244       OptBox.ItemIndex := 0;
245     end else begin
246       OptLabel.Caption := '';
247       OptBox.Enabled := False
248     end;
249   end;
250 end;
251 
252 procedure TMouseaActionDialog.CapturePanelMouseDown(Sender: TObject;
253   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
254 begin
255   ButtonBox.ItemIndex := BtnToIndex[SynMouseButtonMap[Button]];
256   ClickBox.ItemIndex := 0;
257   if ssDouble in Shift then ClickBox.ItemIndex := 1;
258   if ssTriple in Shift then ClickBox.ItemIndex := 2;
259   if ssQuad in Shift then ClickBox.ItemIndex := 3;
260   ShiftCheck.Checked := ssShift in Shift;
261   AltCheck.Checked   := ssAlt in Shift;
262   CtrlCheck.Checked  := ssCtrl in Shift;
263 end;
264 
265 procedure TMouseaActionDialog.DirCheckChange(Sender: TObject);
266 begin
267   chkUpRestrict.Enabled := DirCheck.Checked;
268 end;
269 
270 procedure TMouseaActionDialog.PaintBox1MouseWheel(Sender: TObject; Shift: TShiftState;
271   WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
272 begin
273   if WheelDelta > 0
274   then ButtonBox.ItemIndex := BtnToIndex[mbXWheelUp]
275   else ButtonBox.ItemIndex := BtnToIndex[mbXWheelDown];
276   ClickBox.ItemIndex := 4;
277   ShiftCheck.Checked := ssShift in Shift;
278   AltCheck.Checked   := ssAlt in Shift;
279   CtrlCheck.Checked  := ssCtrl in Shift;
280 end;
281 
282 procedure TMouseaActionDialog.PaintBox1MouseWheelHorz(Sender: TObject;
283   Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
284   var Handled: Boolean);
285 begin
286   if WheelDelta < 0
287   then ButtonBox.ItemIndex := BtnToIndex[mbXWheelLeft]
288   else ButtonBox.ItemIndex := BtnToIndex[mbXWheelRight];
289   ClickBox.ItemIndex := 4;
290   ShiftCheck.Checked := ssShift in Shift;
291   AltCheck.Checked   := ssAlt in Shift;
292   CtrlCheck.Checked  := ssCtrl in Shift;
293 end;
294 
295 procedure TMouseaActionDialog.ReadFromAction(MAct: TSynEditMouseAction);
296 var
297   r: TSynMAUpRestriction;
298 begin
299   ActionBox.ItemIndex := ActionBox.Items.IndexOfObject(TObject({%H-}Pointer(PtrUInt(MAct.Command))));
300   ButtonBox.ItemIndex := BtnToIndex[MAct.Button];
301   ClickBox.ItemIndex  := ClickToIndex[MAct.ClickCount];
302   DirCheck.Checked    := MAct.ClickDir = cdUp;
303   CaretCheck.Checked := MAct.MoveCaret;
304   ShiftCheck.Checked := (ssShift in MAct.ShiftMask) and (ssShift in MAct.Shift);
305   if not(ssShift in MAct.ShiftMask) then ShiftCheck.State := cbGrayed;
306   AltCheck.Checked := (ssAlt in MAct.ShiftMask) and (ssAlt in MAct.Shift);
307   if not(ssAlt in MAct.ShiftMask) then AltCheck.State := cbGrayed;
308   CtrlCheck.Checked := (ssCtrl in MAct.ShiftMask) and (ssCtrl in MAct.Shift);
309   if not(ssCtrl in MAct.ShiftMask) then CtrlCheck.State := cbGrayed;
310   PriorSpin.Value := MAct.Priority;
311   Opt2Spin.Value := MAct.Option2;
312   for r := low(TSynMAUpRestriction) to high(TSynMAUpRestriction) do
313     chkUpRestrict.Checked[ord(r)] := r in MAct.ButtonUpRestrictions;
314 
315   ActionBoxChange(nil);
316   ButtonBoxChange(nil);
317   if OptBox.Enabled then begin
318     if MAct.Command =  emcSynEditCommand then
319       OptBox.ItemIndex := OptBox.Items.IndexOfObject(TObject({%H-}Pointer(PtrUInt(MAct.Option))))
320     else
321       OptBox.ItemIndex := MAct.Option;
322   end;
323 end;
324 
325 procedure TMouseaActionDialog.WriteToAction(MAct: TSynEditMouseAction);
326 var
327   r: TSynMAUpRestriction;
328 begin
329   MAct.Command := TSynEditorMouseCommand({%H-}PtrUInt(Pointer(ActionBox.items.Objects[ActionBox.ItemIndex])));
330   MAct.Button := IndexToBtn[ButtonBox.ItemIndex];
331   MAct.ClickCount := IndexToClick[ClickBox.ItemIndex];
332   MAct.MoveCaret := CaretCheck.Checked;
333   if DirCheck.Checked
334   then MAct.ClickDir := cdUp
335   else MAct.ClickDir := cdDown;
336   MAct.Shift := [];
337   MAct.ShiftMask := [];
338   if ShiftCheck.State <> cbGrayed then MAct.ShiftMask := MAct.ShiftMask + [ssShift];
339   if AltCheck.State <> cbGrayed then MAct.ShiftMask := MAct.ShiftMask + [ssAlt];
340   if CtrlCheck.State <> cbGrayed then MAct.ShiftMask := MAct.ShiftMask + [ssCtrl];
341   if ShiftCheck.Checked then MAct.Shift := MAct.Shift + [ssShift];
342   if AltCheck.Checked then MAct.Shift := MAct.Shift + [ssAlt];
343   if CtrlCheck.Checked then MAct.Shift := MAct.Shift + [ssCtrl];
344   MAct.Priority := PriorSpin.Value;
345   MAct.Option2 := Opt2Spin.Value;
346   MAct.ButtonUpRestrictions := [];
347   for r := low(TSynMAUpRestriction) to high(TSynMAUpRestriction) do
348     if chkUpRestrict.Checked[ord(r)] then
349       MAct.ButtonUpRestrictions := MAct.ButtonUpRestrictions + [r];
350 
351   if OptBox.Enabled then begin
352     if MAct.Command =  emcSynEditCommand then begin
353       MAct.Option := TSynEditorMouseCommandOpt({%H-}PtrUInt(OptBox.Items.Objects[OptBox.ItemIndex]));
354     end
355     else
356       MAct.Option := OptBox.ItemIndex;
357   end
358   else
359     MAct.Option := 0;
360 end;
361 
362 end.
363 
364