X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcellrenderertext.c;h=3399bb2be0450e7f63164e1200b3fb9b4a7e9a00;hb=HEAD;hp=cf58d4dacbde0b7a1514bced623a750948312f4e;hpb=1779ae79a13029a4efb77b2ab4b39393a3a9c9b8;p=~andy%2Fgtk diff --git a/gtk/gtkcellrenderertext.c b/gtk/gtkcellrenderertext.c index cf58d4dac..3399bb2be 100644 --- a/gtk/gtkcellrenderertext.c +++ b/gtk/gtkcellrenderertext.c @@ -12,9 +12,7 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ #include "config.h" @@ -30,6 +28,7 @@ #include "gtkintl.h" #include "gtkprivate.h" #include "gtktreeprivate.h" +#include "a11y/gtktextcellaccessible.h" /** @@ -84,6 +83,13 @@ static void gtk_cell_renderer_text_get_preferred_height_for_width (GtkCell gint width, gint *minimum_height, gint *natural_height); +static void gtk_cell_renderer_text_get_aligned_area (GtkCellRenderer *cell, + GtkWidget *widget, + GtkCellRendererState flags, + const GdkRectangle *cell_area, + GdkRectangle *aligned_area); + + enum { EDITED, @@ -101,7 +107,8 @@ enum { PROP_MAX_WIDTH_CHARS, PROP_WRAP_WIDTH, PROP_ALIGN, - + PROP_PLACEHOLDER_TEXT, + /* Style args */ PROP_BACKGROUND, PROP_FOREGROUND, @@ -154,19 +161,18 @@ struct _GtkCellRendererTextPrivate { GtkWidget *entry; - PangoAlignment align; PangoAttrList *extra_attrs; GdkRGBA foreground; GdkRGBA background; + PangoAlignment align; PangoEllipsizeMode ellipsize; PangoFontDescription *font; PangoLanguage *language; PangoUnderline underline_style; PangoWrapMode wrap_mode; - gboolean in_entry_menu; - gchar *text; + gchar *placeholder_text; gdouble font_scale; @@ -176,6 +182,7 @@ struct _GtkCellRendererTextPrivate gint max_width_chars; gint wrap_width; + guint in_entry_menu : 1; guint strikethrough : 1; guint editable : 1; guint scale_set : 1; @@ -240,6 +247,7 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class) cell_class->get_preferred_width = gtk_cell_renderer_text_get_preferred_width; cell_class->get_preferred_height = gtk_cell_renderer_text_get_preferred_height; cell_class->get_preferred_height_for_width = gtk_cell_renderer_text_get_preferred_height_for_width; + cell_class->get_aligned_area = gtk_cell_renderer_text_get_aligned_area; g_object_class_install_property (object_class, PROP_TEXT, @@ -282,13 +290,20 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class) NULL, GTK_PARAM_WRITABLE)); + /** + * GtkCellRendererText:background-gdk: + * + * Background color as a #GdkColor + * + * Deprecated: 3.4: Use #GtkCellRendererText:background-rgba instead. + */ g_object_class_install_property (object_class, PROP_BACKGROUND_GDK, g_param_spec_boxed ("background-gdk", P_("Background color"), P_("Background color as a GdkColor"), GDK_TYPE_COLOR, - GTK_PARAM_READWRITE)); + GTK_PARAM_READWRITE | G_PARAM_DEPRECATED)); /** * GtkCellRendererText:background-rgba: @@ -312,13 +327,20 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class) NULL, GTK_PARAM_WRITABLE)); + /** + * GtkCellRendererText:foreground-gdk: + * + * Foreground color as a #GdkColor + * + * Deprecated: 3.4: Use #GtkCellRendererText:foreground-rgba instead. + */ g_object_class_install_property (object_class, PROP_FOREGROUND_GDK, g_param_spec_boxed ("foreground-gdk", P_("Foreground color"), P_("Foreground color as a GdkColor"), GDK_TYPE_COLOR, - GTK_PARAM_READWRITE)); + GTK_PARAM_READWRITE | G_PARAM_DEPRECATED)); /** * GtkCellRendererText:foreground-rgba: @@ -599,7 +621,22 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class) PANGO_TYPE_ALIGNMENT, PANGO_ALIGN_LEFT, GTK_PARAM_READWRITE)); - + + /** + * GtkCellRendererText:placeholder-text: + * + * The text that will be displayed in the #GtkCellRenderer if + * #GtkCellRendererText:editable is %TRUE and the cell is empty. + * + * Since 3.6 + */ + g_object_class_install_property (object_class, + PROP_PLACEHOLDER_TEXT, + g_param_spec_string ("placeholder-text", + P_("Placeholder text"), + P_("Text rendered when an editable cell is empty"), + NULL, + GTK_PARAM_READWRITE)); /* Style props are set or not */ @@ -671,7 +708,7 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class) P_("Whether this tag affects the alignment mode")); /** - * GtkCellRendererText::edited + * GtkCellRendererText::edited: * @renderer: the object which received the signal * @path: the path identifying the edited cell * @new_text: the new text @@ -693,6 +730,8 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class) G_TYPE_STRING); g_type_class_add_private (object_class, sizeof (GtkCellRendererTextPrivate)); + + gtk_cell_renderer_class_set_accessible_type (cell_class, GTK_TYPE_TEXT_CELL_ACCESSIBLE); } static void @@ -704,6 +743,7 @@ gtk_cell_renderer_text_finalize (GObject *object) pango_font_description_free (priv->font); g_free (priv->text); + g_free (priv->placeholder_text); if (priv->extra_attrs) pango_attr_list_unref (priv->extra_attrs); @@ -711,6 +751,8 @@ gtk_cell_renderer_text_finalize (GObject *object) if (priv->language) g_object_unref (priv->language); + g_clear_object (&priv->entry); + G_OBJECT_CLASS (gtk_cell_renderer_text_parent_class)->finalize (object); } @@ -928,6 +970,10 @@ gtk_cell_renderer_text_get_property (GObject *object, g_value_set_int (value, priv->max_width_chars); break; + case PROP_PLACEHOLDER_TEXT: + g_value_set_string (value, priv->placeholder_text); + break; + case PROP_BACKGROUND: case PROP_FOREGROUND: case PROP_MARKUP: @@ -1488,7 +1534,12 @@ gtk_cell_renderer_text_set_property (GObject *object, case PROP_ALIGN_SET: priv->align_set = g_value_get_boolean (value); break; - + + case PROP_PLACEHOLDER_TEXT: + g_free (priv->placeholder_text); + priv->placeholder_text = g_value_dup_string (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -1514,6 +1565,15 @@ gtk_cell_renderer_text_new (void) return g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL); } +static inline gboolean +show_placeholder_text (GtkCellRendererText *celltext) +{ + GtkCellRendererTextPrivate *priv = celltext->priv; + + return priv->editable && priv->placeholder_text && + (!priv->text || !priv->text[0]); +} + static void add_attr (PangoAttrList *attr_list, PangoAttribute *attr) @@ -1535,8 +1595,10 @@ get_layout (GtkCellRendererText *celltext, PangoLayout *layout; PangoUnderline uline; gint xpad; + gboolean placeholder_layout = show_placeholder_text (celltext); - layout = gtk_widget_create_pango_layout (widget, priv->text); + layout = gtk_widget_create_pango_layout (widget, placeholder_layout ? + priv->placeholder_text : priv->text); gtk_cell_renderer_get_padding (GTK_CELL_RENDERER (celltext), &xpad, NULL); @@ -1547,7 +1609,7 @@ get_layout (GtkCellRendererText *celltext, pango_layout_set_single_paragraph_mode (layout, priv->single_paragraph); - if (cell_area) + if (!placeholder_layout && cell_area) { /* Add options that affect appearance but not size */ @@ -1572,6 +1634,22 @@ get_layout (GtkCellRendererText *celltext, add_attr (attr_list, pango_attr_strikethrough_new (priv->strikethrough)); } + else if (placeholder_layout) + { + PangoColor color; + GtkStyleContext *context; + GdkRGBA fg = { 0.5, 0.5, 0.5 }; + + context = gtk_widget_get_style_context (widget); + gtk_style_context_lookup_color (context, "placeholder_text_color", &fg); + + color.red = CLAMP (fg.red * 65535. + 0.5, 0, 65535); + color.green = CLAMP (fg.green * 65535. + 0.5, 0, 65535); + color.blue = CLAMP (fg.blue * 65535. + 0.5, 0, 65535); + + add_attr (attr_list, + pango_attr_foreground_new (color.red, color.green, color.blue)); + } add_attr (attr_list, pango_attr_font_desc_new (priv->font)); @@ -1682,12 +1760,17 @@ get_size (GtkCellRenderer *cell, if (priv->calc_fixed_height) { + GtkStyleContext *style_context; + GtkStateFlags state; PangoContext *context; PangoFontMetrics *metrics; PangoFontDescription *font_desc; gint row_height; - font_desc = pango_font_description_copy_static (gtk_widget_get_style (widget)->font_desc); + style_context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); + + gtk_style_context_get (style_context, state, "font", &font_desc, NULL); pango_font_description_merge_static (font_desc, priv->font, TRUE); if (priv->scale_set) @@ -1728,46 +1811,21 @@ get_size (GtkCellRenderer *cell, pango_layout_get_pixel_extents (layout, NULL, &rect); - if (height) - *height = ypad * 2 + rect.height; - - /* The minimum size for ellipsized labels is ~ 3 chars */ - if (width) - { - if (priv->ellipsize || priv->width_chars > 0) - { - PangoContext *context; - PangoFontMetrics *metrics; - gint char_width; - - context = pango_layout_get_context (layout); - metrics = pango_context_get_metrics (context, - gtk_widget_get_style (widget)->font_desc, - pango_context_get_language (context)); - - char_width = pango_font_metrics_get_approximate_char_width (metrics); - pango_font_metrics_unref (metrics); - - *width = xpad * 2 + (PANGO_PIXELS (char_width) * MAX (priv->width_chars, 3)); - } - else - { - *width = xpad * 2 + rect.x + rect.width; - } - } - if (cell_area) { gfloat xalign, yalign; gtk_cell_renderer_get_alignment (cell, &xalign, &yalign); + rect.height = MIN (rect.height, cell_area->height - 2 * ypad); + rect.width = MIN (rect.width, cell_area->width - 2 * xpad); + if (x_offset) { if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - *x_offset = (1.0 - xalign) * (cell_area->width - (rect.x + rect.width + (2 * xpad))); + *x_offset = (1.0 - xalign) * (cell_area->width - (rect.width + (2 * xpad))); else - *x_offset = xalign * (cell_area->width - (rect.x + rect.width + (2 * xpad))); + *x_offset = xalign * (cell_area->width - (rect.width + (2 * xpad))); if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->wrap_width != -1) *x_offset = MAX(*x_offset, 0); @@ -1784,6 +1842,12 @@ get_size (GtkCellRenderer *cell, if (y_offset) *y_offset = 0; } + if (height) + *height = ypad * 2 + rect.height; + + if (width) + *width = xpad * 2 + rect.width; + g_object_unref (layout); } @@ -1798,41 +1862,18 @@ gtk_cell_renderer_text_render (GtkCellRenderer *cell, { GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (cell); GtkCellRendererTextPrivate *priv = celltext->priv; + GtkStyleContext *context; PangoLayout *layout; - GtkStateType state; gint x_offset = 0; gint y_offset = 0; gint xpad, ypad; + PangoRectangle rect; layout = get_layout (celltext, widget, cell_area, flags); get_size (cell, widget, cell_area, layout, &x_offset, &y_offset, NULL, NULL); + context = gtk_widget_get_style_context (widget); - if (!gtk_cell_renderer_get_sensitive (cell)) - { - state = GTK_STATE_INSENSITIVE; - } - else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) - { - if (gtk_widget_has_focus (widget)) - state = GTK_STATE_SELECTED; - else - state = GTK_STATE_ACTIVE; - } - else if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT && - gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT) - { - state = GTK_STATE_PRELIGHT; - } - else - { - if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE) - state = GTK_STATE_INSENSITIVE; - else - state = GTK_STATE_NORMAL; - } - - if (priv->background_set && - (flags & GTK_CELL_RENDERER_SELECTED) == 0) + if (priv->background_set && (flags & GTK_CELL_RENDERER_SELECTED) == 0) { gdk_cairo_rectangle (cr, background_area); gdk_cairo_set_source_rgba (cr, &priv->background); @@ -1842,20 +1883,25 @@ gtk_cell_renderer_text_render (GtkCellRenderer *cell, gtk_cell_renderer_get_padding (cell, &xpad, &ypad); if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) - pango_layout_set_width (layout, + pango_layout_set_width (layout, (cell_area->width - x_offset - 2 * xpad) * PANGO_SCALE); else if (priv->wrap_width == -1) pango_layout_set_width (layout, -1); - gtk_paint_layout (gtk_widget_get_style (widget), - cr, - state, - TRUE, - widget, - "cellrenderertext", - cell_area->x + x_offset + xpad, - cell_area->y + y_offset + ypad, - layout); + pango_layout_get_pixel_extents (layout, NULL, &rect); + x_offset = x_offset - rect.x; + + cairo_save (cr); + + gdk_cairo_rectangle (cr, cell_area); + cairo_clip (cr); + + gtk_render_layout (context, cr, + cell_area->x + x_offset + xpad, + cell_area->y + y_offset + ypad, + layout); + + cairo_restore (cr); g_object_unref (layout); } @@ -1871,7 +1917,7 @@ gtk_cell_renderer_text_editing_done (GtkCellEditable *entry, priv = GTK_CELL_RENDERER_TEXT (data)->priv; - priv->entry = NULL; + g_clear_object (&priv->entry); if (priv->focus_out_id > 0) { @@ -1989,7 +2035,6 @@ gtk_cell_renderer_text_start_editing (GtkCellRenderer *cell, const GdkRectangle *cell_area, GtkCellRendererState flags) { - GtkRequisition requisition; GtkCellRendererText *celltext; GtkCellRendererTextPrivate *priv; gfloat xalign, yalign; @@ -2004,6 +2049,8 @@ gtk_cell_renderer_text_start_editing (GtkCellRenderer *cell, gtk_cell_renderer_get_alignment (cell, &xalign, &yalign); priv->entry = gtk_entry_new (); + g_object_ref_sink (G_OBJECT (priv->entry)); + gtk_entry_set_has_frame (GTK_ENTRY (priv->entry), FALSE); gtk_entry_set_alignment (GTK_ENTRY (priv->entry), xalign); @@ -2013,33 +2060,6 @@ gtk_cell_renderer_text_start_editing (GtkCellRenderer *cell, gtk_editable_select_region (GTK_EDITABLE (priv->entry), 0, -1); - gtk_widget_get_preferred_size (priv->entry, &requisition, NULL); - if (requisition.height < cell_area->height) - { - GtkBorder *style_border; - GtkBorder border; - - gtk_widget_style_get (priv->entry, - "inner-border", &style_border, - NULL); - - if (style_border) - { - border = *style_border; - g_boxed_free (GTK_TYPE_BORDER, style_border); - } - else - { - /* Since boxed style properties can't have default values ... */ - border.left = 2; - border.right = 2; - } - - border.top = (cell_area->height - requisition.height) / 2; - border.bottom = (cell_area->height - requisition.height) / 2; - gtk_entry_set_inner_border (GTK_ENTRY (priv->entry), &border); - } - priv->in_entry_menu = FALSE; if (priv->entry_menu_popdown_timeout) { @@ -2110,14 +2130,13 @@ gtk_cell_renderer_text_get_preferred_width (GtkCellRenderer *cell, gint *minimum_size, gint *natural_size) { - GtkCellRendererTextPrivate *priv; + GtkCellRendererTextPrivate *priv; GtkCellRendererText *celltext; - GtkStyle *style; PangoLayout *layout; PangoContext *context; PangoFontMetrics *metrics; PangoRectangle rect; - gint char_width, digit_width, char_pixels, text_width, ellipsize_chars, guess_width, xpad; + gint char_width, text_width, ellipsize_chars, xpad; gint min_width, nat_width; /* "width-chars" Hard-coded minimum width: @@ -2132,16 +2151,10 @@ gtk_cell_renderer_text_get_preferred_width (GtkCellRenderer *cell, celltext = GTK_CELL_RENDERER_TEXT (cell); priv = celltext->priv; - style = gtk_widget_get_style (widget); - gtk_cell_renderer_get_padding (cell, &xpad, NULL); layout = get_layout (celltext, widget, NULL, 0); - /* Get the layout with the text possibly wrapping at wrap_width */ - pango_layout_get_pixel_extents (layout, NULL, &rect); - guess_width = rect.width; - /* Fetch the length of the complete unwrapped text */ pango_layout_set_width (layout, -1); pango_layout_get_extents (layout, NULL, &rect); @@ -2149,12 +2162,11 @@ gtk_cell_renderer_text_get_preferred_width (GtkCellRenderer *cell, /* Fetch the average size of a charachter */ context = pango_layout_get_context (layout); - metrics = pango_context_get_metrics (context, style->font_desc, - pango_context_get_language (context)); - + metrics = pango_context_get_metrics (context, + pango_context_get_font_description (context), + pango_context_get_language (context)); + char_width = pango_font_metrics_get_approximate_char_width (metrics); - digit_width = pango_font_metrics_get_approximate_digit_width (metrics); - char_pixels = MAX (char_width, digit_width); pango_font_metrics_unref (metrics); g_object_unref (layout); @@ -2164,24 +2176,25 @@ gtk_cell_renderer_text_get_preferred_width (GtkCellRenderer *cell, ellipsize_chars = 3; else ellipsize_chars = 0; - + if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->width_chars > 0) - min_width = - xpad * 2 + (PANGO_PIXELS (char_width) * MAX (priv->width_chars, ellipsize_chars)); + min_width = xpad * 2 + + MIN (PANGO_PIXELS_CEIL (text_width), + (PANGO_PIXELS (char_width) * MAX (priv->width_chars, ellipsize_chars))); /* If no width-chars set, minimum for wrapping text will be the wrap-width */ else if (priv->wrap_width > -1) - min_width = xpad * 2 + rect.x + priv->wrap_width; + min_width = xpad * 2 + rect.x + MIN (PANGO_PIXELS_CEIL (text_width), priv->wrap_width); else - min_width = xpad * 2 + rect.x + guess_width; + min_width = xpad * 2 + rect.x + PANGO_PIXELS_CEIL (text_width); if (priv->width_chars > 0) - nat_width = xpad * 2 + - MAX ((PANGO_PIXELS (char_width) * priv->width_chars), PANGO_PIXELS (text_width)); + nat_width = xpad * 2 + + MAX ((PANGO_PIXELS (char_width) * priv->width_chars), PANGO_PIXELS_CEIL (text_width)); else - nat_width = xpad * 2 + PANGO_PIXELS (text_width); + nat_width = xpad * 2 + PANGO_PIXELS_CEIL (text_width); nat_width = MAX (nat_width, min_width); - + if (priv->max_width_chars > 0) { gint max_width = xpad * 2 + PANGO_PIXELS (char_width) * priv->max_width_chars; @@ -2195,7 +2208,6 @@ gtk_cell_renderer_text_get_preferred_width (GtkCellRenderer *cell, if (natural_size) *natural_size = nat_width; - } static void @@ -2205,14 +2217,12 @@ gtk_cell_renderer_text_get_preferred_height_for_width (GtkCellRenderer *cell, gint *minimum_height, gint *natural_height) { - GtkCellRendererTextPrivate *priv; - GtkCellRendererText *celltext; - PangoLayout *layout; - gint text_height, xpad, ypad; + GtkCellRendererText *celltext; + PangoLayout *layout; + gint text_height, xpad, ypad; celltext = GTK_CELL_RENDERER_TEXT (cell); - priv = celltext->priv; gtk_cell_renderer_get_padding (cell, &xpad, &ypad); @@ -2250,3 +2260,24 @@ gtk_cell_renderer_text_get_preferred_height (GtkCellRenderer *cell, minimum_size, natural_size); } +static void +gtk_cell_renderer_text_get_aligned_area (GtkCellRenderer *cell, + GtkWidget *widget, + GtkCellRendererState flags, + const GdkRectangle *cell_area, + GdkRectangle *aligned_area) +{ + GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (cell); + PangoLayout *layout; + gint x_offset = 0; + gint y_offset = 0; + + layout = get_layout (celltext, widget, cell_area, flags); + get_size (cell, widget, cell_area, layout, &x_offset, &y_offset, + &aligned_area->width, &aligned_area->height); + + aligned_area->x = cell_area->x + x_offset; + aligned_area->y = cell_area->y + y_offset; + + g_object_unref (layout); +}