Code

f5746dbdecb413eece434b7b71a4f5755551d0e5
[inkscape.git] / src / ui / dialog / input.cpp
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 };
246 #include <map>
247 #include <set>
248 #include <glib/gprintf.h>
249 #include <glibmm/i18n.h>
250 #include <gtkmm/comboboxtext.h>
251 #include <gtkmm/enums.h>
252 #include <gtkmm/frame.h>
253 #include <gtkmm/image.h>
254 #include <gtkmm/menubar.h>
255 #include <gtkmm/notebook.h>
256 #include <gtkmm/paned.h>
257 #include <gtkmm/scrolledwindow.h>
258 #include <gtkmm/table.h>
259 #include <gtkmm/eventbox.h>
260 #include <gtkmm/treemodel.h>
261 #include <gtkmm/treemodelcolumn.h>
262 #include <gtkmm/treestore.h>
263 #include <gtkmm/treeview.h>
265 #include "ui/widget/panel.h"
266 #include "device-manager.h"
268 #include "input.h"
270 using Inkscape::InputDevice;
272 namespace Inkscape {
273 namespace UI {
274 namespace Dialog {
278 class MyModelColumns : public Gtk::TreeModel::ColumnRecord
280 public:
281     Gtk::TreeModelColumn<Glib::ustring>                filename;
282     Gtk::TreeModelColumn<Glib::ustring>                description;
283     Gtk::TreeModelColumn< Glib::RefPtr<Gdk::Pixbuf> >  thumbnail;
284     Gtk::TreeModelColumn<InputDevice const *>          device;
286     MyModelColumns() { add(filename); add(description); add(thumbnail); add(device); }
287 };
289 class InputDialogImpl : public InputDialog {
290 public:
291     InputDialogImpl();
292     virtual ~InputDialogImpl() {}
294 private:
295     Glib::RefPtr<Gdk::Pixbuf> corePix;
296     Glib::RefPtr<Gdk::Pixbuf> penPix;
297     Glib::RefPtr<Gdk::Pixbuf> mousePix;
298     Glib::RefPtr<Gdk::Pixbuf> tipPix;
299     Glib::RefPtr<Gdk::Pixbuf> tabletPix;
300     Glib::RefPtr<Gdk::Pixbuf> eraserPix;
301     Glib::RefPtr<Gdk::Pixbuf> sidebuttonsPix;
303     Glib::RefPtr<Gdk::Pixbuf> buttonsNonePix;
304     Glib::RefPtr<Gdk::Pixbuf> buttonsOnPix;
305     Glib::RefPtr<Gdk::Pixbuf> buttonsOffPix;
307     std::map<Glib::ustring, std::set<guint> > buttonMap;
309     GdkInputSource lastSourceSeen;
310     Glib::ustring lastDevnameSeen;
312     MyModelColumns cols;
313     Glib::RefPtr<Gtk::TreeStore> store;
314     Gtk::TreeView tree;
315     Gtk::Frame frame2;
316     Gtk::Frame testFrame;
317     Gtk::ScrolledWindow treeScroller;
318     Gtk::ScrolledWindow detailScroller;
319     Gtk::HPaned splitter;
320     Gtk::VPaned split2;
321     Gtk::Label devName;
322     Gtk::Label devKeyCount;
323     Gtk::Label devAxesCount;
324     Gtk::ComboBoxText axesCombo;
325     Gtk::ComboBoxText buttonCombo;
326     Gtk::ComboBoxText linkCombo;
327     sigc::connection linkConnection;
328     Gtk::Label keyVal;
329     Gtk::Entry keyEntry;
330     Gtk::Table devDetails;
331     Gtk::HPaned confSplitter;
332     Gtk::Notebook topHolder;
333     Gtk::Image testThumb;
334     Gtk::Image testButtons[24];
335     Gtk::Table imageTable;
336     Gtk::EventBox testDetector;
338     void setupValueAndCombo( gint reported, gint actual, Gtk::Label& label, Gtk::ComboBoxText& combo );
339     void updateTestButtons( Glib::ustring const& key, gint hotButton );
340     Glib::ustring getKeyFor( GdkDevice* device );
341     bool eventSnoop(GdkEvent* event);
342     void linkComboChanged();
343     void resyncToSelection();
344     void handleDeviceChange(const Glib::RefPtr<InputDevice>& device);
345     void updateDeviceButtons(const Glib::RefPtr<InputDevice>& device);
346     void updateDeviceLinks(const Glib::RefPtr<InputDevice>& device);
347 };
350 // Now that we've defined the *Impl class, we can do the method to aquire one.
351 InputDialog &InputDialog::getInstance()
353     InputDialog *dialog = new InputDialogImpl();
354     return *dialog;
358 InputDialogImpl::InputDialogImpl() :
359     InputDialog(),
361     corePix(Gdk::Pixbuf::create_from_xpm_data(core_xpm)),
362     penPix(Gdk::Pixbuf::create_from_xpm_data(pen)),
363     mousePix(Gdk::Pixbuf::create_from_xpm_data(mouse)),
364     tipPix(Gdk::Pixbuf::create_from_xpm_data(tip)),
365     tabletPix(Gdk::Pixbuf::create_from_xpm_data(tablet)),
366     eraserPix(Gdk::Pixbuf::create_from_xpm_data(eraser)),
367     sidebuttonsPix(Gdk::Pixbuf::create_from_xpm_data(sidebuttons)),
369     buttonsNonePix(Gdk::Pixbuf::create_from_xpm_data(button_none)),
370     buttonsOnPix(Gdk::Pixbuf::create_from_xpm_data(button_on)),
371     buttonsOffPix(Gdk::Pixbuf::create_from_xpm_data(button_off)),
373     lastSourceSeen((GdkInputSource)-1),
374     lastDevnameSeen(""),
375     cols(),
376     store(Gtk::TreeStore::create(cols)),
377     tree(store),
378     frame2(),
379     testFrame("Test Area"),
380     treeScroller(),
381     detailScroller(),
382     splitter(),
383     split2(),
384     linkCombo(),
385     devDetails(6, 2),
386     confSplitter(),
387     topHolder(),
388     imageTable(8, 4)
390     Gtk::Box *contents = _getContents();
393     treeScroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
394     treeScroller.add(tree);
395     split2.pack1(testFrame);
396     split2.pack2(frame2);
397     splitter.pack1(treeScroller);
398     splitter.pack2(split2);
400     testDetector.add(imageTable);
401     testFrame.add(testDetector);
402     testThumb.set(tabletPix);
403     testThumb.set_padding(24, 24);
404     imageTable.attach(testThumb, 0, 8, 0, 1, ::Gtk::EXPAND, ::Gtk::EXPAND);
405     {
406         guint col = 0;
407         guint row = 1;
408         for ( guint num = 0; num < 24; num++ ) {
409             testButtons[num].set(buttonsNonePix);
410             imageTable.attach(testButtons[num], col, col + 1, row, row + 1, ::Gtk::FILL, ::Gtk::FILL);
411             col++;
412             if (col > 7) {
413                 col = 0;
414                 row++;
415             }
416         }
417     }
420     topHolder.append_page(confSplitter, "Configuration");
421     topHolder.append_page(splitter, "Hardware");
422 //     confSplitter.show_all();
423 //     splitter.show_all();
424     topHolder.show_all();
425     topHolder.set_current_page(1);
427     contents->pack_start(topHolder);
429     int rowNum = 0;
431     Gtk::Label* lbl = Gtk::manage(new Gtk::Label("Name:"));
432     devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
433                       ::Gtk::FILL,
434                       ::Gtk::SHRINK);
435     devDetails.attach(devName, 1, 2, rowNum, rowNum + 1,
436                       ::Gtk::SHRINK,
437                       ::Gtk::SHRINK);
439     rowNum++;
441     lbl = Gtk::manage(new Gtk::Label("Link:"));
442     devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
443                       ::Gtk::FILL,
444                       ::Gtk::SHRINK);
446     linkCombo.append_text("None");
447     linkCombo.set_active_text("None");
448     linkCombo.set_sensitive(false);
449     linkConnection = linkCombo.signal_changed().connect(sigc::mem_fun(*this, &InputDialogImpl::linkComboChanged));
451     devDetails.attach(linkCombo, 1, 2, rowNum, rowNum + 1,
452                       ::Gtk::FILL,
453                       ::Gtk::SHRINK);
454     rowNum++;
456     lbl = Gtk::manage(new Gtk::Label("Reported axes count:"));
457     devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
458                       ::Gtk::FILL,
459                       ::Gtk::SHRINK);
460     devDetails.attach(devAxesCount, 1, 2, rowNum, rowNum + 1,
461                       ::Gtk::SHRINK,
462                       ::Gtk::SHRINK);
464     rowNum++;
466     lbl = Gtk::manage(new Gtk::Label("Actual axes count:"));
467     devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
468                       ::Gtk::FILL,
469                       ::Gtk::SHRINK);
470     devDetails.attach(axesCombo, 1, 2, rowNum, rowNum + 1,
471                       ::Gtk::SHRINK,
472                       ::Gtk::SHRINK);
474     rowNum++;
476     lbl = Gtk::manage(new Gtk::Label("Reported button count:"));
477     devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
478                       ::Gtk::FILL,
479                       ::Gtk::SHRINK);
480     devDetails.attach(devKeyCount, 1, 2, rowNum, rowNum + 1,
481                       ::Gtk::SHRINK,
482                       ::Gtk::SHRINK);
484     rowNum++;
486 /*
487     lbl = Gtk::manage(new Gtk::Label("Actual button count:"));
488     devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
489                       ::Gtk::FILL,
490                       ::Gtk::SHRINK);
491     devDetails.attach(buttonCombo, 1, 2, rowNum, rowNum + 1,
492                       ::Gtk::SHRINK,
493                       ::Gtk::SHRINK);
495     rowNum++;
496 */
498     devDetails.attach(keyVal, 0, 2, rowNum, rowNum + 1,
499                       ::Gtk::FILL,
500                       ::Gtk::SHRINK);
501     rowNum++;
504     testDetector.signal_event().connect(sigc::mem_fun(*this, &InputDialogImpl::eventSnoop));
506 //     void gdk_input_set_extension_events (GdkWindow        *window,
507 //                                          gint              mask,
508 //                                          GdkExtensionMode  mode);
510     gtk_widget_set_extension_events( GTK_WIDGET(testDetector.gobj()), GDK_EXTENSION_EVENTS_ALL );
511     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);
513     devDetails.attach(keyEntry, 0, 2, rowNum, rowNum + 1,
514                       ::Gtk::FILL,
515                       ::Gtk::SHRINK);
516     rowNum++;
519     devDetails.set_sensitive(false);
520     detailScroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
521     detailScroller.add(devDetails);
522     frame2.add(detailScroller);
524 //- 16x16/devices
525 // gnome-dev-mouse-optical
526 // input-mouse
527 // input-tablet
528 // mouse
532     Gtk::TreeModel::Row row;
533     Gtk::TreeModel::Row childrow;
534     Gtk::TreeModel::Row deviceRow;
537     //Add the TreeView's view columns:
538     tree.append_column("I", cols.thumbnail);
539     tree.append_column("Bar", cols.description);
541     tree.set_enable_tree_lines();
542     tree.set_headers_visible(false);
543     tree.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &InputDialogImpl::resyncToSelection));
547     std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
548     if ( !devList.empty() ) {
549         {
550             GdkModifierType  defaultModMask = static_cast<GdkModifierType>(gtk_accelerator_get_default_mod_mask());
551             gchar* name = gtk_accelerator_name(GDK_a, defaultModMask);
552             gchar* label = gtk_accelerator_get_label(GDK_a, defaultModMask);
553             g_message("Name: [%s]  label:[%s]", name, label);
554             g_free(name);
555             g_free(label);
556         }
558         row = *(store->append());
559         row[cols.description] = "Hardware";
561         childrow = *(store->append(row.children()));
562         childrow[cols.description] = "Tablet";
563         childrow[cols.thumbnail] = tabletPix;
565         for ( std::list<InputDevice const *>::iterator it = devList.begin(); it != devList.end(); ++it ) {
566             InputDevice const* dev = *it;
567             if ( dev ) {
568                 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(),
569                           dev->hasCursor() ? "Yes":"no", dev->getNumAxes(), dev->getNumKeys());
571 //                 if ( dev->getSource() != Gdk::SOURCE_MOUSE ) {
572                 if ( dev ) {
573                     deviceRow = *(store->append(childrow.children()));
574                     deviceRow[cols.description] = dev->getName();
575                     deviceRow[cols.device] = dev;
576                     switch ( dev->getSource() ) {
577                         case GDK_SOURCE_MOUSE:
578                             deviceRow[cols.thumbnail] = corePix;
579                             break;
580                         case GDK_SOURCE_PEN:
581                             if (deviceRow[cols.description] == "pad") {
582                                 deviceRow[cols.thumbnail] = sidebuttonsPix;
583                             } else {
584                                 deviceRow[cols.thumbnail] = tipPix;
585                             }
586                             break;
587                         case GDK_SOURCE_CURSOR:
588                             deviceRow[cols.thumbnail] = mousePix;
589                             break;
590                         case GDK_SOURCE_ERASER:
591                             deviceRow[cols.thumbnail] = eraserPix;
592                             break;
593                         default:
594                             ; // nothing
595                     }
596                 }
597             } else {
598                 g_warning("Null device in list");
599             }
600         }
601     } else {
602         g_message("NO DEVICES FOUND");
603     }
604     Inkscape::DeviceManager::getManager().signalDeviceChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::handleDeviceChange));
605     Inkscape::DeviceManager::getManager().signalButtonsChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::updateDeviceButtons));
606     Inkscape::DeviceManager::getManager().signalLinkChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::updateDeviceLinks));
608     tree.expand_all();
609     show_all_children();
612 void InputDialogImpl::handleDeviceChange(const Glib::RefPtr<InputDevice>& /*device*/)
614 //     g_message("OUCH!!!! for %p  hits %s", &device, device->getId().c_str());
617 void InputDialogImpl::updateDeviceButtons(const Glib::RefPtr<InputDevice>& device)
619     gint live = device->getLiveButtons();
620     std::set<guint> existing = buttonMap[device->getId()];
621     gint mask = 0x1;
622     for ( gint num = 0; num < 32; num++, mask <<= 1) {
623         if ( (mask & live) != 0 ) {
624             if ( existing.find(num) == existing.end() ) {
625                 buttonMap[device->getId()].insert(num);
626             }
627         }
628     }
629     updateTestButtons(device->getId(), -1);
632 void InputDialogImpl::updateDeviceLinks(const Glib::RefPtr<InputDevice>& /*device*/)
634 //     g_message("Links!!!! for %p  hits %s  with link of %s", &device, device->getId().c_str(), device->getLink().c_str());
637 void InputDialogImpl::linkComboChanged() {
638     Glib::RefPtr<Gtk::TreeSelection> treeSel = tree.get_selection();
639     Gtk::TreeModel::iterator iter = treeSel->get_selected();
640     if (iter) {
641         Gtk::TreeModel::Row row = *iter;
642         Glib::ustring val = row[cols.description];
643         InputDevice const * dev = row[cols.device];
644         if ( dev ) {
645             Glib::ustring linkName = linkCombo.get_active_text();
646             std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
647             for ( std::list<InputDevice const *>::const_iterator it = devList.begin(); it != devList.end(); ++it ) {
648                 if ( linkName == (*it)->getName() ) {
649                     DeviceManager::getManager().setLinkedTo(dev->getId(), (*it)->getId());
650                     break;
651                 }
652             }
653         }
654     }
657 void InputDialogImpl::resyncToSelection() {
658     bool clear = true;
659     Glib::RefPtr<Gtk::TreeSelection> treeSel = tree.get_selection();
660     Gtk::TreeModel::iterator iter = treeSel->get_selected();
661     if (iter) {
662         Gtk::TreeModel::Row row = *iter;
663         Glib::ustring val = row[cols.description];
664         InputDevice const * dev = row[cols.device];
665         if ( dev ) {
666             devDetails.set_sensitive(true);
668             linkConnection.block();
669             linkCombo.clear_items();
670             linkCombo.append_text("None");
671             linkCombo.set_active(0);
672             if ( dev->getSource() != Gdk::SOURCE_MOUSE ) {
673                 Glib::ustring linked = dev->getLink();
674                 std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
675                 for ( std::list<InputDevice const *>::const_iterator it = devList.begin(); it != devList.end(); ++it ) {
676                     if ( ((*it)->getSource() != Gdk::SOURCE_MOUSE) && ((*it) != dev) ) {
677                         linkCombo.append_text((*it)->getName().c_str());
678                         if ( (linked.length() > 0) && (linked == (*it)->getId()) ) {
679                             linkCombo.set_active_text((*it)->getName().c_str());
680                         }
681                     }
682                 }
683                 linkCombo.set_sensitive(true);
684             } else {
685                 linkCombo.set_sensitive(false);
686             }
687             linkConnection.unblock();
689             clear = false;
690             devName.set_label(row[cols.description]);
691             setupValueAndCombo( dev->getNumAxes(), dev->getNumAxes(), devAxesCount, axesCombo);
692             setupValueAndCombo( dev->getNumKeys(), dev->getNumKeys(), devKeyCount, buttonCombo);
693         }
694     }
696     devDetails.set_sensitive(!clear);
697     if (clear) {
698         devName.set_label("");
699         devAxesCount.set_label("");
700         devKeyCount.set_label("");
701     }
704 void InputDialogImpl::setupValueAndCombo( gint reported, gint actual, Gtk::Label& label, Gtk::ComboBoxText& combo )
706     gchar *tmp = g_strdup_printf("%d", reported);
707     label.set_label(tmp);
708     g_free(tmp);
710     combo.clear_items();
711     for ( gint i = 1; i <= reported; ++i ) {
712         tmp = g_strdup_printf("%d", i);
713         combo.append_text(tmp);
714         g_free(tmp);
715     }
717     if ( (1 <= actual) && (actual <= reported) ) {
718         combo.set_active(actual - 1);
719     }
722 void InputDialogImpl::updateTestButtons( Glib::ustring const& key, gint hotButton )
724     for ( gint i = 0; i < 24; i++ ) {
725         if ( buttonMap[key].find(i) != buttonMap[key].end() ) {
726             if ( i == hotButton ) {
727                 testButtons[i].set(buttonsOnPix);
728             } else {
729                 testButtons[i].set(buttonsOffPix);
730             }
731         } else {
732             testButtons[i].set(buttonsNonePix);
733         }
734     }
737 Glib::ustring InputDialogImpl::getKeyFor( GdkDevice* device )
739     Glib::ustring key;
740     switch ( device->source ) {
741         case GDK_SOURCE_MOUSE:
742             key = "M:";
743             break;
744         case GDK_SOURCE_CURSOR:
745             key = "C:";
746             break;
747         case GDK_SOURCE_PEN:
748             key = "P:";
749             break;
750         case GDK_SOURCE_ERASER:
751             key = "E:";
752             break;
753         default:
754             key = "?:";
755     }
756     key += device->name;
758     return key;
761 bool InputDialogImpl::eventSnoop(GdkEvent* event)
763     int modmod = 0;
765     GdkInputSource source = lastSourceSeen;
766     Glib::ustring devName = lastDevnameSeen;
767     Glib::ustring key;
768     gint hotButton = -1;
770     switch ( event->type ) {
771         case GDK_KEY_PRESS:
772         case GDK_KEY_RELEASE:
773         {
774             GdkEventKey* keyEvt = reinterpret_cast<GdkEventKey*>(event);
775             gchar* name = gtk_accelerator_name(keyEvt->keyval, static_cast<GdkModifierType>(keyEvt->state));
776             keyVal.set_label(name);
777             g_message("%d KEY    state:0x%08x  0x%04x [%s]", keyEvt->type, keyEvt->state, keyEvt->keyval, name);
778             g_free(name);
779         }
780         break;
781         case GDK_BUTTON_PRESS:
782             modmod = 1;
783             // fallthrough
784         case GDK_BUTTON_RELEASE:
785         {
786             GdkEventButton* btnEvt = reinterpret_cast<GdkEventButton*>(event);
787             if ( btnEvt->device ) {
788                 key = getKeyFor(btnEvt->device);
789                 source = btnEvt->device->source;
790                 devName = btnEvt->device->name;
792                 if ( buttonMap[key].find(btnEvt->button) == buttonMap[key].end() ) {
793                     g_message("New button found for %s = %d", key.c_str(), btnEvt->button);
794                     buttonMap[key].insert(btnEvt->button);
795                     DeviceManager::getManager().addButton(key, btnEvt->button);
796                 }
797                 hotButton = modmod ? btnEvt->button : -1;
798                 updateTestButtons(key, hotButton);
799             }
800             gchar* name = gtk_accelerator_name(0, static_cast<GdkModifierType>(btnEvt->state));
801             keyVal.set_label(name);
802             g_message("%d BTN    state:0x%08x %c  %4d [%s] dev:%p [%s]  ",
803                       btnEvt->type, btnEvt->state,
804                       (modmod ? '+':'-'),
805                       btnEvt->button, name, btnEvt->device,
806                       (btnEvt->device ? btnEvt->device->name : "null")
808                 );
809             g_free(name);
810         }
811         break;
812         case GDK_MOTION_NOTIFY:
813         {
814             GdkEventMotion* btnMtn = reinterpret_cast<GdkEventMotion*>(event);
815             if ( btnMtn->device ) {
816                 key = getKeyFor(btnMtn->device);
817                 source = btnMtn->device->source;
818                 devName = btnMtn->device->name;
819             }
820             gchar* name = gtk_accelerator_name(0, static_cast<GdkModifierType>(btnMtn->state));
821             keyVal.set_label(name);
822             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,
823                       name, btnMtn->device,
824                       (btnMtn->device ? btnMtn->device->name : "null"),
825                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 0)) ? btnMtn->axes[0]:0),
826                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 1)) ? btnMtn->axes[1]:0),
827                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 2)) ? btnMtn->axes[2]:0),
828                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 3)) ? btnMtn->axes[3]:0),
829                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 4)) ? btnMtn->axes[4]:0),
830                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 5)) ? btnMtn->axes[5]:0)
831                 );
832             g_free(name);
833         }
834         break;
835         default:
836             ;// nothing
837     }
840     if ( (lastSourceSeen != source) || (lastDevnameSeen != devName) ) {
841         switch (source) {
842             case GDK_SOURCE_MOUSE:
843             {
844                 testThumb.set(corePix);
845             }
846             break;
847             case GDK_SOURCE_CURSOR:
848             {
849                 g_message("flip to cursor");
850                 testThumb.set(mousePix);
851             }
852             break;
853             case GDK_SOURCE_PEN:
854             {
855                 if (devName == "pad") {
856                     g_message("flip to pad");
857                     testThumb.set(sidebuttonsPix);
858                 } else {
859                     g_message("flip to pen");
860                     testThumb.set(tipPix);
861                 }
862             }
863             break;
864             case GDK_SOURCE_ERASER:
865             {
866                 g_message("flip to eraser");
867                 testThumb.set(eraserPix);
868             }
869             break;
870             default:
871                 g_message("gurgle");
872         }
873         updateTestButtons(key, hotButton);
874         lastSourceSeen = source;
875         lastDevnameSeen = devName;
876     }
878     return false;
882 } // end namespace Inkscape
883 } // end namespace UI
884 } // end namespace Dialog
887 /*
888   Local Variables:
889   mode:c++
890   c-file-style:"stroustrup"
891   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
892   indent-tabs-mode:nil
893   fill-column:99
894   End:
895 */
896 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :