Bug 546285 – Allow GtkEntry to draw progress

2008-12-05  Michael Natterer  <mitch@imendio.com>

	Bug 546285 – Allow GtkEntry to draw progress

	* gtk/gtkentry.[ch]: add new API similar to GtkProgressBar which
	allows to set the entry's progress_fraction, its progress_pulse_step
	and to let the entry's progress pulse.

	* gtk/gtk.symbols: updated.

	* tests/testgtk.c: add progress demo code to the "Entry" window.


svn path=/trunk/; revision=21846
This commit is contained in:
Michael Natterer 2008-12-05 11:31:30 +00:00 committed by Michael Natterer
parent e2d2ea6fd7
commit 9b59889847
5 changed files with 392 additions and 11 deletions

View File

@ -1,3 +1,15 @@
2008-12-05 Michael Natterer <mitch@imendio.com>
Bug 546285 Allow GtkEntry to draw progress
* gtk/gtkentry.[ch]: add new API similar to GtkProgressBar which
allows to set the entry's progress_fraction, its progress_pulse_step
and to let the entry's progress pulse.
* gtk/gtk.symbols: updated.
* tests/testgtk.c: add progress demo code to the "Entry" window.
2008-12-04 Johan Dahlin <jdahlin@async.com.br>
* gtk/gtkstatusicon.c:

View File

@ -1282,6 +1282,8 @@ gtk_entry_get_layout
gtk_entry_get_layout_offsets
gtk_entry_get_max_length
gtk_entry_get_overwrite_mode
gtk_entry_get_progress_fraction
gtk_entry_get_progress_pulse_step
gtk_entry_get_text
gtk_entry_get_text_length
gtk_entry_get_type G_GNUC_CONST
@ -1293,6 +1295,7 @@ gtk_entry_new
gtk_entry_new_with_max_length
gtk_entry_append_text
gtk_entry_prepend_text
gtk_entry_progress_pulse
gtk_entry_select_region
gtk_entry_set_position
gtk_entry_set_editable
@ -1305,6 +1308,8 @@ gtk_entry_set_inner_border
gtk_entry_set_invisible_char
gtk_entry_set_max_length
gtk_entry_set_overwrite_mode
gtk_entry_set_progress_fraction
gtk_entry_set_progress_pulse_step
gtk_entry_set_text
gtk_entry_set_visibility
gtk_entry_set_width_chars

View File

