aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore3
-rw-r--r--configure.ac4
-rw-r--r--debian/changelog6
-rw-r--r--libdbusmenu-glib/menuitem.h1
-rw-r--r--libdbusmenu-gtk/Makefile.am7
-rw-r--r--libdbusmenu-gtk/client.c138
-rw-r--r--libdbusmenu-gtk/menuitem.c130
-rw-r--r--libdbusmenu-gtk/menuitem.h39
-rw-r--r--tests/test-gtk-label-server.c2
-rw-r--r--tests/test-gtk-label.json166
10 files changed, 489 insertions, 7 deletions
diff --git a/.bzrignore b/.bzrignore
index 31ac740..510b1d7 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1,5 +1,6 @@
compile
m4
+debian/compat
libdbusmenu-glib/.deps
libdbusmenu-glib/.libs
libdbusmenu-glib/dbusmenu-glib.pc
@@ -41,4 +42,4 @@ dbusmenu.xml
dbusmenu.py
mago.results
test-glib-simple-items
-debian/compat
+libdbusmenu-gtk/libdbusmenu_gtk_la-menuitem.lo
diff --git a/configure.ac b/configure.ac
index b39652e..0515fb7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,11 +1,11 @@
-AC_INIT(libdbusmenu, 0.1.0, ted@canonical.com)
+AC_INIT(libdbusmenu, 0.1.1, ted@canonical.com)
AC_COPYRIGHT([Copyright 2009 Canonical])
AC_PREREQ(2.53)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(libdbusmenu, 0.1.0)
+AM_INIT_AUTOMAKE(libdbusmenu, 0.1.1)
AM_MAINTAINER_MODE
diff --git a/debian/changelog b/debian/changelog
index 8ac6c5b..337d3d0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+libdbusmenu (0.1.1-0ubuntu1~ppa1) karmic; urgency=low
+
+ * Upstream release 0.1.1
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 03 Sep 2009 14:28:11 -0500
+
libdbusmenu (0.1.0-0ubuntu1) UNRELEASED; urgency=low
* Upstream release 0.1.0
diff --git a/libdbusmenu-glib/menuitem.h b/libdbusmenu-glib/menuitem.h
index 7806017..ebde0a0 100644
--- a/libdbusmenu-glib/menuitem.h
+++ b/libdbusmenu-glib/menuitem.h
@@ -51,6 +51,7 @@ G_BEGIN_DECLS
#define DBUSMENU_MENUITEM_SIGNAL_REALIZED_ID (g_signal_lookup(DBUSMENU_MENUITEM_SIGNAL_REALIZED, DBUSMENU_TYPE_MENUITEM))
#define DBUSMENU_MENUITEM_PROP_VISIBLE "visible"
+#define DBUSMENU_MENUITEM_PROP_SENSITIVE "sensitive"
#define DBUSMENU_MENUITEM_PROP_LABEL "label"
#define DBUSMENU_MENUITEM_PROP_ICON "icon"
#define DBUSMENU_MENUITEM_PROP_ICON_DATA "icon-data"
diff --git a/libdbusmenu-gtk/Makefile.am b/libdbusmenu-gtk/Makefile.am
index c375428..918d071 100644
--- a/libdbusmenu-gtk/Makefile.am
+++ b/libdbusmenu-gtk/Makefile.am
@@ -9,13 +9,16 @@ libdbusmenu_gtkincludedir=$(includedir)/libdbusmenu-0.1/libdbusmenu-gtk/
libdbusmenu_gtkinclude_HEADERS = \
client.h \
- menu.h
+ menu.h \
+ menuitem.h
libdbusmenu_gtk_la_SOURCES = \
client.h \
client.c \
menu.h \
- menu.c
+ menu.c \
+ menuitem.h \
+ menuitem.c
libdbusmenu_gtk_la_LDFLAGS = \
-version-info $(LIBDBUSMENU_CURRENT):$(LIBDBUSMENU_REVISION):$(LIBDBUSMENU_AGE) \
diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c
index 7271c37..44d952d 100644
--- a/libdbusmenu-gtk/client.c
+++ b/libdbusmenu-gtk/client.c
@@ -33,6 +33,7 @@ License version 3 and version 2.1 along with this program. If not, see
#include <gtk/gtk.h>
#include "client.h"
+#include "menuitem.h"
/* Prototypes */
static void dbusmenu_gtkclient_class_init (DbusmenuGtkClientClass *klass);
@@ -48,6 +49,9 @@ static gboolean new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuite
static gboolean new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
static gboolean new_item_image (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
+static void process_visible (GtkMenuItem * gmi, const gchar * value);
+static void process_sensitive (GtkMenuItem * gmi, const gchar * value);
+
/* GObject Stuff */
G_DEFINE_TYPE (DbusmenuGtkClient, dbusmenu_gtkclient, DBUSMENU_TYPE_CLIENT);
@@ -116,6 +120,18 @@ process_visible (GtkMenuItem * gmi, const gchar * value)
return;
}
+/* Process the sensitive property */
+static void
+process_sensitive (GtkMenuItem * gmi, const gchar * value)
+{
+ if (value == NULL || !g_strcmp0(value, "true")) {
+ gtk_widget_set_sensitive(GTK_WIDGET(gmi), TRUE);
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(gmi), FALSE);
+ }
+ return;
+}
+
/* Whenever we have a property change on a DbusmenuMenuitem
we need to be responsive to that. */
static void
@@ -125,6 +141,8 @@ menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * value, GtkMenu
gtk_menu_item_set_label(gmi, value);
} else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_VISIBLE)) {
process_visible(gmi, value);
+ } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_SENSITIVE)) {
+ process_sensitive(gmi, value);
}
return;
@@ -171,6 +189,7 @@ dbusmenu_gtkclient_newitem_base (DbusmenuGtkClient * client, DbusmenuMenuitem *
g_object_weak_ref(G_OBJECT(item), destoryed_dbusmenuitem_cb, gmi);
process_visible(gmi, dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_VISIBLE));
+ process_sensitive(gmi, dbusmenu_menuitem_property_get(item, DBUSMENU_MENUITEM_PROP_SENSITIVE));
if (parent != NULL) {
new_child(parent, item, dbusmenu_menuitem_get_position(item, parent), DBUSMENU_GTKCLIENT(client));
@@ -284,6 +303,8 @@ dbusmenu_gtkclient_menuitem_get (DbusmenuGtkClient * client, DbusmenuMenuitem *
return mi;
}
+/* The base type handler that builds a plain ol'
+ GtkMenuItem to represent, well, the GtkMenuItem */
static gboolean
new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
@@ -303,6 +324,8 @@ new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusmenu
return TRUE;
}
+/* Type handler for the seperators where it builds
+ a GtkSeparator to act as the GtkMenuItem */
static gboolean
new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
@@ -322,9 +345,124 @@ new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm
return TRUE;
}
+/* This handler looks at property changes for items that are
+ image menu items. */
+static void
+image_property_handle (DbusmenuMenuitem * item, const gchar * property, const gchar * value, gpointer userdata)
+{
+ /* We're only looking at these two properties here */
+ g_return_if_fail(!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON) || !g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON_DATA));
+
+ if (value == NULL || value[0] == '\0') {
+ /* This means that we're unsetting a value. */
+ /* Try to use the other one */
+ if (g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON)) {
+ property = DBUSMENU_MENUITEM_PROP_ICON_DATA;
+ } else {
+ property = DBUSMENU_MENUITEM_PROP_ICON;
+ }
+ }
+
+ /* Grab the data of the items that we've got, so that
+ we can know how things need to change. */
+ GtkMenuItem * gimi = dbusmenu_gtkclient_menuitem_get (DBUSMENU_GTKCLIENT(userdata), item);
+ if (gimi == NULL) {
+ g_warning("Oddly we're handling image properties on a menuitem that doesn't have any GTK structures associated with it.");
+ return;
+ }
+ GtkWidget * gtkimage = gtk_image_menu_item_get_image(GTK_IMAGE_MENU_ITEM(gimi));
+
+ if (!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON_DATA)) {
+ /* If we have an image already built from a name that is
+ way better than a pixbuf. Keep it. */
+ if (gtk_image_get_storage_type(GTK_IMAGE(gtkimage)) == GTK_IMAGE_ICON_NAME) {
+ return;
+ }
+ }
+
+ /* Now figure out what to change */
+ if (!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ICON)) {
+ const gchar * iconname = dbusmenu_menuitem_property_get(item, property);
+ if (iconname == NULL) {
+ /* If there is no name, by golly we want no
+ icon either. */
+ gtkimage = NULL;
+ } else {
+ /* If we don't have an image, we need to build
+ one so that we can set the name. Otherwise we
+ can just convert it to this name. */
+ if (gtkimage == NULL) {
+ gtkimage = gtk_image_new_from_icon_name(iconname, GTK_ICON_SIZE_MENU);
+ } else {
+ gtk_image_set_from_icon_name(GTK_IMAGE(gtkimage), iconname, GTK_ICON_SIZE_MENU);
+ }
+ }
+ } else {
+ GdkPixbuf * image = dbusmenu_menuitem_property_get_image(item, property);
+ if (image == NULL) {
+ /* If there is no pixbuf, by golly we want no
+ icon either. */
+ gtkimage = NULL;
+ } else {
+ /* Resize the pixbuf */
+ gint width, height;
+ gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
+ if (gdk_pixbuf_get_width(image) > width ||
+ gdk_pixbuf_get_height(image) > height) {
+ GdkPixbuf * newimage = gdk_pixbuf_scale_simple(image,
+ width,
+ height,
+ GDK_INTERP_BILINEAR);
+ g_object_unref(image);
+ image = newimage;
+ }
+
+ /* If we don't have an image, we need to build
+ one so that we can set the pixbuf. */
+ if (gtkimage == NULL) {
+ gtkimage = gtk_image_new_from_pixbuf(image);
+ } else {
+ gtk_image_set_from_pixbuf(GTK_IMAGE(gtkimage), image);
+ }
+ }
+
+ }
+
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(gimi), gtkimage);
+
+ return;
+}
+
+/* This is a type call back for the image type where
+ it uses the GtkImageMenuitem to create the menu item. */
static gboolean
new_item_image (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
+ g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
+ /* Note: not checking parent, it's reasonable for it to be NULL */
+
+ GtkMenuItem * gmi;
+ gmi = GTK_MENU_ITEM(gtk_image_menu_item_new_with_label(dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_LABEL)));
+
+ if (gmi != NULL) {
+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
+ } else {
+ return FALSE;
+ }
+
+ image_property_handle(newitem,
+ DBUSMENU_MENUITEM_PROP_ICON,
+ dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_ICON),
+ client);
+ image_property_handle(newitem,
+ DBUSMENU_MENUITEM_PROP_ICON_DATA,
+ dbusmenu_menuitem_property_get(newitem, DBUSMENU_MENUITEM_PROP_ICON_DATA),
+ client);
+ g_signal_connect(G_OBJECT(newitem),
+ DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED,
+ G_CALLBACK(image_property_handle),
+ client);
return TRUE;
}
diff --git a/libdbusmenu-gtk/menuitem.c b/libdbusmenu-gtk/menuitem.c
new file mode 100644
index 0000000..deded06
--- /dev/null
+++ b/libdbusmenu-gtk/menuitem.c
@@ -0,0 +1,130 @@
+/*
+A library to take the object model made consistent by libdbusmenu-glib
+and visualize it in GTK.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of either or both of the following licenses:
+
+1) the GNU Lesser General Public License version 3, as published by the
+Free Software Foundation; and/or
+2) the GNU Lesser General Public License version 2.1, as published by
+the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+PURPOSE. See the applicable version of the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of both the GNU Lesser General Public
+License version 3 and version 2.1 along with this program. If not, see
+<http://www.gnu.org/licenses/>
+*/
+
+#include "menuitem.h"
+
+/**
+ dbusmenu_menuitem_property_set_image:
+ @menuitem: The #DbusmenuMenuitem to set the property on.
+ @property: Name of the property to set.
+ @data: The image to place on the property.
+
+ This function takes the pixbuf that is stored in @data and
+ turns it into a base64 encoded PNG so that it can be placed
+ onto a standard #DbusmenuMenuitem property.
+
+ Return value: Whether the function was able to set the property
+ or not.
+*/
+gboolean
+dbusmenu_menuitem_property_set_image (DbusmenuMenuitem * menuitem, const gchar * property, const GdkPixbuf * data)
+{
+ g_return_val_if_fail(GDK_IS_PIXBUF(data), FALSE);
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(menuitem), FALSE);
+ g_return_val_if_fail(property != NULL && property[0] != '\0', FALSE);
+
+ GError * error = NULL;
+ gchar * png_data;
+ gsize png_data_len;
+
+ if (!gdk_pixbuf_save_to_buffer((GdkPixbuf *)data, &png_data, &png_data_len, "png", &error, NULL)) {
+ if (error == NULL) {
+ g_warning("Unable to create pixbuf data stream: %d", png_data_len);
+ } else {
+ g_warning("Unable to create pixbuf data stream: %s", error->message);
+ g_error_free(error);
+ error = NULL;
+ }
+
+ return FALSE;
+ }
+
+ gchar * prop_str = g_base64_encode((guchar *)png_data, png_data_len);
+ gboolean propreturn = FALSE;
+ propreturn = dbusmenu_menuitem_property_set(menuitem, property, prop_str);
+
+ g_free(prop_str);
+ g_free(png_data);
+
+ return propreturn;
+}
+
+/**
+ dbusmenu_menuitem_property_get_image:
+ @menuitem: The #DbusmenuMenuite to look for the property on
+ @property: The name of the property to look for.
+
+ This function looks on the menu item for a property by the
+ name of @property. If one exists it tries to turn it into
+ a #GdkPixbuf. It assumes that the property is a base64 encoded
+ PNG file like the one created by #dbusmenu_menuite_property_set_image.
+
+ Return value: A pixbuf or #NULL to signal error.
+*/
+GdkPixbuf *
+dbusmenu_menuitem_property_get_image (DbusmenuMenuitem * menuitem, const gchar * property)
+{
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(menuitem), NULL);
+ g_return_val_if_fail(property != NULL && property[0] != '\0', NULL);
+
+ const gchar * value = dbusmenu_menuitem_property_get(menuitem, property);
+
+ /* There is no icon */
+ if (value == NULL || value[0] == '\0') {
+ return NULL;
+ }
+
+ gsize length = 0;
+ guchar * icondata = g_base64_decode(value, &length);
+
+ GInputStream * input = g_memory_input_stream_new_from_data(icondata, length, NULL);
+ if (input == NULL) {
+ g_warning("Cound not create input stream from icon property data");
+ g_free(icondata);
+ return NULL;
+ }
+
+ GError * error = NULL;
+ GdkPixbuf * icon = gdk_pixbuf_new_from_stream(input, NULL, &error);
+
+ if (error != NULL) {
+ g_warning("Unable to build Pixbuf from icon data: %s", error->message);
+ g_error_free(error);
+ }
+
+ error = NULL;
+ g_input_stream_close(input, NULL, &error);
+ if (error != NULL) {
+ g_warning("Unable to close input stream: %s", error->message);
+ g_error_free(error);
+ }
+ g_free(icondata);
+
+ return icon;
+}
+
diff --git a/libdbusmenu-gtk/menuitem.h b/libdbusmenu-gtk/menuitem.h
new file mode 100644
index 0000000..ff458de
--- /dev/null
+++ b/libdbusmenu-gtk/menuitem.h
@@ -0,0 +1,39 @@
+/*
+A library to take the object model made consistent by libdbusmenu-glib
+and visualize it in GTK.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of either or both of the following licenses:
+
+1) the GNU Lesser General Public License version 3, as published by the
+Free Software Foundation; and/or
+2) the GNU Lesser General Public License version 2.1, as published by
+the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
+PURPOSE. See the applicable version of the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of both the GNU Lesser General Public
+License version 3 and version 2.1 along with this program. If not, see
+<http://www.gnu.org/licenses/>
+*/
+
+#ifndef __DBUSMENU_GTKMENUITEM_H__
+#define __DBUSMENU_GTKMENUITEM_H__ 1
+
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <libdbusmenu-glib/menuitem.h>
+
+gboolean dbusmenu_menuitem_property_set_image (DbusmenuMenuitem * menuitem, const gchar * property, const GdkPixbuf * data);
+GdkPixbuf * dbusmenu_menuitem_property_get_image (DbusmenuMenuitem * menuitem, const gchar * property);
+
+#endif
diff --git a/tests/test-gtk-label-server.c b/tests/test-gtk-label-server.c
index 7730fe2..c4d41ee 100644
--- a/tests/test-gtk-label-server.c
+++ b/tests/test-gtk-label-server.c
@@ -156,7 +156,7 @@ main (int argc, char ** argv)
server = dbusmenu_server_new("/org/test");
timer_func(NULL);
- g_timeout_add_seconds(15, timer_func, NULL);
+ g_timeout_add_seconds(5, timer_func, NULL);
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
diff --git a/tests/test-gtk-label.json b/tests/test-gtk-label.json
index 19a6ca6..14584c3 100644
--- a/tests/test-gtk-label.json
+++ b/tests/test-gtk-label.json
@@ -49,6 +49,52 @@
"label": "value29"}
]
},
+ {"id": 4, "type": "menuitem",
+ "label": "value4",
+ "submenu": [
+ {"id": 40,
+ "type": "menuitem",
+ "sensitive": "true",
+ "label": "value40"},
+ {"id": 41,
+ "type": "menuitem",
+ "sensitive": "false",
+ "label": "value41"},
+ {"id": 42,
+ "type": "menuitem",
+ "sensitive": "true",
+ "label": "value42"},
+ {"id": 43,
+ "type": "menuitem",
+ "sensitive": "false",
+ "label": "value43"},
+ {"id": 44,
+ "type": "menuitem",
+ "sensitive": "true",
+ "label": "value44"},
+ {"id": 45,
+ "type": "menuitem",
+ "sensitive": "false",
+ "label": "value45"},
+ {"id": 46,
+ "type": "menuitem",
+ "sensitive": "true",
+ "label": "value46"},
+ {"id": 47,
+ "type": "menuitem",
+ "sensitive": "false",
+ "label": "value47"},
+ {"id": 48,
+ "type": "menuitem",
+ "sensitive": "true",
+ "label": "value48"},
+ {"id": 49,
+ "type": "menuitem",
+ "visible": "false",
+ "sensitive": "false",
+ "label": "value49"}
+ ]
+ },
{"id": 3, "type": "menuitem",
"label": "a super long label that is really of unreasonable length but we should make sure it makes it across the bus",
"not.a.value": "A useless value",
@@ -154,5 +200,123 @@
]
},
]
- }
+ },
+ {"id": 8, "type": "menuitem",
+ "label": "value1",
+ "submenu": [
+ {"id": 80,
+ "type": "imageitem",
+ "icon": "face-angel",
+ "label": "angel"},
+ {"id": 81,
+ "type": "imageitem",
+ "icon": "face-angry",
+ "label": "angry"},
+ {"id": 82,
+ "type": "imageitem",
+ "icon": "face-cool",
+ "label": "cool"},
+ {"id": 83,
+ "type":"imageitem",
+ "icon": "face-devilish",
+ "label": "devilish"},
+ {"id": 84,
+ "type": "imageitem",
+ "icon": "face-embarrassed",
+ "label": "embarrassed"},
+ {"id": 85,
+ "type": "imageitem",
+ "icon": "face-kiss",
+ "label": "kiss"},
+ {"id": 86,
+ "type": "imageitem",
+ "icon": "face-laugh",
+ "label": "laugh"},
+ {"id": 87,
+ "type": "imageitem",
+ "icon": "face-monkey",
+ "label": "monkey"},
+ {"id": 88,
+ "type": "imageitem",
+ "icon": "face-sad",
+ "label": "sad"},
+ {"id": 89,
+ "type": "imageitem",
+ "icon": "face-sick",
+ "label": "sick"}
+ ]
+ },
+ {"id": 9, "type": "menuitem",
+ "label": "value1",
+ "submenu": [
+ {"id": 90,
+ "type": "imageitem",
+ "icon-data":
+"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACPUlEQVR4nGJgoBAAAAAA///Ch1gW
+BzK0LQ5iaGNgYGDBpQgAAAD//8KpeY4/Q9+DCV7/H/S4/p8byDABlyEAAAAA///CqnluAMOEx5O8
+/3/f0/P/+47m/4967P7PC2GYysDAwIquGAAAAP//YkLXPC+AodfNyStfRMuegenvdwamP98ZhJWM
+GJzNzLIWhGMaAgAAAP//YkLT3Odq75InomrBwPT7CwPDr68M//98Y2D+951BREadwdFAL3VxJMNM
+ZEMAAAAA//9ihPs5gKHPzdo2V0TNkoGZ4T/D//9/GRj+/WJg+PeT4f/vHwwMf78z/P31jeHN89sM
++6/dXpS4lCGFgYHhNwAAAP//ghkguDqC4Z0CNwMDLwsDgxAHAwOfdQrD/1+fGP5/e83w/9tbhq/P
+LjG8+8PA8PkPA8PDbwwMIXMYhBkYGN4BAAAA//80zDEOQDAAAMBLZ2MnITEafEziK2YfM/QBLDoX
+g4jJPeD+IGJAgypNlrbuvNfBcxLYb/rZiIINK/IHAAD//zTRoRHAIBAAsMAU3X8iZCUSy5W7R0EN
+rJDcmoEXFU8sVq/ko5SIDQoaJj74AQAA//+CGfADKoEIGZhmZiQ+RM0D5FgAAAAA//9Cj0aEKNRm
+uGZmrCoZAAAAAP//wm4AskZkg7AAAAAAAP//wpo8n/6A2siEoJ/+wG4AAAAA///CZq4EAwODAZRG
+Bi8YEIEIBwAAAAD//8JmAAcDA4MAlEYGPxgYGD5AaTgAAAAA//8DAD6xjTP5Y+A7AAAAAElFTkSu
+QmCC",
+ "label": "up"},
+ {"id": 91,
+ "type": "imageitem",
+ "icon-data":
+"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACl0lEQVR4nGJgoBAAAAAA//9ixCLG
+sSWS4bs0B1QWip/+YGDwWcLAycDA8ANZMQAAAP//YsFigIA0JwODdvIsBob/fxgY/vxk+P/7OwPD
+6ioGBgYGAQYGhhfIigEAAAD//8JmAAcDEwMDw5/vDAz/fjP8//uLgeHvDwYGJqgcGgAAAAD//8Jm
+AAMDIwPD/99fGBj+/WVg+PeLgeHvTwYGZqwqGQAAAAD//8JuADMDA8PPLwwMDH8Z/v//AzGACbsB
+AAAAAP//wmoAJwsDw/8/XxgY/v9l+P/rM8P/ry8ZONmwGwAAAAD//4LFAsfqaIbvCtwMDLxsDAxC
+7AwMPMqWDP+/Pmf4//01w//fXxm+/2NgePebgeHLHwaGR98ZGIKmQ2IEAAAA//80zisSQFAAAMAd
+wczzKRSvCIqrO4XqGoIkGTOv+SV7gv1j1XqY2jiI/agoSve2eM7VeyUyQk5X0gT2ZEYNHwAAAP//
+gnnhb+lWhuk//90TD1dncBThYGBgYWGA+JsRQv9lYGB4/5uBYcdDhotZSxhaGRgY/jEwMDAAAAAA
+//+CueALAwPDnZrtDK3r7jIcefuHgeEvI5JmRgaG938YGHY9YriatYShkoGB4TYDA8MnBgYGBgAA
+AAD//4IZ8JuBgeE1AwPDjfLNDE2b7jGcfPsLYutfRgaGD78ZGPY+ZrievpChjIGB4SoDA8NLqB4G
+AAAAAP//QkesDAwMMgwMDG6TwxnO3q5i+H+nhuH/nESGawwMDF4MDAzyDAwMKPEBAAAA///CZYgs
+AwODR18kw4UJ0QyX8WkGAAAA///ClpkYoAolGBgYFKBqHjAwMDxnYGD4ha4QAAAA///CZQDMEG4o
++ys2zQwMDAwAAAAA//8DAAF5nhyE7tENAAAAAElFTkSuQmCC",
+ "label": "down"},
+ {"id": 92,
+ "type": "imageitem",
+ "icon": "up",
+ "icon-data":
+"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACl0lEQVR4nGJgoBAAAAAA//9ixCLG
+sSWS4bs0B1QWip/+YGDwWcLAycDA8ANZMQAAAP//YsFigIA0JwODdvIsBob/fxgY/vxk+P/7OwPD
+6ioGBgYGAQYGhhfIigEAAAD//8JmAAcDEwMDw5/vDAz/fjP8//uLgeHvDwYGJqgcGgAAAAD//8Jm
+AAMDIwPD/99fGBj+/WVg+PeLgeHvTwYGZqwqGQAAAAD//8JuADMDA8PPLwwMDH8Z/v//AzGACbsB
+AAAAAP//wmoAJwsDw/8/XxgY/v9l+P/rM8P/ry8ZONmwGwAAAAD//4LFAsfqaIbvCtwMDLxsDAxC
+7AwMPMqWDP+/Pmf4//01w//fXxm+/2NgePebgeHLHwaGR98ZGIKmQ2IEAAAA//80zisSQFAAAMAd
+wczzKRSvCIqrO4XqGoIkGTOv+SV7gv1j1XqY2jiI/agoSve2eM7VeyUyQk5X0gT2ZEYNHwAAAP//
+gnnhb+lWhuk//90TD1dncBThYGBgYWGA+JsRQv9lYGB4/5uBYcdDhotZSxhaGRgY/jEwMDAAAAAA
+//+CueALAwPDnZrtDK3r7jIcefuHgeEvI5JmRgaG938YGHY9YriatYShkoGB4TYDA8MnBgYGBgAA
+AAD//4IZ8JuBgeE1AwPDjfLNDE2b7jGcfPsLYutfRgaGD78ZGPY+ZrievpChjIGB4SoDA8NLqB4G
+AAAAAP//QkesDAwMMgwMDG6TwxnO3q5i+H+nhuH/nESGawwMDF4MDAzyDAwMKPEBAAAA///CZYgs
+AwODR18kw4UJ0QyX8WkGAAAA///ClpkYoAolGBgYFKBqHjAwMDxnYGD4ha4QAAAA///CZQDMEG4o
++ys2zQwMDAwAAAAA//8DAAF5nhyE7tENAAAAAElFTkSuQmCC",
+ "label": "up"},
+ {"id": 93,
+ "type": "imageitem",
+ "icon": "down",
+ "icon-data":
+"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACPUlEQVR4nGJgoBAAAAAA///Ch1gW
+BzK0LQ5iaGNgYGDBpQgAAAD//8KpeY4/Q9+DCV7/H/S4/p8byDABlyEAAAAA///CqnluAMOEx5O8
+/3/f0/P/+47m/4967P7PC2GYysDAwIquGAAAAP//YkLXPC+AodfNyStfRMuegenvdwamP98ZhJWM
+GJzNzLIWhGMaAgAAAP//YkLT3Odq75InomrBwPT7CwPDr68M//98Y2D+951BREadwdFAL3VxJMNM
+ZEMAAAAA//9ihPs5gKHPzdo2V0TNkoGZ4T/D//9/GRj+/WJg+PeT4f/vHwwMf78z/P31jeHN89sM
++6/dXpS4lCGFgYHhNwAAAP//ghkguDqC4Z0CNwMDLwsDgxAHAwOfdQrD/1+fGP5/e83w/9tbhq/P
+LjG8+8PA8PkPA8PDbwwMIXMYhBkYGN4BAAAA//80zDEOQDAAAMBLZ2MnITEafEziK2YfM/QBLDoX
+g4jJPeD+IGJAgypNlrbuvNfBcxLYb/rZiIINK/IHAAD//zTRoRHAIBAAsMAU3X8iZCUSy5W7R0EN
+rJDcmoEXFU8sVq/ko5SIDQoaJj74AQAA//+CGfADKoEIGZhmZiQ+RM0D5FgAAAAA//9Cj0aEKNRm
+uGZmrCoZAAAAAP//wm4AskZkg7AAAAAAAP//wpo8n/6A2siEoJ/+wG4AAAAA///CZq4EAwODAZRG
+Bi8YEIEIBwAAAAD//8JmAAcDA4MAlEYGPxgYGD5AaTgAAAAA//8DAD6xjTP5Y+A7AAAAAElFTkSu
+QmCC",
+ "label": "down"}
+ ]
+ },
]