1 /**
2 * Yudit Unicode Editor Source File
3 *
4 * GNU Copyright (C) 1997-2006 Gaspar Sinai <gaspar@yudit.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2,
8 * dated June 1991. See file COPYYING for details.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "swidget/SDrawing.h"
21
22 #define SS_LEFT_MARGIN 2
23
24 #define SS_MAX_SEGMENTS 100
25 #define SS_MAX_LINES 100
26
SDrawingListener(void)27 SDrawingListener::SDrawingListener(void)
28 {
29 }
~SDrawingListener()30 SDrawingListener::~SDrawingListener()
31 {
32 }
33
34 /**
35 * A drawing component that lets you make a small
36 * drawing with the mouse.
37 */
SDrawing(void)38 SDrawing::SDrawing (void) : fg (SColor (0.0, 0.0, 0.0, 1.0)),
39 lfg (SColor (0.0, 0.0, 1.0, 1.0))
40 {
41 listener = 0;
42 preferredSize = SDimension (20,20);
43 SDimension d = border.getBorderSize();
44 preferredSize.width += d.width * 2;
45 preferredSize.height += d.height * 2;
46 clip (true);
47 }
48
49 /**
50 * Deletes this drawing. Nothing to do.
51 */
~SDrawing()52 SDrawing::~SDrawing ()
53 {
54 }
55
56 /**
57 * There can be only one drawing listener.
58 */
59 void
setDrawingListener(SDrawingListener * _listener)60 SDrawing::setDrawingListener (SDrawingListener* _listener)
61 {
62 listener = _listener;
63 }
64
65 /**
66 * @return the drawing drawn.
67 */
68 const SLineCurves&
getDrawing()69 SDrawing::getDrawing()
70 {
71 return allLines;
72 }
73
74 /**
75 * Set the overall background. This will effectively be the border's
76 * background.
77 * @param bg is the backgroud.
78 */
79 void
setBackground(const SColor & bg)80 SDrawing::setBackground (const SColor& bg)
81 {
82 border.setBackground (bg);
83 }
84
85 /**
86 * Set the background of the drawing itself.
87 * @param bg is the backgroud.
88 */
89 void
setTextBackground(const SColor & bg)90 SDrawing::setTextBackground (const SColor& bg)
91 {
92 SPanel::setBackground (bg);
93 }
94
95 /**
96 * Set the foreground of the drawing itself.
97 * @param fg is the foreground
98 * @param fgrecent is the foreground of the last line, being drawn
99 */
100 void
setForeground(const SColor & _fg,const SColor & fgrecent)101 SDrawing::setForeground (const SColor& _fg, const SColor& fgrecent)
102 {
103 fg = _fg;
104 lfg = fgrecent;
105 }
106
107 /**
108 * Redraw the Component on a canvas
109 * @param canvas is where we redraw this.
110 */
111 void
redraw(SCanvas * canvas,int x,int y,unsigned int width,unsigned int height)112 SDrawing::redraw (SCanvas *canvas, int x, int y, unsigned int width, unsigned int height)
113 {
114 clip (false);
115 border.redraw (canvas, x, y, width, height);
116 clip (true);
117 for (unsigned int i=0; i<allLines.size(); i++)
118 {
119 redrawInternal (canvas, fg, allLines[i]);
120 }
121 redrawInternal (canvas, lfg, lastLines);
122
123 }
124
125 /**
126 * redraw the whole drawing.
127 * @param fore is the foreground color.
128 * @param lines are the lines.
129 */
130 void
redrawInternal(SCanvas * canvas,const SColor & fore,const SLineCurve & lines)131 SDrawing::redrawInternal (SCanvas* canvas, const SColor& fore,
132 const SLineCurve& lines)
133 {
134 for (unsigned int i=1; i<lines.size(); i++)
135 {
136 SLocation p0 = lines[i-1];
137 SLocation p1 = lines[i];
138 canvas->bitline (fore, p0.x, p0.y, p1.x, p1.y);
139 }
140 }
141
142
143 /**
144 * redraw the whole drawing.
145 * @param fore is the foreground color.
146 * @param lines are the lines.
147 */
148 void
redrawContours(SWindow * canvas,const SColor & fore,const SLineCurve & lines)149 SDrawing::redrawContours (SWindow* canvas, const SColor& fore,
150 const SLineCurve& lines)
151 {
152 if (window->isDoubleBufferEnabled ())
153 {
154 window->redraw (true, 0 , 0, canvas->getWidth(), canvas->getHeight());
155 }
156 else
157 {
158 redrawInternal (canvas, fore, lines);
159 }
160 }
161
162
163 /**
164 * Turn clipping at the border on and off.
165 * @param on is true if we turn on clipping.
166 */
167 void
clip(bool on)168 SDrawing::clip (bool on)
169 {
170 if (!on)
171 {
172 window->removeClippingArea ();
173 return;
174 }
175 window->setClippingArea (
176 (int) border.getBorderSize().width ,
177 (int) border.getBorderSize().height,
178 size.width - 2 * border.getBorderSize().width,
179 size.height - 2 * border.getBorderSize().height);
180 }
181
182 /**
183 * Pass this to the editor. Start a timer to measure
184 * the double click. Get the focus.
185 */
186 void
buttonPressed(SWindow * w,int button,int x,int y)187 SDrawing::buttonPressed (SWindow * w, int button, int x, int y)
188 {
189 if (lastLines.size()==0 && (button == 2 || button == 1))
190 {
191 if (listener != 0) listener->clicked (this, button);
192 return;
193 }
194 if (button != 0) return;
195 lastLines.clear();
196 lastLines.append (SLocation (x,y));
197 }
198
199 /**
200 * A button was released.
201 */
202 void
buttonReleased(SWindow * w,int button,int x,int y)203 SDrawing::buttonReleased (SWindow * w, int button, int x, int y)
204 {
205 if (button != 0) return;
206 /* redraw with different color */
207 if (lastLines.size() > 1)
208 {
209 redrawContours (w, fg, lastLines);
210 allLines.append (lastLines);
211 if (allLines.size() > SS_MAX_LINES) clear();
212 if (listener) listener->strokeChanged(this, allLines.size());
213 }
214 lastLines.clear();
215 }
216
217 void
buttonDragged(SWindow * w,int button,int x,int y)218 SDrawing::buttonDragged (SWindow * w, int button, int x, int y)
219 {
220 if (button != 0) return;
221 lastLines.append (SLocation (x,y));
222 redrawContours (w, lfg, lastLines);
223 }
224
225 /**
226 * Resize the component
227 * @param d is the new size
228 */
229 void
resize(const SDimension & d)230 SDrawing::resize(const SDimension& d)
231 {
232 if (getSize() == d) return;
233 SPanel::resize (d);
234 border.resize (d);
235 SDimension td;
236 if (size.width + 2 * SS_LEFT_MARGIN> border.getBorderSize().width * 2)
237 {
238 td.width = size.width - border.getBorderSize().width * 2 - 2 * SS_LEFT_MARGIN;
239 }
240 if (size.height > border.getBorderSize().height * 2)
241 {
242 td.height = size.height - border.getBorderSize().height * 2;
243 }
244 clip (true);
245 SComponent::resize (d);
246 }
247
248 /**
249 * Move the component
250 * @param l is the new location
251 */
252 void
move(const SLocation & l)253 SDrawing::move(const SLocation& l)
254 {
255 SPanel::move (l);
256 }
257
258 /**
259 * getPreferredSize.
260 * This is calculated form the preferred size of the textView and
261 * adding the border size to it.
262 */
263 const SDimension&
getPreferredSize()264 SDrawing::getPreferredSize()
265 {
266 return preferredSize;
267 }
268
269 /**
270 * Schedule a redraw of the whole drawing.
271 * @param isclear is true if window should be cleared before redraw.
272 */
273 void
redrawClear(bool isclear)274 SDrawing::redrawClear (bool isclear)
275 {
276 int eheight = (int)size.height - (int)2 * border.getBorderSize().height;
277 if (eheight <= 0) return;
278 int ewidth = (int)size.width - (int)2 * border.getBorderSize().width
279 + 2 * SS_LEFT_MARGIN;
280
281 window->redraw (isclear, (int) border.getBorderSize().width ,
282 (int) border.getBorderSize().height, ewidth + 2 * SS_LEFT_MARGIN,
283 eheight);
284 }
285
286 /**
287 * Clear the drawing
288 */
289 void
clear()290 SDrawing::clear()
291 {
292 allLines.clear();
293 lastLines.clear();
294 if (listener) listener->strokeChanged(this, allLines.size());
295 redrawClear (true);
296 }
297
298 void
undo()299 SDrawing::undo ()
300 {
301 if (allLines.size()) allLines.truncate (allLines.size()-1);
302 if (listener) listener->strokeChanged(this, allLines.size());
303 redrawClear (true);
304 }
305