add more widgets (WIP)

This commit is contained in:
DanyLE 2024-04-22 00:31:57 +02:00
parent eba7d34476
commit 1219ec1563
14 changed files with 767 additions and 132 deletions

View File

@ -59,6 +59,7 @@ src = [
'src/widgets/cairo-widget.c',
'src/widgets/cairo-box.c',
'src/widgets/cairo-window.c',
'src/widgets/cairo-image.c',
'src/main.c',
wayland_targets]

View File

@ -6,7 +6,7 @@ G_DEFINE_ABSTRACT_TYPE(DiyaObject, diya_object, G_TYPE_OBJECT)
static void diya_object_dispose(GObject* object)
{
g_debug("diya_object_dispose");
g_debug("diya_object_dispose: %s", diya_object_to_string(object));
G_OBJECT_CLASS (diya_object_parent_class)->dispose(object);
}
@ -40,7 +40,7 @@ G_DEFINE_TYPE_WITH_PRIVATE(DiyaShellObject, diya_shell_object, DIYA_TYPE_OBJECT)
static void diya_shell_object_dispose(GObject* object)
{
g_debug("diya_shell_object_dispose");
g_debug("diya_shell_object_dispose: %s", diya_object_to_string(object));
G_OBJECT_CLASS(diya_shell_object_parent_class)->dispose(object);
}

View File

@ -83,10 +83,11 @@ void diya_shell_launcher_init(DiyaShell * shell)
for (l = apps; l != NULL; l = l->next)
{
gpointer element_data = l->data;
g_warning("%s", g_app_info_get_display_name(element_data)); /*print out all of the display names of the .desktop files */
/*g_warning("%s", g_app_info_get_display_name(element_data));
g_warning("%s", g_app_info_get_id(element_data));
g_warning("%s", g_app_info_get_name(element_data));
//g_warning("%s", g_app_info_get_icon(element_data));
//g_warning("%s", g_app_info_get_icon(element_data));*/
}
g_list_free_full(apps, g_object_unref);
}

View File

@ -11,6 +11,9 @@ static void activate(GtkApplication *app, void *data)
{
(void)app;
(void)data;
DiyaShell *shell = data;
diya_shell_lock(shell);
}
static gboolean restart(gpointer d)

View File

