changeset 18498:2e7cad6f180c gui-release

Initial integration of QtHandles. * configure.ac: Check for QtOpenGL module. * libgui/Makefile.am: Include libgui/graphics/module.mk. (liboctgui_la_LIBADD): Include graphics/libgui-graphics.la in the list. (rcc-command): Pass "-name DIR" to rcc command. * main-window.cc (main_window::construct): Install qt functions and register qt toolkit. * libgui/src/module.mk (src_libgui_src_la_CPPFLAGS): Include $(FONTCONFIG_CPPFLAGS) and -I$(srcdir)/graphics in the list. * graphics.cc (gtk_manager::gtk_manager): Make qt the default toolkit if it is available. * libgui/graphics/Backend.cc, libgui/graphics/Backend.h, libgui/graphics/BaseControl.cc, libgui/graphics/BaseControl.h, libgui/graphics/ButtonControl.cc, libgui/graphics/ButtonControl.h, libgui/graphics/Canvas.cc, libgui/graphics/Canvas.h, libgui/graphics/CheckBoxControl.cc, libgui/graphics/CheckBoxControl.h, libgui/graphics/Container.cc, libgui/graphics/Container.h, libgui/graphics/ContextMenu.cc, libgui/graphics/ContextMenu.h, libgui/graphics/EditControl.cc, libgui/graphics/EditControl.h, libgui/graphics/Figure.cc, libgui/graphics/Figure.h, libgui/graphics/FigureWindow.cc, libgui/graphics/FigureWindow.h, libgui/graphics/GLCanvas.cc, libgui/graphics/GLCanvas.h, , libgui/graphics/GenericEventNotify.h, libgui/graphics/KeyMap.cc, libgui/graphics/KeyMap.h, libgui/graphics/ListBoxControl.cc, libgui/graphics/ListBoxControl.h, libgui/graphics/Logger.cc, libgui/graphics/Logger.h, libgui/graphics/Menu.cc, libgui/graphics/Menu.h, libgui/graphics/MenuContainer.h, libgui/graphics/MouseModeActionGroup.cc, libgui/graphics/MouseModeActionGroup.h, libgui/graphics/Object.cc, libgui/graphics/Object.h, libgui/graphics/ObjectFactory.cc, libgui/graphics/ObjectFactory.h, libgui/graphics/ObjectProxy.cc, libgui/graphics/ObjectProxy.h, libgui/graphics/Panel.cc, libgui/graphics/Panel.h, libgui/graphics/PopupMenuControl.cc, libgui/graphics/PopupMenuControl.h, libgui/graphics/PushButtonControl.cc, libgui/graphics/PushButtonControl.h, libgui/graphics/PushTool.cc, libgui/graphics/PushTool.h, libgui/graphics/RadioButtonControl.cc, libgui/graphics/RadioButtonControl.h, libgui/graphics/SliderControl.cc, libgui/graphics/SliderControl.h, libgui/graphics/TextControl.cc, libgui/graphics/TextControl.h, libgui/graphics/TextEdit.cc, libgui/graphics/TextEdit.h, libgui/graphics/ToggleButtonControl.cc, libgui/graphics/ToggleButtonControl.h, libgui/graphics/ToggleTool.cc, libgui/graphics/ToggleTool.h, libgui/graphics/ToolBar.cc, libgui/graphics/ToolBar.h, libgui/graphics/ToolBarButton.cc, libgui/graphics/ToolBarButton.h, libgui/graphics/Utils.cc, libgui/graphics/Utils.h, libgui/graphics/__init_qt__.cc, libgui/graphics/__init_qt__.h, libgui/graphics/gl-select.cc, libgui/graphics/gl-select.h, libgui/graphics/images/README, libgui/graphics/images/pan.png, libgui/graphics/images/rotate.png, libgui/graphics/images/select.png, libgui/graphics/images/zoom.png, libgui/graphics/module.mk, libgui/graphics/qthandles.qrc: New files.
author John W. Eaton <jwe@octave.org>
date Thu, 20 Feb 2014 14:05:45 -0500
parents 1ec884e5ff00
children c579bd4e12c9 49877d3be064
files configure.ac libgui/Makefile.am libgui/graphics/Backend.cc libgui/graphics/Backend.h libgui/graphics/BaseControl.cc libgui/graphics/BaseControl.h libgui/graphics/ButtonControl.cc libgui/graphics/ButtonControl.h libgui/graphics/Canvas.cc libgui/graphics/Canvas.h libgui/graphics/CheckBoxControl.cc libgui/graphics/CheckBoxControl.h libgui/graphics/Container.cc libgui/graphics/Container.h libgui/graphics/ContextMenu.cc libgui/graphics/ContextMenu.h libgui/graphics/EditControl.cc libgui/graphics/EditControl.h libgui/graphics/Figure.cc libgui/graphics/Figure.h libgui/graphics/FigureWindow.cc libgui/graphics/FigureWindow.h libgui/graphics/GLCanvas.cc libgui/graphics/GLCanvas.h libgui/graphics/GenericEventNotify.h libgui/graphics/KeyMap.cc libgui/graphics/KeyMap.h libgui/graphics/ListBoxControl.cc libgui/graphics/ListBoxControl.h libgui/graphics/Logger.cc libgui/graphics/Logger.h libgui/graphics/Menu.cc libgui/graphics/Menu.h libgui/graphics/MenuContainer.h libgui/graphics/MouseModeActionGroup.cc libgui/graphics/MouseModeActionGroup.h libgui/graphics/Object.cc libgui/graphics/Object.h libgui/graphics/ObjectFactory.cc libgui/graphics/ObjectFactory.h libgui/graphics/ObjectProxy.cc libgui/graphics/ObjectProxy.h libgui/graphics/Panel.cc libgui/graphics/Panel.h libgui/graphics/PopupMenuControl.cc libgui/graphics/PopupMenuControl.h libgui/graphics/PushButtonControl.cc libgui/graphics/PushButtonControl.h libgui/graphics/PushTool.cc libgui/graphics/PushTool.h libgui/graphics/RadioButtonControl.cc libgui/graphics/RadioButtonControl.h libgui/graphics/SliderControl.cc libgui/graphics/SliderControl.h libgui/graphics/TextControl.cc libgui/graphics/TextControl.h libgui/graphics/TextEdit.cc libgui/graphics/TextEdit.h libgui/graphics/ToggleButtonControl.cc libgui/graphics/ToggleButtonControl.h libgui/graphics/ToggleTool.cc libgui/graphics/ToggleTool.h libgui/graphics/ToolBar.cc libgui/graphics/ToolBar.h libgui/graphics/ToolBarButton.cc libgui/graphics/ToolBarButton.h libgui/graphics/Utils.cc libgui/graphics/Utils.h libgui/graphics/__init_qt__.cc libgui/graphics/__init_qt__.h libgui/graphics/gl-select.cc libgui/graphics/gl-select.h libgui/graphics/images/README libgui/graphics/images/pan.png libgui/graphics/images/rotate.png libgui/graphics/images/select.png libgui/graphics/images/zoom.png libgui/graphics/module.mk libgui/graphics/qthandles.qrc libgui/src/main-window.cc libgui/src/module.mk libinterp/corefcn/graphics.cc
diffstat 82 files changed, 9066 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Thu Feb 20 16:18:02 2014 +0100
+++ b/configure.ac	Thu Feb 20 14:05:45 2014 -0500
@@ -2712,16 +2712,16 @@
 
   warn_gui=""
   ## Check for Qt libraries
-  PKG_CHECK_MODULES(QT, [QtCore, QtGui, QtNetwork],
+  PKG_CHECK_MODULES(QT, [QtCore, QtGui, QtNetwork, QtOpenGL],
     [],
     [warn_gui="Qt libraries not found -- disabling GUI"
      build_gui=no])
 
   if test $build_gui = yes; then
     ## Retrieve Qt compilation and linker flags
-    QT_CPPFLAGS="`$PKG_CONFIG --cflags-only-I QtCore QtGui QtNetwork`"
-    QT_LDFLAGS="`$PKG_CONFIG --libs-only-L QtCore QtGui QtNetwork`"
-    QT_LIBS="`$PKG_CONFIG --libs-only-l QtCore QtGui QtNetwork`"
+    QT_CPPFLAGS="`$PKG_CONFIG --cflags-only-I QtCore QtGui QtNetwork QtOpenGL`"
+    QT_LDFLAGS="`$PKG_CONFIG --libs-only-L QtCore QtGui QtNetwork QtOpenGL`"
+    QT_LIBS="`$PKG_CONFIG --libs-only-l QtCore QtGui QtNetwork QtOpenGL`"
 
     case $host_os in
       *darwin*)
--- a/libgui/Makefile.am	Thu Feb 20 16:18:02 2014 +0100
+++ b/libgui/Makefile.am	Thu Feb 20 14:05:45 2014 -0500
@@ -48,6 +48,7 @@
 noinst_LTLIBRARIES =
 
 include src/module.mk
+include graphics/module.mk
 include qterminal-module.mk
 
 ## liboctgui merely collects a bunch of compiled convenience libraries.
@@ -62,6 +63,7 @@
 liboctgui_la_LIBADD = \
   qterminal/libqterminal.la \
   src/libgui-src.la \
+  graphics/libgui-graphics.la \
   $(top_builddir)/libinterp/liboctinterp.la \
   $(top_builddir)/liboctave/liboctave.la \
   $(LIBOCTGUI_LINK_DEPS)
@@ -98,7 +100,7 @@
 ( echo '#ifdef HAVE_CONFIG_H'; \
   echo '#include <config.h>'; \
   echo '#endif'; \
-  $(RCC) $< ) > $@-t
+  $(RCC) -name $(@D) $< ) > $@-t
 mv $@-t $@
 endef
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Backend.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,224 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QApplication>
+#include <QThread>
+
+#include <stdint.h>
+
+#include "Backend.h"
+#include "Logger.h"
+#include "Object.h"
+#include "ObjectFactory.h"
+#include "ObjectProxy.h"
+
+//#if INTPTR_MAX == INT32_MAX
+//# define OCTAVE_PTR_TYPE octave_uint32
+//# define OCTAVE_INTPTR_TYPE uint32_t
+//# define OCTAVE_PTR_SCALAR uint32_scalar_value
+//#else
+# define OCTAVE_PTR_TYPE octave_uint64
+# define OCTAVE_INTPTR_TYPE uint64_t
+# define OCTAVE_PTR_SCALAR uint64_scalar_value
+//#endif
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+static std::string toolkitObjectProperty (const graphics_object& go)
+{
+  if (go.isa ("figure"))
+    return std::string ("__plot_stream__");
+  else if (go.isa ("uicontrol")
+	   || go.isa ("uipanel")
+	   || go.isa ("uimenu")
+	   || go.isa ("uicontextmenu")
+	   || go.isa ("uitoolbar")
+	   || go.isa ("uipushtool")
+	   || go.isa ("uitoggletool"))
+    return std::string ("__object__");
+  else
+    qCritical ("QtHandles::Backend: no __object__ property known for object "
+	       "of type %s", go.type ().c_str ());
+
+  return std::string ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Backend::Backend (void)
+  : QObject (), base_graphics_toolkit ("qt")
+{
+  ObjectFactory* factory = ObjectFactory::instance ();
+
+  connect (this, SIGNAL (createObject (double)),
+	   factory, SLOT (createObject (double)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Backend::~Backend (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool Backend::initialize (const graphics_object& go)
+{
+  if (go.isa ("figure")
+      || go.isa ("uicontrol")
+      || go.isa ("uipanel")
+      || go.isa ("uimenu")
+      || go.isa ("uicontextmenu")
+      || go.isa ("uitoolbar")
+      || go.isa ("uipushtool")
+      || go.isa ("uitoggletool"))
+    {
+      Logger::debug ("Backend::initialize %s from thread %08x",
+		     go.type ().c_str (), QThread::currentThreadId ());
+
+      ObjectProxy* proxy = new ObjectProxy ();
+      graphics_object gObj (go);
+
+      gObj.get_properties ().set(toolkitObjectProperty (go),
+				 OCTAVE_PTR_TYPE ((OCTAVE_INTPTR_TYPE) proxy));
+
+      emit createObject (go.get_handle ().value ());
+
+      return true;
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Backend::update (const graphics_object& go, int pId)
+{
+  // Rule out obvious properties we want to ignore.
+  if (pId == figure::properties::ID___PLOT_STREAM__
+      || pId == uicontrol::properties::ID___OBJECT__
+      || pId == uipanel::properties::ID___OBJECT__
+      || pId == uimenu::properties::ID___OBJECT__
+      || pId == uicontextmenu::properties::ID___OBJECT__
+      || pId == uitoolbar::properties::ID___OBJECT__
+      || pId == uipushtool::properties::ID___OBJECT__
+      || pId == uitoggletool::properties::ID___OBJECT__
+      || pId == base_properties::ID___MODIFIED__)
+    return;
+
+  Logger::debug ("Backend::update %s(%d) from thread %08x",
+		 go.type ().c_str (), pId, QThread::currentThreadId ());
+
+  ObjectProxy* proxy = toolkitObjectProxy (go);
+
+  if (proxy)
+    {
+      if (go.isa ("uicontrol")
+	  && pId == uicontrol::properties::ID_STYLE)
+	{
+	  // Special case: we need to recreate the control widget
+	  // associated with the octave graphics_object
+
+	  finalize (go);
+	  initialize (go);
+	}
+      else
+	proxy->update (pId);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Backend::finalize (const graphics_object& go)
+{
+  Logger::debug ("Backend::finalize %s from thread %08x",
+		 go.type ().c_str (), QThread::currentThreadId ());
+
+  ObjectProxy* proxy = toolkitObjectProxy (go);
+
+  if (proxy)
+    {
+      proxy->finalize ();
+      delete proxy;
+
+      graphics_object gObj (go);
+
+      gObj.get_properties ().set (toolkitObjectProperty (go), Matrix ());
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Backend::redraw_figure (const graphics_object& go) const
+{
+  if (go.get_properties ().is_visible ())
+    {
+      ObjectProxy* proxy = toolkitObjectProxy (go);
+
+      if (proxy)
+	proxy->redraw ();
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Object* Backend::toolkitObject (const graphics_object& go)
+{
+  ObjectProxy* proxy = toolkitObjectProxy (go);
+
+  if (proxy)
+    return proxy->object ();
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ObjectProxy* Backend::toolkitObjectProxy (const graphics_object& go)
+{
+  if (go)
+    {
+      octave_value ov = go.get (toolkitObjectProperty (go));
+
+      if (ov.is_defined () && ! ov.is_empty ())
+	{
+	  OCTAVE_INTPTR_TYPE ptr = ov.OCTAVE_PTR_SCALAR ().value ();
+
+	  if (! error_state)
+	    return reinterpret_cast<ObjectProxy*> (ptr);
+	}
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Backend.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,74 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_Backend__
+#define __QtHandles_Backend__ 1
+
+#include <QObject>
+
+#include "graphics.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Object;
+class ObjectProxy;
+
+class Backend :
+  public QObject,
+  public base_graphics_toolkit
+{
+  Q_OBJECT
+
+public:
+  Backend (void);
+
+  ~Backend (void);
+
+  bool is_valid (void) const { return true; }
+
+  void redraw_figure (const graphics_object& h) const;
+
+  void update (const graphics_object& obj, int pId);
+
+  bool initialize (const graphics_object& obj);
+
+  void finalize (const graphics_object& obj);
+
+  static Object* toolkitObject (const graphics_object& go);
+
+  static ObjectProxy* toolkitObjectProxy (const graphics_object& go);
+
+signals:
+  void createObject (double handle);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/BaseControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,233 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QEvent>
+#include <QKeyEvent>
+#include <QMouseEvent>
+#include <QWidget>
+
+#include "BaseControl.h"
+#include "ContextMenu.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void updatePalette (const uicontrol::properties& props, QWidget* w)
+{
+  QPalette p = w->palette ();
+
+  if (props.style_is ("edit")
+      || props.style_is ("listbox")
+      || props.style_is ("popupmenu"))
+    {
+      p.setColor (QPalette::Base,
+		  Utils::fromRgb (props.get_backgroundcolor_rgb ()));
+      p.setColor (QPalette::Text,
+		  Utils::fromRgb (props.get_foregroundcolor_rgb ()));
+    }
+  else if (props.style_is ("pushbutton")
+	   || props.style_is ("togglebutton"))
+    {
+      p.setColor (QPalette::Button,
+		  Utils::fromRgb (props.get_backgroundcolor_rgb ()));
+      p.setColor (QPalette::ButtonText,
+		  Utils::fromRgb (props.get_foregroundcolor_rgb ()));
+    }
+  else
+    {
+      p.setColor (QPalette::Window,
+		  Utils::fromRgb (props.get_backgroundcolor_rgb ()));
+      p.setColor (QPalette::WindowText,
+		  Utils::fromRgb (props.get_foregroundcolor_rgb ()));
+    }
+
+  w->setPalette (p);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+BaseControl::BaseControl (const graphics_object& go, QWidget* w)
+  : Object (go, w), m_normalizedFont (false), m_keyPressHandlerDefined (false)
+{
+  init (w);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void BaseControl::init (QWidget* w, bool callBase)
+{
+  if (callBase)
+    Object::init (w, callBase);
+
+  uicontrol::properties& up = properties<uicontrol> ();
+
+  Matrix bb = up.get_boundingbox (false);
+  w->setGeometry (xround (bb(0)), xround (bb(1)),
+		  xround (bb(2)), xround (bb(3)));
+  w->setFont (Utils::computeFont<uicontrol> (up, bb(3)));
+  updatePalette (up, w);
+  w->setEnabled (up.enable_is ("on"));
+  w->setToolTip (Utils::fromStdString (up.get_tooltipstring ()));
+  w->setVisible (up.is_visible ());
+  m_keyPressHandlerDefined = ! up.get_keypressfcn ().is_empty ();
+
+  w->installEventFilter (this);
+
+  m_normalizedFont = up.fontunits_is ("normalized");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+BaseControl::~BaseControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void BaseControl::update (int pId)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+  QWidget* w = qWidget<QWidget> ();
+
+   switch (pId)
+    {
+    case uicontrol::properties::ID_POSITION:
+	{
+	  Matrix bb = up.get_boundingbox (false);
+	  w->setGeometry (xround (bb(0)), xround (bb(1)),
+			  xround (bb(2)), xround (bb(3)));
+	}
+      break;
+    case uicontrol::properties::ID_FONTNAME:
+    case uicontrol::properties::ID_FONTSIZE:
+    case uicontrol::properties::ID_FONTWEIGHT:
+    case uicontrol::properties::ID_FONTANGLE:
+      w->setFont (Utils::computeFont<uicontrol> (up));
+      break;
+    case uicontrol::properties::ID_FONTUNITS:
+      // FIXME: We shouldn't have to do anything, octave should update
+      //        the "fontsize" property automatically to the new units.
+      //        Hence the actual font used shouldn't change.
+      m_normalizedFont = up.fontunits_is ("normalized");
+      break;
+    case uicontrol::properties::ID_BACKGROUNDCOLOR:
+    case uicontrol::properties::ID_FOREGROUNDCOLOR:
+      updatePalette (up, w);
+      break;
+    case uicontrol::properties::ID_ENABLE:
+      w->setEnabled (up.enable_is ("on"));
+      break;
+    case uicontrol::properties::ID_TOOLTIPSTRING:
+      w->setToolTip (Utils::fromStdString (up.get_tooltipstring ()));
+      break;
+    case base_properties::ID_VISIBLE:
+      w->setVisible (up.is_visible ());
+      break;
+    case uicontrol::properties::ID_KEYPRESSFCN:
+      m_keyPressHandlerDefined = ! up.get_keypressfcn ().is_empty ();
+      break;
+    default:
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool BaseControl::eventFilter (QObject* watched, QEvent* event)
+{
+  switch (event->type ())
+    {
+    case QEvent::Resize:
+      if (m_normalizedFont)
+	{
+	  gh_manager::auto_lock lock;
+
+	  qWidget<QWidget> ()->setFont (Utils::computeFont<uicontrol>
+					(properties<uicontrol> ()));
+	}
+      break;
+    case QEvent::MouseButtonPress:
+	{
+	  gh_manager::auto_lock lock;
+
+	  QMouseEvent* m = dynamic_cast<QMouseEvent*> (event);
+	  graphics_object go = object ();
+	  uicontrol::properties& up = Utils::properties<uicontrol> (go);
+	  graphics_object fig = go.get_ancestor ("figure");
+
+	  if (m->button () != Qt::LeftButton
+	      || ! up.enable_is ("on"))
+	    {
+	      gh_manager::post_set (fig.get_handle (), "selectiontype",
+				    Utils::figureSelectionType (m), false);
+	      gh_manager::post_set (fig.get_handle (), "currentpoint",
+				    Utils::figureCurrentPoint (fig, m),
+				    false);
+	      gh_manager::post_callback (fig.get_handle (),
+					 "windowbuttondownfcn");
+	      gh_manager::post_callback (m_handle, "buttondownfcn");
+
+	      if (m->button () == Qt::RightButton)
+		ContextMenu::executeAt (up, m->globalPos ());
+	    }
+	  else
+	    {
+	      if (up.style_is ("listbox"))
+		gh_manager::post_set (fig.get_handle (), "selectiontype",
+				      Utils::figureSelectionType (m), false);
+	      else
+		gh_manager::post_set (fig.get_handle (), "selectiontype",
+				      octave_value ("normal"), false);
+	    }
+	}
+      break;
+    case QEvent::KeyPress:
+      if (m_keyPressHandlerDefined)
+        {
+          gh_manager::auto_lock lock;
+
+          octave_scalar_map keyData =
+            Utils::makeKeyEventStruct (dynamic_cast<QKeyEvent*> (event));
+          graphics_object fig = object ().get_ancestor ("figure");
+
+          gh_manager::post_set (fig.get_handle (), "currentcharacter",
+                                keyData.getfield ("Character"), false);
+          gh_manager::post_callback (m_handle, "keypressfcn", keyData);
+        }
+      break;
+    default: break;
+    }
+
+  return Object::eventFilter (watched, event);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/BaseControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,62 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_BaseControl__
+#define __QtHandles_BaseControl__ 1
+
+#include "Object.h"
+
+class QEvent;
+class QObject;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class BaseControl : public Object
+{
+public:
+  BaseControl (const graphics_object& go, QWidget* w);
+  ~BaseControl (void);
+
+  Container* innerContainer (void) { return 0; }
+
+  bool eventFilter (QObject* watched, QEvent* event);
+
+protected:
+  void init (QWidget* w, bool callBase = false);
+  void update (int pId);
+
+private:
+  bool m_normalizedFont;
+  bool m_keyPressHandlerDefined;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ButtonControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,135 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QAbstractButton>
+
+#include "ButtonControl.h"
+#include "Container.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+ButtonControl::ButtonControl (const graphics_object& go, QAbstractButton* btn)
+    : BaseControl (go, btn), m_blockCallback (false)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+
+  btn->setText (Utils::fromStdString (up.get_string_string ()));
+  if (btn->isCheckable () || up.style_is ("togglebutton"))
+    {
+      btn->setCheckable (true);
+
+      Matrix value = up.get_value ().matrix_value ();
+
+      if (value.numel () > 0 && value(0) == up.get_max ())
+	btn->setChecked (true);
+    }
+
+  connect (btn, SIGNAL (clicked (void)), SLOT (clicked (void)));
+  connect (btn, SIGNAL (toggled (bool)), SLOT (toggled (bool)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ButtonControl::~ButtonControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ButtonControl::update (int pId)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+  QAbstractButton* btn = qWidget<QAbstractButton> ();
+
+  switch (pId)
+    {
+    case uicontrol::properties::ID_STRING:
+      btn->setText (Utils::fromStdString (up.get_string_string ()));
+      break;
+    case uicontrol::properties::ID_VALUE:
+      m_blockCallback = true;
+      if (btn->isCheckable ())
+	{
+	  Matrix value = up.get_value ().matrix_value ();
+
+	  if (value.numel () > 0)
+	    {
+	      double dValue = value(0);
+
+	      if (dValue == up.get_min () && btn->isChecked ())
+		btn->setChecked (false);
+	      else if (dValue == up.get_max () && ! btn->isChecked ())
+		btn->setChecked (true);
+	    }
+	}
+      m_blockCallback = false;
+      break;
+    default:
+      BaseControl::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ButtonControl::toggled (bool checked)
+{
+  QAbstractButton* btn = qWidget<QAbstractButton> ();
+
+  if (! m_blockCallback && btn->isCheckable ())
+    {
+      gh_manager::auto_lock lock;
+
+      uicontrol::properties& up = properties<uicontrol> ();
+
+      Matrix oldValue = up.get_value ().matrix_value ();
+      double newValue = (checked ? up.get_max () : up.get_min ());
+
+      if (oldValue.numel() != 1
+	  || (newValue != oldValue(0)))
+	gh_manager::post_set (m_handle, "value", newValue, false);
+      gh_manager::post_callback (m_handle, "callback");
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ButtonControl::clicked (void)
+{
+  QAbstractButton* btn = qWidget<QAbstractButton> ();
+
+  if (! btn->isCheckable ())
+    gh_manager::post_callback (m_handle, "callback");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ButtonControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,61 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_ButtonControl__
+#define __QtHandles_ButtonControl__ 1
+
+#include "BaseControl.h"
+
+class QAbstractButton;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class ButtonControl : public BaseControl
+{
+  Q_OBJECT
+
+public:
+  ButtonControl (const graphics_object& go, QAbstractButton* btn);
+  ~ButtonControl (void);
+
+protected:
+  void update (int pId); 
+
+private slots:
+  void clicked (void);
+  void toggled (bool checked);
+
+private:
+  bool m_blockCallback;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Canvas.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,393 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QApplication>
+#include <QList>
+#include <QMouseEvent>
+#include <QRectF>
+
+#include "Backend.h"
+#include "Canvas.h"
+#include "ContextMenu.h"
+#include "GLCanvas.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Canvas::redraw (bool sync)
+{
+  if (sync)
+    qWidget ()->repaint ();
+  else
+    qWidget ()->update ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Canvas::blockRedraw (bool block)
+{
+  m_redrawBlocked = block;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Canvas::canvasPaintEvent (void)
+{
+  if (! m_redrawBlocked)
+    {
+      gh_manager::auto_lock lock;
+
+      draw (m_handle);
+
+      if (m_mouseMode == ZoomMode && m_mouseAxes.ok ())
+	drawZoomBox (m_mouseAnchor, m_mouseCurrent);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Canvas::canvasMouseMoveEvent (QMouseEvent* event)
+{
+  gh_manager::auto_lock lock;
+  graphics_object ax = gh_manager::get_object (m_mouseAxes);
+
+  if (m_mouseMode != NoMode && ax.valid_object ())
+    {
+      axes::properties& ap = Utils::properties<axes> (ax);
+
+      switch (m_mouseMode)
+	{
+	case RotateMode:
+	    {
+	      Matrix bb = ap.get_boundingbox (true);
+	      Matrix view = ap.get_view ().matrix_value ();
+
+	      // Compute new view angles
+	      view(0) += ((m_mouseCurrent.x () - event->x ())
+			  * (180.0 / bb(2)));
+	      view(1) += ((event->y () - m_mouseCurrent.y ())
+			  * (180.0 / bb(3)));
+
+	      // Clipping
+	      view(1) = std::min (view(1), 90.0);
+	      view(1) = std::max (view(1), -90.0);
+	      if (view(0) > 180.0)
+		view(0) -= 360.0;
+	      else if (view(0) < -180.0)
+		view(0) += 360.0;
+
+	      // Snapping
+	      double snapMargin = 1.0;
+	      for (int a = -90; a <= 90; a += 90)
+		if ((a - snapMargin) < view(1)
+		    && view(1) < (a + snapMargin))
+		  {
+		    view(1) = a;
+		    break;
+		  }
+	      for (int a = -180; a <= 180; a += 180)
+		if ((a - snapMargin) < view(0)
+		    && view(0) < (a + snapMargin))
+		  {
+		    if (a == 180)
+		      view(0) = -180;
+		    else
+		      view(0) = a;
+		    break;
+		  }
+
+	      // Update axes properties
+	      ap.set_view (view);
+
+	      // Update current mouse position
+	      m_mouseCurrent = event->pos ();
+
+	      // Force immediate redraw
+	      redraw (true);
+	    }
+	  break;
+	case ZoomMode:
+	  m_mouseCurrent = event->pos();
+	  redraw (true);
+	  break;
+	case PanMode:
+	  break;
+	default:
+	  break;
+	}
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Canvas::canvasMousePressEvent (QMouseEvent* event)
+{
+  gh_manager::auto_lock lock;
+  graphics_object obj = gh_manager::get_object (m_handle);
+
+  if (obj.valid_object ())
+    {
+      graphics_object figObj (obj.get_ancestor ("figure"));
+      graphics_object currentObj, axesObj;
+      QList<graphics_object> axesList;
+
+      Matrix children = obj.get_properties ().get_children ();
+      octave_idx_type num_children = children.numel ();
+
+      for (int i = 0; i < num_children; i++)
+	{
+	  graphics_object childObj (gh_manager::get_object (children(i)));
+
+          if (childObj.isa ("axes"))
+            axesList.append (childObj);
+	  else if (childObj.isa ("uicontrol") || childObj.isa ("uipanel"))
+	    {
+	      Matrix bb = childObj.get_properties ().get_boundingbox (false);
+	      QRectF r (bb(0), bb(1), bb(2), bb(3));
+
+	      r.adjust (-5, -5, 5, 5);
+	      if (r.contains (event->posF ()))
+		{
+		  currentObj = childObj;
+		  break;
+		}
+	    }
+	}
+
+      if (! currentObj)
+        {
+          for (QList<graphics_object>::ConstIterator it = axesList.begin ();
+               it != axesList.end (); ++it)
+            {
+              graphics_object go = selectFromAxes (*it, event->pos ());
+
+              if (go)
+                {
+                  currentObj = go;
+                  axesObj = *it;
+                }
+              // FIXME: is this really necessary? the axes object should
+              //        have been selected through selectFromAxes anyway
+              else if (it->get_properties ().is_hittest ())
+                {
+                  Matrix bb = it->get_properties ().get_boundingbox (true);
+                  QRectF r (bb(0), bb(1), bb(2), bb(3));
+
+                  if (r.contains (event->posF ()))
+                    axesObj = *it;
+                }
+
+              if (axesObj)
+                break;
+            }
+
+          if (axesObj)
+            {
+              if (axesObj.get_properties ().handlevisibility_is ("on"))
+                Utils::properties<figure> (figObj)
+                  .set_currentaxes (axesObj.get_handle ().as_octave_value ());
+              if (! currentObj)
+                currentObj = axesObj;
+            }
+        }
+
+      if (! currentObj)
+        currentObj = obj;
+
+      if (currentObj.get_properties ().handlevisibility_is ("on"))
+        Utils::properties<figure> (figObj)
+          .set_currentobject (currentObj.get_handle ().as_octave_value ());
+      else
+        Utils::properties<figure> (figObj).set_currentobject (octave_NaN);
+
+      Figure* fig = dynamic_cast<Figure*> (Backend::toolkitObject (figObj));
+
+      MouseMode newMouseMode = NoMode;
+
+      if (fig)
+	newMouseMode = fig->mouseMode ();
+
+      switch (newMouseMode)
+	{
+	case NoMode:
+	  gh_manager::post_set (figObj.get_handle (), "selectiontype",
+				Utils::figureSelectionType (event), false);
+	  gh_manager::post_set (figObj.get_handle (), "currentpoint",
+				Utils::figureCurrentPoint (figObj, event),
+				false);
+	  gh_manager::post_callback (figObj.get_handle (),
+				     "windowbuttondownfcn");
+          gh_manager::post_callback (currentObj.get_handle (),
+                                     "buttondownfcn");
+	  if (event->button () == Qt::RightButton)
+	    ContextMenu::executeAt (currentObj.get_properties (),
+				    event->globalPos ());
+	  break;
+	case RotateMode:
+	case ZoomMode:
+	case PanMode:
+	  if (axesObj)
+	    {
+	      if (event->buttons () == Qt::LeftButton
+		  && event->modifiers () == Qt::NoModifier)
+		{
+		  m_mouseAnchor = m_mouseCurrent = event->pos ();
+		  m_mouseAxes = axesObj.get_handle ();
+		  m_mouseMode = newMouseMode;
+		}
+	      else if (newMouseMode == ZoomMode
+		       && event->modifiers () == Qt::NoModifier)
+		{
+		  switch (event->buttons ())
+		    {
+		    case Qt::RightButton:
+		      Utils::properties<axes> (axesObj).unzoom ();
+		      break;
+		    case Qt::MidButton:
+			{
+			  axes::properties& ap =
+			    Utils::properties<axes> (axesObj);
+
+			  ap.clear_zoom_stack ();
+			  ap.set_xlimmode ("auto");
+			  ap.set_ylimmode ("auto");
+			  ap.set_zlimmode ("auto");
+			}
+		      break;
+		    }
+		  redraw (false);
+		}
+	    }
+	  break;
+	default:
+	  break;
+	}
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Canvas::canvasMouseReleaseEvent (QMouseEvent* event)
+{
+  if (m_mouseMode == ZoomMode
+      && m_mouseAxes.ok ()
+      && m_mouseAnchor != event->pos ())
+    {
+      gh_manager::auto_lock lock;
+      graphics_object ax = gh_manager::get_object (m_mouseAxes);
+
+      if (ax.valid_object ())
+	{
+	  axes::properties& ap = Utils::properties<axes> (ax);
+
+	  ColumnVector p0 = ap.pixel2coord (m_mouseAnchor.x (),
+					    m_mouseAnchor.y ());
+	  ColumnVector p1 = ap.pixel2coord (event->x (),
+					    event->y ());
+
+	  Matrix xl (1, 2, 0.0);
+	  Matrix yl (1, 2, 0.0);
+
+	  xl(0) = std::min (p0(0), p1(0));
+	  xl(1) = std::max (p0(0), p1(0));
+	  yl(0) = std::min (p0(1), p1(1));
+	  yl(1) = std::max (p0(1), p1(1));
+
+	  ap.zoom (xl, yl);
+
+	  redraw (false);
+	}
+    }
+  else if (m_mouseMode == NoMode)
+    {
+      gh_manager::auto_lock lock;
+      graphics_object obj = gh_manager::get_object (m_handle);
+
+      if (obj.valid_object ())
+        {
+          graphics_object figObj (obj.get_ancestor ("figure"));
+
+	  gh_manager::post_set (figObj.get_handle (), "currentpoint",
+				Utils::figureCurrentPoint (figObj, event),
+				false);
+          gh_manager::post_callback (figObj.get_handle (),
+                                     "windowbuttonupfcn");
+        }
+    }
+
+  m_mouseAxes = graphics_handle ();
+  m_mouseMode = NoMode;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool Canvas::canvasKeyPressEvent (QKeyEvent* event)
+{
+  if (m_eventMask & KeyPress)
+    {
+      octave_scalar_map eventData = Utils::makeKeyEventStruct (event);
+
+      gh_manager::post_set (m_handle, "currentcharacter",
+                            eventData.getfield ("Character"), false);
+      gh_manager::post_callback (m_handle, "keypressfcn", eventData);
+
+      return true;
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool Canvas::canvasKeyReleaseEvent (QKeyEvent* event)
+{
+  if (! event->isAutoRepeat () && (m_eventMask & KeyRelease))
+    {
+      gh_manager::post_callback (m_handle, "keyreleasefcn",
+                                 Utils::makeKeyEventStruct (event));
+
+      return true;
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Canvas* Canvas::create (const std::string& /* name */, QWidget* parent,
+			const graphics_handle& handle)
+{
+  // Only OpenGL
+  return new GLCanvas (parent, handle);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Canvas.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,104 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_Canvas__
+#define __QtHandles_Canvas__ 1
+
+#include <QPoint>
+
+#include "graphics.h"
+
+#include "Figure.h"
+
+class QKeyEvent;
+class QMouseEvent;
+class QWidget;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Canvas
+{
+public:
+  enum EventMask
+    {
+      KeyPress   = 0x01,
+      KeyRelease = 0x02
+    };
+
+public:
+  virtual ~Canvas (void) { }
+
+  void redraw (bool sync = false);
+  void blockRedraw (bool block = true);
+
+  void addEventMask (int m) { m_eventMask |= m; }
+  void clearEventMask (int m) { m_eventMask &= (~m); }
+  void setEventMask (int m) { m_eventMask = m; }
+
+  virtual QWidget* qWidget (void) = 0;
+
+  static Canvas* create (const std::string& name, QWidget* parent,
+			 const graphics_handle& handle);
+
+protected:
+  virtual void draw (const graphics_handle& handle) = 0;
+  virtual void drawZoomBox (const QPoint& p1, const QPoint& p2) = 0;
+  virtual void resize (int x, int y, int width, int height) = 0;
+  virtual graphics_object selectFromAxes (const graphics_object& ax,
+                                          const QPoint& pt) = 0;
+
+protected:
+  Canvas (const graphics_handle& handle)
+    : m_handle (handle),
+      m_redrawBlocked (false),
+      m_mouseMode (NoMode),
+      m_eventMask (0)
+    { }
+
+  void canvasPaintEvent (void);
+  void canvasMouseMoveEvent (QMouseEvent* event);
+  void canvasMousePressEvent (QMouseEvent* event);
+  void canvasMouseReleaseEvent (QMouseEvent* event);
+  bool canvasKeyPressEvent (QKeyEvent* event);
+  bool canvasKeyReleaseEvent (QKeyEvent* event);
+
+private:
+  graphics_handle m_handle;
+  bool m_redrawBlocked;
+  MouseMode m_mouseMode;
+  QPoint m_mouseAnchor;
+  QPoint m_mouseCurrent;
+  graphics_handle m_mouseAxes;
+  int m_eventMask;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/CheckBoxControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,69 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QCheckBox>
+
+#include "CheckBoxControl.h"
+#include "Container.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+CheckBoxControl* CheckBoxControl::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      Container* container = parent->innerContainer ();
+
+      if (container)
+	return new CheckBoxControl (go, new QCheckBox (container));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+CheckBoxControl::CheckBoxControl (const graphics_object& go, QCheckBox* box)
+    : ButtonControl (go, box)
+{
+  box->setAutoFillBackground (true);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+CheckBoxControl::~CheckBoxControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/CheckBoxControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,51 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_CheckBoxControl__
+#define __QtHandles_CheckBoxControl__ 1
+
+#include "ButtonControl.h"
+
+class QCheckBox;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class CheckBoxControl : public ButtonControl
+{
+public:
+  CheckBoxControl (const graphics_object& go, QCheckBox* box);
+  ~CheckBoxControl (void);
+
+  static CheckBoxControl* create (const graphics_object& go);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Container.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,109 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QVBoxLayout>
+
+#include "graphics.h"
+
+#include "Canvas.h"
+#include "Container.h"
+#include "Object.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+Container::Container (QWidget* parent)
+  : ContainerBase (parent), m_canvas (0)
+{
+  setFocusPolicy (Qt::ClickFocus);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Container::~Container (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Canvas* Container::canvas (const graphics_handle& handle, bool create)
+{
+  if (! m_canvas && create)
+    {
+      graphics_object go = gh_manager::get_object (handle);
+
+      if (go)
+	{
+	  graphics_object fig = go.get_ancestor ("figure");
+
+	  m_canvas = Canvas::create (fig.get("renderer").string_value (),
+				     this, handle);
+
+	  QWidget* canvasWidget = m_canvas->qWidget ();
+
+	  canvasWidget->lower ();
+	  canvasWidget->show ();
+	  canvasWidget->setGeometry (0, 0, width (), height ());
+	}
+    }
+
+  return m_canvas;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Container::resizeEvent (QResizeEvent* /* event */)
+{
+  if (m_canvas)
+    m_canvas->qWidget ()->setGeometry (0, 0, width (), height ());
+
+  gh_manager::auto_lock lock;
+
+  foreach (QObject* qObj, children ())
+    {
+      if (qObj->isWidgetType ())
+	{
+	  Object* obj = Object::fromQObject (qObj);
+
+	  if (obj)
+	    {
+	      Matrix bb = obj->properties ().get_boundingbox (false);
+
+	      obj->qWidget<QWidget> ()
+		->setGeometry (xround (bb(0)), xround (bb(1)),
+			       xround (bb(2)), xround (bb(3)));
+	    }
+	}
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Container.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,63 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_Container__
+#define __QtHandles_Container__ 1
+
+#include <QWidget>
+
+#include "GenericEventNotify.h"
+
+#include "graphics.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+DECLARE_GENERICEVENTNOTIFY_SENDER(ContainerBase, QWidget);
+
+class Canvas;
+
+class Container : public ContainerBase
+{
+public:
+  Container (QWidget* parent);
+  ~Container (void);
+
+  Canvas* canvas (const graphics_handle& handle, bool create = true);
+
+protected:
+  void resizeEvent (QResizeEvent* event);
+
+private:
+  Canvas* m_canvas;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ContextMenu.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,153 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QMenu>
+
+#include "Backend.h"
+#include "ContextMenu.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+ContextMenu* ContextMenu::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      QWidget* w = parent->qWidget<QWidget> ();
+
+      return new ContextMenu (go, new QMenu (w));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ContextMenu::ContextMenu (const graphics_object& go, QMenu* menu)
+    : Object (go, menu)
+{
+  uicontextmenu::properties& up = properties<uicontextmenu> ();
+
+  menu->setAutoFillBackground (true);
+
+  connect (menu, SIGNAL (aboutToShow (void)), SLOT (aboutToShow (void)));
+  connect (menu, SIGNAL (aboutToHide (void)), SLOT (aboutToHide (void)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ContextMenu::~ContextMenu (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ContextMenu::update (int pId)
+{
+  uicontextmenu::properties& up = properties<uicontextmenu> ();
+  QMenu* menu = qWidget<QMenu> ();
+
+  switch (pId)
+    {
+    case base_properties::ID_VISIBLE:
+      if (up.is_visible ())
+	{
+	  Matrix pos = up.get_position ().matrix_value ();
+	  QWidget* parentW = menu->parentWidget ();
+	  QPoint pt;
+
+	  pt.rx () = xround (pos(0));
+	  pt.ry () = parentW->height () - xround (pos(1));
+	  pt = parentW->mapToGlobal (pt);
+
+	  menu->popup (pt);
+	}
+      else
+	menu->hide ();
+      break;
+    default:
+      Object::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ContextMenu::aboutToShow (void)
+{
+  gh_manager::post_callback (m_handle, "callback");
+  gh_manager::post_set (m_handle, "visible", "on", false);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ContextMenu::aboutToHide (void)
+{
+  gh_manager::post_set (m_handle, "visible", "off", false);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QWidget* ContextMenu::menu (void)
+{
+  return qWidget<QWidget> ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ContextMenu::executeAt (const base_properties& props, const QPoint& pt)
+{
+  graphics_handle h = props.get_uicontextmenu ();
+
+  if (h.ok ())
+    {
+      graphics_object go = gh_manager::get_object (h);
+
+      if (go.valid_object ())
+	{
+	  ContextMenu* cMenu =
+	    dynamic_cast<ContextMenu*> (Backend::toolkitObject (go));
+
+	  if (cMenu)
+	    {
+	      QMenu* menu = cMenu->qWidget<QMenu> ();
+
+	      if (menu)
+		menu->popup (pt);
+	    }
+	}
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ContextMenu.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,68 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_ContextMenu__
+#define __QtHandles_ContextMenu__ 1
+
+#include <QPoint>
+
+#include "MenuContainer.h"
+#include "Object.h"
+
+class QMenu;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class ContextMenu : public Object, public MenuContainer
+{
+  Q_OBJECT
+
+public:
+  ContextMenu (const graphics_object& go, QMenu* menu);
+  ~ContextMenu (void);
+
+  static ContextMenu* create (const graphics_object& go);
+  static void executeAt (const base_properties& props, const QPoint& pt);
+
+  Container* innerContainer (void) { return 0; }
+
+  QWidget* menu (void);
+
+protected:
+  void update (int pId);
+
+private slots:
+  void aboutToShow (void);
+  void aboutToHide (void);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/EditControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,248 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QLineEdit>
+
+#include "Container.h"
+#include "EditControl.h"
+#include "TextEdit.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+EditControl* EditControl::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      Container* container = parent->innerContainer ();
+
+      if (container)
+	{
+	  uicontrol::properties& up = Utils::properties<uicontrol> (go);
+
+	  if ((up.get_max () - up.get_min ()) > 1)
+	    return new EditControl (go, new TextEdit (container));
+	  else
+	    return new EditControl (go, new QLineEdit (container));
+	}
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+EditControl::EditControl (const graphics_object& go, QLineEdit* edit)
+     : BaseControl (go, edit), m_multiLine (false), m_textChanged (false)
+{
+  init (edit);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void EditControl::init (QLineEdit* edit, bool callBase)
+{
+  if (callBase)
+    BaseControl::init (edit, callBase);
+
+  m_multiLine = false;
+  initCommon (edit);
+
+  uicontrol::properties& up = properties<uicontrol> ();
+
+  edit->setText (Utils::fromStdString (up.get_string_string ()));
+  edit->setAlignment (Utils::fromHVAlign (up.get_horizontalalignment (),
+					  up.get_verticalalignment ()));
+
+  connect (edit, SIGNAL (textEdited (const QString&)),
+	   SLOT (textChanged (void)));
+  connect (edit, SIGNAL (editingFinished (void)),
+	   SLOT (editingFinished (void)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+EditControl::EditControl (const graphics_object& go, TextEdit* edit)
+     : BaseControl (go, edit), m_multiLine (true), m_textChanged (false)
+{
+  init (edit);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void EditControl::init (TextEdit* edit, bool callBase)
+{
+  if (callBase)
+    BaseControl::init (edit, callBase);
+
+  m_multiLine = true;
+  initCommon (edit);
+
+  uicontrol::properties& up = properties<uicontrol> ();
+
+  edit->setAcceptRichText (false);
+  // FIXME: support string_vector
+  edit->setPlainText (Utils::fromStdString (up.get_string_string ()));
+  
+  connect (edit, SIGNAL (textChanged (void)),
+	   SLOT (textChanged (void)));
+  connect (edit, SIGNAL (editingFinished (void)),
+	   SLOT (editingFinished (void)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+EditControl::~EditControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void EditControl::initCommon (QWidget*)
+{
+  m_textChanged = false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void EditControl::update (int pId)
+{
+  bool handled = false;
+
+  if (m_multiLine)
+    handled = updateMultiLine (pId);
+  else
+    handled = updateSingleLine (pId);
+
+  if (! handled)
+    {
+      switch (pId)
+	{
+	default:
+	  BaseControl::update (pId);
+	  break;
+	}
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool EditControl::updateSingleLine (int pId)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+  QLineEdit* edit = qWidget<QLineEdit> ();
+
+  switch (pId)
+    {
+    case uicontrol::properties::ID_STRING:
+      edit->setText (Utils::fromStdString (up.get_string_string ()));
+      return true;
+    case uicontrol::properties::ID_HORIZONTALALIGNMENT:
+    case uicontrol::properties::ID_VERTICALALIGNMENT:
+      edit->setAlignment (Utils::fromHVAlign (up.get_horizontalalignment (),
+					      up.get_verticalalignment ()));
+      return true;
+    case uicontrol::properties::ID_MIN:
+    case uicontrol::properties::ID_MAX:
+      if ((up.get_max () - up.get_min ()) > 1)
+	{
+	  QWidget* container = edit->parentWidget ();
+
+	  delete edit;
+	  init (new TextEdit (container), true);
+	}
+      return true;
+    default:
+      break;
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool EditControl::updateMultiLine (int pId)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+  TextEdit* edit = qWidget<TextEdit> ();
+
+  switch (pId)
+    {
+    case uicontrol::properties::ID_STRING:
+      edit->setPlainText (Utils::fromStdString (up.get_string_string ()));
+      return true;
+    case uicontrol::properties::ID_MIN:
+    case uicontrol::properties::ID_MAX:
+      if ((up.get_max () - up.get_min ()) <= 1)
+	{
+	  QWidget* container = edit->parentWidget ();
+
+	  delete edit;
+	  init (new QLineEdit (container), true);
+	}
+      return true;
+    default:
+      break;
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void EditControl::textChanged (void)
+{
+  m_textChanged = true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void EditControl::editingFinished (void)
+{
+  if (m_textChanged)
+    {
+      QString txt = (m_multiLine
+		     ? qWidget<TextEdit> ()->toPlainText ()
+		     : qWidget<QLineEdit> ()->text ());
+
+      gh_manager::post_set (m_handle, "string", Utils::toStdString (txt), false);
+      gh_manager::post_callback (m_handle, "callback");
+
+      m_textChanged = false;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/EditControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,75 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_EditControl__
+#define __QtHandles_EditControl__ 1
+
+#include "BaseControl.h"
+
+class QLineEdit;
+class QWidget;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class TextEdit;
+
+class EditControl : public BaseControl
+{
+  Q_OBJECT
+
+public:
+  EditControl (const graphics_object& go, QLineEdit* edit);
+  EditControl (const graphics_object& go, TextEdit* edit);
+  ~EditControl (void);
+
+  static EditControl* create (const graphics_object& go);
+
+protected:
+  void update (int pId);
+
+private:
+  void init (QLineEdit* edit, bool callBase = false);
+  void init (TextEdit* edit, bool callBase = false);
+  void initCommon (QWidget* widget);
+  bool updateSingleLine (int pId);
+  bool updateMultiLine (int pId);
+
+private slots:
+  void textChanged (void);
+  void editingFinished (void);
+
+private:
+  bool m_multiLine;
+  bool m_textChanged;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Figure.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,725 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QAction>
+#include <QActionEvent>
+#include <QActionGroup>
+#include <QApplication>
+#include <QEvent>
+#include <QFrame>
+#include <QMainWindow>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QtDebug>
+#include <QTimer>
+#include <QToolBar>
+
+#include "Canvas.h"
+#include "Container.h"
+#include "Figure.h"
+#include "FigureWindow.h"
+#include "MouseModeActionGroup.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define ABOUT_TEXT "<b>QtHandles</b> - a Qt-based toolkit for <a href=\"http://www.octave.org\">Octave</a>.<br><br>Copyright (C) 2011 Michael Goffioul."
+
+//////////////////////////////////////////////////////////////////////////////
+
+DECLARE_GENERICEVENTNOTIFY_SENDER(MenuBar, QMenuBar);
+
+//////////////////////////////////////////////////////////////////////////////
+
+static bool hasUiControlChildren (const figure::properties& fp)
+{
+  Matrix kids = fp.get_all_children ();
+
+  for (int i = 0; i < kids.numel (); i++)
+    {
+      graphics_object go (gh_manager::get_object (kids(i)));
+
+      if (go && (go.isa ("uicontrol") || go.isa ("uipanel")
+		 || go.isa ("uibuttongroup")))
+	return true;
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static bool hasUiMenuChildren (const figure::properties& fp)
+{
+  Matrix kids = fp.get_all_children ();
+
+  for (int i = 0; i < kids.numel (); i++)
+    {
+      graphics_object go (gh_manager::get_object (kids(i)));
+
+      if (go && go.isa ("uimenu"))
+	return true;
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static QRect boundingBoxToRect (const Matrix& bb)
+{
+  QRect r;
+
+  if (bb.numel () == 4)
+    {
+      r = QRect (xround (bb(0)), xround (bb(1)),
+                 xround (bb(2)), xround (bb(3)));
+      if (! r.isValid ())
+        r = QRect ();
+    }
+
+  return r;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Figure* Figure::create (const graphics_object& go)
+{
+  return new Figure (go, new FigureWindow ());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Figure::Figure (const graphics_object& go, FigureWindow* win)
+     : Object (go, win), m_blockUpdates (false), m_mouseMode (NoMode),
+       m_lastMouseMode (NoMode), m_figureToolBar (0), m_menuBar (0),
+       m_innerRect (), m_outerRect ()
+{
+  m_container = new Container (win);
+  win->setCentralWidget (m_container);
+
+  figure::properties& fp = properties<figure> ();
+
+  createFigureToolBarAndMenuBar ();
+
+  int offset = 0;
+  if (fp.toolbar_is ("figure")
+      || (fp.toolbar_is ("auto") && ! hasUiControlChildren (fp)))
+    offset += m_figureToolBar->sizeHint ().height ();
+  else
+    m_figureToolBar->hide ();
+  if (fp.menubar_is ("figure") || hasUiMenuChildren (fp))
+    offset += m_menuBar->sizeHint ().height () + 1;
+  else
+    m_menuBar->hide ();
+
+  m_innerRect = boundingBoxToRect (fp.get_boundingbox (true));
+  m_outerRect = boundingBoxToRect (fp.get_boundingbox (false));
+
+  //qDebug () << "Figure::Figure:" << m_innerRect;
+  win->setGeometry (m_innerRect.adjusted (0, -offset, 0, 0));
+  //qDebug () << "Figure::Figure(adjusted)" << m_innerRect.adjusted (0, -offset, 0, 0);
+  win->setWindowTitle (Utils::fromStdString (fp.get_title ()));
+
+  int eventMask = 0;
+  if (! fp.get_keypressfcn ().is_empty ())
+    eventMask |= Canvas::KeyPress;
+  if (! fp.get_keyreleasefcn ().is_empty ())
+    eventMask |= Canvas::KeyRelease;
+  m_container->canvas (m_handle)->setEventMask (eventMask);
+
+  connect (this, SIGNAL (asyncUpdate (void)),
+           this, SLOT (updateContainer (void)));
+
+  if (fp.is_visible ())
+    QTimer::singleShot (0, win, SLOT (show ()));
+  else
+    win->hide ();
+
+  win->addReceiver (this);
+  m_container->addReceiver (this);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Figure::~Figure (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::createFigureToolBarAndMenuBar (void)
+{
+  QMainWindow* win = qWidget<QMainWindow> ();
+
+  m_figureToolBar = win->addToolBar (tr ("Figure ToolBar"));
+  m_figureToolBar->setMovable (false);
+  m_figureToolBar->setFloatable (false);
+
+  MouseModeActionGroup* mouseModeGroup = new MouseModeActionGroup (win);
+  connect (mouseModeGroup, SIGNAL (modeChanged (MouseMode)),
+	   SLOT (setMouseMode (MouseMode)));
+  m_figureToolBar->addActions (mouseModeGroup->actions ());
+
+  m_menuBar = new MenuBar (win);
+  win->setMenuBar (m_menuBar);
+
+  QMenu* fileMenu = m_menuBar->addMenu (tr ("&File"));
+  fileMenu->menuAction ()->setObjectName ("builtinMenu");
+  fileMenu->addAction (tr ("&New Figure"), this, SLOT (fileNewFigure (void)));
+  fileMenu->addAction (tr ("&Open..."))->setEnabled (false);
+  fileMenu->addSeparator ();
+  fileMenu->addAction (tr ("&Save"))->setEnabled (false);
+  fileMenu->addAction (tr ("Save &As"))->setEnabled (false);
+  fileMenu->addSeparator ();
+  fileMenu->addAction (tr ("&Close Figure"), this,
+		       SLOT (fileCloseFigure (void)), Qt::CTRL|Qt::Key_W);
+
+  QMenu* editMenu = m_menuBar->addMenu (tr ("&Edit"));
+  editMenu->menuAction ()->setObjectName ("builtinMenu");
+  editMenu->addAction (tr ("Cop&y"), this, SLOT (editCopy (void)),
+		       Qt::CTRL|Qt::Key_C)->setEnabled (false);
+  editMenu->addAction (tr ("Cu&t"), this, SLOT (editCut (void)),
+		       Qt::CTRL|Qt::Key_X)->setEnabled (false);
+  editMenu->addAction (tr ("&Paste"), this, SLOT (editPaste(void)),
+		       Qt::CTRL|Qt::Key_V)->setEnabled (false);
+  editMenu->addSeparator ();
+  editMenu->addActions (mouseModeGroup->actions ());
+
+  QMenu* helpMenu = m_menuBar->addMenu (tr ("&Help"));
+  helpMenu->menuAction ()->setObjectName ("builtinMenu");
+  helpMenu->addAction (tr ("&About QtHandles"), this,
+		       SLOT (helpAboutQtHandles (void)));
+  helpMenu->addAction (tr ("About &Qt"), qApp, SLOT (aboutQt (void)));
+
+  m_menuBar->addReceiver (this);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Container* Figure::innerContainer (void)
+{
+  return m_container;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::redraw (void)
+{
+  Canvas* canvas = m_container->canvas (m_handle);
+
+  if (canvas)
+    {
+    canvas->redraw ();
+    //canvas->setMouseMode (RotateMode);
+    }
+
+  foreach (QFrame* frame,
+	   qWidget<QWidget> ()->findChildren<QFrame*> ("UIPanel"))
+    {
+      Object* obj = Object::fromQObject (frame);
+
+      if (obj)
+	obj->slotRedraw ();
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::beingDeleted (void)
+{
+  Canvas* canvas = m_container->canvas (m_handle.value (), false);
+
+  if (canvas)
+    canvas->blockRedraw (true);
+
+  m_menuBar->removeReceiver (this);
+  m_container->removeReceiver (this);
+  qWidget<FigureWindow> ()->removeReceiver (this);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::update (int pId)
+{
+  if (m_blockUpdates)
+    return;
+
+  figure::properties& fp = properties<figure> ();
+  QMainWindow* win = qWidget<QMainWindow> ();
+
+  m_blockUpdates = true;
+
+  switch (pId)
+    {
+    case figure::properties::ID_POSITION:
+	{
+          m_innerRect = boundingBoxToRect (fp.get_boundingbox (true));
+          //qDebug () << "Figure::update(position):" << m_innerRect;
+	  int offset = 0;
+
+          foreach (QToolBar* tb, win->findChildren<QToolBar*> ())
+            if (! tb->isHidden ())
+              offset += tb->sizeHint ().height ();
+	  if (! m_menuBar->isHidden ())
+	    offset += m_menuBar->sizeHint ().height () + 1;
+          //qDebug () << "Figure::update(position)(adjusted):" << m_innerRect.adjusted (0, -offset, 0, 0);
+	  win->setGeometry (m_innerRect.adjusted (0, -offset, 0, 0));
+          //qDebug () << "Figure::update(position): done";
+	}
+      break;
+    case figure::properties::ID_NAME:
+    case figure::properties::ID_NUMBERTITLE:
+      win->setWindowTitle (Utils::fromStdString (fp.get_title ()));
+      break;
+    case figure::properties::ID_VISIBLE:
+      if (fp.is_visible ())
+	QTimer::singleShot (0, win, SLOT (show ()));
+      else
+	win->hide ();
+      break;
+    case figure::properties::ID_TOOLBAR:
+      if (fp.toolbar_is ("none"))
+	showFigureToolBar (false);
+      else if (fp.toolbar_is ("figure"))
+	showFigureToolBar (true);
+      else // "auto"
+	showFigureToolBar (! hasUiControlChildren (fp));
+      break;
+    case figure::properties::ID_MENUBAR:
+      showMenuBar (fp.menubar_is ("figure"));
+      break;
+    case figure::properties::ID_KEYPRESSFCN:
+      if (fp.get_keypressfcn ().is_empty ())
+        m_container->canvas (m_handle)->clearEventMask (Canvas::KeyPress);
+      else
+        m_container->canvas (m_handle)->addEventMask (Canvas::KeyPress);
+      break;
+    case figure::properties::ID_KEYRELEASEFCN:
+      if (fp.get_keyreleasefcn ().is_empty ())
+        m_container->canvas (m_handle)->clearEventMask (Canvas::KeyRelease);
+      else
+        m_container->canvas (m_handle)->addEventMask (Canvas::KeyRelease);
+      break;
+    default:
+      break;
+    }
+
+  m_blockUpdates = false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::showFigureToolBar (bool visible)
+{
+  if ((! m_figureToolBar->isHidden ()) != visible)
+    {
+      int dy = m_figureToolBar->sizeHint ().height ();
+      QRect r = qWidget<QWidget> ()->geometry ();
+
+      if (! visible)
+	r.adjust (0, dy, 0, 0);
+      else
+	r.adjust (0, -dy, 0, 0);
+
+      m_blockUpdates = true;
+      qWidget<QWidget> ()->setGeometry (r);
+      m_figureToolBar->setVisible (visible);
+      m_blockUpdates = false;
+
+      updateBoundingBox (false);
+
+      if (visible)
+	m_mouseMode = m_lastMouseMode;
+      else
+	{
+	  m_lastMouseMode = m_mouseMode;
+	  m_mouseMode = NoMode;
+	}
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::showMenuBar (bool visible)
+{
+  int h1 = m_menuBar->sizeHint ().height ();
+
+  foreach (QAction* a, m_menuBar->actions ())
+    if (a->objectName () == "builtinMenu")
+      a->setVisible (visible);
+
+  int h2 = m_menuBar->sizeHint ().height ();
+
+  if (! visible)
+    visible = hasUiMenuChildren (properties<figure> ());
+
+  if ((! m_menuBar->isHidden ()) != visible)
+    {
+      int dy = qMax (h1, h2) + 1;
+      QRect r = qWidget<QWidget> ()->geometry ();
+
+      //qDebug () << "Figure::showMenuBar:" << r;
+      if (! visible)
+	r.adjust (0, dy, 0, 0);
+      else
+	r.adjust (0, -dy, 0, 0);
+      //qDebug () << "Figure::showMenuBar(adjusted):" << r;
+
+      m_blockUpdates = true;
+      qWidget<QWidget> ()->setGeometry (r);
+      m_menuBar->setVisible (visible);
+      m_blockUpdates = false;
+
+      updateBoundingBox (false);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::updateMenuBar (void)
+{
+  gh_manager::auto_lock lock;
+  graphics_object go = object ();
+
+  if (go.valid_object ())
+    showMenuBar (Utils::properties<figure> (go).menubar_is ("figure"));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QWidget* Figure::menu (void)
+{
+  return qWidget<QMainWindow> ()->menuBar ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+struct UpdateBoundingBoxData
+{
+  Matrix m_bbox;
+  bool m_internal;
+  graphics_handle m_handle;
+  Figure* m_figure;
+};
+
+void Figure::updateBoundingBoxHelper (void* data)
+{
+  gh_manager::auto_lock lock;
+
+  UpdateBoundingBoxData* d = reinterpret_cast<UpdateBoundingBoxData*> (data);
+  graphics_object go = gh_manager::get_object (d->m_handle);
+
+  if (go.valid_object ())
+    {
+      figure::properties& fp = Utils::properties<figure> (go);
+
+      //qDebug ("Figure::updateBoundingBoxHelper: internal=%d, bbox=[%g %g %g %g]",
+      //        d->m_internal, d->m_bbox(0), d->m_bbox(1), d->m_bbox(2), d->m_bbox(3));
+      fp.set_boundingbox (d->m_bbox, d->m_internal, false);
+
+      if (d->m_internal)
+        emit d->m_figure->asyncUpdate ();
+    }
+
+  delete d;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::updateBoundingBox (bool internal, int flags)
+{
+  QWidget* win = qWidget<QWidget> ();
+  Matrix bb (1, 4);
+
+  if (internal)
+    {
+      QRect r = m_innerRect;
+
+      if (flags & UpdateBoundingBoxPosition)
+        r.moveTopLeft (win->mapToGlobal (m_container->pos ()));
+      if (flags & UpdateBoundingBoxSize)
+        r.setSize (m_container->size ());
+
+      if (r.isValid () && r != m_innerRect)
+        {
+          //qDebug() << "inner rect changed:" << m_innerRect << "->>" << r;
+          m_innerRect = r;
+
+          bb(0) = r.x ();
+          bb(1) = r.y ();
+          bb(2) = r.width ();
+          bb(3) = r.height ();
+        }
+      else
+        return;
+    }
+  else
+    {
+      QRect r = m_outerRect;
+
+      if (flags & UpdateBoundingBoxPosition)
+        r.moveTopLeft (win->pos ());
+      if (flags & UpdateBoundingBoxSize)
+        r.setSize (win->frameGeometry ().size ());
+
+      if (r.isValid () && r != m_outerRect )
+        {
+          //qDebug() << "outer rect changed:" << m_outerRect << "->>" << r;
+          m_outerRect = r;
+
+          bb(0) = r.x ();
+          bb(1) = r.y ();
+          bb(2) = r.width ();
+          bb(3) = r.height ();
+        }
+      else
+        return;
+    }
+
+  UpdateBoundingBoxData* d = new UpdateBoundingBoxData ();
+
+  d->m_bbox = bb;
+  d->m_internal = internal;
+  d->m_handle = m_handle;
+  d->m_figure = this;
+
+  //qDebug ("Figure::updateBoundingBox: internal=%d, bbox=[%g %g %g %g]",
+  //        d->m_internal, d->m_bbox(0), d->m_bbox(1), d->m_bbox(2), d->m_bbox(3));
+  gh_manager::post_function (Figure::updateBoundingBoxHelper, d);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool Figure::eventNotifyBefore (QObject* obj, QEvent* event)
+{
+  if (! m_blockUpdates)
+    {
+      if (obj == m_container)
+	{
+          // Do nothing...
+	}
+      else if (obj == m_menuBar)
+	{
+	  switch (event->type ())
+	    {
+	    case QEvent::ActionRemoved:
+		{
+		  QAction* a = dynamic_cast<QActionEvent*> (event)->action ();
+
+		  if (! a->isSeparator ()
+		      && a->objectName () != "builtinMenu")
+                    updateMenuBar ();
+		}
+	      break;
+	    default:
+	      break;
+	    }
+	}
+      else
+	{
+	  switch (event->type ())
+	    {
+	    case QEvent::Close:
+	      event->ignore ();
+	      gh_manager::post_callback (m_handle, "closerequestfcn");
+	      return true;
+	    default:
+	      break;
+	    }
+	}
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::eventNotifyAfter (QObject* watched, QEvent* event)
+{
+  if (! m_blockUpdates)
+    {
+      if (watched == m_container)
+        {
+	  switch (event->type ())
+	    {
+	    case QEvent::Resize:
+	      updateBoundingBox (true, UpdateBoundingBoxSize);
+	      break;
+	    case QEvent::ChildAdded:
+	      if (dynamic_cast<QChildEvent*> (event)->child
+		  ()->isWidgetType())
+		{
+		  gh_manager::auto_lock lock;
+		  const figure::properties& fp = properties<figure> ();
+
+		  showFigureToolBar (! hasUiControlChildren (fp));
+		}
+	    default:
+	      break;
+	    }
+        }
+      else if (watched == m_menuBar)
+        {
+	  switch (event->type ())
+	    {
+	    case QEvent::ActionAdded:
+		{
+		  QAction* a = dynamic_cast<QActionEvent*> (event)->action ();
+
+		  if (! a->isSeparator ()
+                      && a->objectName () != "builtinMenu")
+                    updateMenuBar ();
+		}
+	      break;
+	    default:
+	      break;
+	    }
+        }
+      else
+        {
+	  switch (event->type ())
+	    {
+	    case QEvent::Move:
+	      updateBoundingBox (false, UpdateBoundingBoxPosition);
+	      updateBoundingBox (true, UpdateBoundingBoxPosition);
+	      break;
+	    case QEvent::Resize:
+	      updateBoundingBox (false, UpdateBoundingBoxSize);
+	      break;
+	    default:
+	      break;
+	    }
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::helpAboutQtHandles (void)
+{
+  QMessageBox::about (qWidget<QMainWindow> (), tr ("About QtHandles"),
+		      ABOUT_TEXT);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::fileNewFigure (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::fileCloseFigure (void)
+{
+  qWidget<QMainWindow> ()->close ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::editCopy (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::editCut (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::editPaste (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::addCustomToolBar (QToolBar* bar, bool visible)
+{
+  QMainWindow* win = qWidget<QMainWindow> ();
+
+  if (! visible)
+    win->addToolBar (bar);
+  else
+    {
+      QSize sz = bar->sizeHint ();
+      QRect r = win->geometry ();
+      //qDebug () << "Figure::addCustomToolBar:" << r;
+
+      r.adjust (0, -sz.height (), 0, 0);
+
+      m_blockUpdates = true;
+      win->setGeometry (r);
+      win->addToolBarBreak ();
+      win->addToolBar (bar);
+      m_blockUpdates = false;
+
+      //qDebug () << "Figure::addCustomToolBar:" << win->geometry ();
+      updateBoundingBox (false);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::showCustomToolBar (QToolBar* bar, bool visible)
+{
+  QMainWindow* win = qWidget<QMainWindow> ();
+
+  if ((! bar->isHidden ()) != visible)
+    {
+      QSize sz = bar->sizeHint ();
+      QRect r = win->geometry ();
+
+      if (visible)
+	r.adjust (0, -sz.height (), 0, 0);
+      else
+	r.adjust (0, sz.height (), 0, 0);
+
+      m_blockUpdates = true;
+      win->setGeometry (r);
+      bar->setVisible (visible);
+      m_blockUpdates = false;
+
+      updateBoundingBox (false);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Figure::updateContainer (void)
+{
+  redraw ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Figure.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,133 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_Figure__
+#define __QtHandles_Figure__ 1
+
+#include <QRect>
+
+#include "GenericEventNotify.h"
+#include "MenuContainer.h"
+#include "Object.h"
+
+class QMainWindow;
+class QToolBar;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+enum MouseMode
+{
+  NoMode	= 0,
+  RotateMode	= 1,
+  ZoomMode	= 2,
+  PanMode	= 3,
+  SelectMode	= 4
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Container;
+class FigureWindow;
+class MenuBar;
+class ToolBar;
+
+class Figure :
+  public Object,
+  public MenuContainer,
+  public GenericEventNotifyReceiver
+{
+  Q_OBJECT
+
+  friend class ToolBar;
+
+public:
+  Figure (const graphics_object& go, FigureWindow* win);
+  ~Figure (void);
+
+  static Figure* create (const graphics_object& go);
+
+  MouseMode mouseMode (void) { return m_mouseMode; }
+
+  Container* innerContainer (void);
+  QWidget* menu (void);
+
+  bool eventNotifyBefore (QObject* watched, QEvent* event);
+  void eventNotifyAfter (QObject* watched, QEvent* event);
+
+protected:
+  enum UpdateBoundingBoxFlag
+    {
+      UpdateBoundingBoxPosition = 0x1,
+      UpdateBoundingBoxSize     = 0x2,
+      UpdateBoundingBoxAll      = 0x3
+    };
+
+protected:
+  void redraw (void);
+  void update (int pId);
+  void updateBoundingBox (bool internal = false, int flags = 0);
+  void beingDeleted (void);
+
+private:
+  void createFigureToolBarAndMenuBar (void);
+  void showFigureToolBar (bool visible);
+  void showMenuBar (bool visible);
+  void addCustomToolBar (QToolBar* bar, bool visible);
+  void showCustomToolBar (QToolBar* bar, bool visible);
+
+  static void updateBoundingBoxHelper (void*);
+
+private slots:
+  void setMouseMode (MouseMode mode) { m_mouseMode = mode; }
+  void fileNewFigure (void);
+  void fileCloseFigure (void);
+  void editCopy (void);
+  void editCut (void);
+  void editPaste (void);
+  void helpAboutQtHandles (void);
+  void updateMenuBar (void);
+  void updateContainer (void);
+
+signals:
+  void asyncUpdate (void);
+
+private:
+  Container* m_container;
+  bool m_blockUpdates;
+  MouseMode m_mouseMode, m_lastMouseMode;
+  QToolBar* m_figureToolBar;
+  MenuBar* m_menuBar;
+  QRect m_innerRect;
+  QRect m_outerRect;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/FigureWindow.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,58 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QMenu>
+
+#include "FigureWindow.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+FigureWindow::FigureWindow (QWidget* parent)
+  : FigureWindowBase (parent)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+FigureWindow::~FigureWindow (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QMenu* FigureWindow::createPopupMenu (void)
+{
+  // For the time being, disable menubar/toolbar popup menu
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/FigureWindow.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,55 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_FigureWindow__
+#define __QtHandles_FigureWindow__ 1
+
+#include <QMainWindow>
+
+#include "GenericEventNotify.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+DECLARE_GENERICEVENTNOTIFY_SENDER(FigureWindowBase, QMainWindow);
+
+class FigureWindow : public FigureWindowBase
+{
+  Q_OBJECT
+
+public:
+  FigureWindow (QWidget* parent = 0);
+  ~FigureWindow (void);
+
+  QMenu* createPopupMenu (void);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/GLCanvas.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,174 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gl-render.h"
+#include "graphics.h"
+
+#include "GLCanvas.h"
+#include "gl-select.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+GLCanvas::GLCanvas (QWidget* parent, const graphics_handle& handle)
+  : QGLWidget (parent), Canvas (handle)
+{
+  setFocusPolicy (Qt::ClickFocus);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GLCanvas::~GLCanvas (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void GLCanvas::draw (const graphics_handle& handle)
+{
+  graphics_object go = gh_manager::get_object (handle);
+
+  if (go)
+    {
+      opengl_renderer r;
+
+      r.set_viewport (width (), height ());
+      r.draw(go);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+graphics_object GLCanvas::selectFromAxes (const graphics_object& ax,
+                                          const QPoint& pt)
+{
+  makeCurrent ();
+
+  if (ax)
+    {
+      opengl_selector s;
+
+      s.set_viewport (width (), height ());
+      return s.select (ax, pt.x (), height () - pt.y ());
+    }
+
+  return graphics_object ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+inline void glDrawZoomBox (const QPoint& p1, const QPoint& p2)
+{
+  glVertex2d (p1.x (), p1.y ());
+  glVertex2d (p2.x (), p1.y ());
+  glVertex2d (p2.x (), p2.y ());
+  glVertex2d (p1.x (), p2.y ());
+  glVertex2d (p1.x (), p1.y ());
+}
+
+void GLCanvas::drawZoomBox (const QPoint& p1, const QPoint& p2)
+{
+  glPushMatrix ();
+
+  glMatrixMode (GL_MODELVIEW);
+  glLoadIdentity ();
+
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  glOrtho (0, width (), height (), 0, 1, -1);
+
+  glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT);
+  glDisable (GL_DEPTH_TEST);
+
+  glBegin (GL_POLYGON);
+  glColor4f (0.45, 0.62, 0.81, 0.1);
+  glDrawZoomBox (p1, p2);
+  glEnd ();
+
+  glBegin (GL_LINE_STRIP);
+  glLineWidth (1.5);
+  glColor4f (0.45, 0.62, 0.81, 0.9);
+  glDrawZoomBox (p1, p2);
+  glEnd ();
+
+  glPopAttrib ();
+  glPopMatrix ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void GLCanvas::paintGL (void)
+{
+  canvasPaintEvent ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void GLCanvas::mouseMoveEvent (QMouseEvent* event)
+{
+  canvasMouseMoveEvent (event);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void GLCanvas::mousePressEvent (QMouseEvent* event)
+{
+  canvasMousePressEvent (event);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void GLCanvas::mouseReleaseEvent (QMouseEvent* event)
+{
+  canvasMouseReleaseEvent (event);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void GLCanvas::keyPressEvent (QKeyEvent* event)
+{
+  if (! canvasKeyPressEvent (event))
+    QGLWidget::keyPressEvent (event);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void GLCanvas::keyReleaseEvent (QKeyEvent* event)
+{
+  if (! canvasKeyReleaseEvent (event))
+    QGLWidget::keyReleaseEvent (event);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/GLCanvas.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,65 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_GLCanvas__
+#define __QtHandles_GLCanvas__ 1
+
+#include <QGLWidget>
+
+#include "Canvas.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class GLCanvas : public QGLWidget, public Canvas
+{
+public:
+  GLCanvas (QWidget* parent, const graphics_handle& handle);
+  ~GLCanvas (void);
+
+  void draw (const graphics_handle& handle);
+  void drawZoomBox (const QPoint& p1, const QPoint& p2);
+  void resize (int /* x */, int /* y */,
+	       int /* width */, int /* height */) { }
+  graphics_object selectFromAxes (const graphics_object& ax,
+                                  const QPoint& pt);
+  QWidget* qWidget (void) { return this; }
+
+protected:
+  void paintGL (void);
+  void mouseMoveEvent (QMouseEvent* event);
+  void mousePressEvent (QMouseEvent* event);
+  void mouseReleaseEvent (QMouseEvent* event);
+  void keyPressEvent (QKeyEvent* event);
+  void keyReleaseEvent (QKeyEvent* event);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/GenericEventNotify.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,119 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __GenericEventNotify_h__
+#define __GenericEventNotify_h__ 1
+
+#include <QSet>
+
+class QEvent;
+class QObject;
+class QWidget;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class GenericEventNotifyReceiver;
+
+class GenericEventNotifySender
+{
+public:
+  GenericEventNotifySender (void) : m_receivers () { }
+  virtual ~GenericEventNotifySender (void) { }
+
+  void addReceiver (GenericEventNotifyReceiver* r)
+    { m_receivers.insert (r); }
+
+  void removeReceiver (GenericEventNotifyReceiver* r)
+    { m_receivers.remove (r); }
+
+protected:
+  bool notifyReceiversBefore (QObject* obj, QEvent* evt);
+  void notifyReceiversAfter (QObject* obj, QEvent* evt);
+
+private:
+  QSet<GenericEventNotifyReceiver*> m_receivers;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+class GenericEventNotifyReceiver
+{
+public:
+  GenericEventNotifyReceiver (void) { }
+  virtual ~GenericEventNotifyReceiver (void) { }
+
+  virtual bool eventNotifyBefore (QObject* obj, QEvent* evt) = 0;
+  virtual void eventNotifyAfter (QObject* obj, QEvent* evt) = 0;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+inline
+bool GenericEventNotifySender::notifyReceiversBefore (QObject* obj,
+                                                      QEvent* evt)
+{
+  foreach (GenericEventNotifyReceiver* r, m_receivers)
+    if (r->eventNotifyBefore (obj, evt))
+      return true;
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+inline
+void GenericEventNotifySender::notifyReceiversAfter (QObject* obj,
+                                                     QEvent* evt)
+{
+  foreach (GenericEventNotifyReceiver* r, m_receivers)
+    r->eventNotifyAfter (obj, evt);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define DECLARE_GENERICEVENTNOTIFY_SENDER(T,B) \
+class T : public B, public GenericEventNotifySender \
+{ \
+public: \
+  T (QWidget* parent) : B (parent), GenericEventNotifySender () { } \
+  ~ T (void) { } \
+\
+  bool event (QEvent* evt) \
+    { \
+      bool result = true; \
+      if (! notifyReceiversBefore (this, evt)) \
+        result = B::event (evt); \
+      notifyReceiversAfter (this, evt); \
+      return result; \
+    } \
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/KeyMap.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,267 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QMap>
+#include <Qt>
+
+#include "KeyMap.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace KeyMap
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::string qKeyToKeyString (int key)
+{
+  static QMap<int, std::string> keyMapper;
+
+  if (keyMapper.isEmpty ())
+    {
+      keyMapper[Qt::Key_Escape] = "escape";
+      keyMapper[Qt::Key_Tab] = "tab";
+      keyMapper[Qt::Key_Backtab] = "backtab";
+      keyMapper[Qt::Key_Backspace] = "backspace";
+      keyMapper[Qt::Key_Return] = "return";
+      keyMapper[Qt::Key_Enter] = "enter";
+      keyMapper[Qt::Key_Insert] = "insert";
+      keyMapper[Qt::Key_Delete] = "delete";
+      keyMapper[Qt::Key_Pause] = "pause";
+      keyMapper[Qt::Key_Print] = "print";
+      keyMapper[Qt::Key_SysReq] = "sysreq";
+      keyMapper[Qt::Key_Clear] = "clear";
+      keyMapper[Qt::Key_Home] = "home";
+      keyMapper[Qt::Key_End] = "end";
+      keyMapper[Qt::Key_Left] = "left";
+      keyMapper[Qt::Key_Up] = "up";
+      keyMapper[Qt::Key_Right] = "right";
+      keyMapper[Qt::Key_Down] = "down";
+      keyMapper[Qt::Key_PageUp] = "pageup";
+      keyMapper[Qt::Key_PageDown] = "pagedown";
+      keyMapper[Qt::Key_Shift] = "shift";
+      keyMapper[Qt::Key_Control] = "control";
+      keyMapper[Qt::Key_Meta] = "meta";
+      keyMapper[Qt::Key_Alt] = "alt";
+      keyMapper[Qt::Key_CapsLock] = "capslock";
+      keyMapper[Qt::Key_NumLock] = "numlock";
+      keyMapper[Qt::Key_ScrollLock] = "scrolllock";
+      keyMapper[Qt::Key_F1] = "f1";
+      keyMapper[Qt::Key_F2] = "f2";
+      keyMapper[Qt::Key_F3] = "f3";
+      keyMapper[Qt::Key_F4] = "f4";
+      keyMapper[Qt::Key_F5] = "f5";
+      keyMapper[Qt::Key_F6] = "f6";
+      keyMapper[Qt::Key_F7] = "f7";
+      keyMapper[Qt::Key_F8] = "f8";
+      keyMapper[Qt::Key_F9] = "f9";
+      keyMapper[Qt::Key_F10] = "f10";
+      keyMapper[Qt::Key_F11] = "f11";
+      keyMapper[Qt::Key_F12] = "f12";
+      keyMapper[Qt::Key_F13] = "f13";
+      keyMapper[Qt::Key_F14] = "f14";
+      keyMapper[Qt::Key_F15] = "f15";
+      keyMapper[Qt::Key_F16] = "f16";
+      keyMapper[Qt::Key_F17] = "f17";
+      keyMapper[Qt::Key_F18] = "f18";
+      keyMapper[Qt::Key_F19] = "f19";
+      keyMapper[Qt::Key_F20] = "f20";
+      keyMapper[Qt::Key_F21] = "f21";
+      keyMapper[Qt::Key_F22] = "f22";
+      keyMapper[Qt::Key_F23] = "f23";
+      keyMapper[Qt::Key_F24] = "f24";
+      keyMapper[Qt::Key_F25] = "f25";
+      keyMapper[Qt::Key_F26] = "f26";
+      keyMapper[Qt::Key_F27] = "f27";
+      keyMapper[Qt::Key_F28] = "f28";
+      keyMapper[Qt::Key_F29] = "f29";
+      keyMapper[Qt::Key_F30] = "f30";
+      keyMapper[Qt::Key_F31] = "f31";
+      keyMapper[Qt::Key_F32] = "f32";
+      keyMapper[Qt::Key_F33] = "f33";
+      keyMapper[Qt::Key_F34] = "f34";
+      keyMapper[Qt::Key_F35] = "f35";
+      keyMapper[Qt::Key_Super_L] = "super_l";
+      keyMapper[Qt::Key_Super_R] = "super_r";
+      keyMapper[Qt::Key_Menu] = "menu";
+      keyMapper[Qt::Key_Hyper_L] = "hyper_l";
+      keyMapper[Qt::Key_Hyper_R] = "hyper_r";
+      keyMapper[Qt::Key_Help] = "help";
+      keyMapper[Qt::Key_Direction_L] = "direction_l";
+      keyMapper[Qt::Key_Direction_R] = "direction_r";
+      keyMapper[Qt::Key_Space] = "space";
+      keyMapper[Qt::Key_Any] = "any";
+      keyMapper[Qt::Key_Exclam] = "exclam";
+      keyMapper[Qt::Key_QuoteDbl] = "quotedbl";
+      keyMapper[Qt::Key_NumberSign] = "numbersign";
+      keyMapper[Qt::Key_Dollar] = "dollar";
+      keyMapper[Qt::Key_Percent] = "percent";
+      keyMapper[Qt::Key_Ampersand] = "ampersand";
+      keyMapper[Qt::Key_Apostrophe] = "apostrophe";
+      keyMapper[Qt::Key_ParenLeft] = "parenleft";
+      keyMapper[Qt::Key_ParenRight] = "parenright";
+      keyMapper[Qt::Key_Asterisk] = "asterisk";
+      keyMapper[Qt::Key_Plus] = "plus";
+      keyMapper[Qt::Key_Comma] = "comma";
+      keyMapper[Qt::Key_Minus] = "minus";
+      keyMapper[Qt::Key_Period] = "period";
+      keyMapper[Qt::Key_Slash] = "slash";
+      keyMapper[Qt::Key_0] = "0";
+      keyMapper[Qt::Key_1] = "1";
+      keyMapper[Qt::Key_2] = "2";
+      keyMapper[Qt::Key_3] = "3";
+      keyMapper[Qt::Key_4] = "4";
+      keyMapper[Qt::Key_5] = "5";
+      keyMapper[Qt::Key_6] = "6";
+      keyMapper[Qt::Key_7] = "7";
+      keyMapper[Qt::Key_8] = "8";
+      keyMapper[Qt::Key_9] = "9";
+      keyMapper[Qt::Key_Colon] = "colon";
+      keyMapper[Qt::Key_Semicolon] = "semicolon";
+      keyMapper[Qt::Key_Less] = "less";
+      keyMapper[Qt::Key_Equal] = "equal";
+      keyMapper[Qt::Key_Greater] = "greater";
+      keyMapper[Qt::Key_Question] = "question";
+      keyMapper[Qt::Key_At] = "at";
+      keyMapper[Qt::Key_A] = "a";
+      keyMapper[Qt::Key_B] = "b";
+      keyMapper[Qt::Key_C] = "c";
+      keyMapper[Qt::Key_D] = "d";
+      keyMapper[Qt::Key_E] = "e";
+      keyMapper[Qt::Key_F] = "f";
+      keyMapper[Qt::Key_G] = "g";
+      keyMapper[Qt::Key_H] = "h";
+      keyMapper[Qt::Key_I] = "i";
+      keyMapper[Qt::Key_J] = "j";
+      keyMapper[Qt::Key_K] = "k";
+      keyMapper[Qt::Key_L] = "l";
+      keyMapper[Qt::Key_M] = "m";
+      keyMapper[Qt::Key_N] = "n";
+      keyMapper[Qt::Key_O] = "o";
+      keyMapper[Qt::Key_P] = "p";
+      keyMapper[Qt::Key_Q] = "q";
+      keyMapper[Qt::Key_R] = "r";
+      keyMapper[Qt::Key_S] = "s";
+      keyMapper[Qt::Key_T] = "t";
+      keyMapper[Qt::Key_U] = "u";
+      keyMapper[Qt::Key_V] = "v";
+      keyMapper[Qt::Key_W] = "w";
+      keyMapper[Qt::Key_X] = "x";
+      keyMapper[Qt::Key_Y] = "y";
+      keyMapper[Qt::Key_Z] = "z";
+      keyMapper[Qt::Key_BracketLeft] = "bracketleft";
+      keyMapper[Qt::Key_Backslash] = "backslash";
+      keyMapper[Qt::Key_BracketRight] = "bracketright";
+      keyMapper[Qt::Key_AsciiCircum] = "asciicircum";
+      keyMapper[Qt::Key_Underscore] = "underscore";
+      keyMapper[Qt::Key_QuoteLeft] = "quoteleft";
+      keyMapper[Qt::Key_BraceLeft] = "braceleft";
+      keyMapper[Qt::Key_Bar] = "bar";
+      keyMapper[Qt::Key_BraceRight] = "braceright";
+      keyMapper[Qt::Key_AsciiTilde] = "asciitilde";
+
+      keyMapper[Qt::Key_nobreakspace] = "nobreakspace";
+      keyMapper[Qt::Key_exclamdown] = "exclamdown";
+      keyMapper[Qt::Key_cent] = "cent";
+      keyMapper[Qt::Key_sterling] = "sterling";
+      keyMapper[Qt::Key_currency] = "currency";
+      keyMapper[Qt::Key_yen] = "yen";
+      keyMapper[Qt::Key_brokenbar] = "brokenbar";
+      keyMapper[Qt::Key_section] = "section";
+      keyMapper[Qt::Key_diaeresis] = "diaeresis";
+      keyMapper[Qt::Key_copyright] = "copyright";
+      keyMapper[Qt::Key_ordfeminine] = "ordfeminine";
+      keyMapper[Qt::Key_guillemotleft] = "guillemotleft";
+      keyMapper[Qt::Key_notsign] = "notsign";
+      keyMapper[Qt::Key_hyphen] = "hyphen";
+      keyMapper[Qt::Key_registered] = "registered";
+      keyMapper[Qt::Key_macron] = "macron";
+      keyMapper[Qt::Key_degree] = "degree";
+      keyMapper[Qt::Key_plusminus] = "plusminus";
+      keyMapper[Qt::Key_twosuperior] = "twosuperior";
+      keyMapper[Qt::Key_threesuperior] = "threesuperior";
+      keyMapper[Qt::Key_acute] = "acute";
+      keyMapper[Qt::Key_mu] = "mu";
+      keyMapper[Qt::Key_paragraph] = "paragraph";
+      keyMapper[Qt::Key_periodcentered] = "periodcentered";
+      keyMapper[Qt::Key_cedilla] = "cedilla";
+      keyMapper[Qt::Key_onesuperior] = "onesuperior";
+      keyMapper[Qt::Key_masculine] = "masculine";
+      keyMapper[Qt::Key_guillemotright] = "guillemotright";
+      keyMapper[Qt::Key_onequarter] = "onequarter";
+      keyMapper[Qt::Key_onehalf] = "onehalf";
+      keyMapper[Qt::Key_threequarters] = "threequarters";
+      keyMapper[Qt::Key_questiondown] = "questiondown";
+      keyMapper[Qt::Key_Agrave] = "agrave";
+      keyMapper[Qt::Key_Aacute] = "aacute";
+      keyMapper[Qt::Key_Acircumflex] = "acircumflex";
+      keyMapper[Qt::Key_Atilde] = "atilde";
+      keyMapper[Qt::Key_Adiaeresis] = "adiaeresis";
+      keyMapper[Qt::Key_Aring] = "aring";
+      keyMapper[Qt::Key_AE] = "ae";
+      keyMapper[Qt::Key_Ccedilla] = "ccedilla";
+      keyMapper[Qt::Key_Egrave] = "egrave";
+      keyMapper[Qt::Key_Eacute] = "eacute";
+      keyMapper[Qt::Key_Ecircumflex] = "ecircumflex";
+      keyMapper[Qt::Key_Ediaeresis] = "ediaeresis";
+      keyMapper[Qt::Key_Igrave] = "igrave";
+      keyMapper[Qt::Key_Iacute] = "iacute";
+      keyMapper[Qt::Key_Icircumflex] = "icircumflex";
+      keyMapper[Qt::Key_Idiaeresis] = "idiaeresis";
+      keyMapper[Qt::Key_ETH] = "eth";
+      keyMapper[Qt::Key_Ntilde] = "ntilde";
+      keyMapper[Qt::Key_Ograve] = "ograve";
+      keyMapper[Qt::Key_Oacute] = "oacute";
+      keyMapper[Qt::Key_Ocircumflex] = "ocircumflex";
+      keyMapper[Qt::Key_Otilde] = "otilde";
+      keyMapper[Qt::Key_Odiaeresis] = "odiaeresis";
+      keyMapper[Qt::Key_multiply] = "multiply";
+      keyMapper[Qt::Key_Ooblique] = "ooblique";
+      keyMapper[Qt::Key_Ugrave] = "ugrave";
+      keyMapper[Qt::Key_Uacute] = "uacute";
+      keyMapper[Qt::Key_Ucircumflex] = "ucircumflex";
+      keyMapper[Qt::Key_Udiaeresis] = "udiaeresis";
+      keyMapper[Qt::Key_Yacute] = "yacute";
+      keyMapper[Qt::Key_THORN] = "thorn";
+      keyMapper[Qt::Key_ssharp] = "ssharp";
+      keyMapper[Qt::Key_division] = "division";
+      keyMapper[Qt::Key_ydiaeresis] = "ydiaeresis";
+    }
+
+  return keyMapper.value (key, std::string ("<unknown key>"));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; //namespace KeyMap
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/KeyMap.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,49 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles__KeyMap__
+#define __QtHandles__KeyMap__ 1
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace KeyMap
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::string qKeyToKeyString (int key);
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace KeyMap
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ListBoxControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,185 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QListWidget>
+
+#include "Container.h"
+#include "ListBoxControl.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void updateSelection (QListWidget* list, const Matrix& value)
+{
+  octave_idx_type n = value.numel ();
+  int lc = list->count ();
+
+  list->clearSelection ();
+
+  for (octave_idx_type i = 0; i < n; i++)
+    {
+      int idx = xround (value(i));
+
+      if (1 <= idx && idx <= lc)
+        {
+          list->item (idx-1)->setSelected (true);
+          if (i == 0
+              && list->selectionMode () == QAbstractItemView::SingleSelection)
+            break;
+        }
+      else
+        {
+          // Invalid selection.
+          list->clearSelection ();
+          break;
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ListBoxControl* ListBoxControl::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      Container* container = parent->innerContainer ();
+
+      if (container)
+	return new ListBoxControl (go, new QListWidget (container));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ListBoxControl::ListBoxControl (const graphics_object& go, QListWidget* list)
+     : BaseControl (go, list), m_blockCallback (false)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+
+  list->addItems (Utils::fromStringVector (up.get_string_vector ()));
+  if ((up.get_max () - up.get_min ()) > 1)
+    list->setSelectionMode (QAbstractItemView::ExtendedSelection);
+  else
+    list->setSelectionMode (QAbstractItemView::SingleSelection);
+  Matrix value = up.get_value ().matrix_value ();
+  if (value.numel () > 0)
+    {
+      octave_idx_type n = value.numel ();
+      int lc = list->count ();
+
+      for (octave_idx_type i = 0; i < n; i++)
+	{
+	  int idx = xround (value(i));
+
+	  if (1 <= idx && idx <= lc)
+	    {
+	      list->item (idx-1)->setSelected (true);
+	      if (i == 0
+		  && list->selectionMode () ==
+		  	QAbstractItemView::SingleSelection)
+		break;
+	    }
+	}
+    }
+
+  list->removeEventFilter (this);
+  list->viewport ()->installEventFilter (this);
+
+  connect (list, SIGNAL (itemSelectionChanged (void)),
+	   SLOT (itemSelectionChanged (void)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ListBoxControl::~ListBoxControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ListBoxControl::update (int pId)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+  QListWidget* list = qWidget<QListWidget> ();
+
+  switch (pId)
+    {
+    case uicontrol::properties::ID_STRING:
+      m_blockCallback = true;
+      list->clear ();
+      list->addItems (Utils::fromStringVector (up.get_string_vector ()));
+      updateSelection (list, up.get_value ().matrix_value ());
+      m_blockCallback = false;
+      break;
+    case uicontrol::properties::ID_MIN:
+    case uicontrol::properties::ID_MAX:
+      if ((up.get_max () - up.get_min ()) > 1)
+	list->setSelectionMode (QAbstractItemView::ExtendedSelection);
+      else
+	list->setSelectionMode (QAbstractItemView::SingleSelection);
+      break;
+    case uicontrol::properties::ID_VALUE:
+      m_blockCallback = true;
+      updateSelection (list, up.get_value ().matrix_value ());
+      m_blockCallback = false;
+      break;
+    default:
+      BaseControl::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ListBoxControl::itemSelectionChanged (void)
+{
+  if (! m_blockCallback)
+    {
+      QListWidget* list = qWidget<QListWidget> ();
+
+      QModelIndexList l = list->selectionModel ()->selectedIndexes ();
+      Matrix value (dim_vector (1, l.size ()));
+      int i = 0;
+
+      foreach (const QModelIndex& idx, l)
+       value(i++) = (idx.row () + 1);
+
+      gh_manager::post_set (m_handle, "value", octave_value (value), false);
+      gh_manager::post_callback (m_handle, "callback");
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ListBoxControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,62 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_ListBoxControl__
+#define __QtHandles_ListBoxControl__ 1
+
+#include "BaseControl.h"
+
+class QListWidget;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class ListBoxControl : public BaseControl
+{
+  Q_OBJECT
+
+public:
+  ListBoxControl (const graphics_object& go, QListWidget* list);
+  ~ListBoxControl (void);
+
+  static ListBoxControl* create (const graphics_object& go);
+
+protected:
+  void update (int pId);
+
+private slots:
+  void itemSelectionChanged (void);
+
+private:
+  bool m_blockCallback;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Logger.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,101 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QMutex>
+#include <QMutexLocker>
+#include <QProcessEnvironment>
+
+#include <cstdio>
+
+#include "Logger.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+Logger* Logger::s_instance = 0;
+QMutex* Logger::s_mutex = 0;
+
+//////////////////////////////////////////////////////////////////////////////
+
+Logger::Logger (void)
+    : m_debugEnabled (false)
+{
+  QProcessEnvironment pe (QProcessEnvironment::systemEnvironment ());
+
+  if (pe.value ("QTHANDLES_DEBUG", "0") != "0")
+    m_debugEnabled = true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Logger::~Logger (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Logger* Logger::instance (void)
+{
+  if (! s_instance)
+    {
+      s_instance = new Logger ();
+      s_mutex = new QMutex ();
+    }
+
+  return s_instance;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define STATIC_LOGGER(fun) \
+void Logger::fun (const char* fmt, ...) \
+{ \
+  QMutexLocker lock (s_mutex); \
+  va_list vl; \
+  va_start (vl, fmt); \
+  instance ()->fun ## V (fmt, vl); \
+  va_end (vl); \
+}
+
+STATIC_LOGGER (debug)
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Logger::debugV (const char* fmt, va_list arg)
+{
+  if (m_debugEnabled)
+    {
+      vfprintf (stderr, fmt, arg);
+      fprintf (stderr, "\n");
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Logger.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,62 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_Logger__
+#define __QtHandles_Logger__ 1
+
+#include <cstdarg>
+
+class QMutex;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Logger
+{
+public:
+  static void debug (const char* fmt, ...);
+
+private:
+  bool m_debugEnabled;
+
+  static Logger* s_instance;
+  static QMutex* s_mutex;
+
+private:
+  Logger (void);
+  ~Logger (void);
+
+  static Logger* instance (void);
+
+  void debugV (const char* fmt, va_list arg);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Menu.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,328 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QAction>
+#include <QMainWindow>
+#include <QMenu>
+#include <QMenuBar>
+
+#include "Figure.h"
+#include "Menu.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+static QKeySequence accelSequence (const uimenu::properties& up)
+{
+  std::string s (up.get_accelerator ());
+
+  if (! s.empty ())
+    {
+      char c = s[0];
+      int keyMod = Qt::CTRL;
+
+      if (c >= 'A' && c <= 'Z')
+	keyMod |= Qt::SHIFT;
+      if (c >= 'a' && c <= 'z')
+	c -= ('a' - 'A');
+      if (c >= 'A' && c <= 'Z')
+	return QKeySequence (keyMod | static_cast<int> (c));
+    }
+
+  return QKeySequence ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Menu* Menu::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      QObject* qObj = parent->qObject ();
+
+      if (qObj)
+	return new Menu (go, new QAction (qObj), parent);
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Menu::Menu (const graphics_object& go, QAction* action, Object* parent)
+    : Object (go, action), m_parent (0), m_separator (0)
+{
+  uimenu::properties& up = properties<uimenu> ();
+
+  action->setText (Utils::fromStdString (up.get_label ()));
+  if (up.is_checked ())
+    {
+      action->setCheckable (true);
+      action->setChecked (up.is_checked ());
+    }
+  action->setEnabled (up.is_enable ());
+  action->setShortcut (accelSequence (up));
+  action->setVisible (up.is_visible ());
+  if (up.is_separator ())
+    {
+      m_separator = new QAction (action);
+      m_separator->setSeparator (true);
+      m_separator->setVisible (up.is_visible ());
+    }
+
+  MenuContainer* menuContainer = dynamic_cast<MenuContainer*> (parent);
+
+  if (menuContainer)
+    m_parent = menuContainer->menu ();
+
+  if (m_parent)
+    {
+      int pos = static_cast<int> (up.get_position ());
+
+      if (pos <= 0)
+	{
+	  if (m_separator)
+	    m_parent->insertAction (0, m_separator);
+	  m_parent->insertAction (0, action);
+
+	  int count = 0;
+
+	  foreach (QAction* a, m_parent->actions ())
+	    if (! a->isSeparator () && a->objectName () != "builtinMenu")
+	      count++;
+	  up.get_property ("position").set
+	    (octave_value (static_cast<double> (count)), true, false);
+	}
+      else
+	{
+
+	  int count = 0;
+	  QAction* before = 0;
+
+	  foreach (QAction* a, m_parent->actions ())
+	    if (! a->isSeparator () && a->objectName () != "builtinMenu")
+	      {
+		count++;
+		if (pos <= count)
+		  {
+		    before = a;
+		    break;
+		  }
+	      }
+
+	  if (m_separator)
+	    m_parent->insertAction (before, m_separator);
+	  m_parent->insertAction (before, action);
+
+	  if (before)
+	    updateSiblingPositions ();
+	  else
+	    up.get_property ("position").set
+	      (octave_value (static_cast<double> (count+1)), true, false);
+	}
+    }
+
+  connect (action, SIGNAL (triggered (bool)), SLOT (actionTriggered (void)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Menu::~Menu (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Menu::update (int pId)
+{
+  uimenu::properties& up = properties<uimenu> ();
+  QAction* action = qWidget<QAction> ();
+
+  switch (pId)
+    {
+    case uimenu::properties::ID_LABEL:
+      action->setText (Utils::fromStdString (up.get_label ()));
+      break;
+    case uimenu::properties::ID_CHECKED:
+      if (up.is_checked ())
+	{
+	  action->setCheckable (true);
+	  action->setChecked (up.is_checked ());
+	}
+      else
+	{
+	  action->setChecked (false);
+	  action->setCheckable (false);
+	}
+      break;
+    case uimenu::properties::ID_ENABLE:
+      action->setEnabled (up.is_enable ());
+      break;
+    case uimenu::properties::ID_ACCELERATOR:
+      if (! action->menu ())
+	action->setShortcut (accelSequence (up));
+      break;
+    case uimenu::properties::ID_SEPARATOR:
+      if (up.is_separator ())
+	{
+	  if (! m_separator)
+	    {
+	      m_separator = new QAction (action);
+	      m_separator->setSeparator (true);
+	      m_separator->setVisible (up.is_visible ());
+	      if (m_parent)
+		m_parent->insertAction (action, m_separator);
+	    }
+	}
+      else
+	{
+	  if (m_separator)
+	    delete m_separator;
+	  m_separator = 0;
+	}
+      break;
+    case uimenu::properties::ID_VISIBLE:
+      action->setVisible (up.is_visible ());
+      if (m_separator)
+	m_separator->setVisible (up.is_visible ());
+      break;
+    case uimenu::properties::ID_POSITION:
+      if (m_separator)
+	m_parent->removeAction (m_separator);
+      m_parent->removeAction (action);
+	{
+	  int pos = static_cast<int> (up.get_position ());
+	  QAction* before = 0;
+
+	  if (pos > 0)
+	    {
+	      int count = 0;
+
+	      foreach (QAction* a, m_parent->actions ())
+		if (! a->isSeparator () && a->objectName () != "builtinMenu")
+		  {
+		    count++;
+		    if (pos <= count)
+		      {
+			before = a;
+			break;
+		      }
+		  }
+	    }
+
+	  if (m_separator)
+	    m_parent->insertAction (before, m_separator);
+	  m_parent->insertAction (before, action);
+	  updateSiblingPositions ();
+	}
+      break;
+    default:
+      Object::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QWidget* Menu::menu (void)
+{
+  QAction* action = qWidget<QAction> ();
+  QMenu* _menu = action->menu ();
+
+  if (! _menu)
+    {
+      _menu = new QMenu (action->parentWidget ());
+      action->setMenu (_menu);
+      action->setShortcut (QKeySequence ());
+      connect (_menu, SIGNAL (aboutToShow (void)),
+	       this, SLOT (actionHovered (void)));
+    }
+
+  return _menu;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Menu::actionTriggered (void)
+{
+  QAction* action = qWidget<QAction> ();
+
+  if (action->isCheckable ())
+    action->setChecked (! action->isChecked ());
+  gh_manager::post_callback (m_handle, "callback");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Menu::actionHovered (void)
+{
+  gh_manager::post_callback (m_handle, "callback");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Menu::updateSiblingPositions (void)
+{
+  if (m_parent)
+    {
+      double count = 1.0;
+
+      foreach (QAction* a, m_parent->actions ())
+	{
+	  if (! a->isSeparator () && a->objectName () != "builtinMenu")
+	    {
+	      Object* aObj = Object::fromQObject (a);
+
+	      if (aObj)
+		{
+		  graphics_object go = aObj->object ();
+
+		  // Probably overkill as a uimenu child can only be another
+		  // uimenu object.
+		  if (go.isa ("uimenu"))
+		    {
+		      uimenu::properties& up = Utils::properties<uimenu> (go);
+
+		      up.get_property ("position").set
+			(octave_value (count), true, false);
+		    }
+		}
+
+	      count++;
+	    }
+	}
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Menu.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,74 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_Menu__
+#define __QtHandles_Menu__ 1
+
+#include "MenuContainer.h"
+#include "Object.h"
+
+class QAction;
+class QMenu;
+class QWidget;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Menu : public Object, public MenuContainer
+{
+  Q_OBJECT
+
+public:
+  Menu (const graphics_object& go, QAction* action, Object* parent);
+  ~Menu (void);
+
+  static Menu* create (const graphics_object& go);
+
+  Container* innerContainer (void) { return 0; }
+
+  QWidget* menu (void);
+
+protected:
+  void update (int pId);
+
+private slots:
+  void actionTriggered (void);
+  void actionHovered (void);
+
+private:
+  void updateSiblingPositions (void);
+
+private:
+  QWidget* m_parent;
+  QAction* m_separator;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/MenuContainer.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,46 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_MenuContainer__
+#define __QtHandles_MenuContainer__ 1
+
+class QWidget;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class MenuContainer
+{
+public:
+  virtual QWidget* menu (void) = 0;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/MouseModeActionGroup.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,104 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QAction>
+#include <QIcon>
+
+#include "Figure.h"
+#include "MouseModeActionGroup.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+MouseModeActionGroup::MouseModeActionGroup (QObject* parent)
+  : QObject (parent), m_current (0)
+{
+  m_actions.append (new QAction (QIcon (":/images/rotate.png"),
+				 tr ("Rotate"), this));
+  m_actions.append (new QAction (QIcon (":/images/zoom.png"),
+				 tr ("Zoom"), this));
+  m_actions.append (new QAction (QIcon (":/images/pan.png"),
+				 tr ("Pan"), this));
+  m_actions.append (new QAction (QIcon (":/images/select.png"),
+				 tr ("Select"), this));
+  m_actions[2]->setEnabled (false);
+  m_actions[3]->setEnabled (false);
+
+  foreach (QAction* a, m_actions)
+    {
+      a->setCheckable (true);
+      connect (a, SIGNAL (toggled (bool)), this, SLOT (actionToggled (bool)));
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+MouseModeActionGroup::~MouseModeActionGroup (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void MouseModeActionGroup::actionToggled (bool checked)
+{
+  if (! checked)
+    {
+      if (sender () == m_current)
+	{
+	  m_current = 0;
+	  emit modeChanged (NoMode);
+	}
+    }
+  else
+    {
+      int i = m_actions.indexOf (qobject_cast<QAction*> (sender ()));
+
+      if (i >= 0)
+	{
+	  m_current = m_actions[i];
+	  for (int j = 0; j < m_actions.size (); j++)
+	    if (j != i)
+	      m_actions[j]->setChecked (false);
+	  emit modeChanged (static_cast<MouseMode> (i+1));
+	}
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+MouseMode MouseModeActionGroup::mouseMode (void) const
+{
+  int i = (m_current ? -1 : m_actions.indexOf (m_current));
+
+  return static_cast<MouseMode> (i+1);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/MouseModeActionGroup.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,67 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_MouseModeActionGroup__
+#define __QtHandles_MouseModeActionGroup__ 1
+
+#include <QList>
+#include <QObject>
+
+#include "Figure.h"
+
+class QAction;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class MouseModeActionGroup : public QObject
+{
+  Q_OBJECT
+
+public:
+  MouseModeActionGroup (QObject* parent = 0);
+  ~MouseModeActionGroup (void);
+
+  QList<QAction*> actions (void) const { return m_actions; }
+  MouseMode mouseMode (void) const;
+
+signals:
+  void modeChanged (MouseMode mode);
+
+private slots:
+  void actionToggled (bool checked);
+
+private:
+  QList<QAction*> m_actions;
+  QAction* m_current;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Object.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,193 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QVariant>
+
+#include "Backend.h"
+#include "Object.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+Object::Object (const graphics_object& go, QObject* obj)
+  : QObject (), m_handle (go.get_handle ()), m_qobject (0)
+{
+  gh_manager::auto_lock lock (false);
+
+  if (! lock)
+    qCritical ("QtHandles::Object::Object: "
+	       "creating Object (h=%g) without a valid lock!!!",
+	       m_handle.value ());
+
+  init (obj);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Object::init (QObject* obj, bool)
+{
+  if (m_qobject)
+    qCritical ("QtHandles::Object::init: "
+	       "resetting QObject while in invalid state");
+
+  m_qobject = obj;
+
+  if (m_qobject)
+    {
+      m_qobject->setProperty ("QtHandles::Object",
+			      qVariantFromValue<void*> (this));
+      connect (m_qobject, SIGNAL (destroyed (QObject*)),
+	       SLOT (objectDestroyed (QObject*)));
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Object::~Object (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+graphics_object Object::object (void) const
+{
+  gh_manager::auto_lock lock (false);
+
+  if (! lock)
+    qCritical ("QtHandles::Object::object: "
+	       "accessing graphics object (h=%g) without a valid lock!!!",
+	       m_handle.value ());
+
+  return gh_manager::get_object (m_handle);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Object::slotUpdate (int pId)
+{
+  gh_manager::auto_lock lock;
+
+  switch (pId)
+    {
+    // Special case for objects being deleted, as it's very likely
+    // that the graphics_object already has been destroyed when this
+    // is executed (because of the async behavior).
+    case base_properties::ID_BEINGDELETED:
+      beingDeleted ();
+      break;
+    default:
+      if (object ().valid_object ())
+	update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Object::slotFinalize (void)
+{
+  gh_manager::auto_lock lock;
+
+  finalize ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Object::slotRedraw (void)
+{
+  gh_manager::auto_lock lock;
+
+  if (object ().valid_object ())
+    redraw ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Object::update (int /* pId */)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Object::finalize (void)
+{
+  if (m_qobject)
+    {
+      delete m_qobject;
+      m_qobject = 0;
+    }
+  deleteLater ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Object::redraw (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Object::beingDeleted (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Object::objectDestroyed (QObject* obj)
+{
+  if (obj && obj == m_qobject)
+    m_qobject = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Object* Object::parentObject (const graphics_object& go)
+{
+  Object* parent = Backend::toolkitObject
+    (gh_manager::get_object (go.get_parent ()));
+
+  return parent;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Object* Object::fromQObject (QObject* obj)
+{
+  QVariant v = obj->property ("QtHandles::Object");
+
+  if (v.isValid ())
+    return reinterpret_cast<Object*> (qVariantValue<void*> (v));
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Object.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,110 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_Object__
+#define __QtHandles_Object__ 1
+
+#include <QObject>
+
+#include "graphics.h"
+
+class QObject;
+class QWidget;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Container;
+class ObjectProxy;
+
+class Object : public QObject
+{
+  Q_OBJECT
+
+public:
+  Object (const graphics_object& go, QObject* obj = 0);
+
+  virtual ~Object (void);
+
+  base_properties& properties (void)
+    { return object ().get_properties (); }
+  
+  const base_properties& properties (void) const
+    { return object ().get_properties (); }
+
+  template <class T>
+  typename T::properties& properties (void)
+    {
+      return dynamic_cast<typename T::properties&>
+	(object ().get_properties ());
+    }
+  
+  template <class T>
+  const typename T::properties& properties (void) const
+    {
+      return dynamic_cast<const typename T::properties&>
+	(object ().get_properties ());
+    }
+
+  graphics_object object (void) const;
+
+  virtual QObject* qObject (void) { return m_qobject; }
+
+  template <class T>
+  T* qWidget (void) { return qobject_cast<T*>(qObject ()); }
+
+  virtual Container* innerContainer (void) = 0;
+
+  static Object* fromQObject (QObject* obj);
+
+public slots:
+  void slotUpdate (int pId);
+  void slotFinalize (void);
+  void slotRedraw (void);
+
+  void objectDestroyed (QObject *obj = 0);
+
+protected:
+  static Object* parentObject (const graphics_object& go);
+  void init (QObject* obj, bool callBase = false);
+
+  virtual void update (int pId);
+  virtual void finalize (void);
+  virtual void redraw (void);
+
+  virtual void beingDeleted (void);
+
+protected:
+  graphics_handle m_handle;
+  QObject* m_qobject;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ObjectFactory.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,156 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QApplication>
+#include <QThread>
+
+#include "graphics.h"
+
+#include "Backend.h"
+#include "CheckBoxControl.h"
+#include "ContextMenu.h"
+#include "EditControl.h"
+#include "Figure.h"
+#include "ListBoxControl.h"
+#include "Logger.h"
+#include "Menu.h"
+#include "ObjectFactory.h"
+#include "ObjectProxy.h"
+#include "Panel.h"
+#include "PopupMenuControl.h"
+#include "PushButtonControl.h"
+#include "PushTool.h"
+#include "RadioButtonControl.h"
+#include "SliderControl.h"
+#include "TextControl.h"
+#include "ToggleButtonControl.h"
+#include "ToggleTool.h"
+#include "ToolBar.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+ObjectFactory* ObjectFactory::instance (void)
+{
+  static ObjectFactory s_instance;
+  static bool s_instanceCreated = false;
+
+  if (! s_instanceCreated)
+    {
+      if (QThread::currentThread () != QApplication::instance ()->thread ())
+	s_instance.moveToThread (QApplication::instance ()->thread ());
+      s_instanceCreated = true;
+    }
+
+  return &s_instance;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ObjectFactory::createObject (double handle)
+{
+  gh_manager::auto_lock lock;
+
+  graphics_object go (gh_manager::get_object (graphics_handle (handle)));
+
+  if (go.valid_object ())
+    {
+      if (go.get_properties ().is_beingdeleted ())
+	qWarning ("ObjectFactory::createObject: object is being deleted");
+      else
+	{
+	  ObjectProxy* proxy = Backend::toolkitObjectProxy (go);
+
+	  if (proxy)
+	    {
+	      Logger::debug ("ObjectFactory::createObject: "
+			     "create %s from thread %08x",
+			     go.type ().c_str (), QThread::currentThreadId ());
+
+	      Object* obj = 0;
+
+	      if (go.isa ("figure"))
+		obj = Figure::create (go);
+	      else if (go.isa ("uicontrol"))
+		{
+		  uicontrol::properties& up =
+		   Utils::properties<uicontrol> (go);
+
+		  if (up.style_is ("pushbutton"))
+		    obj = PushButtonControl::create (go);
+		  else if (up.style_is ("edit"))
+		    obj = EditControl::create (go);
+		  else if (up.style_is ("checkbox"))
+		    obj = CheckBoxControl::create (go);
+		  else if (up.style_is ("radiobutton"))
+		    obj = RadioButtonControl::create (go);
+		  else if (up.style_is ("togglebutton"))
+		    obj = ToggleButtonControl::create (go);
+		  else if (up.style_is ("text"))
+		    obj = TextControl::create (go);
+		  else if (up.style_is ("popupmenu"))
+		    obj = PopupMenuControl::create (go);
+		  else if (up.style_is ("slider"))
+		    obj = SliderControl::create (go);
+		  else if (up.style_is ("listbox"))
+		    obj = ListBoxControl::create (go);
+		}
+	      else if (go.isa ("uipanel"))
+		obj = Panel::create (go);
+	      else if (go.isa ("uimenu"))
+		obj = Menu::create (go);
+	      else if (go.isa ("uicontextmenu"))
+		obj = ContextMenu::create (go);
+	      else if (go.isa ("uitoolbar"))
+		obj = ToolBar::create (go);
+	      else if (go.isa ("uipushtool"))
+		obj = PushTool::create (go);
+	      else if (go.isa ("uitoggletool"))
+		obj = ToggleTool::create (go);
+	      else
+		qWarning ("ObjectFactory::createObject: unsupported type `%s'",
+			  go.type ().c_str ());
+
+	      if (obj)
+		proxy->setObject (obj);
+	    }
+	  else
+	    qWarning ("ObjectFactory::createObject: no proxy for handle %g",
+		      handle);
+	}
+    }
+  else
+    qWarning ("ObjectFactory::createObject: invalid object for handle %g",
+	      handle);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ObjectFactory.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,60 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_ObjectFactory__
+#define __QtHandles_ObjectFactory__ 1
+
+#include <QObject>
+
+class graphics_object;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Object;
+
+class ObjectFactory : public QObject
+{
+  Q_OBJECT
+
+public:
+  static ObjectFactory* instance (void);
+
+public slots:
+  void createObject (double handle);
+
+private:
+  ObjectFactory (void)
+    : QObject ()
+    { }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ObjectProxy.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,109 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "oct-mutex.h"
+
+#include "Object.h"
+#include "ObjectProxy.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+ObjectProxy::ObjectProxy (Object* obj)
+  : QObject (), m_object (0)
+{
+  init (obj);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ObjectProxy::init (Object* obj)
+{
+  if (obj != m_object)
+    {
+      if (m_object)
+	{
+	  disconnect (this, SIGNAL (sendUpdate (int)),
+		      m_object, SLOT (slotUpdate (int)));
+	  disconnect (this, SIGNAL (sendFinalize (void)),
+		      m_object, SLOT (slotFinalize (void)));
+	  disconnect (this, SIGNAL (sendRedraw (void)),
+		      m_object, SLOT (slotRedraw (void)));
+	}
+
+      m_object = obj;
+
+      if (m_object)
+	{
+	  connect (this, SIGNAL (sendUpdate (int)),
+		   m_object, SLOT (slotUpdate (int)));
+	  connect (this, SIGNAL (sendFinalize (void)),
+		   m_object, SLOT (slotFinalize (void)));
+	  connect (this, SIGNAL (sendRedraw (void)),
+		   m_object, SLOT (slotRedraw (void)));
+	}
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ObjectProxy::setObject (Object* obj)
+{
+  emit sendFinalize ();
+  init (obj);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ObjectProxy::update (int pId)
+{
+  if (octave_thread::is_octave_thread ())
+    emit sendUpdate (pId);
+  else
+    m_object->slotUpdate (pId);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ObjectProxy::finalize (void)
+{
+  emit sendFinalize ();
+  init (0);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ObjectProxy::redraw (void)
+{
+  emit sendRedraw ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ObjectProxy.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,68 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_ObjectProxy__
+#define __QtHandles_ObjectProxy__ 1
+
+#include <QObject>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Object;
+
+class ObjectProxy : public QObject
+{
+  Q_OBJECT
+
+public:
+   ObjectProxy (Object* obj = 0);
+
+   void update (int pId);
+   void finalize (void);
+   void redraw (void);
+
+   Object* object (void) { return m_object; }
+   void setObject (Object* obj);
+
+signals:
+   void sendUpdate (int pId);
+   void sendFinalize (void);
+   void sendRedraw (void);
+
+private:
+   void init (Object* obj);
+
+private:
+   Object* m_object;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Panel.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,375 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QEvent>
+#include <QFrame>
+#include <QLabel>
+#include <QMouseEvent>
+#include <QTimer>
+
+#include "Canvas.h"
+#include "Container.h"
+#include "ContextMenu.h"
+#include "Panel.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+static int frameStyleFromProperties (const uipanel::properties& pp)
+{
+  if (pp.bordertype_is ("none"))
+    return QFrame::NoFrame;
+  else if (pp.bordertype_is ("etchedin"))
+    return (QFrame::Box | QFrame::Sunken);
+  else if (pp.bordertype_is ("etchedout"))
+    return (QFrame::Box | QFrame::Raised);
+  else if (pp.bordertype_is ("beveledin"))
+    return (QFrame::Panel | QFrame::Sunken);
+  else if (pp.bordertype_is ("beveledout"))
+    return (QFrame::Panel | QFrame::Raised);
+  else
+    return (QFrame::Panel | QFrame::Plain);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void setupPalette (const uipanel::properties& pp, QPalette& p)
+{
+  p.setColor (QPalette::Window,
+	      Utils::fromRgb (pp.get_backgroundcolor_rgb ()));
+  p.setColor (QPalette::WindowText,
+	      Utils::fromRgb (pp.get_foregroundcolor_rgb ()));
+  p.setColor (QPalette::Light,
+	      Utils::fromRgb (pp.get_highlightcolor_rgb ()));
+  p.setColor (QPalette::Dark,
+	      Utils::fromRgb (pp.get_shadowcolor_rgb ()));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static int borderWidthFromProperties (const uipanel::properties& pp)
+{
+  int bw = 0;
+
+  if (! pp.bordertype_is ("none"))
+    {
+      bw = xround (pp.get_borderwidth ());
+      if (pp.bordertype_is ("etchedin") || pp.bordertype_is ("etchedout"))
+	bw *= 2;
+    }
+
+  return bw;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Panel* Panel::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      Container* container = parent->innerContainer ();
+
+      if (container)
+	return new Panel (go, new QFrame (container));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Panel::Panel (const graphics_object& go, QFrame* frame)
+    : Object (go, frame), m_container (0), m_title (0), m_blockUpdates (false)
+{
+  uipanel::properties& pp = properties<uipanel> ();
+
+  frame->setObjectName ("UIPanel");
+  frame->setAutoFillBackground (true);
+  Matrix bb = pp.get_boundingbox (false);
+  frame->setGeometry (xround (bb(0)), xround (bb(1)),
+		      xround (bb(2)), xround (bb(3)));
+  frame->setFrameStyle (frameStyleFromProperties (pp));
+  frame->setLineWidth (xround (pp.get_borderwidth ()));
+  QPalette pal = frame->palette ();
+  setupPalette (pp, pal);
+  frame->setPalette (pal);
+
+  m_container = new Container (frame);
+  m_container->canvas (m_handle);
+
+  QString title = Utils::fromStdString (pp.get_title ());
+  if (! title.isEmpty ())
+    {
+      m_title = new QLabel (title, frame);
+      m_title->setAutoFillBackground (true);
+      m_title->setContentsMargins (4, 0, 4, 0);
+      m_title->setPalette (pal);
+      m_title->setFont (Utils::computeFont<uipanel> (pp, bb(3)));
+    }
+
+  frame->installEventFilter (this);
+  m_container->installEventFilter (this);
+
+  if (pp.is_visible ())
+    QTimer::singleShot (0, frame, SLOT (show (void)));
+  else
+    frame->hide ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Panel::~Panel (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool Panel::eventFilter (QObject* watched, QEvent* event)
+{
+  if (! m_blockUpdates)
+    {
+      if (watched == qObject ())
+	{
+	  switch (event->type ())
+	    {
+	    case QEvent::Resize:
+		{
+		  gh_manager::auto_lock lock;
+		  graphics_object go = object ();
+
+		  if (go.valid_object ())
+		    {
+		      if (m_title)
+			{
+			  const uipanel::properties& pp =
+			    Utils::properties<uipanel> (go);
+
+			  if (pp.fontunits_is ("normalized"))
+			    {
+			      QFrame* frame = qWidget<QFrame> ();
+
+			      m_title->setFont (Utils::computeFont<uipanel>
+						(pp, frame->height ()));
+			      m_title->resize (m_title->sizeHint ());
+			    }
+			}
+		      updateLayout ();
+		    }
+		}
+	      break;
+	    case QEvent::MouseButtonPress:
+		{
+		  QMouseEvent* m = dynamic_cast<QMouseEvent*> (event);
+
+		  if (m->button () == Qt::RightButton)
+		    {
+		      gh_manager::auto_lock lock;
+
+		      ContextMenu::executeAt (properties (), m->globalPos ());
+		    }
+		}
+	      break;
+	    default:
+	      break;
+	    }
+	}
+      else if (watched == m_container)
+	{
+	  switch (event->type ())
+	    {
+	    case QEvent::Resize:
+	      if (qWidget<QWidget> ()->isVisible ())
+		{
+		  gh_manager::auto_lock lock;
+
+		  properties ().update_boundingbox ();
+		}
+	      break;
+	    default:
+	      break;
+	    }
+	}
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Panel::update (int pId)
+{
+  uipanel::properties& pp = properties<uipanel> ();
+  QFrame* frame = qWidget<QFrame> ();
+
+  m_blockUpdates = true;
+
+  switch (pId)
+    {
+    case uipanel::properties::ID_POSITION:
+	{
+	  Matrix bb = pp.get_boundingbox (false);
+
+	  frame->setGeometry (xround (bb(0)), xround (bb(1)),
+			      xround (bb(2)), xround (bb(3)));
+	  updateLayout ();
+	}
+      break;
+    case uipanel::properties::ID_BORDERWIDTH:
+      frame->setLineWidth (xround (pp.get_borderwidth ()));
+      updateLayout ();
+      break;
+    case uipanel::properties::ID_BACKGROUNDCOLOR:
+    case uipanel::properties::ID_FOREGROUNDCOLOR:
+    case uipanel::properties::ID_HIGHLIGHTCOLOR:
+    case uipanel::properties::ID_SHADOWCOLOR:
+	{
+	  QPalette pal = frame->palette ();
+
+	  setupPalette (pp, pal);
+	  frame->setPalette (pal);
+	  if (m_title)
+	    m_title->setPalette (pal);
+	}
+      break;
+    case uipanel::properties::ID_TITLE:
+	{
+	  QString title = Utils::fromStdString (pp.get_title ());
+
+	  if (title.isEmpty ())
+	    {
+	      if (m_title)
+		delete m_title;
+	      m_title = 0;
+	    }
+	  else
+	    {
+	      if (! m_title)
+		{
+		  QPalette pal = frame->palette ();
+
+		  m_title = new QLabel (title, frame);
+		  m_title->setAutoFillBackground (true);
+		  m_title->setContentsMargins (4, 0, 4, 0);
+		  m_title->setPalette (pal);
+		  m_title->setFont (Utils::computeFont<uipanel> (pp));
+		  m_title->show ();
+		}
+	      else
+		{
+		  m_title->setText (title);
+		  m_title->resize (m_title->sizeHint ());
+		}
+	    }
+	  updateLayout ();
+	}
+    case uipanel::properties::ID_TITLEPOSITION:
+      updateLayout ();
+      break;
+    case uipanel::properties::ID_BORDERTYPE:
+      frame->setFrameStyle (frameStyleFromProperties (pp));
+      updateLayout ();
+      break;
+    case uipanel::properties::ID_FONTNAME:
+    case uipanel::properties::ID_FONTSIZE:
+    case uipanel::properties::ID_FONTWEIGHT:
+    case uipanel::properties::ID_FONTANGLE:
+      if (m_title)
+	{
+	  m_title->setFont (Utils::computeFont<uipanel> (pp));
+	  m_title->resize (m_title->sizeHint ());
+	  updateLayout ();
+	}
+      break;
+    case uipanel::properties::ID_VISIBLE:
+      frame->setVisible (pp.is_visible ());
+      updateLayout ();
+      break;
+    default:
+      break;
+    }
+
+  m_blockUpdates = false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Panel::redraw (void)
+{
+  Canvas* canvas = m_container->canvas (m_handle);
+
+  if (canvas)
+    canvas->redraw ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void Panel::updateLayout (void)
+{
+  uipanel::properties& pp = properties<uipanel> ();
+  QFrame* frame = qWidget<QFrame> ();
+
+  Matrix bb = pp.get_boundingbox (true);
+  int bw = borderWidthFromProperties (pp);
+
+  frame->setFrameRect (QRect (xround (bb(0)) - bw, xround (bb(1)) - bw,
+			      xround (bb(2)) + 2*bw, xround (bb(3)) + 2*bw));
+  m_container->setGeometry (xround (bb(0)), xround (bb(1)),
+			    xround (bb(2)), xround (bb(3)));
+
+  if (m_blockUpdates)
+    pp.update_boundingbox ();
+
+  if (m_title)
+    {
+      QSize sz = m_title->sizeHint ();
+      int offset = 5;
+
+      if (pp.titleposition_is ("lefttop"))
+	m_title->move (bw+offset, 0);
+      else if (pp.titleposition_is ("righttop"))
+	m_title->move (frame->width () - bw - offset - sz.width (), 0);
+      else if (pp.titleposition_is ("leftbottom"))
+	m_title->move (bw+offset, frame->height () - sz.height ());
+      else if (pp.titleposition_is ("rightbottom"))
+	m_title->move (frame->width () - bw - offset - sz.width (),
+		       frame->height () - sz.height ());
+      else if (pp.titleposition_is ("centertop"))
+	m_title->move (frame->width () / 2 - sz.width () / 2, 0);
+      else if (pp.titleposition_is ("centerbottom"))
+	m_title->move (frame->width () / 2 - sz.width () / 2,
+		       frame->height () - sz.height ());
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Panel.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,70 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_Panel__
+#define __QtHandles_Panel__ 1
+
+#include "Object.h"
+
+class QFrame;
+class QLabel;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Container;
+
+class Panel : public Object
+{
+public:
+  Panel (const graphics_object& go, QFrame* frame);
+  ~Panel (void);
+
+  Container* innerContainer (void) { return m_container; }
+
+  bool eventFilter (QObject* watched, QEvent* event);
+
+  static Panel* create (const graphics_object& go);
+
+protected:
+  void update (int pId);
+  void redraw (void);
+
+private:
+  void updateLayout (void);
+
+private:
+  Container* m_container;
+  QLabel* m_title;
+  bool m_blockUpdates;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/PopupMenuControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,143 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QComboBox>
+
+#include "Container.h"
+#include "PopupMenuControl.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+PopupMenuControl* PopupMenuControl::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      Container* container = parent->innerContainer ();
+
+      if (container)
+	return new PopupMenuControl (go, new QComboBox (container));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+PopupMenuControl::PopupMenuControl (const graphics_object& go, QComboBox *box)
+     : BaseControl (go, box), m_blockUpdate (false)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+
+  box->addItems (Utils::fromStdString (up.get_string_string ()).split ('|'));
+
+  connect (box, SIGNAL (currentIndexChanged (int)),
+	   SLOT (currentIndexChanged (int)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+PopupMenuControl::~PopupMenuControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void PopupMenuControl::update (int pId)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+  QComboBox* box = qWidget<QComboBox> ();
+
+  switch (pId)
+    {
+    case uicontrol::properties::ID_STRING:
+      m_blockUpdate = true;
+	{
+	  int oldCurrent = box->currentIndex ();
+
+	  box->clear ();
+	  box->addItems (Utils::fromStdString
+			 (up.get_string_string ()).split ('|'));
+	  if (box->count() > 0
+	      && oldCurrent >= 0
+	      && oldCurrent < box->count ())
+	    {
+	      box->setCurrentIndex (oldCurrent);
+	    }
+	  else
+	    {
+	      gh_manager::post_set (m_handle, "value",
+				    octave_value (box->count () > 0
+						  ? 1.0 : 0.0),
+				    false);
+	    }
+	}
+      m_blockUpdate = false;
+      break;
+    case uicontrol::properties::ID_VALUE:
+	{
+	  Matrix value = up.get_value ().matrix_value ();
+
+	  if (value.numel () > 0)
+	    {
+	      int newIndex = int (value(0)) - 1;
+
+	      if (newIndex >= 0 && newIndex < box->count ()
+		  && newIndex != box->currentIndex ())
+		{
+		  box->setCurrentIndex (newIndex);
+		}
+	    }
+	}
+      break;
+    default:
+      BaseControl::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void PopupMenuControl::currentIndexChanged (int index)
+{
+  if (! m_blockUpdate)
+    {
+      gh_manager::post_set (m_handle, "value",
+			    octave_value (double (index + 1)),
+			    false);
+      gh_manager::post_callback (m_handle, "callback");
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/PopupMenuControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,62 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_PopupMenuControl__
+#define __QtHandles_PopupMenuControl__ 1
+
+#include "BaseControl.h"
+
+class QComboBox;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class PopupMenuControl : public BaseControl
+{
+  Q_OBJECT
+
+public:
+  PopupMenuControl (const graphics_object& go, QComboBox* box);
+  ~PopupMenuControl (void);
+
+  static PopupMenuControl* create (const graphics_object& go);
+
+protected:
+  void update (int pId);
+
+private slots:
+  void currentIndexChanged (int index);
+
+private:
+  bool m_blockUpdate;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/PushButtonControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,89 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QPushButton>
+#include <QtDebug>
+
+#include "PushButtonControl.h"
+#include "Container.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+PushButtonControl* PushButtonControl::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      Container* container = parent->innerContainer ();
+
+      if (container)
+	return new PushButtonControl (go, new QPushButton (container));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+PushButtonControl::PushButtonControl (const graphics_object& go, QPushButton* btn)
+  : ButtonControl (go, btn)
+{
+  btn->setAutoFillBackground (true);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+PushButtonControl::~PushButtonControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void PushButtonControl::update (int pId)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+  QPushButton* btn = qWidget<QPushButton> ();
+
+  switch (pId)
+    {
+    case uicontrol::properties::ID_STRING:
+      btn->setText (Utils::fromStdString (up.get_string_string ()));
+      break;
+    default:
+      BaseControl::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespave QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/PushButtonControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,54 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_PushButtonControl__
+#define __QtHandles_PushButtonControl__ 1
+
+#include "ButtonControl.h"
+
+class QPushButton;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class PushButtonControl : public ButtonControl
+{
+public:
+  PushButtonControl (const graphics_object& go, QPushButton* btn);
+  ~PushButtonControl (void);
+
+  static PushButtonControl* create (const graphics_object& go);
+
+protected:
+  void update (int pId);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/PushTool.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,87 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "PushTool.h"
+
+#include "ToolBarButton.cc"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+PushTool* PushTool::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      QWidget* parentWidget = parent->qWidget<QWidget> ();
+
+      if (parentWidget)
+	return new PushTool (go, new QAction (parentWidget));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+PushTool::PushTool (const graphics_object& go, QAction* action)
+    : ToolBarButton<uipushtool> (go, action)
+{
+  connect (action, SIGNAL (triggered (bool)), this, SLOT (clicked (void)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+PushTool::~PushTool (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void PushTool::update (int pId)
+{
+  switch (pId)
+    {
+    default:
+      ToolBarButton<uipushtool>::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void PushTool::clicked (void)
+{
+  gh_manager::post_callback (m_handle, "clickedcallback");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/PushTool.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,57 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_PushTool__
+#define __QtHandles_PushTool__ 1
+
+#include "ToolBarButton.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class PushTool : public ToolBarButton<uipushtool>
+{
+  Q_OBJECT
+
+public:
+  PushTool (const graphics_object& go, QAction* action);
+  ~PushTool (void);
+
+  static PushTool* create (const graphics_object& go);
+
+protected:
+  void update (int pId);
+
+private slots:
+  void clicked (void);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/RadioButtonControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,72 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QRadioButton>
+
+#include "RadioButtonControl.h"
+#include "Container.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+RadioButtonControl* RadioButtonControl::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      Container* container = parent->innerContainer ();
+
+      if (container)
+	return new RadioButtonControl (go, new QRadioButton (container));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+RadioButtonControl::RadioButtonControl (const graphics_object& go,
+					QRadioButton* radio)
+    : ButtonControl (go, radio)
+{
+  radio->setAutoFillBackground (true);
+  radio->setAutoExclusive (false);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+RadioButtonControl::~RadioButtonControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/RadioButtonControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,51 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_RadioButton__
+#define __QtHandles_RadioButton__ 1
+
+#include "ButtonControl.h"
+
+class QRadioButton;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class RadioButtonControl : public ButtonControl
+{
+public:
+  RadioButtonControl (const graphics_object& go, QRadioButton* box);
+  ~RadioButtonControl (void);
+
+  static RadioButtonControl* create (const graphics_object& go);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/SliderControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,163 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QScrollBar>
+
+#include "Container.h"
+#include "SliderControl.h"
+#include "Utils.h"
+
+#define RANGE_INT_MAX 1000000
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+SliderControl* SliderControl::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      Container* container = parent->innerContainer ();
+
+      if (container)
+	return new SliderControl (go, new QScrollBar (container));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+SliderControl::SliderControl (const graphics_object& go,
+			      QAbstractSlider* slider)
+    : BaseControl (go, slider), m_blockUpdates (false)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+
+  slider->setTracking (false);
+  Matrix bb = up.get_boundingbox ();
+  slider->setOrientation (bb(2) > bb(3) ? Qt::Horizontal : Qt::Vertical);
+  Matrix steps = up.get_sliderstep ().matrix_value ();
+  slider->setMinimum (0);
+  slider->setMaximum (RANGE_INT_MAX);
+  slider->setSingleStep (xround (steps(0) * RANGE_INT_MAX));
+  slider->setPageStep (xround (steps(1) * RANGE_INT_MAX));
+  Matrix value = up.get_value ().matrix_value ();
+  if (value.numel () > 0)
+    {
+      double dmin = up.get_min (), dmax = up.get_max ();
+
+      slider->setValue (xround (((value(0) - dmin) / (dmax - dmin))
+				* RANGE_INT_MAX));
+    }
+
+  connect (slider, SIGNAL (valueChanged (int)), SLOT (valueChanged (int)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+SliderControl::~SliderControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void SliderControl::update (int pId)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+  QScrollBar* slider = qWidget<QScrollBar> ();
+
+  switch (pId)
+    {
+    case uicontrol::properties::ID_SLIDERSTEP:
+	{
+	  Matrix steps = up.get_sliderstep ().matrix_value ();
+
+	  slider->setSingleStep (xround (steps(0) * RANGE_INT_MAX));
+	  slider->setPageStep (xround (steps(1) * RANGE_INT_MAX));
+	}
+      break;
+    case uicontrol::properties::ID_VALUE:
+	{
+	  Matrix value = up.get_value ().matrix_value ();
+	  double dmax = up.get_max (), dmin = up.get_min ();
+
+	  if (value.numel () > 0)
+	    {
+	      int ival = xround (((value(0) - dmin) / (dmax - dmin))
+				 * RANGE_INT_MAX);
+
+	      m_blockUpdates = true;
+	      slider->setValue (ival);
+	      m_blockUpdates = false;
+	    }
+	}
+      break;
+    default:
+      BaseControl::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void SliderControl::valueChanged (int ival)
+{
+  if (! m_blockUpdates)
+    {
+      gh_manager::auto_lock lock;
+      graphics_object go = object ();
+
+      if (go.valid_object ())
+	{
+	  uicontrol::properties& up = Utils::properties<uicontrol> (go);
+
+	  Matrix value = up.get_value ().matrix_value ();
+	  double dmin = up.get_min (), dmax = up.get_max ();
+
+	  int ival_tmp = (value.numel () > 0 ?
+			  xround (((value(0) - dmin) / (dmax - dmin))
+				  * RANGE_INT_MAX) :
+			  0);
+
+	  if (ival != ival_tmp || value.numel () > 0)
+	    {
+	      double dval = dmin + (ival * (dmax - dmin) / RANGE_INT_MAX);
+
+	      gh_manager::post_set (m_handle, "value", octave_value (dval));
+	      gh_manager::post_callback (m_handle, "callback");
+	    }
+	}
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/SliderControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,62 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_SliderControl__
+#define __QtHandles_SliderControl__ 1
+
+#include "BaseControl.h"
+
+class QAbstractSlider;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class SliderControl : public BaseControl
+{
+  Q_OBJECT
+
+public:
+  SliderControl (const graphics_object& go, QAbstractSlider* slider);
+  ~SliderControl (void);
+
+  static SliderControl* create (const graphics_object& go);
+
+protected:
+  void update (int pId);
+
+private slots:
+  void valueChanged (int ival);
+
+private:
+  bool m_blockUpdates;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/TextControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,102 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QLabel>
+
+#include "Container.h"
+#include "TextControl.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+TextControl* TextControl::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      Container* container = parent->innerContainer ();
+
+      if (container)
+	return new TextControl (go, new QLabel (container));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+TextControl::TextControl (const graphics_object& go, QLabel* label)
+     : BaseControl (go, label)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+
+  label->setAutoFillBackground (true);
+  label->setTextFormat (Qt::PlainText);
+  label->setWordWrap (false);
+  label->setAlignment (Utils::fromHVAlign (up.get_horizontalalignment (),
+					   up.get_verticalalignment ()));
+  // FIXME: support string_vector
+  label->setText (Utils::fromStdString (up.get_string_string ()));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+TextControl::~TextControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void TextControl::update (int pId)
+{
+  uicontrol::properties& up = properties<uicontrol> ();
+  QLabel* label = qWidget<QLabel> ();
+
+  switch (pId)
+    {
+    case uicontrol::properties::ID_STRING:
+      // FIXME: support string_vector
+      label->setText (Utils::fromStdString (up.get_string_string ()));
+      break;
+    case uicontrol::properties::ID_HORIZONTALALIGNMENT:
+    case uicontrol::properties::ID_VERTICALALIGNMENT:
+      label->setAlignment (Utils::fromHVAlign (up.get_horizontalalignment (),
+					       up.get_verticalalignment ()));
+      break;
+    default:
+      BaseControl::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/TextControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,54 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_TextControl__
+#define __QtHandles_TextControl__ 1
+
+#include "BaseControl.h"
+
+class QLabel;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class TextControl : public BaseControl
+{
+public:
+  TextControl (const graphics_object& go, QLabel* label);
+  ~TextControl (void);
+
+  static TextControl* create (const graphics_object& go);
+
+protected:
+  void update (int pId);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/TextEdit.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,58 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QKeyEvent>
+
+#include "TextEdit.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+void TextEdit::focusOutEvent (QFocusEvent* event)
+{
+  QTextEdit::focusOutEvent (event);
+
+  emit editingFinished ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void TextEdit::keyPressEvent (QKeyEvent* event)
+{
+  QTextEdit::keyPressEvent (event);
+
+  if ((event->key () == Qt::Key_Return
+       || event->key () == Qt::Key_Enter)
+      && event->modifiers () == Qt::ControlModifier)
+    emit editingFinished ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/TextEdit.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,56 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_TextEdit__
+#define __QtHandles_TextEdit__ 1
+
+#include <QTextEdit>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class TextEdit : public QTextEdit
+{
+  Q_OBJECT
+
+public:
+  TextEdit (QWidget* parent) : QTextEdit(parent) { }
+  ~TextEdit (void) { }
+
+signals:
+  void editingFinished (void);
+
+protected:
+  void focusOutEvent (QFocusEvent* event);
+  void keyPressEvent (QKeyEvent* event);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ToggleButtonControl.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,72 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QPushButton>
+
+#include "ToggleButtonControl.h"
+#include "Container.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+ToggleButtonControl* ToggleButtonControl::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      Container* container = parent->innerContainer ();
+
+      if (container)
+	return new ToggleButtonControl (go, new QPushButton (container));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ToggleButtonControl::ToggleButtonControl (const graphics_object& go,
+					  QPushButton* btn)
+    : ButtonControl (go, btn)
+{
+  btn->setCheckable (true);
+  btn->setAutoFillBackground (true);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ToggleButtonControl::~ToggleButtonControl (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ToggleButtonControl.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,51 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_ToggleButtonControl__
+#define __QtHandles_ToggleButtonControl__ 1
+
+#include "ButtonControl.h"
+
+class QPushButton;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class ToggleButtonControl : public ButtonControl
+{
+public:
+  ToggleButtonControl (const graphics_object& go, QPushButton* box);
+  ~ToggleButtonControl (void);
+
+  static ToggleButtonControl* create (const graphics_object& go);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ToggleTool.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,104 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ToggleTool.h"
+
+#include "ToolBarButton.cc"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+ToggleTool* ToggleTool::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      QWidget* parentWidget = parent->qWidget<QWidget> ();
+
+      if (parentWidget)
+	return new ToggleTool (go, new QAction (parentWidget));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ToggleTool::ToggleTool (const graphics_object& go, QAction* action)
+    : ToolBarButton<uitoggletool> (go, action)
+{
+  uitoggletool::properties& tp = properties<uitoggletool> ();
+
+  action->setCheckable (true);
+  action->setChecked (tp.is_state ());
+
+  connect (action, SIGNAL (toggled (bool)),
+	   this, SLOT (triggered (bool)));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ToggleTool::~ToggleTool (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ToggleTool::update (int pId)
+{
+  uitoggletool::properties& tp = properties<uitoggletool> ();
+  QAction* action = qWidget<QAction> ();
+
+  switch (pId)
+    {
+    case uitoggletool::properties::ID_STATE:
+      action->setChecked (tp.is_state ());
+      break;
+    default:
+      ToolBarButton<uitoggletool>::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ToggleTool::triggered (bool checked)
+{
+  gh_manager::post_set (m_handle, "state", checked, false);
+  gh_manager::post_callback (m_handle,
+			     checked
+			     ? "oncallback"
+			     : "offcallback");
+  gh_manager::post_callback (m_handle, "clickedcallback");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ToggleTool.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,57 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_ToggleTool__
+#define __QtHandles_ToggleTool__ 1
+
+#include "ToolBarButton.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class ToggleTool : public ToolBarButton<uitoggletool>
+{
+  Q_OBJECT
+
+public:
+  ToggleTool (const graphics_object& go, QAction* action);
+  ~ToggleTool (void);
+
+  static ToggleTool* create (const graphics_object& go);
+
+protected:
+  void update (int pId);
+
+private slots:
+  void triggered (bool checked);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ToolBar.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,191 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QAction>
+#include <QActionEvent>
+#include <QApplication>
+#include <QEvent>
+#include <QIcon>
+#include <QMainWindow>
+#include <QPixmap>
+#include <QTimer>
+#include <QToolBar>
+
+#include "Figure.h"
+#include "ToolBar.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+static QAction* addEmptyAction (QToolBar* bar)
+{
+  static QIcon _empty;
+
+  if (_empty.isNull ())
+    {
+      QPixmap pix (16, 16);
+
+      pix.fill (Qt::transparent);
+
+      _empty = QIcon (pix);
+    }
+
+  QAction* a = bar->addAction (_empty, "Empty Toolbar");
+
+  a->setEnabled (false);
+  a->setToolTip ("");
+
+  return a;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ToolBar* ToolBar::create (const graphics_object& go)
+{
+  Object* parent = Object::parentObject (go);
+
+  if (parent)
+    {
+      QWidget* parentWidget = parent->qWidget<QWidget> ();
+
+      if (parentWidget)
+	return new ToolBar (go, new QToolBar (parentWidget));
+    }
+
+  return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ToolBar::ToolBar (const graphics_object& go, QToolBar* bar)
+     : Object (go, bar), m_empty (0), m_figure (0)
+{
+  uitoolbar::properties& tp = properties<uitoolbar> ();
+
+  bar->setFloatable (false);
+  bar->setMovable (false);
+  bar->setVisible (tp.is_visible ());
+
+  m_empty = addEmptyAction (bar);
+
+  m_figure =
+    dynamic_cast<Figure*> (Object::fromQObject (bar->parentWidget ()));
+
+  if (m_figure)
+    m_figure->addCustomToolBar (bar, tp.is_visible ());
+
+  bar->installEventFilter (this);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ToolBar::~ToolBar (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ToolBar::update (int pId)
+{
+  uitoolbar::properties& tp = properties<uitoolbar> ();
+  QToolBar* bar = qWidget<QToolBar> ();
+
+  switch (pId)
+    {
+    case base_properties::ID_VISIBLE:
+      if (m_figure)
+	m_figure->showCustomToolBar (bar, tp.is_visible ());
+      break;
+    default:
+      Object::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool ToolBar::eventFilter (QObject* watched, QEvent* event)
+{
+  if (watched == qObject ())
+    {
+      switch (event->type ())
+	{
+	case QEvent::ActionAdded:
+	case QEvent::ActionRemoved:
+	    {
+	      QActionEvent* ae = dynamic_cast<QActionEvent*> (event);
+	      QToolBar* bar = qWidget<QToolBar> ();
+
+	      if (ae->action () != m_empty)
+		{
+		  if (event->type () == QEvent::ActionAdded)
+		    {
+		      if (bar->actions ().size () == 2)
+			QTimer::singleShot (0, this, SLOT (hideEmpty (void)));
+		    }
+		  else
+		    {
+		      if (bar->actions ().size () == 1)
+			m_empty->setVisible (true);
+		    }
+		}
+	    }
+	  break;
+	default:
+	  break;
+	}
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ToolBar::hideEmpty (void)
+{
+  m_empty->setVisible (false);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ToolBar::beingDeleted (void)
+{
+  if (m_figure)
+    {
+      QToolBar* bar = qWidget<QToolBar> ();
+
+      if (bar)
+	m_figure->showCustomToolBar (bar, false);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ToolBar.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,71 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_ToolBar__
+#define __QtHandles_ToolBar__ 1
+
+#include "Object.h"
+
+class QAction;
+class QToolBar;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Figure;
+
+class ToolBar : public Object
+{
+  Q_OBJECT
+
+public:
+  ToolBar (const graphics_object& go, QToolBar* bar);
+  ~ToolBar (void);
+
+  static ToolBar* create (const graphics_object& go);
+
+  Container* innerContainer (void) { return 0; }
+
+  bool eventFilter (QObject* watched, QEvent* event);
+
+protected:
+  void update (int pId);
+  void beingDeleted (void);
+
+private slots:
+  void hideEmpty (void);
+
+private:
+  QAction* m_empty;
+  Figure* m_figure;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ToolBarButton.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,128 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QAction>
+#include <QWidget>
+
+#include "ToolBarButton.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+ToolBarButton<T>::ToolBarButton (const graphics_object& go, QAction* action)
+    : Object (go, action), m_separator (0)
+{
+  typename T::properties& tp = properties<T> ();
+
+  action->setToolTip (Utils::fromStdString (tp.get_tooltipstring ()));
+  action->setVisible (tp.is_visible ());
+  QImage img = Utils::makeImageFromCData (tp.get_cdata (), 16, 16);
+  action->setIcon (QIcon (QPixmap::fromImage (img)));
+  if (tp.is_separator ())
+    {
+      m_separator = new QAction (action);
+      m_separator->setSeparator (true);
+      m_separator->setVisible (tp.is_visible ());
+    }
+  action->setEnabled (tp.is_enable ());
+
+  QWidget* w = qobject_cast<QWidget*> (action->parent ());
+
+  w->insertAction (w->actions ().back (), action);
+  if (m_separator)
+    w->insertAction (action, m_separator);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+ToolBarButton<T>::~ToolBarButton (void)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+void ToolBarButton<T>::update (int pId)
+{
+  typename T::properties& tp = properties<T> ();
+  QAction* action = qWidget<QAction> ();
+
+  switch (pId)
+    {
+    case base_properties::ID_VISIBLE:
+      action->setVisible (tp.is_visible ());
+      if (m_separator)
+	m_separator->setVisible (tp.is_visible ());
+      break;
+    case T::properties::ID_TOOLTIPSTRING:
+      action->setToolTip (Utils::fromStdString (tp.get_tooltipstring ()));
+      break;
+    case T::properties::ID_CDATA:
+	{
+	  QImage img = Utils::makeImageFromCData (tp.get_cdata (), 16, 16);
+
+	  action->setIcon (QIcon (QPixmap::fromImage (img)));
+	}
+      break;
+    case T::properties::ID_SEPARATOR:
+      if (tp.is_separator ())
+	{
+	  if (! m_separator)
+	    {
+	      m_separator = new QAction (action);
+	      m_separator->setSeparator (true);
+	      m_separator->setVisible (tp.is_visible ());
+
+	      QWidget* w = qobject_cast<QWidget*> (action->parent ());
+
+	      w->insertAction (action, m_separator);
+	    }
+	}
+      else
+	{
+	  if (m_separator)
+	    delete m_separator;
+	  m_separator = 0;
+	}
+      break;
+    case T::properties::ID_ENABLE:
+      action->setEnabled (tp.is_enable ());
+      break;
+    default:
+      Object::update (pId);
+      break;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/ToolBarButton.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,60 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_ToolBarButton__
+#define __QtHandles_ToolBarButton__ 1
+
+#include "Object.h"
+
+class QAction;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Container;
+  
+template <class T>
+class ToolBarButton : public Object
+{
+public:
+  ToolBarButton (const graphics_object& go, QAction* action);
+  ~ToolBarButton (void);
+
+  Container* innerContainer (void) { return 0; }
+
+protected:
+  void update (int pId);
+
+private:
+  QAction* m_separator;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Utils.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,355 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QApplication>
+#include <QKeyEvent>
+#include <QMouseEvent>
+
+#include <list>
+
+#include "ov.h"
+#include "graphics.h"
+
+#include "Backend.h"
+#include "Container.h"
+#include "KeyMap.h"
+#include "Object.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace Utils
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+QString fromStdString (const std::string& s)
+{
+  return QString::fromLocal8Bit (s.c_str ());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::string toStdString (const QString& s)
+{
+  return std::string (s.toLocal8Bit ().data ());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QStringList fromStringVector (const string_vector& v)
+{
+  QStringList l;
+  octave_idx_type n = v.length ();
+
+  for (octave_idx_type i = 0; i < n; i++)
+    l << fromStdString (v[i]);
+
+  return l;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+string_vector toStringVector (const QStringList& l)
+{
+  string_vector v (l.length ());
+  int i = 0;
+
+  foreach (const QString& s, l)
+    v[i++] = toStdString (s);
+
+  return v;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+QFont computeFont (const typename T::properties& props, int height)
+{
+  QFont f (fromStdString (props.get_fontname ()));
+
+  static std::map<std::string, QFont::Weight> weightMap;
+  static std::map<std::string, QFont::Style> angleMap;
+  static bool mapsInitialized = false;
+
+  if (! mapsInitialized)
+    {
+      weightMap[std::string ("normal")] = QFont::Normal;
+      weightMap[std::string ("light")] = QFont::Light;
+      weightMap[std::string ("demi")] = QFont::DemiBold;
+      weightMap[std::string ("bold")] = QFont::Normal;
+
+      angleMap[std::string ("normal")] = QFont::StyleNormal;
+      angleMap[std::string ("italic")] = QFont::StyleItalic;
+      angleMap[std::string ("oblique")] = QFont::StyleOblique;
+
+      mapsInitialized = true;
+    }
+
+  f.setPointSizeF (props.get_fontsize_points (height));
+  f.setWeight (weightMap[props.get_fontweight ()]);
+  f.setStyle (angleMap[props.get_fontangle ()]);
+
+  return f;
+}
+
+template QFont computeFont<uicontrol> (const uicontrol::properties& props,
+				       int height);
+template QFont computeFont<uipanel> (const uipanel::properties& props,
+				     int height);
+
+//////////////////////////////////////////////////////////////////////////////
+
+QColor fromRgb (const Matrix& rgb)
+{
+  QColor c;
+
+  if (rgb.numel () == 3)
+    c.setRgbF (rgb(0), rgb(1), rgb(2));
+  
+  return c;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Matrix toRgb (const QColor& c)
+{
+  Matrix rgb (1, 3);
+  double* rgbData = rgb.fortran_vec ();
+
+  c.getRgbF (rgbData, rgbData+1, rgbData+2);
+
+  return rgb;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::string figureSelectionType (QMouseEvent* event, bool isDoubleClick)
+{
+  if (isDoubleClick)
+    return std::string ("open");
+  else
+    {
+      Qt::MouseButtons buttons = event->buttons ();
+      Qt::KeyboardModifiers mods = event->modifiers ();
+
+      if (mods == Qt::NoModifier)
+	{
+	  if (buttons == Qt::LeftButton)
+	    return std::string ("normal");
+	  else if (buttons == Qt::RightButton)
+	    return std::string ("alt");
+#if defined (Q_WS_WIN)
+	  else if (buttons == (Qt::LeftButton|Qt::RightButton))
+	    return std::string ("extend");
+#elif defined (Q_WS_X11)
+	  else if (buttons == Qt::MidButton)
+	    return std::string ("extend");
+#endif
+	}
+      else if (buttons == Qt::LeftButton)
+	{
+	  if (mods == Qt::ShiftModifier)
+	    return std::string ("extend");
+	  else if (mods == Qt::ControlModifier)
+	    return std::string ("alt");
+	}
+    }
+
+  return std::string ("normal");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Matrix figureCurrentPoint (const graphics_object& fig, QMouseEvent* event)
+{
+  Object* tkFig = Backend::toolkitObject (fig);
+
+  if (tkFig)
+    {
+      Container* c = tkFig->innerContainer ();
+
+      if (c)
+	{
+	  QPoint qp = c->mapFromGlobal (event->globalPos ());
+
+	  return
+	    tkFig->properties<figure> ().map_from_boundingbox (qp.x (),
+							       qp.y ());
+	}
+    }
+
+  return Matrix (1, 2, 0.0);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+Qt::Alignment fromHVAlign (const caseless_str& halign,
+			   const caseless_str& valign)
+{
+  Qt::Alignment flags;
+
+  if (halign.compare ("left"))
+    flags |= Qt::AlignLeft;
+  else if (halign.compare ("center"))
+    flags |= Qt::AlignHCenter;
+  else if (halign.compare ("right"))
+    flags |= Qt::AlignRight;
+  else
+    flags |= Qt::AlignLeft;
+
+  if (valign.compare ("middle"))
+    flags |= Qt::AlignVCenter;
+  else if (valign.compare ("top"))
+    flags |= Qt::AlignTop;
+  else if (valign.compare ("bottom"))
+    flags |= Qt::AlignBottom;
+  else
+    flags |= Qt::AlignVCenter;
+
+  return flags;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QImage makeImageFromCData (const octave_value& v, int width, int height)
+{
+  dim_vector dv (v.dims ());
+
+  if (dv.length () == 3 && dv(2) == 3)
+    {
+      int w = qMin (dv(1), width);
+      int h = qMin (dv(0), height);
+
+      int x_off = (w < width ? (width - w) / 2 : 0);
+      int y_off = (h < height ? (height - h) / 2 : 0);
+
+      QImage img (width, height, QImage::Format_ARGB32);
+      img.fill (qRgba (0, 0, 0, 0));
+
+      if (v.is_uint8_type ())
+	{
+	  uint8NDArray d = v.uint8_array_value ();
+
+	  for (int i = 0; i < w; i++)
+	    for (int j = 0; j < h; j++)
+	      {
+		int r = d(j, i, 0);
+		int g = d(j, i, 1);
+		int b = d(j, i, 2);
+		int a = 255;
+
+		img.setPixel (x_off + i, y_off + j, qRgba (r, g, b, a));
+	      }
+	}
+      else if (v.is_single_type ())
+	{
+	  FloatNDArray f = v.float_array_value ();
+
+	  for (int i = 0; i < w; i++)
+	    for (int j = 0; j < h; j++)
+	      {
+		float r = f(j, i, 0);
+		float g = f(j, i, 1);
+		float b = f(j, i, 2);
+		int a = (xisnan (r) || xisnan (g) || xisnan (b) ? 0 : 255);
+
+		img.setPixel (x_off + i, y_off + j,
+			      qRgba (xround (r * 255),
+				     xround (g * 255),
+				     xround (b * 255),
+				     a));
+	      }
+	}
+      else if (v.is_real_type ())
+	{
+	  NDArray d = v.array_value ();
+
+	  for (int i = 0; i < w; i++)
+	    for (int j = 0; j < h; j++)
+	      {
+		double r = d(j, i, 0);
+		double g = d(j, i, 1);
+		double b = d(j, i, 2);
+		int a = (xisnan (r) || xisnan (g) || xisnan (b) ? 0 : 255);
+
+		img.setPixel (x_off + i, y_off + j,
+			      qRgba (xround (r * 255),
+				     xround (g * 255),
+				     xround (b * 255),
+				     a));
+	      }
+	}
+
+      return img;
+    }
+
+  return QImage ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+octave_scalar_map makeKeyEventStruct (QKeyEvent* event)
+{
+  octave_scalar_map retval;
+
+  retval.setfield ("Key", KeyMap::qKeyToKeyString (event->key ()));
+  retval.setfield ("Character", toStdString (event->text ()));
+
+  std::list<std::string> modList;
+  Qt::KeyboardModifiers mods = event->modifiers ();
+
+  if (mods & Qt::ShiftModifier)
+    modList.push_back ("shift");
+  if (mods & Qt::ControlModifier)
+#ifdef Q_OS_MAC
+    modList.push_back ("command");
+#else
+    modList.push_back ("control");
+#endif
+  if (mods & Qt::AltModifier)
+    modList.push_back ("alt");
+#ifdef Q_OS_MAC
+  if (mods & Qt::MetaModifier)
+    modList.push_back ("control");
+#endif
+
+  retval.setfield ("Modifier", Cell (modList));
+
+  return retval;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace Utils
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Utils.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,89 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_Utils__
+#define __QtHandles_Utils__ 1
+
+#include <QColor>
+#include <QFont>
+#include <QImage>
+#include <QString>
+#include <QStringList>
+
+#include <string>
+
+#include "graphics.h"
+
+class QKeyEvent;
+class QMouseEvent;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace Utils
+{
+  QString fromStdString (const std::string& s);
+  std::string toStdString (const QString& s);
+
+  QStringList fromStringVector (const string_vector& v);
+  string_vector toStringVector (const QStringList& l);
+
+  template <class T>
+  QFont computeFont (const typename T::properties& props, int height = -1);
+
+  QColor fromRgb (const Matrix& rgb);
+  Matrix toRgb (const QColor& c);
+
+  Qt::Alignment fromHVAlign (const caseless_str& halign,
+			     const caseless_str& valign);
+
+  std::string figureSelectionType (QMouseEvent* event,
+				   bool isDoubleClick = false);
+
+  Matrix figureCurrentPoint (const graphics_object& fig, QMouseEvent* event);
+
+  template <class T>
+  inline typename T::properties&
+  properties (graphics_object obj)
+    { return dynamic_cast<typename T::properties&> (obj.get_properties ()); }
+
+  template <class T>
+  inline typename T::properties&
+  properties (const graphics_handle& h)
+    { return Utils::properties<T> (gh_manager::get_object (h)); }
+
+  QImage makeImageFromCData (const octave_value& v, int width = -1,
+			     int height = -1);
+
+  octave_scalar_map makeKeyEventStruct (QKeyEvent* event);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/__init_qt__.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,355 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <QApplication>
+#include <QDir>
+#include <QFileDialog>
+#include <QMetaType>
+#include <QPalette>
+#include <QRegExp>
+
+#include "graphics.h"
+#include "toplev.h"
+#include "defun.h"
+
+#include "Backend.h"
+#include "Utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+static bool qtHandlesInitialized = false;
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool __init__ (void)
+{
+  if (! qtHandlesInitialized)
+    {
+      if (qApp)
+	{
+	  qRegisterMetaType<graphics_object> ("graphics_object");
+
+	  gh_manager::enable_event_processing (true);
+
+	  graphics_toolkit tk (new Backend ());
+          gtk_manager::load_toolkit (tk);
+
+	  octave_add_atexit_function ("__shutdown_qt__");
+
+	  // Change some default settings to use Qt default colors
+	  QPalette p;
+	  graphics_object root = gh_manager::get_object (0);
+
+	  /*
+	  root.set ("defaultfigurecolor",
+		    octave_value (Utils::toRgb (p.color (QPalette::Window))));
+	  */
+	  root.set ("defaultuicontrolbackgroundcolor",
+		    octave_value (Utils::toRgb (p.color (QPalette::Window))));
+	  root.set ("defaultuicontrolforegroundcolor",
+		    octave_value (Utils::toRgb
+				  (p.color (QPalette::WindowText))));
+	  root.set ("defaultuipanelbackgroundcolor",
+		    octave_value (Utils::toRgb (p.color (QPalette::Window))));
+	  root.set ("defaultuipanelforegroundcolor",
+		    octave_value (Utils::toRgb
+				  (p.color (QPalette::WindowText))));
+	  root.set ("defaultuipanelhighlightcolor",
+		    octave_value (Utils::toRgb (p.color (QPalette::Light))));
+	  root.set ("defaultuipanelshadowcolor",
+		    octave_value (Utils::toRgb (p.color (QPalette::Dark))));
+
+	  qtHandlesInitialized = true;
+
+	  return true;
+	}
+      else
+	error ("__init_qt__: QApplication object must exist.");
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool __shutdown__ (void)
+{
+  if (qtHandlesInitialized)
+    {
+      octave_add_atexit_function ("__shutdown_qt__");
+
+      gtk_manager::unload_toolkit ("qt");
+
+      gh_manager::enable_event_processing (false);
+
+      qtHandlesInitialized = false;
+
+      return true;
+    }
+
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEFUN (__init_qt__, , , "")
+{
+  QtHandles::__init__ ();
+
+  return octave_value ();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEFUN (__shutdown_qt__, , , "")
+{
+  QtHandles::__shutdown__ ();
+
+  return octave_value ();
+}
+
+void
+install___init_qt___functions (void)
+{
+  install_builtin_function (F__init_qt__, "__init_qt__",
+                            "__init_qt__.cc", "");
+
+  install_builtin_function (F__shutdown_qt__, "__shutdown_qt__",
+                            "__init_qt__.cc", "");
+}
+
+#if 0
+
+//////////////////////////////////////////////////////////////////////////////
+
+static QStringList makeFilterSpecs (const Cell& filters)
+{
+  using namespace QtHandles::Utils;
+
+  QStringList filterSpecs;
+  QRegExp parenRe (" ?\\(.*\\)\\s*$");
+
+  for (int i = 0; i < filters.rows (); i++)
+    {
+      QStringList extList =
+        fromStdString (filters(i, 0).string_value ()).split (";");
+      QString desc = fromStdString (filters(i, 1).string_value ()).trimmed ();
+      QString specItem;
+
+      if (desc.contains (parenRe))
+        {
+          // We need to strip any existing parenthesis and recreate it.
+          // In case the format specified in the () section is not correct,
+          // the filters won't work as expected.
+          desc.remove (parenRe);
+        }
+
+      specItem = QString ("%1 (%2)").arg (desc).arg (extList.join (" "));
+
+      filterSpecs.append (specItem);
+    }
+
+  return filterSpecs;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static QString appendDirSep (const QString& d)
+{
+  if (! d.endsWith ("/") && ! d.endsWith (QDir::separator ()))
+    return (d + "/");
+  return d;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEFUN (__uigetfile_qt__, args, , "")
+{
+  using namespace QtHandles::Utils;
+
+  // Expected arguments:
+  //   args(0) : File filter as a cell array {ext1, name1; ext2, name2; ...}
+  //   args(1) : Dialog title
+  //   args(2) : Default file name
+  //   args(3) : Dialog position [ignored]
+  //   args(4) : Multiselection "on"/"off"
+  //   args(5) : Default directory
+
+  octave_value_list retval (3);
+
+  QString caption = fromStdString (args(1).string_value ());
+  QString defaultDirectory = fromStdString (args(5).string_value ());
+  QString defaultFileName = fromStdString (args(2).string_value ());
+  bool isMultiSelect = (args(4).string_value () == "on");
+
+  if (isMultiSelect)
+    retval(0) = Cell ();
+  else
+    retval(0) = "";
+  retval(1) = "";
+  retval(2) = static_cast<double> (0);
+
+  if (defaultFileName.isEmpty ())
+    defaultFileName = defaultDirectory;
+  else
+    defaultFileName = defaultDirectory + "/" + defaultFileName;
+  
+  QStringList filterSpecs = makeFilterSpecs (args(0).cell_value ());
+
+  if (isMultiSelect)
+    {
+      QString filter;
+      QStringList files =
+        QFileDialog::getOpenFileNames (0, caption, defaultFileName,
+				       filterSpecs.join (";;"), &filter, 0);
+
+      if (! files.isEmpty ())
+	{
+	  Cell cFiles (1, files.length ());
+	  QString dirName;
+	  int i = 0;
+
+	  foreach (const QString& s, files)
+	    {
+	      QFileInfo fi (s);
+
+	      if (dirName.isEmpty ())
+		dirName = appendDirSep (fi.canonicalPath ());
+	      cFiles(i++) = toStdString (fi.fileName ());
+	    }
+
+	  retval(0) = cFiles;
+	  retval(1) = toStdString (dirName);
+	  if (! filter.isEmpty ())
+	    retval(2) = static_cast<double> (filterSpecs.indexOf (filter) + 1);
+	}
+    }
+  else
+    {
+      QString filter;
+      QString fileName =
+        QFileDialog::getOpenFileName (0, caption, defaultFileName,
+				      filterSpecs.join (";;"), &filter, 0);
+
+      if (! fileName.isNull ())
+	{
+	  QFileInfo fi (fileName);
+
+	  retval(0) = toStdString (fi.fileName ());
+	  retval(1) = toStdString (appendDirSep (fi.canonicalPath ()));
+	  if (! filter.isEmpty ())
+	    retval(2) = static_cast<double> (filterSpecs.indexOf (filter) + 1);
+	}
+    }
+
+  return retval;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEFUN (__uiputfile_qt__, args, , "")
+{
+  using namespace QtHandles::Utils;
+
+  // Expected arguments:
+  //   args(0) : File filter as a cell array {ext1, name1; ext2, name2; ...}
+  //   args(1) : Dialog title
+  //   args(2) : Default file name
+  //   args(3) : Dialog position [ignored]
+  //   args(4) : Tag [ignored]
+  //   args(5) : Default directory
+
+  octave_value_list retval (3);
+
+  QString caption = fromStdString (args(1).string_value ());
+  QString defaultDirectory = fromStdString (args(5).string_value ());
+  QString defaultFileName = fromStdString (args(2).string_value ());
+
+  retval(0) = "";
+  retval(1) = "";
+  retval(2) = static_cast<double> (0);
+
+  if (defaultFileName.isEmpty ())
+    defaultFileName = defaultDirectory;
+  else
+    defaultFileName = defaultDirectory + "/" + defaultFileName;
+  
+  QStringList filterSpecs = makeFilterSpecs (args(0).cell_value ());
+
+  QString filter;
+  QString fileName =
+    QFileDialog::getSaveFileName (0, caption, defaultFileName,
+				  filterSpecs.join (";;"), &filter, 0);
+
+  if (! fileName.isNull ())
+    {
+      QFileInfo fi (fileName);
+
+      retval(0) = toStdString (fi.fileName ());
+      if (fi.exists ())
+	retval(1) = toStdString (appendDirSep (fi.canonicalPath ()));
+      else
+	retval(1) = toStdString (appendDirSep (fi.absolutePath ()));
+      if (! filter.isEmpty ())
+	retval(2) = static_cast<double> (filterSpecs.indexOf (filter) + 1);
+    }
+
+  return retval;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEFUN (__uigetdir_qt__, args, , "")
+{
+  using namespace QtHandles::Utils;
+
+  // Expected arguments:
+  //   args(0) : Start directory
+  //   args(1) : Dialog title
+
+  octave_value retval ("");
+
+  QString caption = fromStdString (args(1).string_value ());
+  QString defaultDirectory = fromStdString (args(0).string_value ());
+
+  QString dirName = QFileDialog::getExistingDirectory (0, caption,
+						       defaultDirectory);
+
+  if (! dirName.isNull ())
+    retval = toStdString (dirName);
+
+  return retval;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/__init_qt__.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,42 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_init_qt__
+#define __QtHandles_init_qt__ 1
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace QtHandles
+{
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool __init__ (void);
+
+//////////////////////////////////////////////////////////////////////////////
+
+}; // namespace QtHandles
+
+extern void install___init_qt___functions (void);
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/gl-select.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,202 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gl-select.h"
+
+#include <iostream>
+
+void
+opengl_selector::apply_pick_matrix (void)
+{
+  GLdouble p_matrix[16];
+  GLint viewport[4];
+
+  glGetDoublev (GL_PROJECTION_MATRIX, p_matrix);
+  glGetIntegerv (GL_VIEWPORT, viewport);
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  gluPickMatrix (xp, yp, size, size, viewport);
+  glMultMatrixd (p_matrix);
+  glMatrixMode (GL_MODELVIEW);
+}
+
+void
+opengl_selector::setup_opengl_transformation (const axes::properties& props)
+{
+  opengl_renderer::setup_opengl_transformation (props);
+  apply_pick_matrix ();
+}
+
+void
+opengl_selector::init_marker (const std::string& m, double size, float width)  
+{
+  opengl_renderer::init_marker (m, size, width);
+  apply_pick_matrix ();
+}
+
+# define BUFFER_SIZE 128
+
+graphics_object
+opengl_selector::select (const graphics_object& ax, int x, int y, int flags)
+{
+  glEnable (GL_DEPTH_TEST);
+  glDepthFunc (GL_LEQUAL);
+
+  xp = x;
+  yp = y;
+
+  GLuint select_buffer[BUFFER_SIZE];
+
+  glSelectBuffer (BUFFER_SIZE, select_buffer);
+  glRenderMode (GL_SELECT);
+  glInitNames ();
+
+  object_map.clear ();
+
+  draw (ax);
+
+  int hits = glRenderMode (GL_RENDER);
+  graphics_object obj;
+
+  if (hits > 0)
+    {
+      GLuint current_minZ = 0xffffffff;
+      GLuint current_name = 0xffffffff;
+
+      for (int i = 0, j = 0; i < hits && j < BUFFER_SIZE-3; i++)
+        {
+          GLuint n = select_buffer[j++],
+                 minZ = select_buffer[j++];
+
+          j++; // skip maxZ
+          if (((flags & select_last) == 0 && (minZ <= current_minZ)) ||
+              ((flags & select_last) != 0 && (minZ >= current_minZ)))
+            {
+              bool candidate = true;
+              GLuint name =
+                select_buffer[std::min (j + n, GLuint (BUFFER_SIZE)) - 1];
+
+              if ((flags & select_ignore_hittest) == 0)
+                {
+                  graphics_object go = object_map[name];
+
+                  if (! go.get_properties ().is_hittest ())
+                    candidate = false;
+                }
+
+              if (candidate)
+                {
+                  current_minZ = minZ;
+                  current_name = name;
+                }
+
+              j += n;
+            }
+          else
+            j += n;
+        }
+
+      if (current_name != 0xffffffff)
+        obj = object_map[current_name];
+    }
+  else if (hits < 0)
+    warning ("opengl_selector::select: selection buffer overflow");
+
+  object_map.clear ();
+
+  return obj;
+}
+
+void
+opengl_selector::draw (const graphics_object& go, bool toplevel)
+{
+  GLuint name = object_map.size ();
+
+  object_map[name] = go;
+  glPushName (name);
+  opengl_renderer::draw (go, toplevel);
+  glPopName ();
+}
+
+void
+opengl_selector::fake_text (double x, double y, double z, const Matrix& bbox,
+                            bool use_scale)
+{
+  ColumnVector xpos, xp1, xp2;
+
+  xpos = get_transform ().transform (x, y, z, use_scale);
+
+  xp1 = xp2 = xpos;
+  xp1(0) += bbox(0);
+  xp1(1) -= bbox(1);
+  xp2(0) += (bbox(0) + bbox(2));
+  xp2(1) -= (bbox(1) + bbox(3));
+
+  ColumnVector p1, p2, p3, p4;
+
+  p1 = get_transform ().untransform (xp1(0), xp1(1), xp1(2), false);
+  p2 = get_transform ().untransform (xp2(0), xp1(1), xp1(2), false);
+  p3 = get_transform ().untransform (xp2(0), xp2(1), xp1(2), false);
+  p4 = get_transform ().untransform (xp1(0), xp2(1), xp1(2), false);
+
+  glBegin (GL_QUADS);
+  glVertex3dv (p1.data ());
+  glVertex3dv (p2.data ());
+  glVertex3dv (p3.data ());
+  glVertex3dv (p4.data ());
+  glEnd ();
+}
+
+void
+opengl_selector::draw_text (const text::properties& props)
+{
+  if (props.get_string ().is_empty ())
+    return;
+
+  Matrix pos = props.get_data_position ();
+  const Matrix bbox = props.get_extent_matrix ();
+
+  fake_text (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0, bbox);
+}
+
+Matrix
+opengl_selector::render_text (const std::string& txt,
+                              double x, double y, double z,
+                              int halign, int valign, double rotation)
+{
+#if HAVE_FREETYPE
+  uint8NDArray pixels;
+  Matrix bbox;
+
+  // FIXME: probably more efficient to only compute bbox instead
+  //        of doing full text rendering...
+  text_to_pixels (txt, pixels, bbox, halign, valign, rotation);
+  fake_text (x, y, z, bbox, false);
+
+  return bbox;
+#else
+  return Matrix (1, 4, 0.0);
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/gl-select.h	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,75 @@
+/*
+
+Copyright (C) 2011 Michael Goffioul.
+
+This file is part of QtHandles.
+
+Foobar is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+QtHandles is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __QtHandles_gl_selector__
+#define __QtHandles_gl_selector__ 1
+
+#include "gl-render.h"
+
+#include <map>
+
+enum select_flags
+{
+  select_ignore_hittest  = 0x01,
+  select_last            = 0x02
+};
+
+class opengl_selector : public opengl_renderer
+{
+public:
+  opengl_selector (void) : size (5) { }
+
+  virtual ~opengl_selector (void) { }
+
+  graphics_object select (const graphics_object& ax, int x, int y,
+                          int flags = 0);
+
+  virtual void draw (const graphics_object& go, bool toplevel = true);
+
+protected:
+  virtual void draw_text (const text::properties& props);
+
+  virtual void setup_opengl_transformation (const axes::properties& props);
+
+  virtual void init_marker (const std::string& m, double size, float width);
+
+  virtual Matrix render_text (const std::string& txt,
+                              double x, double y, double z,
+                              int halign, int valign, double rotation = 0.0);
+
+private:
+  void apply_pick_matrix (void);
+
+  void fake_text (double x, double y, double z, const Matrix& bbox,
+                  bool use_scale = true);
+
+private:
+  // The mouse coordinate of the selection/picking point
+  int xp, yp;
+
+  // The size (in pixels) of the picking window
+  int size;
+
+  // The OpenGL name mapping
+  std::map<GLuint, graphics_object> object_map;
+};
+
+#endif // __QtHandles_gl_selector__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/images/README	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,10 @@
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+This copyright and license notice covers the images in this directory.
+************************************************************************
+
+TITLE:	Crystal Project Icons
+AUTHOR:	Everaldo Coelho
+SITE:	http://www.everaldo.com
+CONTACT: everaldo@everaldo.com
+
+Copyright (c)  2006-2007  Everaldo Coelho.
Binary file libgui/graphics/images/pan.png has changed
Binary file libgui/graphics/images/rotate.png has changed
Binary file libgui/graphics/images/select.png has changed
Binary file libgui/graphics/images/zoom.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/module.mk	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,131 @@
+EXTRA_DIST += \
+  graphics/module.mk \
+  graphics/qthandles.qrc \
+  graphics/images/README \
+  graphics/images/pan.png \
+  graphics/images/rotate.png \
+  graphics/images/select.png \
+  graphics/images/zoom.png
+
+octave_gui_MOC += \
+  graphics/moc-Backend.cc \
+  graphics/moc-ButtonControl.cc \
+  graphics/moc-ContextMenu.cc \
+  graphics/moc-EditControl.cc \
+  graphics/moc-Figure.cc \
+  graphics/moc-FigureWindow.cc \
+  graphics/moc-ListBoxControl.cc \
+  graphics/moc-Menu.cc \
+  graphics/moc-MouseModeActionGroup.cc \
+  graphics/moc-Object.cc \
+  graphics/moc-ObjectFactory.cc \
+  graphics/moc-ObjectProxy.cc \
+  graphics/moc-PopupMenuControl.cc \
+  graphics/moc-PushTool.cc \
+  graphics/moc-SliderControl.cc \
+  graphics/moc-TextEdit.cc \
+  graphics/moc-ToggleTool.cc \
+  graphics/moc-ToolBar.cc
+
+octave_gui_graphics_RC = graphics/qrc-qthandles.cc
+
+noinst_HEADERS += \
+  graphics/__init_qt__.h \
+  graphics/Backend.h \
+  graphics/BaseControl.h \
+  graphics/ButtonControl.h \
+  graphics/Canvas.h \
+  graphics/CheckBoxControl.h \
+  graphics/Container.h \
+  graphics/ContextMenu.h \
+  graphics/EditControl.h \
+  graphics/Figure.h \
+  graphics/FigureWindow.h \
+  graphics/GenericEventNotify.h \
+  graphics/GLCanvas.h \
+  graphics/KeyMap.h \
+  graphics/ListBoxControl.h \
+  graphics/Logger.h \
+  graphics/Menu.h \
+  graphics/MenuContainer.h \
+  graphics/MouseModeActionGroup.h \
+  graphics/Object.h \
+  graphics/ObjectFactory.h \
+  graphics/ObjectProxy.h \
+  graphics/Panel.h \
+  graphics/PopupMenuControl.h \
+  graphics/PushButtonControl.h \
+  graphics/PushTool.h \
+  graphics/RadioButtonControl.h \
+  graphics/SliderControl.h \
+  graphics/TextControl.h \
+  graphics/TextEdit.h \
+  graphics/ToggleButtonControl.h \
+  graphics/ToggleTool.h \
+  graphics/ToolBar.h \
+  graphics/Utils.h \
+  graphics/gl-select.h
+
+graphics_libgui_graphics_la_SOURCES = \
+  graphics/__init_qt__.cc \
+  graphics/Backend.cc \
+  graphics/BaseControl.cc \
+  graphics/ButtonControl.cc \
+  graphics/Canvas.cc \
+  graphics/CheckBoxControl.cc \
+  graphics/Container.cc \
+  graphics/ContextMenu.cc \
+  graphics/EditControl.cc \
+  graphics/Figure.cc \
+  graphics/FigureWindow.cc \
+  graphics/GLCanvas.cc \
+  graphics/KeyMap.cc \
+  graphics/ListBoxControl.cc \
+  graphics/Logger.cc \
+  graphics/Menu.cc \
+  graphics/MouseModeActionGroup.cc \
+  graphics/Object.cc \
+  graphics/ObjectFactory.cc \
+  graphics/ObjectProxy.cc \
+  graphics/Panel.cc \
+  graphics/PopupMenuControl.cc \
+  graphics/PushButtonControl.cc \
+  graphics/PushTool.cc \
+  graphics/RadioButtonControl.cc \
+  graphics/SliderControl.cc \
+  graphics/TextControl.cc \
+  graphics/TextEdit.cc \
+  graphics/ToggleButtonControl.cc \
+  graphics/ToggleTool.cc \
+  graphics/ToolBar.cc \
+  graphics/Utils.cc \
+  graphics/gl-select.cc
+
+nodist_graphics_libgui_graphics_la_SOURCES = $(octave_gui_graphics_MOC) $(octave_gui_graphics_RC)
+
+graphics_libgui_graphics_la_CPPFLAGS = \
+  $(AM_CPPFLAGS) \
+  $(FONTCONFIG_CPPFLAGS) \
+  @OCTGUI_DLL_DEFS@ \
+  @QT_CPPFLAGS@ \
+  -Igraphics -I$(srcdir)/graphics \
+  -I$(top_srcdir)/liboctave/cruft/misc \
+  -I$(top_srcdir)/liboctave/array \
+  -I$(top_builddir)/liboctave/numeric -I$(top_srcdir)/liboctave/numeric \
+  -I$(top_builddir)/liboctave/operators -I$(top_srcdir)/liboctave/operators \
+  -I$(top_srcdir)/liboctave/system \
+  -I$(top_srcdir)/liboctave/util \
+  -I$(top_builddir)/libinterp -I$(top_srcdir)/libinterp \
+  -I$(top_builddir)/libinterp/parse-tree -I$(top_srcdir)/libinterp/parse-tree \
+  -I$(top_builddir)/libinterp/corefcn -I$(top_srcdir)/libinterp/corefcn \
+  -I$(top_srcdir)/libinterp/octave-value
+
+graphics_libgui_graphics_la_CFLAGS = $(AM_CFLAGS) $(WARN_CFLAGS)
+
+graphics_libgui_graphics_la_CXXFLAGS = $(AM_CXXFLAGS) $(WARN_CXXFLAGS)
+
+noinst_LTLIBRARIES += graphics/libgui-graphics.la
+
+CLEANFILES += \
+  $(octave_gui_graphics_MOC) \
+  $(octave_gui_graphics_RC)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/qthandles.qrc	Thu Feb 20 14:05:45 2014 -0500
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+  <file>images/pan.png</file>
+  <file>images/rotate.png</file>
+  <file>images/select.png</file>
+  <file>images/zoom.png</file>
+</qresource>
+</RCC>
--- a/libgui/src/main-window.cc	Thu Feb 20 16:18:02 2014 +0100
+++ b/libgui/src/main-window.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -52,6 +52,8 @@
 #include "main-window.h"
 #include "settings-dialog.h"
 
+#include "__init_qt__.h"
+
 #include "Array.h"
 #include "cmd-edit.h"
 #include "url-transfer.h"
@@ -1256,8 +1258,11 @@
 
   octave_link::post_event (this, &main_window::resize_command_window_callback);
 
+  install___init_qt___functions ();
+
+  Fregister_graphics_toolkit (ovl ("qt"));
+
   set_global_shortcuts (true);
-
 }
 
 
--- a/libgui/src/module.mk	Thu Feb 20 16:18:02 2014 +0100
+++ b/libgui/src/module.mk	Thu Feb 20 14:05:45 2014 -0500
@@ -173,12 +173,14 @@
 
 src_libgui_src_la_CPPFLAGS = \
   $(AM_CPPFLAGS) \
+  $(FONTCONFIG_CPPFLAGS) \
   @OCTGUI_DLL_DEFS@ \
   @QT_CPPFLAGS@ \
   -I$(srcdir)/qterminal/libqterminal \
   -Isrc -I$(srcdir)/src \
   -I$(srcdir)/src/m-editor \
   -I$(srcdir)/src/qtinfo \
+  -I$(srcdir)/graphics \
   -I$(top_srcdir)/liboctave/cruft/misc \
   -I$(top_srcdir)/liboctave/array \
   -I$(top_builddir)/liboctave/numeric -I$(top_srcdir)/liboctave/numeric \
--- a/libinterp/corefcn/graphics.cc	Thu Feb 20 16:18:02 2014 +0100
+++ b/libinterp/corefcn/graphics.cc	Thu Feb 20 14:05:45 2014 -0500
@@ -9587,7 +9587,9 @@
 gtk_manager::gtk_manager (void)
   : dtk (), available_toolkits (), loaded_toolkits ()
 {
-#if defined (HAVE_FLTK)
+#if defined (HAVE_QT)
+  dtk = display_info::display_available () ? "qt" : "gnuplot";
+#elif defined (HAVE_FLTK)
   dtk = display_info::display_available () ? "fltk" : "gnuplot";
 #else
   dtk = "gnuplot";