示例#1
0
/**
 * @brief Sets the submenu of the menu-item: the submenu will be popped up when the menu-item is selected
 * @param menu_item a menu-item
 * @param submenu the submenu to attach to the menu-item
 */
void etk_menu_item_submenu_set(Etk_Menu_Item *menu_item, Etk_Menu *submenu)
{
   if (!menu_item || menu_item->submenu == submenu)
      return;

   if (menu_item->submenu)
   {
      menu_item->submenu->parent_item = NULL;
      etk_object_notify(ETK_OBJECT(menu_item->submenu), "parent-item");
   }
   menu_item->submenu = submenu;
   if (menu_item->submenu)
   {
      menu_item->submenu->parent_item = menu_item;
      etk_object_notify(ETK_OBJECT(menu_item->submenu), "parent-item");
   }

   if (menu_item->submenu)
      etk_widget_theme_signal_emit(ETK_WIDGET(menu_item), "etk,action,show,arrow", ETK_TRUE);
   else
      etk_widget_theme_signal_emit(ETK_WIDGET(menu_item), "etk,action,hide,arrow", ETK_TRUE);

   etk_widget_size_recalc_queue(ETK_WIDGET(menu_item));
   etk_object_notify(ETK_OBJECT(menu_item), "submenu");
}
示例#2
0
/**
 * @brief Sets the label of the frame
 * @param frame a frame
 * @param label the label to set
 */
void etk_frame_label_set(Etk_Frame *frame, const char *label)
{
   if (!frame)
      return;

   if (label != frame->label)
   {
      free(frame->label);
      frame->label = label ? strdup(label) : NULL;
   }

   if (!frame->label || frame->label[0] == '\0')
   {
      etk_widget_theme_part_text_set(ETK_WIDGET(frame), "etk.text.label", "");
      etk_widget_theme_signal_emit(ETK_WIDGET(frame), "etk,action,hide,label", ETK_TRUE);
   }
   else
   {
      etk_widget_theme_part_text_set(ETK_WIDGET(frame), "etk.text.label", frame->label);
      etk_widget_theme_signal_emit(ETK_WIDGET(frame), "etk,action,show,label", ETK_TRUE);
   }

   if (label != frame->label)
      etk_object_notify(ETK_OBJECT(frame), "label");
}
示例#3
0
/**
 * @brief Inserts a character into a string, at a given position
 * @param string a string. If @a string is NULL, a new string is created
 * @param pos the position where to insert the char
 * @param c the character to insert into the string
 * @return Returns the string
 */
Etk_String *etk_string_insert_char(Etk_String *string, int pos, char c)
{
   int i;

   if (!string)
      return etk_string_insert_char(etk_string_new(NULL), pos, c);
   if (c == '\0')
      return etk_string_truncate(string, pos);

   pos = ETK_CLAMP(pos, 0, string->length);
   if (string->length + 1 > string->allocated_length)
   {
      string->string = realloc(string->string, SIZE_TO_ALLOC(string->length + 1) + 1);
      string->allocated_length = SIZE_TO_ALLOC(string->length + 1);
   }
   for (i = string->length - 1; i >= pos; i--)
      string->string[i + 1] = string->string[i];

   string->string[pos] = c;
   string->length++;
   string->string[string->length] = '\0';

   etk_object_notify(ETK_OBJECT(string), "string");
   return string;
}
示例#4
0
/**
 * @brief Sets the group of the radio-button
 * @param radio_button a radio-button
 * @param group the group to use
 */