@ -11,6 +11,8 @@
#include "session.h"
#include "wayland.h"
#include "widgets/cairo-window.h"
#include "widgets/cairo-box.h"
#include "widgets/cairo-image.h"
#define DEF_SURF_W 600
#define DEF_SURF_H 400
@ -239,6 +241,7 @@ static void lock_surface_configure(void *data,
self->surface_height = height;
session_lock_realloc_surface(self);
diya_cairo_widget_set_size(self->window, width, height);
g_warning("update and damaged window");
diya_cairo_window_update(self->window);
}
ext_session_lock_surface_v1_ack_configure(lock_surface, serial);
@ -264,6 +267,90 @@ static void lock_surface_frame_done(void *data, struct wl_callback *cb, uint32_t
lock_session_draw_frame(lock);
}
static void diya_lock_session_ui(DiyaCairoWindow * window)
{
diya_stroke_t stroke = {
2.0,
{ 1.0, 0.0, 1.0, 1.0 }
};
diya_stroke_t stroke1 = {
2.0,
{ 0.0, 0.0, 1.0, 1.0 }
};
diya_offset_t margin = {10,20,10,20};
diya_offset_t padding = {20, 10, 20, 10};
g_object_set(window, "margin", &margin, "padding", &padding, NULL);
DiyaCairoBox * root = g_object_new(
DIYA_TYPE_CAIRO_BOX,
"mode", DIYA_CAIRO_BOX_HORIZONTAL,
"stroke", &stroke,
NULL);
diya_cairo_window_set_background_image(window, "/etc/xdg/labwc/wpp.jpg", TRUE);
diya_cairo_window_set_root(window, root);
DiyaCairoBox * box = g_object_new(DIYA_TYPE_CAIRO_BOX,
"mode", DIYA_CAIRO_BOX_HORIZONTAL,
"stroke", &stroke1,
NULL);
diya_cairo_container_add(root, box);
box = g_object_new(DIYA_TYPE_CAIRO_BOX,
"mode", DIYA_CAIRO_BOX_VERTICAL,
"vspace", DIYA_CAIRO_WIDGET_FILL_CONTENT,
"hspace", DIYA_CAIRO_WIDGET_FILL_CONTENT,
"stroke", &stroke,
NULL);
diya_cairo_container_add(root, box);
DiyaCairoBox* hbox = g_object_new(DIYA_TYPE_CAIRO_BOX,
"mode", DIYA_CAIRO_BOX_HORIZONTAL,
"stroke", &stroke1,
NULL);
diya_cairo_container_add(box, hbox);
hbox = g_object_new(DIYA_TYPE_CAIRO_BOX,
"mode", DIYA_CAIRO_BOX_HORIZONTAL,
"vspace", DIYA_CAIRO_WIDGET_FILL_CONTENT,
"hspace", DIYA_CAIRO_WIDGET_FILL_CONTENT,
"stroke", &stroke,
"padding", &padding,
NULL);
diya_cairo_container_add(box, hbox);
diya_stroke_t stroke_img = {
2.0,
{ 0.0, 0.0, 1.0, 1.0 }
};
DiyaCairoImage * image = g_object_new(DIYA_TYPE_CAIRO_IMAGE,
"file",
"/home/diya/test.jpg",
"stroke",
&stroke_img,
"vspace", DIYA_CAIRO_WIDGET_FILL_NONE,
"hspace", DIYA_CAIRO_WIDGET_FILL_NONE,
NULL);
diya_cairo_container_add(hbox, image);
hbox = g_object_new(DIYA_TYPE_CAIRO_BOX,
"mode", DIYA_CAIRO_BOX_HORIZONTAL,
"stroke", &stroke1,
NULL);
diya_cairo_container_add(box, hbox);
box = g_object_new(DIYA_TYPE_CAIRO_BOX,
"mode", DIYA_CAIRO_BOX_HORIZONTAL,
"stroke", &stroke1,
NULL);
diya_cairo_container_add(root, box);
}
static void diya_lock_session_init(DiyaLockSession *self)
{
self->session_lock = ext_session_lock_manager_v1_lock(g_session_lock_manager);
@ -282,8 +369,11 @@ static void diya_lock_session_init(DiyaLockSession *self)
self->wl_surface = NULL;
self->wl_buffer = NULL;
self->window = g_object_new(DIYA_TYPE_CAIRO_WINDOW,NULL);
diya_lock_session_ui(self->window);
self->cairo_surface = NULL;
self->raw_shared_buffer = NULL;
self->raw_shared_buffer_size = 0;

View File

@ -56,7 +56,7 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
DiyaWayland * wayland;
g_object_get(shell, "wayland", &wayland, NULL);
assert(DIYA_IS_WAYLAND(wayland));
g_warning("GLOBAL: %s", interface);
g_debug("WAYLAND GLOBAL: %s", interface);
if (!g_strcmp0(interface, zwlr_foreign_toplevel_manager_v1_interface.name))
{
diya_shell_foreign_toplevel_register(registry, name, data);

View File

@ -1,3 +1,5 @@
#include <assert.h>
#include <math.h>
#include "cairo-box.h"
enum
@ -24,7 +26,7 @@ static void diya_cairo_box_dispose(GObject * object)
static void diya_cairo_box_init(DiyaCairoBox* self)
{
self->mode = DIYA_CAIRO_HORIZONTAL_BOX;
self->mode = DIYA_CAIRO_BOX_HORIZONTAL;
}
static void diya_cairo_box_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
@ -55,13 +57,224 @@ static void diya_cairo_box_get_property(GObject *object, guint property_id, GVal
}
}
static gboolean cairo_box_draw(gpointer object, cairo_t * cairo)
{
DIYA_CAIRO_WIDGET_CLASS(diya_cairo_box_parent_class)->draw(object, cairo);
GList * children = DIYA_CAIRO_CONTAINER_GET_CLASS(object)->children(object);
gpointer item;
G_LIST_FOREACH(item, children)
{
DIYA_CAIRO_WIDGET_GET_CLASS(DIYA_CAIRO_WIDGET(item))->draw(item, cairo);
}
return TRUE;
}
static void cairo_box_update(gpointer object)
{
diya_offset_t margin = {0};
g_object_set(
object,
"halign", DIYA_CAIRO_WIDGET_ALIGN_START,
"valign", DIYA_CAIRO_WIDGET_ALIGN_START,
"margin", &margin,
NULL
);
DIYA_CAIRO_WIDGET_CLASS(diya_cairo_box_parent_class)->update(object);
assert(DIYA_IS_CAIRO_BOX(object));
DiyaCairoBox * self = DIYA_CAIRO_BOX(object);
GList * children = DIYA_CAIRO_CONTAINER_GET_CLASS(object)->children(object);
if(!children)
{
return;
}
diya_rect_t space = diya_cairo_widget_get_extent(object);
diya_offset_t * padding;
diya_stroke_t * stroke;
g_object_get(object,"padding", &padding, "stroke", &stroke, NULL);
gint stroke_size = ceil(stroke->size);
gpointer item;
guint n_extended = 0;
gint occupied_space = 2*stroke_size;
guint vspace, hspace;
guint cwidth, cheight;
// explore all other children
if(self->mode == DIYA_CAIRO_BOX_HORIZONTAL)
{
occupied_space += padding->left + padding->right;
}
else
{
occupied_space += padding->right + padding->bottom;
}
G_LIST_FOREACH(item, children)
{
g_object_get(item, "vspace", &vspace, "hspace", &hspace, NULL);
DIYA_CAIRO_WIDGET_GET_CLASS(item)->content_size(item, &cwidth, &cheight);
if(self->mode == DIYA_CAIRO_BOX_HORIZONTAL)
{
switch (hspace)
{
case DIYA_CAIRO_WIDGET_FILL_EXTEND:
n_extended++;
break;
case DIYA_CAIRO_WIDGET_FILL_CONTENT:
case DIYA_CAIRO_WIDGET_FILL_NONE:
occupied_space += cwidth;
break;
default:
break;
}
}
else
{
switch (vspace)
{
case DIYA_CAIRO_WIDGET_FILL_EXTEND:
n_extended++;
break;
case DIYA_CAIRO_WIDGET_FILL_CONTENT:
case DIYA_CAIRO_WIDGET_FILL_NONE:
occupied_space += cheight;
break;
default:
break;
}
}
}
gint off_x = padding->left + stroke_size;
gint off_y = padding->top + stroke_size;
G_LIST_FOREACH(item, children)
{
g_object_get(item, "vspace", &vspace, "hspace", &hspace, NULL);
DIYA_CAIRO_WIDGET_GET_CLASS(item)->content_size(item, &cwidth, &cheight);
diya_rect_t rect = {0};
rect.x = off_x;
rect.y = off_y;
if(self->mode == DIYA_CAIRO_BOX_HORIZONTAL)
{
rect.height = space.height - padding->top - padding->bottom - stroke_size*2;
switch (hspace)
{
case DIYA_CAIRO_WIDGET_FILL_EXTEND:
rect.width = (occupied_space >= space.width)?0:(space.width - occupied_space) / n_extended;
off_x += rect.width;
break;
case DIYA_CAIRO_WIDGET_FILL_CONTENT:
case DIYA_CAIRO_WIDGET_FILL_NONE:
rect.width = cwidth;
if(!DIYA_IS_CAIRO_BOX(item))
{
rect.height = cheight;
}
off_x += cwidth;
break;
default:
break;
}
}
else
{
rect.width = space.width - padding->left - padding->right - stroke_size*2;
switch (vspace)
{
case DIYA_CAIRO_WIDGET_FILL_EXTEND:
rect.height = (occupied_space >= space.height)?0:(space.height - occupied_space) / n_extended;
off_y += rect.height;
break;
case DIYA_CAIRO_WIDGET_FILL_CONTENT:
case DIYA_CAIRO_WIDGET_FILL_NONE:
rect.height = cheight;
if(!DIYA_IS_CAIRO_BOX(item))
{
rect.width = cwidth;
}
off_y += cheight;
break;
default:
break;
}
}
diya_rect_t * item_extent = DIYA_CAIRO_WIDGET_GET_CLASS(item)->extent(item);
memcpy(item_extent, &rect, sizeof(rect));
}
G_LIST_FOREACH(item, children)
{
// back up vspace hspace
g_object_get(item, "vspace", &vspace, "hspace", &hspace, NULL);
g_object_set(item,
"vspace", DIYA_CAIRO_WIDGET_FILL_EXTEND,
"hspace", DIYA_CAIRO_WIDGET_FILL_EXTEND,
NULL);
DIYA_CAIRO_WIDGET_GET_CLASS(DIYA_CAIRO_WIDGET(item))->update(item);
g_object_set(item,
"vspace", vspace,
"hspace", hspace,
NULL);
}
}
static diya_rect_t cairo_box_allocate_space(gpointer object, gpointer child)
{
(void) object;
return diya_cairo_widget_get_extent(child);
}
static void cairo_box_content_size(gpointer object, gint* width, gint * height)
{
DiyaCairoBox * self = DIYA_CAIRO_BOX(object);
*width = 0;
*height = 0;
gpointer item;
GList * children = DIYA_CAIRO_CONTAINER_GET_CLASS(object)->children(object);
diya_stroke_t * stroke;
diya_offset_t * padding;
g_object_get(object, "stroke", &stroke,"padding", &padding, NULL);
gint stroke_size = ceil(stroke->size) * 2;
G_LIST_FOREACH(item, children)
{
gint cw,ch;
DIYA_CAIRO_WIDGET_GET_CLASS(item)->content_size(item,&cw,&ch);
if(self->mode == DIYA_CAIRO_BOX_HORIZONTAL)
{
*width += cw;
*height = MAX(*height,ch);
}
else
{
*height += ch;
*width = MAX(*width,cw);
}
}
*height += stroke_size + padding->bottom + padding->top;
*width += stroke_size + padding->left + padding->right;
}
static void diya_cairo_box_class_init(DiyaCairoBoxClass * class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DIYA_CAIRO_WIDGET_SET_NAME(class, "DiyaCairoBox");
DiyaCairoWidgetClass *wclass = DIYA_CAIRO_WIDGET_CLASS(class);
wclass->draw = cairo_box_draw;
wclass->update = cairo_box_update;
wclass->alloc_space = cairo_box_allocate_space;
wclass->content_size = cairo_box_content_size;
gobject_class->dispose = diya_cairo_box_dispose;
gobject_class->set_property = diya_cairo_box_set_property;
gobject_class->get_property = diya_cairo_box_get_property;
g_prop[BOX_MODE] = g_param_spec_pointer("mode", NULL, "Box mode", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_prop[BOX_MODE] = g_param_spec_uint(
"mode", NULL,
"Box mode", DIYA_CAIRO_BOX_HORIZONTAL,
DIYA_CAIRO_BOX_VERTICAL, DIYA_CAIRO_BOX_HORIZONTAL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, N_PROPERTIES, g_prop);
}

View File

@ -4,8 +4,8 @@
#include "cairo-widget.h"
enum {
DIYA_CAIRO_HORIZONTAL_BOX,
DIYA_CAIRO_VERTICAL_BOX
DIYA_CAIRO_BOX_HORIZONTAL,
DIYA_CAIRO_BOX_VERTICAL
};
#define DIYA_TYPE_CAIRO_BOX (diya_cairo_box_get_type ())

263
src/widgets/cairo-image.c Normal file
View File

@ -0,0 +1,263 @@
#include <gdk/gdk.h>
#include <math.h>
#include "cairo-image.h"
enum
{
NO_PROP,
IMG_FILE,
IMG_ALPHA,
IMG_PIXBUF,
IMG_FIT,
N_PROPERTIES
};
static GParamSpec *g_prop[N_PROPERTIES] = {0};
struct _DiyaCairoImage
{
DiyaCairoWidget parent_object;
gchar * file;
GdkPixbuf * buffer;
gdouble alpha;
gboolean fit;
};
G_DEFINE_FINAL_TYPE(DiyaCairoImage, diya_cairo_image, DIYA_TYPE_CAIRO_WIDGET)
static void diya_cairo_image_dispose(GObject * object)
{
g_debug("diya_cairo_image_dispose: %s", diya_object_to_string(object));
DiyaCairoImage * self = DIYA_CAIRO_IMAGE(object);
if(self->file)
{
g_free(self->file);
}
if(self->buffer)
{
g_debug("diya_cairo_image_dispose: release image buffer");
g_object_unref(self->buffer);
}
G_OBJECT_CLASS(diya_cairo_image_parent_class)->dispose(object);
}
static void diya_cairo_set_pixbuf(DiyaCairoImage* self, GdkPixbuf * buf)
{
if(self->buffer)
{
g_object_unref(self->buffer);
self->buffer = NULL;
}
self->buffer = buf;
diya_cairo_widget_set_size(self,
gdk_pixbuf_get_width(self->buffer),
gdk_pixbuf_get_height(self->buffer)
);
diya_cairo_widget_damage(self);
}
static void diya_cairo_load_image_from_file(DiyaCairoImage* self, const gchar* path)
{
if(self->file)
{
g_free(self->file);
}
self->file = g_strdup(path);
GError *error = NULL;
GdkPixbuf * buf = gdk_pixbuf_new_from_file(self->file,&error);
if(!buf)
{
g_error("diya_cairo_load_image_from_file: [%s] %s", self->file, error->message);
return;
}
diya_cairo_set_pixbuf(self,buf);
}
static void diya_cairo_image_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
DiyaCairoImage * self = DIYA_CAIRO_IMAGE(object);
switch (property_id)
{
case IMG_FILE:
diya_cairo_load_image_from_file(self, g_value_get_pointer(value));
break;
case IMG_ALPHA:
self->alpha = g_value_get_double(value);
break;
case IMG_FIT:
self->fit = g_value_get_boolean(value);
break;
case IMG_PIXBUF:
if(self->file)
{
g_free(self->file);
self->file = NULL;
}
diya_cairo_set_pixbuf(self,g_value_get_pointer(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void diya_cairo_image_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
DiyaCairoImage * self = DIYA_CAIRO_IMAGE(object);
switch (property_id)
{
case IMG_FILE:
g_value_set_pointer(value, self->file);
break;
case IMG_ALPHA:
g_value_set_double(value, self->alpha);
break;
case IMG_FIT:
g_value_set_boolean(value, self->fit);
break;
case IMG_PIXBUF:
g_value_set_pointer(value, self->buffer);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void diya_cairo_image_init(DiyaCairoImage * self)
{
self->file = NULL;
self->buffer = NULL;
self->alpha = 1.0;
self->fit = FALSE;
}
static gboolean diya_cairo_image_draw(gpointer object, cairo_t * context)
{
DiyaCairoImage * self = DIYA_CAIRO_IMAGE(object);
if(!self->buffer || !diya_cairo_widget_is_damaged(self) || !diya_cairo_widget_is_visible(self))
{
return FALSE;
}
diya_rect_t view_port = diya_cairo_widget_get_view_port(object);
diya_rect_dump("view port: ", &view_port);
if(diya_rect_is_empty(&view_port))
{
return FALSE;
}
cairo_save(context);
cairo_rectangle(context, view_port.x, view_port.y, view_port.width, view_port.height);
cairo_clip(context);
diya_color_t * color;
diya_stroke_t * stroke;
diya_point_t gpos = diya_cairo_widget_get_global_position(object);
diya_rect_t * default_extent;
guint halign, valign;
diya_offset_t * margin;
diya_rect_t extent = diya_cairo_widget_get_extent(object);
diya_rect_dump("extent: ", &extent);
g_object_get(object,
"fill", &color,
"stroke", &stroke,
"halign", &halign,
"valign", &valign,
"margin", &margin,
"default-extent", &default_extent,
NULL);
gint img_width = default_extent->width;
gint img_height = default_extent->height;
gint stroke_size = ceil(stroke->size);
GdkPixbuf * buf = NULL;
if(self->fit)
{
img_width = extent.width;
img_height = extent.height;
buf = gdk_pixbuf_scale_simple(self->buffer,img_width, img_height, GDK_INTERP_BILINEAR);
}
else
{
buf = g_object_ref(self->buffer);
}
gint off_x = margin->left + stroke->size / 2.0;
gint off_y = margin->top + stroke->size / 2.0;
switch (halign)
{
case DIYA_CAIRO_WIDGET_ALIGN_MIDDLE:
off_x += (extent.width - img_width) / 2;
break;
case DIYA_CAIRO_WIDGET_ALIGN_END:
off_x += extent.width - img_width;
break;
default:
break;
}
switch (valign)
{
case DIYA_CAIRO_WIDGET_ALIGN_MIDDLE:
off_y += (extent.height - img_height) / 2;
break;
case DIYA_CAIRO_WIDGET_ALIGN_END:
off_y += extent.height - img_height;
break;
default:
break;
}
g_warning("Global position %d %d offset %d %d", gpos.x, gpos.y, off_x, off_y);
if(color->a > 0)
{
//cairo_move_to(context, (double)gpos.x, (double)gpos.y);
cairo_rectangle(context,
gpos.x + margin->left + stroke_size,
gpos.y + margin->top + stroke_size,
extent.width - margin->left - margin->right - 2*stroke_size,
extent.height - margin->bottom - margin->top - 2*stroke_size);
cairo_set_source_rgba(context, color->r, color->g, color->b, color->a);
cairo_fill(context);
}
// draw image
gdk_cairo_set_source_pixbuf(context, buf, (double)(gpos.x + off_x), (double)(gpos.y + off_y));
cairo_paint_with_alpha(context, self->alpha);
if(stroke->size > 0 && stroke->color.a != 0)
{
//cairo_move_to(context, (double)gpos.x, (double)gpos.y);
cairo_rectangle(context,
gpos.x + margin->left + stroke_size,
gpos.y + margin->top + stroke_size,
extent.width - margin->left - margin->right - 2*stroke_size,
extent.height - margin->bottom - margin->top - 2*stroke_size);
cairo_set_source_rgba(context, stroke->color.r, stroke->color.g, stroke->color.b, stroke->color.a);
cairo_set_line_width(context,stroke->size);
cairo_stroke(context);
}
g_object_unref(buf);
cairo_restore(context);
return TRUE;
}
static void diya_cairo_image_class_init(DiyaCairoImageClass* class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaCairoWidgetClass *wclass = DIYA_CAIRO_WIDGET_CLASS(class);
wclass->draw = diya_cairo_image_draw;
DIYA_CAIRO_WIDGET_SET_NAME(class, "DiyaCairoImage");
gobject_class->dispose = diya_cairo_image_dispose;
gobject_class->set_property = diya_cairo_image_set_property;
gobject_class->get_property = diya_cairo_image_get_property;
g_prop[IMG_FILE] = g_param_spec_pointer("file", NULL, "Image file", G_PARAM_READWRITE );
g_prop[IMG_ALPHA] = g_param_spec_pointer("alpha", NULL, "Image alpha", G_PARAM_READWRITE );
g_prop[IMG_PIXBUF] = g_param_spec_pointer("pixbuf", NULL, "Image data from gdk_pixbuf", G_PARAM_READWRITE );
g_prop[IMG_FIT] = g_param_spec_boolean("scale-to-fit", NULL, "Scale image to fit space", FALSE, G_PARAM_READWRITE );
g_object_class_install_properties (gobject_class, N_PROPERTIES, g_prop);
}

View File

@ -0,0 +1,9 @@
#ifndef CAIRO_IMAGE_H
#define CAIRO_IMAGE_H
#include "cairo-widget.h"
#define DIYA_TYPE_CAIRO_IMAGE (diya_cairo_image_get_type ())
G_DECLARE_FINAL_TYPE (DiyaCairoImage, diya_cairo_image, DIYA, CAIRO_IMAGE, DiyaCairoWidget)
#endif

View File

@ -2,6 +2,7 @@
#include <string.h>
#include <assert.h>
#include <limits.h>
#include <math.h>
#include "cairo-widget.h"
/*
#include <cairo.h>
@ -56,7 +57,7 @@ static GParamSpec *g_cw_prop[CW_N_PROPERTIES] = {0};
typedef struct _DiyaCairoWidgetPrivate
{
DiyaObject * parent_object;
DiyaObject parent_object;
diya_rect_t extent;
diya_rect_t default_extent;
DiyaCairoWidget * parent_widget;
@ -248,33 +249,41 @@ static const gchar *diya_cairo_widget_to_string(DiyaObject *object)
DiyaCairoWidgetClass *class = DIYA_CAIRO_WIDGET_GET_CLASS(object);
DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self);
diya_point_t gpos = diya_cairo_widget_get_global_position(object);
g_snprintf(priv->string,sizeof(priv->string),
"%s (%dx%d) at %d@%d",
"%s (%dx%d) at %d@%d (local %d@%d)",
class->name,
priv->extent.x, priv->extent.y,
priv->extent.width, priv->extent.height
priv->extent.width, priv->extent.height,
gpos.x, gpos.y,
priv->extent.x, priv->extent.y
);
return priv->string;
}
static diya_rect_t diya_cairo_widget_get_view_port(gpointer object)
diya_rect_t diya_cairo_widget_get_view_port(gpointer object)
{
DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object);
DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self);
diya_offset_t * margin;
g_object_get(object,"margin", &margin, NULL);
diya_point_t gpos = diya_cairo_widget_get_global_position(object);
diya_rect_t view = {gpos.x, gpos.y, priv->extent.width, priv->extent.height};
diya_rect_t view = {
gpos.x + margin->left,
gpos.y + margin->top,
priv->extent.width - margin->left - margin->right,
priv->extent.height - margin->bottom - margin->top
};
if(priv->parent_widget)
{
diya_rect_t parent_view = diya_cairo_widget_get_view_port(priv->parent_widget);
if(!diya_rect_overlap(&view, &parent_view))
{
view.x = view.y = view.width = view.height = 0;
return view;
}
view.width = MIN(view.x + view.width, parent_view.x + parent_view.width);
view.width = MIN(view.x + view.width, parent_view.x + parent_view.width) ;
view.height = MIN(view.y + view.height, parent_view.y + parent_view.height);
view.x = MAX(view.x, parent_view.x);
@ -287,58 +296,72 @@ static diya_rect_t diya_cairo_widget_get_view_port(gpointer object)
return view;
}
static void diya_cairo_widget_draw(gpointer object, cairo_t* context)
static gboolean diya_cairo_widget_draw(gpointer object, cairo_t* context)
{
(void) context;
DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object);
DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self);
if(!priv->damaged)
{
return;
return FALSE;
}
if(priv->visibility != DIYA_CAIRO_WIDGET_VISIBLE_ON)
{
return;
return FALSE;
}
diya_rect_t view_port = diya_cairo_widget_get_view_port(object);
if(diya_rect_is_empty(&view_port))
{
return;
return FALSE;
}
cairo_save(context);
cairo_rectangle(context, view_port.x, view_port.y, view_port.width, view_port.height);
cairo_clip(context);
diya_point_t gpos = diya_cairo_widget_get_global_position(object);
cairo_move_to(context, (double)gpos.x, (double)gpos.y);
//cairo_move_to(context, (double)gpos.x +, (double)gpos.y);
guint stroke_size = ceil(priv->stroke.size);
guint half_stroke_size = ceil(priv->stroke.size / 2.0);
cairo_rectangle(context,
gpos.x + priv->margin.left + half_stroke_size,
gpos.y + priv->margin.top + half_stroke_size,
priv->extent.width - priv->margin.left - priv->margin.right - stroke_size,
priv->extent.height - priv->margin.bottom - priv->margin.top - stroke_size);
if(priv->fill.a > 0)
{
cairo_set_source_rgba(context, priv->fill.r, priv->fill.g, priv->fill.b, priv->fill.a);
cairo_fill(context);
cairo_fill_preserve(context);
}
if(priv->stroke.size > 0 && priv->stroke.color.a != 0)
{
cairo_set_source_rgba(context, priv->stroke.color.r, priv->stroke.color.g, priv->stroke.color.b, priv->stroke.color.a);
cairo_set_line_width(context,priv->stroke.size);
cairo_stroke(context);
}
cairo_restore(context);
priv->damaged = FALSE;
return TRUE;
}
static void diya_cairo_widget_content_size(gpointer object, guint* width, guint* height)
static void diya_cairo_widget_content_size(gpointer object, gint* width, gint* height)
{
DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object);
DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self);
*width = priv->extent.width;
*height = priv->extent.height;
// take into account margin
gint stroke_size = ceil(priv->stroke.size) *2;
*width = priv->default_extent.width + priv->margin.left + priv->margin.right + stroke_size;
*height = priv->default_extent.height + priv->margin.top + priv->margin.bottom + stroke_size;
}
static void diya_cairo_widget_resize(gpointer object)
static void diya_cairo_widget_update(gpointer object)
{
// calculate effective size
assert(DIYA_IS_CAIRO_WIDGET(object));
DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object);
DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self);
if(priv->visibility == DIYA_CAIRO_WIDGET_VISIBLE_HIDDEN)
{
/**
@ -355,49 +378,41 @@ static void diya_cairo_widget_resize(gpointer object)
return;
}
diya_rect_t space = {
priv->margin.left,
priv->margin.top,
priv->extent.width - priv->margin.left - priv->margin.right,
priv->extent.height - priv->margin.top - priv->margin.bottom};
0,
0,
priv->default_extent.width,
priv->default_extent.height };
if(priv->parent_widget)
{
space = DIYA_CAIRO_WIDGET_GET_CLASS(self)->alloc_space(priv->parent_object, object);
space = DIYA_CAIRO_WIDGET_GET_CLASS(priv->parent_widget)->alloc_space(priv->parent_widget, object);
}
guint width,height,cwidth = 0,cheight = 0;
if(priv->hspace == DIYA_CAIRO_WIDGET_FILL_CONTENT ||
priv->vspace == DIYA_CAIRO_WIDGET_FILL_CONTENT)
{
DIYA_CAIRO_WIDGET_GET_CLASS(self)->content_size(object, &cwidth, &cheight);
}
gint width,height,cwidth = 0,cheight = 0;
DIYA_CAIRO_WIDGET_GET_CLASS(self)->content_size(object, &cwidth, &cheight);
switch(priv->hspace)
{
case DIYA_CAIRO_WIDGET_FILL_NONE:
width = priv->default_extent.width;
break;
case DIYA_CAIRO_WIDGET_FILL_EXTEND:
width = space.width;
break;
case DIYA_CAIRO_WIDGET_FILL_CONTENT:
case DIYA_CAIRO_WIDGET_FILL_NONE:
width = cwidth;
break;
default:
width = priv->extent.width;
width = priv->default_extent.width + priv->margin.left + priv->margin.right;
break;
}
switch(priv->vspace)
{
case DIYA_CAIRO_WIDGET_FILL_NONE:
height = priv->default_extent.height;
break;
case DIYA_CAIRO_WIDGET_FILL_EXTEND:
height = space.height;
break;
case DIYA_CAIRO_WIDGET_FILL_CONTENT:
case DIYA_CAIRO_WIDGET_FILL_NONE:
height = cheight;
break;
default:
height = priv->extent.height;
height = priv->default_extent.height + priv->margin.top + priv->margin.bottom;
break;
}
@ -407,79 +422,48 @@ static void diya_cairo_widget_resize(gpointer object)
}
priv->extent.width = width;
priv->extent.height = height;
/*if(space.x != priv->extent.x || space.y != priv->extent.y)
if(space.x != priv->extent.x || space.y != priv->extent.y)
{
priv->damaged = TRUE;
}*/
}
priv->extent.x = space.x;
priv->extent.y = space.y;
}
static void diya_cairo_widget_align(gpointer object)
{
guint cwidth, cheight;
// calculate widget position
DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object);
DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self);
DIYA_CAIRO_WIDGET_GET_CLASS(self)->content_size(object, &cwidth, &cheight);
if(diya_rect_is_empty(&priv->extent))
{
return;
}
int x = priv->extent.x, y = priv->extent.y;
switch(priv->halign)
{
case DIYA_CAIRO_WIDGET_ALIGN_MIDDLE:
x += (priv->extent.width - cwidth ) / 2;
break;
case DIYA_CAIRO_WIDGET_ALIGN_END:
x += priv->extent.width - cwidth;
break;
default:
break;
}
switch(priv->valign)
{
case DIYA_CAIRO_WIDGET_ALIGN_MIDDLE:
y += (priv->extent.height - cheight ) / 2;
break;
case DIYA_CAIRO_WIDGET_ALIGN_END:
y += priv->extent.height - cheight;
break;
default:
break;
}
if(x != priv->extent.x || y != priv->extent.y)
{
priv->damaged = TRUE;
}
priv->extent.x = x;
priv->extent.y = y;
}
static void diya_cairo_widget_update(gpointer object)
{
DIYA_CAIRO_WIDGET_GET_CLASS(DIYA_CAIRO_WIDGET(object))->resize(object);
DIYA_CAIRO_WIDGET_GET_CLASS(DIYA_CAIRO_WIDGET(object))->align(object);
}
static diya_rect_t diya_cairo_widget_alloc_space(gpointer object, gpointer child)
{
(void) child;
assert(object);
DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object);
DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self);
diya_rect_t space = {0,0,priv->extent.width, priv->extent.height};
diya_offset_t * margin = NULL;
g_object_get(child,"margin", &margin, NULL);
space.x += priv->padding.left + margin->left;
space.y += priv->padding.top + margin->top;
space.width -= (priv->padding.right + priv->padding.left + margin->right + margin->left);
space.height -= (priv->padding.bottom + priv->padding.top + margin->bottom + margin->top);
diya_rect_t space = {0,0,priv->extent.width, priv->extent.height};
guint stroke_size = ceil(priv->stroke.size);
space.x += priv->padding.left + priv->margin.left + stroke_size;
space.y += priv->padding.top + priv->margin.top + stroke_size;
space.width -= (priv->padding.right + priv->padding.left + priv->margin.left+ priv->margin.right + stroke_size*2);
space.height -= (priv->padding.bottom + priv->padding.top + priv->margin.top + priv->margin.bottom + stroke_size*2);
return space;
}
static diya_rect_t diya_cairo_widget_get_default_extent(gpointer object)
{
DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object);
DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self);
return priv->default_extent;
}
static diya_rect_t* diya_cairo_widget_get_extent_mut(gpointer object)
{
assert(DIYA_IS_CAIRO_WIDGET(object));
DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object);
DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self);
return &priv->extent;
}
static void diya_cairo_widget_class_init(DiyaCairoWidgetClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
@ -491,9 +475,14 @@ static void diya_cairo_widget_class_init(DiyaCairoWidgetClass *class)
class->draw = diya_cairo_widget_draw;
class->update = diya_cairo_widget_update;
class->alloc_space = diya_cairo_widget_alloc_space;
class->resize = diya_cairo_widget_resize;
class->align = diya_cairo_widget_align;
class->content_size = diya_cairo_widget_content_size;
class->parent = diya_cairo_widget_get_parent;
class->position = diya_cairo_widget_get_position;
class->global_position = diya_cairo_widget_get_global_position;
class->extent = diya_cairo_widget_get_extent_mut;
class->view_port = diya_cairo_widget_get_view_port;
class->damaged = diya_cairo_widget_is_damaged;
class->default_extent = diya_cairo_widget_get_default_extent;
g_cw_prop[CW_EXTENT_DEF] = g_param_spec_pointer("default-extent", NULL, "Widget actual extent relative to its parent", G_PARAM_READWRITE); //
g_cw_prop[CW_EXTENT] = g_param_spec_pointer("extent", NULL, "Widget default extent", G_PARAM_READABLE);
@ -529,7 +518,7 @@ static void diya_cairo_widget_class_init(DiyaCairoWidgetClass *class)
G_PARAM_READWRITE);
g_cw_prop[CW_VSPACE] = g_param_spec_uint(
"vpsace", NULL, "Widget vspace",
"vspace", NULL, "Widget vspace",
DIYA_CAIRO_WIDGET_FILL_NONE,
DIYA_CAIRO_WIDGET_FILL_MAX,
DIYA_CAIRO_WIDGET_FILL_EXTEND,
@ -715,7 +704,7 @@ void diya_cairo_widget_damage(gpointer object)
typedef struct _DiyaCairoContainerPrivate
{
DiyaCairoWidget * parent_object;
DiyaCairoWidget parent_object;
GList* children;
} DiyaCairoContainerPrivate;
@ -736,12 +725,20 @@ static void diya_cairo_container_init(DiyaCairoContainer *self)
DiyaCairoContainerPrivate* priv = diya_cairo_container_get_instance_private(self);
priv->children = NULL;
}
static GList * diya_cairo_container_get_children(gpointer object)
{
DiyaCairoContainerPrivate* priv = diya_cairo_container_get_instance_private(DIYA_CAIRO_CONTAINER(object));
return priv->children;
}
static void diya_cairo_container_class_init(DiyaCairoContainerClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
//DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
//DiyaCairoWidgetClass *wclass = DIYA_CAIRO_WIDGET_CLASS(class);
DIYA_CAIRO_WIDGET_SET_NAME(class, "DiyaCairoContainer");
gobject_class->dispose = diya_cairo_container_dispose;
class->children = diya_cairo_container_get_children;
}
void diya_cairo_container_add(gpointer object, gpointer child)

