experimental-legacy/ecdb/trunk/src/ecdb_widgets.c

762 lines
20 KiB
C

/* vim: set sw=3 ts=3 sts=3 expandtab: */
#include "ecdb.h"
static void
_widget_focus_handle(void *data, Evas_Object *o)
{
static char *old_source;
const char *name;
Evas_Object *eo;
name = data;
printf("part name: %s\n", name);
// Some widgets aren't named (such as when in combo), so check
if (!name)
return;
if ((old_source) && (strcmp(old_source, name)))
{
eo = evas_object_name_find(ecore_evas_get(em->main_win_ee), old_source);
edje_object_signal_emit(eo, "ecdb,focus,out", "ecdb");
FREE(old_source);
old_source = strdup(name);
}
else if (!old_source)
{
old_source = strdup(name);
}
// Send focus to the freshly clicked widget
evas_object_focus_set(o, 1);
}
static void
_mouse_down_edje(void *data, Evas_Object *o, const char *emission,
const char *source)
{
_widget_focus_handle(data, o);
}
static void
_mouse_down_evas(void *data, Evas *e __UNUSED__, Evas_Object *eo,
void *ev_data __UNUSED__)
{
_widget_focus_handle(data, eo);
}
void
ecdb_widget_focus_callback_add(Evas_Object *o, const char *name)
{
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN,
_mouse_down_evas, (void *)name);
}
Evas_Object *
ecdb_widget_add(Evas_Object *parent, const char *name)
{
Evas_Object *o;
int x, y, w, h;
o = edje_object_add(evas_object_evas_get(parent));
edje_object_signal_callback_add(o, "mouse,down,*", "*",
_mouse_down_edje,
(void *)name);
if (name)
{
evas_object_name_set(o, name);
edje_object_part_geometry_get(parent, name, &x, &y, &w, &h);
evas_object_move(o, x, y);
evas_object_resize(o, w, h);
edje_object_part_swallow(parent, name, o);
}
return o;
}
/************************** BUTTON ******************************************/
void
_button_click_cb_call(void *data, Evas_Object *obj, const char *emission,
const char *source)
{
evas_object_smart_callback_call(obj, "clicked", NULL);
}
Evas_Object *
ecdb_button_add(Evas_Object *parent, const char *name)
{
Evas_Object *b;
b = ecdb_widget_add(parent, name);
edje_object_file_set(b, em->theme_path, "ecdb/button");
edje_object_signal_callback_add(b, "clicked", "ecdb",
_button_click_cb_call, b);
return b;
}
void
ecdb_button_label_set(Evas_Object *b, const char *label)
{
edje_object_part_text_set(b, "ecdb.label", label);
}
void
ecdb_button_icon_set(Evas_Object *b, const char *group)
{
Evas_Object *icon;
icon = ecdb_widget_add(b, "ecdb.swallow.icon");
edje_object_file_set(icon, em->theme_path, group);
evas_object_show(icon);
}
const char *
ecdb_button_label_get(Evas_Object *b)
{
return edje_object_part_text_get(b, "ecdb.label");
}
/************************* CHECK *********************************************/
typedef struct _Check_Data Check_Data;
struct _Check_Data
{
unsigned int checked;
};
void
_check_toggle_cb_call(void *data, Evas_Object *obj, const char *emission,
const char *source)
{
Check_Data *cd;
cd = evas_object_data_get(obj, "cd");
if (!strcmp(emission, "ecdb,check,checked"))
{
evas_object_smart_callback_call(obj, "checked", NULL);
cd->checked = 1;
}
else
{
evas_object_smart_callback_call(obj, "unchecked", NULL);
cd->checked = 0;
}
}
Evas_Object *
ecdb_check_add(Evas_Object *parent, const char *name)
{
Evas_Object *c;
Check_Data *cd;
c = ecdb_widget_add(parent, name);
edje_object_file_set(c, em->theme_path, "ecdb/check");
edje_object_signal_callback_add(c, "ecdb,check,*", "ecdb",
_check_toggle_cb_call, c);
cd = calloc(1, sizeof(Check_Data));
evas_object_data_set(c, "cd", cd);
return c;
}
void
ecdb_check_label_set(Evas_Object *c, const char *label)
{
edje_object_part_text_set(c, "ecdb.label", label);
}
void
ecdb_check_states_set(Evas_Object *c, const char *ystate, const char *nstate)
{
edje_object_part_text_set(c, "ecdb.ystate", ystate);
edje_object_part_text_set(c, "ecdb.nstate", nstate);
}
void
ecdb_check_checked_set(Evas_Object *c, int state)
{
Check_Data *cd;
cd = evas_object_data_get(c, "cd");
if (state)
{
cd->checked = 1;
edje_object_signal_emit(c, "ecdb,check,on", "ecdb");
}
else
{
cd->checked = 0;
edje_object_signal_emit(c, "ecdb,check,off", "ecdb");
}
}
int
ecdb_check_checked_get(Evas_Object *c)
{
Check_Data *cd;
cd = evas_object_data_get(c, "cd");
return cd->checked;
}
/************************** ENTRY *******************************************/
/* Shamelessly stolen from Elementary... */
static char *
_entry_str_append(char *str, const char *txt, int *len, int *alloc)
{
int txt_len = strlen(txt);
if (txt_len <= 0) return str;
if ((*len + txt_len) >= *alloc)
{
char *str2;
int alloc2;
alloc2 = *alloc + txt_len + 128;
str2 = realloc(str, alloc2);
if (!str2) return str;
*alloc = alloc2;
str = str2;
}
strcpy(str + *len, txt);
*len += txt_len;
return str;
}
static char *
_entry_markup_to_text(const char *mkup)
{
char *str = NULL;
int str_len = 0, str_alloc = 0;
// FIXME: markup -> text
char *s, *p;
char *tag_start, *tag_end, *esc_start, *esc_end, *ts;
tag_start = tag_end = esc_start = esc_end = NULL;
p = (char *)mkup;
s = p;
for (;;)
{
if ((*p == 0) ||
(tag_end) || (esc_end) ||
(tag_start) || (esc_start))
{
if (tag_end)
{
char *ttag;
ttag = malloc(tag_end - tag_start);
if (ttag)
{
strncpy(ttag, tag_start + 1, tag_end - tag_start - 1);
ttag[tag_end - tag_start - 1] = 0;
/*
if (!strcmp(ttag, "br"))
str = _str_append(str, "\n", &str_len, &str_alloc);
*/
if (!strcmp(ttag, "\n"))
str = _entry_str_append(str, "\n", &str_len,
&str_alloc);
else if (!strcmp(ttag, "\\n"))
str = _entry_str_append(str, "\n", &str_len,
&str_alloc);
else if (!strcmp(ttag, "\t"))
str = _entry_str_append(str, "\t", &str_len,
&str_alloc);
else if (!strcmp(ttag, "\\t"))
str = _entry_str_append(str, "\t", &str_len,
&str_alloc);
free(ttag);
}
tag_start = tag_end = NULL;
}
else if (esc_end)
{
ts = malloc(esc_end - esc_start + 1);
if (ts)
{
const char *esc;
strncpy(ts, esc_start, esc_end - esc_start);
ts[esc_end - esc_start] = 0;
esc = evas_textblock_escape_string_get(ts);
if (esc)
str = _entry_str_append(str, esc, &str_len,
&str_alloc);
free(ts);
}
esc_start = esc_end = NULL;
}
else if (*p == 0)
{
ts = malloc(p - s + 1);
if (ts)
{
strncpy(ts, s, p - s);
ts[p - s] = 0;
str = _entry_str_append(str, ts, &str_len, &str_alloc);
free(ts);
}
s = NULL;
}
if (*p == 0)
break;
}
if (*p == '<')
{
if (!esc_start)
{
tag_start = p;
tag_end = NULL;
ts = malloc(p - s + 1);
if (ts)
{
strncpy(ts, s, p - s);
ts[p - s] = 0;
str = _entry_str_append(str, ts, &str_len, &str_alloc);
free(ts);
}
s = NULL;
}
}
else if (*p == '>')
{
if (tag_start)
{
tag_end = p;
s = p + 1;
}
}
else if (*p == '&')
{
if (!tag_start)
{
esc_start = p;
esc_end = NULL;
ts = malloc(p - s + 1);
if (ts)
{
strncpy(ts, s, p - s);
ts[p - s] = 0;
str = _entry_str_append(str, ts, &str_len, &str_alloc);
free(ts);
}
s = NULL;
}
}
else if (*p == ';')
{
if (esc_start)
{
esc_end = p;
s = p + 1;
}
}
p++;
}
return str;
}
static void
_entry_click_cb_call(void *data, Evas_Object *obj, const char *emission,
const char *source)
{
evas_object_focus_set(obj, 1);
evas_object_smart_callback_call(obj, "clicked", NULL);
}
Evas_Object *
ecdb_entry_add(Evas_Object *parent, const char *name)
{
Evas_Object *e;
e = ecdb_widget_add(parent, name);
edje_object_file_set(e, em->theme_path, "ecdb/entry");
em->evas_dnd_candidates = eina_list_append(em->evas_dnd_candidates, e);
evas_object_data_set(e, "dnd_call_func", ecdb_dnd_entry_dnd_set);
edje_object_signal_callback_add(e, "clicked", "ecdb", _entry_click_cb_call,
e);
return e;
}
void
ecdb_entry_text_set(Evas_Object *e, const char *text)
{
edje_object_part_text_set(e, "ecdb.text", text);
}
char *
ecdb_entry_text_get(Evas_Object *e)
{
return _entry_markup_to_text(edje_object_part_text_get(e, "ecdb.text"));
}
/****************************** COMBO ****************************************/
typedef struct _Combo_Data Combo_Data;
struct _Combo_Data
{
Evas_Object *parent;
Evas_Object *back;
Evas_Object *popup;
unsigned int expanded;
unsigned int count;
int selected;
const char *name;
const char *header;
void *data;
Evas_Object * (*create_header)(Evas_Object *, const char *name, void *data,
Evas_Object *, int);
};
/*
static void
_combo_min_size(Evas_Object *o, Evas_Object_Box_Data *p, void *data)
{
Eina_List *l;
Evas_Object_Box_Option *opt;
int offset_x, offset_y;
int w, h, y;
int wt, ht, xt, yt;
if (eina_list_count(p->children) <= 0)
return;
evas_object_geometry_get(o, &offset_x, &offset_y, &w, &h);
y = offset_y + (h / 2);
p->children = eina_list_nth_list(p->children, 0);
opt = eina_list_nth(p->children, 0);
h = 30;
edje_object_size_min_get(opt->obj, NULL, &h);
EINA_LIST_FOREACH(p->children, l, opt)
{
evas_object_resize(opt->obj, w, h);
evas_object_move(opt->obj, offset_x, y);
y += h;
}
}
*/
// Axis preferential -- for now vertical
const char *
_combo_best_location(Evas_Object *c)
{
int x, y, w, h;
int ww, wh;
ecore_evas_geometry_get(em->main_win_ee, NULL, NULL, &ww, &wh);
evas_object_geometry_get(c, &x, &y, &w, &h);
if ((y + h) > (wh - y - h))
{
return "top";
}
else
{
return "bottom";
}
}
static void
_combo_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
Combo_Data *cd;
cd = evas_object_data_get(data, "cd");
eina_stringshare_del(cd->name);
eina_stringshare_del(cd->header);
FREE(cd);
}
static void
_combo_resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
Combo_Data *cd;
cd = evas_object_data_get(data, "cd");
if (cd->expanded)
ecdb_combo_collapse(data);
}
static void
_combo_hide(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
Combo_Data *cd;
cd = evas_object_data_get(data, "cd");
if (cd->expanded)
ecdb_combo_collapse(data);
}
static void
_combo_clicked(void *data, Evas_Object *obj, void *event_info)
{
Combo_Data *cd;
Evas_Object *swallow, *header;
Eina_Iterator *it;
int i = 0;
cd = evas_object_data_get(data, "cd");
swallow = edje_object_part_swallow_get(data, "ecdb.header.swallow");
if (swallow)
evas_object_del(swallow);
it = evas_object_box_iterator_new(edje_object_part_object_get(cd->popup,
"ecdb.box"));
while (eina_iterator_next(it, (void **)&swallow))
{
if (swallow == obj)
break;
i++;
}
eina_iterator_free(it);
cd->selected = i;
if (cd->create_header)
header = cd->create_header(data, "ecdb.header.swallow", cd->data,
swallow, i);
edje_object_signal_emit(data, "ecdb,combo,header,swallow", "ecdb");
ecdb_combo_collapse(data);
}
static void
_combo_moveable_click_cb(void *data, Evas_Object *obj, const char *emission,
const char *source)
{
Combo_Data *cd;
cd = evas_object_data_get(data, "cd");
if (cd->expanded)
ecdb_combo_collapse(data);
}
static void
_combo_click_cb(void *data, Evas_Object *obj, const char *emission,
const char *source)
{
Evas_Object *c;
Combo_Data *cd;
c = data;
cd = evas_object_data_get(c, "cd");
if ((cd) && (!cd->expanded))
ecdb_combo_expand(c);
else
ecdb_combo_collapse(c);
evas_object_smart_callback_call(c, "clicked", NULL);
}
Evas_Object *
ecdb_combo_add(Evas_Object *parent, const char *name)
{
Evas_Object *c;
Combo_Data *cd;
c = ecdb_widget_add(parent, name);
edje_object_file_set(c, em->theme_path, "ecdb/combo");
evas_object_event_callback_add(parent, EVAS_CALLBACK_RESIZE, _combo_resize,
c);
evas_object_event_callback_add(parent, EVAS_CALLBACK_HIDE, _combo_hide, c);
evas_object_event_callback_add(c, EVAS_CALLBACK_DEL, _combo_del, c);
edje_object_signal_callback_add(c, "ecdb,combo,clicked", "ecdb",
_combo_click_cb, c);
cd = calloc(1, sizeof(Combo_Data));
cd->back = edje_object_add(evas_object_evas_get(parent));
edje_object_file_set(cd->back, em->theme_path, "ecdb/combo/background");
edje_object_signal_callback_add(cd->back, "ecdb,combo,back,dismiss", "ecdb",
_combo_moveable_click_cb, c);
evas_object_pass_events_set(cd->back, 1);
evas_object_show(cd->back);
cd->popup = edje_object_add(evas_object_evas_get(parent));
edje_object_file_set(cd->popup, em->theme_path, "ecdb/combo/popup");
edje_object_signal_callback_add(cd->back, "ecdb,combo,back,dismiss", "ecdb",
_combo_moveable_click_cb, c);
//edje_box_layout_register("min_size", _combo_min_size, NULL, NULL, NULL,
// NULL);
evas_object_pass_events_set(cd->popup, 1);
evas_object_show(cd->popup);
cd->parent = parent;
cd->name = eina_stringshare_add(name);
cd->selected = -1;
evas_object_data_set(c, "cd", cd);
return c;
}
void
ecdb_combo_header_set(Evas_Object *c, const char *text)
{
Combo_Data *cd;
cd = evas_object_data_get(c, "cd");
edje_object_part_text_set(c, "ecdb.header", text);
eina_stringshare_del(cd->header);
cd->header = eina_stringshare_add(text);
}
void
ecdb_combo_append(Evas_Object *c, Evas_Object *o)
{
Combo_Data *cd;
cd = evas_object_data_get(c, "cd");
cd->count++;
edje_object_part_box_append(cd->popup, "ecdb.box", o);
evas_object_smart_callback_add(o, "clicked", _combo_clicked, c);
}
void
ecdb_combo_expand(Evas_Object *c)
{
Combo_Data *cd;
Eina_Iterator *it;
Evas_Object *o;
const Evas_Object *box;
const char *location;
char buf[1024];
int x, y, w, h, h2, padding;
cd = evas_object_data_get(c, "cd");
if (cd->count == 0)
return;
edje_object_signal_emit(c, "ecdb,combo,active", "ecdb");
evas_object_move(cd->back, 0, 0);
ecore_evas_geometry_get(em->main_win_ee, NULL, NULL, &w, &h);
evas_object_resize(cd->back, w, h);
evas_object_pass_events_set(cd->back, 0);
evas_object_layer_set(cd->back, evas_object_layer_get(c) + 1);
edje_object_signal_emit(cd->back, "ecdb,combo,back,show", "ecdb");
location = _combo_best_location(c);
snprintf(buf, sizeof(buf), "ecdb,combo,popup,show,%s", location);
evas_object_geometry_get(c, &x, &y, &w, &h);
box = edje_object_part_object_get(cd->popup, "ecdb.box");
evas_object_box_padding_get(box, NULL, &padding);
h2 = -padding;
/* Now resize the attached object... There is code to do this in the
* layout, which makes more sense. However, it goes into an infinite loop,
* so resize here for now
*/
it = evas_object_box_iterator_new(edje_object_part_object_get(cd->popup,
"ecdb.box"));
while (eina_iterator_next(it, (void **)&o))
{
edje_object_size_min_get(o, NULL, &h);
evas_object_resize(o, w, h);
h2 += h + padding;
}
if (!strcmp(location, "top"))
evas_object_move(cd->popup, x, y - h2);
else
evas_object_move(cd->popup, x, y + h);
eina_iterator_free(it);
evas_object_resize(cd->popup, w, h2);
evas_object_pass_events_set(cd->popup, 0);
evas_object_layer_set(cd->popup, evas_object_layer_get(cd->back) + 1);
edje_object_signal_emit(cd->popup, buf, "ecdb");
cd->expanded = 1;
}
void
ecdb_combo_collapse(Evas_Object *c)
{
Combo_Data *cd;
const char *location;
char buf[1024];
// If we close the window
if ((!em) || (!em->main_win_ee))
return;
cd = evas_object_data_get(c, "cd");
edje_object_signal_emit(cd->back, "ecdb,combo,back,hide", "ecdb");
evas_object_pass_events_set(cd->back, 1);
edje_object_signal_emit(c, "ecdb,combo,default", "ecdb");
location = _combo_best_location(c);
snprintf(buf, sizeof(buf), "ecdb,combo,popup,hide,%s", location);
evas_object_pass_events_set(cd->popup, 1);
edje_object_signal_emit(cd->popup, buf, "ecdb");
cd->expanded = 0;
}
void
ecdb_combo_header_create_set(Evas_Object *c, Evas_Object * (*func)
(Evas_Object *c, const char *name,
void *data, Evas_Object *clicked, int idx))
{
Combo_Data *cd;
cd = evas_object_data_get(c, "cd");
cd->create_header = func;
}
int
ecdb_combo_selected_get(Evas_Object *c)
{
Combo_Data *cd;
cd = evas_object_data_get(c, "cd");
return cd->selected;
}
void
ecdb_combo_data_set(Evas_Object *c, void *data)
{
Combo_Data *cd;
cd = evas_object_data_get(c, "cd");
cd->data = data;
}
void
ecdb_combo_clear(Evas_Object *c)
{
Combo_Data *cd;
cd = evas_object_data_get(c, "cd");
edje_object_part_box_remove_all(cd->popup, "ecdb.box", 1);
cd->selected = 1;
cd->count = 0;
}
/******************************* Label ***************************************/
Evas_Object *
ecdb_label_add(Evas_Object *parent, const char *name)
{
Evas_Object *l;
l = ecdb_widget_add(parent, name);
edje_object_file_set(l, em->theme_path, "ecdb/label");
return l;
}
void
ecdb_label_text_set(Evas_Object *l, const char *text)
{
edje_object_part_text_set(l, "ecdb.label", text);
}