Improve the drawing of progress in entries, using fg/bg[SELECTED]. Add a

* gtk/gtkentry.c: Improve the drawing of progress in entries,
        using fg/bg[SELECTED]. Add a progress-border style property.
        Draw progress behind icons too.
        * gtk/gtkrc.c: Add defaults for fg/bg[SELECTED] in entries.
        Patch by Benjamin Berg.



svn path=/trunk/; revision=22445
This commit is contained in:
Matthias Clasen 2009-03-02 18:22:56 +00:00
parent 316e97b6eb
commit a1ec034734
3 changed files with 266 additions and 93 deletions

View File

@ -1,3 +1,13 @@
2009-03-02 Matthias Clasen <mclasen@redhat.com>
Bug 546285 Allow GtkEntry to draw progress
* gtk/gtkentry.c: Improve the drawing of progress in entries,
using fg/bg[SELECTED]. Add a progress-border style property.
Draw progress behind icons too.
* gtk/gtkrc.c: Add defaults for fg/bg[SELECTED] in entries.
Patch by Benjamin Berg.
2009-03-02 Matthias Clasen <mclasen@redhat.com>
Bug 573688 Don't steal update region in gtk_text_view_paint()

View File

@ -257,7 +257,7 @@ static void gtk_entry_size_request (GtkWidget *widget,
static void gtk_entry_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_entry_draw_frame (GtkWidget *widget,
GdkRectangle *area);
GdkEventExpose *event);
static void gtk_entry_draw_progress (GtkWidget *widget,
GdkEventExpose *event);
static gint gtk_entry_expose (GtkWidget *widget,
@ -1198,6 +1198,20 @@ gtk_entry_class_init (GtkEntryClass *class)
P_("Whether activatable icons should prelight when hovered"),
TRUE,
GTK_PARAM_READABLE));
/**
* GtkEntry::progress-border:
*
* The border around the progress bar in the entry.
*
* Since: 2.16
*/
gtk_widget_class_install_style_property (widget_class,
g_param_spec_boxed ("progress-border",
P_("Progress Border"),
P_("Border around the progress bar"),
GTK_TYPE_BORDER,
GTK_PARAM_READABLE));
/**
* GtkEntry::populate-popup:
@ -3094,8 +3108,8 @@ draw_icon (GtkWidget *widget,
static void
gtk_entry_draw_frame (GtkWidget *widget,
GdkRectangle *area)
gtk_entry_draw_frame (GtkWidget *widget,
GdkEventExpose *event)
{
GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
gint x = 0, y = 0, width, height;
@ -3134,7 +3148,10 @@ gtk_entry_draw_frame (GtkWidget *widget,
gtk_paint_shadow (widget->style, widget->window,
state, priv->shadow_type,
area, widget, "entry", x, y, width, height);
&event->area, widget, "entry", x, y, width, height);
gtk_entry_draw_progress (widget, event);
if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus)
{
@ -3144,55 +3161,123 @@ gtk_entry_draw_frame (GtkWidget *widget,
height += 2 * priv->focus_width;
gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
area, widget, "entry",
&event->area, widget, "entry",
0, 0, width, height);
}
}
static void
gtk_entry_get_progress_border (GtkWidget *widget,
GtkBorder *progress_border)
{
GtkBorder *tmp_border;
gtk_widget_style_get (widget, "progress-border", &tmp_border, NULL);
if (tmp_border)
{
*progress_border = *tmp_border;
gtk_border_free (tmp_border);
}
else
{
progress_border->left = widget->style->xthickness;
progress_border->right = widget->style->xthickness;
progress_border->top = widget->style->ythickness;
progress_border->bottom = widget->style->ythickness;
}
}
static void
get_progress_area (GtkWidget *widget,
gint *x,
gint *y,
gint *width,
gint *height)
{
GtkEntryPrivate *private = GTK_ENTRY_GET_PRIVATE (widget);
GtkEntry *entry = GTK_ENTRY (widget);
GtkBorder progress_border;
gtk_entry_get_progress_border (widget, &progress_border);
*x = progress_border.left;
*y = progress_border.top;
gdk_drawable_get_size (widget->window, width, height);
*width -= progress_border.left + progress_border.right;
*height -= progress_border.top + progress_border.bottom;
if (GTK_WIDGET_HAS_FOCUS (widget) && !private->interior_focus)
{
*x += private->focus_width;
*y += private->focus_width;
*width -= 2 * private->focus_width;
*height -= 2 * private->focus_width;
}
if (private->progress_pulse_mode)
{
gdouble value = private->progress_pulse_current;
*x += (gint) floor(value * (*width));
*width = (gint) ceil(private->progress_pulse_fraction * (*width));
}
else if (private->progress_fraction > 0)
{
gdouble value = private->progress_fraction;
if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
{
gint bar_width;
bar_width = floor(value * (*width) + 0.5);
*x += *width - bar_width;
*width = bar_width;
}
else
{
*width = (gint) floor(value * (*width) + 0.5);
}
}
else
{
*width = 0;
*height = 0;
}
}
static void
gtk_entry_draw_progress (GtkWidget *widget,
GdkEventExpose *event)
{
GtkEntryPrivate *private = GTK_ENTRY_GET_PRIVATE (widget);
GtkEntry *entry = GTK_ENTRY (widget);
gint x, y, width, height;
GtkStateType state;
if (private->progress_pulse_mode)
get_progress_area (widget, &x, &y, &width, &height);
if ((width <= 0) || (height <= 0))
return;
if (event->window != widget->window)
{
gdouble value = private->progress_pulse_current;
gint area_width, area_height;
gint pos_x, pos_y;
gdk_drawable_get_size (entry->text_area, &area_width, &area_height);
gdk_window_get_position (event->window, &pos_x, &pos_y);
gtk_paint_box (widget->style, entry->text_area,
GTK_STATE_SELECTED, GTK_SHADOW_OUT,
&event->area, widget, "entry-progress",
value * area_width, 0,
private->progress_pulse_fraction * area_width, area_height);
x -= pos_x;
y -= pos_y;
}
else if (private->progress_fraction > 0)
{
gdouble value = private->progress_fraction;
gint area_width, area_height;
gdk_drawable_get_size (entry->text_area, &area_width, &area_height);
state = GTK_STATE_SELECTED;
if (!GTK_WIDGET_SENSITIVE (widget))
state = GTK_STATE_INSENSITIVE;
if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
{
gtk_paint_box (widget->style, entry->text_area,
GTK_STATE_SELECTED, GTK_SHADOW_OUT,
&event->area, widget, "entry-progress",
area_width - value * area_width, 0,
value * area_width, area_height);
}
else
{
gtk_paint_box (widget->style, entry->text_area,
GTK_STATE_SELECTED, GTK_SHADOW_OUT,
&event->area, widget, "entry-progress",
0, 0,
value * area_width, area_height);
}
}
gtk_paint_box (widget->style, event->window,
state, GTK_SHADOW_OUT,
&event->area, widget, "entry-progress",
x, y,
width, height);
}
static gint
@ -3213,7 +3298,7 @@ gtk_entry_expose (GtkWidget *widget,
if (widget->window == event->window)
{
gtk_entry_draw_frame (widget, &event->area);
gtk_entry_draw_frame (widget, event);
}
else if (entry->text_area == event->window)
{
@ -3257,6 +3342,7 @@ gtk_entry_expose (GtkWidget *widget,
NULL, widget, "entry_bg",
0, 0, width, height);
gtk_entry_draw_progress (widget, event);
draw_icon (widget, i);
break;
@ -5356,73 +5442,134 @@ get_layout_position (GtkEntry *entry,
*y = y_pos;
}
static void
draw_text_with_color (GtkEntry *entry, cairo_t *cr, GdkColor *default_color)
{
PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
GtkWidget *widget;
gint x, y;
gint start_pos, end_pos;
widget = GTK_WIDGET (entry);
cairo_save (cr);
get_layout_position (entry, &x, &y);
cairo_move_to (cr, x, y);
gdk_cairo_set_source_color (cr, default_color);
pango_cairo_show_layout (cr, layout);
if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos))
{
gint *ranges;
gint n_ranges, i;
PangoRectangle logical_rect;
GdkColor *selection_color, *text_color;
GtkBorder inner_border;
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
if (GTK_WIDGET_HAS_FOCUS (entry))
{
selection_color = &widget->style->base [GTK_STATE_SELECTED];
text_color = &widget->style->text [GTK_STATE_SELECTED];
}
else
{
selection_color = &widget->style->base [GTK_STATE_ACTIVE];
text_color = &widget->style->text [GTK_STATE_ACTIVE];
}
_gtk_entry_effective_inner_border (entry, &inner_border);
for (i = 0; i < n_ranges; ++i)
cairo_rectangle (cr,
inner_border.left - entry->scroll_offset + ranges[2 * i],
y,
ranges[2 * i + 1],
logical_rect.height);
cairo_clip (cr);
gdk_cairo_set_source_color (cr, selection_color);
cairo_paint (cr);
cairo_move_to (cr, x, y);
gdk_cairo_set_source_color (cr, text_color);
pango_cairo_show_layout (cr, layout);
g_free (ranges);
}
cairo_restore (cr);
}
static void
gtk_entry_draw_text (GtkEntry *entry)
{
GtkWidget *widget;
GtkWidget *widget = GTK_WIDGET (entry);
cairo_t *cr;
if (!entry->visible && entry->invisible_char == 0)
return;
if (GTK_WIDGET_DRAWABLE (entry))
{
PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
cairo_t *cr;
gint x, y;
gint start_pos, end_pos;
widget = GTK_WIDGET (entry);
get_layout_position (entry, &x, &y);
GdkColor text_color, bar_text_color;
gint pos_x, pos_y;
gint width, height;
gint progress_x, progress_y, progress_width, progress_height;
GtkStateType state;
state = GTK_STATE_SELECTED;
if (!GTK_WIDGET_SENSITIVE (widget))
state = GTK_STATE_INSENSITIVE;
text_color = widget->style->text[widget->state];
bar_text_color = widget->style->fg[state];
get_progress_area (widget,
&progress_x, &progress_y,
&progress_width, &progress_height);
cr = gdk_cairo_create (entry->text_area);
cairo_move_to (cr, x, y);
gdk_cairo_set_source_color (cr, &widget->style->text [widget->state]);
pango_cairo_show_layout (cr, layout);
/* If the color is the same, or the progress area has a zero
* size, then we only need to draw once. */
if ((text_color.pixel == bar_text_color.pixel) ||
((progress_width == 0) || (progress_height == 0)))
{
draw_text_with_color (entry, cr, &text_color);
}
else
{
gdk_drawable_get_size (entry->text_area, &width, &height);
if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos))
{
gint *ranges;
gint n_ranges, i;
PangoRectangle logical_rect;
GdkColor *selection_color, *text_color;
GtkBorder inner_border;
cairo_rectangle (cr, 0, 0, width, height);
cairo_clip (cr);
cairo_save (cr);
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
cairo_rectangle (cr, 0, 0, width, height);
if (GTK_WIDGET_HAS_FOCUS (entry))
{
selection_color = &widget->style->base [GTK_STATE_SELECTED];
text_color = &widget->style->text [GTK_STATE_SELECTED];
}
else
{
selection_color = &widget->style->base [GTK_STATE_ACTIVE];
text_color = &widget->style->text [GTK_STATE_ACTIVE];
}
gdk_window_get_position (entry->text_area, &pos_x, &pos_y);
progress_x -= pos_x;
progress_y -= pos_y;
_gtk_entry_effective_inner_border (entry, &inner_border);
cairo_rectangle (cr, progress_x, progress_y,
progress_width, progress_height);
cairo_clip (cr);
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
draw_text_with_color (entry, cr, &text_color);
cairo_restore (cr);
for (i = 0; i < n_ranges; ++i)
cairo_rectangle (cr,
inner_border.left - entry->scroll_offset + ranges[2 * i],
y,
ranges[2 * i + 1],
logical_rect.height);
cairo_rectangle (cr, progress_x, progress_y,
progress_width, progress_height);
cairo_clip (cr);
cairo_clip (cr);
gdk_cairo_set_source_color (cr, selection_color);
cairo_paint (cr);
cairo_move_to (cr, x, y);
gdk_cairo_set_source_color (cr, text_color);
pango_cairo_show_layout (cr, layout);
g_free (ranges);
}
draw_text_with_color (entry, cr, &bar_text_color);
}
cairo_destroy (cr);
}
@ -9434,6 +9581,8 @@ gtk_entry_set_progress_fraction (GtkEntry *entry,
{
GtkEntryPrivate *private;
gdouble old_fraction;
gint x, y, width, height;
gint old_x, old_y, old_width, old_height;
g_return_if_fail (GTK_IS_ENTRY (entry));
@ -9444,14 +9593,22 @@ gtk_entry_set_progress_fraction (GtkEntry *entry,
else
old_fraction = private->progress_fraction;
if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (entry)))
get_progress_area (GTK_WIDGET(entry), &old_x, &old_y, &old_width, &old_height);
fraction = CLAMP (fraction, 0.0, 1.0);
private->progress_fraction = fraction;
private->progress_pulse_mode = FALSE;
private->progress_pulse_current = 0.0;
if (fabs (fraction - old_fraction) > 0.0001)
gtk_entry_queue_draw (entry);
if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (entry)))
{
get_progress_area (GTK_WIDGET(entry), &x, &y, &width, &height);
if ((x != old_x) || (y != old_y) || (width != old_width) || (height != old_height))
gtk_widget_queue_draw (GTK_WIDGET (entry));
}
if (fraction != old_fraction)
g_object_notify (G_OBJECT (entry), "progress-fraction");
@ -9506,7 +9663,7 @@ gtk_entry_set_progress_pulse_step (GtkEntry *entry,
{
private->progress_pulse_fraction = fraction;
gtk_entry_queue_draw (entry);
gtk_widget_queue_draw (GTK_WIDGET (entry));
g_object_notify (G_OBJECT (entry), "progress-pulse-step");
}
@ -9587,7 +9744,7 @@ gtk_entry_progress_pulse (GtkEntry *entry)
private->progress_pulse_current = 0.0;
}
gtk_entry_queue_draw (entry);
gtk_widget_queue_draw (GTK_WIDGET (entry));
}
/* Caps Lock warning for password entries */

View File

@ -867,6 +867,11 @@ _gtk_rc_init (void)
" bg[NORMAL] = \"#c4c2bd\"\n"
"}\n"
"\n"
"style \"gtk-default-entry-style\" {\n"
" bg[SELECTED] = \"#b7c3cd\"\n"
" fg[SELECTED] = \"#000000\"\n"
"}\n"
"\n"
"style \"gtk-default-menu-bar-item-style\" {\n"
" GtkMenuItem::horizontal_padding = 5\n"
"}\n"
@ -884,6 +889,7 @@ _gtk_rc_init (void)
"}\n"
"\n"
"class \"GtkProgressBar\" style : gtk \"gtk-default-progress-bar-style\"\n"
"class \"GtkEntry\" style : gtk \"gtk-default-entry-style\"\n"
"widget \"gtk-tooltip*\" style : gtk \"gtk-default-tooltips-style\"\n"
"widget_class \"*<GtkMenuItem>*\" style : gtk \"gtk-default-menu-item-style\"\n"
"widget_class \"*<GtkMenuBar>*<GtkMenuItem>\" style : gtk \"gtk-default-menu-bar-item-style\"\n"