mx/tests/test-widgets.c

493 lines
14 KiB
C

/*
* Copyright 2011 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
#include <mx/mx.h>
#include <stdlib.h>
#include <string.h>
static struct
{
MxApplication *app;
ClutterActor *table;
ClutterActor *frame;
ClutterActor *inspector;
} data;
/* skip properties that have no effect or could cause other problems */
static gchar *skip_properties[] = {
"fixed-position-set",
"fixed-x",
"fixed-y",
"height",
"min-height",
"min-height-set",
"min-width",
"min-width-set",
"natural-height",
"natural-height-set",
"natural-width",
"natural-width-set",
"request-mode",
"show-on-parent-set",
"width",
"x",
"y"
};
static gboolean
num_to_string (GBinding *binding,
const GValue *source_value,
GValue *target_value,
gpointer userdata)
{
gchar *string;
if (G_VALUE_HOLDS_INT (source_value))
string = g_strdup_printf ("%d", g_value_get_int (source_value));
else if (G_VALUE_HOLDS_UINT (source_value))
string = g_strdup_printf ("%d", g_value_get_uint (source_value));
else if (G_VALUE_HOLDS_DOUBLE (source_value))
string = g_strdup_printf ("%.2f", g_value_get_double (source_value));
else if (G_VALUE_HOLDS_FLOAT (source_value))
string = g_strdup_printf ("%.2f", g_value_get_float (source_value));
else
return FALSE;
g_value_take_string (target_value, string);
return TRUE;
}
static gboolean
string_to_num (GBinding *binding,
const GValue *source_value,
GValue *target_value,
gpointer userdata)
{
if (G_VALUE_HOLDS_INT (target_value))
g_value_set_int (target_value,
atoi (g_value_get_string (source_value)));
else if (G_VALUE_HOLDS_UINT (target_value))
g_value_set_uint (target_value,
atoi (g_value_get_string (source_value)));
else if (G_VALUE_HOLDS_DOUBLE (target_value))
g_value_set_double (target_value,
strtod (g_value_get_string (source_value), NULL));
else if (G_VALUE_HOLDS_FLOAT (target_value))
g_value_set_float (target_value,
strtof (g_value_get_string (source_value), NULL));
else
return FALSE;
return TRUE;
}
static ClutterActor *
create_property_editor (GObject *object,
GParamSpec *pspec)
{
ClutterActor *box, *label, *value;
gint i;
/* skip properties that are not writable */
if (!(pspec->flags & G_PARAM_WRITABLE))
return NULL;
/* skip other properties */
for (i = 0; i < G_N_ELEMENTS (skip_properties); i++)
{
if (g_str_equal (pspec->name, skip_properties[i]))
return NULL;
}
box = mx_box_layout_new ();
label = mx_label_new_with_text (pspec->name);
clutter_actor_set_width (label, 150);
clutter_container_add_actor (CLUTTER_CONTAINER (box), label);
if (pspec->value_type == G_TYPE_BOOLEAN)
{
value = mx_toggle_new ();
g_object_bind_property (object, pspec->name, value, "active",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
}
else if (pspec->value_type == G_TYPE_STRING)
{
value = mx_entry_new ();
g_object_bind_property (object, pspec->name, value, "text",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
}
else if (pspec->value_type == G_TYPE_INT || pspec->value_type == G_TYPE_UINT
|| pspec->value_type == G_TYPE_FLOAT
|| pspec->value_type == G_TYPE_DOUBLE)
{
value = mx_entry_new ();
g_object_bind_property_full (object, pspec->name, value, "text",
G_BINDING_BIDIRECTIONAL
| G_BINDING_SYNC_CREATE,
num_to_string,
string_to_num,
NULL, NULL);
}
else if (g_type_is_a (pspec->value_type, G_TYPE_ENUM))
{
GEnumValue *evalue;
GEnumClass *eclass;
gint init = 0;
value = mx_combo_box_new ();
clutter_actor_set_width (value, 100);
eclass = g_type_class_ref (pspec->value_type);
while ((evalue = g_enum_get_value (eclass, init)))
{
mx_combo_box_append_text (MX_COMBO_BOX (value), evalue->value_nick);
init++;
}
g_type_class_unref (eclass);
g_object_bind_property (object, pspec->name, value, "index",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
}
else
value = NULL;
if (value)
{
clutter_container_add_actor (CLUTTER_CONTAINER (box), value);
return box;
}
else
return NULL;
}
static void
change_widget (MxComboBox *box,
GParamSpec *pspec,
gpointer userdata)
{
GObjectClass *class;
const gchar *typename;
guint id;
ClutterActor *actor, *vbox;
GParamSpec **properties;
guint n_properties;
gint i;
/* test the destroy sequence */
if (mx_bin_get_child (MX_BIN (data.frame)))
clutter_actor_destroy (mx_bin_get_child (MX_BIN (data.frame)));
typename = mx_combo_box_get_active_text (box);
id = g_type_from_name (typename);
actor = g_object_new (id, NULL);
class = G_OBJECT_GET_CLASS (actor);
mx_bin_set_child (MX_BIN (data.frame), actor);
if (data.inspector)
clutter_actor_destroy (data.inspector);
vbox = mx_box_layout_new ();
mx_box_layout_set_orientation (MX_BOX_LAYOUT (vbox),
MX_ORIENTATION_VERTICAL);
properties = g_object_class_list_properties (class, &n_properties);
for (i = n_properties - 1; i >= 0; i--)
{
ClutterActor *editor;
editor = create_property_editor (G_OBJECT (actor), properties[i]);
/* set a default value for label or text property */
if (g_str_equal (properties[i]->name, "label")
|| g_str_equal (properties[i]->name, "text"))
g_object_set (actor, properties[i]->name, typename, NULL);
if (editor)
clutter_container_add_actor (CLUTTER_CONTAINER (vbox), editor);
}
/* set up various widgets as needed */
if (g_str_equal (typename, "MxIcon"))
g_object_set (actor, "icon-name", "face-smile", NULL);
else if (g_str_equal (typename, "MxComboBox"))
{
mx_combo_box_set_active_text (MX_COMBO_BOX (actor), "MxComboBox");
mx_combo_box_append_text (MX_COMBO_BOX (actor), "Item 1");
mx_combo_box_append_text (MX_COMBO_BOX (actor), "Item 2");
mx_combo_box_append_text (MX_COMBO_BOX (actor), "Item 3");
}
else if (g_str_equal (typename, "MxPathBar"))
{
mx_path_bar_push (MX_PATH_BAR (actor), "Mx");
mx_path_bar_push (MX_PATH_BAR (actor), "Path");
mx_path_bar_push (MX_PATH_BAR (actor), "Bar");
}
else if (g_str_equal (typename, "MxProgressBar"))
{
mx_progress_bar_set_progress (MX_PROGRESS_BAR (actor), 0.6);
}
else if (g_str_equal (typename, "MxScrollBar"))
{
mx_scroll_bar_set_adjustment (MX_SCROLL_BAR (actor),
mx_adjustment_new_with_values (10, 0, 100,
10, 25, 25));
}
data.inspector = mx_scroll_view_new ();
clutter_actor_set_width (data.inspector, 300);
clutter_container_add_actor (CLUTTER_CONTAINER (data.inspector), vbox);
mx_table_add_actor_with_properties (MX_TABLE (data.table), data.inspector,
0, 1,
"x-expand", FALSE,
NULL);
}
static ClutterActor*
create_combo_box (gchar *selected_widget)
{
ClutterActor *combo;
gint i, set_index = 0;
gchar *needle;
GType types[] = {
mx_button_get_type (),
mx_combo_box_get_type (),
mx_entry_get_type (),
mx_icon_get_type (),
mx_label_get_type (),
mx_path_bar_get_type (),
mx_progress_bar_get_type (),
mx_scroll_bar_get_type (),
mx_slider_get_type (),
mx_toggle_get_type (),
mx_spinner_get_type (),
};
combo = mx_combo_box_new ();
if (selected_widget)
needle = g_ascii_strdown (selected_widget, -1);
else
needle = NULL;
for (i = 0; i < G_N_ELEMENTS (types); i++)
{
gchar *haystack;
haystack = g_ascii_strdown (g_type_name (types[i]), -1);
if (needle && strstr (haystack, needle))
set_index = i;
g_free (haystack);
mx_combo_box_append_text (MX_COMBO_BOX (combo), g_type_name (types[i]));
}
g_free (needle);
g_signal_connect (combo, "notify::index", G_CALLBACK (change_widget), NULL);
mx_combo_box_set_index (MX_COMBO_BOX (combo), set_index);
return combo;
}
static void
rotate_left_clicked_cb (ClutterActor *button,
MxWindow *window)
{
MxWindowRotation rotation = mx_window_get_window_rotation (window);
switch (rotation)
{
case MX_WINDOW_ROTATION_0:
rotation = MX_WINDOW_ROTATION_270;
break;
case MX_WINDOW_ROTATION_90:
rotation = MX_WINDOW_ROTATION_0;
break;
case MX_WINDOW_ROTATION_180:
rotation = MX_WINDOW_ROTATION_90;
break;
case MX_WINDOW_ROTATION_270:
rotation = MX_WINDOW_ROTATION_180;
break;
}
mx_window_set_window_rotation (window, rotation);
}
static void
rotate_right_clicked_cb (ClutterActor *button,
MxWindow *window)
{
MxWindowRotation rotation = mx_window_get_window_rotation (window);
switch (rotation)
{
case MX_WINDOW_ROTATION_0:
rotation = MX_WINDOW_ROTATION_90;
break;
case MX_WINDOW_ROTATION_90:
rotation = MX_WINDOW_ROTATION_180;
break;
case MX_WINDOW_ROTATION_180:
rotation = MX_WINDOW_ROTATION_270;
break;
case MX_WINDOW_ROTATION_270:
rotation = MX_WINDOW_ROTATION_0;
break;
}
mx_window_set_window_rotation (window, rotation);
}
static void
rotate_180_clicked_cb (ClutterActor *button,
MxWindow *window)
{
MxWindowRotation rotation = mx_window_get_window_rotation (window);
switch (rotation)
{
case MX_WINDOW_ROTATION_0:
rotation = MX_WINDOW_ROTATION_180;
break;
case MX_WINDOW_ROTATION_90:
rotation = MX_WINDOW_ROTATION_270;
break;
case MX_WINDOW_ROTATION_180:
rotation = MX_WINDOW_ROTATION_0;
break;
case MX_WINDOW_ROTATION_270:
rotation = MX_WINDOW_ROTATION_90;
break;
}
mx_window_set_window_rotation (window, rotation);
}
static ClutterActor *
create_rotate_box (MxWindow *window)
{
ClutterActor *button, *icon, *icon2, *layout2;
ClutterActor *layout = mx_box_layout_new ();
/* Create rotate-left button */
icon = mx_icon_new ();
mx_icon_set_icon_name (MX_ICON (icon), "object-rotate-left");
mx_icon_set_icon_size (MX_ICON (icon), 16);
button = mx_button_new ();
mx_bin_set_child (MX_BIN (button), icon);
g_signal_connect (button, "clicked",
G_CALLBACK (rotate_left_clicked_cb), window);
clutter_container_add_actor (CLUTTER_CONTAINER (layout), button);
/* Create rotate-180 button */
icon = mx_icon_new ();
mx_icon_set_icon_name (MX_ICON (icon), "object-rotate-left");
mx_icon_set_icon_size (MX_ICON (icon), 16);
icon2 = mx_icon_new ();
mx_icon_set_icon_name (MX_ICON (icon2), "object-rotate-right");
mx_icon_set_icon_size (MX_ICON (icon2), 16);
layout2 = mx_box_layout_new ();
clutter_container_add (CLUTTER_CONTAINER (layout2), icon, icon2, NULL);
button = mx_button_new ();
mx_bin_set_child (MX_BIN (button), layout2);
g_signal_connect (button, "clicked",
G_CALLBACK (rotate_180_clicked_cb), window);
clutter_container_add_actor (CLUTTER_CONTAINER (layout), button);
/* Create rotate-right button */
icon = mx_icon_new ();
mx_icon_set_icon_name (MX_ICON (icon), "object-rotate-right");
mx_icon_set_icon_size (MX_ICON (icon), 16);
button = mx_button_new ();
mx_bin_set_child (MX_BIN (button), icon);
g_signal_connect (button, "clicked",
G_CALLBACK (rotate_right_clicked_cb), window);
clutter_container_add_actor (CLUTTER_CONTAINER (layout), button);
return layout;
}
int
main (int argc, char **argv)
{
MxApplication *application;
MxWindow *window;
ClutterActor *box;
MxToolbar *toolbar;
gchar *selected_widget;
application = mx_application_new (&argc, &argv, "test-widgets", 0);
window = mx_application_create_window (application);
if (argc > 1)
selected_widget = argv[1];
else
selected_widget = NULL;
/* main content */
data.table = mx_table_new ();
data.frame = mx_frame_new ();
data.inspector = NULL;
mx_table_add_actor (MX_TABLE (data.table), data.frame, 0, 0);
mx_window_set_child (window, data.table);
/* toolbar */
box = mx_box_layout_new ();
mx_box_layout_add_actor_with_properties (MX_BOX_LAYOUT (box),
create_combo_box (selected_widget),
0,
"expand", TRUE,
"x-fill", FALSE,
"x-align", MX_ALIGN_START,
NULL);
mx_box_layout_add_actor (MX_BOX_LAYOUT (box), create_rotate_box (window), 1);
toolbar = mx_window_get_toolbar (window);
mx_bin_set_child (MX_BIN (toolbar), box);
mx_bin_set_fill (MX_BIN (toolbar), TRUE, TRUE);
/* show the window */
mx_window_show (window);
/* run the application */
mx_application_run (application);
return 0;
}