void etk_radio_button_group_set(Etk_Radio_Button *radio_button, Eina_List **group)
{
   Etk_Toggle_Button *toggle_button;
   Etk_Bool active;

   if (!(toggle_button = ETK_TOGGLE_BUTTON(radio_button)) || (group && (radio_button->group == group)))
      return;

   if (radio_button->group)
   {
      *radio_button->group = eina_list_remove(*radio_button->group, radio_button);
      if (!(*radio_button->group))
      {
         free(radio_button->group);
         radio_button->group = NULL;
      }
   }

   if (!group)
   {
      group = malloc(sizeof(Eina_List *));
      *group = NULL;
      active = ETK_TRUE;
   }
   else
      active = ETK_FALSE;

   *group = eina_list_append(*group, radio_button);
   radio_button->group = group;
   etk_object_notify(ETK_OBJECT(radio_button), "group");

   radio_button->can_uncheck = ETK_TRUE;
   etk_toggle_button_active_set(toggle_button, active);
}
示例#5
0
/* This function is called when the radio-button is turned on: it deactivates all
 * the other radio-buttons of the group, and activate the given radio-button */
static void _etk_radio_button_active_set(Etk_Toggle_Button *toggle_button, Etk_Bool active)
{
   Etk_Radio_Button *radio_button;
   Etk_Toggle_Button *tb;
   Eina_List *l;

   if (!(radio_button = ETK_RADIO_BUTTON(toggle_button)) || toggle_button->active == active)
      return;

   if (!toggle_button->active || (toggle_button->active && radio_button->can_uncheck))
   {
      toggle_button->active = active;
      etk_signal_emit(ETK_TOGGLE_BUTTON_TOGGLED_SIGNAL, ETK_OBJECT(toggle_button));
      etk_object_notify(ETK_OBJECT(toggle_button), "active");

      if (toggle_button->active)
      {
         /* Deactivate the current active button of the group */
         for (l = *radio_button->group; l; l = l->next)
         {
            tb = ETK_TOGGLE_BUTTON(l->data);
            if (tb != toggle_button && tb->active)
            {
               ETK_RADIO_BUTTON(tb)->can_uncheck = ETK_TRUE;
               etk_toggle_button_active_set(tb, ETK_FALSE);
            }
         }
      }
      radio_button->can_uncheck = ETK_FALSE;
   }
}
示例#6
0
/**
 * @brief Sets the group of the radio menu-item
 * @param radio_item a radio menu-item
 * @param group the group to set
 */
void etk_menu_item_radio_group_set(Etk_Menu_Item_Radio *radio_item, Eina_List **group)
{
   Etk_Menu_Item_Check *check_item;
   Etk_Bool active;

   if (!(check_item = ETK_MENU_ITEM_CHECK(radio_item)) || (group && (radio_item->group == group)))
      return;

   if (radio_item->group)
   {
      *radio_item->group = eina_list_remove(*radio_item->group, radio_item);
      if (!(*radio_item->group))
      {
         free(radio_item->group);
         radio_item->group = NULL;
      }
   }

   if (!group)
   {
      group = malloc(sizeof(Eina_List *));
      *group = NULL;
      active = ETK_TRUE;
   }
   else
      active = ETK_FALSE;

   *group = eina_list_append(*group, radio_item);
   radio_item->group = group;
   etk_object_notify(ETK_OBJECT(radio_item), "group");

   radio_item->can_uncheck = ETK_TRUE;
   etk_menu_item_check_active_set(check_item, active);
}
示例#7
0
/* Behavior of the "active_set" function for a radio menu item */
static void _etk_menu_item_radio_active_set(Etk_Menu_Item_Check *check_item, Etk_Bool active)
{
   Etk_Menu_Item_Radio *radio_item;
   Etk_Menu_Item_Check *ci;
   Eina_List *l;

   if (!(radio_item = ETK_MENU_ITEM_RADIO(check_item)) || check_item->active == active)
      return;

   if (!check_item->active || (check_item->active && radio_item->can_uncheck))
   {
      check_item->active = active;
      etk_signal_emit(ETK_MENU_ITEM_CHECK_TOGGLED_SIGNAL, ETK_OBJECT(check_item));
      etk_object_notify(ETK_OBJECT(check_item), "active");

      if (check_item->active)
      {
         /* Uncheck the previously checked item of the group */
         for (l = *radio_item->group; l; l = l->next)
         {
            ci = ETK_MENU_ITEM_CHECK(l->data);
            if (ci != check_item && ci->active)
            {
               ETK_MENU_ITEM_RADIO(ci)->can_uncheck = ETK_TRUE;
               etk_menu_item_check_active_set(ci, ETK_FALSE);
            }
         }
      }
      radio_item->can_uncheck = ETK_FALSE;
   }
}
示例#8
0
/**
 * @brief Sets whether or not the action-area's hbox is homogeneous, i.e whether or not all the widgets of the
 * action-area should have the same size
 * @param dialog a dialog
 * @param homogeneous ETK_TRUE to make the action-area's hbox homogeneous, ETK_FALSE otherwise
 */