View File

@ -11,8 +11,8 @@ typedef struct
{
gint x;
gint y;
guint width;
guint height;
gint width;
gint height;
} diya_rect_t;
typedef struct
@ -26,8 +26,8 @@ typedef struct
{
gint left;
gint top;
gint bottom;
gint right;
gint bottom;
}
diya_offset_t;
@ -46,13 +46,18 @@ typedef struct
diya_color_t color;
} diya_stroke_t;
#define BETWEEN(value,min,max) ((value > min) && (value < max))
#define BETWEEN(value,min,max) ((value >= min) && (value <= max))
#define diya_rect_is_empty(rect) (((rect)->width <= 0) && ((rect)->height <= 0))
#define diya_rect_is_empty(rect) (((rect)->width <= 0) || ((rect)->height <= 0))
#define diya_rect_to_offset(rect) ({(rect)->x,(rect)->y,(rect)->y+(rect)->height, (rect)->x + (rect)->width})
#define diya_rect_overlap(a,b) ( \
(BETWEEN((a)->x, (b)->x, (b)->x + (gint)(b)->width) || BETWEEN((b)->x, (a)->x, (a)->x + (gint)(a)->width)) && \
(BETWEEN((a)->y, (b)->y, (b)->y + (gint)(b)->height) || BETWEEN((b)->y, (a)->y, (a)->y + (gint)(a)->height)))
(BETWEEN((a)->x, (b)->x, (b)->x + (b)->width) || BETWEEN((b)->x, (a)->x, (a)->x + (a)->width)) && \
(BETWEEN((a)->y, (b)->y, (b)->y + (b)->height) || BETWEEN((b)->y, (a)->y, (a)->y + (a)->height)))
#define diya_rect_dump(prefix, rect) (g_warning(prefix ": [%d@%d, %dx%d]", (rect)->x,(rect)->y, (rect)->width, (rect)->height))
#define G_LIST_FOREACH(item, list) for(GList *__glist = list; __glist && (item = __glist->data, TRUE); __glist = __glist->next)
void diya_offset_normalize(diya_offset_t * offset);
@ -66,6 +71,7 @@ enum
DIYA_CAIRO_WIDGET_ALIGN_START,
DIYA_CAIRO_WIDGET_ALIGN_MIDDLE,
DIYA_CAIRO_WIDGET_ALIGN_END,
DIYA_CAIRO_WIDGET_ALIGN_DEFAULT,
DIYA_CAIRO_WIDGET_ALIGN_MAX, // not used
/*fill enum*/
DIYA_CAIRO_WIDGET_FILL_NONE, // using extent size
@ -84,13 +90,19 @@ enum
struct _DiyaCairoWidgetClass
{
DiyaObjectClass parent_class;
void (*draw)(gpointer, cairo_t*);
gboolean (*draw)(gpointer, cairo_t*);
void (*update)(gpointer);
void (*resize)(gpointer);
void (*align)(gpointer);
void (*content_size)(gpointer, guint*, guint*);
void (*content_size)(gpointer, gint*, gint*);
diya_rect_t (*alloc_space)(gpointer, gpointer);
DiyaCairoWidget* (*parent)(gpointer);
diya_point_t (*position)(gpointer);
diya_point_t (*global_position)(gpointer);
diya_rect_t* (*extent)(gpointer);
diya_rect_t (*default_extent)(gpointer);
diya_rect_t (*view_port)(gpointer);
gboolean (*damaged)(gpointer);
const gchar* name;
};
@ -101,6 +113,7 @@ diya_rect_t diya_cairo_widget_get_extent(gpointer object);
gboolean diya_cairo_widget_is_visible(gpointer object);
gboolean diya_cairo_widget_is_hidden(gpointer object);
gboolean diya_cairo_widget_is_damaged(gpointer object);
diya_rect_t diya_cairo_widget_get_view_port(gpointer object);
void diya_cairo_widget_damage(gpointer object);
@ -110,15 +123,17 @@ void diya_cairo_widget_fill(gpointer object, diya_color_t * color);
void diya_cairo_widget_set_stroke_size(gpointer object, gdouble size);
void diya_cairo_widget_set_stroke_color(gpointer object, diya_color_t * color);
#define DIYA_TYPE_CAIRO_CONTAINER (diya_cairo_container_get_type ())
G_DECLARE_DERIVABLE_TYPE (DiyaCairoContainer, diya_cairo_container, DIYA, CAIRO_CONTAINER, DiyaCairoWidget)
struct _DiyaCairoContainerClass
{
DiyaCairoWidget parent_class;
DiyaCairoWidgetClass parent_class;
GList* (*children)(gpointer);
};
void diya_cairo_container_add(gpointer object, gpointer child);
#endif

