Logo Search packages:      
Sourcecode: inkscape version File versions

sodipodi-ctrlrect.cpp

#define __INKSCAPE_CTRLRECT_C__

/*
 * Simple non-transformed rectangle, usable for rubberband
 *
 * Author:
 *   Lauris Kaplinski <lauris@ximian.com>
 *
 * Copyright (C) 1999-2001 Lauris Kaplinski
 * Copyright (C) 2000-2001 Ximian, Inc.
 *
 * Released under GNU GPL
 *
 */

#include <math.h>
#include "sp-canvas.h"
#include "sp-canvas-util.h"
#include "sodipodi-ctrlrect.h"

/*
 * Currently we do not have point method, as it should always be painted
 * during some transformation, which takes care of events...
 *
 * Corner coords can be in any order - i.e. x1 < x0 is allowed
 */

static void sp_ctrlrect_class_init (SPCtrlRectClass *klass);
static void sp_ctrlrect_init (SPCtrlRect *ctrlrect);
static void sp_ctrlrect_destroy (GtkObject *object);

static void sp_ctrlrect_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags);
static void sp_ctrlrect_render (SPCanvasItem *item, SPCanvasBuf *buf);

static SPCanvasItemClass *parent_class;

static const guint DASH_LENGTH = 4;

GtkType
sp_ctrlrect_get_type (void)
{
      static GtkType ctrlrect_type = 0;

      if (!ctrlrect_type) {
            GtkTypeInfo ctrlrect_info = {
                  "SPCtrlRect",
                  sizeof (SPCtrlRect),
                  sizeof (SPCtrlRectClass),
                  (GtkClassInitFunc) sp_ctrlrect_class_init,
                  (GtkObjectInitFunc) sp_ctrlrect_init,
                  NULL, NULL, NULL
            };
            ctrlrect_type = gtk_type_unique (SP_TYPE_CANVAS_ITEM, &ctrlrect_info);
      }
      return ctrlrect_type;
}

static void
sp_ctrlrect_class_init (SPCtrlRectClass *klass)
{
      GtkObjectClass *object_class;
      SPCanvasItemClass *item_class;

      object_class = (GtkObjectClass *) klass;
      item_class = (SPCanvasItemClass *) klass;

      parent_class = (SPCanvasItemClass*)gtk_type_class (sp_canvas_item_get_type ());

      object_class->destroy = sp_ctrlrect_destroy;

      item_class->update = sp_ctrlrect_update;
      item_class->render = sp_ctrlrect_render;
}

static void
sp_ctrlrect_init (SPCtrlRect *cr)
{
      cr->has_fill = FALSE;
        cr->dashed = FALSE;

      cr->rect.x0 = cr->rect.y0 = cr->rect.x1 = cr->rect.y1 = 0;

      cr->shadow = 0;

      cr->area.x0 = cr->area.y0 = 0;
      cr->area.x1 = cr->area.y1 = -1;

      cr->shadow_size = 0;

      cr->border_color = 0x000000ff;
      cr->fill_color = 0xffffffff;
      cr->shadow_color = 0x000000ff;
}

static void
sp_ctrlrect_destroy (GtkObject *object)
{
      if (GTK_OBJECT_CLASS (parent_class)->destroy)
            (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}

#define RGBA_R(v) ((v) >> 24)
#define RGBA_G(v) (((v) >> 16) & 0xff)
#define RGBA_B(v) (((v) >> 8) & 0xff)
#define RGBA_A(v) ((v) & 0xff)
#define COMPOSE(b,f,a) ( ( ((guchar) b) * ((guchar) (0xff - a)) + ((guchar) ((b ^ ~f) + b/4 - (b>127? 63 : 0))) * ((guchar) a) ) / 0xff )

static void
sp_ctrlrect_hline (SPCanvasBuf *buf, gint y, gint xs, gint xe, guint32 rgba, guint dashed)
{
      if ((y >= buf->rect.y0) && (y < buf->rect.y1)) {
            guint r, g, b, a;
            gint x0, x1, x;
            guchar *p;
            r = RGBA_R (rgba);
            g = RGBA_G (rgba);
            b = RGBA_B (rgba);
            a = RGBA_A (rgba);
            x0 = MAX (buf->rect.x0, xs);
            x1 = MIN (buf->rect.x1, xe + 1);
            p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 3;
            for (x = x0; x < x1; x++) {
                if (!dashed || ((x / DASH_LENGTH) % 2)) {
                  p[0] = COMPOSE (p[0], r, a);
                  p[1] = COMPOSE (p[1], g, a);
                  p[2] = COMPOSE (p[2], b, a);
                }
                p += 3;
            }
      }
}

static void
sp_ctrlrect_vline (SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba, guint dashed)
{
      if ((x >= buf->rect.x0) && (x < buf->rect.x1)) {
            guint r, g, b, a;
            gint y0, y1, y;
            guchar *p;
            r = RGBA_R (rgba);
            g = RGBA_G (rgba);
            b = RGBA_B (rgba);
            a = RGBA_A (rgba);
            y0 = MAX (buf->rect.y0, ys);
            y1 = MIN (buf->rect.y1, ye + 1);
            p = buf->buf + (y0 - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 3;
            for (y = y0; y < y1; y++) {
                if (!dashed || ((y / DASH_LENGTH) % 2)) {
                  p[0] = COMPOSE (p[0], r, a);
                  p[1] = COMPOSE (p[1], g, a);
                  p[2] = COMPOSE (p[2], b, a);
                }
                p += buf->buf_rowstride;
            }
      }
}

/** Fills the pixels in [xs, xe)*[ys,ye) clipped to the tile with rgb * a. */
static void
sp_ctrlrect_area (SPCanvasBuf *buf, gint xs, gint ys, gint xe, gint ye, guint32 rgba)
{
      guint r, g, b, a;
      gint x0, x1, x;
      gint y0, y1, y;
      guchar *p;
      r = RGBA_R (rgba);
      g = RGBA_G (rgba);
      b = RGBA_B (rgba);
      a = RGBA_A (rgba);
      x0 = MAX (buf->rect.x0, xs);
      x1 = MIN (buf->rect.x1, xe + 1);
      y0 = MAX (buf->rect.y0, ys);
      y1 = MIN (buf->rect.y1, ye + 1);
      for (y = y0; y < y1; y++) {
            p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 3;
            for (x = x0; x < x1; x++) {
                  p[0] = COMPOSE (p[0], r, a);
                  p[1] = COMPOSE (p[1], g, a);
                  p[2] = COMPOSE (p[2], b, a);
                  p += 3;
            }
      }
}

static void
sp_ctrlrect_render (SPCanvasItem *item, SPCanvasBuf *buf)
{
      SPCtrlRect *cr = SP_CTRLRECT (item);
      
      if ((cr->area.x0 < buf->rect.x1) &&
          (cr->area.y0 < buf->rect.y1) &&
          ((cr->area.x1 + cr->shadow_size) >= buf->rect.x0) &&
          ((cr->area.y1 + cr->shadow_size) >= buf->rect.y0)) {
            /* Initialize buffer, if needed */
            if (buf->is_bg) {
                  sp_canvas_clear_buffer (buf);
                  buf->is_bg = FALSE;
                  buf->is_buf = TRUE;
            }
            /* Top */
            sp_ctrlrect_hline (buf, cr->area.y0, cr->area.x0, cr->area.x1, cr->border_color, cr->dashed);
            /* Bottom */
            sp_ctrlrect_hline (buf, cr->area.y1, cr->area.x0, cr->area.x1, cr->border_color, cr->dashed);
            /* Left */
            sp_ctrlrect_vline (buf, cr->area.x0, cr->area.y0 + 1, cr->area.y1 - 1, cr->border_color, cr->dashed);
            /* Right */
            sp_ctrlrect_vline (buf, cr->area.x1, cr->area.y0 + 1, cr->area.y1 - 1, cr->border_color, cr->dashed);
            if (cr->shadow_size > 0) {
                  /* Right shadow */
                  sp_ctrlrect_area (buf, cr->area.x1 + 1, cr->area.y0 + cr->shadow_size,
                                cr->area.x1 + cr->shadow_size, cr->area.y1 + cr->shadow_size, cr->shadow_color);
                  /* Bottom shadow */
                  sp_ctrlrect_area (buf, cr->area.x0 + cr->shadow_size, cr->area.y1 + 1,
                                cr->area.x1, cr->area.y1 + cr->shadow_size, cr->shadow_color);
            }
            if (cr->has_fill) {
                  /* Fill */
                  sp_ctrlrect_area (buf, cr->area.x0 + 1, cr->area.y0 + 1,
                                cr->area.x1 - 1, cr->area.y1 - 1, cr->fill_color);
            }
      }
}

static void
sp_ctrlrect_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags)
{
        SPCtrlRect *cr = SP_CTRLRECT (item);

      if (((SPCanvasItemClass *) parent_class)->update)
            ((SPCanvasItemClass *) parent_class)->update (item, affine, flags);

      sp_canvas_item_reset_bounds (item);

      /* Request redraw old */
      if (!cr->has_fill) {
            /* Top */
            sp_canvas_request_redraw (item->canvas,
                                   cr->area.x0 - 1, cr->area.y0 - 1,
                                   cr->area.x1 + 1, cr->area.y0 + 1);
            /* Left */
            sp_canvas_request_redraw (item->canvas,
                                   cr->area.x0 - 1, cr->area.y0 - 1,
                                   cr->area.x0 + 1, cr->area.y1 + 1);
            /* Right */
            sp_canvas_request_redraw (item->canvas,
                                   cr->area.x1 - 1, cr->area.y0 - 1,
                                   cr->area.x1 + cr->shadow_size + 1, cr->area.y1 + cr->shadow_size + 1);
            /* Bottom */
            sp_canvas_request_redraw (item->canvas,
                                   cr->area.x0 - 1, cr->area.y1 - 1,
                                   cr->area.x1 + cr->shadow_size + 1, cr->area.y1 + cr->shadow_size + 1);
      } else {
            sp_canvas_request_redraw (item->canvas,
                                   cr->area.x0 - 1, cr->area.y0 - 1,
                                   cr->area.x1 + cr->shadow_size + 1, cr->area.y1 + cr->shadow_size + 1);
      }

      NRRect bbox;

      nr_rect_d_matrix_transform (&bbox, &cr->rect, affine);

      cr->area.x0 = (int) floor (bbox.x0 + 0.5);
      cr->area.y0 = (int) floor (bbox.y0 + 0.5);
      cr->area.x1 = (int) floor (bbox.x1 + 0.5);
      cr->area.y1 = (int) floor (bbox.y1 + 0.5);

      cr->shadow_size = cr->shadow;

      /* Request redraw new */
      if (!cr->has_fill) {
            /* Top */
            sp_canvas_request_redraw (item->canvas,
                                   cr->area.x0 - 1, cr->area.y0 - 1,
                                   cr->area.x1 + 1, cr->area.y0 + 1);
            /* Left */
            sp_canvas_request_redraw (item->canvas,
                                   cr->area.x0 - 1, cr->area.y0 - 1,
                                   cr->area.x0 + 1, cr->area.y1 + 1);
            /* Right */
            sp_canvas_request_redraw (item->canvas,
                                   cr->area.x1 - 1, cr->area.y0 - 1,
                                   cr->area.x1 + cr->shadow_size + 1, cr->area.y1 + cr->shadow_size + 1);
            /* Bottom */
            sp_canvas_request_redraw (item->canvas,
                                   cr->area.x0 - 1, cr->area.y1 - 1,
                                   cr->area.x1 + cr->shadow_size + 1, cr->area.y1 + cr->shadow_size + 1);
      } else {
            sp_canvas_request_redraw (item->canvas,
                                   cr->area.x0 - 1, cr->area.y0 - 1,
                                   cr->area.x1 + cr->shadow_size + 1, cr->area.y1 + cr->shadow_size + 1);
      }

      item->x1 = cr->area.x0 - 1;
      item->y1 = cr->area.y0 - 1;
      item->x2 = cr->area.x1 + cr->shadow_size + 1;
      item->y2 = cr->area.y1 + cr->shadow_size + 1;
}

void
sp_ctrlrect_set_area (SPCtrlRect *cr, double x0, double y0, double x1, double y1)
{
      g_return_if_fail (cr != NULL);
      g_return_if_fail (SP_IS_CTRLRECT (cr));

      cr->rect.x0 = MIN (x0, x1);
      cr->rect.y0 = MIN (y0, y1);
      cr->rect.x1 = MAX (x0, x1);
      cr->rect.y1 = MAX (y0, y1);

      sp_canvas_item_request_update (SP_CANVAS_ITEM (cr));
}

void
sp_ctrlrect_set_color (SPCtrlRect *cr, guint32 border_color, gboolean has_fill, guint32 fill_color)
{
      g_return_if_fail (cr != NULL);
      g_return_if_fail (SP_IS_CTRLRECT (cr));

      cr->border_color = border_color;
      cr->has_fill = has_fill;
      cr->fill_color = fill_color;

      sp_canvas_item_request_update (SP_CANVAS_ITEM (cr));
}

void
sp_ctrlrect_set_shadow (SPCtrlRect *cr, gint shadow_size, guint32 shadow_color)
{
      g_return_if_fail (cr != NULL);
      g_return_if_fail (SP_IS_CTRLRECT (cr));

      cr->shadow = shadow_size;
      cr->shadow_color = shadow_color;

      sp_canvas_item_request_update (SP_CANVAS_ITEM (cr));
}

void
sp_ctrlrect_set_rect (SPCtrlRect * cr, NRRect * r)
{
      cr->rect.x0 = MIN (r->x0, r->x1);
      cr->rect.y0 = MIN (r->y0, r->y1);
      cr->rect.x1 = MAX (r->x0, r->x1);
      cr->rect.y1 = MAX (r->y0, r->y1);

      sp_canvas_item_request_update (SP_CANVAS_ITEM (cr));
}

void
sp_ctrlrect_set_dashed (SPCtrlRect * cr, guint d)
{
    cr->dashed = d;

    sp_canvas_item_request_update (SP_CANVAS_ITEM (cr));
}

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :

Generated by  Doxygen 1.6.0   Back to index