void etk_dialog_action_area_homogeneous_set(Etk_Dialog *dialog, Etk_Bool homogeneous)
{
   if (!dialog)
      return;

   etk_box_homogeneous_set(ETK_BOX(dialog->action_area_hbox), homogeneous);
   etk_object_notify(ETK_OBJECT(dialog), "action-area-homogeneous");
}
示例#9
0
/**
 * @brief Sets the horizontal alignment of the widget in the dialog's action-area
 * @param dialog a dialog
 * @param align the horizontal alignment (0.0 = left, 0.5 = center, 1.0 = right, ...)
 */
void etk_dialog_action_area_alignment_set(Etk_Dialog *dialog, float align)
{
   if (!dialog)
      return;

   etk_alignment_set(ETK_ALIGNMENT(dialog->action_area_alignment), align, 0.5, 0.0, 0.0);
   etk_object_notify(ETK_OBJECT(dialog), "action-area-align");
}
示例#10
0
/**
 * @brief Sets whether or not the spinner's value should wrap around to the opposite limit when the value exceed one
 * of the spinner's bounds
 * @param spinner a spinner
 * @param wrap ETK_TRUE to make the value wrap around, ETK_FALSE otherwise
 */
void etk_spinner_wrap_set(Etk_Spinner *spinner, Etk_Bool wrap)
{
   if (!spinner || spinner->wrap == wrap)
      return;

   spinner->wrap = wrap;
   etk_object_notify(ETK_OBJECT(spinner), "wrap");
}
示例#11
0
/**
 * @brief Sets the amount of free space between two cells
 * @param box a box
 * @param spacing the new amount of free space between two cells, in pixels
 */
void etk_box_spacing_set(Etk_Box *box, int spacing)
{
   if (!box)
      return;

   box->spacing = spacing;
   etk_widget_size_recalc_queue(ETK_WIDGET(box));
   etk_object_notify(ETK_OBJECT(box), "spacing");
}
示例#12
0
/* Behavior of the "active_set" function for a check menu item */
static void _etk_menu_item_check_active_set(Etk_Menu_Item_Check *check_item, Etk_Bool active)
{
   if (!check_item || check_item->active == active)
      return;

   check_item->active = active;
   etk_signal_emit(ETK_MENU_ITEM_CHECK_TOGGLED_SIGNAL, ETK_OBJECT(check_item));
   etk_object_notify(ETK_OBJECT(check_item), "active");
}
示例#13
0
/**
 * @brief Sets whether or not all the cells of the box should have the same size
 * @param box a box
 * @param homogeneous if @a homogeneous is ETK_TRUE, all the cells will have the same size
 */
void etk_box_homogeneous_set(Etk_Box *box, Etk_Bool homogeneous)
{
   if (!box)
      return;

   box->homogeneous = homogeneous;
   etk_widget_size_recalc_queue(ETK_WIDGET(box));
   etk_object_notify(ETK_OBJECT(box), "homogeneous");
}
示例#14
0
/**
 * @brief Changes the homogenous property of the table
 * @param table a table
 * @param homogeneous a flag describing whether the table should be homogenous horizontally, vertically,
 * in both directions or not at all
 */
