drawingarea: Add gtk_drawing_area_set_draw_func()

This commit is contained in:
Benjamin Otte 2016-11-18 05:45:36 +01:00
parent 41d1e1fea8
commit 5940625e9e
3 changed files with 140 additions and 23 deletions

View File

@ -896,6 +896,7 @@ gtk_drawing_area_get_content_width
gtk_drawing_area_set_content_width
gtk_drawing_area_get_content_height
gtk_drawing_area_set_content_height
gtk_drawing_area_set_draw_func
<SUBSECTION Standard>
GTK_DRAWING_AREA
GTK_IS_DRAWING_AREA

View File

@ -33,6 +33,10 @@ typedef struct _GtkDrawingAreaPrivate GtkDrawingAreaPrivate;
struct _GtkDrawingAreaPrivate {
int content_width;
int content_height;
GtkDrawingAreaDrawFunc draw_func;
gpointer draw_func_target;
GDestroyNotify draw_func_target_destroy_notify;
};
enum {
@ -46,7 +50,7 @@ static GParamSpec *props[LAST_PROP] = { NULL, };
/**
* SECTION:gtkdrawingarea
* @Short_description: A widget for custom user interface elements
* @Short_description: A simple widget for custom user interface elements
* @Title: GtkDrawingArea
* @See_also: #GtkImage
*
@ -65,32 +69,30 @@ static GParamSpec *props[LAST_PROP] = { NULL, };
* - The #GtkWidget::size-allocate signal to take any necessary
* actions when the widget changes size.
*
* - The #GtkWidget::draw signal to handle redrawing the
* - Call gtk_drawing_area_set_draw_func() to handle redrawing the
* contents of the widget.
*
* The following code portion demonstrates using a drawing
* area to display a circle in the normal widget foreground
* color.
*
* Note that GDK automatically clears the exposed area before sending
* the expose event, and that drawing is implicitly clipped to the exposed
* Note that GDK automatically clears the exposed area before causing a
* redraw, and that drawing is implicitly clipped to the exposed
* area. If you want to have a theme-provided background, you need
* to call gtk_render_background() in your ::draw method.
*
* ## Simple GtkDrawingArea usage
*
* |[<!-- language="C" -->
* gboolean
* draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
* void
* draw_function (GtkDrawingArea *area, cairo_t *cr,
* int width, int height,
* gpointer data)
* {
* guint width, height;
* GdkRGBA color;
* GtkStyleContext *context;
*
* context = gtk_widget_get_style_context (widget);
*
* width = gtk_widget_get_allocated_width (widget);
* height = gtk_widget_get_allocated_height (widget);
* context = gtk_widget_get_style_context (GTK_WIDGET (area));
*
* gtk_render_background (context, cr, 0, 0, width, height);
*
@ -105,23 +107,22 @@ static GParamSpec *props[LAST_PROP] = { NULL, };
* gdk_cairo_set_source_rgba (cr, &color);
*
* cairo_fill (cr);
*
* return FALSE;
* }
* [...]
* GtkWidget *drawing_area = gtk_drawing_area_new ();
* gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (drawing_area), 100);
* gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (drawing_area), 100);
* g_signal_connect (G_OBJECT (drawing_area), "draw",
* G_CALLBACK (draw_callback), NULL);
* GtkWidget *area = gtk_drawing_area_new ();
* gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (area), 100);
* gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (area), 100);
* gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area),
* draw_function,
* NULL, NULL);
* ]|
*
* Draw signals are normally delivered when a drawing area first comes
* The draw function is normally called when a drawing area first comes
* onscreen, or when its covered by another window and then uncovered.
* You can also force an expose event by adding to the damage region
* of the drawing areas window using gtk_widget_queue_draw_region(),
* You can also force a redraw by adding to the damage region of the
* drawing areas window using gtk_widget_queue_draw_region(),
* gtk_widget_queue_draw_area() or gtk_widget_queue_draw().
* Youll then get a draw signal for the invalid region.
* This will cause the drawing area to call the draw function again.
*
* The available routines for drawing are documented on the
* [GDK Drawing Primitives][gdk3-Cairo-Interaction] page
@ -134,6 +135,9 @@ static GParamSpec *props[LAST_PROP] = { NULL, };
* area is focused. Use gtk_widget_has_focus() in your expose event
* handler to decide whether to draw the focus indicator. See
* gtk_render_focus() for one way to draw focus.
*
* If you need more complex control over your widget, you should consider
* creating your own #GtkWidget subclass.
*/
G_DEFINE_TYPE_WITH_PRIVATE (GtkDrawingArea, gtk_drawing_area, GTK_TYPE_WIDGET)
@ -185,6 +189,22 @@ gtk_drawing_area_get_property (GObject *gobject,
}
}
static void
gtk_drawing_area_dispose (GObject *object)
{
GtkDrawingArea *self = GTK_DRAWING_AREA (object);
GtkDrawingAreaPrivate *priv = gtk_drawing_area_get_instance_private (self);
if (priv->draw_func_target_destroy_notify != NULL)
priv->draw_func_target_destroy_notify (priv->draw_func_target);
priv->draw_func = NULL;
priv->draw_func_target = NULL;
priv->draw_func_target_destroy_notify = NULL;
G_OBJECT_CLASS (gtk_drawing_area_parent_class)->dispose (object);
}
static void
gtk_drawing_area_measure (GtkWidget *widget,
GtkOrientation orientation,
@ -207,6 +227,30 @@ gtk_drawing_area_measure (GtkWidget *widget,
}
}
static void
gtk_drawing_area_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkDrawingArea *self = GTK_DRAWING_AREA (widget);
GtkDrawingAreaPrivate *priv = gtk_drawing_area_get_instance_private (self);
cairo_t *cr;
if (!priv->draw_func)
return;
cr = gtk_snapshot_append_cairo_node (snapshot,
&(graphene_rect_t) GRAPHENE_RECT_INIT(0, 0,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget)),
"DrawingAreaContents");
priv->draw_func (self,
cr,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget),
priv->draw_func_target);
cairo_destroy (cr);
}
static void
gtk_drawing_area_class_init (GtkDrawingAreaClass *class)
{
@ -215,8 +259,10 @@ gtk_drawing_area_class_init (GtkDrawingAreaClass *class)
gobject_class->set_property = gtk_drawing_area_set_property;
gobject_class->get_property = gtk_drawing_area_get_property;
gobject_class->dispose = gtk_drawing_area_dispose;
widget_class->measure = gtk_drawing_area_measure;
widget_class->snapshot = gtk_drawing_area_snapshot;
/**
* GtkDrawingArea:content-width
@ -376,3 +422,46 @@ gtk_drawing_area_get_content_height (GtkDrawingArea *self)
return priv->content_height;
}
/**
* gtk_drawing_area_set_draw_func:
* @self: a #GtkDrawingArea
* @draw_func: (closure user_data) (allow-none): callback that lets you draw
* the drawing area's contents
* @user_data: user data passed to @draw_func
* @destroy: destroy notifier for @user_data
*
* Setting a draw function is the main thing you want to do when using a drawing
* area. It is called whenever GTK needs to draw the contents of the drawing area
* to the screen.
*
* The draw function will be called during the drawing stage of GTK. In the
* drawing stage it is not allowed to change properties of any GTK widgets or call
* any functions that would cause any properties to be changed.
* You should restrict yourself exclusively to drawing your contents in the draw
* function.
*
* If what you are drawing does change, call gtk_widget_queue_draw() on the
* drawing area. This will call a redraw and will call @draw_func again.
*
* Since: 3.90
*/
void
gtk_drawing_area_set_draw_func (GtkDrawingArea *self,
GtkDrawingAreaDrawFunc draw_func,
gpointer user_data,
GDestroyNotify destroy)
{
GtkDrawingAreaPrivate *priv = gtk_drawing_area_get_instance_private (self);
g_return_if_fail (GTK_IS_DRAWING_AREA (self));
if (priv->draw_func_target_destroy_notify != NULL)
priv->draw_func_target_destroy_notify (priv->draw_func_target);
priv->draw_func = draw_func;
priv->draw_func_target = user_data;
priv->draw_func_target_destroy_notify = destroy;
gtk_widget_queue_draw (GTK_WIDGET (self));
}

View File

@ -42,10 +42,32 @@ G_BEGIN_DECLS
#define GTK_IS_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_DRAWING_AREA))
#define GTK_DRAWING_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_DRAWING_AREA, GtkDrawingAreaClass))
typedef struct _GtkDrawingArea GtkDrawingArea;
typedef struct _GtkDrawingAreaClass GtkDrawingAreaClass;
/**
* GtkDrawingAreaDrawFunc:
* @drawing_area: the #GtkDrawingArea to redraw
* @cr: the context to draw to
* @width: the actual width of the contents. This value will be at least
* as wide as GtkDrawingArea:width.
* @height: the actual height of the contents. This value will be at least
* as wide as GtkDrawingArea:height.
* @user_data: (closure): user data
*
* Whenever @drawing_area needs to redraw, this function will be called.
*
* This function should exclusively redraw the contents of the drawing area
* and must not call any widget functions that cause changes.
*
* Since: 3.90
*/
typedef void (* GtkDrawingAreaDrawFunc) (GtkDrawingArea *drawing_area,
cairo_t *cr,
int width,
int height,
gpointer user_data);
struct _GtkDrawingArea
{
GtkWidget widget;
@ -78,6 +100,11 @@ void gtk_drawing_area_set_content_height (GtkDrawingArea
int height);
GDK_AVAILABLE_IN_3_90
int gtk_drawing_area_get_content_height (GtkDrawingArea *self);
GDK_AVAILABLE_IN_3_90
void gtk_drawing_area_set_draw_func (GtkDrawingArea *self,
GtkDrawingAreaDrawFunc draw_func,
gpointer user_data,
GDestroyNotify destroy);
G_END_DECLS