View File

@ -1,6 +1,6 @@
#include <assert.h>
#include "cairo-window.h"
#include "cairo-image.h"
/*
enum
{
@ -12,8 +12,10 @@ static GParamSpec *g_prop[N_PROPERTIES] = {0};
*/
struct _DiyaCairoWindow
{
DiyaCairoWidget * parent_object;
DiyaCairoWidget parent_object;
DiyaCairoWidget * root;
gpointer background;
};
G_DEFINE_FINAL_TYPE(DiyaCairoWindow, diya_cairo_window, DIYA_TYPE_CAIRO_WIDGET)
@ -26,32 +28,51 @@ static void diya_cairo_window_dispose(GObject * object)
{
g_object_unref(window->root);
}
if(window->background)
{
g_object_unref(window->background);
}
G_OBJECT_CLASS(diya_cairo_window_parent_class)->dispose(object);
}
static void diya_cairo_window_init(DiyaCairoWindow * window)
{
window->root = NULL;
window->background = NULL;
}
static void cairo_window_draw(gpointer object, cairo_t * cairo)
static gboolean cairo_window_draw(gpointer object, cairo_t * cairo)
{
DiyaCairoWindow * window = DIYA_CAIRO_WINDOW(object);
DIYA_CAIRO_WIDGET_CLASS(diya_cairo_window_parent_class)->draw(object, cairo);
if(window->background)
{
g_warning("drawing background");
assert(DIYA_IS_CAIRO_IMAGE(window->background));
DIYA_CAIRO_WIDGET_GET_CLASS(DIYA_CAIRO_WIDGET(window->background))->draw(window->background, cairo);
}
if(window->root)
{
DIYA_CAIRO_WIDGET_GET_CLASS(DIYA_CAIRO_WIDGET(window->root))->draw(object, cairo);
DIYA_CAIRO_WIDGET_GET_CLASS(DIYA_CAIRO_WIDGET(window->root))->draw(window->root, cairo);
}
return TRUE;
}
static void cairo_window_update(gpointer object)
{
g_warning("Updating cairo window");
DiyaCairoWindow * self = DIYA_CAIRO_WINDOW(object);
DIYA_CAIRO_WIDGET_CLASS(diya_cairo_window_parent_class)->update(object);
if(self->background)
{
g_warning("Updating cairo image");
assert(DIYA_IS_CAIRO_IMAGE(self->background));
DIYA_CAIRO_WIDGET_GET_CLASS(DIYA_CAIRO_WIDGET(self->background))->update(self->background);
}
if(self->root)
{
DIYA_CAIRO_WIDGET_CLASS(DIYA_CAIRO_WIDGET(self->root))->update(self->root);
g_warning("Updating root");
DIYA_CAIRO_WIDGET_GET_CLASS(DIYA_CAIRO_WIDGET(self->root))->update(self->root);
}
}
@ -61,6 +82,7 @@ static void diya_cairo_window_class_init(DiyaCairoWindowClass* class)
DiyaCairoWidgetClass *wclass = DIYA_CAIRO_WIDGET_CLASS(class);
wclass->draw = cairo_window_draw;
wclass->update = cairo_window_update;
// wclass->alloc_space = cairo_window_allocate_space;
DIYA_CAIRO_WIDGET_SET_NAME(class, "DiyaCairoWindow");
gobject_class->dispose = diya_cairo_window_dispose;
}
@ -93,5 +115,25 @@ void diya_cairo_window_render(gpointer object, cairo_surface_t * surface)
void diya_cairo_window_update(gpointer object)
{
assert(DIYA_IS_CAIRO_WINDOW(object));
DIYA_CAIRO_WIDGET_CLASS(DIYA_CAIRO_WIDGET(object))->update(object);
g_warning("update and damaged widget");
DiyaCairoWidget * widget = DIYA_CAIRO_WIDGET(object);
assert(DIYA_IS_CAIRO_WIDGET(widget));
DIYA_CAIRO_WIDGET_GET_CLASS(widget)->update(object);
}
void diya_cairo_window_set_background_image(gpointer object, const char* path, gboolean scale_to_fit)
{
assert(DIYA_IS_CAIRO_WINDOW(object));
DiyaCairoWindow * self = DIYA_CAIRO_WINDOW(object);
self->background = g_object_new(DIYA_TYPE_CAIRO_IMAGE,
"file",path, "parent", object,
"scale-to-fit", scale_to_fit,
"hspace", DIYA_CAIRO_WIDGET_FILL_EXTEND,
"vspace", DIYA_CAIRO_WIDGET_FILL_EXTEND,
"halign", DIYA_CAIRO_WIDGET_ALIGN_START,
"valign", DIYA_CAIRO_WIDGET_ALIGN_START,
NULL);
}

View File

@ -10,4 +10,5 @@ G_DECLARE_FINAL_TYPE (DiyaCairoWindow, diya_cairo_window, DIYA, CAIRO_WINDOW, Di
void diya_cairo_window_set_root(gpointer object, gpointer root);
void diya_cairo_window_render(gpointer object, cairo_surface_t * surface);
void diya_cairo_window_update(gpointer object);
void diya_cairo_window_set_background_image(gpointer object, const char * file, gboolean scale_to_fit);
#endif