ce971c61463ad0af20ed9416cb28009b15518011
[framework/uifw/elementary.git] / src / lib / elm_colorpalette.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include <Ecore.h>
4
5 /**
6  * @defgroup Colorpalette Colorpalette
7  * @ingroup Elementary
8  *
9  * Using colorpalette, you can select a color by clicking
10  * a color rectangle on the colorpalette.
11  *
12  * Smart callbacks that you can add are:
13  *
14  * clicked - This signal is sent when a color rectangle is clicked.
15  *
16  */
17
18 #define MAX_NUM_COLORS 30
19
20 typedef struct _Colorpalette_Item Colorpalette_Item;
21 typedef struct _Widget_Data Widget_Data;
22
23 struct _Colorpalette_Item
24 {
25    Evas_Object *obj;
26    Evas_Object *lo;
27    Evas_Object *cr;
28    unsigned int r, g, b;
29 };
30
31 struct _Widget_Data
32 {
33    Evas_Object *base;
34    Evas_Object *tab;
35    Elm_Colorpalette_Color *color;
36    Eina_List *items;
37    unsigned int row, col;
38    unsigned int num;
39 };
40
41 static const char *widtype = NULL;
42 static void _del_hook(Evas_Object *obj);
43 static void _theme_hook(Evas_Object *obj);
44 static void _sizing_eval(Evas_Object *obj);
45 static void _colorpalette_object_resize(void *data, Evas *e, Evas_Object *obj, void *event_info);
46 static void _color_select_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
47 static void _color_release_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
48 static void _color_table_delete(Evas_Object *obj);
49 static void _color_table_update(Evas_Object *obj, unsigned int row, unsigned int col, unsigned int color_num, Elm_Colorpalette_Color *color);
50
51 static void
52 _del_hook(Evas_Object *obj)
53 {
54    Widget_Data *wd = elm_widget_data_get(obj);
55    if (!wd) return;
56    _color_table_delete(obj);
57    if (wd->color)
58      {
59         free(wd->color);
60      }
61    free(wd);
62 }
63
64 static void
65 _theme_hook(Evas_Object *obj)
66 {
67    Widget_Data *wd = elm_widget_data_get(obj);
68    _elm_theme_object_set(obj, wd->base, "colorpalette", "base", elm_widget_style_get(obj));
69    _color_table_update(obj, wd->row, wd->col, wd->num, wd->color);
70    _sizing_eval(obj);
71 }
72
73 static void
74 _sizing_eval(Evas_Object *obj)
75 {
76    Widget_Data *wd = NULL;
77    Colorpalette_Item *item = NULL;
78    Evas_Coord tab_w = 0, tab_h = 0;
79    Evas_Coord pad_x = 0, pad_y = 0;
80    Evas_Coord rect_w = 0, rect_h = 0;
81    Evas_Coord minw = -1, minh = -1;
82
83    wd = elm_widget_data_get((Evas_Object *)obj);
84    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
85    edje_object_size_min_restricted_calc(wd->base, &minw, &minh, minw, minh);
86    evas_object_size_hint_min_set(obj, minw, minh);
87    evas_object_size_hint_max_set(obj, -1, -1);
88
89    edje_object_part_geometry_get(wd->base,"bg" ,NULL, NULL, &tab_w, &tab_h);
90    if (wd->items)
91      item = wd->items->data;
92    edje_object_part_geometry_get(elm_layout_edje_get(item->lo),"bg" ,NULL, NULL, &rect_w, &rect_h);
93    if (wd->col - 1) /*value cannot be 0 else divide by zero error will cause floating point exception*/
94      pad_x = (tab_w - (rect_w * wd->col)) / (wd->col - 1);
95    if (wd->row - 1) /*value cannot be 0 else divide by zero error will cause floating point exception*/
96      pad_y = (tab_h - (rect_h * wd->row)) / (wd->row - 1);
97    elm_table_padding_set(wd->tab, pad_x, pad_y);
98    elm_table_homogeneous_set(wd->tab, EINA_TRUE);
99 }
100
101 static void _colorpalette_object_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
102 {
103    _sizing_eval(data);
104 }
105
106 static void _color_select_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
107 {
108    Elm_Colorpalette_Color *color;
109    Colorpalette_Item *item = (Colorpalette_Item *) data;
110    color = ELM_NEW(Elm_Colorpalette_Color);
111    if (!color) return;
112    color->r = item->r;
113    color->g = item->g;
114    color->b = item->b;
115    evas_object_smart_callback_call(item->obj, "clicked", color);
116    edje_object_signal_emit(elm_layout_edje_get(item->lo), "focus_visible", "elm");
117 }
118
119 static void _color_release_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
120 {
121    Colorpalette_Item *item = (Colorpalette_Item *) data;
122    edje_object_signal_emit(elm_layout_edje_get(item->lo), "focus_invisible", "elm");
123 }
124
125 static void _color_table_delete(Evas_Object *obj)
126 {
127    Widget_Data *wd = NULL;
128    Colorpalette_Item *item;
129    wd = elm_widget_data_get(obj);
130
131    if (wd->items)
132      {
133         EINA_LIST_FREE(wd->items, item)
134           {
135              if (item->lo)
136                {
137                   evas_object_del(item->lo);
138                   item->lo = NULL;
139                }
140              if (item->cr)
141                {
142                   evas_object_del(item->cr);
143                   item->cr = NULL;
144                }
145              free(item);
146           }
147      }
148    if (wd->tab) evas_object_del(wd->tab);
149 }
150
151 static void _color_table_update(Evas_Object *obj, unsigned int row, unsigned int col, unsigned int color_num, Elm_Colorpalette_Color *color)
152 {
153    Widget_Data *wd = elm_widget_data_get(obj);
154    Colorpalette_Item *item;
155    Evas_Object *lo;
156    Evas_Object *cr;
157    unsigned int i, j, count;
158
159    _color_table_delete(obj);
160    count = 0;
161    wd->row = row;
162    wd->col = col;
163    wd->num = color_num;
164
165    wd->tab = elm_table_add(obj);
166    evas_object_size_hint_weight_set(wd->tab, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
167    evas_object_size_hint_align_set(wd->tab, EVAS_HINT_FILL, EVAS_HINT_FILL);
168    edje_object_part_swallow(wd->base, "palette", wd->tab);
169
170    for ( i = 0 ; i < row ; i++)
171      {
172         for ( j = 0 ; j < col ; j++ )
173           {
174              item = ELM_NEW(Colorpalette_Item);
175              if (item)
176                {
177                   lo = elm_layout_add(obj);
178                   elm_layout_theme_set(lo, "colorpalette", "base", "bg");
179                   evas_object_size_hint_weight_set(lo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
180                   evas_object_size_hint_align_set(lo, EVAS_HINT_FILL, EVAS_HINT_FILL);
181                   evas_object_show(lo);
182                   elm_table_pack(wd->tab, lo, (int)j, (int)i, 1, 1);
183                   item->obj = obj;
184                   item->lo = lo;
185                   if (count < color_num)
186                     {
187                        cr =  edje_object_add(evas_object_evas_get(obj));
188                        _elm_theme_object_set(obj, cr, "colorpalette", "base", "color");
189                        evas_object_color_set(cr, color[count].r, color[count].g, color[count].b, 255);
190                        evas_object_size_hint_weight_set(cr, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
191                        evas_object_size_hint_align_set(cr, EVAS_HINT_FILL, EVAS_HINT_FILL);
192                        evas_object_event_callback_add(cr, EVAS_CALLBACK_MOUSE_DOWN, _color_select_cb, item);
193                        evas_object_event_callback_add(cr, EVAS_CALLBACK_MOUSE_UP, _color_release_cb, item);
194                        evas_object_show(cr);
195                        edje_object_part_swallow(elm_layout_edje_get(lo), "color_rect", cr);
196                        item->cr = cr;
197                        item->r = color[count].r;
198                        item->g = color[count].g;
199                        item->b = color[count].b;
200                     }
201                   wd->items = eina_list_append(wd->items, item);
202                   count ++;
203                }
204           }
205      }
206 }
207
208 static int
209 _hex_string_get(char ch)
210 {
211    if ((ch >= '0') && (ch <= '9')) return (ch - '0');
212    else if ((ch >= 'A') && (ch <= 'F')) return (ch - 'A' + 10);
213    else if ((ch >= 'a') && (ch <= 'f')) return (ch - 'a' + 10);
214    return 0;
215 }
216
217 static void
218 _color_parse(const char *str, unsigned char *r, unsigned char *g, unsigned char *b)
219 {
220    int slen;
221
222    slen = strlen(str);
223    *r = *g = *b = 0;
224
225    if (slen == 7) /* #RRGGBB */
226      {
227         *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2]));
228         *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4]));
229         *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6]));
230      }
231    *r = (*r * 0xff) / 255;
232    *g = (*g * 0xff) / 255;
233    *b = (*b * 0xff) / 255;
234 }
235
236 /**
237  * Add a new colorpalette to the parent.
238  *
239  * @param parent The parent object
240  * @return The new object or NULL if it cannot be created
241  *
242  * @ingroup Colorpalette
243  */
244 EAPI Evas_Object *elm_colorpalette_add(Evas_Object *parent)
245 {
246    Evas_Object *obj = NULL;
247    Widget_Data *wd = NULL;
248    Evas *e;
249    Eina_List *colors;
250    const Eina_List *l;
251    const char *color_code;
252    int color_num = 0;
253    int row = 0;
254    int col = 0;
255    int index = 0;
256
257    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
258
259    ELM_SET_WIDTYPE(widtype, "colorpalette");
260    elm_widget_type_set(obj, "colorpalette");
261    elm_widget_sub_object_add(parent, obj);
262    elm_widget_data_set(obj, wd);
263    elm_widget_del_hook_set(obj, _del_hook);
264    elm_widget_theme_hook_set(obj, _theme_hook);
265
266    wd->base = edje_object_add(e);
267    _elm_theme_object_set(obj, wd->base, "colorpalette", "base", "default");
268    elm_widget_resize_object_set(obj, wd->base);
269
270    color_num = atoi(edje_object_data_get(wd->base, "color_num")); /* Need to get this value
271    from edc inorder to allocate memory in advance: Think of a better way*/
272    row = atoi(edje_object_data_get(wd->base, "row"));
273    col = atoi(edje_object_data_get(wd->base, "col"));
274    wd->color = (Elm_Colorpalette_Color*) calloc (color_num, sizeof(Elm_Colorpalette_Color));
275    colors = elm_widget_stringlist_get(edje_object_data_get(wd->base, "colors"));
276    EINA_LIST_FOREACH(colors, l, color_code)
277      {
278         unsigned char r, g, b;
279         /*Optimized color parsing algorithm*/
280         _color_parse(color_code, &r, &g, &b);
281         /*TODO: Make color storing structure and item also take unsigned char*/
282         wd->color[index].r = (unsigned int)r;
283         wd->color[index].g = (unsigned int)g;
284         wd->color[index].b = (unsigned int)b;
285         index++;
286      }
287    elm_widget_stringlist_free(colors);
288    _color_table_update(obj, row, col, color_num, wd->color);
289    evas_object_event_callback_add(wd->base, EVAS_CALLBACK_RESIZE, _colorpalette_object_resize, obj);
290    _sizing_eval(obj);
291    return obj;
292 }
293
294
295 /**
296  * Set colors to the colorpalette.
297  *
298  * @param obj   Colorpalette object
299  * @param color_num     number of the colors on the colorpalette
300  * @param color     Color lists
301  *
302  * @ingroup Colorpalette
303  */
304 EAPI void elm_colorpalette_color_set(Evas_Object *obj, int color_num, Elm_Colorpalette_Color *color)
305 {
306    ELM_CHECK_WIDTYPE(obj, widtype);
307    Widget_Data *wd = elm_widget_data_get(obj);
308    int i;
309
310    if (color_num > MAX_NUM_COLORS) return;
311    if (!wd) return;
312
313    if (wd->color)
314      {
315         free(wd->color);
316         wd->color = NULL;
317      }
318    wd->color = (Elm_Colorpalette_Color*) calloc (color_num, sizeof(Elm_Colorpalette_Color));
319    for (i = 0; i < color_num; i++)
320      {
321         wd->color[i].r = color[i].r;
322         wd->color[i].g = color[i].g;
323         wd->color[i].b = color[i].b;
324      }
325    _color_table_update(obj, wd->row, wd->col, color_num, wd->color);
326    _sizing_eval(obj);
327 }
328
329 /**
330  * Set row/column value for the colorpalette.
331  *
332  * @param obj   Colorpalette object
333  * @param row   row value for the colorpalette
334  * @param col   column value for the colorpalette
335  *
336  * @ingroup Colorpalette
337  */
338 EAPI void elm_colorpalette_row_column_set(Evas_Object *obj, int row, int col)
339 {
340    ELM_CHECK_WIDTYPE(obj, widtype);
341    Widget_Data *wd = elm_widget_data_get(obj);
342    if (!wd) return;
343    /*Row can be incomplete with atleast one color*/
344    if(((row-1)*col) > MAX_NUM_COLORS) return;
345    _color_table_update(obj, row, col, wd->num, wd->color);
346    _sizing_eval(obj);
347 }
348