Code

Numeric values on test area
[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 };
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
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()
406     InputDialog *dialog = new InputDialogImpl();
407     return *dialog;
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)
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();
684 void InputDialogImpl::handleDeviceChange(const Glib::RefPtr<InputDevice>& /*device*/)
686 //     g_message("OUCH!!!! for %p  hits %s", &device, device->getId().c_str());
689 void InputDialogImpl::updateDeviceButtons(const Glib::RefPtr<InputDevice>& device)
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);
704 void InputDialogImpl::updateDeviceLinks(const Glib::RefPtr<InputDevice>& /*device*/)
706 //     g_message("Links!!!! for %p  hits %s  with link of %s", &device, device->getId().c_str(), device->getLink().c_str());
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     }
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     }
776 void InputDialogImpl::setupValueAndCombo( gint reported, gint actual, Gtk::Label& label, Gtk::ComboBoxText& combo )
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     }
794 void InputDialogImpl::updateTestButtons( Glib::ustring const& key, gint hotButton )
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     }
809 void InputDialogImpl::updateTestAxes( Glib::ustring const& key, GdkDevice* dev )
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     }
876 void InputDialogImpl::mapAxesValues( Glib::ustring const& key, guint numAxes, gdouble const * axes, GdkDevice* dev )
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;
924 Glib::ustring InputDialogImpl::getKeyFor( GdkDevice* device )
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;
948 bool InputDialogImpl::eventSnoop(GdkEvent* event)
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;
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 :