summaryrefslogtreecommitdiffstats
path: root/src/circle.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/circle.c')
-rw-r--r--src/circle.c467
1 files changed, 0 insertions, 467 deletions
diff --git a/src/circle.c b/src/circle.c
deleted file mode 100644
index a69c207..0000000
--- a/src/circle.c
+++ /dev/null
@@ -1,467 +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 "ganv/canvas.h"
-#include "ganv/circle.h"
-
-#include "./color.h"
-#include "./boilerplate.h"
-#include "./gettext.h"
-#include "./ganv-private.h"
-
-G_DEFINE_TYPE_WITH_CODE(GanvCircle, ganv_circle, GANV_TYPE_NODE,
- G_ADD_PRIVATE(GanvCircle))
-
-static GanvNodeClass* parent_class;
-
-enum {
- PROP_0,
- PROP_RADIUS,
- PROP_RADIUS_EMS,
- PROP_FIT_LABEL
-};
-
-static void
-ganv_circle_init(GanvCircle* circle)
-{
- circle->impl = ganv_circle_get_instance_private(circle);
-
- memset(&circle->impl->coords, '\0', sizeof(GanvCircleCoords));
- circle->impl->coords.radius = 0.0;
- circle->impl->coords.radius_ems = 1.0;
- circle->impl->coords.width = 2.0;
- circle->impl->old_coords = circle->impl->coords;
- circle->impl->fit_label = TRUE;
-}
-
-static void
-ganv_circle_destroy(GtkObject* object)
-{
- g_return_if_fail(object != NULL);
- g_return_if_fail(GANV_IS_CIRCLE(object));
-
- if (GTK_OBJECT_CLASS(parent_class)->destroy) {
- (*GTK_OBJECT_CLASS(parent_class)->destroy)(object);
- }
-}
-
-static void
-ganv_circle_set_property(GObject* object,
- guint prop_id,
- const GValue* value,
- GParamSpec* pspec)
-{
- g_return_if_fail(object != NULL);
- g_return_if_fail(GANV_IS_CIRCLE(object));
-
- GanvCircle* circle = GANV_CIRCLE(object);
-
- switch (prop_id) {
- SET_CASE(RADIUS, double, circle->impl->coords.radius);
- SET_CASE(RADIUS_EMS, double, circle->impl->coords.radius_ems);
- SET_CASE(FIT_LABEL, boolean, circle->impl->fit_label);
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
-
- if (prop_id == PROP_RADIUS_EMS) {
- ganv_circle_set_radius_ems(circle, circle->impl->coords.radius_ems);
- }
-}
-
-static void
-ganv_circle_get_property(GObject* object,
- guint prop_id,
- GValue* value,
- GParamSpec* pspec)
-{
- g_return_if_fail(object != NULL);
- g_return_if_fail(GANV_IS_CIRCLE(object));
-
- GanvCircle* circle = GANV_CIRCLE(object);
-
- switch (prop_id) {
- GET_CASE(RADIUS, double, circle->impl->coords.radius);
- GET_CASE(RADIUS_EMS, double, circle->impl->coords.radius_ems);
- GET_CASE(FIT_LABEL, boolean, circle->impl->fit_label);
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
-}
-
-static void
-ganv_circle_resize(GanvNode* self)
-{
- GanvNode* node = GANV_NODE(self);
- GanvCircle* circle = GANV_CIRCLE(self);
- GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(node)->impl->canvas);
-
- if (node->impl->label) {
- if (node->impl->label->impl->needs_layout) {
- ganv_text_layout(node->impl->label);
- }
-
- const double label_w = node->impl->label->impl->coords.width;
- const double label_h = node->impl->label->impl->coords.height;
- if (circle->impl->fit_label) {
- // Resize to fit text
- const double radius = MAX(label_w, label_h) / 2.0 + 3.0;
- if (radius != circle->impl->coords.radius) {
- ganv_item_set(GANV_ITEM(self),
- "radius", radius,
- NULL);
- }
- }
-
- // Center label
- ganv_item_set(GANV_ITEM(node->impl->label),
- "x", label_w / -2.0,
- "y", label_h / -2.0,
- NULL);
- }
-
- if (parent_class->resize) {
- parent_class->resize(self);
- }
-
- ganv_canvas_for_each_edge_on(
- canvas, node, (GanvEdgeFunc)ganv_edge_update_location, NULL);
-}
-
-static void
-ganv_circle_redraw_text(GanvNode* self)
-{
- GanvCircle* circle = GANV_CIRCLE(self);
- if (circle->impl->coords.radius_ems) {
- ganv_circle_set_radius_ems(circle, circle->impl->coords.radius_ems);
- }
-
- if (parent_class->redraw_text) {
- parent_class->redraw_text(self);
- }
-}
-
-static gboolean
-ganv_circle_is_within(const GanvNode* self,
- double x1,
- double y1,
- double x2,
- double y2)
-{
- const double x = GANV_ITEM(self)->impl->x;
- const double y = GANV_ITEM(self)->impl->y;
-
- return x >= x1
- && x <= x2
- && y >= y1
- && y <= y2;
-}
-
-static void
-ganv_circle_vector(const GanvNode* self,
- const GanvNode* other,
- double* x,
- double* y,
- double* dx,
- double* dy)
-{
- GanvCircle* circle = GANV_CIRCLE(self);
-
- const double cx = GANV_ITEM(self)->impl->x;
- const double cy = GANV_ITEM(self)->impl->y;
- const double other_x = GANV_ITEM(other)->impl->x;
- const double other_y = GANV_ITEM(other)->impl->y;
-
- const double border = circle->node.impl->border_width;
- const double xdist = other_x - cx;
- const double ydist = other_y - cy;
- const double h = sqrt((xdist * xdist) + (ydist * ydist));
- const double theta = asin(xdist / (h + DBL_EPSILON));
- const double y_mod = (cy < other_y) ? 1 : -1;
- const double ret_h = h - circle->impl->coords.radius - border / 2.0;
- const double ret_x = other_x - sin(theta) * ret_h;
- const double ret_y = other_y - cos(theta) * ret_h * y_mod;
-
- *x = ret_x;
- *y = ret_y;
- *dx = 0.0;
- *dy = 0.0;
-
- ganv_item_i2w(GANV_ITEM(circle)->impl->parent, x, y);
-}
-
-static void
-request_redraw(GanvItem* item,
- const GanvCircleCoords* coords,
- gboolean world)
-{
- const double w = coords->width;
-
- double x1 = coords->x - coords->radius - w;
- double y1 = coords->y - coords->radius - w;
- double x2 = coords->x + coords->radius + w;
- double y2 = coords->y + coords->radius + w;
-
- if (!world) {
- // Convert from parent-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, GanvCircleCoords* coords)
-{
- ganv_item_i2w(item, &coords->x, &coords->y);
-}
-
-static void
-ganv_circle_bounds_item(GanvItem* item,
- double* x1, double* y1,
- double* x2, double* y2)
-{
- const GanvCircle* circle = GANV_CIRCLE(item);
- const GanvCircleCoords* coords = &circle->impl->coords;
- *x1 = coords->x - coords->radius - coords->width;
- *y1 = coords->y - coords->radius - coords->width;
- *x2 = coords->x + coords->radius + coords->width;
- *y2 = coords->y + coords->radius + coords->width;
-}
-
-static void
-ganv_circle_bounds(GanvItem* item,
- double* x1, double* y1,
- double* x2, double* y2)
-{
- ganv_circle_bounds_item(item, x1, y1, x2, y2);
-}
-
-static void
-ganv_circle_update(GanvItem* item, int flags)
-{
- GanvCircle* circle = GANV_CIRCLE(item);
- GanvCirclePrivate* impl = circle->impl;
- impl->coords.width = circle->node.impl->border_width;
-
- // Request redraw of old location
- 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);
-
- // Update world-relative bounding box
- ganv_circle_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
- request_redraw(item, &impl->coords, FALSE);
-
- GANV_ITEM_CLASS(parent_class)->update(item, flags);
-}
-
-static void
-ganv_circle_draw(GanvItem* item,
- cairo_t* cr, double cx, double cy, double cw, double ch)
-{
- GanvNode* node = GANV_NODE(item);
- GanvCircle* circle = GANV_CIRCLE(item);
- GanvCirclePrivate* impl = circle->impl;
-
- double r, g, b, a;
-
- double x = impl->coords.x;
- double y = impl->coords.y;
- ganv_item_i2w(item, &x, &y);
-
- double dash_length, border_color, fill_color;
- ganv_node_get_draw_properties(
- &circle->node, &dash_length, &border_color, &fill_color);
-
- // Fill
- cairo_new_path(cr);
- cairo_arc(cr,
- x,
- y,
- impl->coords.radius + (impl->coords.width / 2.0),
- 0, 2 * G_PI);
- color_to_rgba(fill_color, &r, &g, &b, &a);
- cairo_set_source_rgba(cr, r, g, b, a);
- cairo_fill(cr);
-
- // Border
- cairo_arc(cr,
- x,
- y,
- impl->coords.radius,
- 0, 2 * G_PI);
- 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.width);
- if (dash_length > 0) {
- cairo_set_dash(cr, &dash_length, 1, circle->node.impl->dash_offset);
- } else {
- cairo_set_dash(cr, &dash_length, 0, 0);
- }
- cairo_stroke(cr);
-
- // Draw label
- if (node->impl->label) {
- GanvItem* label_item = GANV_ITEM(node->impl->label);
-
- if (label_item->object.flags & GANV_ITEM_VISIBLE) {
- GANV_ITEM_GET_CLASS(label_item)->draw(
- label_item, cr, cx, cy, cw, ch);
- }
- }
-}
-
-static double
-ganv_circle_point(GanvItem* item, double x, double y, GanvItem** actual_item)
-{
- const GanvCircle* circle = GANV_CIRCLE(item);
- const GanvCircleCoords* coords = &circle->impl->coords;
-
- *actual_item = item;
-
- const double dx = fabs(x - coords->x);
- const double dy = fabs(y - coords->y);
- const double d = sqrt((dx * dx) + (dy * dy));
-
- if (d <= coords->radius + coords->width) {
- // Point is inside the circle
- return 0.0;
- } else {
- // Distance from the edge of the circle
- return d - (coords->radius + coords->width);
- }
-}
-
-static void
-ganv_circle_class_init(GanvCircleClass* 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_circle_set_property;
- gobject_class->get_property = ganv_circle_get_property;
-
- g_object_class_install_property(
- gobject_class, PROP_RADIUS, g_param_spec_double(
- "radius",
- _("Radius"),
- _("The radius of the circle."),
- 0, G_MAXDOUBLE,
- 0.0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property(
- gobject_class, PROP_RADIUS_EMS, g_param_spec_double(
- "radius-ems",
- _("Radius in ems"),
- _("The radius of the circle in ems."),
- 0, G_MAXDOUBLE,
- 1.0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property(
- gobject_class, PROP_FIT_LABEL, g_param_spec_boolean(
- "fit-label",
- _("Fit label"),
- _("If true, expand circle to fit its label"),
- TRUE,
- (GParamFlags)G_PARAM_READWRITE));
-
- object_class->destroy = ganv_circle_destroy;
-
- node_class->resize = ganv_circle_resize;
- node_class->is_within = ganv_circle_is_within;
- node_class->tail_vector = ganv_circle_vector;
- node_class->head_vector = ganv_circle_vector;
- node_class->redraw_text = ganv_circle_redraw_text;
-
- item_class->update = ganv_circle_update;
- item_class->bounds = ganv_circle_bounds;
- item_class->point = ganv_circle_point;
- item_class->draw = ganv_circle_draw;
-}
-
-GanvCircle*
-ganv_circle_new(GanvCanvas* canvas,
- const char* first_property_name, ...)
-{
- GanvCircle* circle = GANV_CIRCLE(
- g_object_new(ganv_circle_get_type(), "canvas", canvas, NULL));
-
- va_list args;
- va_start(args, first_property_name);
- g_object_set_valist(G_OBJECT(circle), first_property_name, args);
- va_end(args);
-
- return circle;
-}
-
-double
-ganv_circle_get_radius(const GanvCircle* circle)
-{
- return circle->impl->coords.radius;
-}
-
-void
-ganv_circle_set_radius(GanvCircle* circle, double radius)
-{
- circle->impl->coords.radius = radius;
- ganv_item_request_update(GANV_ITEM(circle));
-}
-
-double
-ganv_circle_get_radius_ems(const GanvCircle* circle)
-{
- return circle->impl->coords.radius_ems;
-}
-
-void
-ganv_circle_set_radius_ems(GanvCircle* circle, double ems)
-{
- GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(circle)->impl->canvas);
- const double points = ganv_canvas_get_font_size(canvas);
- circle->impl->coords.radius_ems = ems;
- circle->impl->coords.radius = points * ems;
- ganv_item_request_update(GANV_ITEM(circle));
-}
-
-gboolean
-ganv_circle_get_fit_label(const GanvCircle* circle)
-{
- return circle->impl->fit_label;
-}
-
-void
-ganv_circle_set_fit_label(GanvCircle* circle, gboolean fit_label)
-{
- circle->impl->fit_label = fit_label;
- ganv_item_request_update(GANV_ITEM(circle));
-}