Code

Block "special" solid gradients from gradient F&S dialog.
[inkscape.git] / src / ui / dialog / input.cpp
index f5746dbdecb413eece434b7b71a4f5755551d0e5..ae8594e5008b245f6b25025136143e4ec5ec3a45 100644 (file)
@@ -1,7 +1,40 @@
+/** @file
+ * @brief Input devices dialog (new) - implementation
+ */
+/* Author:
+ *   Jon A. Cruz
+ *
+ * Copyright (C) 2008 Author
+ * Released under GNU GPL.  Read the file 'COPYING' for more information.
+ */
 
+#include <map>
+#include <set>
+#include <glib/gprintf.h>
+#include <glibmm/i18n.h>
+#include <gtkmm/comboboxtext.h>
+#include <gtkmm/enums.h>
+#include <gtkmm/eventbox.h>
+#include <gtkmm/frame.h>
+#include <gtkmm/image.h>
+#include <gtkmm/menubar.h>
+#include <gtkmm/notebook.h>
+#include <gtkmm/paned.h>
+#include <gtkmm/progressbar.h>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/table.h>
+#include <gtkmm/treemodel.h>
+#include <gtkmm/treemodelcolumn.h>
+#include <gtkmm/treestore.h>
+#include <gtkmm/treeview.h>
+
+#include "ui/widget/panel.h"
+#include "device-manager.h"
+
+#include "input.h"
 
 /* XPM */