void etk_table_homogeneous_set(Etk_Table *table, Etk_Table_Homogeneous homogeneous)
{
   if (!table)
      return;

   table->homogeneous = homogeneous;
   etk_widget_size_recalc_queue(ETK_WIDGET(table));
   etk_object_notify(ETK_OBJECT(table), "homogeneous");
}
示例#15
0
/**
 * @brief Sets the label of the menu-item
 * @param menu_item a menu-item
 * @param label the label to set
 */
void etk_menu_item_label_set(Etk_Menu_Item *menu_item, const char *label)
{
   if (!menu_item || menu_item->label == label)
      return;

   free(menu_item->label);
   menu_item->label = label ? strdup(label) : NULL;
   etk_widget_theme_part_text_set(ETK_WIDGET(menu_item), "etk.text.label", label ? label : "");

   etk_object_notify(ETK_OBJECT(menu_item), "label");
}
示例#16
0
/**
 * @brief Sets the number of digits displayed by the spinner
 * @param spinner a spinner
 * @param digits the number of digits to display
 */
void etk_spinner_digits_set(Etk_Spinner *spinner, int digits)
{
   if (!spinner || spinner->digits == digits)
      return;

   spinner->digits = ETK_MAX(0, digits);
   snprintf(spinner->value_format, 16, "%%.%df", spinner->digits);

   _etk_spinner_update_text_from_value(spinner);
   etk_object_notify(ETK_OBJECT(spinner), "digits");
}
示例#17
0
/**
 * @brief Sets whether the statusbar has a resize-grip. The resize-grip is a small grip at the right of the statusbar
 * that the user can use to resize the window
 * @param statusbar a statusbar
 * @param has_resize_grip if @a has_resize_grip is ETK_TRUE to make the statusbar have a resize-grip
 */
void etk_statusbar_has_resize_grip_set(Etk_Statusbar *statusbar, Etk_Bool has_resize_grip)
{
   if (!statusbar || statusbar->has_resize_grip == has_resize_grip)
      return;

   statusbar->has_resize_grip = has_resize_grip;
   if (statusbar->has_resize_grip)
      etk_widget_theme_signal_emit(ETK_WIDGET(statusbar), "etk,action,show,resize_grip", ETK_TRUE);
   else
      etk_widget_theme_signal_emit(ETK_WIDGET(statusbar), "etk,action,hide,resize_grip", ETK_TRUE);
   etk_object_notify(ETK_OBJECT(statusbar), "has-resize-grip");
}
示例#18
0
/**
 * @brief Sets whether or not there is a horizontal separator between the main-area and the action-area of the dialog
 * @param dialog a dialog
 * @param has_separator ETK_TRUE to make the separator visible, ETK_FALSE to hide it
 */
void etk_dialog_has_separator_set(Etk_Dialog *dialog, Etk_Bool has_separator)
{
   if (!dialog || dialog->has_separator == has_separator)
      return;

   if (has_separator)
      etk_widget_show(dialog->separator);
   else
      etk_widget_hide(dialog->separator);
   dialog->has_separator = has_separator;
   etk_object_notify(ETK_OBJECT(dialog), "has-separator");
}
示例#19
0
/**
 * @brief Truncates the string
 * @param string a string
 * @param length the new length of the string. If @a length is greater than
 * the current length of the string, the function does nothing
 * @return Returns the truncated string
 */
Etk_String *etk_string_truncate(Etk_String *string, int length)
{
   if (!string || length < 0)
      return NULL;

   if (length < string->length)
   {
      string->string[length] = '\0';
      string->length = length;
      etk_object_notify(ETK_OBJECT(string), "string");
   }
   
   return string;
}
示例#20
0
/**
 * @brief Sets whether or not the value of the spinner should be automatically
 * corrected to the nearest step-increment
 * @param spinner a spinner
 * @param snap_to_ticks ETK_TRUE if you want the value to be corrected, ETK_FALSE otherwise
 */
