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