-static char * core_xpm[] = {
+static char const * core_xpm[] = {
 "16 16 4 1",
 "      c None",
 ".     c #808080",
@@ -25,7 +58,7 @@ static char * core_xpm[] = {
 "                "};
 
 /* XPM */
-static char *eraser[] = {
+static char const *eraser[] = {
 /* columns rows colors chars-per-pixel */
 "16 16 5 1",
 "  c black",
@@ -53,7 +86,7 @@ static char *eraser[] = {
 };
 
 /* XPM */
-static char *mouse[] = {
+static char const *mouse[] = {
 /* columns rows colors chars-per-pixel */
 "16 16 3 1",
 "  c black",
@@ -79,7 +112,7 @@ static char *mouse[] = {
 };
 
 /* XPM */
-static char *pen[] = {
+static char const *pen[] = {
 /* columns rows colors chars-per-pixel */
 "16 16 3 1",
 "  c black",
@@ -105,7 +138,7 @@ static char *pen[] = {
 };
 
 /* XPM */
-static char *sidebuttons[] = {
+static char const *sidebuttons[] = {
 /* columns rows colors chars-per-pixel */
 "16 16 4 1",
 "  c black",
@@ -132,7 +165,7 @@ static char *sidebuttons[] = {
 };
 
 /* XPM */
-static char *tablet[] = {
+static char const *tablet[] = {
 /* columns rows colors chars-per-pixel */
 "16 16 3 1",
 "  c black",
@@ -158,7 +191,7 @@ static char *tablet[] = {
 };
 
 /* XPM */
-static char *tip[] = {
+static char const *tip[] = {
 /* columns rows colors chars-per-pixel */
 "16 16 5 1",
 "  c black",
@@ -186,7 +219,7 @@ static char *tip[] = {
 };
 
 /* XPM */
-static char *button_none[] = {
+static char const *button_none[] = {
 /* columns rows colors chars-per-pixel */
 "8 8 3 1",
 "  c black",
@@ -203,7 +236,7 @@ static char *button_none[] = {
 "XXXXXXXX"
 };
 /* XPM */
-static char *button_off[] = {
+static char const *button_off[] = {
 /* columns rows colors chars-per-pixel */
 "8 8 4 1",
 "  c black",
@@ -221,7 +254,7 @@ static char *button_off[] = {
 "oooooooo"
 };
 /* XPM */
-static char *button_on[] = {
+static char const *button_on[] = {
 /* columns rows colors chars-per-pixel */
 "8 8 3 1",
 "  c black",
@@ -238,34 +271,49 @@ static char *button_on[] = {
 "XXXXXXXX"
 };
 
-
-
-
-
-
-#include <map>
-#include <set>
-#include <glib/gprintf.h>
-#include <glibmm/i18n.h>
-#include <gtkmm/comboboxtext.h>
-#include <gtkmm/enums.h>
-#include <gtkmm/frame.h>
-#include <gtkmm/image.h>
-#include <gtkmm/menubar.h>
-#include <gtkmm/notebook.h>
-#include <gtkmm/paned.h>
-#include <gtkmm/scrolledwindow.h>
-#include <gtkmm/table.h>
-#include <gtkmm/eventbox.h>
-#include <gtkmm/treemodel.h>
-#include <gtkmm/treemodelcolumn.h>
-#include <gtkmm/treestore.h>
-#include <gtkmm/treeview.h>
-
-#include "ui/widget/panel.h"
-#include "device-manager.h"
-
-#include "input.h"
+/* XPM */
+static char const * axis_none_xpm[] = {
+"24 8 3 1",
+"      c None",
+".     c #000000",
+"+     c #808080",
+"                        ",
+"  .++++++++++++++++++.  ",
+" .+               . .+. ",
+" +          . . .     + ",
+" +     . . .          + ",
+" .+. .               +. ",
+"  .++++++++++++++++++.  ",
+"                        "};
+/* XPM */
+static char const * axis_off_xpm[] = {
+"24 8 4 1",
+"      c None",
+".     c #808080",
+"+     c #000000",
+"@     c #FFFFFF",
+"                        ",
+"  .++++++++++++++++++.  ",
+" .+@@@@@@@@@@@@@@@@@@+. ",
+" +@@@@@@@@@@@@@@@@@@@@+ ",
+" +@@@@@@@@@@@@@@@@@@@@+ ",
+" .+@@@@@@@@@@@@@@@@@@+. ",
+"  .++++++++++++++++++.  ",
+"                        "};
+/* XPM */
+static char const * axis_on_xpm[] = {
+"24 8 3 1",
+"      c None",
+".     c #000000",
+"+     c #00FF00",
+"                        ",
+"  ....................  ",
+" ..++++++++++++++++++.. ",
+" .++++++++++++++++++++. ",
+" .++++++++++++++++++++. ",
+" ..++++++++++++++++++.. ",
+"  ....................  ",
+"                        "};
 
 using Inkscape::InputDevice;
 
@@ -304,13 +352,19 @@ private:
     Glib::RefPtr<Gdk::Pixbuf> buttonsOnPix;
     Glib::RefPtr<Gdk::Pixbuf> buttonsOffPix;
 
+    Glib::RefPtr<Gdk::Pixbuf> axisNonePix;
+    Glib::RefPtr<Gdk::Pixbuf> axisOnPix;
+    Glib::RefPtr<Gdk::Pixbuf> axisOffPix;
+
     std::map<Glib::ustring, std::set<guint> > buttonMap;
+    std::map<Glib::ustring, std::map<guint, std::pair<guint, gdouble> > > axesMap;
 
     GdkInputSource lastSourceSeen;
     Glib::ustring lastDevnameSeen;
 
     MyModelColumns cols;
     Glib::RefPtr<Gtk::TreeStore> store;
+    Gtk::TreeIter tabletIter;
     Gtk::TreeView tree;
     Gtk::Frame frame2;
     Gtk::Frame testFrame;
@@ -322,6 +376,7 @@ private:
     Gtk::Label devKeyCount;
     Gtk::Label devAxesCount;
     Gtk::ComboBoxText axesCombo;
+    Gtk::ProgressBar axesValues[6];
     Gtk::ComboBoxText buttonCombo;
     Gtk::ComboBoxText linkCombo;
     sigc::connection linkConnection;
@@ -332,18 +387,29 @@ private:
     Gtk::Notebook topHolder;
     Gtk::Image testThumb;
     Gtk::Image testButtons[24];
+    Gtk::Image testAxes[8];
     Gtk::Table imageTable;
     Gtk::EventBox testDetector;
 
     void setupValueAndCombo( gint reported, gint actual, Gtk::Label& label, Gtk::ComboBoxText& combo );
     void updateTestButtons( Glib::ustring const& key, gint hotButton );
+    void updateTestAxes( Glib::ustring const& key, GdkDevice* dev );
+    void mapAxesValues( Glib::ustring const& key, guint numAxes, gdouble const * axes, GdkDevice* dev);
     Glib::ustring getKeyFor( GdkDevice* device );
     bool eventSnoop(GdkEvent* event);
     void linkComboChanged();
     void resyncToSelection();
     void handleDeviceChange(const Glib::RefPtr<InputDevice>& device);
+    void updateDeviceAxes(const Glib::RefPtr<InputDevice>& device);
     void updateDeviceButtons(const Glib::RefPtr<InputDevice>& device);
     void updateDeviceLinks(const Glib::RefPtr<InputDevice>& device);
+
+    bool findDevice(const Gtk::TreeModel::iterator& iter,
+                    Glib::ustring id,
+                    Gtk::TreeModel::iterator* result);
+    bool findDeviceByLink(const Gtk::TreeModel::iterator& iter,
+                          Glib::ustring link,
+                          Gtk::TreeModel::iterator* result);
 };
 
 
@@ -370,6 +436,10 @@ InputDialogImpl::InputDialogImpl() :
     buttonsOnPix(Gdk::Pixbuf::create_from_xpm_data(button_on)),
     buttonsOffPix(Gdk::Pixbuf::create_from_xpm_data(button_off)),
 
+    axisNonePix(Gdk::Pixbuf::create_from_xpm_data(axis_none_xpm)),
+    axisOnPix(Gdk::Pixbuf::create_from_xpm_data(axis_on_xpm)),
+    axisOffPix(Gdk::Pixbuf::create_from_xpm_data(axis_off_xpm)),
+
     lastSourceSeen((GdkInputSource)-1),
     lastDevnameSeen(""),
     cols(),
@@ -382,10 +452,10 @@ InputDialogImpl::InputDialogImpl() :
     splitter(),
     split2(),
     linkCombo(),
-    devDetails(6, 2),
+    devDetails(12, 2),
     confSplitter(),
     topHolder(),
-    imageTable(8, 4)
+    imageTable(8, 7)
 {
     Gtk::Box *contents = _getContents();
 
@@ -405,7 +475,7 @@ InputDialogImpl::InputDialogImpl() :
     {
         guint col = 0;
         guint row = 1;
-        for ( guint num = 0; num < 24; num++ ) {
+        for ( guint num = 0; num < G_N_ELEMENTS(testButtons); num++ ) {
             testButtons[num].set(buttonsNonePix);
             imageTable.attach(testButtons[num], col, col + 1, row, row + 1, ::Gtk::FILL, ::Gtk::FILL);
             col++;
@@ -414,6 +484,17 @@ InputDialogImpl::InputDialogImpl() :
                 row++;
             }
         }
+
+        col = 0;
+        for ( guint num = 0; num < G_N_ELEMENTS(testAxes); num++ ) {
+            testAxes[num].set(axisNonePix);
+            imageTable.attach(testAxes[num], col * 2, (col + 1) * 2, row, row + 1, ::Gtk::FILL, ::Gtk::FILL);
+            col++;
+            if (col > 3) {
+                col = 0;
+                row++;
+            }
+        }
     }
 
 
@@ -453,7 +534,7 @@ InputDialogImpl::InputDialogImpl() :
                       ::Gtk::SHRINK);
     rowNum++;
 
-    lbl = Gtk::manage(new Gtk::Label("Reported axes count:"));
+    lbl = Gtk::manage(new Gtk::Label("Axes count:"));
     devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
                       ::Gtk::FILL,
                       ::Gtk::SHRINK);
@@ -463,6 +544,7 @@ InputDialogImpl::InputDialogImpl() :
 
     rowNum++;
 
+/*
     lbl = Gtk::manage(new Gtk::Label("Actual axes count:"));
     devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
                       ::Gtk::FILL,
@@ -472,8 +554,22 @@ InputDialogImpl::InputDialogImpl() :
                       ::Gtk::SHRINK);
 
     rowNum++;
+*/
 
-    lbl = Gtk::manage(new Gtk::Label("Reported button count:"));
+    for ( guint barNum = 0; barNum < static_cast<guint>(G_N_ELEMENTS(axesValues)); barNum++ ) {
+        lbl = Gtk::manage(new Gtk::Label("axis:"));
+        devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
+                          ::Gtk::FILL,
+                          ::Gtk::SHRINK);
+        devDetails.attach(axesValues[barNum], 1, 2, rowNum, rowNum + 1,
+                          ::Gtk::EXPAND,
+                          ::Gtk::SHRINK);
+        axesValues[barNum].set_sensitive(false);
+
+        rowNum++;
+    }
+
+    lbl = Gtk::manage(new Gtk::Label("Button count:"));
     devDetails.attach(*lbl, 0, 1, rowNum, rowNum+ 1,
                       ::Gtk::FILL,
                       ::Gtk::SHRINK);
@@ -546,27 +642,19 @@ InputDialogImpl::InputDialogImpl() :
 
     std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
     if ( !devList.empty() ) {
-        {
-            GdkModifierType  defaultModMask = static_cast<GdkModifierType>(gtk_accelerator_get_default_mod_mask());
-            gchar* name = gtk_accelerator_name(GDK_a, defaultModMask);
-            gchar* label = gtk_accelerator_get_label(GDK_a, defaultModMask);
-            g_message("Name: [%s]  label:[%s]", name, label);
-            g_free(name);
-            g_free(label);
-        }
-
         row = *(store->append());
         row[cols.description] = "Hardware";
 
-        childrow = *(store->append(row.children()));
+        tabletIter = store->append(row.children());
+        childrow = *tabletIter;
         childrow[cols.description] = "Tablet";
         childrow[cols.thumbnail] = tabletPix;
 
         for ( std::list<InputDevice const *>::iterator it = devList.begin(); it != devList.end(); ++it ) {
             InputDevice const* dev = *it;
             if ( dev ) {
-                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(),
-                          dev->hasCursor() ? "Yes":"no", dev->getNumAxes(), dev->getNumKeys());
+//                 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(),
+//                           dev->hasCursor() ? "Yes":"no", dev->getNumAxes(), dev->getNumKeys());
 
 //                 if ( dev->getSource() != Gdk::SOURCE_MOUSE ) {
                 if ( dev ) {
@@ -599,9 +687,10 @@ InputDialogImpl::InputDialogImpl() :
             }
         }
     } else {
-        g_message("NO DEVICES FOUND");
+        g_warning("No devices found");
     }
     Inkscape::DeviceManager::getManager().signalDeviceChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::handleDeviceChange));
+    Inkscape::DeviceManager::getManager().signalAxesChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::updateDeviceAxes));
     Inkscape::DeviceManager::getManager().signalButtonsChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::updateDeviceButtons));
     Inkscape::DeviceManager::getManager().signalLinkChanged().connect(sigc::mem_fun(*this, &InputDialogImpl::updateDeviceLinks));
 
@@ -614,6 +703,23 @@ void InputDialogImpl::handleDeviceChange(const Glib::RefPtr<InputDevice>& /*devi
 //     g_message("OUCH!!!! for %p  hits %s", &device, device->getId().c_str());
 }
 
+void InputDialogImpl::updateDeviceAxes(const Glib::RefPtr<InputDevice>& device)
+{
+    gint live = device->getLiveAxes();
+
+    std::map<guint, std::pair<guint, gdouble> > existing = axesMap[device->getId()];
+    gint mask = 0x1;
+    for ( gint num = 0; num < 32; num++, mask <<= 1) {
+        if ( (mask & live) != 0 ) {
+            if ( (existing.find(num) == existing.end()) || (existing[num].first < 2) ) {
+                axesMap[device->getId()][num].first = 2;
+                axesMap[device->getId()][num].second = 0.0;
+            }
+        }
+    }
+    updateTestAxes( device->getId(), 0 );
+}
+
 void InputDialogImpl::updateDeviceButtons(const Glib::RefPtr<InputDevice>& device)
 {
     gint live = device->getLiveButtons();
@@ -629,9 +735,119 @@ void InputDialogImpl::updateDeviceButtons(const Glib::RefPtr<InputDevice>& devic
     updateTestButtons(device->getId(), -1);
 }
 
-void InputDialogImpl::updateDeviceLinks(const Glib::RefPtr<InputDevice>& /*device*/)
+
+bool InputDialogImpl::findDevice(const Gtk::TreeModel::iterator& iter,
+                                 Glib::ustring id,
+                                 Gtk::TreeModel::iterator* result)
+{
+    bool stop = false;
+    const InputDevice* dev = (*iter)[cols.device];
+    if ( dev && (dev->getId() == id) ) {
+        if ( result ) {
+            *result = iter;
+        }
+        stop = true;
+    }
+    return stop;
+}
+
+bool InputDialogImpl::findDeviceByLink(const Gtk::TreeModel::iterator& iter,
+                                       Glib::ustring link,
+                                       Gtk::TreeModel::iterator* result)
+{
+    bool stop = false;
+    const InputDevice* dev = (*iter)[cols.device];
+    if ( dev && (dev->getLink() == link) ) {
+        if ( result ) {
+            *result = iter;
+        }
+        stop = true;
+    }
+    return stop;
+}
+
+void InputDialogImpl::updateDeviceLinks(const Glib::RefPtr<InputDevice>& device)
 {
-//     g_message("Links!!!! for %p  hits %s  with link of %s", &device, device->getId().c_str(), device->getLink().c_str());
+//     g_message("Links!!!! for %p  hits [%s]  with link of [%s]", &device, device->getId().c_str(), device->getLink().c_str());
+    Gtk::TreeModel::iterator deviceIter;
+    store->foreach_iter( sigc::bind<Glib::ustring, Gtk::TreeModel::iterator*>(
+                             sigc::mem_fun(*this, &InputDialogImpl::findDevice),
+                             device->getId(),
+                             &deviceIter) );
+
+    if ( deviceIter ) {
+        // Found the device concerned. Can proceed.
+
+        if ( device->getLink().empty() ) {
+            // is now unlinked
+//             g_message("Item %s is unlinked", device->getId().c_str());
+            if ( deviceIter->parent() != tabletIter ) {
+                // Not the child of the tablet. move on up
+                
+                InputDevice const *dev = (*deviceIter)[cols.device];
+                Glib::ustring descr = (*deviceIter)[cols.description];
+                Glib::RefPtr<Gdk::Pixbuf> thumb = (*deviceIter)[cols.thumbnail];
+
+                Gtk::TreeModel::Row deviceRow = *store->append(tabletIter->children());
+                deviceRow[cols.description] = descr;
+                deviceRow[cols.thumbnail] = thumb;
+                deviceRow[cols.device] = dev;
+
+                Gtk::TreeModel::iterator oldParent = deviceIter->parent();
+                store->erase(deviceIter);
+                if ( oldParent->children().empty() ) {
+                    store->erase(oldParent);
+                }
+            }
+        } else {
+            // is linking
+            if ( deviceIter->parent() == tabletIter ) {
+                // Simple case. Not already linked
+
+                Gtk::TreeIter newGroup = store->append(tabletIter->children());
+                (*newGroup)[cols.description] = "Pen";
+                (*newGroup)[cols.thumbnail] = penPix;
+
+                InputDevice const *dev = (*deviceIter)[cols.device];
+                Glib::ustring descr = (*deviceIter)[cols.description];
+                Glib::RefPtr<Gdk::Pixbuf> thumb = (*deviceIter)[cols.thumbnail];
+
+                Gtk::TreeModel::Row deviceRow = *store->append(newGroup->children());
+                deviceRow[cols.description] = descr;
+                deviceRow[cols.thumbnail] = thumb;
+                deviceRow[cols.device] = dev;
+
+                
+                Gtk::TreeModel::iterator linkIter;
+                store->foreach_iter( sigc::bind<Glib::ustring, Gtk::TreeModel::iterator*>(
+                                         sigc::mem_fun(*this, &InputDialogImpl::findDeviceByLink),
+                                         device->getId(),
+                                         &linkIter) );
+                if ( linkIter ) {
+                    dev = (*linkIter)[cols.device];
+                    descr = (*linkIter)[cols.description];
+                    thumb = (*linkIter)[cols.thumbnail];
+
+                    deviceRow = *store->append(newGroup->children());
+                    deviceRow[cols.description] = descr;
+                    deviceRow[cols.thumbnail] = thumb;
+                    deviceRow[cols.device] = dev;
+                    Gtk::TreeModel::iterator oldParent = linkIter->parent();
+                    store->erase(linkIter);
+                    if ( oldParent->children().empty() ) {
+                        store->erase(oldParent);
+                    }
+                }
+
+                Gtk::TreeModel::iterator oldParent = deviceIter->parent();
+                store->erase(deviceIter);
+                if ( oldParent->children().empty() ) {
+                    store->erase(oldParent);
+                }
+                tree.expand_row(Gtk::TreePath(newGroup), true);
+            }
+        }
+    }
 }
 
 void InputDialogImpl::linkComboChanged() {
@@ -642,12 +858,17 @@ void InputDialogImpl::linkComboChanged() {
         Glib::ustring val = row[cols.description];
         InputDevice const * dev = row[cols.device];
         if ( dev ) {
-            Glib::ustring linkName = linkCombo.get_active_text();
-            std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
-            for ( std::list<InputDevice const *>::const_iterator it = devList.begin(); it != devList.end(); ++it ) {
-                if ( linkName == (*it)->getName() ) {
-                    DeviceManager::getManager().setLinkedTo(dev->getId(), (*it)->getId());
-                    break;
+            if ( linkCombo.get_active_row_number() == 0 ) {
+                // It is the "None" entry
+                DeviceManager::getManager().setLinkedTo(dev->getId(), "");
+            } else {
+                Glib::ustring linkName = linkCombo.get_active_text();
+                std::list<InputDevice const *> devList = Inkscape::DeviceManager::getManager().getDevices();
+                for ( std::list<InputDevice const *>::const_iterator it = devList.begin(); it != devList.end(); ++it ) {
+                    if ( linkName == (*it)->getName() ) {
+                        DeviceManager::getManager().setLinkedTo(dev->getId(), (*it)->getId());
+                        break;
+                    }
                 }
             }
         }
@@ -721,7 +942,7 @@ void InputDialogImpl::setupValueAndCombo( gint reported, gint actual, Gtk::Label
 
 void InputDialogImpl::updateTestButtons( Glib::ustring const& key, gint hotButton )
 {
-    for ( gint i = 0; i < 24; i++ ) {
+    for ( gint i = 0; i < static_cast<gint>(G_N_ELEMENTS(testButtons)); i++ ) {
         if ( buttonMap[key].find(i) != buttonMap[key].end() ) {
             if ( i == hotButton ) {
                 testButtons[i].set(buttonsOnPix);
@@ -734,6 +955,122 @@ void InputDialogImpl::updateTestButtons( Glib::ustring const& key, gint hotButto
     }
 }
 
+void InputDialogImpl::updateTestAxes( Glib::ustring const& key, GdkDevice* dev )
+{
+    static gdouble epsilon = 0.0001;
+    {
+        Glib::RefPtr<Gtk::TreeSelection> treeSel = tree.get_selection();
+        Gtk::TreeModel::iterator iter = treeSel->get_selected();
+        if (iter) {
+            Gtk::TreeModel::Row row = *iter;
+            Glib::ustring val = row[cols.description];
+            InputDevice const * idev = row[cols.device];
+            if ( !idev || (idev->getId() != key) ) {
+                dev = 0;
+            }
+        }
+    }
+
+
+    for ( gint i = 0; i < static_cast<gint>(G_N_ELEMENTS(testAxes)); i++ ) {
+        if ( axesMap[key].find(i) != axesMap[key].end() ) {
+            switch ( axesMap[key][i].first ) {
+                case 0:
+                case 1:
+                    testAxes[i].set(axisNonePix);
+                    if ( dev && (i < static_cast<gint>(G_N_ELEMENTS(axesValues)) ) ) {
+                        axesValues[i].set_sensitive(false);
+                    }
+                    break;
+                case 2:
+                    testAxes[i].set(axisOffPix);
+                    axesValues[i].set_sensitive(true);
+                    if ( dev && (i < static_cast<gint>(G_N_ELEMENTS(axesValues)) ) ) {
+                        if ( (dev->axes[i].max - dev->axes[i].min) > epsilon ) {
+                            axesValues[i].set_sensitive(true);
+                            axesValues[i].set_fraction( (axesMap[key][i].second- dev->axes[i].min) / (dev->axes[i].max - dev->axes[i].min) );
+                        }
+                        gchar* str = g_strdup_printf("%f", axesMap[key][i].second);
+                        axesValues[i].set_text(str);
+                        g_free(str);
+                    }
+                    break;
+                case 3:
+                    testAxes[i].set(axisOnPix);
+                    axesValues[i].set_sensitive(true);
+                    if ( dev && (i < static_cast<gint>(G_N_ELEMENTS(axesValues)) ) ) {
+                        if ( (dev->axes[i].max - dev->axes[i].min) > epsilon ) {
+                            axesValues[i].set_sensitive(true);
+                            axesValues[i].set_fraction( (axesMap[key][i].second- dev->axes[i].min) / (dev->axes[i].max - dev->axes[i].min) );
+                        }
+                        gchar* str = g_strdup_printf("%f", axesMap[key][i].second);
+                        axesValues[i].set_text(str);
+                        g_free(str);
+                    }
+            }
+
+        } else {
+            testAxes[i].set(axisNonePix);
+        }
+    }
+    if ( !dev ) {
+        for ( gint i = 0; i < static_cast<gint>(G_N_ELEMENTS(axesValues)); i++ ) {
+            axesValues[i].set_fraction(0.0);
+            axesValues[i].set_text("");
+            axesValues[i].set_sensitive(false);
+        }
+    }
+}
+
+void InputDialogImpl::mapAxesValues( Glib::ustring const& key, guint numAxes, gdouble const * axes, GdkDevice* dev )
+{
+    static gdouble epsilon = 0.0001;
+    if ( (numAxes > 0) && axes) {
+        for ( guint axisNum = 0; axisNum < numAxes; axisNum++ ) {
+            // 0 == new, 1 == set value, 2 == changed value, 3 == active
+            gdouble diff = axesMap[key][axisNum].second - axes[axisNum];
+            switch(axesMap[key][axisNum].first) {
+                case 0:
+                {
+                    axesMap[key][axisNum].first = 1;
+                    axesMap[key][axisNum].second = axes[axisNum];
+                }
+                break;
+                case 1:
+                {
+                    if ( (diff > epsilon) || (diff < -epsilon) ) {
+//                         g_message("Axis %d changed on %s]", axisNum, key.c_str());
+                        axesMap[key][axisNum].first = 3;
+                        axesMap[key][axisNum].second = axes[axisNum];
+                        updateTestAxes(key, dev);
+                        DeviceManager::getManager().addAxis(key, axisNum);
+                    }
+                }
+                break;
+                case 2:
+                {
+                    if ( (diff > epsilon) || (diff < -epsilon) ) {
+                        axesMap[key][axisNum].first = 3;
+                        axesMap[key][axisNum].second = axes[axisNum];
+                        updateTestAxes(key, dev);
+                    }
+                }
+                break;
+                case 3:
+                {
+                    if ( (diff > epsilon) || (diff < -epsilon) ) {
+                        axesMap[key][axisNum].second = axes[axisNum];
+                    } else {
+                        axesMap[key][axisNum].first = 2;
+                        updateTestAxes(key, dev);
+                    }
+                }
+            }
+        }
+    }
+    // std::map<Glib::ustring, std::map<guint, std::pair<guint, gdouble> > > axesMap;
+}
+
 Glib::ustring InputDialogImpl::getKeyFor( GdkDevice* device )
 {
     Glib::ustring key;
@@ -774,7 +1111,7 @@ bool InputDialogImpl::eventSnoop(GdkEvent* event)
             GdkEventKey* keyEvt = reinterpret_cast<GdkEventKey*>(event);
             gchar* name = gtk_accelerator_name(keyEvt->keyval, static_cast<GdkModifierType>(keyEvt->state));
             keyVal.set_label(name);
-            g_message("%d KEY    state:0x%08x  0x%04x [%s]", keyEvt->type, keyEvt->state, keyEvt->keyval, name);
+//             g_message("%d KEY    state:0x%08x  0x%04x [%s]", keyEvt->type, keyEvt->state, keyEvt->keyval, name);
             g_free(name);
         }
         break;
@@ -789,8 +1126,9 @@ bool InputDialogImpl::eventSnoop(GdkEvent* event)
                 source = btnEvt->device->source;
                 devName = btnEvt->device->name;
 
+                mapAxesValues(key, btnEvt->device->num_axes, btnEvt->axes, btnEvt->device);
                 if ( buttonMap[key].find(btnEvt->button) == buttonMap[key].end() ) {
-                    g_message("New button found for %s = %d", key.c_str(), btnEvt->button);
+//                     g_message("New button found for %s = %d", key.c_str(), btnEvt->button);
                     buttonMap[key].insert(btnEvt->button);
                     DeviceManager::getManager().addButton(key, btnEvt->button);
                 }
@@ -799,13 +1137,13 @@ bool InputDialogImpl::eventSnoop(GdkEvent* event)
             }
             gchar* name = gtk_accelerator_name(0, static_cast<GdkModifierType>(btnEvt->state));
             keyVal.set_label(name);
-            g_message("%d BTN    state:0x%08x %c  %4d [%s] dev:%p [%s]  ",
-                      btnEvt->type, btnEvt->state,
-                      (modmod ? '+':'-'),
-                      btnEvt->button, name, btnEvt->device,
-                      (btnEvt->device ? btnEvt->device->name : "null")
+//             g_message("%d BTN    state:0x%08x %c  %4d [%s] dev:%p [%s]  ",
+//                       btnEvt->type, btnEvt->state,
+//                       (modmod ? '+':'-'),
+//                       btnEvt->button, name, btnEvt->device,
+//                       (btnEvt->device ? btnEvt->device->name : "null")
 
-                );
+//                 );
             g_free(name);
         }
         break;
@@ -816,19 +1154,20 @@ bool InputDialogImpl::eventSnoop(GdkEvent* event)
                 key = getKeyFor(btnMtn->device);
                 source = btnMtn->device->source;
                 devName = btnMtn->device->name;
+                mapAxesValues(key, btnMtn->device->num_axes, btnMtn->axes, btnMtn->device);
             }
             gchar* name = gtk_accelerator_name(0, static_cast<GdkModifierType>(btnMtn->state));
             keyVal.set_label(name);
-            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,
-                      name, btnMtn->device,
-                      (btnMtn->device ? btnMtn->device->name : "null"),
-                      ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 0)) ? btnMtn->axes[0]:0),
-                      ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 1)) ? btnMtn->axes[1]:0),
-                      ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 2)) ? btnMtn->axes[2]:0),
-                      ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 3)) ? btnMtn->axes[3]:0),
-                      ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 4)) ? btnMtn->axes[4]:0),
-                      ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 5)) ? btnMtn->axes[5]:0)
-                );
+//             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,
+//                       name, btnMtn->device,
+//                       (btnMtn->device ? btnMtn->device->name : "null"),
+//                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 0)) ? btnMtn->axes[0]:0),
+//                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 1)) ? btnMtn->axes[1]:0),
+//                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 2)) ? btnMtn->axes[2]:0),
+//                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 3)) ? btnMtn->axes[3]:0),
+//                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 4)) ? btnMtn->axes[4]:0),
+//                       ((btnMtn->device && btnMtn->axes && (btnMtn->device->num_axes > 5)) ? btnMtn->axes[5]:0)
+//                 );
             g_free(name);
         }
         break;
@@ -846,29 +1185,29 @@ bool InputDialogImpl::eventSnoop(GdkEvent* event)
             break;
             case GDK_SOURCE_CURSOR:
             {
-                g_message("flip to cursor");
+//                 g_message("flip to cursor");
                 testThumb.set(mousePix);
             }
             break;
             case GDK_SOURCE_PEN:
             {
                 if (devName == "pad") {
-                    g_message("flip to pad");
+//                     g_message("flip to pad");
                     testThumb.set(sidebuttonsPix);
                 } else {
-                    g_message("flip to pen");
+//                     g_message("flip to pen");
                     testThumb.set(tipPix);
                 }
             }
             break;
             case GDK_SOURCE_ERASER:
             {
-                g_message("flip to eraser");
+//                 g_message("flip to eraser");
                 testThumb.set(eraserPix);
             }
             break;
-            default:
-                g_message("gurgle");
+//             default:
+//                 g_message("gurgle");
         }
         updateTestButtons(key, hotButton);
         lastSourceSeen = source;