void etk_spinner_snap_to_ticks_set(Etk_Spinner *spinner, Etk_Bool snap_to_ticks)
{
   if (!spinner || spinner->snap_to_ticks == snap_to_ticks)
      return;

   spinner->snap_to_ticks = snap_to_ticks;

   if (snap_to_ticks)
   {
      double new_value;

      new_value = _etk_spinner_value_snap(spinner, etk_range_value_get(ETK_RANGE(spinner)));
      etk_range_value_set(ETK_RANGE(spinner), new_value);
   }
   etk_object_notify(ETK_OBJECT(spinner), "snap-to-ticks");
}
示例#21
0
/**
 * @brief Pushs a new message on the statusbar's message-stack
 * @param statusbar a statusbar
 * @param message the message to push
 * @param context_id the context-id to associate to the message.
 * You can generate a context-id with @a etk_statusbar_context_id_get()
 * @return Returns the message-id of the message, or -1 on failure
 */
int etk_statusbar_message_push(Etk_Statusbar *statusbar, const char *message, int context_id)
{
   Etk_Statusbar_Msg *new_msg;

   if (!statusbar || !message)
      return -1;

   new_msg = malloc(sizeof(Etk_Statusbar_Msg));
   new_msg->msg = strdup(message);
   new_msg->context_id = context_id;
   new_msg->message_id = statusbar->next_message_id++;

   statusbar->msg_stack = eina_list_prepend(statusbar->msg_stack, new_msg);
   _etk_statusbar_update(statusbar);

   etk_object_notify(ETK_OBJECT(statusbar), "current-message");
   return new_msg->message_id;
}
示例#22
0
/**
 * @brief Sets the stock-size of the toolbar's tool-buttons
 * @param toolbar a toolbar
 * @param size the stock-size to use
 */
void etk_toolbar_stock_size_set(Etk_Toolbar *toolbar, Etk_Stock_Size size)
{
   Eina_List *children, *l;

   if (!toolbar || toolbar->stock_size == size)
      return;

   toolbar->stock_size = size;
   children = etk_container_children_get(ETK_CONTAINER(toolbar->box));
   for (l = children; l; l = l->next)
   {
      if (ETK_IS_TOOL_ITEM(l->data))
	 etk_button_stock_size_set(ETK_BUTTON(l->data), size);
   }
   eina_list_free(children);

   etk_object_notify(ETK_OBJECT(toolbar), "stock-size");
}
示例#23
0
/**
 * @brief Removes the message corresponding to the message-id from the statusbar
 * @param statusbar a statusbar
 * @param message_id the message-id of the message to remove. It has been returned
 * when you pushed the message with @a etk_statusbar_push()
 */
void etk_statusbar_message_remove(Etk_Statusbar *statusbar, int message_id)
{
   Eina_List *l;
   Etk_Statusbar_Msg *m;

   if (!statusbar)
      return;

   for (l = statusbar->msg_stack; l; l = l->next)
   {
      m = l->data;
      if (m->message_id == message_id)
      {
         free(m->msg);
         free(m);
         statusbar->msg_stack = eina_list_remove_list(statusbar->msg_stack, l);
         _etk_statusbar_update(statusbar);
         etk_object_notify(ETK_OBJECT(statusbar), "current-message");
         break;
      }
   }
}
示例#24
0
/**
 * @brief Sets the style of toolbar's tool-buttons (icon, text, both vertically, both horizontally)
 * @param toolbar a toolbar
 * @param style the style to set
 */
