aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Gould <ted@canonical.com>2009-09-03 14:16:01 -0500
committerTed Gould <ted@canonical.com>2009-09-03 14:16:01 -0500
commit6738b6bfb2d6a740119da23936c941f1ab56d4fa (patch)
tree4947b7ab224de9adf430600eec915a8fe2767f65
parente7c1a0be55b9f48aa2efd74462e67181f9e7a4d2 (diff)
parentcba32423d5f5efd72e3fc3210f93ec1522c270f4 (diff)
downloadlibdbusmenu-6738b6bfb2d6a740119da23936c941f1ab56d4fa.tar.gz
libdbusmenu-6738b6bfb2d6a740119da23936c941f1ab56d4fa.tar.bz2
libdbusmenu-6738b6bfb2d6a740119da23936c941f1ab56d4fa.zip
Merging in support for image items. Including encoding and decoding the images across DBus.
-rw-r--r--.bzrignore1
-rw-r--r--libdbusmenu-gtk/Makefile.am7
-rw-r--r--libdbusmenu-gtk/client.c120
-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.json120
7 files changed, 415 insertions, 4 deletions
diff --git a/.bzrignore b/.bzrignore
index 1bac747..08391f4 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -41,3 +41,4 @@ dbusmenu.xml
dbusmenu.py
mago.results
test-glib-simple-items
+libdbusmenu-gtk/libdbusmenu_gtk_la-menuitem.lo
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 b3d55d9..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);
@@ -302,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)
{
@@ -321,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)
{
@@ -340,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 cea165c..14584c3 100644
--- a/tests/test-gtk-label.json
+++ b/tests/test-gtk-label.json
@@ -200,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"}
+ ]
+ },
]