]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/canvas/canvas.cpp
More theme goodies.
[wxWidgets.git] / contrib / src / canvas / canvas.cpp
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
28 #ifndef wxUSE_FREETYPE
29 #define wxUSE_FREETYPE 1
30 #endif
31
32 #if wxUSE_FREETYPE
33 #include <freetype/freetype.h>
34 #endif
35
36 //----------------------------------------------------------------------------
37 // globals
38 //----------------------------------------------------------------------------
39
40 #if wxUSE_FREETYPE
41 FT_Library g_freetypeLibrary;
42 #endif
43
44 //----------------------------------------------------------------------------
45 // wxCanvasObject
46 //----------------------------------------------------------------------------
47
48 wxCanvasObject::wxCanvasObject()
49 {
50 m_owner = NULL;
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 {
62 m_area.x = x;
63 m_area.y = y;
64 m_area.width = width;
65 m_area.height = height;
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;
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;
80
81 m_area.x = x;
82 m_area.y = y;
83
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
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
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
117 void wxCanvasObject::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
118 {
119 }
120
121 void wxCanvasObject::Recreate()
122 {
123 }
124
125 void wxCanvasObject::WriteSVG( wxTextOutputStream &stream )
126 {
127 }
128
129 //----------------------------------------------------------------------------
130 // wxCanvasObjectGroup
131 //----------------------------------------------------------------------------
132
133 wxCanvasObjectGroup::wxCanvasObjectGroup()
134 {
135 m_validbounds = FALSE;
136 }
137
138 wxCanvasObjectGroup::~wxCanvasObjectGroup()
139 {
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(double x, double y)
157 {
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;
168
169 m_minx = x;
170 m_miny = y;
171 m_maxx = x;
172 m_maxy = y;
173 }
174 }
175
176 void wxCanvasObjectGroup::DeleteContents( bool flag)
177 {
178 m_objects.DeleteContents( flag );
179 m_validbounds = FALSE;
180 }
181
182 void wxCanvasObjectGroup::Prepend( wxCanvasObject* obj )
183 {
184 m_objects.Insert( obj );
185 m_validbounds = FALSE;
186 }
187
188 void wxCanvasObjectGroup::Append( wxCanvasObject* obj )
189 {
190 m_objects.Append( obj );
191 m_validbounds = FALSE;
192 }
193
194 void wxCanvasObjectGroup::Insert( size_t before, wxCanvasObject* obj )
195 {
196 m_objects.Insert( before, obj );
197 m_validbounds = FALSE;
198 }
199
200 void wxCanvasObjectGroup::Remove( wxCanvasObject* obj )
201 {
202 m_objects.DeleteObject( obj );
203 m_validbounds = FALSE;
204 }
205
206 void wxCanvasObjectGroup::Recreate()
207 {
208 m_validbounds = FALSE;
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 {
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 }
312
313 return (wxCanvasObject*) NULL;
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(double x, double 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 void wxCanvasObjectGroupRef::Recreate()
356 {
357 m_validbounds = FALSE;
358 m_group->Recreate();
359 ExtendArea(m_group->GetXMin(),m_group->GetYMin());
360 ExtendArea(m_group->GetXMax(),m_group->GetYMax());
361
362 //set the area in pixels relative to the parent
363 SetArea( m_owner->GetDeviceX( m_x + m_minx ),
364 m_owner->GetDeviceY( m_y + m_miny ),
365 m_owner->GetDeviceWidth( m_maxx-m_minx ),
366 m_owner->GetDeviceHeight( m_maxy-m_miny ) );
367 }
368
369 void wxCanvasObjectGroupRef::Render(int xabs, int yabs, int x, int y, int width, int height )
370 {
371 xabs += m_owner->GetDeviceX(m_x);
372 yabs += m_owner->GetDeviceY(m_y);
373
374 int clip_x = xabs + m_group->GetXMin();
375 int clip_width = m_group->GetXMax()-m_group->GetXMin();
376 if (clip_x < x)
377 {
378 clip_width -= x-clip_x;
379 clip_x = x;
380 }
381 if (clip_width > 0)
382 {
383 if (clip_x + clip_width > x + width)
384 clip_width = x+width-clip_x;
385
386 if (clip_width > 0)
387 {
388 int clip_y = yabs + m_group->GetYMin();
389 int clip_height = m_group->GetYMax()-m_group->GetYMin();
390 if (clip_y < y)
391 {
392 clip_height -= y-clip_y;
393 clip_y = y;
394 }
395 if (clip_height > 0)
396 {
397 if (clip_y + clip_height > y + height)
398 clip_height = y+height-clip_y;
399
400 if (clip_height > 0)
401 m_group->Render(xabs,yabs, clip_x, clip_y, clip_width, clip_height );
402 }
403 }
404 }
405 }
406
407 void wxCanvasObjectGroupRef::WriteSVG( wxTextOutputStream &stream )
408 {
409 }
410
411 bool wxCanvasObjectGroupRef::IsHit( int x, int y, int margin )
412 {
413 return m_group->IsHit(x-GetPosX(),y-GetPosY(),margin);
414 }
415
416 wxCanvasObject* wxCanvasObjectGroupRef::IsHitObject( int x, int y, int margin )
417 {
418 return m_group->IsHitObject(x-GetPosX(),y-GetPosY(),margin);
419 }
420
421 void wxCanvasObjectGroupRef::Move( int x, int y )
422 {
423 m_x = x;
424 m_y = y;
425
426 int old_area_x = m_area.x;
427 int old_area_y = m_area.y;
428
429 m_area.x=m_owner->GetDeviceX( m_x + m_minx );
430 m_area.y=m_owner->GetDeviceY( m_y + m_miny );
431
432 int leftu,rightu,bottomu,topu ;
433 leftu = wxMin (m_area.x, old_area_x ) ;
434 rightu = wxMax (old_area_x + m_area.width, m_area.x + m_area.width) ;
435 topu = wxMin (m_area.y,old_area_y) ;
436 bottomu = wxMax (old_area_y + m_area.height, m_area.y + m_area.height) ;
437
438 if ( rightu - leftu < 2*m_area.width && bottomu - topu < 2*m_area.height )
439 {
440 m_owner->Update(leftu,topu,rightu - leftu,bottomu - topu);
441 }
442 else
443 {
444 m_owner->Update(old_area_x, old_area_y, m_area.width, m_area.height );
445 m_owner->Update( m_area.x, m_area.y, m_area.width, m_area.height );
446 }
447 }
448
449 //----------------------------------------------------------------------------
450 // wxCanvasPolyline
451 //----------------------------------------------------------------------------
452
453 wxCanvasPolyline::wxCanvasPolyline( int n, wxPoint2DDouble points[])
454 : wxCanvasObject()
455 {
456 m_n = n;
457 m_points = points;
458 m_pen = *wxBLACK_PEN;
459 }
460
461 wxCanvasPolyline::~wxCanvasPolyline()
462 {
463 delete m_points;
464 }
465
466 void wxCanvasPolyline::ExtendArea(double x, double y)
467 {
468 if (m_validbounds)
469 {
470 if (x < m_minx) m_minx = x;
471 if (y < m_miny) m_miny = y;
472 if (x > m_maxx) m_maxx = x;
473 if (y > m_maxy) m_maxy = y;
474 }
475 else
476 {
477 m_validbounds = TRUE;
478
479 m_minx = x;
480 m_miny = y;
481 m_maxx = x;
482 m_maxy = y;
483 }
484 }
485
486 void wxCanvasPolyline::Recreate()
487 {
488
489 m_validbounds=FALSE;
490 int i;
491 for (i=0; i < m_n;i++)
492 {
493 ExtendArea(m_points[i].m_x,m_points[i].m_y);
494 }
495
496 //include the pen width also
497 ExtendArea(m_minx -m_pen.GetWidth(),m_miny-m_pen.GetWidth());
498 ExtendArea(m_maxx+m_pen.GetWidth()*2,m_maxy+m_pen.GetWidth()*2);
499
500 //set the area in pixels relative to the parent
501 SetArea( m_owner->GetDeviceX(m_minx ),
502 m_owner->GetDeviceY(m_miny ),
503 m_owner->GetDeviceWidth( m_maxx-m_minx ),
504 m_owner->GetDeviceHeight( m_maxy-m_miny ) );
505 }
506
507 void wxCanvasPolyline::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
508 {
509 int buffer_x = m_owner->GetBufferX();
510 int buffer_y = m_owner->GetBufferY();
511
512 int start_y = clip_y - buffer_y;
513 int end_y = clip_y+clip_height - buffer_y;
514
515 int start_x = clip_x - buffer_x;
516 int end_x = clip_x+clip_width - buffer_x;
517
518 #if IMAGE_CANVAS
519 #else
520 wxPoint *cpoints = new wxPoint[m_n];
521 int i;
522 for (i = 0; i < m_n; i++)
523 {
524 cpoints[i].x = m_owner->GetDeviceX(m_points[i].m_x+xabs);
525 cpoints[i].y = m_owner->GetDeviceY(m_points[i].m_y+yabs);
526 }
527 wxMemoryDC *dc = m_owner->GetDC();
528 dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
529 dc->SetPen(m_pen);
530 dc->DrawLines(m_n, cpoints, 0,0);
531 delete [] cpoints;
532 dc->SetPen(wxNullPen);
533 dc->DestroyClippingRegion();
534 #endif
535 }
536
537 void wxCanvasPolyline::WriteSVG( wxTextOutputStream &stream )
538 {
539 }
540
541 //----------------------------------------------------------------------------
542 // wxCanvasPolygon
543 //----------------------------------------------------------------------------
544
545 wxCanvasPolygon::wxCanvasPolygon( int n, wxPoint2DDouble points[])
546 : wxCanvasObject()
547 {
548 m_n = n;
549 m_points = points;
550 m_brush = *wxBLACK_BRUSH;
551 m_pen = *wxTRANSPARENT_PEN;
552 }
553
554 wxCanvasPolygon::~wxCanvasPolygon()
555 {
556 delete m_points;
557 }
558
559 void wxCanvasPolygon::ExtendArea(double x, double y)
560 {
561 if (m_validbounds)
562 {
563 if (x < m_minx) m_minx = x;
564 if (y < m_miny) m_miny = y;
565 if (x > m_maxx) m_maxx = x;
566 if (y > m_maxy) m_maxy = y;
567 }
568 else
569 {
570 m_validbounds = TRUE;
571
572 m_minx = x;
573 m_miny = y;
574 m_maxx = x;
575 m_maxy = y;
576 }
577 }
578
579 void wxCanvasPolygon::Recreate()
580 {
581
582 m_validbounds=FALSE;
583 int i;
584 for (i=0; i < m_n;i++)
585 {
586 ExtendArea(m_points[i].m_x,m_points[i].m_y);
587 }
588
589 //include the pen width also
590 ExtendArea(m_minx -m_pen.GetWidth(),m_miny-m_pen.GetWidth());
591 ExtendArea(m_maxx+m_pen.GetWidth()*2,m_maxy+m_pen.GetWidth()*2);
592
593 //set the area in pixels relative to the parent
594 SetArea( m_owner->GetDeviceX( m_minx ),
595 m_owner->GetDeviceY( m_miny ),
596 m_owner->GetDeviceWidth( m_maxx-m_minx ),
597 m_owner->GetDeviceHeight( m_maxy-m_miny ) );
598 }
599
600 void wxCanvasPolygon::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
601 {
602 int buffer_x = m_owner->GetBufferX();
603 int buffer_y = m_owner->GetBufferY();
604
605 int start_y = clip_y - buffer_y;
606 int end_y = clip_y+clip_height - buffer_y;
607
608 int start_x = clip_x - buffer_x;
609 int end_x = clip_x+clip_width - buffer_x;
610
611 #if IMAGE_CANVAS
612 #else
613 wxPoint *cpoints = new wxPoint[m_n];
614 int i;
615 for (i = 0; i < m_n; i++)
616 {
617 cpoints[i].x = m_owner->GetDeviceX(m_points[i].m_x+xabs);
618 cpoints[i].y = m_owner->GetDeviceY(m_points[i].m_y+yabs);
619 }
620 wxMemoryDC *dc = m_owner->GetDC();
621 dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
622 dc->SetBrush(m_brush);
623 dc->SetPen(m_pen);
624 dc->DrawPolygon(m_n, cpoints, 0,0,wxWINDING_RULE);
625 delete [] cpoints;
626 dc->SetBrush(wxNullBrush);
627 dc->SetPen(wxNullPen);
628 dc->DestroyClippingRegion();
629 #endif
630 }
631
632 void wxCanvasPolygon::WriteSVG( wxTextOutputStream &stream )
633 {
634 }
635
636
637
638 //----------------------------------------------------------------------------
639 // wxCanvasRect
640 //----------------------------------------------------------------------------
641
642 wxCanvasRect::wxCanvasRect( double x, double y, double w, double h )
643 : wxCanvasObject()
644 {
645 m_x = x;
646 m_y = y;
647 m_width = w;
648 m_height = h;
649
650 m_brush = *wxBLACK_BRUSH;
651 m_pen = *wxTRANSPARENT_PEN;
652 }
653
654 void wxCanvasRect::Recreate()
655 {
656 SetArea( m_owner->GetDeviceX( m_x ),
657 m_owner->GetDeviceY( m_y ),
658 m_owner->GetDeviceWidth( m_width ),
659 m_owner->GetDeviceHeight( m_height ) );
660 }
661
662 void wxCanvasRect::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
663 {
664 int buffer_x = m_owner->GetBufferX();
665 int buffer_y = m_owner->GetBufferY();
666
667 #if IMAGE_CANVAS
668 wxImage *image = m_owner->GetBuffer();
669
670 int start_y = clip_y - buffer_y;
671 int end_y = clip_y+clip_height - buffer_y;
672
673 int start_x = clip_x - buffer_x;
674 int end_x = clip_x+clip_width - buffer_x;
675
676 // speed up later
677 for (int y = start_y; y < end_y; y++)
678 for (int x = start_x; x < end_x; x++)
679 image->SetRGB( x, y, m_red, m_green, m_blue );
680 #else
681 wxMemoryDC *dc = m_owner->GetDC();
682 dc->SetPen( m_pen );
683 dc->SetBrush( m_brush );
684 dc->DrawRectangle( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height );
685 #endif
686 }
687
688 void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
689 {
690 }
691
692 //----------------------------------------------------------------------------
693 // wxCanvasLine
694 //----------------------------------------------------------------------------
695
696 wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2 )
697 : wxCanvasObject()
698 {
699 m_x1 = x1;
700 m_y1 = y1;
701 m_x2 = x2;
702 m_y2 = y2;
703
704 m_pen = *wxBLACK_PEN;
705 }
706
707 void wxCanvasLine::Recreate()
708 {
709 int x1 = m_owner->GetDeviceX( m_x1 );
710 int y1 = m_owner->GetDeviceY( m_y1 );
711 int x2 = m_owner->GetDeviceX( m_x2 );
712 int y2 = m_owner->GetDeviceY( m_y2 );
713 if (x1 > x2)
714 {
715 int tmp = x1;
716 x1 = x2;
717 x2 = tmp;
718 }
719 if (y1 > y2)
720 {
721 int tmp = y1;
722 y1 = y2;
723 y2 = tmp;
724 }
725 SetArea( x1, y1, x2-x1+1, y2-y1+1 );
726 }
727
728 void wxCanvasLine::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
729 {
730 int buffer_x = m_owner->GetBufferX();
731 int buffer_y = m_owner->GetBufferY();
732
733 int x1 = xabs + m_owner->GetDeviceX( m_x1 );
734 int y1 = yabs + m_owner->GetDeviceY( m_y1 );
735 int x2 = xabs + m_owner->GetDeviceX( m_x2 );
736 int y2 = yabs + m_owner->GetDeviceY( m_y2 );
737
738 #if IMAGE_CANVAS
739 wxImage *image = m_owner->GetBuffer();
740 if ((m_area.width == 0) && (m_area.height == 0))
741 {
742 image->SetRGB( m_area.x-buffer_x, m_area.y-buffer_y, m_red, m_green, m_blue );
743 }
744 else
745 {
746 wxInt32 d, ii, jj, di, ai, si, dj, aj, sj;
747 di = x1 - x2;
748 ai = abs(di) << 1;
749 si = (di < 0)? -1 : 1;
750 dj = y1 - y2;
751 aj = abs(dj) << 1;
752 sj = (dj < 0)? -1 : 1;
753
754 ii = x2;
755 jj = y2;
756
757 if (ai > aj)
758 {
759 // iterate over i
760 d = aj - (ai >> 1);
761
762 while (ii != x1)
763 {
764 if ((ii >= clip_x) && (ii < clip_x+clip_width) &&
765 (jj >= clip_y) && (jj < clip_y+clip_height))
766 {
767 image->SetRGB( ii-buffer_x, jj-buffer_y, m_red, m_blue, m_green );
768 }
769 if (d >= 0)
770 {
771 jj += sj;
772 d -= ai;
773 }
774 ii += si;
775 d += aj;
776 }
777 }
778 else
779 {
780 // iterate over j
781 d = ai - (aj >> 1);
782
783 while (jj != y1)
784 {
785 if ((ii >= clip_x) && (ii < clip_x+clip_width) &&
786 (jj >= clip_y) && (jj < clip_y+clip_height))
787 {
788 image->SetRGB( ii-buffer_x, jj-buffer_y, m_red, m_blue, m_green );
789 }
790 if (d >= 0)
791 {
792 ii += si;
793 d -= aj;
794 }
795 jj += sj;
796 d += ai;
797 }
798 }
799 }
800 #else
801 wxMemoryDC *dc = m_owner->GetDC();
802 dc->SetClippingRegion( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height );
803 dc->SetPen( m_pen );
804 dc->DrawLine( x1-buffer_x, y1-buffer_y, x2-buffer_x, y2-buffer_y );
805
806 dc->DestroyClippingRegion();
807 #endif
808 }
809
810 void wxCanvasLine::WriteSVG( wxTextOutputStream &stream )
811 {
812 // no idea
813 }
814
815 //----------------------------------------------------------------------------
816 // wxCanvasImage
817 //----------------------------------------------------------------------------
818
819 wxCanvasImage::wxCanvasImage( const wxImage &image, double x, double y, double w, double h )
820 : wxCanvasObject()
821 {
822 m_x = x;
823 m_y = y;
824 m_width = w;
825 m_height = h;
826
827 m_image = image;
828 m_isImage = TRUE;
829 }
830
831 void wxCanvasImage::Recreate()
832 {
833 SetArea( m_owner->GetDeviceX( m_x ),
834 m_owner->GetDeviceY( m_y ),
835 m_owner->GetDeviceWidth( m_width ),
836 m_owner->GetDeviceHeight( m_height ) );
837
838 #if IMAGE_CANVAS
839 if ((m_area.width == m_image.GetWidth()) &&
840 (m_area.width == m_image.GetWidth()))
841 {
842 m_tmp = m_image;
843 }
844 else
845 {
846 m_tmp = m_image.Scale( m_area.width, m_area.height );
847 }
848 #else
849 if ((m_area.width == m_image.GetWidth()) &&
850 (m_area.width == m_image.GetWidth()))
851 {
852 m_tmp = m_image.ConvertToBitmap();
853 }
854 else
855 {
856 wxImage tmp( m_image.Scale( m_area.width, m_area.height ) );
857 m_tmp = tmp.ConvertToBitmap();
858 }
859 #endif
860 }
861
862 void wxCanvasImage::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
863 {
864 int buffer_x = m_owner->GetBufferX();
865 int buffer_y = m_owner->GetBufferY();
866
867 #if IMAGE_CANVAS
868 if ((clip_x == xabs + m_area.x) &&
869 (clip_y == yabs + m_area.y) &&
870 (clip_width == m_area.width) &&
871 (clip_height == m_area.height))
872 {
873 m_owner->GetBuffer()->Paste( m_tmp, clip_x-buffer_x, clip_y-buffer_y );
874 }
875 else
876 {
877 // local coordinates
878 int start_x = clip_x - (xabs + m_area.x);
879 int start_y = clip_y - (yabs + m_area.y);
880
881 wxRect rect( start_x, start_y, clip_width, clip_height );
882 wxImage sub_image( m_tmp.GetSubImage( rect ) );
883 m_owner->GetBuffer()->Paste( sub_image, clip_x-buffer_x, clip_y-buffer_y );
884 }
885 #else
886 wxMemoryDC *dc = m_owner->GetDC();
887
888 if ((clip_x == xabs + m_area.x) &&
889 (clip_y == yabs + m_area.y) &&
890 (clip_width == m_area.width) &&
891 (clip_height == m_area.height))
892 {
893 dc->DrawBitmap( m_tmp, clip_x-buffer_x, clip_y-buffer_y, TRUE );
894 }
895 else
896 {
897 // local coordinates
898 int start_x = clip_x - (xabs + m_area.x);
899 int start_y = clip_y - (yabs + m_area.y);
900
901 // Clipping region faster ?
902 wxRect rect( start_x, start_y, clip_width, clip_height );
903 wxBitmap sub_bitmap( m_tmp.GetSubBitmap( rect ) );
904 dc->DrawBitmap( sub_bitmap, clip_x-buffer_x, clip_y-buffer_y, TRUE );
905 }
906 #endif
907 }
908
909 void wxCanvasImage::WriteSVG( wxTextOutputStream &stream )
910 {
911 // no idea
912 }
913
914 //----------------------------------------------------------------------------
915 // wxCanvasCtrl
916 //----------------------------------------------------------------------------
917
918 wxCanvasControl::wxCanvasControl( wxWindow *control )
919 : wxCanvasObject()
920 {
921 m_isControl = TRUE;
922 m_control = control;
923 }
924
925 wxCanvasControl::~wxCanvasControl()
926 {
927 m_control->Destroy();
928 }
929
930 void wxCanvasControl::Recreate()
931 {
932 m_control->GetSize( &m_area.width, &m_area.height );
933 m_control->GetPosition( &m_area.x, &m_area.y );
934 }
935
936 void wxCanvasControl::Move( int x, int y )
937 {
938 m_control->Move( x, y );
939 }
940
941 //----------------------------------------------------------------------------
942 // wxCanvasText
943 //----------------------------------------------------------------------------
944
945 class wxFaceData
946 {
947 public:
948 #if wxUSE_FREETYPE
949 FT_Face m_face;
950 #else
951 void *m_dummy;
952 #endif
953 };
954
955 wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxString &fontFile, int size )
956 : wxCanvasObject()
957 {
958 m_text = text;
959 m_fontFileName = fontFile;
960 m_size = size;
961
962 m_red = 0;
963 m_green = 0;
964 m_blue = 0;
965
966 m_alpha = NULL;
967
968 m_x = x;
969 m_y = y;
970
971 #if wxUSE_FREETYPE
972 wxFaceData *data = new wxFaceData;
973 m_faceData = data;
974
975 int error = FT_New_Face( g_freetypeLibrary,
976 m_fontFileName,
977 0,
978 &(data->m_face) );
979
980 error = FT_Set_Char_Size( data->m_face,
981 0,
982 m_size*64,
983 96, // screen dpi
984 96 );
985 #endif
986 }
987
988 wxCanvasText::~wxCanvasText()
989 {
990 #if wxUSE_FREETYPE
991 wxFaceData *data = (wxFaceData*) m_faceData;
992 delete data;
993 #endif
994
995 if (m_alpha) delete [] m_alpha;
996 }
997
998 void wxCanvasText::SetRGB( unsigned char red, unsigned char green, unsigned char blue )
999 {
1000 m_red = red;
1001 m_green = green;
1002 m_blue = blue;
1003 }
1004
1005 void wxCanvasText::SetFlag( int flag )
1006 {
1007 m_flag = flag;
1008 }
1009
1010 void wxCanvasText::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
1011 {
1012 if (!m_alpha) return;
1013
1014 #if IMAGE_CANVAS
1015 wxImage *image = m_owner->GetBuffer();
1016 int buffer_x = m_owner->GetBufferX();
1017 int buffer_y = m_owner->GetBufferY();
1018
1019 // local coordinates
1020 int start_x = clip_x - m_area.x;
1021 int end_x = clip_width + start_x;
1022 int start_y = clip_y - m_area.y;
1023 int end_y = clip_height + start_y;
1024
1025 for (int y = start_y; y < end_y; y++)
1026 for (int x = start_x; x < end_x; x++)
1027 {
1028 int alpha = m_alpha[y*m_area.width + x];
1029 if (alpha)
1030 {
1031 int image_x = m_area.x+x - buffer_x;
1032 int image_y = m_area.y+y - buffer_y;
1033 if (alpha == 255)
1034 {
1035 image->SetRGB( image_x, image_y, m_red, m_green, m_blue );
1036 continue;
1037 }
1038 int red1 = (m_red * alpha) / 255;
1039 int green1 = (m_green * alpha) / 255;
1040 int blue1 = (m_blue * alpha) / 255;
1041
1042 alpha = 255-alpha;
1043 int red2 = image->GetRed( image_x, image_y );
1044 int green2 = image->GetGreen( image_x, image_y );
1045 int blue2 = image->GetBlue( image_x, image_y );
1046 red2 = (red2 * alpha) / 255;
1047 green2 = (green2 * alpha) / 255;
1048 blue2 = (blue2 * alpha) / 255;
1049
1050 image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
1051 }
1052 }
1053 #endif
1054 }
1055
1056 void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
1057 {
1058 }
1059
1060 void wxCanvasText::Recreate()
1061 {
1062 if (m_alpha) delete [] m_alpha;
1063
1064 m_area.x = m_owner->GetDeviceX( m_x );
1065 m_area.y = m_owner->GetDeviceY( m_y );
1066
1067 m_area.width = 100; // TODO, calculate length
1068 m_area.height = m_size;
1069 m_alpha = new unsigned char[100*m_size];
1070 memset( m_alpha, 0, m_area.width*m_area.height );
1071
1072 #if wxUSE_FREETYPE
1073 FT_Face face = ((wxFaceData*)m_faceData)->m_face;
1074 FT_GlyphSlot slot = face->glyph;
1075 int pen_x = 0;
1076 int pen_y = m_size;
1077
1078 for (int n = 0; n < (int)m_text.Len(); n++)
1079 {
1080 FT_UInt index = FT_Get_Char_Index( face, m_text[n] );
1081
1082 int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
1083 if (error) continue;
1084
1085 error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
1086 if (error) continue;
1087
1088 FT_Bitmap *bitmap = &slot->bitmap;
1089 unsigned char* buffer = bitmap->buffer;
1090 for (int y = 0; y < bitmap->rows; y++)
1091 for (int x = 0; x < bitmap->width; x++)
1092 {
1093 unsigned char alpha = buffer[ y*bitmap->pitch + x ];
1094 if (alpha == 0) continue;
1095
1096 int xx = pen_x + slot->bitmap_left + x;
1097 int yy = pen_y - slot->bitmap_top + y;
1098 m_alpha[ yy * m_area.width + xx ] = alpha;
1099 }
1100
1101 pen_x += slot->advance.x >> 6;
1102 pen_y += slot->advance.y >> 6;
1103 }
1104 #endif
1105 }
1106
1107 //----------------------------------------------------------------------------
1108 // wxCanvas
1109 //----------------------------------------------------------------------------
1110
1111 IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow)
1112
1113 BEGIN_EVENT_TABLE(wxCanvas,wxScrolledWindow)
1114 EVT_CHAR( wxCanvas::OnChar )
1115 EVT_PAINT( wxCanvas::OnPaint )
1116 EVT_SIZE( wxCanvas::OnSize )
1117 EVT_IDLE( wxCanvas::OnIdle )
1118 EVT_MOUSE_EVENTS( wxCanvas::OnMouse )
1119 EVT_SET_FOCUS( wxCanvas::OnSetFocus )
1120 EVT_KILL_FOCUS( wxCanvas::OnKillFocus )
1121 EVT_ERASE_BACKGROUND( wxCanvas::OnEraseBackground )
1122 END_EVENT_TABLE()
1123
1124 wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
1125 const wxPoint &position, const wxSize& size, long style ) :
1126 wxScrolledWindow( parent, id, position, size, style )
1127 {
1128 m_bufferX = 0;
1129 m_bufferY = 0;
1130 m_needUpdate = FALSE;
1131 m_red = 0;
1132 m_green = 0;
1133 m_blue = 0;
1134 m_lastMouse = (wxCanvasObject*)NULL;
1135 m_captureMouse = (wxCanvasObject*)NULL;
1136 m_frozen = TRUE;
1137 m_oldDeviceX = 0;
1138 m_oldDeviceY = 0;
1139
1140 //root group always at 0,0
1141 m_root = new wxCanvasObjectGroup();
1142 m_root->DeleteContents( TRUE );
1143 m_root->SetOwner(this);
1144 }
1145
1146 wxCanvas::~wxCanvas()
1147 {
1148 wxNode *node = m_updateRects.First();
1149 while (node)
1150 {
1151 wxRect *rect = (wxRect*) node->Data();
1152 delete rect;
1153 m_updateRects.DeleteNode( node );
1154 node = m_updateRects.First();
1155 }
1156 }
1157
1158 void wxCanvas::SetArea( int width, int height )
1159 {
1160 SetScrollbars( 10, 10, width/10, height/10 );
1161 }
1162
1163 void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char blue )
1164 {
1165 m_red = red;
1166 m_green = green;
1167 m_blue = blue;
1168
1169 SetBackgroundColour( wxColour( red, green, blue ) );
1170
1171 if (m_frozen) return;
1172
1173 #if IMAGE_CANVAS
1174 unsigned char *data = m_buffer.GetData();
1175
1176 for (int y = 0; y < m_buffer.GetHeight(); y++)
1177 for (int x = 0; x < m_buffer.GetWidth(); x++)
1178 {
1179 data[0] = red;
1180 data++;
1181 data[0] = green;
1182 data++;
1183 data[0] = blue;
1184 data++;
1185 }
1186 #else
1187 wxMemoryDC dc;
1188 dc.SelectObject( m_buffer );
1189 dc.SetPen( *wxTRANSPARENT_PEN );
1190 wxBrush brush( wxColour( red,green,blue), wxSOLID );
1191 dc.SetBrush( brush );
1192 dc.DrawRectangle( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() );
1193 dc.SelectObject( wxNullBitmap );
1194 #endif
1195 }
1196
1197 void wxCanvas::SetCaptureMouse( wxCanvasObject *obj )
1198 {
1199 if (obj)
1200 {
1201 wxWindow::CaptureMouse();
1202 m_captureMouse = obj;
1203 }
1204 else
1205 {
1206 wxWindow::ReleaseMouse();
1207 m_captureMouse = NULL;
1208 }
1209 }
1210
1211 void wxCanvas::Freeze()
1212 {
1213 m_frozen = TRUE;
1214 }
1215
1216 void wxCanvas::Thaw()
1217 {
1218 wxNode *node = m_updateRects.First();
1219 while (node)
1220 {
1221 wxRect *rect = (wxRect*) node->Data();
1222 delete rect;
1223 m_updateRects.DeleteNode( node );
1224 node = m_updateRects.First();
1225 }
1226
1227 m_frozen = FALSE;
1228
1229 if (m_buffer.Ok())
1230 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight() );
1231 }
1232
1233 void wxCanvas::Update( int x, int y, int width, int height, bool blit )
1234 {
1235 CalcScrolledPosition( 0, 0, &m_oldDeviceX, &m_oldDeviceY );
1236
1237 if (m_frozen) return;
1238
1239 // clip to buffer
1240 if (x < m_bufferX)
1241 {
1242 width -= m_bufferX-x;
1243 x = m_bufferX;
1244 }
1245 if (width <= 0) return;
1246
1247 if (y < m_bufferY)
1248 {
1249 height -= m_bufferY-y;
1250 y = m_bufferY;
1251 }
1252 if (height <= 0) return;
1253
1254 if (x+width > m_bufferX+m_buffer.GetWidth())
1255 {
1256 width = m_bufferX+m_buffer.GetWidth() - x;
1257 }
1258 if (width <= 0) return;
1259
1260 if (y+height > m_bufferY+m_buffer.GetHeight())
1261 {
1262 height = m_bufferY+m_buffer.GetHeight() - y;
1263 }
1264 if (height <= 0) return;
1265
1266 // update is within the buffer
1267 m_needUpdate = TRUE;
1268
1269 // has to be blitted to screen later
1270 if (blit)
1271 {
1272 m_updateRects.Append(
1273 (wxObject*) new wxRect( x,y,width,height ) );
1274 }
1275
1276 #if IMAGE_CANVAS
1277 // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b)
1278 int start_y = y - m_bufferY;
1279 int end_y = y+height - m_bufferY;
1280 int start_x = x - m_bufferX;
1281 int end_x = x+width - m_bufferX;
1282 for (int yy = start_y; yy < end_y; yy++)
1283 for (int xx = start_x; xx < end_x; xx++)
1284 m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue );
1285
1286 m_root->Render(0,0, x, y, width, height );
1287 #else
1288 wxMemoryDC dc;
1289 dc.SelectObject( m_buffer );
1290 dc.SetPen( *wxTRANSPARENT_PEN );
1291 wxBrush brush( wxColour( m_red,m_green,m_blue), wxSOLID );
1292 dc.SetBrush( brush );
1293 dc.DrawRectangle( x-m_bufferX, y-m_bufferY, width, height );
1294
1295 m_renderDC = &dc;
1296 m_root->Render(0,0, x, y, width, height );
1297
1298 dc.SelectObject( wxNullBitmap );
1299 #endif
1300 }
1301
1302 void wxCanvas::BlitBuffer( wxDC &dc )
1303 {
1304 wxNode *node = m_updateRects.First();
1305 while (node)
1306 {
1307 wxRect *rect = (wxRect*) node->Data();
1308
1309 wxRect sub_rect( *rect );
1310 sub_rect.x -= m_bufferX;
1311 sub_rect.y -= m_bufferY;
1312
1313 #if IMAGE_CANVAS
1314
1315 wxImage sub_image( m_buffer.GetSubImage( sub_rect ) );
1316 #ifdef __WXGTK__
1317 int bpp = wxDisplayDepth();
1318 if (bpp > 8)
1319 {
1320 // the init code is doubled in wxImage
1321 static bool s_hasInitialized = FALSE;
1322
1323 if (!s_hasInitialized)
1324 {
1325 gdk_rgb_init();
1326 s_hasInitialized = TRUE;
1327 }
1328
1329 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow)->bin_window,
1330 m_wxwindow->style->black_gc,
1331 sub_rect.x, sub_rect.y,
1332 sub_image.GetWidth(), sub_image.GetHeight(),
1333 GDK_RGB_DITHER_NONE,
1334 sub_image.GetData(),
1335 sub_image.GetWidth()*3 );
1336 }
1337 else
1338 {
1339 wxBitmap bitmap( sub_image.ConvertToBitmap() );
1340 dc.DrawBitmap( bitmap, rect->x, rect->y );
1341 }
1342 #else
1343 wxBitmap bitmap( sub_image.ConvertToBitmap() );
1344 dc.DrawBitmap( bitmap, rect->x, rect->y );
1345 #endif
1346
1347 #else // IMAGE_CANVAS
1348
1349 // Maybe clipping use SetClipping() is faster than
1350 // getting the subrect first and drawing it then?
1351 wxBitmap sub_bitmap( m_buffer.GetSubBitmap( sub_rect ) );
1352 dc.DrawBitmap( sub_bitmap, rect->x, rect->y );
1353
1354 #endif
1355 delete rect;
1356 m_updateRects.DeleteNode( node );
1357 node = m_updateRects.First();
1358 }
1359
1360 m_needUpdate = FALSE;
1361 }
1362
1363 void wxCanvas::UpdateNow()
1364 {
1365 if (m_frozen) return;
1366
1367 if (!m_needUpdate) return;
1368
1369 wxClientDC dc( this );
1370 PrepareDC( dc );
1371
1372 BlitBuffer( dc );
1373 }
1374
1375 int wxCanvas::GetDeviceX( double x )
1376 {
1377 return (int) x;
1378 }
1379
1380 int wxCanvas::GetDeviceY( double y )
1381 {
1382 return (int) y;
1383 }
1384
1385 int wxCanvas::GetDeviceWidth( double width )
1386 {
1387 return (int) width;
1388 }
1389
1390 int wxCanvas::GetDeviceHeight( double height )
1391 {
1392 return (int) height;
1393 }
1394
1395 void wxCanvas::Recreate()
1396 {
1397 m_root->Recreate();
1398 }
1399
1400 void wxCanvas::Prepend( wxCanvasObject* obj )
1401 {
1402 m_root->Prepend( obj );
1403 obj->SetOwner(this);
1404
1405 m_root->Recreate();
1406
1407 if (!obj->IsControl())
1408 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
1409 }
1410
1411 void wxCanvas::Append( wxCanvasObject* obj )
1412 {
1413 m_root->Append( obj );
1414 obj->SetOwner(this);
1415
1416 m_root->Recreate();
1417
1418 if (!obj->IsControl())
1419 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
1420 }
1421
1422 void wxCanvas::Insert( size_t before, wxCanvasObject* obj )
1423 {
1424 m_root->Insert( before, obj );
1425 obj->SetOwner(this);
1426
1427 m_root->Recreate();
1428
1429 if (!obj->IsControl())
1430 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
1431 }
1432
1433 void wxCanvas::Remove( wxCanvasObject* obj )
1434 {
1435 int x = obj->GetX();
1436 int y = obj->GetY();
1437 int w = obj->GetWidth();
1438 int h = obj->GetHeight();
1439 bool ic = obj->IsControl();
1440
1441 m_root->Remove( obj );
1442
1443 if (!ic)
1444 Update( x, y, w, h );
1445 }
1446
1447 void wxCanvas::OnPaint(wxPaintEvent &event)
1448 {
1449 wxPaintDC dc(this);
1450 PrepareDC( dc );
1451
1452 if (!m_buffer.Ok()) return;
1453
1454 if (m_frozen) return;
1455
1456 m_needUpdate = TRUE;
1457
1458 wxRegionIterator it( GetUpdateRegion() );
1459 while (it)
1460 {
1461 int x = it.GetX();
1462 int y = it.GetY();
1463
1464 int w = it.GetWidth();
1465 int h = it.GetHeight();
1466
1467 if (x+w > m_buffer.GetWidth())
1468 w = m_buffer.GetWidth() - x;
1469 if (y+h > m_buffer.GetHeight())
1470 h = m_buffer.GetHeight() - y;
1471
1472 if ((w > 0) && (h > 0))
1473 {
1474 CalcUnscrolledPosition( x, y, &x, &y );
1475 m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) );
1476 }
1477
1478 it++;
1479 }
1480
1481 BlitBuffer( dc );
1482 }
1483
1484 void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
1485 {
1486 // If any updates are pending, do them now since they will
1487 // expect the previous m_bufferX and m_bufferY as well as
1488 // the previous device origin values.
1489 wxClientDC dc( this );
1490 dc.SetDeviceOrigin( m_oldDeviceX, m_oldDeviceY );
1491 BlitBuffer( dc );
1492
1493 // The buffer always starts at the top left corner of the
1494 // client area. Indeed, it is the client area.
1495 CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
1496
1497 #if IMAGE_CANVAS
1498 unsigned char* data = m_buffer.GetData();
1499
1500 if (dy != 0)
1501 {
1502 if (dy > 0)
1503 {
1504 unsigned char *source = data;
1505 unsigned char *dest = data + (dy * m_buffer.GetWidth() * 3);
1506 size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()-dy));
1507 memmove( dest, source, count );
1508
1509 // We update the new buffer area, but there is no need to
1510 // blit (last param FALSE) since the ensuing paint event will
1511 // do that anyway.
1512 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), dy, FALSE );
1513 }
1514 else
1515 {
1516 unsigned char *dest = data;
1517 unsigned char *source = data + (-dy * m_buffer.GetWidth() * 3);
1518 size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()+dy));
1519 memmove( dest, source, count );
1520
1521 // We update the new buffer area, but there is no need to
1522 // blit (last param FALSE) since the ensuing paint event will
1523 // do that anyway.
1524 Update( m_bufferX, m_bufferY+m_buffer.GetHeight()+dy, m_buffer.GetWidth(), -dy, FALSE );
1525 }
1526 }
1527
1528 if (dx != 0)
1529 {
1530 if (dx > 0)
1531 {
1532 unsigned char *source = data;
1533 for (int y = 0; y < m_buffer.GetHeight(); y++)
1534 {
1535 unsigned char *dest = source + dx*3;
1536 memmove( dest, source, (m_buffer.GetWidth()-dx) * 3 );
1537 source += m_buffer.GetWidth()*3;
1538 }
1539
1540 // We update the new buffer area, but there is no need to
1541 // blit (last param FALSE) since the ensuing paint event will
1542 // do that anyway.
1543 Update( m_bufferX, m_bufferY, dx, m_buffer.GetHeight(), FALSE );
1544 }
1545 else
1546 {
1547 unsigned char *dest = data;
1548 for (int y = 0; y < m_buffer.GetHeight(); y++)
1549 {
1550 unsigned char *source = dest - dx*3;
1551 memmove( dest, source, (m_buffer.GetWidth()+dx) * 3 );
1552 dest += m_buffer.GetWidth()*3;
1553 }
1554
1555 // We update the new buffer area, but there is no need to
1556 // blit (last param FALSE) since the ensuing paint event will
1557 // do that anyway.
1558 Update( m_bufferX+m_buffer.GetWidth()+dx, m_bufferY, -dx, m_buffer.GetHeight(), FALSE );
1559 }
1560 }
1561 #else
1562 // Update everything, TODO: scrolling
1563 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
1564 #endif
1565
1566 wxWindow::ScrollWindow( dx, dy, rect );
1567 }
1568
1569 void wxCanvas::OnMouse(wxMouseEvent &event)
1570 {
1571 int x = event.GetX();
1572 int y = event.GetY();
1573 CalcUnscrolledPosition( x, y, &x, &y );
1574
1575 if (event.GetEventType() == wxEVT_MOTION)
1576 {
1577 if (m_captureMouse) //no matter what go to this one
1578 {
1579 wxMouseEvent child_event( wxEVT_MOTION );
1580 child_event.SetEventObject(m_captureMouse);
1581 child_event.m_x = x - m_captureMouse->GetX();
1582 child_event.m_y = y - m_captureMouse->GetY();
1583 child_event.m_leftDown = event.m_leftDown;
1584 child_event.m_rightDown = event.m_rightDown;
1585 child_event.m_middleDown = event.m_middleDown;
1586 child_event.m_controlDown = event.m_controlDown;
1587 child_event.m_shiftDown = event.m_shiftDown;
1588 child_event.m_altDown = event.m_altDown;
1589 child_event.m_metaDown = event.m_metaDown;
1590
1591 m_captureMouse->ProcessEvent( child_event );
1592 return;
1593 }
1594 else
1595 {
1596 wxCanvasObject *obj = m_root->IsHitObject(x,y,0);
1597
1598 if (obj && !obj->IsControl())
1599 {
1600 wxMouseEvent child_event( wxEVT_MOTION );
1601 child_event.SetEventObject( obj );
1602 child_event.m_x = x - obj->GetX();
1603 child_event.m_y = y - obj->GetY();
1604 child_event.m_leftDown = event.m_leftDown;
1605 child_event.m_rightDown = event.m_rightDown;
1606 child_event.m_middleDown = event.m_middleDown;
1607 child_event.m_controlDown = event.m_controlDown;
1608 child_event.m_shiftDown = event.m_shiftDown;
1609 child_event.m_altDown = event.m_altDown;
1610 child_event.m_metaDown = event.m_metaDown;
1611
1612 if ((obj != m_lastMouse) && (m_lastMouse != NULL))
1613 {
1614 child_event.SetEventType( wxEVT_LEAVE_WINDOW );
1615 child_event.SetEventObject( m_lastMouse );
1616 child_event.m_x = x - m_lastMouse->GetX();
1617 child_event.m_y = y - m_lastMouse->GetY();
1618 m_lastMouse->ProcessEvent( child_event );
1619
1620 m_lastMouse = obj;
1621 child_event.SetEventType( wxEVT_ENTER_WINDOW );
1622 child_event.SetEventObject( m_lastMouse );
1623 child_event.m_x = x - m_lastMouse->GetX();
1624 child_event.m_y = y - m_lastMouse->GetY();
1625 m_lastMouse->ProcessEvent( child_event );
1626
1627 child_event.SetEventType( wxEVT_MOTION );
1628 child_event.SetEventObject( obj );
1629 }
1630
1631 obj->ProcessEvent( child_event );
1632 return;
1633 }
1634 }
1635 if (m_lastMouse)
1636 {
1637 wxMouseEvent child_event( wxEVT_LEAVE_WINDOW );
1638 child_event.SetEventObject( m_lastMouse );
1639 child_event.m_x = x - m_lastMouse->GetX();
1640 child_event.m_y = y - m_lastMouse->GetY();
1641 child_event.m_leftDown = event.m_leftDown;
1642 child_event.m_rightDown = event.m_rightDown;
1643 child_event.m_middleDown = event.m_middleDown;
1644 child_event.m_controlDown = event.m_controlDown;
1645 child_event.m_shiftDown = event.m_shiftDown;
1646 child_event.m_altDown = event.m_altDown;
1647 child_event.m_metaDown = event.m_metaDown;
1648 m_lastMouse->ProcessEvent( child_event );
1649
1650 m_lastMouse = (wxCanvasObject*) NULL;
1651 return;
1652 }
1653 }
1654 else
1655 {
1656 if (m_captureMouse) //no matter what go to this one
1657 {
1658 wxMouseEvent child_event( event.GetEventType() );
1659 child_event.SetEventObject(m_captureMouse);
1660 child_event.m_x = x - m_captureMouse->GetX();
1661 child_event.m_y = y - m_captureMouse->GetY();
1662 child_event.m_leftDown = event.m_leftDown;
1663 child_event.m_rightDown = event.m_rightDown;
1664 child_event.m_middleDown = event.m_middleDown;
1665 child_event.m_controlDown = event.m_controlDown;
1666 child_event.m_shiftDown = event.m_shiftDown;
1667 child_event.m_altDown = event.m_altDown;
1668 child_event.m_metaDown = event.m_metaDown;
1669 m_captureMouse->ProcessEvent( child_event );
1670 }
1671 else
1672 {
1673 wxCanvasObject *obj = m_root->IsHitObject(x,y,0);
1674
1675 if (obj && !obj->IsControl())
1676 {
1677 wxMouseEvent child_event( event.GetEventType() );
1678 child_event.SetEventObject( obj );
1679 child_event.m_x = x - obj->GetX();
1680 child_event.m_y = y - obj->GetY();
1681 child_event.m_leftDown = event.m_leftDown;
1682 child_event.m_rightDown = event.m_rightDown;
1683 child_event.m_middleDown = event.m_middleDown;
1684 child_event.m_controlDown = event.m_controlDown;
1685 child_event.m_shiftDown = event.m_shiftDown;
1686 child_event.m_altDown = event.m_altDown;
1687 child_event.m_metaDown = event.m_metaDown;
1688
1689 obj->ProcessEvent( child_event );
1690 return;
1691 }
1692 }
1693 }
1694
1695 event.Skip();
1696 }
1697
1698 void wxCanvas::OnSize(wxSizeEvent &event)
1699 {
1700 int w,h;
1701 GetClientSize( &w, &h );
1702 #if IMAGE_CANVAS
1703 m_buffer = wxImage( w, h );
1704 #else
1705 m_buffer = wxBitmap( w, h );
1706 #endif
1707
1708 CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
1709
1710 wxNode *node = m_updateRects.First();
1711 while (node)
1712 {
1713 wxRect *rect = (wxRect*) node->Data();
1714 delete rect;
1715 m_updateRects.DeleteNode( node );
1716 node = m_updateRects.First();
1717 }
1718
1719 m_frozen = FALSE;
1720
1721 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
1722
1723 event.Skip();
1724 }
1725
1726 void wxCanvas::OnIdle(wxIdleEvent &event)
1727 {
1728 UpdateNow();
1729 event.Skip();
1730 }
1731
1732 void wxCanvas::OnSetFocus(wxFocusEvent &event)
1733 {
1734 }
1735
1736 void wxCanvas::OnKillFocus(wxFocusEvent &event)
1737 {
1738 }
1739
1740 void wxCanvas::OnChar(wxKeyEvent &event)
1741 {
1742 event.Skip();
1743 }
1744
1745 void wxCanvas::OnEraseBackground(wxEraseEvent &event)
1746 {
1747 }
1748
1749 //--------------------------------------------------------------------
1750 // wxCanvasModule
1751 //--------------------------------------------------------------------
1752
1753 class wxCanvasModule : public wxModule
1754 {
1755 public:
1756 virtual bool OnInit();
1757 virtual void OnExit();
1758
1759 private:
1760 DECLARE_DYNAMIC_CLASS(wxCanvasModule)
1761 };
1762
1763 IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule)
1764
1765 bool wxCanvasModule::OnInit()
1766 {
1767 #if wxUSE_FREETYPE
1768 int error = FT_Init_FreeType( &g_freetypeLibrary );
1769 if (error) return FALSE;
1770 #endif
1771
1772 return TRUE;
1773 }
1774
1775 void wxCanvasModule::OnExit()
1776 {
1777 #if wxUSE_FREETYPE
1778 FT_Done_FreeType( g_freetypeLibrary );
1779 #endif
1780 }