void etk_toolbar_style_set(Etk_Toolbar *toolbar, Etk_Toolbar_Style style)
{
   Eina_List *children, *l;
   Etk_Button_Style button_style;

   if (!toolbar || toolbar->style == style)
      return;

   toolbar->style = style;
   switch (style)
   {
      case ETK_TOOLBAR_ICON:
         button_style = ETK_BUTTON_ICON;
         break;
      case ETK_TOOLBAR_TEXT:
         button_style = ETK_BUTTON_TEXT;
         break;
      case ETK_TOOLBAR_BOTH_VERT:
         button_style = ETK_BUTTON_BOTH_VERT;
         break;
      case ETK_TOOLBAR_BOTH_HORIZ:
         button_style = ETK_BUTTON_BOTH_HORIZ;
         break;
      default:
         button_style = ETK_BUTTON_BOTH_VERT;
         break;
   }

   children = etk_container_children_get(ETK_CONTAINER(toolbar->box));
   for (l = children; l; l = l->next)
   {
      if (ETK_IS_TOOL_ITEM(l->data))
         etk_button_style_set(ETK_BUTTON(l->data), button_style);
   }
   eina_list_free(children);

   etk_object_notify(ETK_OBJECT(toolbar), "style");
}
示例#25
0
/**
 * @brief Inserts a text with a specific length into a string, at a given position
 * @param string a string. If @a string is NULL, a new string is created
 * @param pos the position where to insert the text (starting from 0)
 * @param text the text to insert into the string
 * @param length the maximum length of the text to insert
 * @return Returns the string
 */
Etk_String *etk_string_insert_sized(Etk_String *string, int pos, const char *text, int length)
{
   if (!string)
      return etk_string_new_sized(text, length);
   if (!text || text[0] == '\0' || length <= 0)
      return string;

   pos = ETK_CLAMP(pos, 0, string->length);
   length = _etk_string_strlen_max(text, length);
   if (string->length + length > string->allocated_length)
   {
      string->string = realloc(string->string, SIZE_TO_ALLOC(string->length + length) + 1);
      string->allocated_length = SIZE_TO_ALLOC(string->length + length);
   }

   memmove(&string->string[pos + length], &string->string[pos], string->length - pos);
   strncpy(&string->string[pos], text, length);
   string->length += length;
   string->string[string->length] = '\0';

   etk_object_notify(ETK_OBJECT(string), "string");
   return string;
}
示例#26
0
/**
 * @brief Sets the toolbar's orientation (horizontal or vertical)
 * @param toolbar a toolbar
 * @param orientation the orientation to set
 */
void etk_toolbar_orientation_set(Etk_Toolbar *toolbar, Etk_Toolbar_Orientation orientation)
{
   Eina_List *children, *l;
   Etk_Widget *prev_box;

   if (!toolbar || toolbar->orientation == orientation)
      return;

   toolbar->reorientating = ETK_TRUE;
   prev_box = toolbar->box;
   toolbar->orientation = orientation;
   if (toolbar->orientation == ETK_TOOLBAR_VERT)
      toolbar->box = etk_vbox_new(ETK_FALSE, 0);
   else
      toolbar->box = etk_hbox_new(ETK_FALSE, 0);
   etk_widget_internal_set(toolbar->box, ETK_TRUE);
   etk_widget_show(toolbar->box);

   etk_signal_connect_by_code(ETK_CONTAINER_CHILD_ADDED_SIGNAL, ETK_OBJECT(toolbar->box), ETK_CALLBACK(_etk_toolbar_child_added_cb), toolbar);
   etk_signal_connect_by_code(ETK_CONTAINER_CHILD_REMOVED_SIGNAL, ETK_OBJECT(toolbar->box), ETK_CALLBACK(_etk_toolbar_child_removed_cb), NULL);


   children = etk_container_children_get(ETK_CONTAINER(prev_box));
   for (l = children; l; l = l->next)
      etk_toolbar_append(toolbar, ETK_WIDGET(l->data), ETK_BOX_START);
   eina_list_free(children);
   etk_object_destroy(ETK_OBJECT(prev_box));

   if (toolbar->orientation == ETK_TOOLBAR_VERT)
      etk_widget_theme_group_set(ETK_WIDGET(toolbar), "vtoolbar");
   else
      etk_widget_theme_group_set(ETK_WIDGET(toolbar), "htoolbar");
   etk_widget_parent_set(toolbar->box, ETK_WIDGET(toolbar));

   toolbar->reorientating = ETK_FALSE;
   etk_object_notify(ETK_OBJECT(toolbar), "orientation");
}
示例#27
0
/**
 * @brief Sets the value of a string, with a specific size.
 * @param string a string. If @a string is NULL, a new string is created
 * @param value the value to assign to the string
 * @param size If @a size is lower than the length of @a value, the value will be truncated.
 * Otherwise, if @a size is greater than the length of @a value, extra memory will be allocated.
 * It may be useful if you plan to often insert text and want to avoid too many reallocations.
 * @return Returns the string
 */
