diff --git a/meson.build b/meson.build index 06ac974..da1472b 100644 --- a/meson.build +++ b/meson.build @@ -60,6 +60,7 @@ src = [ 'src/widgets/cairo-box.c', 'src/widgets/cairo-window.c', 'src/widgets/cairo-image.c', + 'src/widgets/cairo-text.c', 'src/main.c', wayland_targets] diff --git a/src/session.c b/src/session.c index 47aad67..75ef0ae 100644 --- a/src/session.c +++ b/src/session.c @@ -13,10 +13,19 @@ #include "widgets/cairo-window.h" #include "widgets/cairo-box.h" #include "widgets/cairo-image.h" +#include "widgets/cairo-text.h" #define DEF_SURF_W 600 #define DEF_SURF_H 400 +#define LOREM "Lorem ipsum dolor sit amet, consectetur adipiscing elit,\n" \ +"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n" \ +"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris \n" \ +"nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in \n" \ +"reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n" \ +"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia \n" \ +"deserunt mollit anim id est laborum." + struct _DiyaLockSession { DiyaObject parent; @@ -314,13 +323,13 @@ static void diya_lock_session_ui(DiyaCairoWindow * window) 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, + "corner-radius", 10.0, NULL); diya_cairo_container_add(box, hbox); @@ -328,7 +337,26 @@ static void diya_lock_session_ui(DiyaCairoWindow * window) 2.0, { 0.0, 0.0, 1.0, 1.0 } }; - DiyaCairoImage * image = g_object_new(DIYA_TYPE_CAIRO_IMAGE, + diya_color_t fill = { 1.0,1.0,1.0,1.0 }; + diya_color_t color = { 0.0,0.0,0.0,1.0 }; + + DiyaCairoText *text = g_object_new(DIYA_TYPE_CAIRO_TEXT, + "vspace", DIYA_CAIRO_WIDGET_FILL_NONE, + "hspace", DIYA_CAIRO_WIDGET_FILL_NONE, + "stroke", &stroke, + "padding", &padding, + "corner-radius", 5.0, + "fill", &fill, + "color", &color, + "font-size", 11, + "font-family", "Monospace", + "halign", DIYA_CAIRO_WIDGET_ALIGN_START, + "valign", DIYA_CAIRO_WIDGET_ALIGN_START, + NULL); + diya_cairo_text_set_text(text, LOREM); + diya_cairo_widget_set_size(text, 600, 400); + diya_cairo_container_add(hbox, text); + /*DiyaCairoImage * image = g_object_new(DIYA_TYPE_CAIRO_IMAGE, "file", "/home/diya/test.jpg", "stroke", @@ -336,7 +364,7 @@ static void diya_lock_session_ui(DiyaCairoWindow * window) "vspace", DIYA_CAIRO_WIDGET_FILL_NONE, "hspace", DIYA_CAIRO_WIDGET_FILL_NONE, NULL); - diya_cairo_container_add(hbox, image); + diya_cairo_container_add(hbox, image);*/ hbox = g_object_new(DIYA_TYPE_CAIRO_BOX, "mode", DIYA_CAIRO_BOX_HORIZONTAL, diff --git a/src/widgets/cairo-box.c b/src/widgets/cairo-box.c index 2df189b..c400602 100644 --- a/src/widgets/cairo-box.c +++ b/src/widgets/cairo-box.c @@ -92,6 +92,7 @@ static void cairo_box_update(gpointer object) diya_rect_t space = diya_cairo_widget_get_extent(object); diya_offset_t * padding; diya_stroke_t * stroke; + diya_rect_t * default_extent; g_object_get(object,"padding", &padding, "stroke", &stroke, NULL); gint stroke_size = ceil(stroke->size); gpointer item; @@ -110,7 +111,7 @@ static void cairo_box_update(gpointer object) } G_LIST_FOREACH(item, children) { - g_object_get(item, "vspace", &vspace, "hspace", &hspace, NULL); + g_object_get(item, "vspace", &vspace, "hspace", &hspace, "default-extent", &default_extent, NULL); DIYA_CAIRO_WIDGET_GET_CLASS(item)->content_size(item, &cwidth, &cheight); if(self->mode == DIYA_CAIRO_BOX_HORIZONTAL) { @@ -120,9 +121,11 @@ static void cairo_box_update(gpointer object) n_extended++; break; case DIYA_CAIRO_WIDGET_FILL_CONTENT: - case DIYA_CAIRO_WIDGET_FILL_NONE: occupied_space += cwidth; break; + case DIYA_CAIRO_WIDGET_FILL_NONE: + occupied_space += default_extent->width; + break; default: break; } @@ -135,9 +138,11 @@ static void cairo_box_update(gpointer object) n_extended++; break; case DIYA_CAIRO_WIDGET_FILL_CONTENT: - case DIYA_CAIRO_WIDGET_FILL_NONE: occupied_space += cheight; break; + case DIYA_CAIRO_WIDGET_FILL_NONE: + occupied_space += default_extent->height; + break; default: break; } @@ -149,7 +154,7 @@ static void cairo_box_update(gpointer object) G_LIST_FOREACH(item, children) { - g_object_get(item, "vspace", &vspace, "hspace", &hspace, NULL); + g_object_get(item, "vspace", &vspace, "hspace", &hspace, "default-extent", &default_extent, NULL); DIYA_CAIRO_WIDGET_GET_CLASS(item)->content_size(item, &cwidth, &cheight); diya_rect_t rect = {0}; @@ -166,7 +171,6 @@ static void cairo_box_update(gpointer object) 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)) { @@ -174,6 +178,14 @@ static void cairo_box_update(gpointer object) } off_x += cwidth; break; + case DIYA_CAIRO_WIDGET_FILL_NONE: + rect.width = default_extent->width; + if(!DIYA_IS_CAIRO_BOX(item)) + { + rect.height = default_extent->height; + } + off_x += default_extent->width; + break; default: break; } @@ -188,7 +200,6 @@ static void cairo_box_update(gpointer object) 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)) { @@ -196,6 +207,14 @@ static void cairo_box_update(gpointer object) } off_y += cheight; break; + case DIYA_CAIRO_WIDGET_FILL_NONE: + rect.height = default_extent->height; + if(!DIYA_IS_CAIRO_BOX(item)) + { + rect.width = default_extent->width; + } + off_y += default_extent->height; + break; default: break; } diff --git a/src/widgets/cairo-image.c b/src/widgets/cairo-image.c index 1ea0b17..0acb363 100644 --- a/src/widgets/cairo-image.c +++ b/src/widgets/cairo-image.c @@ -208,7 +208,7 @@ static gboolean diya_cairo_image_draw(gpointer object, cairo_t * context) break; } - g_warning("Global position %d %d offset %d %d", gpos.x, gpos.y, off_x, off_y); + //g_warning("Global position %d %d offset %d %d", gpos.x, gpos.y, off_x, off_y); if(color->a > 0) { diff --git a/src/widgets/cairo-text.c b/src/widgets/cairo-text.c new file mode 100644 index 0000000..14345ef --- /dev/null +++ b/src/widgets/cairo-text.c @@ -0,0 +1,367 @@ +#include +#include +#include +#include "cairo-text.h" + +#define FONT "Sans Bold 10" + +enum +{ + NO_PROP, + C_TEXT, + C_FONT_FAMILY, + C_FONT_SIZE, + C_FONT_STYLE, + C_FONT_WEIGHT, + C_COLOR, + C_WRAP, + N_PROPERTIES +}; +static GParamSpec *g_prop[N_PROPERTIES] = {0}; + +typedef struct _DiyaCairoTextPrivate +{ + DiyaCairoWidget parent_object; + + gchar *text; + gchar *family; + int size; + guint style; + guint wrap; + guint weight; + diya_color_t color; +} DiyaCairoTextPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE(DiyaCairoText, diya_cairo_text, DIYA_TYPE_CAIRO_WIDGET) + +static void diya_cairo_text_dispose(GObject *object) +{ + DiyaCairoText *self = DIYA_CAIRO_TEXT(object); + DiyaCairoTextPrivate *priv = diya_cairo_text_get_instance_private(self); + g_debug("diya_cairo_text_dispose: %s", diya_object_to_string(object)); + if (priv->text) + { + g_free(priv->text); + } + if (priv->family) + { + g_free(priv->family); + } + G_OBJECT_CLASS(diya_cairo_text_parent_class)->dispose(object); +} + +static void diya_cairo_text_init(DiyaCairoText *self) +{ + DiyaCairoTextPrivate *priv = diya_cairo_text_get_instance_private(self); + priv->text = NULL; + priv->family = NULL; + priv->size = 10; + priv->style = DIYA_CAIRO_FONT_STYLE_NORMAL; + priv->weight = DIYA_CAIRO_FONT_WEIGHT_NORMAL; + priv->wrap = DIYA_CAIRO_TEXT_WRAP_WORD; +} + +static void diya_cairo_text_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + DiyaCairoText *self = DIYA_CAIRO_TEXT(object); + DiyaCairoTextPrivate *priv = diya_cairo_text_get_instance_private(self); + switch (property_id) + { + case C_TEXT: + if (priv->text) + { + g_free(priv->text); + } + priv->text = g_strdup(g_value_get_pointer(value)); + break; + case C_FONT_FAMILY: + if (priv->family) + { + g_free(priv->family); + } + priv->family = g_strdup(g_value_get_pointer(value)); + break; + case C_FONT_SIZE: + priv->size = g_value_get_int(value); + break; + case C_FONT_STYLE: + priv->style = g_value_get_uint(value); + break; + case C_WRAP: + priv->wrap = g_value_get_uint(value); + break; + case C_FONT_WEIGHT: + priv->weight = g_value_get_uint(value); + break; + case C_COLOR: + memcpy(&priv->color,g_value_get_pointer(value), sizeof(priv->color)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void diya_cairo_text_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + DiyaCairoText *self = DIYA_CAIRO_TEXT(object); + DiyaCairoTextPrivate *priv = diya_cairo_text_get_instance_private(self); + switch (property_id) + { + case C_TEXT: + g_value_set_pointer(value, priv->text); + break; + case C_FONT_FAMILY: + g_value_set_pointer(value, priv->family); + break; + case C_FONT_SIZE: + g_value_set_int(value, priv->size); + break; + case C_FONT_STYLE: + g_value_set_uint(value, priv->style); + break; + case C_WRAP: + g_value_set_uint(value, priv->wrap); + break; + case C_FONT_WEIGHT: + g_value_set_uint(value, priv->weight); + break; + case C_COLOR: + g_value_set_pointer(value, &priv->color); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static PangoFontDescription *diya_cairo_text_get_pango_font_desc(DiyaCairoText *self) +{ + PangoFontDescription *desc = pango_font_description_new(); + DiyaCairoTextPrivate *priv = diya_cairo_text_get_instance_private(self); + if (priv->family) + { + pango_font_description_set_family(desc, priv->family); + } + pango_font_description_set_size(desc, priv->size * PANGO_SCALE); + pango_font_description_set_style(desc, priv->style); + pango_font_description_set_weight(desc, priv->weight); + return desc; +} + +static gboolean diya_cairo_text_draw(gpointer object, cairo_t *context) +{ + DiyaCairoText *self = DIYA_CAIRO_TEXT(object); + DiyaCairoTextPrivate *priv = diya_cairo_text_get_instance_private(self); + if(!diya_cairo_widget_is_damaged(object) || !diya_cairo_widget_is_visible(object)) + { + return FALSE; + } + DIYA_CAIRO_WIDGET_CLASS(diya_cairo_text_parent_class)->draw(object, context); + diya_rect_t view_port = diya_cairo_widget_get_view_port(object); + diya_rect_dump("diya_cairo_text_draw: ", &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_rect_t extent = diya_cairo_widget_get_extent(object); + g_warning("diya_cairo_widget_get_extent: width %d, %d", extent.width, extent.height); + diya_offset_t * padding, *margin; + diya_stroke_t *stroke; + diya_color_t *color; + guint halign, valign; + g_object_get(object, + "stroke", &stroke, + "halign", &halign, + "valign", &valign, + "margin", &margin, + "padding", &padding, + "color", &color, + NULL); + gint stroke_size = ceil(stroke->size); + diya_point_t gpos = diya_cairo_widget_get_global_position(object); + + PangoFontDescription *desc = diya_cairo_text_get_pango_font_desc(object); + cairo_set_source_rgba(context, color->r, color->g, color->b, color->a); + int display_w = extent.width - padding->left - padding->right - margin->left - margin->right - 2*stroke_size; + int display_h = extent.height - padding->top - padding->bottom - margin->top - margin->bottom - 2*stroke_size; + int off_x = padding->left + margin->left + stroke_size; + int off_y = padding->top + margin->top + stroke_size; + + PangoLayout *layout = pango_cairo_create_layout(context); + // take into account my padding setting + pango_layout_set_text(layout, priv->text, -1); + pango_layout_set_font_description(layout, desc); + pango_layout_set_width(layout,display_w*PANGO_SCALE); + pango_layout_set_height(layout, display_h*PANGO_SCALE); + pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); + pango_layout_set_wrap(layout, priv->wrap); + switch(halign) + { + case DIYA_CAIRO_WIDGET_ALIGN_START: + pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); + break; + case DIYA_CAIRO_WIDGET_ALIGN_MIDDLE: + pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); + break; + case DIYA_CAIRO_WIDGET_ALIGN_END: + pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT); + break; + } + PangoRectangle text_rect = {0}; + pango_layout_get_extents(layout, NULL, &text_rect); + pango_extents_to_pixels(&text_rect, NULL); + // draw text + switch (valign) + { + case DIYA_CAIRO_WIDGET_ALIGN_MIDDLE: + off_y += (display_h - text_rect.height)/ 2; + break; + case DIYA_CAIRO_WIDGET_ALIGN_END: + off_y += display_h - text_rect.height; + break; + default: + break; + } + cairo_move_to(context, gpos.x + off_x, gpos.y + off_y); + pango_cairo_update_layout(context, layout); + pango_cairo_show_layout(context, layout); + + cairo_restore(context); + pango_font_description_free(desc); + g_object_unref(layout); + + return TRUE; +} + +static void diya_cairo_text_content_size(gpointer object, int *width, int *height) +{ + diya_offset_t* padding, *margin; + diya_stroke_t * stroke; + diya_rect_t * def_xtent; + guint hspace,vspace; + g_object_get(object, + "padding", &padding, + "margin", &margin, + "stroke", &stroke, + "hspace", &hspace, + "vspace", &vspace, + "default-extent", &def_xtent, + NULL); + gint stroke_size = ceil(stroke->size) * 2; + *width = padding->left + padding->right + margin->left + margin->right + stroke_size; + *height = padding->top + padding->bottom + margin->top + margin->bottom + stroke_size; + DiyaCairoText *self = DIYA_CAIRO_TEXT(object); + DiyaCairoTextPrivate *priv = diya_cairo_text_get_instance_private(self); + // diya_rect_t default_extent = DIYA_CAIRO_WIDGET_GET_CLASS(object)->default_extent(object); + int text_width = 0; + int text_height = 0; + if (priv->text) + { + cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + cairo_t *context = cairo_create(surface); + PangoLayout *layout = pango_cairo_create_layout(context); + PangoFontDescription *desc = diya_cairo_text_get_pango_font_desc(object); + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, priv->text, -1); + pango_layout_set_width(layout, -1); + pango_layout_set_height(layout, -1); + pango_layout_set_single_paragraph_mode(layout, FALSE); + //pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_MIDDLE); + PangoRectangle rect = {0}; + pango_layout_get_extents(layout, NULL, &rect); + pango_extents_to_pixels(&rect, NULL); + //rect.width += 4; + text_width = rect.width; + text_height = rect.height; + cairo_destroy(context); + cairo_surface_destroy(surface); + pango_font_description_free(desc); + g_object_unref(layout); + } + + switch (hspace) + { + case DIYA_CAIRO_WIDGET_FILL_NONE: + *width = def_xtent->width; + break; + default: + *width += text_width; + break; + } + switch (vspace) + { + case DIYA_CAIRO_WIDGET_FILL_NONE: + *height = def_xtent->height; + break; + default: + *height += text_height; + break; + } +} + +static void diya_cairo_text_class_init(DiyaCairoTextClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(class); + DiyaCairoWidgetClass *wclass = DIYA_CAIRO_WIDGET_CLASS(class); + + class->set_text = diya_cairo_text_set_text; + class->get_text = diya_cairo_text_get_text; + + wclass->draw = diya_cairo_text_draw; + wclass->content_size = diya_cairo_text_content_size; + + DIYA_CAIRO_WIDGET_SET_NAME(class, "DiyaCairoText"); + gobject_class->dispose = diya_cairo_text_dispose; + gobject_class->set_property = diya_cairo_text_set_property; + gobject_class->get_property = diya_cairo_text_get_property; + + g_prop[C_TEXT] = g_param_spec_pointer("text", NULL, "text content", G_PARAM_READWRITE); + g_prop[C_FONT_FAMILY] = g_param_spec_pointer("font-family", NULL, "text font face", G_PARAM_READWRITE); + g_prop[C_COLOR] = g_param_spec_pointer("color", NULL, "text color", G_PARAM_READWRITE); + + g_prop[C_FONT_STYLE] = g_param_spec_uint( + "font-style", NULL, "text font style", + DIYA_CAIRO_FONT_STYLE_NORMAL, + DIYA_CAIRO_FONT_STYLE_ITALIC, + DIYA_CAIRO_FONT_STYLE_NORMAL, + G_PARAM_READWRITE); + g_prop[C_FONT_WEIGHT] = g_param_spec_uint( + "font-weight", NULL, "text font weight", + PANGO_WEIGHT_THIN, + PANGO_WEIGHT_ULTRAHEAVY, + DIYA_CAIRO_FONT_WEIGHT_NORMAL, + G_PARAM_READWRITE); + g_prop[C_FONT_SIZE] = g_param_spec_int( + "font-size", NULL, "text font size", + 0, + G_MAXINT, + 10, + G_PARAM_READWRITE); + g_prop[C_WRAP] = g_param_spec_uint( + "wrap", NULL, "text wrap mode", + DIYA_CAIRO_TEXT_WRAP_WORD, + DIYA_CAIRO_TEXT_WRAP_WORD_CHAR, + DIYA_CAIRO_TEXT_WRAP_WORD, + G_PARAM_READWRITE); + + g_object_class_install_properties(gobject_class, N_PROPERTIES, g_prop); +} + +void diya_cairo_text_set_text(gpointer object, const gchar *text) +{ + assert(DIYA_IS_CAIRO_TEXT(object)); + g_object_set(object, "text", text, NULL); +} +const gchar *diya_cairo_text_get_text(gpointer object) +{ + assert(DIYA_IS_CAIRO_TEXT(object)); + DiyaCairoText *self = DIYA_CAIRO_TEXT(object); + DiyaCairoTextPrivate *priv = diya_cairo_text_get_instance_private(self); + return priv->text; +} diff --git a/src/widgets/cairo-text.h b/src/widgets/cairo-text.h new file mode 100644 index 0000000..974fa7b --- /dev/null +++ b/src/widgets/cairo-text.h @@ -0,0 +1,31 @@ +#ifndef CAIRO_TEXT_H +#define CAIRO_TEXT_H +#include +#include "cairo-widget.h" + + +#define DIYA_CAIRO_FONT_STYLE_NORMAL PANGO_STYLE_NORMAL +#define DIYA_CAIRO_FONT_STYLE_ITALIC PANGO_STYLE_ITALIC +#define DIYA_CAIRO_FONT_STYLE_OBLIQUE PANGO_STYLE_OBLIQUE + +#define DIYA_CAIRO_FONT_WEIGHT_NORMAL PANGO_WEIGHT_NORMAL +#define DIYA_CAIRO_FONT_WEIGHT_BOLD PANGO_WEIGHT_BOLD + +#define DIYA_CAIRO_TEXT_WRAP_WORD PANGO_WRAP_WORD +#define DIYA_CAIRO_TEXT_WRAP_CHAR PANGO_WRAP_CHAR +#define DIYA_CAIRO_TEXT_WRAP_WORD_CHAR PANGO_WRAP_WORD_CHAR + +#define DIYA_TYPE_CAIRO_TEXT (diya_cairo_text_get_type ()) +G_DECLARE_DERIVABLE_TYPE (DiyaCairoText, diya_cairo_text, DIYA, CAIRO_TEXT, DiyaCairoWidget) + + +struct _DiyaCairoTextClass +{ + DiyaCairoWidgetClass parent_class; + void (*set_text)(gpointer object, const gchar* text); + const gchar* (*get_text)(gpointer object); +}; + +void diya_cairo_text_set_text(gpointer object, const gchar* text); +const gchar* diya_cairo_text_get_text(gpointer object); +#endif \ No newline at end of file diff --git a/src/widgets/cairo-widget.c b/src/widgets/cairo-widget.c index bdf494d..319e3d0 100644 --- a/src/widgets/cairo-widget.c +++ b/src/widgets/cairo-widget.c @@ -51,6 +51,7 @@ enum CW_MARGIN, CW_FILL, CW_STROKE, + CW_CORNER_RADIUS, CW_N_PROPERTIES }; static GParamSpec *g_cw_prop[CW_N_PROPERTIES] = {0}; @@ -70,6 +71,8 @@ typedef struct _DiyaCairoWidgetPrivate guint16 hspace; guint16 vspace; + gdouble corner_radius; + diya_offset_t margin; diya_offset_t padding; @@ -166,6 +169,9 @@ static void diya_cairo_widget_set_property(GObject *object, guint property_id, c assert(ptr); priv->stroke = *(diya_stroke_t*) ptr; break; + case CW_CORNER_RADIUS: + priv->corner_radius = g_value_get_double(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -214,6 +220,9 @@ static void diya_cairo_widget_get_property(GObject *object, guint property_id, G case CW_STROKE: g_value_set_pointer(value, &priv->stroke); break; + case CW_CORNER_RADIUS: + g_value_set_double(value, priv->corner_radius); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -241,6 +250,7 @@ static void diya_cairo_widget_init(DiyaCairoWidget *self) memset(&priv->fill, 0, sizeof(priv->fill)); priv->damaged = TRUE; + priv->corner_radius = 0; } static const gchar *diya_cairo_widget_to_string(DiyaObject *object) @@ -277,6 +287,12 @@ diya_rect_t diya_cairo_widget_get_view_port(gpointer object) if(priv->parent_widget) { diya_rect_t parent_view = diya_cairo_widget_get_view_port(priv->parent_widget); + diya_offset_t* padding; + g_object_get(priv->parent_widget,"padding", &padding, NULL); + parent_view.x += padding->left; + parent_view.y += padding->top; + parent_view.width -= (padding->left + padding->right); + parent_view.height -= (padding->top + padding->bottom); if(!diya_rect_overlap(&view, &parent_view)) { view.x = view.y = view.width = view.height = 0; @@ -298,8 +314,6 @@ diya_rect_t diya_cairo_widget_get_view_port(gpointer object) 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) @@ -325,11 +339,25 @@ static gboolean diya_cairo_widget_draw(gpointer object, cairo_t* context) //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); + + double width = (double)(priv->extent.width - priv->margin.left - priv->margin.right - stroke_size); + int height = (double)(priv->extent.height - priv->margin.bottom - priv->margin.top - stroke_size); + int x = (double)(gpos.x + priv->margin.left + half_stroke_size); + int y = (double)(gpos.y + priv->margin.top + half_stroke_size); + if(priv->corner_radius > 0) + { + double degrees = M_PI / 180.0; + cairo_new_sub_path(context); + cairo_arc (context, x + width - priv->corner_radius, y + priv->corner_radius, priv->corner_radius, -90 * degrees, 0); + cairo_arc (context, x + width - priv->corner_radius, y + height - priv->corner_radius, priv->corner_radius, 0, 90 * degrees); + cairo_arc (context, x + priv->corner_radius, y + height - priv->corner_radius, priv->corner_radius, 90 * degrees, 180 * degrees); + cairo_arc (context, x + priv->corner_radius, y + priv->corner_radius, priv->corner_radius, 180 * degrees, 270 * degrees); + cairo_close_path (context); + } + else + { + cairo_rectangle(context,x,y,width,height); + } if(priv->fill.a > 0) { cairo_set_source_rgba(context, priv->fill.r, priv->fill.g, priv->fill.b, priv->fill.a); @@ -361,7 +389,7 @@ static void diya_cairo_widget_update(gpointer object) assert(DIYA_IS_CAIRO_WIDGET(object)); DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object); DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self); - + gint stroke_size = ceil(priv->stroke.size) *2; if(priv->visibility == DIYA_CAIRO_WIDGET_VISIBLE_HIDDEN) { /** @@ -394,11 +422,10 @@ static void diya_cairo_widget_update(gpointer object) width = space.width; break; case DIYA_CAIRO_WIDGET_FILL_CONTENT: - case DIYA_CAIRO_WIDGET_FILL_NONE: width = cwidth; break; default: - width = priv->default_extent.width + priv->margin.left + priv->margin.right; + width = priv->default_extent.width + priv->margin.left + priv->margin.right + stroke_size; break; } @@ -408,11 +435,10 @@ static void diya_cairo_widget_update(gpointer object) height = space.height; break; case DIYA_CAIRO_WIDGET_FILL_CONTENT: - case DIYA_CAIRO_WIDGET_FILL_NONE: height = cheight; break; default: - height = priv->default_extent.height + priv->margin.top + priv->margin.bottom; + height = priv->default_extent.height + priv->margin.top + priv->margin.bottom + stroke_size; break; } @@ -576,6 +602,12 @@ static void diya_cairo_widget_class_init(DiyaCairoWidgetClass *class) INT_MAX, 0, G_PARAM_WRITABLE); + g_cw_prop[CW_CORNER_RADIUS] = g_param_spec_double( + "corner-radius", NULL, "Corner radius", + 0, + DBL_MAX, + 0, + G_PARAM_READWRITE); base_class->to_string = diya_cairo_widget_to_string; @@ -717,7 +749,7 @@ static void diya_cairo_container_dispose(GObject* object) DiyaCairoContainerPrivate* priv = diya_cairo_container_get_instance_private(self); g_debug("diya_cairo_container_dispose: %s", diya_object_to_string(object)); g_list_free_full(priv->children, g_object_unref); - G_OBJECT_CLASS(diya_cairo_widget_parent_class)->dispose(object); + G_OBJECT_CLASS(diya_cairo_container_parent_class)->dispose(object); } static void diya_cairo_container_init(DiyaCairoContainer *self) diff --git a/src/widgets/cairo-widget.h b/src/widgets/cairo-widget.h index d29510b..30670a4 100644 --- a/src/widgets/cairo-widget.h +++ b/src/widgets/cairo-widget.h @@ -102,7 +102,6 @@ struct _DiyaCairoWidgetClass diya_rect_t (*default_extent)(gpointer); diya_rect_t (*view_port)(gpointer); gboolean (*damaged)(gpointer); - const gchar* name; };