]>
Commit | Line | Data |
---|---|---|
6a2c1874 RR |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: canvas.cpp | |
3 | // Author: Robert Roebling | |
4 | // Created: XX/XX/XX | |
5 | // Copyright: 2000 (c) Robert Roebling | |
6 | // Licence: wxWindows Licence | |
7 | ///////////////////////////////////////////////////////////////////////////// | |
8 | ||
9 | #ifdef __GNUG__ | |
10 | #pragma implementation "canvas.cpp" | |
11 | #endif | |
12 | ||
13 | // For compilers that support precompilation, includes "wx/wx.h". | |
14 | #include "wx/wxprec.h" | |
15 | ||
16 | #ifdef __BORLANDC__ | |
17 | #pragma hdrstop | |
18 | #endif | |
19 | ||
20 | #include "wx/canvas/canvas.h" | |
21 | ||
22 | #ifdef __WXGTK__ | |
23 | #include <gtk/gtk.h> | |
24 | #include <gdk/gdkrgb.h> | |
25 | #include "wx/gtk/win_gtk.h" | |
26 | #endif | |
27 | ||
1e1af41e RR |
28 | #ifndef wxUSE_FREETYPE |
29 | #define wxUSE_FREETYPE 1 | |
30 | #endif | |
d1f9b206 | 31 | |
1e1af41e RR |
32 | #if wxUSE_FREETYPE |
33 | #include <freetype/freetype.h> | |
d1f9b206 RR |
34 | #endif |
35 | ||
36 | //---------------------------------------------------------------------------- | |
37 | // globals | |
38 | //---------------------------------------------------------------------------- | |
39 | ||
1e1af41e | 40 | #if wxUSE_FREETYPE |
d1f9b206 RR |
41 | FT_Library g_freetypeLibrary; |
42 | #endif | |
6a2c1874 RR |
43 | |
44 | //---------------------------------------------------------------------------- | |
45 | // wxCanvasObject | |
46 | //---------------------------------------------------------------------------- | |
47 | ||
4dbd4ee6 | 48 | wxCanvasObject::wxCanvasObject() |
6a2c1874 RR |
49 | { |
50 | m_owner = NULL; | |
4dbd4ee6 RR |
51 | m_area.x = -1; |
52 | m_area.y = -1; | |
53 | m_area.width = -1; | |
54 | m_area.height = -1; | |
55 | m_isControl = FALSE; | |
56 | m_isVector = FALSE; | |
57 | m_isImage = FALSE; | |
58 | } | |
59 | ||
60 | void wxCanvasObject::SetArea( int x, int y, int width, int height ) | |
61 | { | |
6a2c1874 RR |
62 | m_area.x = x; |
63 | m_area.y = y; | |
64 | m_area.width = width; | |
65 | m_area.height = height; | |
4dbd4ee6 RR |
66 | } |
67 | ||
68 | void wxCanvasObject::SetArea( wxRect rect ) | |
69 | { | |
70 | m_area.x = rect.x; | |
71 | m_area.y = rect.y; | |
72 | m_area.width = rect.width; | |
73 | m_area.height = rect.height; | |
6a2c1874 RR |
74 | } |
75 | ||
76 | void wxCanvasObject::Move( int x, int y ) | |
77 | { | |
78 | int old_x = m_area.x; | |
79 | int old_y = m_area.y; | |
21840a6c | 80 | |
6a2c1874 RR |
81 | m_area.x = x; |
82 | m_area.y = y; | |
dc16900b | 83 | |
6a2c1874 RR |
84 | if (!m_isControl) |
85 | { | |
86 | // TODO: sometimes faster to merge into 1 Update or | |
87 | // to break up into four | |
88 | m_owner->Update( old_x, old_y, m_area.width, m_area.height ); | |
89 | m_owner->Update( x, y, m_area.width, m_area.height ); | |
90 | } | |
91 | } | |
92 | ||
239c1f50 RR |
93 | bool wxCanvasObject::IsHit( int x, int y, int margin ) |
94 | { | |
95 | return ((x >= m_area.x-margin) && | |
96 | (x <= m_area.x+m_area.width+margin) && | |
97 | (y >= m_area.y-margin) && | |
98 | (y <= m_area.y+m_area.height+margin)); | |
99 | } | |
100 | ||
dc16900b KH |
101 | void wxCanvasObject::CaptureMouse() |
102 | { | |
103 | m_owner->SetCaptureMouse( this ); | |
104 | } | |
105 | ||
106 | void wxCanvasObject::ReleaseMouse() | |
107 | { | |
108 | m_owner->SetCaptureMouse( NULL ); | |
109 | } | |
110 | ||
111 | bool wxCanvasObject::IsCapturedMouse() | |
112 | { | |
113 | return m_owner->m_captureMouse==this; | |
114 | } | |
115 | ||
116 | ||
fcbb6b37 | 117 | void wxCanvasObject::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height ) |
6a2c1874 RR |
118 | { |
119 | } | |
120 | ||
4dbd4ee6 | 121 | void wxCanvasObject::Recreate() |
1e1af41e RR |
122 | { |
123 | } | |
124 | ||
125 | void wxCanvasObject::WriteSVG( wxTextOutputStream &stream ) | |
6a2c1874 RR |
126 | { |
127 | } | |
128 | ||
fcbb6b37 KH |
129 | //---------------------------------------------------------------------------- |
130 | // wxCanvasObjectGroup | |
131 | //---------------------------------------------------------------------------- | |
132 | ||
133 | wxCanvasObjectGroup::wxCanvasObjectGroup() | |
134 | { | |
21840a6c RR |
135 | m_validbounds = FALSE; |
136 | } | |
137 | ||
138 | wxCanvasObjectGroup::~wxCanvasObjectGroup() | |
139 | { | |
fcbb6b37 KH |
140 | } |
141 | ||
142 | void wxCanvasObjectGroup::SetOwner(wxCanvas* canvas) | |
143 | { | |
144 | m_owner=canvas; | |
145 | wxNode *node = m_objects.First(); | |
146 | while (node) | |
147 | { | |
148 | wxCanvasObject *obj = (wxCanvasObject*) node->Data(); | |
149 | ||
150 | obj->SetOwner(canvas); | |
151 | ||
152 | node = node->Next(); | |
153 | } | |
154 | } | |
155 | ||
156 | void wxCanvasObjectGroup::ExtendArea(int x, int y) | |
157 | { | |
21840a6c RR |
158 | if (m_validbounds) |
159 | { | |
160 | if (x < m_minx) m_minx = x; | |
161 | if (y < m_miny) m_miny = y; | |
162 | if (x > m_maxx) m_maxx = x; | |
163 | if (y > m_maxy) m_maxy = y; | |
164 | } | |
165 | else | |
166 | { | |
167 | m_validbounds = TRUE; | |
fcbb6b37 | 168 | |
21840a6c RR |
169 | m_minx = x; |
170 | m_miny = y; | |
171 | m_maxx = x; | |
172 | m_maxy = y; | |
173 | } | |
fcbb6b37 KH |
174 | } |
175 | ||
fcbb6b37 KH |
176 | void wxCanvasObjectGroup::DeleteContents( bool flag) |
177 | { | |
178 | m_objects.DeleteContents( flag ); | |
21840a6c | 179 | m_validbounds = FALSE; |
fcbb6b37 KH |
180 | } |
181 | ||
fcbb6b37 KH |
182 | void wxCanvasObjectGroup::Prepend( wxCanvasObject* obj ) |
183 | { | |
184 | m_objects.Insert( obj ); | |
21840a6c | 185 | m_validbounds = FALSE; |
fcbb6b37 KH |
186 | } |
187 | ||
188 | void wxCanvasObjectGroup::Append( wxCanvasObject* obj ) | |
189 | { | |
190 | m_objects.Append( obj ); | |
21840a6c | 191 | m_validbounds = FALSE; |
fcbb6b37 KH |
192 | } |
193 | ||
194 | void wxCanvasObjectGroup::Insert( size_t before, wxCanvasObject* obj ) | |
195 | { | |
196 | m_objects.Insert( before, obj ); | |
21840a6c | 197 | m_validbounds = FALSE; |
fcbb6b37 KH |
198 | } |
199 | ||
200 | void wxCanvasObjectGroup::Remove( wxCanvasObject* obj ) | |
201 | { | |
202 | m_objects.DeleteObject( obj ); | |
21840a6c | 203 | m_validbounds = FALSE; |
fcbb6b37 KH |
204 | } |
205 | ||
206 | void wxCanvasObjectGroup::Recreate() | |
207 | { | |
21840a6c | 208 | m_validbounds = FALSE; |
fcbb6b37 KH |
209 | wxNode *node = m_objects.First(); |
210 | while (node) | |
211 | { | |
212 | wxCanvasObject *obj = (wxCanvasObject*) node->Data(); | |
213 | ||
214 | obj->Recreate(); | |
215 | ExtendArea(obj->GetX(),obj->GetY()); | |
216 | ExtendArea(obj->GetX()+obj->GetWidth(),obj->GetY()+obj->GetHeight()); | |
217 | ||
218 | node = node->Next(); | |
219 | } | |
220 | } | |
221 | ||
222 | void wxCanvasObjectGroup::Render(int xabs, int yabs, int x, int y, int width, int height ) | |
223 | { | |
fcbb6b37 KH |
224 | // cycle through all objects |
225 | wxNode *node = m_objects.First(); | |
226 | while (node) | |
227 | { | |
228 | wxCanvasObject *obj = (wxCanvasObject*) node->Data(); | |
229 | ||
230 | if (!obj->IsControl()) | |
231 | { | |
232 | // If we have 10.000 objects, we will go through | |
233 | // this 10.000 times for each update, so we have | |
234 | // to optimise carefully. | |
235 | int clip_x = xabs + obj->GetX(); | |
236 | int clip_width = obj->GetWidth(); | |
237 | if (clip_x < x) | |
238 | { | |
239 | clip_width -= x-clip_x; | |
240 | clip_x = x; | |
241 | } | |
242 | if (clip_width > 0) | |
243 | { | |
244 | if (clip_x + clip_width > x + width) | |
245 | clip_width = x+width-clip_x; | |
246 | ||
247 | if (clip_width > 0) | |
248 | { | |
249 | int clip_y = yabs + obj->GetY(); | |
250 | int clip_height = obj->GetHeight(); | |
251 | if (clip_y < y) | |
252 | { | |
253 | clip_height -= y-clip_y; | |
254 | clip_y = y; | |
255 | } | |
256 | if (clip_height > 0) | |
257 | { | |
258 | if (clip_y + clip_height > y + height) | |
259 | clip_height = y+height-clip_y; | |
260 | ||
261 | if (clip_height > 0) | |
262 | obj->Render(xabs,yabs, clip_x, clip_y, clip_width, clip_height ); | |
263 | } | |
264 | } | |
265 | } | |
266 | } | |
267 | ||
268 | node = node->Next(); | |
269 | } | |
270 | } | |
271 | ||
272 | void wxCanvasObjectGroup::WriteSVG( wxTextOutputStream &stream ) | |
273 | { | |
274 | } | |
275 | ||
276 | bool wxCanvasObjectGroup::IsHit( int x, int y, int margin ) | |
277 | { | |
278 | wxNode *node = m_objects.Last(); | |
279 | while (node) | |
280 | { | |
281 | wxCanvasObject *obj = (wxCanvasObject*) node->Data(); | |
282 | ||
283 | if (!obj->IsControl()) | |
284 | { | |
285 | if (obj->IsHit(x,y,margin)) | |
286 | { | |
287 | return true; | |
288 | } | |
289 | } | |
290 | node = node->Previous(); | |
291 | } | |
292 | return false; | |
293 | } | |
294 | ||
295 | wxCanvasObject* wxCanvasObjectGroup::IsHitObject( int x, int y, int margin ) | |
296 | { | |
297 | wxCanvasObject *obj=0; | |
298 | wxNode *node = m_objects.Last(); | |
299 | while (node) | |
300 | { | |
301 | obj=(wxCanvasObject*) node->Data(); | |
302 | ||
303 | if (!obj->IsControl()) | |
304 | { | |
305 | if (obj->IsHit(x,y,margin)) | |
306 | { | |
307 | return obj; | |
308 | } | |
309 | } | |
310 | node = node->Previous(); | |
311 | } | |
21840a6c RR |
312 | |
313 | return (wxCanvasObject*) NULL; | |
fcbb6b37 KH |
314 | } |
315 | ||
316 | //---------------------------------------------------------------------------- | |
317 | // wxCanvasObjectGroupRef | |
318 | //---------------------------------------------------------------------------- | |
319 | ||
320 | wxCanvasObjectGroupRef::wxCanvasObjectGroupRef(double x, double y, wxCanvasObjectGroup* group) | |
321 | : wxCanvasObject() | |
322 | { | |
323 | m_x = x; | |
324 | m_y = y; | |
325 | m_validbounds=false; | |
326 | m_group=group; | |
327 | } | |
328 | ||
329 | void wxCanvasObjectGroupRef::SetOwner(wxCanvas* canvas) | |
330 | { | |
331 | m_owner=canvas; | |
332 | m_group->SetOwner(canvas); | |
333 | } | |
334 | ||
335 | void wxCanvasObjectGroupRef::ExtendArea(int x, int y) | |
336 | { | |
337 | if (m_validbounds) | |
338 | { | |
339 | if ( x < m_minx ) m_minx = x; | |
340 | if ( y < m_miny ) m_miny = y; | |
341 | if ( x > m_maxx ) m_maxx = x; | |
342 | if ( y > m_maxy ) m_maxy = y; | |
343 | } | |
344 | else | |
345 | { | |
346 | m_validbounds = true; | |
347 | ||
348 | m_minx = x; | |
349 | m_miny = y; | |
350 | m_maxx = x; | |
351 | m_maxy = y; | |
352 | } | |
353 | ||
354 | } | |
355 | ||
356 | void wxCanvasObjectGroupRef::Recreate() | |
357 | { | |
358 | m_validbounds=false; | |
359 | m_group->Recreate(); | |
360 | ExtendArea(m_group->GetXMin(),m_group->GetYMin()); | |
361 | ExtendArea(m_group->GetXMax(),m_group->GetYMax()); | |
362 | ||
363 | //set the area in pixels relative to the parent | |
364 | SetArea( m_owner->GetDeviceX( m_x + m_minx ), | |
365 | m_owner->GetDeviceY( m_y + m_miny ), | |
366 | m_owner->GetDeviceWidth( m_maxx-m_minx ), | |
367 | m_owner->GetDeviceHeight( m_maxy-m_miny ) ); | |
368 | } | |
369 | ||
370 | void wxCanvasObjectGroupRef::Render(int xabs, int yabs, int x, int y, int width, int height ) | |
371 | { | |
21840a6c RR |
372 | xabs += m_owner->GetDeviceX(GetPosX()); |
373 | yabs += m_owner->GetDeviceY(GetPosY()); | |
fcbb6b37 KH |
374 | |
375 | int clip_x = xabs + m_group->GetXMin(); | |
376 | int clip_width = m_group->GetXMax()-m_group->GetXMin(); | |
377 | if (clip_x < x) | |
378 | { | |
379 | clip_width -= x-clip_x; | |
380 | clip_x = x; | |
381 | } | |
382 | if (clip_width > 0) | |
383 | { | |
384 | if (clip_x + clip_width > x + width) | |
385 | clip_width = x+width-clip_x; | |
386 | ||
387 | if (clip_width > 0) | |
388 | { | |
389 | int clip_y = yabs + m_group->GetYMin(); | |
390 | int clip_height = m_group->GetYMax()-m_group->GetYMin(); | |
391 | if (clip_y < y) | |
392 | { | |
393 | clip_height -= y-clip_y; | |
394 | clip_y = y; | |
395 | } | |
396 | if (clip_height > 0) | |
397 | { | |
398 | if (clip_y + clip_height > y + height) | |
399 | clip_height = y+height-clip_y; | |
400 | ||
401 | if (clip_height > 0) | |
402 | m_group->Render(xabs,yabs, clip_x, clip_y, clip_width, clip_height ); | |
403 | } | |
404 | } | |
405 | } | |
406 | } | |
407 | ||
408 | void wxCanvasObjectGroupRef::WriteSVG( wxTextOutputStream &stream ) | |
409 | { | |
410 | } | |
411 | ||
412 | bool wxCanvasObjectGroupRef::IsHit( int x, int y, int margin ) | |
413 | { | |
414 | return m_group->IsHit(x-GetPosX(),y-GetPosY(),margin); | |
415 | } | |
416 | ||
417 | wxCanvasObject* wxCanvasObjectGroupRef::IsHitObject( int x, int y, int margin ) | |
418 | { | |
419 | return m_group->IsHitObject(x-GetPosX(),y-GetPosY(),margin); | |
420 | } | |
421 | ||
422 | void wxCanvasObjectGroupRef::Move( int x, int y ) | |
423 | { | |
fcbb6b37 KH |
424 | m_x = x; |
425 | m_y = y; | |
426 | ||
427 | if (!m_isControl) | |
428 | { | |
429 | // TODO: sometimes faster to merge into 1 Update or | |
430 | // to break up into four | |
431 | m_owner->Update(m_area.x, m_area.y, m_area.width, m_area.height ); | |
432 | //calculate the new area in pixels relative to the parent | |
433 | SetArea( m_owner->GetDeviceX( m_x + m_minx ), | |
434 | m_owner->GetDeviceY( m_y + m_miny ), | |
435 | m_owner->GetDeviceWidth( m_maxx-m_minx ), | |
436 | m_owner->GetDeviceHeight( m_maxy-m_miny ) ); | |
437 | m_owner->Update( m_area.x, m_area.y, m_area.width, m_area.height ); | |
438 | } | |
439 | } | |
440 | ||
441 | ||
21544859 RR |
442 | //---------------------------------------------------------------------------- |
443 | // wxCanvasRect | |
444 | //---------------------------------------------------------------------------- | |
445 | ||
dc16900b | 446 | wxCanvasRect::wxCanvasRect( double x, double y, double w, double h, |
4dbd4ee6 RR |
447 | unsigned char red, unsigned char green, unsigned char blue ) |
448 | : wxCanvasObject() | |
21544859 | 449 | { |
4dbd4ee6 RR |
450 | m_x = x; |
451 | m_y = y; | |
452 | m_width = w; | |
453 | m_height = h; | |
dc16900b | 454 | |
21544859 RR |
455 | m_red = red; |
456 | m_green = green; | |
457 | m_blue = blue; | |
458 | } | |
459 | ||
4dbd4ee6 RR |
460 | void wxCanvasRect::Recreate() |
461 | { | |
462 | SetArea( m_owner->GetDeviceX( m_x ), | |
463 | m_owner->GetDeviceY( m_y ), | |
464 | m_owner->GetDeviceWidth( m_width ), | |
465 | m_owner->GetDeviceHeight( m_height ) ); | |
466 | } | |
467 | ||
fcbb6b37 | 468 | void wxCanvasRect::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height ) |
21544859 RR |
469 | { |
470 | wxImage *image = m_owner->GetBuffer(); | |
41328253 RR |
471 | int buffer_x = m_owner->GetBufferX(); |
472 | int buffer_y = m_owner->GetBufferY(); | |
fcbb6b37 | 473 | |
41328253 RR |
474 | int start_y = clip_y - buffer_y; |
475 | int end_y = clip_y+clip_height - buffer_y; | |
fcbb6b37 | 476 | |
41328253 RR |
477 | int start_x = clip_x - buffer_x; |
478 | int end_x = clip_x+clip_width - buffer_x; | |
fcbb6b37 | 479 | |
21544859 | 480 | // speed up later |
41328253 RR |
481 | for (int y = start_y; y < end_y; y++) |
482 | for (int x = start_x; x < end_x; x++) | |
21544859 RR |
483 | image->SetRGB( x, y, m_red, m_green, m_blue ); |
484 | } | |
485 | ||
486 | void wxCanvasRect::WriteSVG( wxTextOutputStream &stream ) | |
487 | { | |
488 | } | |
489 | ||
239c1f50 RR |
490 | //---------------------------------------------------------------------------- |
491 | // wxCanvasLine | |
492 | //---------------------------------------------------------------------------- | |
493 | ||
4dbd4ee6 RR |
494 | wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2, |
495 | unsigned char red, unsigned char green, unsigned char blue ) | |
496 | : wxCanvasObject() | |
239c1f50 | 497 | { |
4dbd4ee6 RR |
498 | m_x1 = x1; |
499 | m_y1 = y1; | |
500 | m_x2 = x2; | |
501 | m_y2 = y2; | |
502 | ||
239c1f50 RR |
503 | m_red = red; |
504 | m_green = green; | |
505 | m_blue = blue; | |
506 | } | |
507 | ||
4dbd4ee6 RR |
508 | void wxCanvasLine::Recreate() |
509 | { | |
510 | int x1 = m_owner->GetDeviceX( m_x1 ); | |
511 | int y1 = m_owner->GetDeviceY( m_y1 ); | |
512 | int x2 = m_owner->GetDeviceX( m_x2 ); | |
513 | int y2 = m_owner->GetDeviceY( m_y2 ); | |
514 | if (x1 > x2) | |
515 | { | |
516 | int tmp = x1; | |
517 | x1 = x2; | |
518 | x2 = tmp; | |
519 | } | |
520 | if (y1 > y2) | |
521 | { | |
522 | int tmp = y1; | |
523 | y1 = y2; | |
524 | y2 = tmp; | |
525 | } | |
526 | SetArea( x1, y1, x2-x1+1, y2-y1+1 ); | |
527 | } | |
528 | ||
fcbb6b37 | 529 | void wxCanvasLine::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height ) |
239c1f50 RR |
530 | { |
531 | wxImage *image = m_owner->GetBuffer(); | |
41328253 RR |
532 | int buffer_x = m_owner->GetBufferX(); |
533 | int buffer_y = m_owner->GetBufferY(); | |
fcbb6b37 | 534 | |
239c1f50 RR |
535 | if ((m_area.width == 0) && (m_area.height == 0)) |
536 | { | |
41328253 | 537 | image->SetRGB( m_area.x-buffer_x, m_area.y-buffer_y, m_red, m_green, m_blue ); |
239c1f50 RR |
538 | } |
539 | else | |
540 | { | |
fcbb6b37 KH |
541 | int x1 = xabs + m_owner->GetDeviceX( m_x1 ); |
542 | int y1 = yabs + m_owner->GetDeviceY( m_y1 ); | |
543 | int x2 = xabs + m_owner->GetDeviceX( m_x2 ); | |
544 | int y2 = yabs + m_owner->GetDeviceY( m_y2 ); | |
239c1f50 RR |
545 | |
546 | wxInt32 d, ii, jj, di, ai, si, dj, aj, sj; | |
547 | di = x1 - x2; | |
548 | ai = abs(di) << 1; | |
549 | si = (di < 0)? -1 : 1; | |
550 | dj = y1 - y2; | |
551 | aj = abs(dj) << 1; | |
552 | sj = (dj < 0)? -1 : 1; | |
553 | ||
554 | ii = x2; | |
555 | jj = y2; | |
dc16900b | 556 | |
239c1f50 RR |
557 | if (ai > aj) |
558 | { | |
559 | // iterate over i | |
dc16900b KH |
560 | d = aj - (ai >> 1); |
561 | ||
239c1f50 RR |
562 | while (ii != x1) |
563 | { | |
61b64bd9 RR |
564 | if ((ii >= clip_x) && (ii < clip_x+clip_width) && |
565 | (jj >= clip_y) && (jj < clip_y+clip_height)) | |
239c1f50 | 566 | { |
41328253 | 567 | image->SetRGB( ii-buffer_x, jj-buffer_y, m_red, m_blue, m_green ); |
239c1f50 RR |
568 | } |
569 | if (d >= 0) | |
570 | { | |
571 | jj += sj; | |
dc16900b | 572 | d -= ai; |
239c1f50 RR |
573 | } |
574 | ii += si; | |
575 | d += aj; | |
576 | } | |
577 | } | |
578 | else | |
579 | { | |
580 | // iterate over j | |
581 | d = ai - (aj >> 1); | |
582 | ||
583 | while (jj != y1) | |
584 | { | |
61b64bd9 RR |
585 | if ((ii >= clip_x) && (ii < clip_x+clip_width) && |
586 | (jj >= clip_y) && (jj < clip_y+clip_height)) | |
239c1f50 | 587 | { |
41328253 | 588 | image->SetRGB( ii-buffer_x, jj-buffer_y, m_red, m_blue, m_green ); |
239c1f50 RR |
589 | } |
590 | if (d >= 0) | |
591 | { | |
592 | ii += si; | |
dc16900b | 593 | d -= aj; |
239c1f50 RR |
594 | } |
595 | jj += sj; | |
596 | d += ai; | |
597 | } | |
598 | } | |
599 | } | |
600 | } | |
601 | ||
602 | void wxCanvasLine::WriteSVG( wxTextOutputStream &stream ) | |
603 | { | |
1e1af41e | 604 | // no idea |
239c1f50 RR |
605 | } |
606 | ||
6a2c1874 RR |
607 | //---------------------------------------------------------------------------- |
608 | // wxCanvasImage | |
609 | //---------------------------------------------------------------------------- | |
610 | ||
4dbd4ee6 RR |
611 | wxCanvasImage::wxCanvasImage( const wxImage &image, double x, double y, double w, double h ) |
612 | : wxCanvasObject() | |
6a2c1874 | 613 | { |
4dbd4ee6 RR |
614 | m_x = x; |
615 | m_y = y; | |
616 | m_width = w; | |
617 | m_height = h; | |
dc16900b | 618 | |
6a2c1874 RR |
619 | m_image = image; |
620 | m_isImage = TRUE; | |
621 | } | |
622 | ||
4dbd4ee6 RR |
623 | void wxCanvasImage::Recreate() |
624 | { | |
625 | SetArea( m_owner->GetDeviceX( m_x ), | |
626 | m_owner->GetDeviceY( m_y ), | |
627 | m_owner->GetDeviceWidth( m_width ), | |
628 | m_owner->GetDeviceHeight( m_height ) ); | |
dc16900b | 629 | |
4dbd4ee6 RR |
630 | if ((m_area.width == m_image.GetWidth()) && |
631 | (m_area.width == m_image.GetWidth())) | |
632 | m_tmp = m_image; | |
633 | else | |
634 | m_tmp = m_image.Scale( m_area.width, m_area.height ); | |
635 | } | |
636 | ||
fcbb6b37 | 637 | void wxCanvasImage::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height ) |
6a2c1874 | 638 | { |
41328253 RR |
639 | int buffer_x = m_owner->GetBufferX(); |
640 | int buffer_y = m_owner->GetBufferY(); | |
fcbb6b37 KH |
641 | |
642 | if ((clip_x == xabs + m_area.x) && | |
643 | (clip_y == yabs + m_area.y) && | |
21544859 RR |
644 | (clip_width == m_area.width) && |
645 | (clip_height == m_area.height)) | |
d1f9b206 | 646 | { |
41328253 | 647 | m_owner->GetBuffer()->Paste( m_tmp, clip_x-buffer_x, clip_y-buffer_y ); |
d1f9b206 RR |
648 | } |
649 | else | |
650 | { | |
21544859 | 651 | // local coordinates |
fcbb6b37 KH |
652 | int start_x = clip_x - (xabs + m_area.x); |
653 | int start_y = clip_y - (yabs + m_area.y); | |
dc16900b | 654 | |
21544859 | 655 | wxRect rect( start_x, start_y, clip_width, clip_height ); |
4dbd4ee6 | 656 | wxImage sub_image( m_tmp.GetSubImage( rect ) ); |
41328253 | 657 | m_owner->GetBuffer()->Paste( sub_image, clip_x-buffer_x, clip_y-buffer_y ); |
d1f9b206 | 658 | } |
6a2c1874 RR |
659 | } |
660 | ||
661 | void wxCanvasImage::WriteSVG( wxTextOutputStream &stream ) | |
662 | { | |
663 | // no idea | |
664 | } | |
665 | ||
3b111dbe RR |
666 | //---------------------------------------------------------------------------- |
667 | // wxCanvasCtrl | |
668 | //---------------------------------------------------------------------------- | |
669 | ||
670 | wxCanvasControl::wxCanvasControl( wxWindow *control ) | |
4dbd4ee6 | 671 | : wxCanvasObject() |
3b111dbe | 672 | { |
21544859 | 673 | m_isControl = TRUE; |
3b111dbe | 674 | m_control = control; |
3b111dbe RR |
675 | } |
676 | ||
677 | wxCanvasControl::~wxCanvasControl() | |
678 | { | |
679 | m_control->Destroy(); | |
680 | } | |
681 | ||
4dbd4ee6 | 682 | void wxCanvasControl::Recreate() |
3b111dbe | 683 | { |
4dbd4ee6 RR |
684 | m_control->GetSize( &m_area.width, &m_area.height ); |
685 | m_control->GetPosition( &m_area.x, &m_area.y ); | |
3b111dbe RR |
686 | } |
687 | ||
4dbd4ee6 | 688 | void wxCanvasControl::Move( int x, int y ) |
3b111dbe | 689 | { |
4dbd4ee6 | 690 | m_control->Move( x, y ); |
3b111dbe RR |
691 | } |
692 | ||
d1f9b206 RR |
693 | //---------------------------------------------------------------------------- |
694 | // wxCanvasText | |
695 | //---------------------------------------------------------------------------- | |
696 | ||
697 | class wxFaceData | |
698 | { | |
699 | public: | |
1e1af41e | 700 | #if wxUSE_FREETYPE |
d1f9b206 RR |
701 | FT_Face m_face; |
702 | #else | |
703 | void *m_dummy; | |
dc16900b | 704 | #endif |
d1f9b206 RR |
705 | }; |
706 | ||
4dbd4ee6 RR |
707 | wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxString &fontFile, int size ) |
708 | : wxCanvasObject() | |
d1f9b206 RR |
709 | { |
710 | m_text = text; | |
cb281cfc RR |
711 | m_fontFileName = fontFile; |
712 | m_size = size; | |
dc16900b | 713 | |
cb281cfc | 714 | m_red = 0; |
d1f9b206 RR |
715 | m_green = 0; |
716 | m_blue = 0; | |
dc16900b | 717 | |
4dbd4ee6 | 718 | m_alpha = NULL; |
dc16900b | 719 | |
4dbd4ee6 RR |
720 | m_x = x; |
721 | m_y = y; | |
dc16900b KH |
722 | |
723 | #if wxUSE_FREETYPE | |
d1f9b206 RR |
724 | wxFaceData *data = new wxFaceData; |
725 | m_faceData = data; | |
dc16900b | 726 | |
d1f9b206 | 727 | int error = FT_New_Face( g_freetypeLibrary, |
cb281cfc | 728 | m_fontFileName, |
d1f9b206 RR |
729 | 0, |
730 | &(data->m_face) ); | |
731 | ||
732 | error = FT_Set_Char_Size( data->m_face, | |
733 | 0, | |
cb281cfc RR |
734 | m_size*64, |
735 | 96, // screen dpi | |
d1f9b206 RR |
736 | 96 ); |
737 | #endif | |
738 | } | |
739 | ||
740 | wxCanvasText::~wxCanvasText() | |
741 | { | |
fcbb6b37 | 742 | #if wxUSE_FREETYPE |
d1f9b206 RR |
743 | wxFaceData *data = (wxFaceData*) m_faceData; |
744 | delete data; | |
745 | #endif | |
746 | ||
747 | if (m_alpha) delete [] m_alpha; | |
748 | } | |
749 | ||
750 | void wxCanvasText::SetRGB( unsigned char red, unsigned char green, unsigned char blue ) | |
751 | { | |
752 | m_red = red; | |
753 | m_green = green; | |
754 | m_blue = blue; | |
755 | } | |
756 | ||
757 | void wxCanvasText::SetFlag( int flag ) | |
758 | { | |
759 | m_flag = flag; | |
760 | } | |
761 | ||
fcbb6b37 | 762 | void wxCanvasText::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height ) |
d1f9b206 RR |
763 | { |
764 | if (!m_alpha) return; | |
fcbb6b37 | 765 | |
d1f9b206 | 766 | wxImage *image = m_owner->GetBuffer(); |
41328253 RR |
767 | int buffer_x = m_owner->GetBufferX(); |
768 | int buffer_y = m_owner->GetBufferY(); | |
d1f9b206 | 769 | |
21544859 RR |
770 | // local coordinates |
771 | int start_x = clip_x - m_area.x; | |
772 | int end_x = clip_width + start_x; | |
773 | int start_y = clip_y - m_area.y; | |
774 | int end_y = clip_height + start_y; | |
fcbb6b37 | 775 | |
d1f9b206 RR |
776 | for (int y = start_y; y < end_y; y++) |
777 | for (int x = start_x; x < end_x; x++) | |
778 | { | |
779 | int alpha = m_alpha[y*m_area.width + x]; | |
780 | if (alpha) | |
781 | { | |
41328253 RR |
782 | int image_x = m_area.x+x - buffer_x; |
783 | int image_y = m_area.y+y - buffer_y; | |
cb281cfc | 784 | if (alpha == 255) |
d1f9b206 RR |
785 | { |
786 | image->SetRGB( image_x, image_y, m_red, m_green, m_blue ); | |
787 | continue; | |
788 | } | |
cb281cfc RR |
789 | int red1 = (m_red * alpha) / 255; |
790 | int green1 = (m_green * alpha) / 255; | |
791 | int blue1 = (m_blue * alpha) / 255; | |
dc16900b | 792 | |
cb281cfc | 793 | alpha = 255-alpha; |
d1f9b206 RR |
794 | int red2 = image->GetRed( image_x, image_y ); |
795 | int green2 = image->GetGreen( image_x, image_y ); | |
796 | int blue2 = image->GetBlue( image_x, image_y ); | |
cb281cfc RR |
797 | red2 = (red2 * alpha) / 255; |
798 | green2 = (green2 * alpha) / 255; | |
799 | blue2 = (blue2 * alpha) / 255; | |
fcbb6b37 | 800 | |
d1f9b206 RR |
801 | image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 ); |
802 | } | |
803 | } | |
804 | } | |
805 | ||
806 | void wxCanvasText::WriteSVG( wxTextOutputStream &stream ) | |
807 | { | |
808 | } | |
809 | ||
4dbd4ee6 | 810 | void wxCanvasText::Recreate() |
d1f9b206 | 811 | { |
4dbd4ee6 | 812 | if (m_alpha) delete [] m_alpha; |
dc16900b | 813 | |
4dbd4ee6 RR |
814 | m_area.x = m_owner->GetDeviceX( m_x ); |
815 | m_area.y = m_owner->GetDeviceY( m_y ); | |
dc16900b | 816 | |
4dbd4ee6 RR |
817 | m_area.width = 100; // TODO, calculate length |
818 | m_area.height = m_size; | |
819 | m_alpha = new unsigned char[100*m_size]; | |
820 | memset( m_alpha, 0, m_area.width*m_area.height ); | |
fcbb6b37 KH |
821 | |
822 | #if wxUSE_FREETYPE | |
d1f9b206 RR |
823 | FT_Face face = ((wxFaceData*)m_faceData)->m_face; |
824 | FT_GlyphSlot slot = face->glyph; | |
825 | int pen_x = 0; | |
cb281cfc | 826 | int pen_y = m_size; |
fcbb6b37 | 827 | |
cb281cfc | 828 | for (int n = 0; n < (int)m_text.Len(); n++) |
d1f9b206 RR |
829 | { |
830 | FT_UInt index = FT_Get_Char_Index( face, m_text[n] ); | |
dc16900b | 831 | |
d1f9b206 RR |
832 | int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); |
833 | if (error) continue; | |
fcbb6b37 | 834 | |
cb281cfc | 835 | error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); |
d1f9b206 | 836 | if (error) continue; |
fcbb6b37 | 837 | |
cb281cfc RR |
838 | FT_Bitmap *bitmap = &slot->bitmap; |
839 | unsigned char* buffer = bitmap->buffer; | |
840 | for (int y = 0; y < bitmap->rows; y++) | |
841 | for (int x = 0; x < bitmap->width; x++) | |
842 | { | |
843 | unsigned char alpha = buffer[ y*bitmap->pitch + x ]; | |
844 | if (alpha == 0) continue; | |
dc16900b | 845 | |
cb281cfc RR |
846 | int xx = pen_x + slot->bitmap_left + x; |
847 | int yy = pen_y - slot->bitmap_top + y; | |
848 | m_alpha[ yy * m_area.width + xx ] = alpha; | |
849 | } | |
fcbb6b37 | 850 | |
d1f9b206 RR |
851 | pen_x += slot->advance.x >> 6; |
852 | pen_y += slot->advance.y >> 6; | |
fcbb6b37 | 853 | } |
d1f9b206 RR |
854 | #endif |
855 | } | |
856 | ||
6a2c1874 RR |
857 | //---------------------------------------------------------------------------- |
858 | // wxCanvas | |
859 | //---------------------------------------------------------------------------- | |
860 | ||
861 | IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow) | |
862 | ||
863 | BEGIN_EVENT_TABLE(wxCanvas,wxScrolledWindow) | |
864 | EVT_CHAR( wxCanvas::OnChar ) | |
865 | EVT_PAINT( wxCanvas::OnPaint ) | |
866 | EVT_SIZE( wxCanvas::OnSize ) | |
867 | EVT_IDLE( wxCanvas::OnIdle ) | |
868 | EVT_MOUSE_EVENTS( wxCanvas::OnMouse ) | |
869 | EVT_SET_FOCUS( wxCanvas::OnSetFocus ) | |
870 | EVT_KILL_FOCUS( wxCanvas::OnKillFocus ) | |
61b64bd9 | 871 | EVT_ERASE_BACKGROUND( wxCanvas::OnEraseBackground ) |
6a2c1874 RR |
872 | END_EVENT_TABLE() |
873 | ||
874 | wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id, | |
875 | const wxPoint &position, const wxSize& size, long style ) : | |
876 | wxScrolledWindow( parent, id, position, size, style ) | |
877 | { | |
41328253 RR |
878 | m_bufferX = 0; |
879 | m_bufferY = 0; | |
6a2c1874 | 880 | m_needUpdate = FALSE; |
cb281cfc RR |
881 | m_red = 0; |
882 | m_green = 0; | |
883 | m_blue = 0; | |
239c1f50 | 884 | m_lastMouse = (wxCanvasObject*)NULL; |
4dbd4ee6 | 885 | m_captureMouse = (wxCanvasObject*)NULL; |
41328253 RR |
886 | m_frozen = TRUE; |
887 | m_requestNewBuffer = TRUE; | |
fcbb6b37 KH |
888 | |
889 | //root group always at 0,0 | |
890 | m_root = new wxCanvasObjectGroup(); | |
891 | m_root->DeleteContents( TRUE ); | |
892 | m_root->SetOwner(this); | |
6a2c1874 RR |
893 | } |
894 | ||
895 | wxCanvas::~wxCanvas() | |
896 | { | |
897 | wxNode *node = m_updateRects.First(); | |
898 | while (node) | |
899 | { | |
900 | wxRect *rect = (wxRect*) node->Data(); | |
901 | delete rect; | |
902 | m_updateRects.DeleteNode( node ); | |
903 | node = m_updateRects.First(); | |
904 | } | |
905 | } | |
906 | ||
907 | void wxCanvas::SetArea( int width, int height ) | |
908 | { | |
6a2c1874 RR |
909 | SetScrollbars( 10, 10, width/10, height/10 ); |
910 | } | |
911 | ||
cb281cfc RR |
912 | void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char blue ) |
913 | { | |
914 | m_red = red; | |
915 | m_green = green; | |
916 | m_blue = blue; | |
dc16900b | 917 | |
61b64bd9 RR |
918 | SetBackgroundColour( wxColour( red, green, blue ) ); |
919 | ||
239c1f50 | 920 | if (m_frozen) return; |
dc16900b | 921 | |
cb281cfc | 922 | unsigned char *data = m_buffer.GetData(); |
dc16900b | 923 | |
cb281cfc RR |
924 | for (int y = 0; y < m_buffer.GetHeight(); y++) |
925 | for (int x = 0; x < m_buffer.GetWidth(); x++) | |
926 | { | |
927 | data[0] = red; | |
928 | data++; | |
929 | data[0] = green; | |
930 | data++; | |
931 | data[0] = blue; | |
932 | data++; | |
933 | } | |
934 | } | |
935 | ||
dc16900b | 936 | void wxCanvas::SetCaptureMouse( wxCanvasObject *obj ) |
4dbd4ee6 | 937 | { |
dc16900b KH |
938 | if (obj) |
939 | { | |
940 | wxWindow::CaptureMouse(); | |
941 | m_captureMouse = obj; | |
942 | } | |
943 | else | |
944 | { | |
945 | wxWindow::ReleaseMouse(); | |
946 | m_captureMouse = NULL; | |
947 | } | |
4dbd4ee6 RR |
948 | } |
949 | ||
239c1f50 RR |
950 | void wxCanvas::Freeze() |
951 | { | |
952 | m_frozen = TRUE; | |
953 | } | |
954 | ||
955 | void wxCanvas::Thaw() | |
956 | { | |
957 | wxNode *node = m_updateRects.First(); | |
958 | while (node) | |
959 | { | |
960 | wxRect *rect = (wxRect*) node->Data(); | |
961 | delete rect; | |
962 | m_updateRects.DeleteNode( node ); | |
963 | node = m_updateRects.First(); | |
964 | } | |
dc16900b | 965 | |
239c1f50 | 966 | m_frozen = FALSE; |
dc16900b | 967 | |
41328253 RR |
968 | if (m_buffer.Ok()) |
969 | Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight() ); | |
239c1f50 RR |
970 | } |
971 | ||
41328253 | 972 | void wxCanvas::Update( int x, int y, int width, int height, bool blit ) |
6a2c1874 | 973 | { |
239c1f50 | 974 | if (m_frozen) return; |
fcbb6b37 | 975 | |
21544859 | 976 | // clip to buffer |
41328253 | 977 | if (x < m_bufferX) |
21544859 | 978 | { |
41328253 RR |
979 | width -= m_bufferX-x; |
980 | x = m_bufferX; | |
21544859 RR |
981 | } |
982 | if (width < 0) return; | |
dc16900b | 983 | |
41328253 | 984 | if (y < m_bufferY) |
21544859 | 985 | { |
41328253 RR |
986 | height -= m_bufferY-y; |
987 | y = m_bufferY; | |
21544859 RR |
988 | } |
989 | if (height < 0) return; | |
dc16900b | 990 | |
41328253 | 991 | if (x+width > m_bufferX+m_buffer.GetWidth()) |
21544859 | 992 | { |
41328253 | 993 | width = m_bufferX+m_buffer.GetWidth() - x; |
21544859 RR |
994 | } |
995 | if (width < 0) return; | |
dc16900b | 996 | |
41328253 | 997 | if (y+height > m_bufferY+m_buffer.GetHeight()) |
21544859 | 998 | { |
41328253 | 999 | height = m_bufferY+m_buffer.GetHeight() - y; |
21544859 RR |
1000 | } |
1001 | if (height < 0) return; | |
dc16900b | 1002 | |
21544859 | 1003 | // update is within the buffer |
6a2c1874 | 1004 | m_needUpdate = TRUE; |
dc16900b | 1005 | |
21544859 | 1006 | // has to be blitted to screen later |
41328253 RR |
1007 | if (blit) |
1008 | { | |
1009 | m_updateRects.Append( | |
1010 | (wxObject*) new wxRect( x,y,width,height ) ); | |
1011 | } | |
dc16900b | 1012 | |
21544859 | 1013 | // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b) |
41328253 RR |
1014 | int start_y = y - m_bufferY; |
1015 | int end_y = y+height - m_bufferY; | |
1016 | int start_x = x - m_bufferX; | |
1017 | int end_x = x+width - m_bufferX; | |
1018 | for (int yy = start_y; yy < end_y; yy++) | |
1019 | for (int xx = start_x; xx < end_x; xx++) | |
cb281cfc | 1020 | m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue ); |
6a2c1874 | 1021 | |
fcbb6b37 | 1022 | m_root->Render(0,0, x, y, width, height ); |
dc16900b | 1023 | |
6a2c1874 RR |
1024 | } |
1025 | ||
3b111dbe | 1026 | void wxCanvas::BlitBuffer( wxDC &dc ) |
6a2c1874 | 1027 | { |
6a2c1874 RR |
1028 | wxNode *node = m_updateRects.First(); |
1029 | while (node) | |
1030 | { | |
1031 | wxRect *rect = (wxRect*) node->Data(); | |
6a2c1874 | 1032 | |
41328253 RR |
1033 | wxRect sub_rect( *rect ); |
1034 | sub_rect.x -= m_bufferX; | |
1035 | sub_rect.y -= m_bufferY; | |
fcbb6b37 | 1036 | |
41328253 | 1037 | wxImage sub_image( m_buffer.GetSubImage( sub_rect ) ); |
6a2c1874 RR |
1038 | |
1039 | #ifdef __WXGTK__ | |
dc16900b | 1040 | int bpp = wxDisplayDepth(); |
6a2c1874 RR |
1041 | if (bpp > 8) |
1042 | { | |
1043 | // the init code is doubled in wxImage | |
1044 | static bool s_hasInitialized = FALSE; | |
1045 | ||
1046 | if (!s_hasInitialized) | |
1047 | { | |
1048 | gdk_rgb_init(); | |
1049 | s_hasInitialized = TRUE; | |
1050 | } | |
dc16900b | 1051 | |
6a2c1874 RR |
1052 | gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow)->bin_window, |
1053 | m_wxwindow->style->black_gc, | |
41328253 | 1054 | sub_rect.x, sub_rect.y, |
6a2c1874 RR |
1055 | sub_image.GetWidth(), sub_image.GetHeight(), |
1056 | GDK_RGB_DITHER_NONE, | |
1057 | sub_image.GetData(), | |
1058 | sub_image.GetWidth()*3 ); | |
1059 | } | |
1060 | else | |
1061 | { | |
1062 | wxBitmap bitmap( sub_image.ConvertToBitmap() ); | |
1063 | dc.DrawBitmap( bitmap, rect->x, rect->y ); | |
1064 | } | |
1065 | #endif | |
1066 | ||
1067 | #ifndef __WXGTK__ | |
1068 | wxBitmap bitmap( sub_image.ConvertToBitmap() ); | |
1069 | dc.DrawBitmap( bitmap, rect->x, rect->y ); | |
1070 | #endif | |
dc16900b | 1071 | |
6a2c1874 RR |
1072 | delete rect; |
1073 | m_updateRects.DeleteNode( node ); | |
1074 | node = m_updateRects.First(); | |
1075 | } | |
dc16900b | 1076 | |
3b111dbe RR |
1077 | m_needUpdate = FALSE; |
1078 | } | |
1079 | ||
1080 | void wxCanvas::UpdateNow() | |
1081 | { | |
61b64bd9 RR |
1082 | if (m_frozen) return; |
1083 | ||
3b111dbe | 1084 | if (!m_needUpdate) return; |
dc16900b | 1085 | |
3b111dbe RR |
1086 | wxClientDC dc( this ); |
1087 | PrepareDC( dc ); | |
dc16900b | 1088 | |
3b111dbe | 1089 | BlitBuffer( dc ); |
6a2c1874 RR |
1090 | } |
1091 | ||
4dbd4ee6 RR |
1092 | int wxCanvas::GetDeviceX( double x ) |
1093 | { | |
1094 | return (int) x; | |
1095 | } | |
1096 | ||
1097 | int wxCanvas::GetDeviceY( double y ) | |
1098 | { | |
1099 | return (int) y; | |
1100 | } | |
1101 | ||
1102 | int wxCanvas::GetDeviceWidth( double width ) | |
1103 | { | |
1104 | return (int) width; | |
1105 | } | |
1106 | ||
1107 | int wxCanvas::GetDeviceHeight( double height ) | |
1108 | { | |
1109 | return (int) height; | |
1110 | } | |
1111 | ||
1112 | void wxCanvas::Recreate() | |
1113 | { | |
fcbb6b37 | 1114 | m_root->Recreate(); |
4dbd4ee6 RR |
1115 | } |
1116 | ||
6a2c1874 RR |
1117 | void wxCanvas::Prepend( wxCanvasObject* obj ) |
1118 | { | |
fcbb6b37 KH |
1119 | m_root->Prepend( obj ); |
1120 | obj->SetOwner(this); | |
dc16900b | 1121 | |
fcbb6b37 | 1122 | m_root->Recreate(); |
dc16900b | 1123 | |
6a2c1874 RR |
1124 | if (!obj->IsControl()) |
1125 | Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); | |
1126 | } | |
1127 | ||
1128 | void wxCanvas::Append( wxCanvasObject* obj ) | |
1129 | { | |
fcbb6b37 KH |
1130 | m_root->Append( obj ); |
1131 | obj->SetOwner(this); | |
dc16900b | 1132 | |
fcbb6b37 | 1133 | m_root->Recreate(); |
dc16900b | 1134 | |
6a2c1874 RR |
1135 | if (!obj->IsControl()) |
1136 | Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); | |
1137 | } | |
1138 | ||
1139 | void wxCanvas::Insert( size_t before, wxCanvasObject* obj ) | |
1140 | { | |
fcbb6b37 KH |
1141 | m_root->Insert( before, obj ); |
1142 | obj->SetOwner(this); | |
dc16900b | 1143 | |
fcbb6b37 | 1144 | m_root->Recreate(); |
dc16900b | 1145 | |
6a2c1874 RR |
1146 | if (!obj->IsControl()) |
1147 | Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); | |
1148 | } | |
1149 | ||
1150 | void wxCanvas::Remove( wxCanvasObject* obj ) | |
1151 | { | |
1152 | int x = obj->GetX(); | |
1153 | int y = obj->GetY(); | |
1154 | int w = obj->GetWidth(); | |
1155 | int h = obj->GetHeight(); | |
1156 | bool ic = obj->IsControl(); | |
dc16900b | 1157 | |
fcbb6b37 | 1158 | m_root->Remove( obj ); |
dc16900b | 1159 | |
6a2c1874 RR |
1160 | if (!ic) |
1161 | Update( x, y, w, h ); | |
1162 | } | |
1163 | ||
1164 | void wxCanvas::OnPaint(wxPaintEvent &event) | |
1165 | { | |
6a2c1874 | 1166 | wxPaintDC dc(this); |
3b111dbe | 1167 | PrepareDC( dc ); |
dc16900b | 1168 | |
41328253 | 1169 | if (!m_buffer.Ok()) return; |
fcbb6b37 | 1170 | |
b85cfb6f | 1171 | if (m_frozen) return; |
41328253 | 1172 | |
6a2c1874 RR |
1173 | m_needUpdate = TRUE; |
1174 | ||
1175 | wxRegionIterator it( GetUpdateRegion() ); | |
1176 | while (it) | |
1177 | { | |
1178 | int x = it.GetX(); | |
1179 | int y = it.GetY(); | |
dc16900b | 1180 | |
6a2c1874 RR |
1181 | int w = it.GetWidth(); |
1182 | int h = it.GetHeight(); | |
dc16900b | 1183 | |
21544859 RR |
1184 | if (x+w > m_buffer.GetWidth()) |
1185 | w = m_buffer.GetWidth() - x; | |
1186 | if (y+h > m_buffer.GetHeight()) | |
1187 | h = m_buffer.GetHeight() - y; | |
dc16900b | 1188 | |
21544859 | 1189 | if ((w > 0) && (h > 0)) |
41328253 RR |
1190 | { |
1191 | CalcUnscrolledPosition( x, y, &x, &y ); | |
21544859 | 1192 | m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) ); |
41328253 | 1193 | } |
dc16900b | 1194 | |
6a2c1874 RR |
1195 | it++; |
1196 | } | |
dc16900b | 1197 | |
3b111dbe | 1198 | BlitBuffer( dc ); |
6a2c1874 RR |
1199 | } |
1200 | ||
41328253 RR |
1201 | void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect ) |
1202 | { | |
61b64bd9 RR |
1203 | // If any updates are pending, do them now since they will |
1204 | // expect the previous m_bufferX and m_bufferY values. | |
41328253 RR |
1205 | UpdateNow(); |
1206 | ||
61b64bd9 RR |
1207 | // The buffer always starts at the top left corner of the |
1208 | // client area. Indeed, it is the client area. | |
41328253 RR |
1209 | CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY ); |
1210 | ||
1211 | unsigned char* data = m_buffer.GetData(); | |
fcbb6b37 | 1212 | |
41328253 RR |
1213 | if (dy != 0) |
1214 | { | |
1215 | if (dy > 0) | |
1216 | { | |
1217 | unsigned char *source = data; | |
1218 | unsigned char *dest = data + (dy * m_buffer.GetWidth() * 3); | |
1219 | size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()-dy)); | |
1220 | memmove( dest, source, count ); | |
fcbb6b37 | 1221 | |
61b64bd9 RR |
1222 | // We update the new buffer area, but there is no need to |
1223 | // blit (last param FALSE) since the ensuing paint event will | |
1224 | // do that anyway. | |
41328253 RR |
1225 | Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), dy, FALSE ); |
1226 | } | |
1227 | else | |
1228 | { | |
1229 | unsigned char *dest = data; | |
1230 | unsigned char *source = data + (-dy * m_buffer.GetWidth() * 3); | |
1231 | size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()+dy)); | |
1232 | memmove( dest, source, count ); | |
fcbb6b37 | 1233 | |
61b64bd9 RR |
1234 | // We update the new buffer area, but there is no need to |
1235 | // blit (last param FALSE) since the ensuing paint event will | |
1236 | // do that anyway. | |
41328253 RR |
1237 | Update( m_bufferX, m_bufferY+m_buffer.GetHeight()+dy, m_buffer.GetWidth(), -dy, FALSE ); |
1238 | } | |
1239 | } | |
fcbb6b37 | 1240 | |
41328253 RR |
1241 | if (dx != 0) |
1242 | { | |
61b64bd9 RR |
1243 | if (dx > 0) |
1244 | { | |
1245 | unsigned char *source = data; | |
1246 | for (int y = 0; y < m_buffer.GetHeight(); y++) | |
1247 | { | |
1248 | unsigned char *dest = source + dx*3; | |
1249 | memmove( dest, source, (m_buffer.GetWidth()-dx) * 3 ); | |
1250 | source += m_buffer.GetWidth()*3; | |
1251 | } | |
fcbb6b37 | 1252 | |
61b64bd9 RR |
1253 | // We update the new buffer area, but there is no need to |
1254 | // blit (last param FALSE) since the ensuing paint event will | |
1255 | // do that anyway. | |
1256 | Update( m_bufferX, m_bufferY, dx, m_buffer.GetHeight(), FALSE ); | |
1257 | } | |
1258 | else | |
1259 | { | |
1260 | unsigned char *dest = data; | |
1261 | for (int y = 0; y < m_buffer.GetHeight(); y++) | |
1262 | { | |
1263 | unsigned char *source = dest - dx*3; | |
1264 | memmove( dest, source, (m_buffer.GetWidth()+dx) * 3 ); | |
1265 | dest += m_buffer.GetWidth()*3; | |
1266 | } | |
fcbb6b37 | 1267 | |
61b64bd9 RR |
1268 | // We update the new buffer area, but there is no need to |
1269 | // blit (last param FALSE) since the ensuing paint event will | |
1270 | // do that anyway. | |
1271 | Update( m_bufferX+m_buffer.GetWidth()+dx, m_bufferY, -dx, m_buffer.GetHeight(), FALSE ); | |
1272 | } | |
41328253 RR |
1273 | } |
1274 | ||
1275 | wxWindow::ScrollWindow( dx, dy, rect ); | |
1276 | } | |
1277 | ||
6a2c1874 RR |
1278 | void wxCanvas::OnMouse(wxMouseEvent &event) |
1279 | { | |
239c1f50 RR |
1280 | int x = event.GetX(); |
1281 | int y = event.GetY(); | |
1282 | CalcUnscrolledPosition( x, y, &x, &y ); | |
dc16900b | 1283 | |
239c1f50 RR |
1284 | if (event.GetEventType() == wxEVT_MOTION) |
1285 | { | |
dc16900b | 1286 | if (m_captureMouse) //no matter what go to this one |
239c1f50 | 1287 | { |
dc16900b KH |
1288 | wxMouseEvent child_event( wxEVT_MOTION ); |
1289 | child_event.SetEventObject(m_captureMouse); | |
1290 | child_event.m_x = x - m_captureMouse->GetX(); | |
1291 | child_event.m_y = y - m_captureMouse->GetY(); | |
1292 | child_event.m_leftDown = event.m_leftDown; | |
1293 | child_event.m_rightDown = event.m_rightDown; | |
1294 | child_event.m_middleDown = event.m_middleDown; | |
1295 | child_event.m_controlDown = event.m_controlDown; | |
1296 | child_event.m_shiftDown = event.m_shiftDown; | |
1297 | child_event.m_altDown = event.m_altDown; | |
1298 | child_event.m_metaDown = event.m_metaDown; | |
872f1044 | 1299 | |
dc16900b | 1300 | m_captureMouse->ProcessEvent( child_event ); |
872f1044 | 1301 | return; |
dc16900b KH |
1302 | } |
1303 | else | |
1304 | { | |
fcbb6b37 | 1305 | wxCanvasObject *obj = m_root->IsHitObject(x,y,0); |
dc16900b | 1306 | |
fcbb6b37 KH |
1307 | if (obj && !obj->IsControl()) |
1308 | { | |
1309 | wxMouseEvent child_event( wxEVT_MOTION ); | |
1310 | child_event.SetEventObject( obj ); | |
1311 | child_event.m_x = x - obj->GetX(); | |
1312 | child_event.m_y = y - obj->GetY(); | |
1313 | child_event.m_leftDown = event.m_leftDown; | |
1314 | child_event.m_rightDown = event.m_rightDown; | |
1315 | child_event.m_middleDown = event.m_middleDown; | |
1316 | child_event.m_controlDown = event.m_controlDown; | |
1317 | child_event.m_shiftDown = event.m_shiftDown; | |
1318 | child_event.m_altDown = event.m_altDown; | |
1319 | child_event.m_metaDown = event.m_metaDown; | |
1320 | ||
1321 | if ((obj != m_lastMouse) && (m_lastMouse != NULL)) | |
239c1f50 | 1322 | { |
fcbb6b37 KH |
1323 | child_event.SetEventType( wxEVT_LEAVE_WINDOW ); |
1324 | child_event.SetEventObject( m_lastMouse ); | |
1325 | child_event.m_x = x - m_lastMouse->GetX(); | |
1326 | child_event.m_y = y - m_lastMouse->GetY(); | |
1327 | m_lastMouse->ProcessEvent( child_event ); | |
1328 | ||
1329 | m_lastMouse = obj; | |
1330 | child_event.SetEventType( wxEVT_ENTER_WINDOW ); | |
1331 | child_event.SetEventObject( m_lastMouse ); | |
1332 | child_event.m_x = x - m_lastMouse->GetX(); | |
1333 | child_event.m_y = y - m_lastMouse->GetY(); | |
1334 | m_lastMouse->ProcessEvent( child_event ); | |
1335 | ||
1336 | child_event.SetEventType( wxEVT_MOTION ); | |
1337 | child_event.SetEventObject( obj ); | |
239c1f50 | 1338 | } |
872f1044 | 1339 | |
fcbb6b37 KH |
1340 | obj->ProcessEvent( child_event ); |
1341 | return; | |
239c1f50 | 1342 | } |
239c1f50 RR |
1343 | } |
1344 | if (m_lastMouse) | |
1345 | { | |
1346 | wxMouseEvent child_event( wxEVT_LEAVE_WINDOW ); | |
1347 | child_event.SetEventObject( m_lastMouse ); | |
1e1af41e RR |
1348 | child_event.m_x = x - m_lastMouse->GetX(); |
1349 | child_event.m_y = y - m_lastMouse->GetY(); | |
239c1f50 RR |
1350 | child_event.m_leftDown = event.m_leftDown; |
1351 | child_event.m_rightDown = event.m_rightDown; | |
1352 | child_event.m_middleDown = event.m_middleDown; | |
1353 | child_event.m_controlDown = event.m_controlDown; | |
1354 | child_event.m_shiftDown = event.m_shiftDown; | |
1355 | child_event.m_altDown = event.m_altDown; | |
1356 | child_event.m_metaDown = event.m_metaDown; | |
1357 | m_lastMouse->ProcessEvent( child_event ); | |
dc16900b | 1358 | |
239c1f50 RR |
1359 | m_lastMouse = (wxCanvasObject*) NULL; |
1360 | return; | |
1361 | } | |
1362 | } | |
872f1044 RR |
1363 | else |
1364 | { | |
1365 | if (m_captureMouse) //no matter what go to this one | |
1366 | { | |
1367 | wxMouseEvent child_event( event.GetEventType() ); | |
1368 | child_event.SetEventObject(m_captureMouse); | |
1369 | child_event.m_x = x - m_captureMouse->GetX(); | |
1370 | child_event.m_y = y - m_captureMouse->GetY(); | |
1371 | child_event.m_leftDown = event.m_leftDown; | |
1372 | child_event.m_rightDown = event.m_rightDown; | |
1373 | child_event.m_middleDown = event.m_middleDown; | |
1374 | child_event.m_controlDown = event.m_controlDown; | |
1375 | child_event.m_shiftDown = event.m_shiftDown; | |
1376 | child_event.m_altDown = event.m_altDown; | |
1377 | child_event.m_metaDown = event.m_metaDown; | |
1378 | m_captureMouse->ProcessEvent( child_event ); | |
1379 | } | |
1380 | else | |
1381 | { | |
1382 | wxCanvasObject *obj = m_root->IsHitObject(x,y,0); | |
1383 | ||
1384 | if (obj && !obj->IsControl()) | |
1385 | { | |
1386 | wxMouseEvent child_event( event.GetEventType() ); | |
1387 | child_event.SetEventObject( obj ); | |
1388 | child_event.m_x = x - obj->GetX(); | |
1389 | child_event.m_y = y - obj->GetY(); | |
1390 | child_event.m_leftDown = event.m_leftDown; | |
1391 | child_event.m_rightDown = event.m_rightDown; | |
1392 | child_event.m_middleDown = event.m_middleDown; | |
1393 | child_event.m_controlDown = event.m_controlDown; | |
1394 | child_event.m_shiftDown = event.m_shiftDown; | |
1395 | child_event.m_altDown = event.m_altDown; | |
1396 | child_event.m_metaDown = event.m_metaDown; | |
1397 | ||
1398 | obj->ProcessEvent( child_event ); | |
1399 | return; | |
1400 | } | |
1401 | } | |
1402 | } | |
fcbb6b37 | 1403 | |
239c1f50 | 1404 | event.Skip(); |
6a2c1874 RR |
1405 | } |
1406 | ||
1407 | void wxCanvas::OnSize(wxSizeEvent &event) | |
1408 | { | |
b85cfb6f RR |
1409 | int w,h; |
1410 | GetClientSize( &w, &h ); | |
1411 | m_buffer = wxImage( w, h ); | |
fcbb6b37 | 1412 | |
b85cfb6f | 1413 | CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY ); |
fcbb6b37 | 1414 | |
b85cfb6f RR |
1415 | wxNode *node = m_updateRects.First(); |
1416 | while (node) | |
1417 | { | |
1418 | wxRect *rect = (wxRect*) node->Data(); | |
1419 | delete rect; | |
1420 | m_updateRects.DeleteNode( node ); | |
1421 | node = m_updateRects.First(); | |
1422 | } | |
1423 | ||
1424 | m_frozen = FALSE; | |
1425 | ||
1426 | Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE ); | |
41328253 | 1427 | |
6a2c1874 RR |
1428 | event.Skip(); |
1429 | } | |
1430 | ||
1431 | void wxCanvas::OnIdle(wxIdleEvent &event) | |
1432 | { | |
1433 | UpdateNow(); | |
1434 | event.Skip(); | |
1435 | } | |
1436 | ||
1437 | void wxCanvas::OnSetFocus(wxFocusEvent &event) | |
1438 | { | |
1439 | } | |
1440 | ||
1441 | void wxCanvas::OnKillFocus(wxFocusEvent &event) | |
1442 | { | |
1443 | } | |
1444 | ||
1445 | void wxCanvas::OnChar(wxKeyEvent &event) | |
1446 | { | |
1447 | event.Skip(); | |
1448 | } | |
1449 | ||
61b64bd9 RR |
1450 | void wxCanvas::OnEraseBackground(wxEraseEvent &event) |
1451 | { | |
1452 | } | |
1453 | ||
d1f9b206 RR |
1454 | //-------------------------------------------------------------------- |
1455 | // wxCanvasModule | |
1456 | //-------------------------------------------------------------------- | |
1457 | ||
1458 | class wxCanvasModule : public wxModule | |
1459 | { | |
1460 | public: | |
1461 | virtual bool OnInit(); | |
1462 | virtual void OnExit(); | |
1463 | ||
1464 | private: | |
1465 | DECLARE_DYNAMIC_CLASS(wxCanvasModule) | |
1466 | }; | |
1467 | ||
1468 | IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule) | |
6a2c1874 | 1469 | |
d1f9b206 RR |
1470 | bool wxCanvasModule::OnInit() |
1471 | { | |
1e1af41e | 1472 | #if wxUSE_FREETYPE |
d1f9b206 RR |
1473 | int error = FT_Init_FreeType( &g_freetypeLibrary ); |
1474 | if (error) return FALSE; | |
1475 | #endif | |
1476 | ||
1477 | return TRUE; | |
1478 | } | |
1479 | ||
1480 | void wxCanvasModule::OnExit() | |
1481 | { | |
1e1af41e | 1482 | #if wxUSE_FREETYPE |
cb281cfc | 1483 | FT_Done_FreeType( g_freetypeLibrary ); |
d1f9b206 RR |
1484 | #endif |
1485 | } |