Etk_String *etk_string_set_sized(Etk_String *string, const char *value, int size)
{
   if (!string)
      return etk_string_new_sized(value, size);

   if (!value || value[0] == '\0' || size <= 0)
      return etk_string_clear(string);
   else
   {
      if (size > string->allocated_length)
      {
         free(string->string);
         string->string = malloc(SIZE_TO_ALLOC(size) + 1);
         string->allocated_length = SIZE_TO_ALLOC(size);
      }

      string->length = _etk_string_strlen_max(value, size);
      strncpy(string->string, value, string->length);
      string->string[string->length] = '\0';
   }

   etk_object_notify(ETK_OBJECT(string), "string");
   return string;
}
示例#28
0
/**
 * @brief Resizes the table. The children that are attached to a row or a column that is removed will be unparented
 * @param table a table
 * @param num_rows the new number of rows
 * @param num_cols the new number of cols
 */
void etk_table_resize(Etk_Table *table, int num_cols, int num_rows)
{
   Eina_List *l, *next;
   Etk_Table_Cell **new_cells;
   Etk_Table_Cell *cell;
   Etk_Table_Col_Row *new_cols, *new_rows;
   Etk_Widget *child;
   int i, j;

   if (!table)
      return;

   if (num_cols < 0)
      num_cols = 0;
   if (num_rows < 0)
      num_rows = 0;

   if (num_cols == 0 && num_rows == 0)
   {
      new_cells = NULL;
      new_cols = NULL;
      new_rows = NULL;
   }
   else
   {
      new_cells = calloc(num_cols * num_rows, sizeof(Etk_Table_Cell *));
      new_cols = malloc(num_cols * sizeof(Etk_Table_Col_Row));
      new_rows = malloc(num_rows * sizeof(Etk_Table_Col_Row));
   }

   for (l = table->cells_list; l; l = next)
   {
      next = l->next;
      cell = l->data;
      child = cell->child;

      /* The child is in the old table but not in the new one: we remove it */
      if (cell->left_attach >= num_cols || cell->top_attach >= num_rows)
         etk_table_cell_clear(table, cell->left_attach, cell->top_attach);
      /* The child is in the new table: we copy it to the new table */
      else
      {
         cell->right_attach = ETK_MIN(num_cols - 1, cell->right_attach);
         cell->bottom_attach = ETK_MIN(num_rows - 1, cell->bottom_attach);
         for (i = cell->left_attach; i <= cell->right_attach; i++)
         {
            for (j = cell->top_attach; j <= cell->bottom_attach; j++)
               new_cells[j * num_cols + i] = cell;
         }
      }
   }

   free(table->cells);
   free(table->cols);
   free(table->rows);

   table->cells = new_cells;
   table->cols = new_cols;
   table->rows = new_rows;
   table->num_cols = num_cols;
   table->num_rows = num_rows;

   etk_widget_size_recalc_queue(ETK_WIDGET(table));
   etk_object_notify(ETK_OBJECT(table), "num-cols");
   etk_object_notify(ETK_OBJECT(table), "num-rows");
}