@ -26,6 +26,8 @@
*/
#include "config.h"
#include <math.h>
#include <string.h>
#include "gdk/gdkkeysyms.h"
@ -86,14 +88,20 @@ struct _GtkEntryPrivate
gfloat xalign;
gint insert_pos;
guint blink_time; /* time in msec the cursor has blinked since last user event */
guint interior_focus : 1;
guint real_changed : 1;
guint invisible_char_set : 1;
guint caps_lock_warning : 1;
guint change_count : 8;
guint interior_focus : 1;
guint real_changed : 1;
guint invisible_char_set : 1;
guint caps_lock_warning : 1;
guint change_count : 8;
guint progress_pulse_mode : 1;
guint progress_pulse_way_back : 1;
gint focus_width;
GtkShadowType shadow_type;
gdouble progress_fraction;
gdouble progress_pulse_fraction;
gdouble progress_pulse_current;
};
typedef struct _GtkEntryPasswordHint GtkEntryPasswordHint;
@ -149,7 +157,9 @@ enum {
PROP_OVERWRITE_MODE,
PROP_TEXT_LENGTH,
PROP_INVISIBLE_CHAR_SET,
PROP_CAPS_LOCK_WARNING
PROP_CAPS_LOCK_WARNING,
PROP_PROGRESS_FRACTION,
PROP_PROGRESS_PULSE_STEP
};
static guint signals[LAST_SIGNAL] = { 0 };
@ -184,6 +194,8 @@ static void gtk_entry_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_entry_draw_frame (GtkWidget *widget,
GdkRectangle *area);
static void gtk_entry_draw_progress (GtkWidget *widget,
GdkEventExpose *event);
static gint gtk_entry_expose (GtkWidget *widget,
GdkEventExpose *event);
static gint gtk_entry_button_press (GtkWidget *widget,
@ -668,6 +680,7 @@ gtk_entry_class_init (GtkEntryClass *class)
P_("Whether new text overwrites existing text"),
FALSE,
GTK_PARAM_READWRITE));
/**
* GtkEntry:text-length:
*
@ -699,8 +712,6 @@ gtk_entry_class_init (GtkEntryClass *class)
FALSE,
GTK_PARAM_READWRITE));
/**
* GtkEntry:caps-lock-warning
*
@ -717,7 +728,41 @@ gtk_entry_class_init (GtkEntryClass *class)
TRUE,
GTK_PARAM_READWRITE));
/**
* GtkEntry:progress-fraction:
*
* The current fraction of the task that's been completed.
*
* Since: 2.16
*/
g_object_class_install_property (gobject_class,
PROP_PROGRESS_FRACTION,
g_param_spec_double ("progress-fraction",
P_("Progress Fraction"),
P_("The current fraction of the task that's been completed"),
0.0,
1.0,
0.0,
GTK_PARAM_READWRITE));
/**
* GtkEntry:progress-pulse-step:
*
* The fraction of total entry width to move the progress
* bouncing block for each call to gtk_entry_progress_pulse().
*
* Since: 2.16
*/
g_object_class_install_property (gobject_class,
PROP_PROGRESS_PULSE_STEP,
g_param_spec_double ("progress-pulse-step",
P_("Progress Pulse Step"),
P_("The fraction of total entry width to move the progress bouncing block for each call to gtk_entry_progress_pulse()"),
0.0,
1.0,
0.1,
GTK_PARAM_READWRITE));
signals[POPULATE_POPUP] =
g_signal_new (I_("populate-popup"),
G_OBJECT_CLASS_TYPE (gobject_class),
@ -1142,6 +1187,14 @@ gtk_entry_set_property (GObject *object,
priv->caps_lock_warning = g_value_get_boolean (value);
break;
case PROP_PROGRESS_FRACTION:
gtk_entry_set_progress_fraction (entry, g_value_get_double (value));
break;
case PROP_PROGRESS_PULSE_STEP:
gtk_entry_set_progress_pulse_step (entry, g_value_get_double (value));
break;
case PROP_SCROLL_OFFSET:
case PROP_CURSOR_POSITION:
default:
@ -1218,6 +1271,13 @@ gtk_entry_get_property (GObject *object,
case PROP_CAPS_LOCK_WARNING:
g_value_set_boolean (value, priv->caps_lock_warning);
break;
case PROP_PROGRESS_FRACTION:
g_value_set_double (value, priv->progress_fraction);
break;
case PROP_PROGRESS_PULSE_STEP:
g_value_set_double (value, priv->progress_pulse_fraction);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1289,6 +1349,8 @@ gtk_entry_init (GtkEntry *entry)
priv->shadow_type = GTK_SHADOW_IN;
priv->xalign = 0.0;
priv->caps_lock_warning = TRUE;
priv->progress_fraction = 0.0;
priv->progress_pulse_fraction = 0.1;
gtk_drag_dest_set (GTK_WIDGET (entry),
GTK_DEST_DEFAULT_HIGHLIGHT,
@ -1784,6 +1846,52 @@ gtk_entry_draw_frame (GtkWidget *widget,
}
}
static void
gtk_entry_draw_progress (GtkWidget *widget,
GdkEventExpose *event)
{
GtkEntryPrivate *private = GTK_ENTRY_GET_PRIVATE (widget);
GtkEntry *entry = GTK_ENTRY (widget);
if (private->progress_pulse_mode)
{
gdouble value = private->progress_pulse_current;
gint area_width, area_height;
gdk_drawable_get_size (entry->text_area, &area_width, &area_height);
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);
}
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);
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);
}
}
}
static gint
gtk_entry_expose (GtkWidget *widget,
GdkEventExpose *event)
@ -1811,6 +1919,8 @@ gtk_entry_expose (GtkWidget *widget,
&event->area, widget, "entry_bg",
0, 0, area_width, area_height);
gtk_entry_draw_progress (widget, event);
if (entry->dnd_position != -1)
gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND);
@ -6628,6 +6738,179 @@ gtk_entry_get_cursor_hadjustment (GtkEntry *entry)
return g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment);
}
/**
* gtk_entry_set_progress_fraction:
* @entry: a #GtkEntry
* @fraction: fraction of the task that's been completed
*
* Causes the entry's progress indicator to "fill in" the given
* fraction of the bar. The fraction should be between 0.0 and 1.0,
* inclusive.
*
* Since: 2.16
*/
void
gtk_entry_set_progress_fraction (GtkEntry *entry,
gdouble fraction)
{
GtkEntryPrivate *private;
gdouble old_fraction;
g_return_if_fail (GTK_IS_ENTRY (entry));
private = GTK_ENTRY_GET_PRIVATE (entry);
if (private->progress_pulse_mode)
old_fraction = -1;
else
old_fraction = private->progress_fraction;
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 (fraction != old_fraction)
g_object_notify (G_OBJECT (entry), "progress-fraction");
}
/**
* gtk_entry_get_progress_fraction:
* @entry: a #GtkEntry
*
* Returns the current fraction of the task that's been completed.
* See gtk_entry_set_progress_fraction().
*
* Return value: a fraction from 0.0 to 1.0
*
* Since: 2.16
*/
gdouble
gtk_entry_get_progress_fraction (GtkEntry *entry)
{
GtkEntryPrivate *private;
g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
private = GTK_ENTRY_GET_PRIVATE (entry);
return private->progress_fraction;
}
/**
* gtk_entry_set_progress_pulse_step:
* @entry: a #GtkEntry
* @fraction: fraction between 0.0 and 1.0
*
* Sets the fraction of total entry width to move the progress
* bouncing block for each call to gtk_entry_progress_pulse().
*
* Since: 2.16
*/
void
gtk_entry_set_progress_pulse_step (GtkEntry *entry,
gdouble fraction)
{
GtkEntryPrivate *private;
g_return_if_fail (GTK_IS_ENTRY (entry));
private = GTK_ENTRY_GET_PRIVATE (entry);
fraction = CLAMP (fraction, 0.0, 1.0);
if (fraction != private->progress_pulse_fraction)
{
private->progress_pulse_fraction = fraction;
gtk_entry_queue_draw (entry);
g_object_notify (G_OBJECT (entry), "progress-pulse-step");
}
}
/**
* gtk_entry_get_progress_pulse_step:
* @entry: a #GtkEntry
*
* Retrieves the pulse step set with gtk_entry_set_progress_pulse_step().
*
* Return value: a fraction from 0.0 to 1.0
*
* Since: 2.16
*/
gdouble
gtk_entry_get_progress_pulse_step (GtkEntry *entry)
{
GtkEntryPrivate *private;
g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
private = GTK_ENTRY_GET_PRIVATE (entry);
return private->progress_pulse_fraction;
}
/**
* gtk_entry_progress_pulse:
* @entry: a #GtkEntry
*
* Indicates that some progress is made, but you don't know how much.
* Causes the entry's progress indicator to enter "activity mode,"
* where a block bounces back and forth. Each call to
* gtk_entry_progress_pulse() causes the block to move by a little bit
* (the amount of movement per pulse is determined by
* gtk_entry_set_progress_pulse_step()).
*
* Since: 2.16
*/
void
gtk_entry_progress_pulse (GtkEntry *entry)
{
GtkEntryPrivate *private;
g_return_if_fail (GTK_IS_ENTRY (entry));
private = GTK_ENTRY_GET_PRIVATE (entry);
if (private->progress_pulse_mode)
{
if (private->progress_pulse_way_back)
{
private->progress_pulse_current -= private->progress_pulse_fraction;
if (private->progress_pulse_current < 0.0)
{
private->progress_pulse_current = 0.0;
private->progress_pulse_way_back = FALSE;
}
}
else
{
private->progress_pulse_current += private->progress_pulse_fraction;
if (private->progress_pulse_current > 1.0 - private->progress_pulse_fraction)
{
private->progress_pulse_current = 1.0 - private->progress_pulse_fraction;
private->progress_pulse_way_back = TRUE;
}
}
}
else
{
private->progress_fraction = 0.0;
private->progress_pulse_mode = TRUE;
private->progress_pulse_way_back = FALSE;
private->progress_pulse_current = 0.0;
}
gtk_entry_queue_draw (entry);
}
/* Caps Lock warning for password entries */
static void
@ -6793,6 +7076,5 @@ keymap_state_changed (GdkKeymap *keymap,
remove_capslock_feedback (entry);
}
#define __GTK_ENTRY_C__
#include "gtkaliasdef.c"

