3 /* XPM */
4 static char * core_xpm[] = {
5 "16 16 4 1",
6 " c None",
7 ". c #808080",
8 "+ c #000000",
9 "@ c #FFFFFF",
10 " ",
11 " ",
12 " ",
13 " .++++++. ",
14 " +@+@@+@+ ",
15 " +@+@@+@+ ",
16 " +.+..+.+ ",
17 " +@@@@@@+ ",
18 " +@@@@@@+ ",
19 " +@@@@@@+ ",
20 " +@@@@@@+ ",
21 " +@@@@@@+ ",
22 " .++++++. ",
23 " ",
24 " ",
25 " "};
27 /* XPM */
28 static char *eraser[] = {
29 /* columns rows colors chars-per-pixel */
30 "16 16 5 1",
31 " c black",
32 ". c green",
33 "X c #808080",
34 "o c gray100",
35 "O c None",
36 /* pixels */
37 "OOOOOOOOOOOOOOOO",
38 "OOOOOOOOOOOOO OO",
39 "OOOOOOOOOOOO . O",
40 "OOOOOOOOOOO . OO",
41 "OOOOOOOOOO . OOO",
42 "OOOOOOOOO . OOOO",
43 "OOOOOOOO . OOOOO",
44 "OOOOOOOXo OOOOOO",
45 "OOOOOOXoXOOOOOOO",
46 "OOOOOXoXOOOOOOOO",
47 "OOOOXoXOOOOOOOOO",
48 "OOOXoXOOOOOOOOOO",
49 "OOXoXOOOOOOOOOOO",
50 "OOXXOOOOOOOOOOOO",
51 "OOOOOOOOOOOOOOOO",
52 "OOOOOOOOOOOOOOOO"
53 };
55 /* XPM */
56 static char *mouse[] = {
57 /* columns rows colors chars-per-pixel */
58 "16 16 3 1",
59 " c black",
60 ". c gray100",
61 "X c None",
62 /* pixels */
63 "XXXXXXXXXXXXXXXX",
64 "XXXXXXXXXXXXXXXX",
65 "XXXXXXXXXXXXXXXX",
66 "XXXXXXXXXXXXXXXX",
67 "XXXXXXX XXXXXXX",
68 "XXXXX . XXXXXXX",
69 "XXXX .... XXXXXX",
70 "XXXX .... XXXXXX",
71 "XXXXX .... XXXXX",
72 "XXXXX .... XXXXX",
73 "XXXXXX .... XXXX",
74 "XXXXXX .... XXXX",
75 "XXXXXXX . XXXXX",
76 "XXXXXXX XXXXXXX",
77 "XXXXXXXXXXXXXXXX",
78 "XXXXXXXXXXXXXXXX"
79 };
81 /* XPM */
82 static char *pen[] = {
83 /* columns rows colors chars-per-pixel */
84 "16 16 3 1",
85 " c black",
86 ". c gray100",
87 "X c None",
88 /* pixels */
89 "XXXXXXXXXXXXXXXX",
90 "XXXXXXXXXXXXX XX",
91 "XXXXXXXXXXXX . X",
92 "XXXXXXXXXXX . XX",
93 "XXXXXXXXXX . XXX",
94 "XXXXXXXXX . XXXX",
95 "XXXXXXXX . XXXXX",
96 "XXXXXXX . XXXXXX",
97 "XXXXXX . XXXXXXX",
98 "XXXXX . XXXXXXXX",
99 "XXXX . XXXXXXXXX",
100 "XXX . XXXXXXXXXX",
101 "XX . XXXXXXXXXXX",
102 "XX XXXXXXXXXXXX",
103 "XXXXXXXXXXXXXXXX",
104 "XXXXXXXXXXXXXXXX"
105 };
107 /* XPM */
108 static char *sidebuttons[] = {
109 /* columns rows colors chars-per-pixel */
110 "16 16 4 1",
111 " c black",
112 ". c #808080",
113 "o c green",
114 "O c None",
115 /* pixels */
116 "OOOOOOOOOOOOOOOO",
117 "OOOOOOOOOOOOOOOO",
118 "O..............O",
119 "O.OOOOOOOOOOOO.O",
120 "O OOOOOOOO O",
121 "O o OOOOOOOO o O",
122 "O o OOOOOOOO o O",
123 "O OOOOOOOO O",
124 "O.OOOOOOOOOOOO.O",
125 "O.OOOOOOOOOOOO.O",
126 "O.OOOOOOOOOOOO.O",
127 "O.OOOOOOOOOOOO.O",
128 "O.OOOOOOOOOOOO.O",
129 "O..............O",
130 "OOOOOOOOOOOOOOOO",
131 "OOOOOOOOOOOOOOOO"
132 };
134 /* XPM */
135 static char *tablet[] = {
136 /* columns rows colors chars-per-pixel */
137 "16 16 3 1",
138 " c black",
139 ". c gray100",
140 "X c None",
141 /* pixels */
142 "XXXXXXXXXXXXXXXX",
143 "XXXXXXXXXXXXXXXX",
144 "X X",
145 "X ............ X",
146 "X ............ X",
147 "X ............ X",
148 "X ............ X",
149 "X ............ X",
150 "X ............ X",
151 "X ............ X",
152 "X ............ X",
153 "X ............ X",
154 "X ............ X",
155 "X X",
156 "XXXXXXXXXXXXXXXX",
157 "XXXXXXXXXXXXXXXX"
158 };
160 /* XPM */
161 static char *tip[] = {
162 /* columns rows colors chars-per-pixel */
163 "16 16 5 1",
164 " c black",
165 ". c green",
166 "X c #808080",
167 "o c gray100",
168 "O c None",
169 /* pixels */
170 "OOOOOOOOOOOOOOOO",
171 "OOOOOOOOOOOOOXOO",
172 "OOOOOOOOOOOOXoXO",
173 "OOOOOOOOOOOXoXOO",
174 "OOOOOOOOOOXoXOOO",
175 "OOOOOOOOOXoXOOOO",
176 "OOOOOOOOXoXOOOOO",
177 "OOOOOOO oXOOOOOO",
178 "OOOOOO . OOOOOOO",
179 "OOOOO . OOOOOOOO",
180 "OOOO . OOOOOOOOO",
181 "OOO . OOOOOOOOOO",
182 "OO . OOOOOOOOOOO",
183 "OO OOOOOOOOOOOO",
184 "OOOOXXXXXOOOOOOO",
185 "OOOOOOOOOXXXXXOO"
186 };
188 /* XPM */
189 static char *button_none[] = {
190 /* columns rows colors chars-per-pixel */
191 "8 8 3 1",
192 " c black",
193 ". c #808080",
194 "X c None",
195 /* pixels */
196 "XXXXXXXX",
197 "XX .. XX",
198 "X .XX. X",
199 "X.XX X.X",
200 "X.X XX.X",
201 "X .XX. X",
202 "XX .. XX",
203 "XXXXXXXX"
204 };
205 /* XPM */
206 static char *button_off[] = {
207 /* columns rows colors chars-per-pixel */
208 "8 8 4 1",
209 " c black",
210 ". c #808080",
211 "X c gray100",
212 "o c None",
213 /* pixels */
214 "oooooooo",
215 "oo. .oo",
216 "o. XX .o",
217 "o XXXX o",
218 "o XXXX o",
219 "o. XX .o",
220 "oo. .oo",
221 "oooooooo"
222 };
223 /* XPM */
224 static char *button_on[] = {
225 /* columns rows colors chars-per-pixel */
226 "8 8 3 1",
227 " c black",
228 ". c green",
229 "X c None",
230 /* pixels */
231 "XXXXXXXX",
232 "XX XX",
233 "X .. X",
234 "X .... X",
235 "X .... X",
236 "X .. X",
237 "XX XX",
238 "XXXXXXXX"
239 };
241 /* XPM */
242 static char * axis_none_xpm[] = {
243 "24 8 3 1",
244 " c None",
245 ". c #000000",
246 "+ c #808080",
247 " ",
248 " .++++++++++++++++++. ",
249 " .+ . .+. ",
250 " + . . . + ",
251 " + . . . + ",
252 " .+. . +. ",
253 " .++++++++++++++++++. ",
254 " "};
255 /* XPM */
256 static char * axis_off_xpm[] = {
257 "24 8 4 1",
258 " c None",
259 ". c #808080",
260 "+ c #000000",
261 "@ c #FFFFFF",
262 " ",
263 " .++++++++++++++++++. ",
264 " .+@@@@@@@@@@@@@@@@@@+. ",
265 " +@@@@@@@@@@@@@@@@@@@@+ ",
266 " +@@@@@@@@@@@@@@@@@@@@+ ",
267 " .+@@@@@@@@@@@@@@@@@@+. ",
268 " .++++++++++++++++++. ",
269 " "};
270 /* XPM */
271 static char * axis_on_xpm[] = {
272 "24 8 3 1",
273 " c None",
274 ". c #000000",
275 "+ c #00FF00",
276 " ",
277 " .................... ",
278 " ..++++++++++++++++++.. ",
279 " .++++++++++++++++++++. ",
280 " .++++++++++++++++++++. ",
281 " ..++++++++++++++++++.. ",
282 " .................... ",
283 " "};
289 #include <map>
290 #include <set>
291 #include <glib/gprintf.h>
292 #include <glibmm/i18n.h>
293 #include <gtkmm/comboboxtext.h>
294 #include <gtkmm/enums.h>
295 #include <gtkmm/eventbox.h>
296 #include <gtkmm/frame.h>
297 #include <gtkmm/image.h>
298 #include <gtkmm/menubar.h>
299 #include <gtkmm/notebook.h>
300 #include <gtkmm/paned.h>
301 #include <gtkmm/progressbar.h>
302 #include <gtkmm/scrolledwindow.h>
303 #include <gtkmm/table.h>
304 #include <gtkmm/treemodel.h>
305 #include <gtkmm/treemodelcolumn.h>
306 #include <gtkmm/treestore.h>
307 #include <gtkmm/treeview.h>
309 #include "ui/widget/panel.h"
310 #include "device-manager.h"
312 #include "input.h"
314 using Inkscape::InputDevice;
316 namespace Inkscape {
317 namespace UI {
318 namespace Dialog {
322 class MyModelColumns : public Gtk::TreeModel::ColumnRecord
323 {
324 public:
325 Gtk::TreeModelColumn<Glib::ustring> filename;
326 Gtk::TreeModelColumn<Glib::ustring> description;
327 Gtk::TreeModelColumn< Glib::RefPtr<Gdk::Pixbuf> > thumbnail;
328 Gtk::TreeModelColumn<InputDevice const *> device;
330 MyModelColumns() { add(filename); add(description); add(thumbnail); add(device); }
331 };
333 class InputDialogImpl : public InputDialog {
334 public:
335 InputDialogImpl();
336 virtual ~InputDialogImpl() {}
338 private:
339 Glib::RefPtr<Gdk::Pixbuf> corePix;
340 Glib::RefPtr<Gdk::Pixbuf> penPix;
341 Glib::RefPtr<Gdk::Pixbuf> mousePix;
342 Glib::RefPtr<Gdk::Pixbuf> tipPix;
343 Glib::RefPtr<Gdk::Pixbuf> tabletPix;
344 Glib::RefPtr<Gdk::Pixbuf> eraserPix;
345 Glib::RefPtr<Gdk::Pixbuf> sidebuttonsPix;
347 Glib::RefPtr<Gdk::Pixbuf> buttonsNonePix;
348 Glib::RefPtr<Gdk::Pixbuf> buttonsOnPix;
349 Glib::RefPtr<Gdk::Pixbuf> buttonsOffPix;
351 Glib::RefPtr<Gdk::Pixbuf> axisNonePix;
352 Glib::RefPtr<Gdk::Pixbuf> axisOnPix;
353 Glib::RefPtr<Gdk::Pixbuf> axisOffPix;
355 std::map<Glib::ustring, std::set<guint> > buttonMap;
356 std::map<Glib::ustring, std::map<guint, std::pair<guint, gdouble> > > axesMap;
358 GdkInputSource lastSourceSeen;
359 Glib::ustring lastDevnameSeen;
361 MyModelColumns cols;
362 Glib::RefPtr<Gtk::TreeStore> store;
363 Gtk::TreeView tree;
364 Gtk::Frame frame2;
365 Gtk::Frame testFrame;
366 Gtk::ScrolledWindow treeScroller;
367 Gtk::ScrolledWindow detailScroller;
368 Gtk::HPaned splitter;
369 Gtk::VPaned split2;
370 Gtk::Label devName;
371 Gtk::Label devKeyCount;
372 Gtk::Label devAxesCount;
373 Gtk::ComboBoxText axesCombo;
374 Gtk::ProgressBar axesValues[6];
375 Gtk::ComboBoxText buttonCombo;
376 Gtk::ComboBoxText linkCombo;
377 sigc::connection linkConnection;
378 Gtk::Label keyVal;
379 Gtk::Entry keyEntry;
380 Gtk::Table devDetails;
381 Gtk::HPaned confSplitter;
382 Gtk::Notebook topHolder;
383 Gtk::Image testThumb;
384 Gtk::Image testButtons[24];
385 Gtk::Image testAxes[8];
386 Gtk::Table imageTable;
387 Gtk::EventBox testDetector;
389 void setupValueAndCombo( gint reported, gint actual, Gtk::Label& label, Gtk::ComboBoxText& combo );
390 void updateTestButtons( Glib::ustring const& key, gint hotButton );
391 void updateTestAxes( Glib::ustring const& key, GdkDevice* dev );
392 void mapAxesValues( Glib::ustring const& key, guint numAxes, gdouble const * axes, GdkDevice* dev);
393 Glib::ustring getKeyFor( GdkDevice* device );
394 bool eventSnoop(GdkEvent* event);
395 void linkComboChanged();
396 void resyncToSelection();
397 void handleDeviceChange(const Glib::RefPtr<InputDevice>& device);
398 void updateDeviceButtons(const Glib::RefPtr<InputDevice>& device);
399 void updateDeviceLinks(const Glib::RefPtr<InputDevice>& device);
400 };
403 // Now that we've defined the *Impl class, we can do the method to aquire one.
404 InputDialog &InputDialog::getInstance()
405 {
406 InputDialog *dialog = new InputDialogImpl();
407 return *dialog;
408 }
411 InputDialogImpl::InputDialogImpl() :
412 InputDialog(),
414 corePix(Gdk::Pixbuf::create_from_xpm_data(core_xpm)),
415 penPix(Gdk::Pixbuf::create_from_xpm_data(pen)),
416 mousePix(Gdk::Pixbuf::create_from_xpm_data(mouse)),
417 tipPix(Gdk::Pixbuf::create_from_xpm_data(tip)),
418 tabletPix(Gdk::Pixbuf::create_from_xpm_data(tablet)),
419 eraserPix(Gdk::Pixbuf::create_from_xpm_data(eraser)),
420 sidebuttonsPix(Gdk::Pixbuf::create_from_xpm_data(sidebuttons)),
422 buttonsNonePix(Gdk::Pixbuf::create_from_xpm_data(button_none)),
423 buttonsOnPix(Gdk::Pixbuf::create_from_xpm_data(button_on)),
424 buttonsOffPix(Gdk::Pixbuf::create_from_xpm_data(button_off)),
426 axisNonePix(Gdk::Pixbuf::create_from_xpm_data(axis_none_xpm)),
427 axisOnPix(Gdk::Pixbuf::create_from_xpm_data(axis_on_xpm)),
428 axisOffPix(Gdk::Pixbuf::create_from_xpm_data(axis_off_xpm)),
430 lastSourceSeen((GdkInputSource)-1),
431 lastDevnameSeen(""),
432 cols(),
433 store(Gtk::TreeStore::create(cols)),
434 tree(store),
435 frame2(),
436 testFrame("Test Area"),
437 treeScroller(),
438 detailScroller(),
439 splitter(),
440 split2(),
441 linkCombo(),
442 devDetails(12, 2),
443 confSplitter(),
444 topHolder(),
445 imageTable(8, 7)
446 {
447 Gtk::Box *contents = _getContents();
450 treeScroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
451 treeScroller.add(tree);
452 split2.pack1(testFrame);
453 split2.pack2(frame2);
454 splitter.pack1(treeScroller);
455 splitter.pack2(split2);
457 testDetector.add(imageTable);
458 testFrame.add(testDetector);
459 testThumb.set(tabletPix);
460 testThumb.set_padding(24, 24);
461 imageTable.attach(testThumb, 0, 8, 0, 1, ::Gtk::EXPAND, ::Gtk::EXPAND);
462 {
463 guint col = 0;
464 guint row = 1;
465 for ( guint num = 0; num < G_N_ELEMENTS(testButtons); num++ ) {
466 testButtons[num].set(buttonsNonePix);
467 imageTable.attach(testButtons[num], col, col + 1, row, row + 1, ::Gtk::FILL, ::Gtk::FILL);
468 col++;
469 if (col > 7) {
470 col = 0;
471 row++;
472 }
473 }
475 col = 0;
476 for ( guint num = 0; num < G_N_ELEMENTS(testAxes); num++ ) {
477 testAxes[num].set(axisNonePix);
478 imageTable.attach(testAxes[num], col * 2, (col + 1) * 2, row, row + 1, ::Gtk::FILL, ::Gtk::FILL);
479 col++;
480 if (col > 3) {
481 col = 0;
482 row++;
483 }
484 }
485 }
488 topHolder.append_page(confSplitter, "Configuration");
489 topHolder.append_page(splitter, "Hardware");
490 // confSplitter.show_all();
491 // splitter.show_all();
492 topHolder.show_all();
493 topHolder.set_current_page(1);
495 contents->pack_start(topHolder);
497 int rowNum = 0;
499 Gtk::Label* lbl = Gtk::manage(new Gtk::Label("Name:"));
500 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
501 ::Gtk::FILL,
502 ::Gtk::SHRINK);
503 devDetails.attach(devName, 1, 2, rowNum, rowNum + 1,
504 ::Gtk::SHRINK,
505 ::Gtk::SHRINK);
507 rowNum++;
509 lbl = Gtk::manage(new Gtk::Label("Link:"));
510 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
511 ::Gtk::FILL,
512 ::Gtk::SHRINK);
514 linkCombo.append_text("None");
515 linkCombo.set_active_text("None");
516 linkCombo.set_sensitive(false);
517 linkConnection = linkCombo.signal_changed().connect(sigc::mem_fun(*this, &InputDialogImpl::linkComboChanged));
519 devDetails.attach(linkCombo, 1, 2, rowNum, rowNum + 1,
520 ::Gtk::FILL,
521 ::Gtk::SHRINK);
522 rowNum++;
524 lbl = Gtk::manage(new Gtk::Label("Reported axes count:"));
525 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
526 ::Gtk::FILL,
527 ::Gtk::SHRINK);
528 devDetails.attach(devAxesCount, 1, 2, rowNum, rowNum + 1,
529 ::Gtk::SHRINK,
530 ::Gtk::SHRINK);
532 rowNum++;
534 lbl = Gtk::manage(new Gtk::Label("Actual axes count:"));
535 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
536 ::Gtk::FILL,
537 ::Gtk::SHRINK);
538 devDetails.attach(axesCombo, 1, 2, rowNum, rowNum + 1,
539 ::Gtk::SHRINK,
540 ::Gtk::SHRINK);
542 rowNum++;
544 for ( guint barNum = 0; barNum < static_cast<guint>(G_N_ELEMENTS(axesValues)); barNum++ ) {
545 lbl = Gtk::manage(new Gtk::Label("axis:"));
546 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
547 ::Gtk::FILL,
548 ::Gtk::SHRINK);
549 devDetails.attach(axesValues[barNum], 1, 2, rowNum, rowNum + 1,
550 ::Gtk::EXPAND,
551 ::Gtk::SHRINK);
552 axesValues[barNum].set_sensitive(false);
554 rowNum++;
555 }
557 lbl = Gtk::manage(new Gtk::Label("Reported button count:"));
558 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
559 ::Gtk::FILL,
560 ::Gtk::SHRINK);
561 devDetails.attach(devKeyCount, 1, 2, rowNum, rowNum + 1,
562 ::Gtk::SHRINK,
563 ::Gtk::SHRINK);
565 rowNum++;
567 /*
568 lbl = Gtk::manage(new Gtk::Label("Actual button count:"));
569 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
570 ::Gtk::FILL,
571 ::Gtk::SHRINK);
572 devDetails.attach(buttonCombo, 1, 2, rowNum, rowNum + 1,
573 ::Gtk::SHRINK,
574 ::Gtk::SHRINK);
576 rowNum++;
577 */
579 devDetails.attach(keyVal, 0, 2, rowNum, rowNum + 1,
580 ::Gtk::FILL,
581 ::Gtk::SHRINK);
582 rowNum++;
585 testDetector.signal_event().connect(sigc::mem_fun(*this, &InputDialogImpl::eventSnoop));
587 // void gdk_input_set_extension_events (GdkWindow *window,
588 // gint mask,
589 // GdkExtensionMode mode);
591 gtk_widget_set_extension_events( GTK_WIDGET(testDetector.gobj()), GDK_EXTENSION_EVENTS_ALL );
592 testDetector.add_events(Gdk::POINTER_MOTION_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK |Gdk::PROXIMITY_IN_MASK|Gdk::PROXIMITY_OUT_MASK|Gdk::SCROLL_MASK);
594 devDetails.attach(keyEntry, 0, 2, rowNum, rowNum + 1,
595 ::Gtk::FILL,
596 ::Gtk::SHRINK);
597 rowNum++;
600 devDetails.set_sensitive(false);
601 detailScroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
602 detailScroller.add(devDetails);
603 frame2.add(detailScroller);
605 //- 16x16/devices
606 // gnome-dev-mouse-optical
607 // input-mouse
608 // input-tablet
609 // mouse
613 Gtk::TreeModel::Row row;
614 Gtk::TreeModel::Row childrow;
615 Gtk::TreeModel::Row deviceRow;
618 //Add the TreeView's view columns:
619 tree.append_column("I", cols.thumbnail);
620 tree.append_column("Bar", cols.description);
622 tree.set_enable_tree_lines();
623 tree.set_headers_visible(false);
624 tree.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &InputDialogImpl::resyncToSelection));
628 std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
629 if ( !devList.empty() ) {
630 row = *(store->append());
631 row[cols.description] = "Hardware";
633 childrow = *(store->append(row.children()));
634 childrow[cols.description] = "Tablet";
635 childrow[cols.thumbnail] = tabletPix;
637 for ( std::list<InputDevice const *>::iterator it = devList.begin(); it != devList.end(); ++it ) {
638 InputDevice const* dev = *it;
639 if ( dev ) {
640 // g_message("device: name[%s] source[0x%x] mode[0x%x] cursor[%s] axis count[%d] key count[%d]", dev->getName().c_str(), dev->getSource(), dev->getMode(),
641 // dev->hasCursor() ? "Yes":"no", dev->getNumAxes(), dev->getNumKeys());
643 // if ( dev->getSource() != Gdk::SOURCE_MOUSE ) {
644 if ( dev ) {
645 deviceRow = *(store->append(childrow.children()));
646 deviceRow[cols.description] = dev->getName();
647 deviceRow[cols.device] = dev;
648 switch ( dev->getSource() ) {
649 case GDK_SOURCE_MOUSE:
650 deviceRow[cols.thumbnail] = corePix;
651 break;
652 case GDK_SOURCE_PEN:
653 if (deviceRow[cols.description] == "pad") {
654 deviceRow[cols.thumbnail] = sidebuttonsPix;
655 } else {
656 deviceRow[cols.thumbnail] = tipPix;
657 }
658 break;
659 case GDK_SOURCE_CURSOR:
660 deviceRow[cols.thumbnail] = mousePix;
661 break;
662 case GDK_SOURCE_ERASER:
663 deviceRow[cols.thumbnail] = eraserPix;
664 break;
665 default:
666 ; // nothing
667 }
668 }
669 } else {
670 g_warning("Null device in list");
671 }
672 }
673 } else {
674 g_warning("No devices found");
675 }
676 Inkscape::DeviceManager::getManager().signalDeviceChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::handleDeviceChange));
677 Inkscape::DeviceManager::getManager().signalButtonsChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::updateDeviceButtons));
678 Inkscape::DeviceManager::getManager().signalLinkChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::updateDeviceLinks));
680 tree.expand_all();
681 show_all_children();
682 }
684 void InputDialogImpl::handleDeviceChange(const Glib::RefPtr<InputDevice>& /*device*/)
685 {
686 // g_message("OUCH!!!! for %p hits %s", &device, device->getId().c_str());
687 }
689 void InputDialogImpl::updateDeviceButtons(const Glib::RefPtr<InputDevice>& device)
690 {
691 gint live = device->getLiveButtons();
692 std::set<guint> existing = buttonMap[device->getId()];
693 gint mask = 0x1;
694 for ( gint num = 0; num < 32; num++, mask <<= 1) {
695 if ( (mask & live) != 0 ) {
696 if ( existing.find(num) == existing.end() ) {
697 buttonMap[device->getId()].insert(num);
698 }
699 }
700 }
701 updateTestButtons(device->getId(), -1);
702 }
704 void InputDialogImpl::updateDeviceLinks(const Glib::RefPtr<InputDevice>& /*device*/)
705 {
706 // g_message("Links!!!! for %p hits %s with link of %s", &device, device->getId().c_str(), device->getLink().c_str());
707 }
709 void InputDialogImpl::linkComboChanged() {
710 Glib::RefPtr<Gtk::TreeSelection> treeSel = tree.get_selection();
711 Gtk::TreeModel::iterator iter = treeSel->get_selected();
712 if (iter) {
713 Gtk::TreeModel::Row row = *iter;
714 Glib::ustring val = row[cols.description];
715 InputDevice const * dev = row[cols.device];
716 if ( dev ) {
717 Glib::ustring linkName = linkCombo.get_active_text();
718 std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
719 for ( std::list<InputDevice const *>::const_iterator it = devList.begin(); it != devList.end(); ++it ) {
720 if ( linkName == (*it)->getName() ) {
721 DeviceManager::getManager().setLinkedTo(dev->getId(), (*it)->getId());
722 break;
723 }
724 }
725 }
726 }
727 }
729 void InputDialogImpl::resyncToSelection() {
730 bool clear = true;
731 Glib::RefPtr<Gtk::TreeSelection> treeSel = tree.get_selection();
732 Gtk::TreeModel::iterator iter = treeSel->get_selected();
733 if (iter) {
734 Gtk::TreeModel::Row row = *iter;
735 Glib::ustring val = row[cols.description];
736 InputDevice const * dev = row[cols.device];
737 if ( dev ) {
738 devDetails.set_sensitive(true);
740 linkConnection.block();
741 linkCombo.clear_items();
742 linkCombo.append_text("None");
743 linkCombo.set_active(0);
744 if ( dev->getSource() != Gdk::SOURCE_MOUSE ) {
745 Glib::ustring linked = dev->getLink();
746 std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
747 for ( std::list<InputDevice const *>::const_iterator it = devList.begin(); it != devList.end(); ++it ) {
748 if ( ((*it)->getSource() != Gdk::SOURCE_MOUSE) && ((*it) != dev) ) {
749 linkCombo.append_text((*it)->getName().c_str());
750 if ( (linked.length() > 0) && (linked == (*it)->getId()) ) {
751 linkCombo.set_active_text((*it)->getName().c_str());
752 }
753 }
754 }
755 linkCombo.set_sensitive(true);
756 } else {
757 linkCombo.set_sensitive(false);
758 }
759 linkConnection.unblock();
761 clear = false;
762 devName.set_label(row[cols.description]);
763 setupValueAndCombo( dev->getNumAxes(), dev->getNumAxes(), devAxesCount, axesCombo);
764 setupValueAndCombo( dev->getNumKeys(), dev->getNumKeys(), devKeyCount, buttonCombo);
765 }
766 }
768 devDetails.set_sensitive(!clear);
769 if (clear) {
770 devName.set_label("");
771 devAxesCount.set_label("");
772 devKeyCount.set_label("");
773 }
774 }
776 void InputDialogImpl::setupValueAndCombo( gint reported, gint actual, Gtk::Label& label, Gtk::ComboBoxText& combo )
777 {
778 gchar *tmp = g_strdup_printf("%d", reported);
779 label.set_label(tmp);
780 g_free(tmp);
782 combo.clear_items();
783 for ( gint i = 1; i <= reported; ++i ) {
784 tmp = g_strdup_printf("%d", i);
785 combo.append_text(tmp);
786 g_free(tmp);
787 }
789 if ( (1 <= actual) && (actual <= reported) ) {
790 combo.set_active(actual - 1);
791 }
792 }
794 void InputDialogImpl::updateTestButtons( Glib::ustring const& key, gint hotButton )
795 {
796 for ( gint i = 0; i < static_cast<gint>(G_N_ELEMENTS(testButtons)); i++ ) {
797 if ( buttonMap[key].find(i) != buttonMap[key].end() ) {
798 if ( i == hotButton ) {
799 testButtons[i].set(buttonsOnPix);
800 } else {
801 testButtons[i].set(buttonsOffPix);
802 }
803 } else {
804 testButtons[i].set(buttonsNonePix);
805 }
806 }
807 }
809 void InputDialogImpl::updateTestAxes( Glib::ustring const& key, GdkDevice* dev )
810 {
811 static gdouble epsilon = 0.0001;
812 {
813 Glib::RefPtr<Gtk::TreeSelection> treeSel = tree.get_selection();
814 Gtk::TreeModel::iterator iter = treeSel->get_selected();
815 if (iter) {
816 Gtk::TreeModel::Row row = *iter;
817 Glib::ustring val = row[cols.description];
818 InputDevice const * idev = row[cols.device];
819 if ( !idev || (idev->getId() != key) ) {
820 dev = 0;
821 }
822 }
823 }
826 for ( gint i = 0; i < static_cast<gint>(G_N_ELEMENTS(testAxes)); i++ ) {
827 if ( axesMap[key].find(i) != axesMap[key].end() ) {
828 switch ( axesMap[key][i].first ) {
829 case 0:
830 case 1:
831 testAxes[i].set(axisNonePix);
832 if ( dev && (i < static_cast<gint>(G_N_ELEMENTS(axesValues)) ) ) {
833 axesValues[i].set_sensitive(false);
834 }
835 break;
836 case 2:
837 testAxes[i].set(axisOffPix);
838 axesValues[i].set_sensitive(true);
839 if ( dev && (i < static_cast<gint>(G_N_ELEMENTS(axesValues)) ) ) {
840 if ( (dev->axes[i].max - dev->axes[i].min) > epsilon ) {
841 axesValues[i].set_sensitive(true);
842 axesValues[i].set_fraction( (axesMap[key][i].second- dev->axes[i].min) / (dev->axes[i].max - dev->axes[i].min) );
843 }
844 gchar* str = g_strdup_printf("%f", axesMap[key][i].second);
845 axesValues[i].set_text(str);
846 g_free(str);
847 }
848 break;
849 case 3:
850 testAxes[i].set(axisOnPix);
851 axesValues[i].set_sensitive(true);
852 if ( dev && (i < static_cast<gint>(G_N_ELEMENTS(axesValues)) ) ) {
853 if ( (dev->axes[i].max - dev->axes[i].min) > epsilon ) {
854 axesValues[i].set_sensitive(true);
855 axesValues[i].set_fraction( (axesMap[key][i].second- dev->axes[i].min) / (dev->axes[i].max - dev->axes[i].min) );
856 }
857 gchar* str = g_strdup_printf("%f", axesMap[key][i].second);
858 axesValues[i].set_text(str);
859 g_free(str);
860 }
861 }
863 } else {
864 testAxes[i].set(axisNonePix);
865 }
866 }
867 if ( !dev ) {
868 for ( gint i = 0; i < static_cast<gint>(G_N_ELEMENTS(axesValues)); i++ ) {
869 axesValues[i].set_fraction(0.0);
870 axesValues[i].set_text("");
871 axesValues[i].set_sensitive(false);
872 }
873 }
874 }
876 void InputDialogImpl::mapAxesValues( Glib::ustring const& key, guint numAxes, gdouble const * axes, GdkDevice* dev )
877 {
878 static gdouble epsilon = 0.0001;
879 if ( (numAxes > 0) && axes) {
880 for ( guint axesNum = 0; axesNum < numAxes; axesNum++ ) {
881 // 0 == new, 1 == set value, 2 == changed value, 3 == active
882 gdouble diff = axesMap[key][axesNum].second - axes[axesNum];
883 switch(axesMap[key][axesNum].first) {
884 case 0:
885 {
886 axesMap[key][axesNum].first = 1;
887 axesMap[key][axesNum].second = axes[axesNum];
888 }
889 break;
890 case 1:
891 {
892 if ( (diff > epsilon) || (diff < -epsilon) ) {
893 // g_message("Axis %d changed on %s]", axesNum, key.c_str());
894 axesMap[key][axesNum].first = 3;
895 axesMap[key][axesNum].second = axes[axesNum];
896 updateTestAxes(key, dev);
897 }
898 }
899 break;
900 case 2:
901 {
902 if ( (diff > epsilon) || (diff < -epsilon) ) {
903 axesMap[key][axesNum].first = 3;
904 axesMap[key][axesNum].second = axes[axesNum];
905 updateTestAxes(key, dev);
906 }
907 }
908 break;
909 case 3:
910 {
911 if ( (diff > epsilon) || (diff < -epsilon) ) {
912 axesMap[key][axesNum].second = axes[axesNum];
913 } else {
914 axesMap[key][axesNum].first = 2;
915 updateTestAxes(key, dev);
916 }
917 }
918 }
919 }
920 }
921 // std::map<Glib::ustring, std::map<guint, std::pair<guint, gdouble> > > axesMap;
922 }
924 Glib::ustring InputDialogImpl::getKeyFor( GdkDevice* device )
925 {
926 Glib::ustring key;
927 switch ( device->source ) {
928 case GDK_SOURCE_MOUSE:
929 key = "M:";
930 break;
931 case GDK_SOURCE_CURSOR:
932 key = "C:";
933 break;
934 case GDK_SOURCE_PEN:
935 key = "P:";
936 break;
937 case GDK_SOURCE_ERASER:
938 key = "E:";
939 break;
940 default:
941 key = "?:";
942 }
943 key += device->name;
945 return key;
946 }
948 bool InputDialogImpl::eventSnoop(GdkEvent* event)
949 {
950 int modmod = 0;
952 GdkInputSource source = lastSourceSeen;
953 Glib::ustring devName = lastDevnameSeen;
954 Glib::ustring key;
955 gint hotButton = -1;
957 switch ( event->type ) {
958 case GDK_KEY_PRESS:
959 case GDK_KEY_RELEASE:
960 {
961 GdkEventKey* keyEvt = reinterpret_cast<GdkEventKey*>(event);
962 gchar* name = gtk_accelerator_name(keyEvt->keyval, static_cast<GdkModifierType>(keyEvt->state));
963 keyVal.set_label(name);
964 // g_message("%d KEY state:0x%08x 0x%04x [%s]", keyEvt->type, keyEvt->state, keyEvt->keyval, name);
965 g_free(name);
966 }
967 break;
968 case GDK_BUTTON_PRESS:
969 modmod = 1;
970 // fallthrough
971 case GDK_BUTTON_RELEASE:
972 {
973 GdkEventButton* btnEvt = reinterpret_cast<GdkEventButton*>(event);
974 if ( btnEvt->device ) {
975 key = getKeyFor(btnEvt->device);
976 source = btnEvt->device->source;
977 devName = btnEvt->device->name;
979 mapAxesValues(key, btnEvt->device->num_axes, btnEvt->axes, btnEvt->device);
980 if ( buttonMap[key].find(btnEvt->button) == buttonMap[key].end() ) {
981 // g_message("New button found for %s = %d", key.c_str(), btnEvt->button);
982 buttonMap[key].insert(btnEvt->button);
983 DeviceManager::getManager().addButton(key, btnEvt->button);
984 }
985 hotButton = modmod ? btnEvt->button : -1;
986 updateTestButtons(key, hotButton);
987 }
988 gchar* name = gtk_accelerator_name(0, static_cast<GdkModifierType>(btnEvt->state));
989 keyVal.set_label(name);
990 // g_message("%d BTN state:0x%08x %c %4d [%s] dev:%p [%s] ",
991 // btnEvt->type, btnEvt->state,
992 // (modmod ? '+':'-'),
993 // btnEvt->button, name, btnEvt->device,
994 // (btnEvt->device ? btnEvt->device->name : "null")
996 // );
997 g_free(name);
998 }
999 break;
1000 case GDK_MOTION_NOTIFY:
1001 {
1002 GdkEventMotion* btnMtn = reinterpret_cast<GdkEventMotion*>(event);
1003 if ( btnMtn->device ) {
1004 key = getKeyFor(btnMtn->device);
1005 source = btnMtn->device->source;
1006 devName = btnMtn->device->name;
1007 mapAxesValues(key, btnMtn->device->num_axes, btnMtn->axes, btnMtn->device);
1008 }
1009 gchar* name = gtk_accelerator_name(0, static_cast<GdkModifierType>(btnMtn->state));
1010 keyVal.set_label(name);
1011 // g_message("%d MOV state:0x%08x [%s] dev:%p [%s] %3.2f %3.2f %3.2f %3.2f %3.2f %3.2f", btnMtn->type, btnMtn->state,
1012 // name, btnMtn->device,
1013 // (btnMtn->device ? btnMtn->device->name : "null"),
1014 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 0)) ? btnMtn->axes[0]:0),
1015 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 1)) ? btnMtn->axes[1]:0),
1016 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 2)) ? btnMtn->axes[2]:0),
1017 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 3)) ? btnMtn->axes[3]:0),
1018 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 4)) ? btnMtn->axes[4]:0),
1019 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 5)) ? btnMtn->axes[5]:0)
1020 // );
1021 g_free(name);
1022 }
1023 break;
1024 default:
1025 ;// nothing
1026 }
1029 if ( (lastSourceSeen != source) || (lastDevnameSeen != devName) ) {
1030 switch (source) {
1031 case GDK_SOURCE_MOUSE:
1032 {
1033 testThumb.set(corePix);
1034 }
1035 break;
1036 case GDK_SOURCE_CURSOR:
1037 {
1038 // g_message("flip to cursor");
1039 testThumb.set(mousePix);
1040 }
1041 break;
1042 case GDK_SOURCE_PEN:
1043 {
1044 if (devName == "pad") {
1045 // g_message("flip to pad");
1046 testThumb.set(sidebuttonsPix);
1047 } else {
1048 // g_message("flip to pen");
1049 testThumb.set(tipPix);
1050 }
1051 }
1052 break;
1053 case GDK_SOURCE_ERASER:
1054 {
1055 // g_message("flip to eraser");
1056 testThumb.set(eraserPix);
1057 }
1058 break;
1059 // default:
1060 // g_message("gurgle");
1061 }
1062 updateTestButtons(key, hotButton);
1063 lastSourceSeen = source;
1064 lastDevnameSeen = devName;
1065 }
1067 return false;
1068 }
1071 } // end namespace Inkscape
1072 } // end namespace UI
1073 } // end namespace Dialog
1076 /*
1077 Local Variables:
1078 mode:c++
1079 c-file-style:"stroustrup"
1080 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1081 indent-tabs-mode:nil
1082 fill-column:99
1083 End:
1084 */
1085 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :