diff options
Diffstat (limited to 'src/box.c')
-rw-r--r-- | src/box.c | 561 |
1 files changed, 0 insertions, 561 deletions
diff --git a/src/box.c b/src/box.c deleted file mode 100644 index e7ecac8..0000000 --- a/src/box.c +++ /dev/null @@ -1,561 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <math.h> -#include <string.h> - -#include <cairo.h> - -#include "ganv/box.h" - -#include "./boilerplate.h" -#include "./color.h" -#include "./gettext.h" -#include "./ganv-private.h" - -static const double STACKED_OFFSET = 4.0; - -G_DEFINE_TYPE_WITH_CODE(GanvBox, ganv_box, GANV_TYPE_NODE, - G_ADD_PRIVATE(GanvBox)) - -static GanvNodeClass* parent_class; - -enum { - PROP_0, - PROP_X1, - PROP_Y1, - PROP_X2, - PROP_Y2, - PROP_RADIUS_TL, - PROP_RADIUS_TR, - PROP_RADIUS_BR, - PROP_RADIUS_BL, - PROP_STACKED, - PROP_BEVELED -}; - -static void -ganv_box_init(GanvBox* box) -{ - box->impl = ganv_box_get_instance_private(box); - - memset(&box->impl->coords, '\0', sizeof(GanvBoxCoords)); - - box->impl->coords.border_width = GANV_NODE(box)->impl->border_width; - box->impl->old_coords = box->impl->coords; - box->impl->radius_tl = 0.0; - box->impl->radius_tr = 0.0; - box->impl->radius_br = 0.0; - box->impl->radius_bl = 0.0; - box->impl->beveled = FALSE; -} - -static void -ganv_box_destroy(GtkObject* object) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_BOX(object)); - - if (GTK_OBJECT_CLASS(parent_class)->destroy) { - (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); - } -} - -static void -ganv_box_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_BOX(object)); - - GanvBox* box = GANV_BOX(object); - GanvBoxPrivate* impl = box->impl; - GanvBoxCoords* coords = &impl->coords; - - switch (prop_id) { - SET_CASE(X1, double, coords->x1); - SET_CASE(Y1, double, coords->y1); - SET_CASE(X2, double, coords->x2); - SET_CASE(Y2, double, coords->y2); - SET_CASE(RADIUS_TL, double, impl->radius_tl); - SET_CASE(RADIUS_TR, double, impl->radius_tr); - SET_CASE(RADIUS_BR, double, impl->radius_br); - SET_CASE(RADIUS_BL, double, impl->radius_bl); - SET_CASE(STACKED, boolean, coords->stacked); - SET_CASE(BEVELED, boolean, impl->beveled); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_box_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_BOX(object)); - - GanvBox* box = GANV_BOX(object); - GanvBoxPrivate* impl = box->impl; - GanvBoxCoords* coords = &impl->coords; - - switch (prop_id) { - GET_CASE(X1, double, coords->x1); - GET_CASE(X2, double, coords->x2); - GET_CASE(Y1, double, coords->y1); - GET_CASE(Y2, double, coords->y2); - GET_CASE(RADIUS_TL, double, impl->radius_tl); - GET_CASE(RADIUS_TR, double, impl->radius_tr); - GET_CASE(RADIUS_BR, double, impl->radius_br); - GET_CASE(RADIUS_BL, double, impl->radius_bl); - GET_CASE(STACKED, boolean, impl->coords.stacked); - GET_CASE(BEVELED, boolean, impl->beveled); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_box_bounds_item(const GanvBoxCoords* coords, - double* x1, double* y1, - double* x2, double* y2) -{ - *x1 = coords->x1 - coords->border_width; - *y1 = coords->y1 - coords->border_width; - *x2 = coords->x2 + coords->border_width + (coords->stacked * STACKED_OFFSET); - *y2 = coords->y2 + coords->border_width + (coords->stacked * STACKED_OFFSET); -} - -void -ganv_box_request_redraw(GanvItem* item, - const GanvBoxCoords* coords, - gboolean world) -{ - double x1, y1, x2, y2; - ganv_box_bounds_item(coords, &x1, &y1, &x2, &y2); - - if (!world) { - // Convert from item-relative coordinates to world coordinates - ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2); - } - - ganv_canvas_request_redraw_w(item->impl->canvas, x1, y1, x2, y2); -} - -static void -coords_i2w(GanvItem* item, GanvBoxCoords* coords) -{ - ganv_item_i2w_pair(item, &coords->x1, &coords->y1, &coords->x2, &coords->y2); -} - -static void -ganv_box_bounds(GanvItem* item, - double* x1, double* y1, - double* x2, double* y2) -{ - // Note this will not be correct if children are outside the box bounds - GanvBox* box = (GanvBox*)item; - ganv_box_bounds_item(&box->impl->coords, x1, y1, x2, y2); -} - -static void -ganv_box_update(GanvItem* item, int flags) -{ - GanvBox* box = GANV_BOX(item); - GanvBoxPrivate* impl = box->impl; - impl->coords.border_width = box->node.impl->border_width; - - // Request redraw of old location - ganv_box_request_redraw(item, &impl->old_coords, TRUE); - - // Store old coordinates in world relative coordinates in case the - // group we are in moves between now and the next update - impl->old_coords = impl->coords; - coords_i2w(item, &impl->old_coords); - - // Call parent class update method, resizing if necessary - GANV_ITEM_CLASS(parent_class)->update(item, flags); - ganv_box_normalize(box); - - // Update world-relative bounding box - ganv_box_bounds(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2); - ganv_item_i2w_pair(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2); - - // Request redraw of new location - ganv_box_request_redraw(item, &impl->coords, FALSE); -} - -void -ganv_box_path(GanvBox* box, - cairo_t* cr, double x1, double y1, double x2, double y2, - double dr) -{ - static const double degrees = G_PI / 180.0; - - GanvBoxPrivate* impl = box->impl; - - if (impl->radius_tl == 0.0 && impl->radius_tr == 0.0 - && impl->radius_br == 0.0 && impl->radius_bl == 0.0) { - // Simple rectangle - cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); - } else if (impl->beveled) { - // Beveled rectangle - cairo_new_sub_path(cr); - cairo_move_to(cr, x1 + impl->radius_tl, y1); - cairo_line_to(cr, x2 - impl->radius_tr, y1); - cairo_line_to(cr, x2, y1 + impl->radius_tr); - cairo_line_to(cr, x2, y2 - impl->radius_br); - cairo_line_to(cr, x2 - impl->radius_br, y2); - cairo_line_to(cr, x1 + impl->radius_bl, y2); - cairo_line_to(cr, x1, y2 - impl->radius_bl); - cairo_line_to(cr, x1, y2 - impl->radius_bl); - cairo_line_to(cr, x1, y1 + impl->radius_tl); - cairo_close_path(cr); - } else { - // Rounded rectangle - cairo_new_sub_path(cr); - cairo_arc(cr, - x2 - impl->radius_tr - dr, - y1 + impl->radius_tr + dr, - impl->radius_tr + dr, -90 * degrees, 0 * degrees); - cairo_arc(cr, - x2 - impl->radius_br - dr, y2 - impl->radius_br - dr, - impl->radius_br + dr, 0 * degrees, 90 * degrees); - cairo_arc(cr, - x1 + impl->radius_bl + dr, y2 - impl->radius_bl - dr, - impl->radius_bl + dr, 90 * degrees, 180 * degrees); - cairo_arc(cr, - x1 + impl->radius_tl + dr, y1 + impl->radius_tl + dr, - impl->radius_tl + dr, 180 * degrees, 270 * degrees); - cairo_close_path(cr); - } -} - -static void -ganv_box_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - GanvBox* box = GANV_BOX(item); - GanvBoxPrivate* impl = box->impl; - - double x1 = impl->coords.x1; - double y1 = impl->coords.y1; - double x2 = impl->coords.x2; - double y2 = impl->coords.y2; - ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2); - - double dash_length, border_color, fill_color; - ganv_node_get_draw_properties( - &box->node, &dash_length, &border_color, &fill_color); - - double r, g, b, a; - - for (int i = (impl->coords.stacked ? 1 : 0); i >= 0; --i) { - const double x = 0.0 - (STACKED_OFFSET * i); - const double y = 0.0 - (STACKED_OFFSET * i); - - // Trace basic box path - ganv_box_path(box, cr, x1 - x, y1 - y, x2 - x, y2 - y, 0.0); - - // Fill - color_to_rgba(fill_color, &r, &g, &b, &a); - cairo_set_source_rgba(cr, r, g, b, a); - - // Border - if (impl->coords.border_width > 0.0) { - cairo_fill_preserve(cr); - color_to_rgba(border_color, &r, &g, &b, &a); - cairo_set_source_rgba(cr, r, g, b, a); - cairo_set_line_width(cr, impl->coords.border_width); - if (dash_length > 0) { - cairo_set_dash(cr, &dash_length, 1, box->node.impl->dash_offset); - } else { - cairo_set_dash(cr, &dash_length, 0, 0); - } - cairo_stroke(cr); - } else { - cairo_fill(cr); - } - } - - GanvItemClass* item_class = GANV_ITEM_CLASS(parent_class); - item_class->draw(item, cr, cx, cy, cw, ch); -} - -static double -ganv_box_point(GanvItem* item, double x, double y, GanvItem** actual_item) -{ - GanvBox* box = GANV_BOX(item); - GanvBoxPrivate* impl = box->impl; - - *actual_item = NULL; - - double x1, y1, x2, y2; - ganv_box_bounds_item(&impl->coords, &x1, &y1, &x2, &y2); - - // Point is inside the box (distance 0) - if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) { - *actual_item = item; - return 0.0; - } - - // Point is outside the box - double dx = 0.0; - double dy = 0.0; - - // Find horizontal distance to nearest edge - if (x < x1) { - dx = x1 - x; - } else if (x > x2) { - dx = x - x2; - } - - // Find vertical distance to nearest edge - if (y < y1) { - dy = y1 - y; - } else if (y > y2) { - dy = y - y2; - } - - return sqrt((dx * dx) + (dy * dy)); -} - -static gboolean -ganv_box_is_within(const GanvNode* self, - double x1, - double y1, - double x2, - double y2) -{ - double bx1, by1, bx2, by2; - g_object_get(G_OBJECT(self), - "x1", &bx1, - "y1", &by1, - "x2", &bx2, - "y2", &by2, - NULL); - - ganv_item_i2w_pair(GANV_ITEM(self), &bx1, &by1, &bx2, &by2); - - return ( bx1 >= x1 - && by2 >= y1 - && bx2 <= x2 - && by2 <= y2); -} - -static void -ganv_box_default_set_width(GanvBox* box, double width) -{ - box->impl->coords.x2 = ganv_box_get_x1(box) + width; - ganv_item_request_update(GANV_ITEM(box)); -} - -static void -ganv_box_default_set_height(GanvBox* box, double height) -{ - box->impl->coords.y2 = ganv_box_get_y1(box) + height; - ganv_item_request_update(GANV_ITEM(box)); -} - -static void -ganv_box_class_init(GanvBoxClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GanvItemClass* item_class = (GanvItemClass*)klass; - GanvNodeClass* node_class = (GanvNodeClass*)klass; - - parent_class = GANV_NODE_CLASS(g_type_class_peek_parent(klass)); - - gobject_class->set_property = ganv_box_set_property; - gobject_class->get_property = ganv_box_get_property; - - g_object_class_install_property( - gobject_class, PROP_X1, g_param_spec_double( - "x1", - _("x1"), - _("Top left x coordinate."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_Y1, g_param_spec_double( - "y1", - _("y1"), - _("Top left y coordinate."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_X2, g_param_spec_double( - "x2", - _("x2"), - _("Bottom right x coordinate."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_Y2, g_param_spec_double( - "y2", - _("y2"), - _("Bottom right y coordinate."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_RADIUS_TL, g_param_spec_double( - "radius-tl", - _("Top left radius"), - _("The radius of the top left corner."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_RADIUS_TR, g_param_spec_double( - "radius-tr", - _("Top right radius"), - _("The radius of the top right corner."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_RADIUS_BR, g_param_spec_double( - "radius-br", - _("Bottom right radius"), - _("The radius of the bottom right corner."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_RADIUS_BL, g_param_spec_double( - "radius-bl", - _("Bottom left radius"), - _("The radius of the bottom left corner."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_STACKED, g_param_spec_boolean( - "stacked", - _("Stacked"), - _("Show box with a stacked appearance."), - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_BEVELED, g_param_spec_boolean( - "beveled", - _("Beveled"), - _("Show radiused corners with a sharp bevel."), - FALSE, - G_PARAM_READWRITE)); - - object_class->destroy = ganv_box_destroy; - - item_class->update = ganv_box_update; - item_class->bounds = ganv_box_bounds; - item_class->point = ganv_box_point; - item_class->draw = ganv_box_draw; - - node_class->is_within = ganv_box_is_within; - - klass->set_width = ganv_box_default_set_width; - klass->set_height = ganv_box_default_set_height; -} - -void -ganv_box_normalize(GanvBox* box) -{ - if (box->impl->coords.x2 < box->impl->coords.x1) { - const double tmp = box->impl->coords.x1; - box->impl->coords.x1 = box->impl->coords.x2; - box->impl->coords.x2 = tmp; - } - if (box->impl->coords.y2 < box->impl->coords.y1) { - const double tmp = box->impl->coords.y1; - box->impl->coords.y1 = box->impl->coords.y2; - box->impl->coords.y2 = tmp; - } -} - -double -ganv_box_get_x1(const GanvBox* box) -{ - return box->impl->coords.x1; -} - -double -ganv_box_get_y1(const GanvBox* box) -{ - return box->impl->coords.y1; -} - -double -ganv_box_get_x2(const GanvBox* box) -{ - return box->impl->coords.x2; -} - -double -ganv_box_get_y2(const GanvBox* box) -{ - return box->impl->coords.y2; -} - -double -ganv_box_get_width(const GanvBox* box) -{ - return box->impl->coords.x2 - box->impl->coords.x1; -} - -void -ganv_box_set_width(GanvBox* box, - double width) -{ - GANV_BOX_GET_CLASS(box)->set_width(box, width); -} - -double -ganv_box_get_height(const GanvBox* box) -{ - return box->impl->coords.y2 - box->impl->coords.y1; -} - -void -ganv_box_set_height(GanvBox* box, - double height) -{ - GANV_BOX_GET_CLASS(box)->set_height(box, height); -} - -double -ganv_box_get_border_width(const GanvBox* box) -{ - return box->impl->coords.border_width; -} |