View File

@ -212,6 +212,18 @@ void gtk_entry_set_cursor_hadjustment (GtkEntry *entry,
GtkAdjustment *adjustment);
GtkAdjustment* gtk_entry_get_cursor_hadjustment (GtkEntry *entry);
/* Progress API
*/
void gtk_entry_set_progress_fraction (GtkEntry *entry,
gdouble fraction);
gdouble gtk_entry_get_progress_fraction (GtkEntry *entry);
void gtk_entry_set_progress_pulse_step (GtkEntry *entry,
gdouble fraction);
gdouble gtk_entry_get_progress_pulse_step (GtkEntry *entry);
void gtk_entry_progress_pulse (GtkEntry *entry);
/* Deprecated compatibility functions
*/

View File

@ -5193,6 +5193,65 @@ entry_toggle_sensitive (GtkWidget *checkbutton,
gtk_widget_set_sensitive (entry, GTK_TOGGLE_BUTTON(checkbutton)->active);
}
static gboolean
entry_progress_timeout (gpointer data)
{
if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (data), "progress-pulse")))
{
gtk_entry_progress_pulse (GTK_ENTRY (data));
}
else
{
gdouble fraction;
fraction = gtk_entry_get_progress_fraction (GTK_ENTRY (data));
fraction += 0.05;
if (fraction > 1.0001)
fraction = 0.0;
gtk_entry_set_progress_fraction (GTK_ENTRY (data), fraction);
}
return TRUE;
}
static void
entry_remove_timeout (gpointer data)
{
g_source_remove (GPOINTER_TO_UINT (data));
}
static void
entry_toggle_progress (GtkWidget *checkbutton,
GtkWidget *entry)
{
if (GTK_TOGGLE_BUTTON (checkbutton)->active)
{
guint timeout = gdk_threads_add_timeout (100,
entry_progress_timeout,
entry);
g_object_set_data_full (G_OBJECT (entry), "timeout-id",
GUINT_TO_POINTER (timeout),
entry_remove_timeout);
}
else
{
g_object_set_data (G_OBJECT (entry), "timeout-id",
GUINT_TO_POINTER (0));
gtk_entry_set_progress_fraction (GTK_ENTRY (entry), 0.0);
}
}
static void
entry_toggle_pulse (GtkWidget *checkbutton,
GtkWidget *entry)
{
g_object_set_data (G_OBJECT (entry), "progress-pulse",
GINT_TO_POINTER (GTK_TOGGLE_BUTTON (checkbutton)->active));
}
static void
entry_props_clicked (GtkWidget *button,
GObject *entry)
@ -5211,6 +5270,7 @@ create_entry (GtkWidget *widget)
GtkWidget *hbox;
GtkWidget *has_frame_check;
GtkWidget *sensitive_check;
GtkWidget *progress_check;
GtkWidget *entry, *cb;
GtkWidget *button;
GtkWidget *separator;
@ -5281,7 +5341,17 @@ create_entry (GtkWidget *widget)
g_signal_connect (has_frame_check, "toggled",
G_CALLBACK (entry_toggle_frame), entry);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (has_frame_check), TRUE);
progress_check = gtk_check_button_new_with_label("Show Progress");
gtk_box_pack_start (GTK_BOX (box2), progress_check, FALSE, TRUE, 0);
g_signal_connect (progress_check, "toggled",
G_CALLBACK (entry_toggle_progress), entry);
progress_check = gtk_check_button_new_with_label("Pulse Progress");
gtk_box_pack_start (GTK_BOX (box2), progress_check, FALSE, TRUE, 0);
g_signal_connect (progress_check, "toggled",
G_CALLBACK (entry_toggle_pulse), entry);
separator = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);