af813f01731326c81566eb149244779e93a82564
[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 void wxCanvasObjectGroup::SetOwner(wxCanvas* canvas)
139 {
140 m_owner=canvas;
141 wxNode *node = m_objects.First();
142 while (node)
143 {
144 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
145
146 obj->SetOwner(canvas);
147
148 node = node->Next();
149 }
150 }
151
152 void wxCanvasObjectGroup::ExtendArea(int x, int y)
153 {
154 if (m_validbounds)
155 {
156 if ( x < m_minx ) m_minx = x;
157 if ( y < m_miny ) m_miny = y;
158 if ( x > m_maxx ) m_maxx = x;
159 if ( y > m_maxy ) m_maxy = y;
160 }
161 else
162 {
163 m_validbounds = true;
164
165 m_minx = x;
166 m_miny = y;
167 m_maxx = x;
168 m_maxy = y;
169 }
170
171 }
172
173
174 void wxCanvasObjectGroup::DeleteContents( bool flag)
175 {
176 m_objects.DeleteContents( flag );
177 m_validbounds=false;
178 }
179
180
181 void wxCanvasObjectGroup::Prepend( wxCanvasObject* obj )
182 {
183 m_objects.Insert( obj );
184 m_validbounds=false;
185 }
186
187 void wxCanvasObjectGroup::Append( wxCanvasObject* obj )
188 {
189 m_objects.Append( obj );
190 m_validbounds=false;
191 }
192
193 void wxCanvasObjectGroup::Insert( size_t before, wxCanvasObject* obj )
194 {
195 m_objects.Insert( before, obj );
196 m_validbounds=false;
197 }
198
199 void wxCanvasObjectGroup::Remove( wxCanvasObject* obj )
200 {
201 m_objects.DeleteObject( obj );
202 m_validbounds=false;
203 }
204
205 void wxCanvasObjectGroup::Recreate()
206 {
207 m_validbounds=false;
208 wxNode *node = m_objects.First();
209 while (node)
210 {
211 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
212
213 obj->Recreate();
214 ExtendArea(obj->GetX(),obj->GetY());
215 ExtendArea(obj->GetX()+obj->GetWidth(),obj->GetY()+obj->GetHeight());
216
217 node = node->Next();
218 }
219 }
220
221 void wxCanvasObjectGroup::Render(int xabs, int yabs, int x, int y, int width, int height )
222 {
223 wxImage *image = m_owner->GetBuffer();
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 return 0;
313 }
314
315 //----------------------------------------------------------------------------
316 // wxCanvasObjectGroupRef
317 //----------------------------------------------------------------------------
318
319 wxCanvasObjectGroupRef::wxCanvasObjectGroupRef(double x, double y, wxCanvasObjectGroup* group)
320 : wxCanvasObject()
321 {
322 m_x = x;
323 m_y = y;
324 m_validbounds=false;
325 m_group=group;
326 }
327
328 void wxCanvasObjectGroupRef::SetOwner(wxCanvas* canvas)
329 {
330 m_owner=canvas;
331 m_group->SetOwner(canvas);
332 }
333
334 void wxCanvasObjectGroupRef::ExtendArea(int x, int y)
335 {
336 if (m_validbounds)
337 {
338 if ( x < m_minx ) m_minx = x;
339 if ( y < m_miny ) m_miny = y;
340 if ( x > m_maxx ) m_maxx = x;
341 if ( y > m_maxy ) m_maxy = y;
342 }
343 else
344 {
345 m_validbounds = true;
346
347 m_minx = x;
348 m_miny = y;
349 m_maxx = x;
350 m_maxy = y;
351 }
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 wxImage *image = m_owner->GetBuffer();
372 xabs+=m_owner->GetDeviceX(GetPosX());
373 yabs+=m_owner->GetDeviceY(GetPosY());
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 {
424 int old_x = m_x;
425 int old_y = m_y;
426
427 m_x = x;
428 m_y = y;
429
430 if (!m_isControl)
431 {
432 // TODO: sometimes faster to merge into 1 Update or
433 // to break up into four
434 m_owner->Update(m_area.x, m_area.y, m_area.width, m_area.height );
435 //calculate the new area in pixels relative to the parent
436 SetArea( m_owner->GetDeviceX( m_x + m_minx ),
437 m_owner->GetDeviceY( m_y + m_miny ),
438 m_owner->GetDeviceWidth( m_maxx-m_minx ),
439 m_owner->GetDeviceHeight( m_maxy-m_miny ) );
440 m_owner->Update( m_area.x, m_area.y, m_area.width, m_area.height );
441 }
442 }
443
444
445 //----------------------------------------------------------------------------
446 // wxCanvasRect
447 //----------------------------------------------------------------------------
448
449 wxCanvasRect::wxCanvasRect( double x, double y, double w, double h,
450 unsigned char red, unsigned char green, unsigned char blue )
451 : wxCanvasObject()
452 {
453 m_x = x;
454 m_y = y;
455 m_width = w;
456 m_height = h;
457
458 m_red = red;
459 m_green = green;
460 m_blue = blue;
461 }
462
463 void wxCanvasRect::Recreate()
464 {
465 SetArea( m_owner->GetDeviceX( m_x ),
466 m_owner->GetDeviceY( m_y ),
467 m_owner->GetDeviceWidth( m_width ),
468 m_owner->GetDeviceHeight( m_height ) );
469 }
470
471 void wxCanvasRect::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
472 {
473 wxImage *image = m_owner->GetBuffer();
474 int buffer_x = m_owner->GetBufferX();
475 int buffer_y = m_owner->GetBufferY();
476
477 int start_y = clip_y - buffer_y;
478 int end_y = clip_y+clip_height - buffer_y;
479
480 int start_x = clip_x - buffer_x;
481 int end_x = clip_x+clip_width - buffer_x;
482
483 // speed up later
484 for (int y = start_y; y < end_y; y++)
485 for (int x = start_x; x < end_x; x++)
486 image->SetRGB( x, y, m_red, m_green, m_blue );
487 }
488
489 void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
490 {
491 }
492
493 //----------------------------------------------------------------------------
494 // wxCanvasLine
495 //----------------------------------------------------------------------------
496
497 wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2,
498 unsigned char red, unsigned char green, unsigned char blue )
499 : wxCanvasObject()
500 {
501 m_x1 = x1;
502 m_y1 = y1;
503 m_x2 = x2;
504 m_y2 = y2;
505
506 m_red = red;
507 m_green = green;
508 m_blue = blue;
509 }
510
511 void wxCanvasLine::Recreate()
512 {
513 int x1 = m_owner->GetDeviceX( m_x1 );
514 int y1 = m_owner->GetDeviceY( m_y1 );
515 int x2 = m_owner->GetDeviceX( m_x2 );
516 int y2 = m_owner->GetDeviceY( m_y2 );
517 if (x1 > x2)
518 {
519 int tmp = x1;
520 x1 = x2;
521 x2 = tmp;
522 }
523 if (y1 > y2)
524 {
525 int tmp = y1;
526 y1 = y2;
527 y2 = tmp;
528 }
529 SetArea( x1, y1, x2-x1+1, y2-y1+1 );
530 }
531
532 void wxCanvasLine::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
533 {
534 wxImage *image = m_owner->GetBuffer();
535 int buffer_x = m_owner->GetBufferX();
536 int buffer_y = m_owner->GetBufferY();
537
538 if ((m_area.width == 0) && (m_area.height == 0))
539 {
540 image->SetRGB( m_area.x-buffer_x, m_area.y-buffer_y, m_red, m_green, m_blue );
541 }
542 else
543 {
544 int x1 = xabs + m_owner->GetDeviceX( m_x1 );
545 int y1 = yabs + m_owner->GetDeviceY( m_y1 );
546 int x2 = xabs + m_owner->GetDeviceX( m_x2 );
547 int y2 = yabs + m_owner->GetDeviceY( m_y2 );
548
549 wxInt32 d, ii, jj, di, ai, si, dj, aj, sj;
550 di = x1 - x2;
551 ai = abs(di) << 1;
552 si = (di < 0)? -1 : 1;
553 dj = y1 - y2;
554 aj = abs(dj) << 1;
555 sj = (dj < 0)? -1 : 1;
556
557 ii = x2;
558 jj = y2;
559
560 if (ai > aj)
561 {
562 // iterate over i
563 d = aj - (ai >> 1);
564
565 while (ii != x1)
566 {
567 if ((ii >= clip_x) && (ii < clip_x+clip_width) &&
568 (jj >= clip_y) && (jj < clip_y+clip_height))
569 {
570 image->SetRGB( ii-buffer_x, jj-buffer_y, m_red, m_blue, m_green );
571 }
572 if (d >= 0)
573 {
574 jj += sj;
575 d -= ai;
576 }
577 ii += si;
578 d += aj;
579 }
580 }
581 else
582 {
583 // iterate over j
584 d = ai - (aj >> 1);
585
586 while (jj != y1)
587 {
588 if ((ii >= clip_x) && (ii < clip_x+clip_width) &&
589 (jj >= clip_y) && (jj < clip_y+clip_height))
590 {
591 image->SetRGB( ii-buffer_x, jj-buffer_y, m_red, m_blue, m_green );
592 }
593 if (d >= 0)
594 {
595 ii += si;
596 d -= aj;
597 }
598 jj += sj;
599 d += ai;
600 }
601 }
602 }
603 }
604
605 void wxCanvasLine::WriteSVG( wxTextOutputStream &stream )
606 {
607 // no idea
608 }
609
610 //----------------------------------------------------------------------------
611 // wxCanvasImage
612 //----------------------------------------------------------------------------
613
614 wxCanvasImage::wxCanvasImage( const wxImage &image, double x, double y, double w, double h )
615 : wxCanvasObject()
616 {
617 m_x = x;
618 m_y = y;
619 m_width = w;
620 m_height = h;
621
622 m_image = image;
623 m_isImage = TRUE;
624 }
625
626 void wxCanvasImage::Recreate()
627 {
628 SetArea( m_owner->GetDeviceX( m_x ),
629 m_owner->GetDeviceY( m_y ),
630 m_owner->GetDeviceWidth( m_width ),
631 m_owner->GetDeviceHeight( m_height ) );
632
633 if ((m_area.width == m_image.GetWidth()) &&
634 (m_area.width == m_image.GetWidth()))
635 m_tmp = m_image;
636 else
637 m_tmp = m_image.Scale( m_area.width, m_area.height );
638 }
639
640 void wxCanvasImage::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
641 {
642 int buffer_x = m_owner->GetBufferX();
643 int buffer_y = m_owner->GetBufferY();
644
645 if ((clip_x == xabs + m_area.x) &&
646 (clip_y == yabs + m_area.y) &&
647 (clip_width == m_area.width) &&
648 (clip_height == m_area.height))
649 {
650 m_owner->GetBuffer()->Paste( m_tmp, clip_x-buffer_x, clip_y-buffer_y );
651 }
652 else
653 {
654 // local coordinates
655 int start_x = clip_x - (xabs + m_area.x);
656 int start_y = clip_y - (yabs + m_area.y);
657
658 wxRect rect( start_x, start_y, clip_width, clip_height );
659 wxImage sub_image( m_tmp.GetSubImage( rect ) );
660 m_owner->GetBuffer()->Paste( sub_image, clip_x-buffer_x, clip_y-buffer_y );
661 }
662 }
663
664 void wxCanvasImage::WriteSVG( wxTextOutputStream &stream )
665 {
666 // no idea
667 }
668
669 //----------------------------------------------------------------------------
670 // wxCanvasCtrl
671 //----------------------------------------------------------------------------
672
673 wxCanvasControl::wxCanvasControl( wxWindow *control )
674 : wxCanvasObject()
675 {
676 m_isControl = TRUE;
677 m_control = control;
678 }
679
680 wxCanvasControl::~wxCanvasControl()
681 {
682 m_control->Destroy();
683 }
684
685 void wxCanvasControl::Recreate()
686 {
687 m_control->GetSize( &m_area.width, &m_area.height );
688 m_control->GetPosition( &m_area.x, &m_area.y );
689 }
690
691 void wxCanvasControl::Move( int x, int y )
692 {
693 m_control->Move( x, y );
694 }
695
696 //----------------------------------------------------------------------------
697 // wxCanvasText
698 //----------------------------------------------------------------------------
699
700 class wxFaceData
701 {
702 public:
703 #if wxUSE_FREETYPE
704 FT_Face m_face;
705 #else
706 void *m_dummy;
707 #endif
708 };
709
710 wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxString &fontFile, int size )
711 : wxCanvasObject()
712 {
713 m_text = text;
714 m_fontFileName = fontFile;
715 m_size = size;
716
717 m_red = 0;
718 m_green = 0;
719 m_blue = 0;
720
721 m_alpha = NULL;
722
723 m_x = x;
724 m_y = y;
725
726 #if wxUSE_FREETYPE
727 wxFaceData *data = new wxFaceData;
728 m_faceData = data;
729
730 int error = FT_New_Face( g_freetypeLibrary,
731 m_fontFileName,
732 0,
733 &(data->m_face) );
734
735 error = FT_Set_Char_Size( data->m_face,
736 0,
737 m_size*64,
738 96, // screen dpi
739 96 );
740 #endif
741 }
742
743 wxCanvasText::~wxCanvasText()
744 {
745 #if wxUSE_FREETYPE
746 wxFaceData *data = (wxFaceData*) m_faceData;
747 delete data;
748 #endif
749
750 if (m_alpha) delete [] m_alpha;
751 }
752
753 void wxCanvasText::SetRGB( unsigned char red, unsigned char green, unsigned char blue )
754 {
755 m_red = red;
756 m_green = green;
757 m_blue = blue;
758 }
759
760 void wxCanvasText::SetFlag( int flag )
761 {
762 m_flag = flag;
763 }
764
765 void wxCanvasText::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
766 {
767 if (!m_alpha) return;
768
769 wxImage *image = m_owner->GetBuffer();
770 int buffer_x = m_owner->GetBufferX();
771 int buffer_y = m_owner->GetBufferY();
772
773 // local coordinates
774 int start_x = clip_x - m_area.x;
775 int end_x = clip_width + start_x;
776 int start_y = clip_y - m_area.y;
777 int end_y = clip_height + start_y;
778
779 for (int y = start_y; y < end_y; y++)
780 for (int x = start_x; x < end_x; x++)
781 {
782 int alpha = m_alpha[y*m_area.width + x];
783 if (alpha)
784 {
785 int image_x = m_area.x+x - buffer_x;
786 int image_y = m_area.y+y - buffer_y;
787 if (alpha == 255)
788 {
789 image->SetRGB( image_x, image_y, m_red, m_green, m_blue );
790 continue;
791 }
792 int red1 = (m_red * alpha) / 255;
793 int green1 = (m_green * alpha) / 255;
794 int blue1 = (m_blue * alpha) / 255;
795
796 alpha = 255-alpha;
797 int red2 = image->GetRed( image_x, image_y );
798 int green2 = image->GetGreen( image_x, image_y );
799 int blue2 = image->GetBlue( image_x, image_y );
800 red2 = (red2 * alpha) / 255;
801 green2 = (green2 * alpha) / 255;
802 blue2 = (blue2 * alpha) / 255;
803
804 image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
805 }
806 }
807 }
808
809 void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
810 {
811 }
812
813 void wxCanvasText::Recreate()
814 {
815 if (m_alpha) delete [] m_alpha;
816
817 m_area.x = m_owner->GetDeviceX( m_x );
818 m_area.y = m_owner->GetDeviceY( m_y );
819
820 m_area.width = 100; // TODO, calculate length
821 m_area.height = m_size;
822 m_alpha = new unsigned char[100*m_size];
823 memset( m_alpha, 0, m_area.width*m_area.height );
824
825 #if wxUSE_FREETYPE
826 FT_Face face = ((wxFaceData*)m_faceData)->m_face;
827 FT_GlyphSlot slot = face->glyph;
828 int pen_x = 0;
829 int pen_y = m_size;
830
831 for (int n = 0; n < (int)m_text.Len(); n++)
832 {
833 FT_UInt index = FT_Get_Char_Index( face, m_text[n] );
834
835 int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
836 if (error) continue;
837
838 error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
839 if (error) continue;
840
841 FT_Bitmap *bitmap = &slot->bitmap;
842 unsigned char* buffer = bitmap->buffer;
843 for (int y = 0; y < bitmap->rows; y++)
844 for (int x = 0; x < bitmap->width; x++)
845 {
846 unsigned char alpha = buffer[ y*bitmap->pitch + x ];
847 if (alpha == 0) continue;
848
849 int xx = pen_x + slot->bitmap_left + x;
850 int yy = pen_y - slot->bitmap_top + y;
851 m_alpha[ yy * m_area.width + xx ] = alpha;
852 }
853
854 pen_x += slot->advance.x >> 6;
855 pen_y += slot->advance.y >> 6;
856 }
857 #endif
858 }
859
860 //----------------------------------------------------------------------------
861 // wxCanvas
862 //----------------------------------------------------------------------------
863
864 IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow)
865
866 BEGIN_EVENT_TABLE(wxCanvas,wxScrolledWindow)
867 EVT_CHAR( wxCanvas::OnChar )
868 EVT_PAINT( wxCanvas::OnPaint )
869 EVT_SIZE( wxCanvas::OnSize )
870 EVT_IDLE( wxCanvas::OnIdle )
871 EVT_MOUSE_EVENTS( wxCanvas::OnMouse )
872 EVT_SET_FOCUS( wxCanvas::OnSetFocus )
873 EVT_KILL_FOCUS( wxCanvas::OnKillFocus )
874 EVT_ERASE_BACKGROUND( wxCanvas::OnEraseBackground )
875 END_EVENT_TABLE()
876
877 wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
878 const wxPoint &position, const wxSize& size, long style ) :
879 wxScrolledWindow( parent, id, position, size, style )
880 {
881 m_bufferX = 0;
882 m_bufferY = 0;
883 m_needUpdate = FALSE;
884 m_red = 0;
885 m_green = 0;
886 m_blue = 0;
887 m_lastMouse = (wxCanvasObject*)NULL;
888 m_captureMouse = (wxCanvasObject*)NULL;
889 m_frozen = TRUE;
890 m_requestNewBuffer = TRUE;
891
892 //root group always at 0,0
893 m_root = new wxCanvasObjectGroup();
894 m_root->DeleteContents( TRUE );
895 m_root->SetOwner(this);
896 }
897
898 wxCanvas::~wxCanvas()
899 {
900 wxNode *node = m_updateRects.First();
901 while (node)
902 {
903 wxRect *rect = (wxRect*) node->Data();
904 delete rect;
905 m_updateRects.DeleteNode( node );
906 node = m_updateRects.First();
907 }
908 }
909
910 void wxCanvas::SetArea( int width, int height )
911 {
912 SetScrollbars( 10, 10, width/10, height/10 );
913 }
914
915 void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char blue )
916 {
917 m_red = red;
918 m_green = green;
919 m_blue = blue;
920
921 SetBackgroundColour( wxColour( red, green, blue ) );
922
923 if (m_frozen) return;
924
925 unsigned char *data = m_buffer.GetData();
926
927 for (int y = 0; y < m_buffer.GetHeight(); y++)
928 for (int x = 0; x < m_buffer.GetWidth(); x++)
929 {
930 data[0] = red;
931 data++;
932 data[0] = green;
933 data++;
934 data[0] = blue;
935 data++;
936 }
937 }
938
939 void wxCanvas::SetCaptureMouse( wxCanvasObject *obj )
940 {
941 if (obj)
942 {
943 wxWindow::CaptureMouse();
944 m_captureMouse = obj;
945 }
946 else
947 {
948 wxWindow::ReleaseMouse();
949 m_captureMouse = NULL;
950 }
951 }
952
953 void wxCanvas::Freeze()
954 {
955 m_frozen = TRUE;
956 }
957
958 void wxCanvas::Thaw()
959 {
960 wxNode *node = m_updateRects.First();
961 while (node)
962 {
963 wxRect *rect = (wxRect*) node->Data();
964 delete rect;
965 m_updateRects.DeleteNode( node );
966 node = m_updateRects.First();
967 }
968
969 m_frozen = FALSE;
970
971 if (m_buffer.Ok())
972 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight() );
973 }
974
975 void wxCanvas::Update( int x, int y, int width, int height, bool blit )
976 {
977 if (m_frozen) return;
978
979 // clip to buffer
980 if (x < m_bufferX)
981 {
982 width -= m_bufferX-x;
983 x = m_bufferX;
984 }
985 if (width < 0) return;
986
987 if (y < m_bufferY)
988 {
989 height -= m_bufferY-y;
990 y = m_bufferY;
991 }
992 if (height < 0) return;
993
994 if (x+width > m_bufferX+m_buffer.GetWidth())
995 {
996 width = m_bufferX+m_buffer.GetWidth() - x;
997 }
998 if (width < 0) return;
999
1000 if (y+height > m_bufferY+m_buffer.GetHeight())
1001 {
1002 height = m_bufferY+m_buffer.GetHeight() - y;
1003 }
1004 if (height < 0) return;
1005
1006 // update is within the buffer
1007 m_needUpdate = TRUE;
1008
1009 // has to be blitted to screen later
1010 if (blit)
1011 {
1012 m_updateRects.Append(
1013 (wxObject*) new wxRect( x,y,width,height ) );
1014 }
1015
1016 // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b)
1017 int start_y = y - m_bufferY;
1018 int end_y = y+height - m_bufferY;
1019 int start_x = x - m_bufferX;
1020 int end_x = x+width - m_bufferX;
1021 for (int yy = start_y; yy < end_y; yy++)
1022 for (int xx = start_x; xx < end_x; xx++)
1023 m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue );
1024
1025 m_root->Render(0,0, x, y, width, height );
1026
1027 }
1028
1029 void wxCanvas::BlitBuffer( wxDC &dc )
1030 {
1031 wxNode *node = m_updateRects.First();
1032 while (node)
1033 {
1034 wxRect *rect = (wxRect*) node->Data();
1035
1036 wxRect sub_rect( *rect );
1037 sub_rect.x -= m_bufferX;
1038 sub_rect.y -= m_bufferY;
1039
1040 wxImage sub_image( m_buffer.GetSubImage( sub_rect ) );
1041
1042 #ifdef __WXGTK__
1043 int bpp = wxDisplayDepth();
1044 if (bpp > 8)
1045 {
1046 // the init code is doubled in wxImage
1047 static bool s_hasInitialized = FALSE;
1048
1049 if (!s_hasInitialized)
1050 {
1051 gdk_rgb_init();
1052 s_hasInitialized = TRUE;
1053 }
1054
1055 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow)->bin_window,
1056 m_wxwindow->style->black_gc,
1057 sub_rect.x, sub_rect.y,
1058 sub_image.GetWidth(), sub_image.GetHeight(),
1059 GDK_RGB_DITHER_NONE,
1060 sub_image.GetData(),
1061 sub_image.GetWidth()*3 );
1062 }
1063 else
1064 {
1065 wxBitmap bitmap( sub_image.ConvertToBitmap() );
1066 dc.DrawBitmap( bitmap, rect->x, rect->y );
1067 }
1068 #endif
1069
1070 #ifndef __WXGTK__
1071 wxBitmap bitmap( sub_image.ConvertToBitmap() );
1072 dc.DrawBitmap( bitmap, rect->x, rect->y );
1073 #endif
1074
1075 delete rect;
1076 m_updateRects.DeleteNode( node );
1077 node = m_updateRects.First();
1078 }
1079
1080 m_needUpdate = FALSE;
1081 }
1082
1083 void wxCanvas::UpdateNow()
1084 {
1085 if (m_frozen) return;
1086
1087 if (!m_needUpdate) return;
1088
1089 wxClientDC dc( this );
1090 PrepareDC( dc );
1091
1092 BlitBuffer( dc );
1093 }
1094
1095 int wxCanvas::GetDeviceX( double x )
1096 {
1097 return (int) x;
1098 }
1099
1100 int wxCanvas::GetDeviceY( double y )
1101 {
1102 return (int) y;
1103 }
1104
1105 int wxCanvas::GetDeviceWidth( double width )
1106 {
1107 return (int) width;
1108 }
1109
1110 int wxCanvas::GetDeviceHeight( double height )
1111 {
1112 return (int) height;
1113 }
1114
1115 void wxCanvas::Recreate()
1116 {
1117 m_root->Recreate();
1118 }
1119
1120 void wxCanvas::Prepend( wxCanvasObject* obj )
1121 {
1122 m_root->Prepend( obj );
1123 obj->SetOwner(this);
1124
1125 m_root->Recreate();
1126
1127 if (!obj->IsControl())
1128 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
1129 }
1130
1131 void wxCanvas::Append( wxCanvasObject* obj )
1132 {
1133 m_root->Append( obj );
1134 obj->SetOwner(this);
1135
1136 m_root->Recreate();
1137
1138 if (!obj->IsControl())
1139 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
1140 }
1141
1142 void wxCanvas::Insert( size_t before, wxCanvasObject* obj )
1143 {
1144 m_root->Insert( before, obj );
1145 obj->SetOwner(this);
1146
1147 m_root->Recreate();
1148
1149 if (!obj->IsControl())
1150 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
1151 }
1152
1153 void wxCanvas::Remove( wxCanvasObject* obj )
1154 {
1155 int x = obj->GetX();
1156 int y = obj->GetY();
1157 int w = obj->GetWidth();
1158 int h = obj->GetHeight();
1159 bool ic = obj->IsControl();
1160
1161 m_root->Remove( obj );
1162
1163 if (!ic)
1164 Update( x, y, w, h );
1165 }
1166
1167 void wxCanvas::OnPaint(wxPaintEvent &event)
1168 {
1169 wxPaintDC dc(this);
1170 PrepareDC( dc );
1171
1172 if (!m_buffer.Ok()) return;
1173
1174 if (m_frozen) return;
1175
1176 m_needUpdate = TRUE;
1177
1178 wxRegionIterator it( GetUpdateRegion() );
1179 while (it)
1180 {
1181 int x = it.GetX();
1182 int y = it.GetY();
1183
1184 int w = it.GetWidth();
1185 int h = it.GetHeight();
1186
1187 if (x+w > m_buffer.GetWidth())
1188 w = m_buffer.GetWidth() - x;
1189 if (y+h > m_buffer.GetHeight())
1190 h = m_buffer.GetHeight() - y;
1191
1192 if ((w > 0) && (h > 0))
1193 {
1194 CalcUnscrolledPosition( x, y, &x, &y );
1195 m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) );
1196 }
1197
1198 it++;
1199 }
1200
1201 BlitBuffer( dc );
1202 }
1203
1204 void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
1205 {
1206 // If any updates are pending, do them now since they will
1207 // expect the previous m_bufferX and m_bufferY values.
1208 UpdateNow();
1209
1210 // The buffer always starts at the top left corner of the
1211 // client area. Indeed, it is the client area.
1212 CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
1213
1214 unsigned char* data = m_buffer.GetData();
1215
1216 if (dy != 0)
1217 {
1218 if (dy > 0)
1219 {
1220 unsigned char *source = data;
1221 unsigned char *dest = data + (dy * m_buffer.GetWidth() * 3);
1222 size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()-dy));
1223 memmove( dest, source, count );
1224
1225 // We update the new buffer area, but there is no need to
1226 // blit (last param FALSE) since the ensuing paint event will
1227 // do that anyway.
1228 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), dy, FALSE );
1229 }
1230 else
1231 {
1232 unsigned char *dest = data;
1233 unsigned char *source = data + (-dy * m_buffer.GetWidth() * 3);
1234 size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()+dy));
1235 memmove( dest, source, count );
1236
1237 // We update the new buffer area, but there is no need to
1238 // blit (last param FALSE) since the ensuing paint event will
1239 // do that anyway.
1240 Update( m_bufferX, m_bufferY+m_buffer.GetHeight()+dy, m_buffer.GetWidth(), -dy, FALSE );
1241 }
1242 }
1243
1244 if (dx != 0)
1245 {
1246 if (dx > 0)
1247 {
1248 unsigned char *source = data;
1249 for (int y = 0; y < m_buffer.GetHeight(); y++)
1250 {
1251 unsigned char *dest = source + dx*3;
1252 memmove( dest, source, (m_buffer.GetWidth()-dx) * 3 );
1253 source += m_buffer.GetWidth()*3;
1254 }
1255
1256 // We update the new buffer area, but there is no need to
1257 // blit (last param FALSE) since the ensuing paint event will
1258 // do that anyway.
1259 Update( m_bufferX, m_bufferY, dx, m_buffer.GetHeight(), FALSE );
1260 }
1261 else
1262 {
1263 unsigned char *dest = data;
1264 for (int y = 0; y < m_buffer.GetHeight(); y++)
1265 {
1266 unsigned char *source = dest - dx*3;
1267 memmove( dest, source, (m_buffer.GetWidth()+dx) * 3 );
1268 dest += m_buffer.GetWidth()*3;
1269 }
1270
1271 // We update the new buffer area, but there is no need to
1272 // blit (last param FALSE) since the ensuing paint event will
1273 // do that anyway.
1274 Update( m_bufferX+m_buffer.GetWidth()+dx, m_bufferY, -dx, m_buffer.GetHeight(), FALSE );
1275 }
1276 }
1277
1278 wxWindow::ScrollWindow( dx, dy, rect );
1279 }
1280
1281 void wxCanvas::OnMouse(wxMouseEvent &event)
1282 {
1283 int x = event.GetX();
1284 int y = event.GetY();
1285 CalcUnscrolledPosition( x, y, &x, &y );
1286
1287 if (event.GetEventType() == wxEVT_MOTION)
1288 {
1289 if (m_captureMouse) //no matter what go to this one
1290 {
1291 wxMouseEvent child_event( wxEVT_MOTION );
1292 child_event.SetEventObject(m_captureMouse);
1293 child_event.m_x = x - m_captureMouse->GetX();
1294 child_event.m_y = y - m_captureMouse->GetY();
1295 child_event.m_leftDown = event.m_leftDown;
1296 child_event.m_rightDown = event.m_rightDown;
1297 child_event.m_middleDown = event.m_middleDown;
1298 child_event.m_controlDown = event.m_controlDown;
1299 child_event.m_shiftDown = event.m_shiftDown;
1300 child_event.m_altDown = event.m_altDown;
1301 child_event.m_metaDown = event.m_metaDown;
1302 m_captureMouse->ProcessEvent( child_event );
1303 }
1304 else
1305 {
1306 wxCanvasObject *obj = m_root->IsHitObject(x,y,0);
1307
1308 if (obj && !obj->IsControl())
1309 {
1310 wxMouseEvent child_event( wxEVT_MOTION );
1311 child_event.SetEventObject( obj );
1312 child_event.m_x = x - obj->GetX();
1313 child_event.m_y = y - obj->GetY();
1314 child_event.m_leftDown = event.m_leftDown;
1315 child_event.m_rightDown = event.m_rightDown;
1316 child_event.m_middleDown = event.m_middleDown;
1317 child_event.m_controlDown = event.m_controlDown;
1318 child_event.m_shiftDown = event.m_shiftDown;
1319 child_event.m_altDown = event.m_altDown;
1320 child_event.m_metaDown = event.m_metaDown;
1321
1322 if ((obj != m_lastMouse) && (m_lastMouse != NULL))
1323 {
1324 child_event.SetEventType( wxEVT_LEAVE_WINDOW );
1325 child_event.SetEventObject( m_lastMouse );
1326 child_event.m_x = x - m_lastMouse->GetX();
1327 child_event.m_y = y - m_lastMouse->GetY();
1328 m_lastMouse->ProcessEvent( child_event );
1329
1330 m_lastMouse = obj;
1331 child_event.SetEventType( wxEVT_ENTER_WINDOW );
1332 child_event.SetEventObject( m_lastMouse );
1333 child_event.m_x = x - m_lastMouse->GetX();
1334 child_event.m_y = y - m_lastMouse->GetY();
1335 m_lastMouse->ProcessEvent( child_event );
1336
1337 child_event.SetEventType( wxEVT_MOTION );
1338 child_event.SetEventObject( obj );
1339 }
1340 obj->ProcessEvent( child_event );
1341 return;
1342 }
1343 }
1344 if (m_lastMouse)
1345 {
1346 wxMouseEvent child_event( wxEVT_LEAVE_WINDOW );
1347 child_event.SetEventObject( m_lastMouse );
1348 child_event.m_x = x - m_lastMouse->GetX();
1349 child_event.m_y = y - m_lastMouse->GetY();
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 );
1358
1359 m_lastMouse = (wxCanvasObject*) NULL;
1360 return;
1361 }
1362 }
1363
1364 event.Skip();
1365 }
1366
1367 void wxCanvas::OnSize(wxSizeEvent &event)
1368 {
1369 int w,h;
1370 GetClientSize( &w, &h );
1371 m_buffer = wxImage( w, h );
1372
1373 CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
1374
1375 wxNode *node = m_updateRects.First();
1376 while (node)
1377 {
1378 wxRect *rect = (wxRect*) node->Data();
1379 delete rect;
1380 m_updateRects.DeleteNode( node );
1381 node = m_updateRects.First();
1382 }
1383
1384 m_frozen = FALSE;
1385
1386 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
1387
1388 event.Skip();
1389 }
1390
1391 void wxCanvas::OnIdle(wxIdleEvent &event)
1392 {
1393 UpdateNow();
1394 event.Skip();
1395 }
1396
1397 void wxCanvas::OnSetFocus(wxFocusEvent &event)
1398 {
1399 }
1400
1401 void wxCanvas::OnKillFocus(wxFocusEvent &event)
1402 {
1403 }
1404
1405 void wxCanvas::OnChar(wxKeyEvent &event)
1406 {
1407 event.Skip();
1408 }
1409
1410 void wxCanvas::OnEraseBackground(wxEraseEvent &event)
1411 {
1412 }
1413
1414 //--------------------------------------------------------------------
1415 // wxCanvasModule
1416 //--------------------------------------------------------------------
1417
1418 class wxCanvasModule : public wxModule
1419 {
1420 public:
1421 virtual bool OnInit();
1422 virtual void OnExit();
1423
1424 private:
1425 DECLARE_DYNAMIC_CLASS(wxCanvasModule)
1426 };
1427
1428 IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule)
1429
1430 bool wxCanvasModule::OnInit()
1431 {
1432 #if wxUSE_FREETYPE
1433 int error = FT_Init_FreeType( &g_freetypeLibrary );
1434 if (error) return FALSE;
1435 #endif
1436
1437 return TRUE;
1438 }
1439
1440 void wxCanvasModule::OnExit()
1441 {
1442 #if wxUSE_FREETYPE
1443 FT_Done_FreeType( g_freetypeLibrary );
1444 #endif
1445 }