1 /*
2 * Copyright (C) 2002 - David W. Durham
3 *
4 * This file is part of ReZound, an audio editing application.
5 *
6 * ReZound is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License,
9 * or (at your option) any later version.
10 *
11 * ReZound is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20
21 #include "CKeyBindingsDialog.h"
22
23 #include "settings.h"
24 #include "CStatusComm.h"
25
26 #include <ctype.h>
27 #include <stdio.h>
28
29 #include <CNestedDataFile/CNestedDataFile.h>
30
31 CKeyBindingsDialog *gKeyBindingsDialog=NULL;
32
33
34 #if REZ_FOX_VERSION<10501
35 FXString unparseAccel(FXHotKey key);
36 #endif
37
parseItemText(const string itemText,string & name,string & key)38 void parseItemText(const string itemText,string &name,string &key)
39 {
40 size_t tab_pos=itemText.find("\t");
41 name=itemText.substr(0,tab_pos);
42 key=itemText.substr(tab_pos+1);
43 }
44
45 // -----------------------------------------
46
47 class CAssignPopup : public FXDialogBox
48 {
49 FXDECLARE(CAssignPopup);
50 public:
CAssignPopup(FXWindow * owner)51 CAssignPopup(FXWindow *owner) :
52 FXDialogBox(owner,_("Assign Hotkey"),DECOR_TITLE|DECOR_BORDER, 200,50)
53 {
54
55 FXVerticalFrame *t=new FXVerticalFrame(this,LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0, 5,5,5,5, 5,5);
56
57 new FXLabel(t,_("Press a Key Combination"),NULL, LABEL_NORMAL|LAYOUT_CENTER_X);
58 new FXButton(t,_("Assign No Key"),NULL,this,ID_NOKEY_BUTTON, BUTTON_NORMAL|LAYOUT_CENTER_X);
59 new FXButton(t,_("Cancel"),NULL,this,ID_CANCEL, BUTTON_NORMAL|LAYOUT_CENTER_X);
60 }
61
~CAssignPopup()62 virtual ~CAssignPopup()
63 {
64 }
65
66 FXuint key;
showIt()67 FXuint showIt()
68 {
69 if(execute())
70 return key;
71 return 0;
72 }
73
onNoKeyButton(FXObject * sender,FXSelector sel,void * ptr)74 long onNoKeyButton(FXObject *sender,FXSelector sel,void *ptr)
75 {
76 key=1;
77 FXDialogBox::handle(this,MKUINT(ID_ACCEPT,SEL_COMMAND),ptr);
78 return 1;
79 }
80
onKeyRelease(FXObject * sender,FXSelector sel,void * ptr)81 long onKeyRelease(FXObject *sender,FXSelector sel,void *ptr)
82 {
83 FXEvent *ev=(FXEvent *)ptr;
84 if(ev->code>=KEY_Shift_L && ev->code<=KEY_Hyper_R)
85 { // in fox these are contiguously defined, and we won't get key release events for these keys.. they're just modifiers
86 return 1;
87 }
88
89 key=MKUINT(tolower(ev->code),ev->state);
90 FXDialogBox::handle(this,MKUINT(ID_ACCEPT,SEL_COMMAND),ptr);
91 return 1;
92 }
93
94 enum
95 {
96 ID_NOKEY_BUTTON=FXDialogBox::ID_LAST,
97 ID_LAST
98 };
99
CAssignPopup()100 CAssignPopup() {}
101
102 };
103
104 FXDEFMAP(CAssignPopup) CAssignPopupMap[]=
105 {
106 // Message_Type ID Message_Handler
107 FXMAPFUNC(SEL_COMMAND, CAssignPopup::ID_NOKEY_BUTTON, CAssignPopup::onNoKeyButton),
108 FXMAPFUNC(SEL_KEYRELEASE, 0, CAssignPopup::onKeyRelease),
109 };
110
111 FXIMPLEMENT(CAssignPopup,FXDialogBox,CAssignPopupMap,ARRAYNUMBER(CAssignPopupMap))
112
113 // -----------------------------------------
114
115
116
117
118
119
120
121
122
123 FXDEFMAP(CKeyBindingsDialog) CKeyBindingsDialogMap[]=
124 {
125 // Message_Type ID Message_Handler
126 FXMAPFUNC(SEL_DOUBLECLICKED, CKeyBindingsDialog::ID_HOTKEY_LIST, CKeyBindingsDialog::onDefineKeyBinding),
127 FXMAPFUNC(SEL_COMMAND, CKeyBindingsDialog::ID_ASSIGN_BUTTON, CKeyBindingsDialog::onDefineKeyBinding)
128 };
129
130
FXIMPLEMENT(CKeyBindingsDialog,FXModalDialogBox,CKeyBindingsDialogMap,ARRAYNUMBER (CKeyBindingsDialogMap))131 FXIMPLEMENT(CKeyBindingsDialog,FXModalDialogBox,CKeyBindingsDialogMap,ARRAYNUMBER(CKeyBindingsDialogMap))
132
133
134 FXint sortfunc(const FXIconItem *a,const FXIconItem *b)
135 {
136 return strcasecmp(a->getText().text(), b->getText().text());
137 }
138
139
140 // ----------------------------------------
141
CKeyBindingsDialog(FXWindow * mainWindow)142 CKeyBindingsDialog::CKeyBindingsDialog(FXWindow *mainWindow) :
143 FXModalDialogBox(mainWindow,N_("Hot Keys"),600,550,FXModalDialogBox::ftVertical)
144 {
145
146 assignPopup=new CAssignPopup(this);
147
148 new FXLabel(getFrame(),_("Assign Hot Keys"));
149 //new FXHorizontalSeparator(getFrame(),SEPARATOR_GROOVE|LAYOUT_FILL_X|LAYOUT_BOTTOM);
150
151 FXPacker *t;
152
153 // build hot keys list
154 t=new FXPacker(getFrame(),LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0, 4,4,2,3, 0,0);
155 t=new FXPacker(t,LAYOUT_FILL_X|LAYOUT_FILL_Y | FRAME_SUNKEN|FRAME_THICK, 0,0,0,0, 0,0,0,0, 0,0);
156 hotkeyList=new FXIconList(t,this,ID_HOTKEY_LIST,HSCROLLER_NEVER|ICONLIST_BROWSESELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y);
157
158 /*
159 soundListFont=getApp()->getNormalFont();
160 shuttleFont->getFontDesc(d);
161 d.weight=FONTWEIGHT_NORMAL;
162 d.size=80;
163 soundListFont=new FXFont(getApp(),d);
164
165 soundList->setFont(soundListFont);
166
167 soundListHeaderFont=getApp()->getNormalFont();
168 shuttleFont->getFontDesc(d);
169 d.weight=FONTWEIGHT_BOLD;
170 d.size=80;
171 soundListHeaderFont=new FXFont(getApp(),d);
172 */
173
174 //soundList->getHeader()->setFont(soundListHeaderFont);
175 hotkeyList->getHeader()->setPadLeft(2);
176 hotkeyList->getHeader()->setPadRight(2);
177 hotkeyList->getHeader()->setPadTop(0);
178 hotkeyList->getHeader()->setPadBottom(0);
179
180 hotkeyList->appendHeader(_("Action"),NULL,400);
181 hotkeyList->appendHeader(_("Hot Key"),NULL,9999);
182
183 hotkeyList->setSortFunc(sortfunc);
184
185 new FXButton(getFrame(),_("Assign\tOr Double-Click An Item"),NULL,this,ID_ASSIGN_BUTTON);
186
187 }
188
~CKeyBindingsDialog()189 CKeyBindingsDialog::~CKeyBindingsDialog()
190 {
191 delete assignPopup;
192 }
193
onDefineKeyBinding(FXObject * sender,FXSelector sel,void * ptr)194 long CKeyBindingsDialog::onDefineKeyBinding(FXObject *sender,FXSelector sel,void *ptr)
195 {
196 FXint index=hotkeyList->getCurrentItem();
197 if(index>=0)
198 {
199 string name,key;
200 parseItemText(hotkeyList->getItemText(index).text(),name,key);
201
202 FXuint keycode=assignPopup->showIt();
203 if(keycode>0)
204 {
205 if(keycode==1)
206 { // special return value meaning to unassign
207 key="";
208 }
209 else
210 {
211 string tmp_key=unparseAccel(keycode).text();
212 if(tmp_key=="")
213 Error(_("Unhandled Key Combination"));
214 else
215 {
216 // verify if it's already been assigned
217 for(FXint t=0;t<hotkeyList->getNumItems();t++)
218 {
219 if(t==index)
220 continue; // skip the one we're assigning to
221
222 string name,key;
223 parseItemText(hotkeyList->getItemText(t).text(),name,key);
224
225 if(key==tmp_key)
226 {
227 if(Question("'"+tmp_key+"'"+_(" is already assigned to: ")+name+"\n\n"+_("Do you want to override the existing key assignment?"),yesnoQues)==yesAns)
228 {
229 hotkeyList->setItemText(t,name.c_str());
230 break;
231 }
232 else
233 return 1; // cancel the assignment
234 }
235 }
236
237 // ok make the assignment
238 key=tmp_key;
239 }
240 }
241
242 hotkeyList->setItemText(index,(name+"\t"+key).c_str());
243 }
244
245 }
246
247 return 1;
248 }
249
showIt(const map<string,FXMenuCommand * > & keyBindingRegistry)250 bool CKeyBindingsDialog::showIt(const map<string,FXMenuCommand *> &keyBindingRegistry)
251 {
252 hotkeyList->clearItems();
253
254 for(map<string,FXMenuCommand *>::const_iterator i=keyBindingRegistry.begin(); i!=keyBindingRegistry.end(); i++)
255 {
256 const string name=i->first;
257
258 string key="";
259 if(gKeyBindingsStore->keyExists(name))
260 key=gKeyBindingsStore->getValue<string>(name);
261
262 hotkeyList->appendItem( (i->first+"\t"+key).c_str() );
263 }
264
265 hotkeyList->sortItems();
266
267 if(execute())
268 {
269 for(FXint t=0;t<hotkeyList->getNumItems();t++)
270 {
271 string name,key;
272 parseItemText(hotkeyList->getItemText(t).text(),name,key);
273
274 gKeyBindingsStore->setValue<string>(name,key);
275 }
276 gKeyBindingsStore->save();
277
278
279 return true;
280 }
281 return false;
282 }
283
284 #if REZ_FOX_VERSION<10501
fxunparseAccel(FXHotKey key)285 FXString fxunparseAccel(FXHotKey key)
286 {
287 FXString s;
288
289 FXuint code=key&0xffff;
290 FXuint mods=(key&0xffff0000)>>16;
291
292 // handle modifier keys
293 if(mods&CONTROLMASK)
294 s+="ctrl+";
295 if(mods&ALTMASK)
296 s+="alt+";
297 if(mods&SHIFTMASK)
298 s+="shift+";
299 if(mods&METAMASK)
300 s+="meta+";
301
302
303 // handle some special keys
304 switch(code)
305 {
306 case KEY_Home:
307 s+="Home";
308 break;
309
310 case KEY_End:
311 s+="End";
312 break;
313
314 case KEY_Page_Up:
315 s+="PgUp";
316 break;
317
318 case KEY_Page_Down:
319 s+="PgDn";
320 break;
321
322 case KEY_Left:
323 s+="Left";
324 break;
325
326 case KEY_Right:
327 s+="Right";
328 break;
329
330 case KEY_Up:
331 s+="Up";
332 break;
333
334 case KEY_Down:
335 s+="Down";
336 break;
337
338 case KEY_Insert:
339 s+="Ins";
340 break;
341
342 case KEY_Delete:
343 s+="Del";
344 break;
345
346 case KEY_Escape:
347 s+="Esc";
348 break;
349
350 case KEY_Tab:
351 s+="Tab";
352 break;
353
354 case KEY_Return:
355 s+="Return";
356 break;
357
358 case KEY_BackSpace:
359 s+="Back";
360 break;
361
362 case KEY_space:
363 s+="Space";
364 break;
365
366 case KEY_F1:
367 case KEY_F2:
368 case KEY_F3:
369 case KEY_F4:
370 case KEY_F5:
371 case KEY_F6:
372 case KEY_F7:
373 case KEY_F8:
374 case KEY_F9:
375 case KEY_F10:
376 case KEY_F11:
377 case KEY_F12:
378 case KEY_F13:
379 case KEY_F14:
380 case KEY_F15:
381 case KEY_F16:
382 case KEY_F17:
383 case KEY_F18:
384 case KEY_F19:
385 case KEY_F20:
386 case KEY_F21:
387 case KEY_F22:
388 case KEY_F23:
389 case KEY_F24:
390 case KEY_F25:
391 case KEY_F26:
392 case KEY_F27:
393 case KEY_F28:
394 case KEY_F29:
395 case KEY_F30:
396 case KEY_F31:
397 case KEY_F32:
398 case KEY_F33:
399 case KEY_F34:
400 case KEY_F35:
401 {
402 char buffer[64];
403 sprintf(buffer,"F%d",code-KEY_F1+1);
404 s+=buffer;
405 }
406 break;
407
408 default:
409 if(isprint(code))
410 {
411 if(mods&SHIFTMASK)
412 s+=(char)toupper(code);
413 else
414 s+=(char)tolower(code);
415 }
416 else
417 {
418 return ""; // return that it's unknown
419 /* would like to do this, but fxparseAccel wouldn't handle it inversly .. can I get this changed?
420 char buffer[64];
421 sprintf(buffer,"#%d",code);
422 s+=buffer;
423 */
424 }
425 break;
426 }
427
428 return s;
429 }
430 #endif
431