Started the GTK+ uiArea implementation. Much of the scrolling boilerplate is finished.
This commit is contained in:
parent
e47bd367e1
commit
04dcccf914
|
@ -0,0 +1,214 @@
|
|||
// 4 september 2015
|
||||
#include "area.h"
|
||||
|
||||
struct areaPrivate {
|
||||
uiArea *a;
|
||||
uiAreaHandler *ah;
|
||||
|
||||
GtkAdjustment *ha;
|
||||
GtkAdjustment *va;
|
||||
int clientWidth;
|
||||
int clientHeight;
|
||||
// needed for GtkScrollable
|
||||
GtkScrollablePolicy hpolicy, vpolicy;
|
||||
};
|
||||
|
||||
static void areaWidget_scrollable_init(GtkScrollable *);
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE(areaWidget, areaWidget, GTK_TYPE_DRAWING_AREA,
|
||||
G_IMPLEMENT_INTERFACE(GTK_TYPE_SCROLLABLE, areaWidget_scrollable_init))
|
||||
|
||||
static void updateScroll(areaWidget *a)
|
||||
{
|
||||
struct areaPrivate *ap = a->priv;
|
||||
uintmax_t count, pixelsPer;
|
||||
|
||||
// don't call if too early
|
||||
if (ap->ha == NULL || ap->va == NULL)
|
||||
return;
|
||||
|
||||
(*(ap->ah->HScrollConfig))(ap->ah, ap->a,
|
||||
&count, &pixelsPer);
|
||||
gtk_adjustment_configure(ap->ha,
|
||||
gtk_adjustment_get_value(ap->ha),
|
||||
0,
|
||||
count,
|
||||
1,
|
||||
ap->clientWidth / pixelsPer,
|
||||
ap->clientWidth / pixelsPer);
|
||||
|
||||
(*(ap->ah->VScrollConfig))(ap->ah, ap->a,
|
||||
&count, &pixelsPer);
|
||||
gtk_adjustment_configure(ap->va,
|
||||
gtk_adjustment_get_value(ap->va),
|
||||
0,
|
||||
count,
|
||||
1,
|
||||
ap->clientHeight / pixelsPer,
|
||||
ap->clientHeight / pixelsPer);
|
||||
|
||||
// TODO notify adjustment changes?
|
||||
g_object_notify(G_OBJECT(a), "hadjustment");
|
||||
g_object_notify(G_OBJECT(a), "vadjustment");
|
||||
}
|
||||
|
||||
static void areaWidget_init(areaWidget *a)
|
||||
{
|
||||
a->priv = G_TYPE_INSTANCE_GET_PRIVATE(a, areaWidgetType, struct areaPrivate);
|
||||
|
||||
// for events
|
||||
gtk_widget_add_events(GTK_WIDGET(a),
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_BUTTON_MOTION_MASK |
|
||||
GDK_BUTTON_PRESS_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_KEY_PRESS_MASK |
|
||||
GDK_KEY_RELEASE_MASK);
|
||||
|
||||
// for scrolling
|
||||
// TODO do we need GDK_TOUCH_MASK?
|
||||
gtk_widget_add_events(GTK_WIDGET(a),
|
||||
GDK_SCROLL_MASK |
|
||||
GDK_TOUCH_MASK |
|
||||
GDK_SMOOTH_SCROLL_MASK);
|
||||
|
||||
gtk_widget_set_can_focus(GTK_WIDGET(a), TRUE);
|
||||
}
|
||||
|
||||
static void areaWidget_dispose(GObject *obj)
|
||||
{
|
||||
struct areaPrivate *ap = areaWidget(obj)->priv;
|
||||
|
||||
if (ap->ha != NULL) {
|
||||
g_object_unref(ap->ha);
|
||||
ap->ha = NULL;
|
||||
}
|
||||
if (ap->va != NULL) {
|
||||
g_object_unref(ap->va);
|
||||
ap->va = NULL;
|
||||
}
|
||||
G_OBJECT_CLASS(areaWidget_parent_class)->dispose(obj);
|
||||
}
|
||||
|
||||
static void areaWidget_finalize(GObject *obj)
|
||||
{
|
||||
G_OBJECT_CLASS(areaWidget_parent_class)->finalize(obj);
|
||||
}
|
||||
|
||||
static void areaWidget_size_allocate(GtkWidget *w, GtkAllocation *allocation)
|
||||
{
|
||||
struct areaPrivate *ap = areaWidget(w)->priv;
|
||||
|
||||
// GtkDrawingArea has a size_allocate() implementation; we need to call it
|
||||
// this will call gtk_widget_set_allocation() for us
|
||||
GTK_WIDGET_CLASS(areaWidget_parent_class)->size_allocate(w, allocation);
|
||||
ap->clientWidth = allocation->width;
|
||||
ap->clientHeight = allocation->height;
|
||||
updateScroll(areaWidget(w));
|
||||
}
|
||||
|
||||
// TODO draw
|
||||
|
||||
// TODO preferred height/width
|
||||
|
||||
// TODO events
|
||||
|
||||
enum {
|
||||
pHAdjustment = 1,
|
||||
pVAdjustment,
|
||||
pHScrollPolicy,
|
||||
pVScrollPolicy,
|
||||
nProps,
|
||||
};
|
||||
|
||||
static void onValueChanged(GtkAdjustment *a, gpointer data)
|
||||
{
|
||||
gtk_widget_queue_draw(GTK_WIDGET(data));
|
||||
}
|
||||
|
||||
static void replaceAdjustment(areaWidget *a, GtkAdjustment **adj, const GValue *value)
|
||||
{
|
||||
if (*adj != NULL) {
|
||||
g_signal_handlers_disconnect_by_func(*adj, G_CALLBACK(onValueChanged), cc);
|
||||
g_object_unref(*adj);
|
||||
}
|
||||
*adj = GTK_ADJUSTMENT(g_value_get_object(value));
|
||||
if (*adj != NULL)
|
||||
g_object_ref_sink(*adj);
|
||||
else
|
||||
*adj = gtk_adjustment_new(0, 0, 0, 0, 0, 0);
|
||||
g_signal_connect(*adj, "value-changed", G_CALLBACK(onValueChanged), a);
|
||||
updateScroll(a);
|
||||
}
|
||||
|
||||
static void areaWidget_set_property(GObject *obj, guint prop, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
areaWidget *a = areaWidget(obj);
|
||||
struct areaPrivate *ap = a->priv;
|
||||
|
||||
switch (prop) {
|
||||
case pHAdjustment:
|
||||
replaceAdjustment(a, &(ap->ha), value);
|
||||
return;
|
||||
case pVAdjustment:
|
||||
replaceAdjustment(a, &(ap->va), value);
|
||||
return;
|
||||
case pHScrollPolicy:
|
||||
ap->hpolicy = g_value_get_enum(value);
|
||||
return;
|
||||
case pVScrollPolicy:
|
||||
ap->vpolicy = g_value_get_enum(value);
|
||||
return;
|
||||
}
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec);
|
||||
}
|
||||
|
||||
static void areaWidget_get_property(GObject *obj, guint prop, GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
areaWidget *a = areaWidget(obj);
|
||||
struct areaPrivate *ap = a->priv;
|
||||
|
||||
switch (prop) {
|
||||
case pHAdjustment:
|
||||
g_value_set_object(value, ap->ha);
|
||||
return;
|
||||
case pVAdjustment:
|
||||
g_value_set_object(value, ap->va);
|
||||
return;
|
||||
case pHScrollPolicy:
|
||||
g_value_set_enum(value, ap->hpolicy);
|
||||
return;
|
||||
case pVScrollPolicy:
|
||||
g_value_set_enum(value, ap->vpolicy);
|
||||
return;
|
||||
}
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec);
|
||||
}
|
||||
|
||||
static void areaWidget_class_init(areaWidgetClass *class)
|
||||
{
|
||||
G_OBJECT_CLASS(class)->dispose = areaWidget_dispose;
|
||||
G_OBJECT_CLASS(class)->finalize = areaWidget_finalize;
|
||||
G_OBJECT_CLASS(class)->set_property = areaWidget_set_property;
|
||||
G_OBJECT_CLASS(class)->get_property = areaWidget_get_property;
|
||||
|
||||
GTK_WIDGET_CLASS(class)->size_allocate = areaWidget_size_allocate;
|
||||
// GTK_WIDGET_CLASS(class)->draw = areaWidget_draw;
|
||||
// GTK_WIDGET_CLASS(class)->get_preferred_height = areaWidget_get_preferred_height;
|
||||
// GTK_WIDGET_CLASS(class)->get_preferred_width = areaWidget_get_preferred_width;
|
||||
// GTK_WIDGET_CLASS(class)->button_press_event = areaWidget_button_press_event;
|
||||
// GTK_WIDGET_CLASS(class)->button_release_event = areaWidget_button_release_event;
|
||||
// GTK_WIDGET_CLASS(class)->motion_notify_event = areaWidget_motion_notify_event;
|
||||
// GTK_WIDGET_CLASS(class)->key_press_event = areaWidget_key_press_event;
|
||||
|
||||
// this is the actual interface implementation
|
||||
g_object_class_override_property(G_OBJECT_CLASS(class), pHAdjustment, "hadjustment");
|
||||
g_object_class_override_property(G_OBJECT_CLASS(class), pVAdjustment, "vadjustment");
|
||||
g_object_class_override_property(G_OBJECT_CLASS(class), pHScrollPolicy, "hscroll-policy");
|
||||
g_object_class_override_property(G_OBJECT_CLASS(class), pVScrollPolicy, "vscroll-policy");
|
||||
}
|
||||
|
||||
static void areaWidget_scrollable_init(GtkScrollable *iface)
|
||||
{
|
||||
// no need to do anything; the interface only has properties
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// 4 september 2015
|
||||
#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_32
|
||||
#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_32
|
||||
#define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_4
|
||||
#define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_4
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define areaWidgetType (areaWidget_get_type())
|
||||
#define areaWidget(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), areaWidgetType, areaWidget))
|
||||
#define isAreaWidget(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), areaWidgetType))
|
||||
#define areaWidgetClass(class) (G_TYPE_CHECK_CLASS_CAST((class), areaWidgetType, areaWidgetClass))
|
||||
#define isAreaWidgetClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), areaWidget))
|
||||
#define getAreaWidgetClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), areaWidgetType, areaWidgetClass))
|
||||
|
||||
typedef struct areaWidget areaWidget;
|
||||
typedef struct areaWidgetClass areaWidgetClass;
|
||||
|
||||
struct areaWidget {
|
||||
GtkDrawingArea parent_instance;
|
||||
struct areaPrivate *priv;
|
||||
};
|
||||
|
||||
struct areaWidgetClass {
|
||||
GtkDrawingAreaClass parent_class;
|
||||
};
|
||||
|
||||
extern GType areaWidget_get_type(void);
|
||||
|
||||
#include "ui.h"
|
|
@ -0,0 +1,13 @@
|
|||
// 4 september 2015
|
||||
|
||||
typedef struct uiArea uiArea;
|
||||
typedef struct uiAreaHandler uiAreaHandler;
|
||||
typedef struct uiAreaDrawParams uiAreaDrawParams;
|
||||
|
||||
struct uiAreaHandler {
|
||||
// TODO draw
|
||||
void (*HScrollConfig)(uiAreaHandler *, uiArea *, uintmax_t *, uintmax_t *);
|
||||
void (*VScrollConfig)(uiAreaHandler *, uiArea *, uintmax_t *, uintmx_t *);
|
||||
};
|
||||
|
||||
// TODO uiAreaDrawParams
|
Loading…
Reference in New Issue