static void anjuta_tabber_get_preferred_width (GtkWidget* widget, gint* minimum, gint* preferred) { g_return_if_fail (ANJUTA_IS_TABBER (widget)); AnjutaTabber* tabber = ANJUTA_TABBER (widget); GtkStyleContext* context; GList* child; gint focus_width; gint focus_pad; gint tab_curvature; gint tab_overlap; *minimum = 0; *preferred = 0; gtk_widget_style_get (GTK_WIDGET (tabber->priv->notebook), "focus-line-width", &focus_width, "focus-padding", &focus_pad, "tab-curvature", &tab_curvature, "tab-overlap", &tab_overlap, NULL); context = gtk_widget_get_style_context (widget); for (child = tabber->priv->children; child != NULL; child = g_list_next (child)) { GtkStateFlags state; GtkBorder tab_padding; gint xpadding; gint child_min; gint child_preferred; gint extra_space = 2 * (tab_curvature - tab_overlap); /* Get the padding of the tab */ gtk_style_context_save (context); anjuta_tabber_setup_style_context (tabber, context, child, &state, NULL); gtk_style_context_get_padding (context, state, &tab_padding); gtk_style_context_restore (context); xpadding = 2 * (focus_width + focus_pad) + tab_padding.left + tab_padding.right; if (child->prev == NULL) extra_space += tab_overlap; if (child->next == NULL) extra_space += tab_overlap; gtk_widget_get_preferred_width (GTK_WIDGET (child->data), &child_min, &child_preferred); if (minimum) { *minimum += child_min + xpadding + extra_space; } if (preferred) { *preferred += child_preferred + xpadding + extra_space; } } }
static gboolean anjuta_tabber_draw (GtkWidget* widget, cairo_t* cr) { AnjutaTabber* tabber; GList* current_tab; GList* child; g_return_val_if_fail (ANJUTA_IS_TABBER (widget), FALSE); tabber = ANJUTA_TABBER (widget); if (!tabber->priv->children) return TRUE; current_tab = g_list_nth (tabber->priv->children, tabber->priv->active_page); /* Draw the current tab last since it overlaps the others */ for (child = tabber->priv->children; child != current_tab; child = g_list_next (child)) { anjuta_tabber_draw_tab (tabber, cr, child); } for (child = g_list_last (tabber->priv->children); child != current_tab; child = g_list_previous (child)) { anjuta_tabber_draw_tab (tabber, cr, child); } anjuta_tabber_draw_tab (tabber, cr, current_tab); return GTK_WIDGET_CLASS (anjuta_tabber_parent_class)->draw (widget, cr); }
static void anjuta_tabber_get_preferred_height (GtkWidget* widget, gint* minimum, gint* preferred) { g_return_if_fail (ANJUTA_IS_TABBER (widget)); AnjutaTabber* tabber = ANJUTA_TABBER (widget); GList* child; gint focus_width; gtk_widget_style_get (GTK_WIDGET (tabber), "focus-line-width", &focus_width, NULL); for (child = tabber->priv->children; child != NULL; child = g_list_next (child)) { gint child_min; gint child_preferred; gtk_widget_get_preferred_height (GTK_WIDGET (child->data), &child_min, &child_preferred); if (minimum) { *minimum = MAX(*minimum, child_min + 2 * (focus_width + tabber->priv->tab_vborder)); } if (preferred) { *preferred = MAX(*preferred, child_preferred + 2 * (focus_width + tabber->priv->tab_vborder)); } } }
static void anjuta_tabber_get_preferred_width (GtkWidget* widget, gint* minimum, gint* preferred) { g_return_if_fail (ANJUTA_IS_TABBER (widget)); AnjutaTabber* tabber = ANJUTA_TABBER (widget); GList* child; gint xthickness; gint focus_width; gint tab_curvature; gint tab_overlap; gint padding; GtkStyle* style = gtk_widget_get_style (widget); xthickness = style->xthickness; *minimum = 0; *preferred = 0; gtk_widget_style_get (GTK_WIDGET (tabber->priv->notebook), "focus-line-width", &focus_width, "tab-curvature", &tab_curvature, "tab-overlap", &tab_overlap, NULL); padding = xthickness + focus_width + tabber->priv->tab_hborder; for (child = tabber->priv->children; child != NULL; child = g_list_next (child)) { gint child_min; gint child_preferred; gint extra_space = 2 * (tab_curvature - tab_overlap); if (child == g_list_first (tabber->priv->children)) extra_space += tab_overlap; if (child == g_list_last (tabber->priv->children)) extra_space += tab_overlap; gtk_widget_get_preferred_width (GTK_WIDGET (child->data), &child_min, &child_preferred); if (minimum) { *minimum += child_min + 2 * padding + extra_space; } if (preferred) { *preferred += child_preferred + 2 * padding + extra_space; } } }
static void anjuta_tabber_forall (GtkContainer* container, gboolean include_internals, GtkCallback callback, gpointer callback_data) { g_return_if_fail (ANJUTA_IS_TABBER (container)); AnjutaTabber* tabber = ANJUTA_TABBER (container); GList* child; for (child = tabber->priv->children; child != NULL; child = g_list_next (child)) { (* callback) (GTK_WIDGET(child->data), callback_data); } }
static void anjuta_tabber_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { g_return_if_fail (ANJUTA_IS_TABBER (object)); switch (prop_id) { case PROP_NOTEBOOK: g_value_set_object (value, object); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void anjuta_tabber_get_preferred_height (GtkWidget* widget, gint* minimum, gint* preferred) { g_return_if_fail (ANJUTA_IS_TABBER (widget)); AnjutaTabber* tabber = ANJUTA_TABBER (widget); GtkStyleContext* context; GList* child; gint focus_width; gint focus_pad; gtk_widget_style_get (GTK_WIDGET (tabber), "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL); context = gtk_widget_get_style_context (widget); for (child = tabber->priv->children; child != NULL; child = g_list_next (child)) { GtkStateFlags state; GtkBorder tab_padding; gint ypadding; gint child_min; gint child_preferred; /* Get the padding of the tab */ gtk_style_context_save (context); anjuta_tabber_setup_style_context (tabber, context, child, &state, NULL); gtk_style_context_get_padding (context, state, &tab_padding); gtk_style_context_restore (context); ypadding = 2 * (focus_width + focus_pad) + tab_padding.top + tab_padding.bottom; gtk_widget_get_preferred_height (GTK_WIDGET (child->data), &child_min, &child_preferred); if (minimum) { *minimum = MAX(*minimum, child_min + ypadding); } if (preferred) { *preferred = MAX(*preferred, child_preferred + ypadding); } } }
static void anjuta_tabber_add (GtkContainer* container, GtkWidget* widget) { g_return_if_fail (ANJUTA_IS_TABBER (container)); g_return_if_fail (GTK_IS_WIDGET (widget)); AnjutaTabber* tabber = ANJUTA_TABBER (container); gboolean visible = gtk_widget_get_visible (widget); tabber->priv->children = g_list_append (tabber->priv->children, widget); gtk_widget_set_parent (widget, GTK_WIDGET (tabber)); if (visible) { gtk_container_resize_children (GTK_CONTAINER (tabber)); gtk_widget_queue_resize (widget); } }
static void anjuta_tabber_remove (GtkContainer* container, GtkWidget* widget) { g_return_if_fail (ANJUTA_IS_TABBER (container)); g_return_if_fail (GTK_IS_WIDGET (widget)); AnjutaTabber* tabber = ANJUTA_TABBER (container); gboolean visible = gtk_widget_get_visible (widget); gtk_widget_unparent (widget); tabber->priv->children = g_list_remove (tabber->priv->children, widget); if (tabber->priv->active_page > 0) tabber->priv->active_page--; if (visible) gtk_widget_queue_resize (GTK_WIDGET (tabber)); }
static void anjuta_tabber_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { g_return_if_fail (ANJUTA_IS_TABBER (object)); AnjutaTabber* tabber = ANJUTA_TABBER (object); switch (prop_id) { case PROP_NOTEBOOK: tabber->priv->notebook = g_value_get_object (value); anjuta_tabber_connect_notebook (tabber); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void anjuta_tabber_size_allocate(GtkWidget* widget, GtkAllocation* allocation) { g_return_if_fail (ANJUTA_IS_TABBER (widget)); AnjutaTabber* tabber = ANJUTA_TABBER (widget); GtkStyleContext* context; GList* child; gint focus_width; gint focus_pad; gint tab_curvature; gint tab_overlap; gint n_children = g_list_length (tabber->priv->children); gint x; gint focus_space; gint tab_space; context = gtk_widget_get_style_context (widget); gtk_widget_style_get (GTK_WIDGET (tabber), "focus-line-width", &focus_width, "focus-padding", &focus_pad, "tab-curvature", &tab_curvature, "tab-overlap", &tab_overlap, NULL); focus_space = focus_width + focus_pad; tab_space = tab_curvature - tab_overlap; gtk_widget_set_allocation (widget, allocation); switch (gtk_widget_get_direction (widget)) { case GTK_TEXT_DIR_RTL: x = allocation->x + allocation->width; break; case GTK_TEXT_DIR_LTR: default: x = allocation->x; } if (gtk_widget_get_realized (widget)) { gdk_window_move_resize (tabber->priv->event_window, allocation->x, allocation->y, allocation->width, allocation->height); if (gtk_widget_get_mapped (widget)) gdk_window_show_unraised (tabber->priv->event_window); } if (n_children > 0) { gint total_space; gint total_width; gboolean use_natural = FALSE; gint child_equal; gint extra_space = 0; gint real_width = allocation->width; /* Calculate the total space that is used for padding/overlap */ total_space = 2 * tab_curvature + 2 * tab_space * (n_children - 1) + 2 * focus_space * n_children; for (child = tabber->priv->children; child != NULL; child = g_list_next (child)) { GtkStateFlags state; GtkBorder tab_padding; /* Get the padding of the tab */ gtk_style_context_save (context); anjuta_tabber_setup_style_context (tabber, context, child, &state, NULL); gtk_style_context_get_padding (context, state, &tab_padding); gtk_style_context_restore (context); total_space += tab_padding.left + tab_padding.right; } /* Check if we have enough space for all widgets natural size */ child_equal = (real_width - total_space) / n_children; if (child_equal < 0) return; /* Calculate the total width of the tabs */ total_width = total_space; for (child = tabber->priv->children; child != NULL; child = g_list_next (child)) { GtkWidget* child_widget = GTK_WIDGET (child->data); gint natural; gtk_widget_get_preferred_width (child_widget, NULL, &natural); total_width += natural; if (natural < child_equal) extra_space += child_equal - natural; } use_natural = (total_width <= real_width); child_equal += extra_space / n_children; for (child = tabber->priv->children; child != NULL; child = g_list_next (child)) { GtkWidget* child_widget = GTK_WIDGET (child->data); GtkStateFlags state; GtkBorder tab_padding, active_padding; GtkAllocation child_alloc; gint natural; gint minimal; gint begin_tab = tab_space; gint end_tab = tab_space; /* Get the padding of the tab */ gtk_style_context_save (context); anjuta_tabber_setup_style_context (tabber, context, child, &state, NULL); gtk_style_context_get_padding (context, state, &tab_padding); gtk_style_context_get_padding (context, state | GTK_STATE_ACTIVE, &active_padding); gtk_style_context_restore (context); if (child->prev == NULL) begin_tab = tab_curvature; if (child->next == NULL) end_tab = tab_curvature; gtk_widget_get_preferred_width (child_widget, &minimal, &natural); if (use_natural) { child_alloc.width = natural; } else { if (natural < child_equal) child_alloc.width = natural; else child_alloc.width = child_equal; } /* The active pad is by definition at least the same height * as the inactive one. Therefore we always use the padding of the * active tab to calculate the height and y position of the child. */ child_alloc.height = allocation->height - 2 * focus_space - active_padding.top - active_padding.bottom; child_alloc.y = allocation->y + focus_space + active_padding.top; switch (gtk_widget_get_direction (widget)) { case GTK_TEXT_DIR_RTL: child_alloc.x = x - focus_space - tab_padding.right - begin_tab - child_alloc.width; x = child_alloc.x - focus_space - tab_padding.left - end_tab; break; case GTK_TEXT_DIR_LTR: default: child_alloc.x = x + focus_space + tab_padding.left + begin_tab; x = child_alloc.x + child_alloc.width + focus_space + tab_padding.right + end_tab; } gtk_widget_size_allocate (child_widget, &child_alloc); } } }
static void anjuta_tabber_size_allocate(GtkWidget* widget, GtkAllocation* allocation) { g_return_if_fail (ANJUTA_IS_TABBER (widget)); AnjutaTabber* tabber = ANJUTA_TABBER (widget); GList* child; gint focus_width; gint tab_curvature; gint tab_overlap; gint n_children = g_list_length (tabber->priv->children); gint x; gint padding; gint tab_space; gtk_widget_style_get (GTK_WIDGET (tabber), "focus-line-width", &focus_width, "tab-curvature", &tab_curvature, "tab-overlap", &tab_overlap, NULL); padding = focus_width + tabber->priv->tab_hborder; tab_space = tab_curvature - tab_overlap; gtk_widget_set_allocation (widget, allocation); switch (gtk_widget_get_direction (widget)) { case GTK_TEXT_DIR_RTL: x = allocation->x + allocation->width; break; case GTK_TEXT_DIR_LTR: default: x = allocation->x; } if (gtk_widget_get_realized (widget)) { gdk_window_move_resize (tabber->priv->event_window, allocation->x, allocation->y, allocation->width, allocation->height); if (gtk_widget_get_mapped (widget)) gdk_window_show_unraised (tabber->priv->event_window); } if (n_children > 0) { gint total_width = 2 * tab_overlap; gboolean use_natural = FALSE; gint child_equal; gint extra_space = 0; gint real_width = allocation->width; /* Check if we have enough space for all widgets natural size */ child_equal = real_width / n_children - n_children * 2 * (padding + tab_space) - 2 * tab_overlap; if (child_equal < 0) return; for (child = tabber->priv->children; child != NULL; child = g_list_next (child)) { GtkWidget* child_widget = GTK_WIDGET (child->data); gint natural; gtk_widget_get_preferred_width (child_widget, NULL, &natural); total_width += natural + 2 * (padding + tab_space); if (natural < child_equal) extra_space += child_equal - natural; } use_natural = (total_width <= real_width); child_equal += extra_space / n_children; for (child = tabber->priv->children; child != NULL; child = g_list_next (child)) { GtkWidget* child_widget = GTK_WIDGET (child->data); GtkAllocation child_alloc; gint natural; gint minimal; gint begin_tab = tab_space; gint end_tab = tab_space; if (child == g_list_first (tabber->priv->children)) begin_tab += tab_overlap; if (child == g_list_last (tabber->priv->children)) end_tab += tab_overlap; gtk_widget_get_preferred_width (child_widget, &minimal, &natural); if (use_natural) { child_alloc.width = natural; } else { if (natural < child_equal) child_alloc.width = natural; else child_alloc.width = child_equal; } child_alloc.height = allocation->height - 2 * (focus_width + tabber->priv->tab_vborder); switch (gtk_widget_get_direction (widget)) { case GTK_TEXT_DIR_RTL: child_alloc.x = x - padding - begin_tab - child_alloc.width; x = child_alloc.x - padding - end_tab; break; case GTK_TEXT_DIR_LTR: default: child_alloc.x = x + padding + begin_tab; x = child_alloc.x + child_alloc.width + padding + end_tab; } child_alloc.y = allocation->y + tabber->priv->tab_vborder + focus_width; gtk_widget_size_allocate (GTK_WIDGET (child->data), &child_alloc); } } }