Enlightenment CVS committal Author : moom16 Project : e17 Module : proto
Dir : e17/proto/etk/src/lib Modified Files: etk_object.c etk_toplevel_widget.c etk_tree.c etk_tree.h etk_types.h etk_widget.c etk_widget.h Log Message: * Fix the focus system * A lot of work on the tree (expandable rows, selection, clip, image cells...). It still needs some work though * Clicking on the label of a radio/checkbutton now activates the button =================================================================== RCS file: /cvsroot/enlightenment/e17/proto/etk/src/lib/etk_object.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -3 -r1.4 -r1.5 --- etk_object.c 7 Oct 2005 03:17:06 -0000 1.4 +++ etk_object.c 7 Oct 2005 21:33:43 -0000 1.5 @@ -364,7 +364,6 @@ property_value = etk_property_value_create_valist(etk_property_type_get(property), &args2); type->property_set(object, property->id, property_value); etk_property_value_delete(property_value); - va_end(args2); } } } =================================================================== RCS file: /cvsroot/enlightenment/e17/proto/etk/src/lib/etk_toplevel_widget.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -3 -r1.1 -r1.2 --- etk_toplevel_widget.c 1 Oct 2005 16:29:45 -0000 1.1 +++ etk_toplevel_widget.c 7 Oct 2005 21:33:43 -0000 1.2 @@ -83,29 +83,16 @@ } /** - * @brief Sets the focused widget of the toplevel widget + * @brief Sets the focused widget of the toplevel widget. Only for widget implementations. If you want to focus a widget, use etk_widget_focus() * @param toplevel_widget a toplevel widget * @param widget the widget to set as focused */ void etk_toplevel_widget_focused_widget_set(Etk_Toplevel_Widget *toplevel_widget, Etk_Widget *widget) { - Etk_Widget *old_focused; - if (!toplevel_widget || (widget == toplevel_widget->focused_widget)) return; - old_focused = toplevel_widget->focused_widget; - toplevel_widget->focused_widget = widget; - - if (old_focused) - etk_widget_unfocus(old_focused); - toplevel_widget->focused_widget = widget; - if (widget) - etk_widget_focus(widget); - else - etk_widget_focus(ETK_WIDGET(toplevel_widget)); - etk_object_notify(ETK_OBJECT(toplevel_widget), "focused_widget"); } @@ -122,7 +109,7 @@ } /** - * @brief Gets the next widget to focus + * @brief Gets the next widget to focus. Mainly for widget implementations * @param toplevel_widget a toplevel widget * @return Returns the next widget to focus */ @@ -140,7 +127,7 @@ } /** - * @brief Gets the previous widget to focus + * @brief Gets the previous widget to focus. Mainly for widget implementations * @param toplevel_widget a toplevel widget * @return Returns the previous widget to focus */ =================================================================== RCS file: /cvsroot/enlightenment/e17/proto/etk/src/lib/etk_tree.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -3 -r1.1 -r1.2 --- etk_tree.c 1 Oct 2005 16:29:45 -0000 1.1 +++ etk_tree.c 7 Oct 2005 21:33:43 -0000 1.2 @@ -23,22 +23,39 @@ typedef struct _Etk_Tree_Item_Objects { + Evas_Object *expander; Evas_Object *rect_bg; Etk_Tree_Item_Object *objects; } Etk_Tree_Item_Objects; +enum _Etk_Tree_Property_Id +{ + ETK_TREE_MODE_PROPERTY, + ETK_TREE_MULTIPLE_SELECT_PROPERTY +}; + static void _etk_tree_constructor(Etk_Tree *tree); static void _etk_tree_destructor(Etk_Tree *tree); +static void _etk_tree_property_set(Etk_Object *object, int property_id, Etk_Property_Value *value); +static void _etk_tree_property_get(Etk_Object *object, int property_id, Etk_Property_Value *value); static void _etk_tree_move_resize(Etk_Widget *widget, int x, int y, int w, int h); static void _etk_tree_realize_cb(Etk_Object *object, void *data); static void _etk_tree_mouse_wheel_cb(Etk_Object *object, void *event_info, void *data); +static void _etk_tree_expander_clicked_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); +static void _etk_tree_row_pressed_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _etk_tree_update(Etk_Tree *tree); -static Etk_Tree_Row *_etk_tree_row_new_valist(Etk_Tree *tree, Ecore_List *rows_list, va_list args); +static int _etk_tree_rows_draw(Etk_Tree *tree, Etk_Tree_Node *node, Ecore_List *items_objects, + int x, int w, int h, int xoffset, int yoffset, int first_row_id, int first_row_color); +static Etk_Tree_Row *_etk_tree_row_new_valist(Etk_Tree *tree, Etk_Tree_Node *node, va_list args); static Etk_Tree_Item_Objects *_etk_tree_item_objects_new(Etk_Tree *tree); static void _etk_tree_item_objects_free(Etk_Tree_Item_Objects *item_objects, Etk_Tree *tree); static void _etk_tree_row_free(Etk_Tree_Row *row); static void _etk_tree_cell_clear(Etk_Tree_Cell *cell, Etk_Tree_Col_Type cell_type); +static void _etk_tree_col_realize(Etk_Tree *tree, int col_nth); + +static void _etk_tree_node_unselect_all(Etk_Tree_Node *node); +static void _etk_tree_node_select(Etk_Tree *tree, Etk_Tree_Node *node, Evas_Modifier *modifiers); /************************** * @@ -57,6 +74,12 @@ if (!tree_type) { tree_type = etk_type_new("Etk_Tree", ETK_WIDGET_TYPE, sizeof(Etk_Tree), ETK_CONSTRUCTOR(_etk_tree_constructor), ETK_DESTRUCTOR(_etk_tree_destructor), NULL); + + etk_type_property_add(tree_type, "mode", ETK_TREE_MODE_PROPERTY, ETK_PROPERTY_INT, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_int(ETK_TREE_MODE_LIST)); + etk_type_property_add(tree_type, "multiple_select", ETK_TREE_MODE_PROPERTY, ETK_PROPERTY_BOOL, ETK_PROPERTY_READABLE_WRITABLE, etk_property_value_bool(TRUE)); + + tree_type->property_set = _etk_tree_property_set; + tree_type->property_get = _etk_tree_property_get; } return tree_type; @@ -104,11 +127,39 @@ new_col->visible = TRUE; tree->num_cols++; + _etk_tree_col_realize(tree, tree->num_cols - 1); return new_col; } /** + * @brief Sets the mode used by the tree. The tree has to be not built + * @param tree a tree + * @param mode the mode which will be used by the tree: ETK_TREE_MODE_LIST (rows can not have children) or ETK_TREE_MODE_TREE (rows can have children) + */ +void etk_tree_mode_set(Etk_Tree *tree, Etk_Tree_Mode mode) +{ + if (!tree || tree->built) + return; + if (mode != ETK_TREE_MODE_LIST) + etk_tree_multiple_select_set(tree, FALSE); + tree->mode = mode; + etk_object_notify(ETK_OBJECT(tree), "mode"); +} + +/** + * @brief Gets the mode used by the tree + * @param tree a tree + * @return Returns the mode used by the tree: ETK_TREE_MODE_LIST (rows can not have children) or ETK_TREE_MODE_TREE (rows can have children) + */ +Etk_Tree_Mode etk_tree_mode_get(Etk_Tree *tree) +{ + if (!tree) + return ETK_TREE_MODE_LIST; + return tree->mode; +} + +/** * @brief Builds the tree. This function to be called after having added all the columns and before being able to add rows to the tree * @param tree a tree */ @@ -121,6 +172,128 @@ } /** + * @brief Freezes the tree: it will not be updated until it is thawed (TODO: irregular verb?!) @n + * This function is useful when you want to add a lot of rows quickly. + * @param tree a tree + */ +void etk_tree_freeze(Etk_Tree *tree) +{ + if (!tree) + return; + tree->frozen = TRUE; +} + +/** + * @brief Thaws the tree: it will update the tree if it was frozen + * @param tree a tree + */ +void etk_tree_thaw(Etk_Tree *tree) +{ + if (!tree || !tree->frozen) + return; + + tree->frozen = FALSE; + etk_widget_redraw_queue(ETK_WIDGET(tree)); +} + +/** + * @brief Sets whether several rows can be selected in the tree. The tree has to be in the ETK_TREE_MODE_LIST mode + * @param tree a tree + * @param multiple_select TRUE if several rows can be selected + */ +void etk_tree_multiple_select_set(Etk_Tree *tree, Etk_Bool multiple_select) +{ + if (!tree || (tree->mode != ETK_TREE_MODE_LIST)) + return; + + if (!multiple_select) + etk_tree_unselect_all(tree); + tree->multiple_select = multiple_select; + etk_object_notify(ETK_OBJECT(tree), "multiple_select"); +} + +/** + * @brief Gets whether several rows can be selected in the tree. + * @param tree a tree + * @return TRUE if several rows can be selected + */ +Etk_Bool etk_tree_multiple_select_get(Etk_Tree *tree) +{ + if (!tree) + return FALSE; + return tree->multiple_select; +} + +/** + * @brief Selects all the node of the tree. Multiple selection has to be enabled (with etk_tree_multiple_select_set()), @n + * so it will only work with a tree in the ETK_TREE_MODE_LIST mode. + * @param tree a tree + */ +void etk_tree_select_all(Etk_Tree *tree) +{ + Etk_Tree_Row *row; + + if (!tree || (tree->mode != ETK_TREE_MODE_LIST) || !tree->multiple_select) + return; + + ecore_list_goto_first(tree->root.child_rows); + while ((row = ecore_list_next(tree->root.child_rows))) + row->node.selected = TRUE; + etk_widget_redraw_queue(ETK_WIDGET(tree)); +} + +/** + * @brief Unselects all the node of the tree + * @param tree a tree + */ +void etk_tree_unselect_all(Etk_Tree *tree) +{ + if (!tree) + return; + + _etk_tree_node_unselect_all(&tree->root); + etk_widget_redraw_queue(ETK_WIDGET(tree)); +} + +/** + * @brief Expands the row. The child rows of the row will be displayed. It will only take effect with a tree in the ETK_TREE_MODE_TREE mode + * @param row a row + */ +void etk_tree_row_expand(Etk_Tree_Row *row) +{ + if (!row || row->node.expanded || !row->tree || (row->tree->mode != ETK_TREE_MODE_TREE)) + return; + + row->node.expanded = TRUE; + /* TODO: fixme */ + if (row->node.parent) + row->node.parent->num_visible_children -= row->node.num_visible_children; + printf("%p %d %d\n", row->node.parent, row->node.num_visible_children, row->tree->root.num_visible_children); + + if (!row->tree->frozen) + etk_widget_redraw_queue(ETK_WIDGET(row->tree)); +} + +/** + * @brief Collapses the row. The child rows of the row are no longer displayed. It will only take effect with a tree in the ETK_TREE_MODE_TREE mode + * @param row a row + */ +void etk_tree_row_collapse(Etk_Tree_Row *row) +{ + if (!row || !row->node.expanded || !row->tree || (row->tree->mode != ETK_TREE_MODE_TREE)) + return; + + row->node.expanded = FALSE; + /* TODO: fixme */ + if (row->node.parent) + row->node.parent->num_visible_children += row->node.num_visible_children; + printf("%p %d %d\n", row->node.parent, row->node.num_visible_children, row->tree->root.num_visible_children); + + if (!row->tree->frozen) + etk_widget_redraw_queue(ETK_WIDGET(row->tree)); +} + +/** * @brief Appends a new row to the tree * @param tree a tree * @param ... an Etk_Tree_Col * followed by the value of the cell, then again, an Etk_Tree_Col * followed by its value... terminated by NULL @@ -135,7 +308,28 @@ return NULL; va_start(args, tree); - new_row = _etk_tree_row_new_valist(tree, tree->rows, args); + new_row = _etk_tree_row_new_valist(tree, &tree->root, args); + va_end(args); + + return new_row; +} + +/** + * @brief Appends a new row as a child of a another row of the tree. The tree has to be in the ETK_TREE_MODE_TREE mode + * @param row a row + * @param ... an Etk_Tree_Col * followed by the value of the cell, then again, an Etk_Tree_Col * followed by its value... terminated by NULL + * @return Returns the new row + */ +Etk_Tree_Row *etk_tree_append_to_row(Etk_Tree_Row *row, ...) +{ + Etk_Tree_Row *new_row; + va_list args; + + if (!row || !row->tree || !row->tree->built || (row->tree->mode != ETK_TREE_MODE_TREE)) + return NULL; + + va_start(args, row); + new_row = _etk_tree_row_new_valist(row->tree, &row->node, args); va_end(args); return new_row; @@ -153,16 +347,26 @@ if (!tree) return; - tree->built = FALSE; tree->num_cols = 0; tree->columns = NULL; + tree->last_selected = NULL; - tree->rows = ecore_list_new(); - ecore_list_set_free_cb(tree->rows, ECORE_FREE_CB(_etk_tree_row_free)); - - tree->item_height = 10; + tree->root.parent = NULL; + tree->root.child_rows = ecore_list_new(); + ecore_list_set_free_cb(tree->root.child_rows, ECORE_FREE_CB(_etk_tree_row_free)); + tree->root.num_visible_children = 0; + tree->root.num_parent_children = 0; + tree->root.expanded = TRUE; + + tree->item_height = -1; + tree->image_height = -1; + tree->expander_size = -1; tree->items_objects = ecore_list_new(); + tree->built = FALSE; + tree->frozen = FALSE; + tree->mode = ETK_TREE_MODE_LIST; + tree->multiple_select = FALSE; tree->scroll_percent = 0.0; ETK_WIDGET(tree)->move_resize = _etk_tree_move_resize; @@ -179,12 +383,11 @@ if (!tree) return; - ecore_list_goto_first(tree->items_objects); while ((item_objects = ecore_list_next(tree->items_objects))) _etk_tree_item_objects_free(item_objects, tree); ecore_list_destroy(tree->items_objects); - ecore_list_destroy(tree->rows); + ecore_list_destroy(tree->root.child_rows); for (i = 0; i < tree->num_cols; i++) { if (tree->columns[i]) @@ -196,6 +399,48 @@ free(tree->columns); } +/* Sets the property whose id is "property_id" to the value "value" */ +static void _etk_tree_property_set(Etk_Object *object, int property_id, Etk_Property_Value *value) +{ + Etk_Tree *tree; + + if (!(tree = ETK_TREE(object)) || !value) + return; + + switch (property_id) + { + case ETK_TREE_MODE_PROPERTY: + etk_tree_mode_set(tree, etk_property_value_int_get(value)); + break; + case ETK_TREE_MULTIPLE_SELECT_PROPERTY: + etk_tree_multiple_select_set(tree, etk_property_value_bool_get(value)); + break; + default: + break; + } +} + +/* Gets the value of the property whose id is "property_id" */ +static void _etk_tree_property_get(Etk_Object *object, int property_id, Etk_Property_Value *value) +{ + Etk_Tree *tree; + + if (!(tree = ETK_TREE(object)) || !value) + return; + + switch (property_id) + { + case ETK_TREE_MODE_PROPERTY: + etk_property_value_int_set(value, tree->mode); + break; + case ETK_TREE_MULTIPLE_SELECT_PROPERTY: + etk_property_value_bool_set(value, tree->multiple_select); + break; + default: + break; + } +} + /* Moves and resizes the tree */ static void _etk_tree_move_resize(Etk_Widget *widget, int x, int y, int w, int h) { @@ -234,6 +479,9 @@ } } + evas_object_move(tree->clip, x, y); + evas_object_resize(tree->clip, w, h); + _etk_tree_update(tree); } @@ -249,6 +497,8 @@ const char *data_value; Etk_Tree *tree; Etk_Widget *tree_widget; + Evas *evas; + int i; if (!(tree_widget = ETK_WIDGET(object)) || !tree_widget->theme_object) return; @@ -281,12 +531,47 @@ tree->row_color2.a = tree->row_color1.a; } - data_value = edje_object_data_get(tree_widget->theme_object, "item_height"); - if (!data_value || sscanf(data_value, "%d", &tree->item_height) != 1) - tree->item_height = 10; + data_value = edje_object_data_get(tree_widget->theme_object, "row_selected_color"); + if (!data_value || sscanf(data_value, "%d %d %d %d", &tree->row_selected_color.r, &tree->row_selected_color.g, &tree->row_selected_color.b, &tree->row_selected_color.a) != 4) + { + tree->row_selected_color.r = tree->row_color1.r - 50; + tree->row_selected_color.g = tree->row_color1.g - 50; + tree->row_selected_color.b = tree->row_color1.b - 50; + tree->row_selected_color.a = tree->row_color1.a - 50; + } + + if (tree->item_height < 10) + { + data_value = edje_object_data_get(tree_widget->theme_object, "item_height"); + if (!data_value || sscanf(data_value, "%d", &tree->item_height) != 1 || tree->item_height < 10) + tree->item_height = 10; + } + + if (tree->image_height < 6) + { + data_value = edje_object_data_get(tree_widget->theme_object, "image_height"); + if (!data_value || sscanf(data_value, "%d", &tree->image_height) != 1 || tree->image_height < 6 || tree->image_height > tree->item_height) + tree->image_height = tree->item_height - 4; + } + + if (tree->expander_size < 6) + { + data_value = edje_object_data_get(tree_widget->theme_object, "expander_size"); + if (!data_value || sscanf(data_value, "%d", &tree->expander_size) != 1 || tree->expander_size < 6 || tree->expander_size > tree->item_height) + tree->expander_size = tree->item_height - 4; + } + + if ((evas = etk_widget_toplevel_evas_get(tree_widget))) + { + tree->clip = evas_object_rectangle_add(evas); + etk_widget_member_object_add(tree_widget, tree->clip); + } + + for (i = 0; i < tree->num_cols; i++) + _etk_tree_col_realize(tree, i); } -/* TODO! */ +/* Called when the mouse wheel is used over the tree. TODO: scrollbars */ static void _etk_tree_mouse_wheel_cb(Etk_Object *object, void *event_info, void *data) { Etk_Tree *tree; @@ -295,11 +580,38 @@ if (!(tree = ETK_TREE(object)) || !(event = event_info)) return; - tree->scroll_percent += event->z * 0.05; + tree->scroll_percent += event->z * ((float)3 / tree->root.num_visible_children); tree->scroll_percent = ETK_CLAMP(tree->scroll_percent, 0.0, 1.0); _etk_tree_update(tree); } +/* Called when an expander is clicked */ +static void _etk_tree_expander_clicked_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Etk_Tree_Row *row; + + if (!(row = evas_object_data_get(obj, "etk_row"))) + return; + + if (row->node.expanded) + etk_tree_row_collapse(row); + else + etk_tree_row_expand(row); +} + +/* Called when the row is pressed */ +static void _etk_tree_row_pressed_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Etk_Tree_Row *row; + Evas_Event_Mouse_Down *event; + + if (!(row = evas_object_data_get(obj, "etk_row"))) + return; + + event = event_info; + _etk_tree_node_select(row->tree, &row->node, event->modifiers); +} + /************************** * * Private functions @@ -309,11 +621,10 @@ /* Updates the tree */ static void _etk_tree_update(Etk_Tree *tree) { - Etk_Tree_Row *row; Etk_Tree_Item_Objects *item_objects; int invisible_height, offset, first_visible_nth, delta; int x, y, w, h; - int i, j; + int i; if (!tree) return; @@ -323,39 +634,127 @@ w = ETK_WIDGET(tree)->inner_geometry.w; h = ETK_WIDGET(tree)->inner_geometry.h; - invisible_height = (ecore_list_nodes(tree->rows) * tree->item_height) - h; + for (i = 0; i < tree->num_cols; i++) + { + if (tree->columns[i]->xoffset > w) + { + evas_object_hide(tree->columns[i]->clip); + evas_object_hide(tree->columns[i]->separator); + } + else + { + evas_object_show(tree->columns[i]->clip); + evas_object_move(tree->columns[i]->clip, x + tree->columns[i]->xoffset, y); + + if (tree->columns[i]->xoffset + tree->columns[i]->width > w) + { + evas_object_resize(tree->columns[i]->clip, w - tree->columns[i]->xoffset, h); + evas_object_hide(tree->columns[i]->separator); + } + else + { + evas_object_resize(tree->columns[i]->clip, tree->columns[i]->width, h); + if (i < tree->num_cols - 1) + evas_object_show(tree->columns[i]->separator); + else + evas_object_hide(tree->columns[i]->separator); + evas_object_raise(tree->columns[i]->separator); + evas_object_move(tree->columns[i]->separator, x + tree->columns[i]->xoffset + tree->columns[i]->width, y); + evas_object_resize(tree->columns[i]->separator, 1, h); + } + } + } + + invisible_height = (tree->root.num_visible_children * tree->item_height) - h; if (invisible_height < 0) invisible_height = 0; offset = invisible_height * tree->scroll_percent; first_visible_nth = offset / tree->item_height; delta = offset - (first_visible_nth * tree->item_height); - ecore_list_goto_index(tree->rows, first_visible_nth); ecore_list_goto_first(tree->items_objects); - i = 0; + _etk_tree_rows_draw(tree, &tree->root, tree->items_objects, x, w, h, 0, y - delta, first_visible_nth, (first_visible_nth % 2)); + while ((item_objects = ecore_list_next(tree->items_objects))) { - int item_y; + evas_object_hide(item_objects->rect_bg); + evas_object_hide(item_objects->expander); + for (i = 0; i < tree->num_cols; i++) + { + if (item_objects->objects[i].text_object) + evas_object_hide(item_objects->objects[i].text_object); + if (item_objects->objects[i].image_object) + evas_object_hide(item_objects->objects[i].image_object); + } + } +} + +/* Draws recursively a list of rows and their children */ +static int _etk_tree_rows_draw(Etk_Tree *tree, Etk_Tree_Node *node, Ecore_List *items_objects, + int x, int w, int h, int xoffset, int yoffset, int first_row_id, int first_row_color) +{ + Etk_Tree_Row *row; + Etk_Tree_Item_Objects *item_objects; + int i, j; + int first_col_offset; + + if (!tree || !node || !items_objects) + return 0; - item_y = y + i * tree->item_height - delta; - evas_object_move(item_objects->rect_bg, x, item_y); - evas_object_resize(item_objects->rect_bg, w, tree->item_height); + first_col_offset = xoffset + ((node->num_parent_children > 0) ? tree->expander_size + 4 : 8); - if ((row = ecore_list_current(tree->rows))) + i = 0; + ecore_list_goto_first(node->child_rows); + while ((row = ecore_list_next(node->child_rows))) + { + if (first_row_id <= 0) { + int item_y; + + if (!(item_objects = ecore_list_next(items_objects))) + break; + + item_y = yoffset + i * tree->item_height; + evas_object_move(item_objects->rect_bg, x, item_y); + evas_object_resize(item_objects->rect_bg, w, tree->item_height); + evas_object_data_set(item_objects->rect_bg, "etk_row", row); evas_object_show(item_objects->rect_bg); - if ((first_visible_nth + i) % 2 == 0) - evas_object_color_set(item_objects->rect_bg, tree->row_color1.r, tree->row_color1.g, tree->row_color1.b, tree->row_color1.a); + if (row->node.selected) + evas_object_color_set(item_objects->rect_bg, tree->row_selected_color.r, tree->row_selected_color.g, tree->row_selected_color.b, tree->row_selected_color.a); else - evas_object_color_set(item_objects->rect_bg, tree->row_color2.r, tree->row_color2.g, tree->row_color2.b, tree->row_color2.a); - + { + if ((first_row_color + i) % 2 == 0) + evas_object_color_set(item_objects->rect_bg, tree->row_color1.r, tree->row_color1.g, tree->row_color1.b, tree->row_color1.a); + else + evas_object_color_set(item_objects->rect_bg, tree->row_color2.r, tree->row_color2.g, tree->row_color2.b, tree->row_color2.a); + } + + if (node->num_parent_children > 0) + { + if (row->node.child_rows && ecore_list_nodes(row->node.child_rows) > 0) + { + evas_object_move(item_objects->expander, xoffset + x, item_y + (tree->item_height - tree->expander_size + 1) / 2); + evas_object_resize(item_objects->expander, tree->expander_size, tree->expander_size); + if (row->node.expanded) + edje_object_signal_emit(item_objects->expander, "expand", ""); + else + edje_object_signal_emit(item_objects->expander, "collapse", ""); + evas_object_data_set(item_objects->expander, "etk_row", row); + evas_object_show(item_objects->expander); + } + else + evas_object_hide(item_objects->expander); + } + else + evas_object_hide(item_objects->expander); + for (j = 0; j < tree->num_cols; j++) { Etk_Bool show_text = FALSE, show_image = FALSE; - + if (!tree->columns[j]) continue; - + switch (tree->columns[j]->type) { case ETK_TREE_COL_TEXT: @@ -365,7 +764,7 @@ case ETK_TREE_COL_INT: { char string[256]; - + snprintf(string, 255, "%d", row->cells[j].int_value); evas_object_text_text_set(item_objects->objects[j].text_object, string); show_text = TRUE; @@ -374,49 +773,85 @@ case ETK_TREE_COL_DOUBLE: { char string[256]; - + snprintf(string, 255, "%'.2f", row->cells[j].double_value); evas_object_text_text_set(item_objects->objects[j].text_object, string); show_text = TRUE; break; } + case ETK_TREE_COL_IMAGE: + evas_object_image_file_set(item_objects->objects[j].image_object, row->cells[j].image_filename_value, NULL); + show_image = TRUE; + break; + default: + break; } - + + if (show_image) + { + int iw, ih; + + evas_object_image_size_get(item_objects->objects[j].image_object, &iw, &ih); + if (iw > tree->image_height) + { + iw = tree->image_height * ((float)iw / ih); + ih = tree->image_height; + } + evas_object_move(item_objects->objects[j].image_object, + x + ((j == 0) ? first_col_offset : tree->columns[j]->xoffset + 8), + item_y + (tree->item_height - ih + 1) / 2); + evas_object_resize(item_objects->objects[j].image_object, iw, ih); + evas_object_image_fill_set(item_objects->objects[j].image_object, 0, 0, iw, ih); + evas_object_show(item_objects->objects[j].image_object); + } + else + evas_object_hide(item_objects->objects[j].image_object); + if (show_text) { - Evas_Coord ch; - - evas_object_text_char_pos_get(item_objects->objects[j].text_object, 0, NULL, NULL, NULL, &ch); - evas_object_move(item_objects->objects[j].text_object, x + tree->columns[j]->xoffset, item_y + (tree->item_height - ch + 1) / 2); - evas_object_resize(item_objects->objects[j].text_object, tree->columns[j]->width, tree->item_height); + Evas_Coord th; + + evas_object_geometry_get(item_objects->objects[j].text_object, NULL, NULL, NULL, &th); + evas_object_move(item_objects->objects[j].text_object, + x + ((j == 0) ? first_col_offset : tree->columns[j]->xoffset + 8), + item_y + (tree->item_height - th + 1) / 2); evas_object_show(item_objects->objects[j].text_object); } else evas_object_hide(item_objects->objects[j].text_object); } - - ecore_list_next(tree->rows); i++; } - else + first_row_id--; + + if (row->node.child_rows && row->node.expanded && ecore_list_goto_first(row->node.child_rows)) { - evas_object_hide(item_objects->rect_bg); + i += _etk_tree_rows_draw(tree, &row->node, items_objects, x, w, h, first_col_offset, yoffset + i * tree->item_height, first_row_id, (first_row_color + i) % 2); + first_row_id -= row->node.num_visible_children; } } + + return i; } -/* Creates a new row and add it to the rows list*/ -static Etk_Tree_Row *_etk_tree_row_new_valist(Etk_Tree *tree, Ecore_List *rows_list, va_list args) +/* Creates a new row and add it to the node */ +static Etk_Tree_Row *_etk_tree_row_new_valist(Etk_Tree *tree, Etk_Tree_Node *node, va_list args) { Etk_Tree_Row *new_row; Etk_Tree_Col *col; + Etk_Tree_Node *n; - if (!tree || !tree->built || !rows_list) + if (!tree || !tree->built || !node) return NULL; new_row = malloc(sizeof(Etk_Tree_Row)); new_row->tree = tree; - new_row->child_rows = NULL; + new_row->node.parent = node; + new_row->node.child_rows = NULL; + new_row->node.num_visible_children = 0; + new_row->node.num_parent_children = 0; + new_row->node.expanded = FALSE; + new_row->node.selected = FALSE; new_row->cells = malloc(sizeof(Etk_Tree_Cell) * tree->num_cols); while ((col = va_arg(args, Etk_Tree_Col *))) @@ -492,7 +927,23 @@ } } - ecore_list_append(rows_list, new_row); + for (n = new_row->node.parent; n; n = n->parent) + { + if (n->expanded) + n->num_visible_children++; + else + break; + } + + if ((n = new_row->node.parent) && (n = n->parent)) + n->num_parent_children++; + + if (!node->child_rows) + { + node->child_rows = ecore_list_new(); + ecore_list_set_free_cb(node->child_rows, ECORE_FREE_CB(_etk_tree_row_free)); + } + ecore_list_append(node->child_rows, new_row); etk_widget_redraw_queue(ETK_WIDGET(tree)); return new_row; } @@ -509,8 +960,17 @@ new_item_objects = malloc(sizeof(Etk_Tree_Item_Objects)); new_item_objects->rect_bg = evas_object_rectangle_add(evas); + evas_object_clip_set(new_item_objects->rect_bg, tree->clip); + evas_object_event_callback_add(new_item_objects->rect_bg, EVAS_CALLBACK_MOUSE_DOWN, _etk_tree_row_pressed_cb, NULL); etk_widget_member_object_add(ETK_WIDGET(tree), new_item_objects->rect_bg); + new_item_objects->expander = edje_object_add(evas); + edje_object_file_set(new_item_objects->expander, ETK_WIDGET(tree)->theme_file, "tree_expander"); + if (tree->num_cols > 0) + evas_object_clip_set(new_item_objects->expander, tree->columns[0]->clip); + evas_object_event_callback_add(new_item_objects->expander, EVAS_CALLBACK_MOUSE_UP, _etk_tree_expander_clicked_cb, NULL); + etk_widget_member_object_add(ETK_WIDGET(tree), new_item_objects->expander); + new_item_objects->objects = malloc(sizeof(Etk_Tree_Item_Object) * tree->num_cols); for (i = 0; i < tree->num_cols; i++) { @@ -523,22 +983,31 @@ case ETK_TREE_COL_INT: case ETK_TREE_COL_DOUBLE: new_item_objects->objects[i].text_object = evas_object_text_add(evas); - etk_widget_member_object_add(ETK_WIDGET(tree), new_item_objects->objects[i].text_object); evas_object_text_font_set(new_item_objects->objects[i].text_object, "Vera", 10); evas_object_color_set(new_item_objects->objects[i].text_object, 0, 0, 0, 255); + evas_object_repeat_events_set(new_item_objects->objects[i].text_object, 1); + evas_object_clip_set(new_item_objects->objects[i].text_object, tree->columns[i]->clip); + etk_widget_member_object_add(ETK_WIDGET(tree), new_item_objects->objects[i].text_object); new_item_objects->objects[i].image_object = NULL; break; case ETK_TREE_COL_IMAGE: new_item_objects->objects[i].text_object = NULL; new_item_objects->objects[i].image_object = evas_object_image_add(evas); + evas_object_repeat_events_set(new_item_objects->objects[i].image_object, 1); + evas_object_clip_set(new_item_objects->objects[i].image_object, tree->columns[i]->clip); etk_widget_member_object_add(ETK_WIDGET(tree), new_item_objects->objects[i].image_object); break; case ETK_TREE_COL_TEXT_IMAGE: new_item_objects->objects[i].text_object = evas_object_text_add(evas); - etk_widget_member_object_add(ETK_WIDGET(tree), new_item_objects->objects[i].text_object); evas_object_text_font_set(new_item_objects->objects[i].text_object, "Vera", 10); evas_object_color_set(new_item_objects->objects[i].text_object, 0, 0, 0, 255); + evas_object_repeat_events_set(new_item_objects->objects[i].text_object, 1); + evas_object_clip_set(new_item_objects->objects[i].text_object, tree->columns[i]->clip); + etk_widget_member_object_add(ETK_WIDGET(tree), new_item_objects->objects[i].text_object); + new_item_objects->objects[i].image_object = evas_object_image_add(evas); + evas_object_repeat_events_set(new_item_objects->objects[i].image_object, 1); + evas_object_clip_set(new_item_objects->objects[i].image_object, tree->columns[i]->clip); etk_widget_member_object_add(ETK_WIDGET(tree), new_item_objects->objects[i].image_object); break; default: @@ -546,8 +1015,14 @@ new_item_objects->objects[i].image_object = NULL; break; } + + /* TODO: */ + etk_widget_member_object_del(ETK_WIDGET(tree), tree->columns[i]->separator); + etk_widget_member_object_add(ETK_WIDGET(tree), tree->columns[i]->separator); + etk_widget_restack_queue(ETK_WIDGET(tree)); } + etk_widget_restack_queue(ETK_WIDGET(tree)); return new_item_objects; } @@ -564,6 +1039,11 @@ etk_widget_member_object_del(ETK_WIDGET(tree), item_objects->rect_bg); evas_object_del(item_objects->rect_bg); } + if (item_objects->expander) + { + etk_widget_member_object_del(ETK_WIDGET(tree), item_objects->expander); + evas_object_del(item_objects->expander); + } for (i = 0; i < tree->num_cols; i++) { @@ -585,6 +1065,8 @@ /* Frees a row */ static void _etk_tree_row_free(Etk_Tree_Row *row) { + Etk_Tree_Node *n; + if (!row) return; @@ -600,8 +1082,19 @@ free(row->cells); } - if (row->child_rows) - ecore_list_destroy(row->child_rows); + if (row->node.child_rows) + ecore_list_destroy(row->node.child_rows); + + for (n = row->node.parent; n; n = n->parent) + { + if (n->expanded) + n->num_visible_children--; + else + break; + } + if ((n = row->node.parent) && (n = n->parent)) + n->num_parent_children--; + free(row); } @@ -627,3 +1120,105 @@ break; } } + +/* Creates the evas_objects of the "col_nth" column */ +static void _etk_tree_col_realize(Etk_Tree *tree, int col_nth) +{ + Evas *evas; + Etk_Widget *tree_widget; + + if (!(tree_widget = ETK_WIDGET(tree)) || col_nth < 0 || col_nth >= tree->num_cols || !(evas = etk_widget_toplevel_evas_get(tree_widget))) + return; + + tree->columns[col_nth]->clip = evas_object_rectangle_add(evas); + etk_widget_member_object_add(tree_widget, tree->columns[col_nth]->clip); + + tree->columns[col_nth]->separator = evas_object_rectangle_add(evas); + evas_object_color_set(tree->columns[col_nth]->separator, tree->separator_color.r, tree->separator_color.g, tree->separator_color.b, tree->separator_color.a); + etk_widget_member_object_add(tree_widget, tree->columns[col_nth]->separator); +} + +/* Unselects recursively all the rows of the node */ +static void _etk_tree_node_unselect_all(Etk_Tree_Node *node) +{ + Etk_Tree_Row *row; + + if (!node) + return; + + node->selected = FALSE; + if (node->child_rows) + { + ecore_list_goto_first(node->child_rows); + while ((row = ecore_list_next(node->child_rows))) + _etk_tree_node_unselect_all(&row->node); + } +} + +/* TODO: doc */ +static void _etk_tree_node_select(Etk_Tree *tree, Etk_Tree_Node *node, Evas_Modifier *modifiers) +{ + if (!tree || !node) + return; + + if (tree->mode == ETK_TREE_MODE_TREE || !tree->multiple_select) + { + etk_tree_unselect_all(tree); + node->selected = TRUE; + } + else + { + if (evas_key_modifier_is_set(modifiers, "Shift")) + { + if (!evas_key_modifier_is_set(modifiers, "Control")) + etk_tree_unselect_all(tree); + + if (!tree->last_selected) + { + node->selected = TRUE; + tree->last_selected = node; + } + else + { + Etk_Bool selected = FALSE; + Etk_Tree_Row *row; + + ecore_list_goto_first(tree->root.child_rows); + while ((row = ecore_list_next(tree->root.child_rows))) + { + if (&row->node == tree->last_selected || &row->node == node) + { + row->node.selected = TRUE; + selected = !selected; + } + else + row->node.selected |= selected; + } + if (selected) + { + etk_tree_unselect_all(tree); + node->selected = TRUE; + tree->last_selected = node; + } + } + } + else if (evas_key_modifier_is_set(modifiers, "Control")) + { + if (node->selected) + node->selected = FALSE; + else + { + node->selected = TRUE; + tree->last_selected = node; + } + } + else + { + etk_tree_unselect_all(tree); + node->selected = TRUE; + tree->last_selected = node; + } + } + + etk_widget_redraw_queue(ETK_WIDGET(tree)); +} =================================================================== RCS file: /cvsroot/enlightenment/e17/proto/etk/src/lib/etk_tree.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -3 -r1.1 -r1.2 --- etk_tree.h 1 Oct 2005 16:29:45 -0000 1.1 +++ etk_tree.h 7 Oct 2005 21:33:43 -0000 1.2 @@ -20,6 +20,20 @@ #define ETK_IS_TREE(obj) (ETK_OBJECT_CHECK_TYPE((obj), ETK_TREE_TYPE)) /** + * @struct Etk_Tree_Node + * @brief A node of a tree contains several rows + */ +struct _Etk_Tree_Node +{ + Etk_Tree_Node *parent; + Ecore_List *child_rows; + int num_visible_children; + int num_parent_children; + Etk_Bool expanded; + Etk_Bool selected; +}; + +/** * @struct Etk_Tree * @brief A tree is a widget that displays objects (text, images, ...) into columns and rows, with eventually a hierarchy */ @@ -31,17 +45,27 @@ int num_cols; Etk_Tree_Col **columns; - Ecore_List *rows; + Ecore_List *cols_objects; + + Etk_Tree_Node root; + Etk_Tree_Node *last_selected; + Evas_Object *clip; Ecore_List *items_objects; - Etk_Bool built; + Etk_Tree_Mode mode; + Etk_Bool multiple_select; float scroll_percent; + Etk_Bool frozen; + Etk_Bool built; int item_height; + int image_height; + int expander_size; Etk_Color separator_color; Etk_Color row_color1; Etk_Color row_color2; + Etk_Color row_selected_color; }; /** @@ -60,6 +84,9 @@ int width; int place; Etk_Bool visible; + + Evas_Object *clip; + Evas_Object *separator; }; /** @@ -70,8 +97,9 @@ { /* private: */ Etk_Tree *tree; + Etk_Tree_Node node; + Etk_Tree_Cell *cells; - Ecore_List *child_rows; }; /** @@ -94,10 +122,25 @@ Etk_Type *etk_tree_type_get(); Etk_Widget *etk_tree_new(); +void etk_tree_mode_set(Etk_Tree *tree, Etk_Tree_Mode mode); +Etk_Tree_Mode etk_tree_mode_get(Etk_Tree *tree); + Etk_Tree_Col *etk_tree_col_new(Etk_Tree *tree, const char *title, Etk_Tree_Col_Type type); + void etk_tree_build(Etk_Tree *tree); +void etk_tree_freeze(Etk_Tree *tree); +void etk_tree_thaw(Etk_Tree *tree); + +void etk_tree_multiple_select_set(Etk_Tree *tree, Etk_Bool multiple_select); +Etk_Bool etk_tree_multiple_select_get(Etk_Tree *tree); +void etk_tree_select_all(Etk_Tree *tree); +void etk_tree_unselect_all(Etk_Tree *tree); + +void etk_tree_row_fold(Etk_Tree_Row *row); +void etk_tree_row_unfold(Etk_Tree_Row *row); Etk_Tree_Row *etk_tree_append(Etk_Tree *tree, ...); +Etk_Tree_Row *etk_tree_append_to_row(Etk_Tree_Row *row, ...); /** @} */ =================================================================== RCS file: /cvsroot/enlightenment/e17/proto/etk/src/lib/etk_types.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -3 -r1.1 -r1.2 --- etk_types.h 1 Oct 2005 16:29:45 -0000 1.1 +++ etk_types.h 7 Oct 2005 21:33:43 -0000 1.2 @@ -74,8 +74,8 @@ typedef struct _Etk_Tree Etk_Tree; typedef struct _Etk_Tree_Col Etk_Tree_Col; typedef struct _Etk_Tree_Row Etk_Tree_Row; -typedef struct _Etk_Tree_Text_Image_Cell Etk_Tree_Text_Image_Cell; typedef union _Etk_Tree_Cell Etk_Tree_Cell; +typedef struct _Etk_Tree_Node Etk_Tree_Node; /* Enums: */ @@ -158,4 +158,14 @@ ETK_TREE_COL_DOUBLE } Etk_Tree_Col_Type; +/** + * @enum Etk_Tree_Mode + * @brief The mode of the tree: List (rows can not have children) or tree (rows can have children) + */ +typedef enum _Etk_Tree_Mode +{ + ETK_TREE_MODE_LIST, + ETK_TREE_MODE_TREE +} Etk_Tree_Mode; + #endif =================================================================== RCS file: /cvsroot/enlightenment/e17/proto/etk/src/lib/etk_widget.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -3 -r1.1 -r1.2 --- etk_widget.c 1 Oct 2005 16:29:45 -0000 1.1 +++ etk_widget.c 7 Oct 2005 21:33:43 -0000 1.2 @@ -1408,33 +1408,9 @@ if ((toplevel = (widget->toplevel_parent))) { if (strcmp(event->key, "Tab") == 0) - { - Etk_Widget *focused, *next_to_focus; - - focused = etk_toplevel_widget_focused_widget_get(toplevel); - next_to_focus = etk_toplevel_widget_focused_widget_next_get(toplevel); - - if (focused) - etk_widget_leave(focused); - if (next_to_focus) - etk_widget_enter(next_to_focus); - - etk_widget_focus(next_to_focus); - } + etk_widget_focus(etk_toplevel_widget_focused_widget_next_get(toplevel)); else if (strcmp(event->key, "ISO_Left_Tab") == 0) - { - Etk_Widget *focused, *next_to_focus; - - focused = etk_toplevel_widget_focused_widget_get(toplevel); - next_to_focus = etk_toplevel_widget_focused_widget_prev_get(toplevel); - - if (focused) - etk_widget_leave(focused); - if (next_to_focus) - etk_widget_enter(next_to_focus); - - etk_widget_focus(next_to_focus); - } + etk_widget_focus(etk_toplevel_widget_focused_widget_prev_get(toplevel)); } } @@ -1457,11 +1433,18 @@ /* Default handler for the "focus" signal */ static void _etk_widget_focus_handler(Etk_Widget *widget) { - if (!widget) + Etk_Widget *focused; + + if (!widget || !widget->toplevel_parent) + return; + if ((focused = etk_toplevel_widget_focused_widget_get(widget->toplevel_parent)) && (widget == focused)) return; - if (widget->toplevel_parent) - etk_toplevel_widget_focused_widget_set(widget->toplevel_parent, widget); + if (focused) + etk_widget_unfocus(focused); + + etk_toplevel_widget_focused_widget_set(widget->toplevel_parent, widget); + etk_widget_enter(widget); if (widget->smart_object) evas_object_focus_set(widget->smart_object, 1); etk_widget_theme_object_signal_emit(widget, "focus"); @@ -1470,10 +1453,15 @@ /* Default handler for the "unfocus" signal */ static void _etk_widget_unfocus_handler(Etk_Widget *widget) { - if (!widget) + Etk_Widget *focused; + + if (!widget || !widget->toplevel_parent || !(focused = etk_toplevel_widget_focused_widget_get(widget->toplevel_parent)) || (focused != widget)) return; - if (widget->toplevel_parent) - etk_toplevel_widget_focused_widget_set(widget->toplevel_parent, NULL); + + etk_toplevel_widget_focused_widget_set(widget->toplevel_parent, NULL); + etk_widget_leave(widget); + if (widget->smart_object) + evas_object_focus_set(widget->smart_object, 0); etk_widget_theme_object_signal_emit(widget, "unfocus"); } @@ -1586,7 +1574,7 @@ { if (!object) return; - etk_signal_emit(_etk_widget_signals[ETK_WIDGET_ENTER_SIGNAL], object, NULL); + etk_widget_enter(ETK_WIDGET(object)); } /* Called when the mouse pointer leaves the widget */ @@ -1618,7 +1606,7 @@ { if (!object) return; - etk_signal_emit(_etk_widget_signals[ETK_WIDGET_LEAVE_SIGNAL], object, NULL); + etk_widget_leave(ETK_WIDGET(object)); } /* Called when the mouse pointer moves */ =================================================================== RCS file: /cvsroot/enlightenment/e17/proto/etk/src/lib/etk_widget.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -3 -r1.1 -r1.2 --- etk_widget.h 1 Oct 2005 16:29:45 -0000 1.1 +++ etk_widget.h 7 Oct 2005 21:33:43 -0000 1.2 @@ -238,7 +238,7 @@ void etk_widget_theme_object_signal_emit(Etk_Widget *widget, const char *signal_name); void etk_widget_theme_object_part_text_set(Etk_Widget *widget, const char *part_name, const char *text); -void etk_widget_member_object_add(Etk_Widget *widget, Evas_Object *object); +void etk_widget_member_object_add(Etk_Widget *widget, Evas_Object *object/*, Etk_Bool grab_events*/); void etk_widget_member_object_del(Etk_Widget *widget, Evas_Object *object); /** @} */ ------------------------------------------------------- This SF.Net email is sponsored by: Power Architecture Resource Center: Free content, downloads, discussions, and more. http://solutions.newsforge.com/ibmarch.tmpl _______________________________________________ enlightenment-cvs mailing list enlightenment-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs