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 updateDeviceAxes(const Glib::RefPtr<InputDevice>& device);
399 void updateDeviceButtons(const Glib::RefPtr<InputDevice>& device);
400 void updateDeviceLinks(const Glib::RefPtr<InputDevice>& device);
401 };
404 // Now that we've defined the *Impl class, we can do the method to aquire one.
405 InputDialog &InputDialog::getInstance()
406 {
407 InputDialog *dialog = new InputDialogImpl();
408 return *dialog;
409 }
412 InputDialogImpl::InputDialogImpl() :
413 InputDialog(),
415 corePix(Gdk::Pixbuf::create_from_xpm_data(core_xpm)),
416 penPix(Gdk::Pixbuf::create_from_xpm_data(pen)),
417 mousePix(Gdk::Pixbuf::create_from_xpm_data(mouse)),
418 tipPix(Gdk::Pixbuf::create_from_xpm_data(tip)),
419 tabletPix(Gdk::Pixbuf::create_from_xpm_data(tablet)),
420 eraserPix(Gdk::Pixbuf::create_from_xpm_data(eraser)),
421 sidebuttonsPix(Gdk::Pixbuf::create_from_xpm_data(sidebuttons)),
423 buttonsNonePix(Gdk::Pixbuf::create_from_xpm_data(button_none)),
424 buttonsOnPix(Gdk::Pixbuf::create_from_xpm_data(button_on)),
425 buttonsOffPix(Gdk::Pixbuf::create_from_xpm_data(button_off)),
427 axisNonePix(Gdk::Pixbuf::create_from_xpm_data(axis_none_xpm)),
428 axisOnPix(Gdk::Pixbuf::create_from_xpm_data(axis_on_xpm)),
429 axisOffPix(Gdk::Pixbuf::create_from_xpm_data(axis_off_xpm)),
431 lastSourceSeen((GdkInputSource)-1),
432 lastDevnameSeen(""),
433 cols(),
434 store(Gtk::TreeStore::create(cols)),
435 tree(store),
436 frame2(),
437 testFrame("Test Area"),
438 treeScroller(),
439 detailScroller(),
440 splitter(),
441 split2(),
442 linkCombo(),
443 devDetails(12, 2),
444 confSplitter(),
445 topHolder(),
446 imageTable(8, 7)
447 {
448 Gtk::Box *contents = _getContents();
451 treeScroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
452 treeScroller.add(tree);
453 split2.pack1(testFrame);
454 split2.pack2(frame2);
455 splitter.pack1(treeScroller);
456 splitter.pack2(split2);
458 testDetector.add(imageTable);
459 testFrame.add(testDetector);
460 testThumb.set(tabletPix);
461 testThumb.set_padding(24, 24);
462 imageTable.attach(testThumb, 0, 8, 0, 1, ::Gtk::EXPAND, ::Gtk::EXPAND);
463 {
464 guint col = 0;
465 guint row = 1;
466 for ( guint num = 0; num < G_N_ELEMENTS(testButtons); num++ ) {
467 testButtons[num].set(buttonsNonePix);
468 imageTable.attach(testButtons[num], col, col + 1, row, row + 1, ::Gtk::FILL, ::Gtk::FILL);
469 col++;
470 if (col > 7) {
471 col = 0;
472 row++;
473 }
474 }
476 col = 0;
477 for ( guint num = 0; num < G_N_ELEMENTS(testAxes); num++ ) {
478 testAxes[num].set(axisNonePix);
479 imageTable.attach(testAxes[num], col * 2, (col + 1) * 2, row, row + 1, ::Gtk::FILL, ::Gtk::FILL);
480 col++;
481 if (col > 3) {
482 col = 0;
483 row++;
484 }
485 }
486 }
489 topHolder.append_page(confSplitter, "Configuration");
490 topHolder.append_page(splitter, "Hardware");
491 // confSplitter.show_all();
492 // splitter.show_all();
493 topHolder.show_all();
494 topHolder.set_current_page(1);
496 contents->pack_start(topHolder);
498 int rowNum = 0;
500 Gtk::Label* lbl = Gtk::manage(new Gtk::Label("Name:"));
501 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
502 ::Gtk::FILL,
503 ::Gtk::SHRINK);
504 devDetails.attach(devName, 1, 2, rowNum, rowNum + 1,
505 ::Gtk::SHRINK,
506 ::Gtk::SHRINK);
508 rowNum++;
510 lbl = Gtk::manage(new Gtk::Label("Link:"));
511 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
512 ::Gtk::FILL,
513 ::Gtk::SHRINK);
515 linkCombo.append_text("None");
516 linkCombo.set_active_text("None");
517 linkCombo.set_sensitive(false);
518 linkConnection = linkCombo.signal_changed().connect(sigc::mem_fun(*this, &InputDialogImpl::linkComboChanged));
520 devDetails.attach(linkCombo, 1, 2, rowNum, rowNum + 1,
521 ::Gtk::FILL,
522 ::Gtk::SHRINK);
523 rowNum++;
525 lbl = Gtk::manage(new Gtk::Label("Reported axes count:"));
526 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
527 ::Gtk::FILL,
528 ::Gtk::SHRINK);
529 devDetails.attach(devAxesCount, 1, 2, rowNum, rowNum + 1,
530 ::Gtk::SHRINK,
531 ::Gtk::SHRINK);
533 rowNum++;
535 lbl = Gtk::manage(new Gtk::Label("Actual axes count:"));
536 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
537 ::Gtk::FILL,
538 ::Gtk::SHRINK);
539 devDetails.attach(axesCombo, 1, 2, rowNum, rowNum + 1,
540 ::Gtk::SHRINK,
541 ::Gtk::SHRINK);
543 rowNum++;
545 for ( guint barNum = 0; barNum < static_cast<guint>(G_N_ELEMENTS(axesValues)); barNum++ ) {
546 lbl = Gtk::manage(new Gtk::Label("axis:"));
547 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
548 ::Gtk::FILL,
549 ::Gtk::SHRINK);
550 devDetails.attach(axesValues[barNum], 1, 2, rowNum, rowNum + 1,
551 ::Gtk::EXPAND,
552 ::Gtk::SHRINK);
553 axesValues[barNum].set_sensitive(false);
555 rowNum++;
556 }
558 lbl = Gtk::manage(new Gtk::Label("Reported button count:"));
559 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
560 ::Gtk::FILL,
561 ::Gtk::SHRINK);
562 devDetails.attach(devKeyCount, 1, 2, rowNum, rowNum + 1,
563 ::Gtk::SHRINK,
564 ::Gtk::SHRINK);
566 rowNum++;
568 /*
569 lbl = Gtk::manage(new Gtk::Label("Actual button count:"));
570 devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
571 ::Gtk::FILL,
572 ::Gtk::SHRINK);
573 devDetails.attach(buttonCombo, 1, 2, rowNum, rowNum + 1,
574 ::Gtk::SHRINK,
575 ::Gtk::SHRINK);
577 rowNum++;
578 */
580 devDetails.attach(keyVal, 0, 2, rowNum, rowNum + 1,
581 ::Gtk::FILL,
582 ::Gtk::SHRINK);
583 rowNum++;
586 testDetector.signal_event().connect(sigc::mem_fun(*this, &InputDialogImpl::eventSnoop));
588 // void gdk_input_set_extension_events (GdkWindow *window,
589 // gint mask,
590 // GdkExtensionMode mode);
592 gtk_widget_set_extension_events( GTK_WIDGET(testDetector.gobj()), GDK_EXTENSION_EVENTS_ALL );
593 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);
595 devDetails.attach(keyEntry, 0, 2, rowNum, rowNum + 1,
596 ::Gtk::FILL,
597 ::Gtk::SHRINK);
598 rowNum++;
601 devDetails.set_sensitive(false);
602 detailScroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
603 detailScroller.add(devDetails);
604 frame2.add(detailScroller);
606 //- 16x16/devices
607 // gnome-dev-mouse-optical
608 // input-mouse
609 // input-tablet
610 // mouse
614 Gtk::TreeModel::Row row;
615 Gtk::TreeModel::Row childrow;
616 Gtk::TreeModel::Row deviceRow;
619 //Add the TreeView's view columns:
620 tree.append_column("I", cols.thumbnail);
621 tree.append_column("Bar", cols.description);
623 tree.set_enable_tree_lines();
624 tree.set_headers_visible(false);
625 tree.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &InputDialogImpl::resyncToSelection));
629 std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
630 if ( !devList.empty() ) {
631 row = *(store->append());
632 row[cols.description] = "Hardware";
634 childrow = *(store->append(row.children()));
635 childrow[cols.description] = "Tablet";
636 childrow[cols.thumbnail] = tabletPix;
638 for ( std::list<InputDevice const *>::iterator it = devList.begin(); it != devList.end(); ++it ) {
639 InputDevice const* dev = *it;
640 if ( dev ) {
641 // 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(),
642 // dev->hasCursor() ? "Yes":"no", dev->getNumAxes(), dev->getNumKeys());
644 // if ( dev->getSource() != Gdk::SOURCE_MOUSE ) {
645 if ( dev ) {
646 deviceRow = *(store->append(childrow.children()));
647 deviceRow[cols.description] = dev->getName();
648 deviceRow[cols.device] = dev;
649 switch ( dev->getSource() ) {
650 case GDK_SOURCE_MOUSE:
651 deviceRow[cols.thumbnail] = corePix;
652 break;
653 case GDK_SOURCE_PEN:
654 if (deviceRow[cols.description] == "pad") {
655 deviceRow[cols.thumbnail] = sidebuttonsPix;
656 } else {
657 deviceRow[cols.thumbnail] = tipPix;
658 }
659 break;
660 case GDK_SOURCE_CURSOR:
661 deviceRow[cols.thumbnail] = mousePix;
662 break;
663 case GDK_SOURCE_ERASER:
664 deviceRow[cols.thumbnail] = eraserPix;
665 break;
666 default:
667 ; // nothing
668 }
669 }
670 } else {
671 g_warning("Null device in list");
672 }
673 }
674 } else {
675 g_warning("No devices found");
676 }
677 Inkscape::DeviceManager::getManager().signalDeviceChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::handleDeviceChange));
678 Inkscape::DeviceManager::getManager().signalAxesChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::updateDeviceAxes));
679 Inkscape::DeviceManager::getManager().signalButtonsChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::updateDeviceButtons));
680 Inkscape::DeviceManager::getManager().signalLinkChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::updateDeviceLinks));
682 tree.expand_all();
683 show_all_children();
684 }
686 void InputDialogImpl::handleDeviceChange(const Glib::RefPtr<InputDevice>& /*device*/)
687 {
688 // g_message("OUCH!!!! for %p hits %s", &device, device->getId().c_str());
689 }
691 void InputDialogImpl::updateDeviceAxes(const Glib::RefPtr<InputDevice>& device)
692 {
693 gint live = device->getLiveAxes();
695 std::map<guint, std::pair<guint, gdouble> > existing = axesMap[device->getId()];
696 gint mask = 0x1;
697 for ( gint num = 0; num < 32; num++, mask <<= 1) {
698 if ( (mask & live) != 0 ) {
699 if ( (existing.find(num) == existing.end()) || (existing[num].first < 2) ) {
700 axesMap[device->getId()][num].first = 2;
701 axesMap[device->getId()][num].second = 0.0;
702 }
703 }
704 }
705 updateTestAxes( device->getId(), 0 );
706 }
708 void InputDialogImpl::updateDeviceButtons(const Glib::RefPtr<InputDevice>& device)
709 {
710 gint live = device->getLiveButtons();
711 std::set<guint> existing = buttonMap[device->getId()];
712 gint mask = 0x1;
713 for ( gint num = 0; num < 32; num++, mask <<= 1) {
714 if ( (mask & live) != 0 ) {
715 if ( existing.find(num) == existing.end() ) {
716 buttonMap[device->getId()].insert(num);
717 }
718 }
719 }
720 updateTestButtons(device->getId(), -1);
721 }
723 void InputDialogImpl::updateDeviceLinks(const Glib::RefPtr<InputDevice>& /*device*/)
724 {
725 // g_message("Links!!!! for %p hits %s with link of %s", &device, device->getId().c_str(), device->getLink().c_str());
726 }
728 void InputDialogImpl::linkComboChanged() {
729 Glib::RefPtr<Gtk::TreeSelection> treeSel = tree.get_selection();
730 Gtk::TreeModel::iterator iter = treeSel->get_selected();
731 if (iter) {
732 Gtk::TreeModel::Row row = *iter;
733 Glib::ustring val = row[cols.description];
734 InputDevice const * dev = row[cols.device];
735 if ( dev ) {
736 Glib::ustring linkName = linkCombo.get_active_text();
737 std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
738 for ( std::list<InputDevice const *>::const_iterator it = devList.begin(); it != devList.end(); ++it ) {
739 if ( linkName == (*it)->getName() ) {
740 DeviceManager::getManager().setLinkedTo(dev->getId(), (*it)->getId());
741 break;
742 }
743 }
744 }
745 }
746 }
748 void InputDialogImpl::resyncToSelection() {
749 bool clear = true;
750 Glib::RefPtr<Gtk::TreeSelection> treeSel = tree.get_selection();
751 Gtk::TreeModel::iterator iter = treeSel->get_selected();
752 if (iter) {
753 Gtk::TreeModel::Row row = *iter;
754 Glib::ustring val = row[cols.description];
755 InputDevice const * dev = row[cols.device];
756 if ( dev ) {
757 devDetails.set_sensitive(true);
759 linkConnection.block();
760 linkCombo.clear_items();
761 linkCombo.append_text("None");
762 linkCombo.set_active(0);
763 if ( dev->getSource() != Gdk::SOURCE_MOUSE ) {
764 Glib::ustring linked = dev->getLink();
765 std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
766 for ( std::list<InputDevice const *>::const_iterator it = devList.begin(); it != devList.end(); ++it ) {
767 if ( ((*it)->getSource() != Gdk::SOURCE_MOUSE) && ((*it) != dev) ) {
768 linkCombo.append_text((*it)->getName().c_str());
769 if ( (linked.length() > 0) && (linked == (*it)->getId()) ) {
770 linkCombo.set_active_text((*it)->getName().c_str());
771 }
772 }
773 }
774 linkCombo.set_sensitive(true);
775 } else {
776 linkCombo.set_sensitive(false);
777 }
778 linkConnection.unblock();
780 clear = false;
781 devName.set_label(row[cols.description]);
782 setupValueAndCombo( dev->getNumAxes(), dev->getNumAxes(), devAxesCount, axesCombo);
783 setupValueAndCombo( dev->getNumKeys(), dev->getNumKeys(), devKeyCount, buttonCombo);
784 }
785 }
787 devDetails.set_sensitive(!clear);
788 if (clear) {
789 devName.set_label("");
790 devAxesCount.set_label("");
791 devKeyCount.set_label("");
792 }
793 }
795 void InputDialogImpl::setupValueAndCombo( gint reported, gint actual, Gtk::Label& label, Gtk::ComboBoxText& combo )
796 {
797 gchar *tmp = g_strdup_printf("%d", reported);
798 label.set_label(tmp);
799 g_free(tmp);
801 combo.clear_items();
802 for ( gint i = 1; i <= reported; ++i ) {
803 tmp = g_strdup_printf("%d", i);
804 combo.append_text(tmp);
805 g_free(tmp);
806 }
808 if ( (1 <= actual) && (actual <= reported) ) {
809 combo.set_active(actual - 1);
810 }
811 }
813 void InputDialogImpl::updateTestButtons( Glib::ustring const& key, gint hotButton )
814 {
815 for ( gint i = 0; i < static_cast<gint>(G_N_ELEMENTS(testButtons)); i++ ) {
816 if ( buttonMap[key].find(i) != buttonMap[key].end() ) {
817 if ( i == hotButton ) {
818 testButtons[i].set(buttonsOnPix);
819 } else {
820 testButtons[i].set(buttonsOffPix);
821 }
822 } else {
823 testButtons[i].set(buttonsNonePix);
824 }
825 }
826 }
828 void InputDialogImpl::updateTestAxes( Glib::ustring const& key, GdkDevice* dev )
829 {
830 static gdouble epsilon = 0.0001;
831 {
832 Glib::RefPtr<Gtk::TreeSelection> treeSel = tree.get_selection();
833 Gtk::TreeModel::iterator iter = treeSel->get_selected();
834 if (iter) {
835 Gtk::TreeModel::Row row = *iter;
836 Glib::ustring val = row[cols.description];
837 InputDevice const * idev = row[cols.device];
838 if ( !idev || (idev->getId() != key) ) {
839 dev = 0;
840 }
841 }
842 }
845 for ( gint i = 0; i < static_cast<gint>(G_N_ELEMENTS(testAxes)); i++ ) {
846 if ( axesMap[key].find(i) != axesMap[key].end() ) {
847 switch ( axesMap[key][i].first ) {
848 case 0:
849 case 1:
850 testAxes[i].set(axisNonePix);
851 if ( dev && (i < static_cast<gint>(G_N_ELEMENTS(axesValues)) ) ) {
852 axesValues[i].set_sensitive(false);
853 }
854 break;
855 case 2:
856 testAxes[i].set(axisOffPix);
857 axesValues[i].set_sensitive(true);
858 if ( dev && (i < static_cast<gint>(G_N_ELEMENTS(axesValues)) ) ) {
859 if ( (dev->axes[i].max - dev->axes[i].min) > epsilon ) {
860 axesValues[i].set_sensitive(true);
861 axesValues[i].set_fraction( (axesMap[key][i].second- dev->axes[i].min) / (dev->axes[i].max - dev->axes[i].min) );
862 }
863 gchar* str = g_strdup_printf("%f", axesMap[key][i].second);
864 axesValues[i].set_text(str);
865 g_free(str);
866 }
867 break;
868 case 3:
869 testAxes[i].set(axisOnPix);
870 axesValues[i].set_sensitive(true);
871 if ( dev && (i < static_cast<gint>(G_N_ELEMENTS(axesValues)) ) ) {
872 if ( (dev->axes[i].max - dev->axes[i].min) > epsilon ) {
873 axesValues[i].set_sensitive(true);
874 axesValues[i].set_fraction( (axesMap[key][i].second- dev->axes[i].min) / (dev->axes[i].max - dev->axes[i].min) );
875 }
876 gchar* str = g_strdup_printf("%f", axesMap[key][i].second);
877 axesValues[i].set_text(str);
878 g_free(str);
879 }
880 }
882 } else {
883 testAxes[i].set(axisNonePix);
884 }
885 }
886 if ( !dev ) {
887 for ( gint i = 0; i < static_cast<gint>(G_N_ELEMENTS(axesValues)); i++ ) {
888 axesValues[i].set_fraction(0.0);
889 axesValues[i].set_text("");
890 axesValues[i].set_sensitive(false);
891 }
892 }
893 }
895 void InputDialogImpl::mapAxesValues( Glib::ustring const& key, guint numAxes, gdouble const * axes, GdkDevice* dev )
896 {
897 static gdouble epsilon = 0.0001;
898 if ( (numAxes > 0) && axes) {
899 for ( guint axisNum = 0; axisNum < numAxes; axisNum++ ) {
900 // 0 == new, 1 == set value, 2 == changed value, 3 == active
901 gdouble diff = axesMap[key][axisNum].second - axes[axisNum];
902 switch(axesMap[key][axisNum].first) {
903 case 0:
904 {
905 axesMap[key][axisNum].first = 1;
906 axesMap[key][axisNum].second = axes[axisNum];
907 }
908 break;
909 case 1:
910 {
911 if ( (diff > epsilon) || (diff < -epsilon) ) {
912 // g_message("Axis %d changed on %s]", axisNum, key.c_str());
913 axesMap[key][axisNum].first = 3;
914 axesMap[key][axisNum].second = axes[axisNum];
915 updateTestAxes(key, dev);
916 DeviceManager::getManager().addAxis(key, axisNum);
917 }
918 }
919 break;
920 case 2:
921 {
922 if ( (diff > epsilon) || (diff < -epsilon) ) {
923 axesMap[key][axisNum].first = 3;
924 axesMap[key][axisNum].second = axes[axisNum];
925 updateTestAxes(key, dev);
926 }
927 }
928 break;
929 case 3:
930 {
931 if ( (diff > epsilon) || (diff < -epsilon) ) {
932 axesMap[key][axisNum].second = axes[axisNum];
933 } else {
934 axesMap[key][axisNum].first = 2;
935 updateTestAxes(key, dev);
936 }
937 }
938 }
939 }
940 }
941 // std::map<Glib::ustring, std::map<guint, std::pair<guint, gdouble> > > axesMap;
942 }
944 Glib::ustring InputDialogImpl::getKeyFor( GdkDevice* device )
945 {
946 Glib::ustring key;
947 switch ( device->source ) {
948 case GDK_SOURCE_MOUSE:
949 key = "M:";
950 break;
951 case GDK_SOURCE_CURSOR:
952 key = "C:";
953 break;
954 case GDK_SOURCE_PEN:
955 key = "P:";
956 break;
957 case GDK_SOURCE_ERASER:
958 key = "E:";
959 break;
960 default:
961 key = "?:";
962 }
963 key += device->name;
965 return key;
966 }
968 bool InputDialogImpl::eventSnoop(GdkEvent* event)
969 {
970 int modmod = 0;
972 GdkInputSource source = lastSourceSeen;
973 Glib::ustring devName = lastDevnameSeen;
974 Glib::ustring key;
975 gint hotButton = -1;
977 switch ( event->type ) {
978 case GDK_KEY_PRESS:
979 case GDK_KEY_RELEASE:
980 {
981 GdkEventKey* keyEvt = reinterpret_cast<GdkEventKey*>(event);
982 gchar* name = gtk_accelerator_name(keyEvt->keyval, static_cast<GdkModifierType>(keyEvt->state));
983 keyVal.set_label(name);
984 // g_message("%d KEY state:0x%08x 0x%04x [%s]", keyEvt->type, keyEvt->state, keyEvt->keyval, name);
985 g_free(name);
986 }
987 break;
988 case GDK_BUTTON_PRESS:
989 modmod = 1;
990 // fallthrough
991 case GDK_BUTTON_RELEASE:
992 {
993 GdkEventButton* btnEvt = reinterpret_cast<GdkEventButton*>(event);
994 if ( btnEvt->device ) {
995 key = getKeyFor(btnEvt->device);
996 source = btnEvt->device->source;
997 devName = btnEvt->device->name;
999 mapAxesValues(key, btnEvt->device->num_axes, btnEvt->axes, btnEvt->device);
1000 if ( buttonMap[key].find(btnEvt->button) == buttonMap[key].end() ) {
1001 // g_message("New button found for %s = %d", key.c_str(), btnEvt->button);
1002 buttonMap[key].insert(btnEvt->button);
1003 DeviceManager::getManager().addButton(key, btnEvt->button);
1004 }
1005 hotButton = modmod ? btnEvt->button : -1;
1006 updateTestButtons(key, hotButton);
1007 }
1008 gchar* name = gtk_accelerator_name(0, static_cast<GdkModifierType>(btnEvt->state));
1009 keyVal.set_label(name);
1010 // g_message("%d BTN state:0x%08x %c %4d [%s] dev:%p [%s] ",
1011 // btnEvt->type, btnEvt->state,
1012 // (modmod ? '+':'-'),
1013 // btnEvt->button, name, btnEvt->device,
1014 // (btnEvt->device ? btnEvt->device->name : "null")
1016 // );
1017 g_free(name);
1018 }
1019 break;
1020 case GDK_MOTION_NOTIFY:
1021 {
1022 GdkEventMotion* btnMtn = reinterpret_cast<GdkEventMotion*>(event);
1023 if ( btnMtn->device ) {
1024 key = getKeyFor(btnMtn->device);
1025 source = btnMtn->device->source;
1026 devName = btnMtn->device->name;
1027 mapAxesValues(key, btnMtn->device->num_axes, btnMtn->axes, btnMtn->device);
1028 }
1029 gchar* name = gtk_accelerator_name(0, static_cast<GdkModifierType>(btnMtn->state));
1030 keyVal.set_label(name);
1031 // 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,
1032 // name, btnMtn->device,
1033 // (btnMtn->device ? btnMtn->device->name : "null"),
1034 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 0)) ? btnMtn->axes[0]:0),
1035 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 1)) ? btnMtn->axes[1]:0),
1036 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 2)) ? btnMtn->axes[2]:0),
1037 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 3)) ? btnMtn->axes[3]:0),
1038 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 4)) ? btnMtn->axes[4]:0),
1039 // ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 5)) ? btnMtn->axes[5]:0)
1040 // );
1041 g_free(name);
1042 }
1043 break;
1044 default:
1045 ;// nothing
1046 }
1049 if ( (lastSourceSeen != source) || (lastDevnameSeen != devName) ) {
1050 switch (source) {
1051 case GDK_SOURCE_MOUSE:
1052 {
1053 testThumb.set(corePix);
1054 }
1055 break;
1056 case GDK_SOURCE_CURSOR:
1057 {
1058 // g_message("flip to cursor");
1059 testThumb.set(mousePix);
1060 }
1061 break;
1062 case GDK_SOURCE_PEN:
1063 {
1064 if (devName == "pad") {
1065 // g_message("flip to pad");
1066 testThumb.set(sidebuttonsPix);
1067 } else {
1068 // g_message("flip to pen");
1069 testThumb.set(tipPix);
1070 }
1071 }
1072 break;
1073 case GDK_SOURCE_ERASER:
1074 {
1075 // g_message("flip to eraser");
1076 testThumb.set(eraserPix);
1077 }
1078 break;
1079 // default:
1080 // g_message("gurgle");
1081 }
1082 updateTestButtons(key, hotButton);
1083 lastSourceSeen = source;
1084 lastDevnameSeen = devName;
1085 }
1087 return false;
1088 }
1091 } // end namespace Inkscape
1092 } // end namespace UI
1093 } // end namespace Dialog
1096 /*
1097 Local Variables:
1098 mode:c++
1099 c-file-style:"stroustrup"
1100 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1101 indent-tabs-mode:nil
1102 fill-column:99
1103 End:
1104 */
1105 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :