David Robillard
ed626628b5
git-svn-id: svn://localhost/ardour2/branches/3.0@9656 d708f5d6-7413-0410-9779-e7cbd77b26cf
804 lines
18 KiB
C++
804 lines
18 KiB
C++
/*
|
|
Copyright (C) 2007 Paul Davis
|
|
This program 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 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "lineset.h"
|
|
#include "rgb_macros.h"
|
|
|
|
#include <libgnomecanvas/libgnomecanvas.h>
|
|
#include <libgnomecanvasmm/group.h>
|
|
#include <libgnomecanvasmm/canvas.h>
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <iostream>
|
|
|
|
using namespace std;
|
|
|
|
namespace Gnome {
|
|
namespace Canvas {
|
|
|
|
LineSetClass LineSet::lineset_class;
|
|
|
|
//static const char* overlap_error_str = "LineSet error: Line overlap";
|
|
|
|
LineSet::Line::Line(double c, double w, uint32_t color)
|
|
: coord(c)
|
|
, width(w)
|
|
{
|
|
UINT_TO_RGBA (color, &r, &g, &b, &a);
|
|
}
|
|
|
|
/* Constructor for dummy lines that are used only with the coordinate */
|
|
LineSet::Line::Line(double c)
|
|
: coord(c)
|
|
{
|
|
}
|
|
|
|
void
|
|
LineSet::Line::set_color(uint32_t color)
|
|
{
|
|
UINT_TO_RGBA (color, &r, &g, &b, &a);
|
|
}
|
|
|
|
const Glib::Class&
|
|
LineSetClass::init()
|
|
{
|
|
if (!gtype_) {
|
|
class_init_func_ = &LineSetClass::class_init_function;
|
|
register_derived_type(Item::get_type());
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
void
|
|
LineSetClass::class_init_function(void* /*g_class*/, void* /*class_data*/)
|
|
{
|
|
}
|
|
|
|
LineSet::LineSet(Group& parent, Orientation o)
|
|
: Glib::ObjectBase("GnomeCanvasLineSet")
|
|
, Item(Glib::ConstructParams(lineset_class.init()))
|
|
, cached_pos(lines.end())
|
|
, orientation(o)
|
|
, x1(*this, "x1", 0.0)
|
|
, y1(*this, "y1", 0.0)
|
|
, x2(*this, "x2", 0.0)
|
|
, y2(*this, "y2", 0.0)
|
|
, in_update(false)
|
|
, update_region1(1.0)
|
|
, update_region2(0.0)
|
|
, bounds_changed(false)
|
|
, covered1(1.0) // covered1 > covered2 ==> nothing's covered
|
|
, covered2(0.0)
|
|
{
|
|
|
|
item_construct(parent);
|
|
|
|
property_x1().signal_changed().connect(sigc::mem_fun(*this, &LineSet::bounds_need_update));
|
|
property_y1().signal_changed().connect(sigc::mem_fun(*this, &LineSet::bounds_need_update));
|
|
property_x2().signal_changed().connect(sigc::mem_fun(*this, &LineSet::bounds_need_update));
|
|
property_y2().signal_changed().connect(sigc::mem_fun(*this, &LineSet::bounds_need_update));
|
|
}
|
|
|
|
LineSet::~LineSet()
|
|
{
|
|
}
|
|
|
|
bool
|
|
LineSet::line_compare(const Line& a, const Line& b)
|
|
{
|
|
return a.coord < b.coord;
|
|
}
|
|
|
|
void
|
|
LineSet::print_lines()
|
|
{
|
|
for (Lines::iterator it = lines.begin(); it != lines.end(); ++it) {
|
|
cerr << " " << it->coord << " " << it->width << " " << (int)it->r << " " << (int)it->g << " " << (int)it->b << " " << (int)it->a << endl;
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::move_line(double coord, double dest)
|
|
{
|
|
if (coord == dest) {
|
|
return;
|
|
}
|
|
|
|
Lines::iterator it = line_at(coord);
|
|
|
|
if (it != lines.end()) {
|
|
|
|
double width = it->width;
|
|
it->coord = dest;
|
|
|
|
Lines::iterator ins = lower_bound(lines.begin(), lines.end(), *it, line_compare);
|
|
|
|
lines.insert(ins, *it);
|
|
lines.erase(it);
|
|
|
|
if (coord > dest) {
|
|
region_needs_update(dest, coord + width);
|
|
} else {
|
|
region_needs_update(coord, dest + width);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::change_line_width(double coord, double width)
|
|
{
|
|
Lines::iterator it = line_at(coord);
|
|
|
|
if (it != lines.end()) {
|
|
Line& l = *it;
|
|
++it;
|
|
|
|
if (it != lines.end()) {
|
|
if (l.coord + width > it->coord) {
|
|
//cerr << overlap_error_str << endl;
|
|
return;
|
|
}
|
|
}
|
|
|
|
l.width = width;
|
|
region_needs_update(coord, coord + width);
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::change_line_color(double coord, uint32_t color)
|
|
{
|
|
Lines::iterator it = line_at(coord);
|
|
|
|
if (it != lines.end()) {
|
|
it->set_color(color);
|
|
region_needs_update(it->coord, it->coord + it->width);
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::add_line(double coord, double width, uint32_t color)
|
|
{
|
|
Line l(coord, width, color);
|
|
|
|
Lines::iterator it = std::lower_bound(lines.begin(), lines.end(), l, line_compare);
|
|
|
|
/* overlap checking */
|
|
if (it != lines.end()) {
|
|
if (l.coord + l.width > it->coord) {
|
|
//cerr << overlap_error_str << endl;
|
|
return;
|
|
}
|
|
}
|
|
if (it != lines.begin()) {
|
|
--it;
|
|
if (l.coord < it->coord + it->width) {
|
|
//cerr << overlap_error_str << endl;
|
|
return;
|
|
}
|
|
++it;
|
|
}
|
|
|
|
lines.insert(it, l);
|
|
region_needs_update(coord, coord + width);
|
|
}
|
|
|
|
void
|
|
LineSet::remove_line(double coord)
|
|
{
|
|
Lines::iterator it = line_at(coord);
|
|
|
|
if (it != lines.end()) {
|
|
double start = it->coord;
|
|
double end = start + it->width;
|
|
|
|
lines.erase(it);
|
|
|
|
region_needs_update(start, end);
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::remove_lines(double c1, double c2)
|
|
{
|
|
if (!lines.empty()) {
|
|
region_needs_update(c1, c2);
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::remove_until(double coord)
|
|
{
|
|
if (!lines.empty()) {
|
|
double first = lines.front().coord;
|
|
|
|
// code
|
|
|
|
region_needs_update(first, coord);
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::remove_from(double coord)
|
|
{
|
|
if (!lines.empty()) {
|
|
double last = lines.back().coord + lines.back().width;
|
|
|
|
// code
|
|
|
|
region_needs_update(coord, last);
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::clear()
|
|
{
|
|
if (!lines.empty()) {
|
|
double coord1 = lines.front().coord;
|
|
double coord2 = lines.back().coord + lines.back().width;
|
|
|
|
lines.clear();
|
|
region_needs_update(coord1, coord2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* this function is optimized to work faster if we access elements that are adjacent to each other.
|
|
* so if a large number of lines are modified, it is wise to modify them in sorted order.
|
|
*/
|
|
LineSet::Lines::iterator
|
|
LineSet::line_at(double coord)
|
|
{
|
|
if (cached_pos != lines.end()) {
|
|
if (coord < cached_pos->coord) {
|
|
/* backward search */
|
|
while (--cached_pos != lines.end()) {
|
|
if (cached_pos->coord <= coord) {
|
|
if (cached_pos->coord + cached_pos->width < coord) {
|
|
/* coord is between two lines */
|
|
return lines.end();
|
|
} else {
|
|
return cached_pos;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
/* forward search */
|
|
while (cached_pos != lines.end()) {
|
|
if (cached_pos->coord > coord) {
|
|
/* we searched past the line that we want, so now see
|
|
if the previous line includes the coordinate */
|
|
--cached_pos;
|
|
if (cached_pos->coord + cached_pos->width >= coord) {
|
|
return cached_pos;
|
|
} else {
|
|
return lines.end();
|
|
}
|
|
}
|
|
++cached_pos;
|
|
}
|
|
}
|
|
} else {
|
|
/* initialize the cached position */
|
|
Line dummy(coord);
|
|
|
|
cached_pos = lower_bound(lines.begin(), lines.end(), dummy, line_compare);
|
|
|
|
/* The iterator found should point to the element after the one we want. */
|
|
--cached_pos;
|
|
|
|
if (cached_pos != lines.end()) {
|
|
if (cached_pos->coord <= coord) {
|
|
if (cached_pos->coord + cached_pos->width >= coord) {
|
|
return cached_pos;
|
|
} else {
|
|
return lines.end();
|
|
}
|
|
} else {
|
|
return lines.end();
|
|
}
|
|
} else {
|
|
return lines.end();
|
|
}
|
|
}
|
|
|
|
return lines.end();
|
|
}
|
|
|
|
void
|
|
LineSet::redraw_request (ArtDRect const & r)
|
|
{
|
|
int x0, y0, x1, y1;
|
|
Canvas& cv = *get_canvas();
|
|
|
|
//cerr << "redraw request: " << r.x0 << " " << r.y0 << " " << r.x1 << " " << r.y1 << endl;
|
|
|
|
double fx0 = r.x0;
|
|
if (fx0 > INT_MAX) {
|
|
fx0 = INT_MAX;
|
|
}
|
|
|
|
double fx1 = r.x1;
|
|
if (fx1 > INT_MAX) {
|
|
fx1 = INT_MAX;
|
|
}
|
|
|
|
cv.w2c (fx0, r.y0, x0, y0);
|
|
cv.w2c (fx1, r.y1, x1, y1);
|
|
|
|
cv.request_redraw(x0, y0, x1, y1);
|
|
}
|
|
|
|
void
|
|
LineSet::update_lines(bool need_redraw)
|
|
{
|
|
//cerr << "update_lines need_redraw=" << need_redraw << endl;
|
|
if (!need_redraw) {
|
|
update_region1 = 1.0;
|
|
update_region2 = 0.0;
|
|
return;
|
|
}
|
|
|
|
if (update_region2 > update_region1) {
|
|
ArtDRect redraw;
|
|
LineSet::bounds_vfunc(&redraw.x0, &redraw.y0, &redraw.x1, &redraw.y1);
|
|
i2w(redraw.x0, redraw.y0);
|
|
i2w(redraw.x1, redraw.y1);
|
|
|
|
if (orientation == Vertical) {
|
|
redraw.x1 = redraw.x0 + update_region2;
|
|
redraw.x0 += update_region1;
|
|
} else {
|
|
redraw.y1 = redraw.y0 + update_region2;
|
|
redraw.y0 += update_region1;
|
|
}
|
|
redraw_request(redraw);
|
|
update_region1 = 1.0;
|
|
update_region2 = 0.0;
|
|
}
|
|
|
|
// if we need to calculate what becomes visible, use some of this
|
|
//cv.c2w (0, 0, world_v[X1], world_v[Y1]);
|
|
//cv.c2w (cv.get_width(), cv.get_height(), world_v[X2], world_v[Y2]);
|
|
}
|
|
|
|
/*
|
|
* return false if a full redraw request has been made.
|
|
* return true if nothing or only parts of the rect area has been requested for redraw
|
|
*/
|
|
bool
|
|
LineSet::update_bounds()
|
|
{
|
|
GnomeCanvasItem* item = GNOME_CANVAS_ITEM(gobj());
|
|
ArtDRect old_b;
|
|
ArtDRect new_b;
|
|
ArtDRect redraw;
|
|
Canvas& cv = *get_canvas();
|
|
|
|
/* store the old bounding box */
|
|
old_b.x0 = item->x1;
|
|
old_b.y0 = item->y1;
|
|
old_b.x1 = item->x2;
|
|
old_b.y1 = item->y2;
|
|
LineSet::bounds_vfunc(&new_b.x0, &new_b.y0, &new_b.x1, &new_b.y1);
|
|
|
|
i2w(new_b.x0, new_b.y0);
|
|
i2w(new_b.x1, new_b.y1);
|
|
|
|
item->x1 = new_b.x0;
|
|
item->y1 = new_b.y0;
|
|
item->x2 = new_b.x1;
|
|
item->y2 = new_b.y1;
|
|
|
|
/* Update bounding box used in rendering function */
|
|
|
|
double fx0 = new_b.x0;
|
|
if (fx0 > INT_MAX) {
|
|
fx0 = INT_MAX;
|
|
}
|
|
|
|
double fx1 = new_b.x1;
|
|
if (fx1 > INT_MAX) {
|
|
fx1 = INT_MAX;
|
|
}
|
|
|
|
cv.w2c (fx0, new_b.y0, bbox.x0, bbox.y0);
|
|
cv.w2c (fx1, new_b.y1, bbox.x1, bbox.y1);
|
|
|
|
/*
|
|
* if the first primary axis property (x1 for Vertical, y1 for Horizontal) changed, we must redraw everything,
|
|
* because lines are positioned relative to this coordinate. Please excuse the confusion resulting from
|
|
* gnome canvas coordinate numbering (1, 2) and libart's (0, 1).
|
|
*/
|
|
if (orientation == Vertical) {
|
|
if (new_b.x0 == old_b.x0) {
|
|
/* No need to update everything */
|
|
if (new_b.y0 != old_b.y0) {
|
|
redraw.x0 = old_b.x0;
|
|
redraw.y0 = min(old_b.y0, new_b.y0);
|
|
redraw.x1 = old_b.x1;
|
|
redraw.y1 = max(old_b.y0, new_b.y0);
|
|
redraw_request(redraw);
|
|
}
|
|
if (new_b.y1 != old_b.y1) {
|
|
redraw.x0 = old_b.x0;
|
|
redraw.y0 = min(old_b.y1, new_b.y1);
|
|
redraw.x1 = old_b.x1;
|
|
redraw.y1 = max(old_b.y1, new_b.y1);
|
|
redraw_request(redraw);
|
|
}
|
|
|
|
if (new_b.x1 > old_b.x1) {
|
|
// we have a larger area ==> possibly more lines
|
|
request_lines(old_b.x1, new_b.x1);
|
|
redraw.x0 = old_b.x1;
|
|
redraw.y0 = min(old_b.y0, new_b.y0);
|
|
redraw.x1 = new_b.x1;
|
|
redraw.y1 = max(old_b.y1, new_b.y1);
|
|
redraw_request(redraw);
|
|
} else if (new_b.x1 < old_b.x1) {
|
|
remove_lines(new_b.x1, old_b.x1);
|
|
redraw.x0 = new_b.x1;
|
|
redraw.y0 = min(old_b.y0, new_b.y0);
|
|
redraw.x1 = old_b.x1;
|
|
redraw.y1 = max(old_b.y1, new_b.y1);
|
|
redraw_request(redraw);
|
|
}
|
|
return true;
|
|
} else {
|
|
/* update everything */
|
|
//cerr << "update everything" << endl;
|
|
art_drect_union(&redraw, &old_b, &new_b);
|
|
redraw_request(redraw);
|
|
return false;
|
|
}
|
|
} else {
|
|
if (new_b.y0 == old_b.y0) {
|
|
/* No need to update everything */
|
|
if (new_b.x0 != old_b.x0) {
|
|
redraw.y0 = old_b.y0;
|
|
redraw.x0 = min(old_b.x0, new_b.x0);
|
|
redraw.y1 = old_b.y1;
|
|
redraw.x1 = max(old_b.x0, new_b.x0);
|
|
redraw_request(redraw);
|
|
}
|
|
if (new_b.x1 != old_b.x1) {
|
|
redraw.y0 = old_b.y0;
|
|
redraw.x0 = min(old_b.x1, new_b.x1);
|
|
redraw.y1 = old_b.y1;
|
|
redraw.x1 = max(old_b.x1, new_b.x1);
|
|
redraw_request(redraw);
|
|
}
|
|
|
|
if (new_b.y1 > old_b.y1) {
|
|
// we have a larger area ==> possibly more lines
|
|
request_lines(old_b.y1, new_b.y1);
|
|
redraw.y0 = old_b.y1;
|
|
redraw.x0 = min(old_b.x0, new_b.x0);
|
|
redraw.y1 = new_b.y1;
|
|
redraw.x1 = max(old_b.x1, new_b.x1);
|
|
redraw_request(redraw);
|
|
} else if (new_b.y1 < old_b.y1) {
|
|
remove_lines(new_b.y1, old_b.y1);
|
|
redraw.y0 = new_b.y1;
|
|
redraw.x0 = min(old_b.x0, new_b.x0);
|
|
redraw.y1 = old_b.y1;
|
|
redraw.x1 = max(old_b.x1, new_b.x1);
|
|
redraw_request(redraw);
|
|
}
|
|
return true;
|
|
} else {
|
|
/* update everything */
|
|
art_drect_union(&redraw, &old_b, &new_b);
|
|
redraw_request(redraw);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* what to do here?
|
|
* 1. find out if any line data has been modified since last update.
|
|
* N. find out if the item moved. if it moved, the old bbox and the new bbox need to be updated.
|
|
*/
|
|
void
|
|
LineSet::update_vfunc(double* /*affine*/, ArtSVP* /*clip_path*/, int /*flags*/)
|
|
{
|
|
GnomeCanvasItem* item = GNOME_CANVAS_ITEM(gobj());
|
|
bool lines_need_redraw = true;
|
|
|
|
/*
|
|
* need to call gnome_canvas_item_update here, to unset the need_update flag.
|
|
* but a call to Gnome::Canvas::Item::update_vfunc results in infinite recursion.
|
|
* that function is declared in gnome_canvas.c so no way to call it directly:
|
|
* Item::update_vfunc(affine, clip_path, flags);
|
|
* So just copy the code from that function. This has to be a bug or
|
|
* something I haven't figured out.
|
|
*/
|
|
GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_UPDATE);
|
|
GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_AFFINE);
|
|
GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_CLIP);
|
|
GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_VIS);
|
|
|
|
//cerr << "update {" << endl;
|
|
in_update = true;
|
|
|
|
// ahh. We must update bounds no matter what. If the group position changed,
|
|
// there is no way that we are notified of that.
|
|
|
|
//if (bounds_changed) {
|
|
lines_need_redraw = update_bounds();
|
|
bounds_changed = false;
|
|
//}
|
|
|
|
update_lines(lines_need_redraw);
|
|
|
|
in_update = false;
|
|
//cerr << "}" << endl;
|
|
}
|
|
|
|
void
|
|
LineSet::draw_vfunc(const Glib::RefPtr<Gdk::Drawable>& /*drawable*/, int /*x*/, int /*y*/, int /*width*/, int /*height*/)
|
|
{
|
|
cerr << "please don't use the GnomeCanvasLineSet item in a non-aa Canvas" << endl;
|
|
abort();
|
|
}
|
|
|
|
inline void
|
|
LineSet::paint_vert(GnomeCanvasBuf* buf, LineSet::Line& line, int x1, int y1, int x2, int y2)
|
|
{
|
|
if (line.width == 1.0) {
|
|
PAINT_VERTA(buf, line.r, line.g, line.b, line.a, x1, y1, y2);
|
|
} else {
|
|
PAINT_BOX(buf, line.r, line.g, line.b, line.a, x1, y1, x2, y2);
|
|
}
|
|
}
|
|
|
|
inline void
|
|
LineSet::paint_horiz(GnomeCanvasBuf* buf, LineSet::Line& line, int x1, int y1, int x2, int y2)
|
|
{
|
|
if (line.width == 1.0) {
|
|
PAINT_HORIZA(buf, line.r, line.g, line.b, line.a, x1, x2, y1);
|
|
} else {
|
|
PAINT_BOX(buf, line.r, line.g, line.b, line.a, x1, y1, x2, y2);
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::render_vfunc(GnomeCanvasBuf* buf)
|
|
{
|
|
ArtIRect rect;
|
|
int pos0, pos1, offset;
|
|
|
|
if (buf->is_bg) {
|
|
gnome_canvas_buf_ensure_buf (buf);
|
|
buf->is_bg = FALSE;
|
|
}
|
|
|
|
/* get the rect that we are rendering to */
|
|
art_irect_intersect(&rect, &bbox, &buf->rect);
|
|
|
|
#if 0
|
|
/* DEBUG render bounding box for this region. should result in the full
|
|
bounding box when all rendering regions are finished */
|
|
PAINT_BOX(buf, 0xaa, 0xaa, 0xff, 0xbb, rect.x0, rect.y0, rect.x1, rect.y1);
|
|
#endif
|
|
|
|
#if 0
|
|
/* harlequin debugging, shows the rect that is actually drawn, distinct from
|
|
rects from other render cycles */
|
|
gint r, g, b, a;
|
|
r = random() % 0xff;
|
|
g = random() % 0xff;
|
|
b = random() % 0xff;
|
|
PAINT_BOX(buf, r, g, b, 0x33, rect.x0, rect.y0, rect.x1, rect.y1);
|
|
#endif
|
|
|
|
if (lines.empty()) {
|
|
return;
|
|
}
|
|
|
|
Lines::iterator it = lines.begin();
|
|
Lines::iterator end = --lines.end();
|
|
|
|
/**
|
|
* The first and the last line in this render have to be handled separately from those in between, because those lines
|
|
* may be cut off at the ends.
|
|
*/
|
|
|
|
if (orientation == Vertical) {
|
|
offset = bbox.x0;
|
|
|
|
// skip parts of lines that are to the right of the buffer, and paint the last line visible
|
|
for (; end != lines.end(); --end) {
|
|
pos0 = ((int) floor(end->coord)) + offset;
|
|
|
|
if (pos0 < rect.x1) {
|
|
pos1 = min((pos0 + (int) floor(end->width)), rect.x1);
|
|
if (pos0 < rect.x0 && pos1 < rect.x0) {
|
|
return;
|
|
}
|
|
|
|
paint_vert(buf, *end, pos0, rect.y0, pos1, rect.y1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (end == lines.end()) {
|
|
return;
|
|
}
|
|
|
|
// skip parts of lines that are to the left of the buffer
|
|
for (; it != end; ++it) {
|
|
pos0 = ((int) floor(it->coord)) + offset;
|
|
pos1 = pos0 + ((int) floor(it->width));
|
|
|
|
if (pos1 > rect.x0) {
|
|
pos0 = max(pos0, rect.x0);
|
|
paint_vert(buf, *it, pos0, rect.y0, pos1, rect.y1);
|
|
++it;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// render what's between the first and last lines
|
|
for (; it != end; ++it) {
|
|
pos0 = ((int) floor(it->coord)) + offset;
|
|
pos1 = pos0 + ((int) floor(it->width));
|
|
|
|
paint_vert(buf, *it, pos0, rect.y0, pos1, rect.y1);
|
|
}
|
|
} else {
|
|
offset = bbox.y0;
|
|
|
|
// skip parts of lines that are to the right of the buffer, and paint the last line visible
|
|
for (; end != lines.end(); --end) {
|
|
pos0 = ((int) floor(end->coord)) + offset;
|
|
|
|
if (pos0 < rect.y1) {
|
|
pos1 = min((pos0 + (int) floor(end->width)), rect.y1);
|
|
if (pos0 < rect.y0 && pos1 < rect.y0) {
|
|
return;
|
|
}
|
|
|
|
paint_horiz(buf, *end, rect.x0, pos0, rect.x1, pos1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (end == lines.end()) {
|
|
return;
|
|
}
|
|
|
|
// skip parts of lines that are to the left of the buffer
|
|
for (; it != end; ++it) {
|
|
pos0 = ((int) floor(it->coord)) + offset;
|
|
pos1 = pos0 + ((int) floor(it->width));
|
|
|
|
if (pos1 > rect.y0) {
|
|
pos0 = max(pos0, rect.y0);
|
|
paint_horiz(buf, *it, rect.x0, pos0, rect.x1, pos1);
|
|
++it;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// render what's between the first and last lines
|
|
for (; it != end; ++it) {
|
|
pos0 = ((int) floor(it->coord)) + offset;
|
|
pos1 = pos0 + ((int) floor(it->width));
|
|
paint_horiz(buf, *it, rect.x0, pos0, rect.x1, pos1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::bounds_vfunc(double* _x1, double* _y1, double* _x2, double* _y2)
|
|
{
|
|
*_x1 = x1;
|
|
*_y1 = y1;
|
|
*_x2 = x2 + 1;
|
|
*_y2 = y2 + 1;
|
|
}
|
|
|
|
|
|
double
|
|
LineSet::point_vfunc(double x, double y, int /*cx*/, int /*cy*/, GnomeCanvasItem** actual_item)
|
|
{
|
|
double x1, y1, x2, y2;
|
|
double dx, dy;
|
|
|
|
LineSet::bounds_vfunc(&x1, &y1, &x2, &y2);
|
|
|
|
*actual_item = gobj();
|
|
|
|
if (x < x1) {
|
|
dx = x1 - x;
|
|
} else if (x > x2) {
|
|
dx = x - x2;
|
|
} else {
|
|
dx = 0.0;
|
|
}
|
|
|
|
if (y < y1) {
|
|
dy = y1 - y;
|
|
} else if (y > y2) {
|
|
dy = y - y2;
|
|
} else {
|
|
if (dx == 0.0) {
|
|
// point is inside
|
|
return 0.0;
|
|
} else {
|
|
dy = 0.0;
|
|
}
|
|
}
|
|
|
|
return sqrt (dx * dx + dy * dy);
|
|
}
|
|
|
|
/* If not overrided emit the signal */
|
|
void
|
|
LineSet::request_lines(double c1, double c2)
|
|
{
|
|
signal_request_lines(*this, c1, c2);
|
|
}
|
|
|
|
void
|
|
LineSet::bounds_need_update()
|
|
{
|
|
bounds_changed = true;
|
|
|
|
if (!in_update) {
|
|
request_update();
|
|
}
|
|
}
|
|
|
|
void
|
|
LineSet::region_needs_update(double coord1, double coord2)
|
|
{
|
|
if (update_region1 > update_region2) {
|
|
update_region1 = coord1;
|
|
update_region2 = coord2;
|
|
} else {
|
|
update_region1 = min(update_region1, coord1);
|
|
update_region2 = max(update_region2, coord2);
|
|
}
|
|
|
|
if (!in_update) {
|
|
request_update();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* These have been defined to avoid endless recursion with gnomecanvasmm.
|
|
* Don't know why this happens
|
|
*/
|
|
bool LineSet::on_event(GdkEvent* /*p1*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void LineSet::realize_vfunc() { }
|
|
void LineSet::unrealize_vfunc() { }
|
|
void LineSet::map_vfunc() { }
|
|
void LineSet::unmap_vfunc() { }
|
|
|
|
} /* namespace Canvas */
|
|
} /* namespace Gnome */
|