#include "spritedrawingarea.h"
#include "sdalayer.h"
#include "sdalayerprivate.h"
struct _SpriteDrawingAreaPrivate {
gint center_x, center_y;
gdouble scale_factor;
gboolean drag_active;
gdouble drag_x, drag_y;
GList *layers;
};
enum {
PROP_0,
PROP_CENTER_X,
PROP_CENTER_Y,
PROP_SCALE_FACTOR,
PROP_COUNT
};
void
sprite_drawing_area_get_center (
SpriteDrawingArea *sdarea,
gint *center_x,
gint *center_y
) {
g_object_get (
sdarea,
"center-x", center_x,
"center-y", center_y,
NULL
);
}
void
sprite_drawing_area_set_center (
SpriteDrawingArea *sdarea,
gint center_x,
gint center_y
) {
g_object_set (
sdarea,
"center-x", center_x,
"center-y", center_y,
NULL
);
}
gdouble
sprite_drawing_area_get_scale_factor (
SpriteDrawingArea *sdarea
) {
gdouble result;
g_object_get (
sdarea,
"scale-factor", &result,
NULL
);
return result;
}
void
sprite_drawing_area_set_scale_factor (
SpriteDrawingArea *sdarea,
gdouble scale_factor
) {
g_object_set (
sdarea,
"scale-factor", scale_factor,
NULL
);
}
static gboolean
_sprite_drawing_area_draw_handler (
GtkWidget *widget,
cairo_t *cr,
gpointer user_data
) {
SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (widget);
GList *l;
gint width = gtk_widget_get_allocated_width (widget);
gint height = gtk_widget_get_allocated_height (widget);
gdouble scale = sprite_drawing_area_get_scale_factor (sdarea);
gint center_x, center_y;
sprite_drawing_area_get_center (sdarea, ¢er_x, ¢er_y);
cairo_translate (
cr,
0.5 * (gdouble) width,
0.5 * (gdouble) height
);
cairo_scale (cr, scale, scale);
cairo_translate (
cr,
-center_x,
-center_y
);
sdarea->priv->layers = g_list_sort (
sdarea->priv->layers,
(GCompareFunc) sda_layer_compare_by_z_index
);
for (l = sdarea->priv->layers; l != NULL; l = l->next) {
SDALayer *layer = SDA_LAYER (l->data);
if (!layer->priv->visible)
continue;
cairo_save (cr);
cairo_translate (
cr,
layer->priv->offset_x,
layer->priv->offset_y
);
if (layer->priv->draw_func != NULL)
layer->priv->draw_func (layer, cr, layer->priv->user_data);
cairo_restore (cr);
}
return FALSE;
}
static void
sprite_drawing_area_get_property (
GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec
) {
SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (object);
switch (prop_id) {
case PROP_CENTER_X:
g_value_set_int (
value, sdarea->priv->center_x
);
break;
case PROP_CENTER_Y:
g_value_set_int (
value, sdarea->priv->center_y
);
break;
case PROP_SCALE_FACTOR:
g_value_set_double (
value, sdarea->priv->scale_factor
);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
sprite_drawing_area_set_property (
GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec
) {
SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (object);
switch (prop_id) {
case PROP_CENTER_X:
sdarea->priv->center_x = g_value_get_int (value);
break;
case PROP_CENTER_Y:
sdarea->priv->center_y = g_value_get_int (value);
break;
case PROP_SCALE_FACTOR:
sdarea->priv->scale_factor = g_value_get_double (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
gboolean
_sprite_drawing_area_drag_start_callback (
GtkWidget *widget,
GdkEvent *event,
gpointer user_data
) {
SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (widget);
if (event->button.button != 1)
return FALSE;
sdarea->priv->drag_active = TRUE;
sdarea->priv->drag_x = event->button.x;
sdarea->priv->drag_y = event->button.y;
return FALSE;
}
gboolean
_sprite_drawing_area_drag_end_callback (
GtkWidget *widget,
GdkEvent *event,
gpointer user_data
) {
SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (widget);
if (event->button.button != 1)
return FALSE;
sdarea->priv->drag_active = FALSE;
return FALSE;
}
gboolean
_sprite_drawing_area_drag_motion_callback (
GtkWidget *widget,
GdkEvent *event,
gpointer user_data
) {
SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (widget);
gdouble event_x, event_y;
gint center_x, center_y;
gint delta_x, delta_y;
gdouble scale_factor;
if ((event->motion.state & GDK_BUTTON1_MASK) == 0)
return FALSE;
if (!sdarea->priv->drag_active)
return FALSE;
event_x = event->motion.x;
event_y = event->motion.y;
sprite_drawing_area_get_center (sdarea, ¢er_x, ¢er_y);
scale_factor = sprite_drawing_area_get_scale_factor (sdarea);
delta_x =
(gint) (event_x / scale_factor + 0.5) - (gint) (sdarea->priv->drag_x / scale_factor + 0.5);
delta_y =
(gint) (event_y / scale_factor + 0.5) - (gint) (sdarea->priv->drag_y / scale_factor + 0.5);
sprite_drawing_area_set_center (
sdarea,
center_x - delta_x,
center_y - delta_y
);
sdarea->priv->drag_x = event_x;
sdarea->priv->drag_y = event_y;
gtk_widget_queue_draw (widget);
return FALSE;
}
static void
sprite_drawing_area_init (
SpriteDrawingArea *sdarea,
SpriteDrawingAreaClass *klass
) {
/* Setting up private */
sdarea->priv = G_TYPE_INSTANCE_GET_PRIVATE (
sdarea,
TYPE_SPRITE_DRAWING_AREA,
SpriteDrawingAreaPrivate
);
sdarea->priv->layers = NULL;
g_signal_connect (
sdarea,
"button-press-event",
(GCallback) _sprite_drawing_area_drag_start_callback,
NULL
);
g_signal_connect (
sdarea,
"button-release-event",
(GCallback) _sprite_drawing_area_drag_end_callback,
NULL
);
g_signal_connect (
sdarea,
"motion-notify-event",
(GCallback) _sprite_drawing_area_drag_motion_callback,
NULL
);
}
static void
sprite_drawing_area_class_init (
SpriteDrawingAreaClass *klass,
gpointer class_data
) {
GObjectClass *object_class;
g_type_class_add_private (klass, sizeof (SpriteDrawingAreaPrivate));
object_class = G_OBJECT_CLASS (klass);
object_class->set_property = sprite_drawing_area_set_property;
object_class->get_property = sprite_drawing_area_get_property;
g_signal_override_class_handler (
"draw",
TYPE_SPRITE_DRAWING_AREA,
(GCallback) _sprite_drawing_area_draw_handler
);
g_object_class_install_property (
object_class,
PROP_CENTER_X,
g_param_spec_int (
"center-x",
"Center X",
"The X coordinate of the point on the field "
"camera is centered on, in pixels",
-SPRITE_DRAWING_AREA_FIELD_SIZE,
SPRITE_DRAWING_AREA_FIELD_SIZE,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT
)
);
g_object_class_install_property (
object_class,
PROP_CENTER_Y,
g_param_spec_int (
"center-y",
"Center Y",
"The Y coordinate of the point on the field "
"camera is centered on, in pixels",
-SPRITE_DRAWING_AREA_FIELD_SIZE,
SPRITE_DRAWING_AREA_FIELD_SIZE,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT
)
);
g_object_class_install_property (
object_class,
PROP_SCALE_FACTOR,
g_param_spec_double (
"scale-factor",
"Scale factor",
"The scaling factor that is used in making "
"the camera zooming effect",
0.01, 100.0, 1.0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT
)
);
}
GType
sprite_drawing_area_get_type (void) {
static GType sdarea_type = 0;
if (sdarea_type == 0) {
const GTypeInfo sdarea_info = {
sizeof (SpriteDrawingAreaClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) sprite_drawing_area_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (SpriteDrawingArea),
0, /* n_preallocs */
(GInstanceInitFunc) sprite_drawing_area_init,
NULL, /* value_table */
};
sdarea_type = g_type_register_static (
GTK_TYPE_DRAWING_AREA,
"SpriteDrawingArea",
&sdarea_info,
0
);
}
return sdarea_type;
}
GtkWidget *
sprite_drawing_area_new (void) {
GtkWidget *sdarea = GTK_WIDGET (
g_object_new (TYPE_SPRITE_DRAWING_AREA, NULL)
);
return sdarea;
}
void
sprite_drawing_area_add_layer (
SpriteDrawingArea *sdarea,
SDALayer *layer
) {
sdarea->priv->layers = g_list_insert_sorted (
sdarea->priv->layers,
layer,
(GCompareFunc) sda_layer_compare_by_z_index
);
}
void
sprite_drawing_area_remove_layer (
SpriteDrawingArea *sdarea,
SDALayer *layer
) {
sdarea->priv->layers = g_list_remove (
sdarea->priv->layers,
layer
);
}