1 #define __RUBBERBAND_C__
3 /**
4 * \file src/rubberband.cpp
5 * \brief Rubberbanding selector
6 *
7 * Author:
8 * Lauris Kaplinski <lauris@kaplinski.com>
9 *
10 * Copyright (C) 1999-2002 Lauris Kaplinski
11 *
12 * Released under GNU GPL, read the file 'COPYING' for more information
13 */
15 #include "display/sodipodi-ctrlrect.h"
16 #include "desktop.h"
17 #include "inkscape.h"
18 #include "desktop-handles.h"
19 #include "rubberband.h"
20 #include "display/canvas-bpath.h"
21 #include "display/curve.h"
22 #include "libnr/nr-point.h"
24 Inkscape::Rubberband *Inkscape::Rubberband::_instance = NULL;
26 Inkscape::Rubberband::Rubberband()
27 : _desktop(SP_ACTIVE_DESKTOP), _rect(NULL), _touchpath(NULL), _started(false)
28 {
29 _points.clear();
30 _mode = RUBBERBAND_MODE_RECT;
31 _touchpath_curve = new SPCurve();
32 }
34 void Inkscape::Rubberband::delete_canvas_items()
35 {
36 if (_rect) {
37 GtkObject *temp = _rect;
38 _rect = NULL;
39 gtk_object_destroy(temp);
40 }
41 if (_touchpath) {
42 GtkObject *temp = _touchpath;
43 _touchpath = NULL;
44 gtk_object_destroy(temp);
45 }
46 }
49 void Inkscape::Rubberband::start(SPDesktop *d, NR::Point const &p)
50 {
51 _points.clear();
52 _touchpath_curve->reset();
53 delete_canvas_items();
54 _desktop = d;
55 _start = p;
56 _started = true;
57 _points.push_back(_desktop->d2w(p));
58 _touchpath_curve->moveto(p);
60 sp_canvas_force_full_redraw_after_interruptions(_desktop->canvas, 5);
61 }
63 void Inkscape::Rubberband::stop()
64 {
65 _started = false;
66 _mode = RUBBERBAND_MODE_RECT; // restore the default
68 _points.clear();
69 _touchpath_curve->reset();
71 delete_canvas_items();
73 if (_desktop)
74 sp_canvas_end_forced_full_redraws(_desktop->canvas);
75 }
77 void Inkscape::Rubberband::move(NR::Point const &p)
78 {
79 if (!_started)
80 return;
82 _end = p;
83 _desktop->scroll_to_point(&p);
84 _touchpath_curve->lineto(p);
86 NR::Point next = _desktop->d2w(p);
87 // we want the points to be at most 0.5 screen pixels apart,
88 // so that we don't lose anything small;
89 // if they are farther apart, we interpolate more points
90 if (_points.size() > 0 && NR::L2(next-_points.back()) > 0.5) {
91 NR::Point prev = _points.back();
92 int subdiv = 2 * (int) round(NR::L2(next-prev) + 0.5);
93 for (int i = 1; i <= subdiv; i ++) {
94 _points.push_back(prev + ((double)i/subdiv) * (next - prev));
95 }
96 } else {
97 _points.push_back(next);
98 }
100 if (_mode == RUBBERBAND_MODE_RECT) {
101 if (_rect == NULL) {
102 _rect = static_cast<CtrlRect *>(sp_canvas_item_new(sp_desktop_controls(_desktop), SP_TYPE_CTRLRECT, NULL));
103 }
104 _rect->setRectangle(NR::Rect(_start, _end));
106 sp_canvas_item_show(_rect);
107 if (_touchpath)
108 sp_canvas_item_hide(_touchpath);
110 } else if (_mode == RUBBERBAND_MODE_TOUCHPATH) {
111 if (_touchpath == NULL) {
112 _touchpath = sp_canvas_bpath_new(sp_desktop_sketch(_desktop), NULL);
113 sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(_touchpath), 0xff0000ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
114 sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(_touchpath), 0, SP_WIND_RULE_NONZERO);
115 }
116 sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(_touchpath), _touchpath_curve);
118 sp_canvas_item_show(_touchpath);
119 if (_rect)
120 sp_canvas_item_hide(_rect);
121 }
122 }
124 void Inkscape::Rubberband::setMode(int mode)
125 {
126 _mode = mode;
127 }
129 NR::Maybe<NR::Rect> Inkscape::Rubberband::getRectangle() const
130 {
131 if (!_started) {
132 return NR::Nothing();
133 }
135 return NR::Rect(_start, _end);
136 }
138 Inkscape::Rubberband *Inkscape::Rubberband::get()
139 {
140 if (_instance == NULL) {
141 _instance = new Inkscape::Rubberband;
142 }
144 return _instance;
145 }
147 bool Inkscape::Rubberband::is_started()
148 {
149 return _started;
150 }
152 /*
153 Local Variables:
154 mode:c++
155 c-file-style:"stroustrup"
156 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
157 indent-tabs-mode:nil
158 fill-column:99
159 End:
160 */
161 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :