]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/canvas/canvas.cpp
ddb3b06615d1fa04621d3bf4eeae8588a8716c1d
[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::Render( int clip_x, int clip_y, int clip_width, int clip_height )
102 {
103 }
104
105 void wxCanvasObject::Recreate()
106 {
107 }
108
109 void wxCanvasObject::WriteSVG( wxTextOutputStream &stream )
110 {
111 }
112
113 //----------------------------------------------------------------------------
114 // wxCanvasRect
115 //----------------------------------------------------------------------------
116
117 wxCanvasRect::wxCanvasRect( double x, double y, double w, double h,
118 unsigned char red, unsigned char green, unsigned char blue )
119 : wxCanvasObject()
120 {
121 m_x = x;
122 m_y = y;
123 m_width = w;
124 m_height = h;
125
126 m_red = red;
127 m_green = green;
128 m_blue = blue;
129 }
130
131 void wxCanvasRect::Recreate()
132 {
133 SetArea( m_owner->GetDeviceX( m_x ),
134 m_owner->GetDeviceY( m_y ),
135 m_owner->GetDeviceWidth( m_width ),
136 m_owner->GetDeviceHeight( m_height ) );
137 }
138
139 void wxCanvasRect::Render( int clip_x, int clip_y, int clip_width, int clip_height )
140 {
141 wxImage *image = m_owner->GetBuffer();
142 // speed up later
143 for (int y = clip_y; y < clip_y+clip_height; y++)
144 for (int x = clip_x; x < clip_x+clip_width; x++)
145 image->SetRGB( x, y, m_red, m_green, m_blue );
146 }
147
148 void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
149 {
150 }
151
152 //----------------------------------------------------------------------------
153 // wxCanvasLine
154 //----------------------------------------------------------------------------
155
156 wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2,
157 unsigned char red, unsigned char green, unsigned char blue )
158 : wxCanvasObject()
159 {
160 m_x1 = x1;
161 m_y1 = y1;
162 m_x2 = x2;
163 m_y2 = y2;
164
165 m_red = red;
166 m_green = green;
167 m_blue = blue;
168 }
169
170 void wxCanvasLine::Recreate()
171 {
172 int x1 = m_owner->GetDeviceX( m_x1 );
173 int y1 = m_owner->GetDeviceY( m_y1 );
174 int x2 = m_owner->GetDeviceX( m_x2 );
175 int y2 = m_owner->GetDeviceY( m_y2 );
176 if (x1 > x2)
177 {
178 int tmp = x1;
179 x1 = x2;
180 x2 = tmp;
181 }
182 if (y1 > y2)
183 {
184 int tmp = y1;
185 y1 = y2;
186 y2 = tmp;
187 }
188 SetArea( x1, y1, x2-x1+1, y2-y1+1 );
189 }
190
191 void wxCanvasLine::Render( int clip_x, int clip_y, int clip_width, int clip_height )
192 {
193 wxImage *image = m_owner->GetBuffer();
194
195 if ((m_area.width == 0) && (m_area.height == 0))
196 {
197 image->SetRGB( m_area.x, m_area.y, m_red, m_green, m_blue );
198 }
199 else
200 {
201 int x1 = m_owner->GetDeviceX( m_x1 );
202 int y1 = m_owner->GetDeviceY( m_y1 );
203 int x2 = m_owner->GetDeviceX( m_x2 );
204 int y2 = m_owner->GetDeviceY( m_y2 );
205
206 wxInt32 d, ii, jj, di, ai, si, dj, aj, sj;
207 di = x1 - x2;
208 ai = abs(di) << 1;
209 si = (di < 0)? -1 : 1;
210 dj = y1 - y2;
211 aj = abs(dj) << 1;
212 sj = (dj < 0)? -1 : 1;
213
214 ii = x2;
215 jj = y2;
216
217 if (ai > aj)
218 {
219 // iterate over i
220 d = aj - (ai >> 1);
221
222 while (ii != x1)
223 {
224 if ((ii >= clip_x) && (ii <= clip_x+clip_width) &&
225 (jj >= clip_y) && (jj <= clip_y+clip_height))
226 {
227 image->SetRGB( ii, jj, m_red, m_blue, m_green );
228 }
229 if (d >= 0)
230 {
231 jj += sj;
232 d -= ai;
233 }
234 ii += si;
235 d += aj;
236 }
237 }
238 else
239 {
240 // iterate over j
241 d = ai - (aj >> 1);
242
243 while (jj != y1)
244 {
245 if ((ii >= clip_x) && (ii <= clip_x+clip_width) &&
246 (jj >= clip_y) && (jj <= clip_y+clip_height))
247 {
248 image->SetRGB( ii, jj, m_red, m_blue, m_green );
249 }
250 if (d >= 0)
251 {
252 ii += si;
253 d -= aj;
254 }
255 jj += sj;
256 d += ai;
257 }
258 }
259 }
260 }
261
262 void wxCanvasLine::WriteSVG( wxTextOutputStream &stream )
263 {
264 // no idea
265 }
266
267 //----------------------------------------------------------------------------
268 // wxCanvasImage
269 //----------------------------------------------------------------------------
270
271 wxCanvasImage::wxCanvasImage( const wxImage &image, double x, double y, double w, double h )
272 : wxCanvasObject()
273 {
274 m_x = x;
275 m_y = y;
276 m_width = w;
277 m_height = h;
278
279 m_image = image;
280 m_isImage = TRUE;
281 }
282
283 void wxCanvasImage::Recreate()
284 {
285 SetArea( m_owner->GetDeviceX( m_x ),
286 m_owner->GetDeviceY( m_y ),
287 m_owner->GetDeviceWidth( m_width ),
288 m_owner->GetDeviceHeight( m_height ) );
289
290 if ((m_area.width == m_image.GetWidth()) &&
291 (m_area.width == m_image.GetWidth()))
292 m_tmp = m_image;
293 else
294 m_tmp = m_image.Scale( m_area.width, m_area.height );
295 }
296
297 void wxCanvasImage::Render( int clip_x, int clip_y, int clip_width, int clip_height )
298 {
299 if ((clip_x == m_area.x) &&
300 (clip_y == m_area.y) &&
301 (clip_width == m_area.width) &&
302 (clip_height == m_area.height))
303 {
304 m_owner->GetBuffer()->Paste( m_tmp, clip_x, clip_y );
305 }
306 else
307 {
308 // local coordinates
309 int start_x = clip_x - m_area.x;
310 int start_y = clip_y - m_area.y;
311
312 wxRect rect( start_x, start_y, clip_width, clip_height );
313 wxImage sub_image( m_tmp.GetSubImage( rect ) );
314 m_owner->GetBuffer()->Paste( sub_image, clip_x, clip_y );
315 }
316 }
317
318 void wxCanvasImage::WriteSVG( wxTextOutputStream &stream )
319 {
320 // no idea
321 }
322
323 //----------------------------------------------------------------------------
324 // wxCanvasCtrl
325 //----------------------------------------------------------------------------
326
327 wxCanvasControl::wxCanvasControl( wxWindow *control )
328 : wxCanvasObject()
329 {
330 m_isControl = TRUE;
331 m_control = control;
332 }
333
334 wxCanvasControl::~wxCanvasControl()
335 {
336 m_control->Destroy();
337 }
338
339 void wxCanvasControl::Recreate()
340 {
341 m_control->GetSize( &m_area.width, &m_area.height );
342 m_control->GetPosition( &m_area.x, &m_area.y );
343 }
344
345 void wxCanvasControl::Move( int x, int y )
346 {
347 m_control->Move( x, y );
348 }
349
350 //----------------------------------------------------------------------------
351 // wxCanvasText
352 //----------------------------------------------------------------------------
353
354 class wxFaceData
355 {
356 public:
357 #if wxUSE_FREETYPE
358 FT_Face m_face;
359 #else
360 void *m_dummy;
361 #endif
362 };
363
364 wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxString &fontFile, int size )
365 : wxCanvasObject()
366 {
367 m_text = text;
368 m_fontFileName = fontFile;
369 m_size = size;
370
371 m_red = 0;
372 m_green = 0;
373 m_blue = 0;
374
375 m_alpha = NULL;
376
377 m_x = x;
378 m_y = y;
379
380 #if wxUSE_FREETYPE
381 wxFaceData *data = new wxFaceData;
382 m_faceData = data;
383
384 int error = FT_New_Face( g_freetypeLibrary,
385 m_fontFileName,
386 0,
387 &(data->m_face) );
388
389 error = FT_Set_Char_Size( data->m_face,
390 0,
391 m_size*64,
392 96, // screen dpi
393 96 );
394 #endif
395 }
396
397 wxCanvasText::~wxCanvasText()
398 {
399 #if wxUSE_FREETYPE
400 wxFaceData *data = (wxFaceData*) m_faceData;
401 delete data;
402 #endif
403
404 if (m_alpha) delete [] m_alpha;
405 }
406
407 void wxCanvasText::SetRGB( unsigned char red, unsigned char green, unsigned char blue )
408 {
409 m_red = red;
410 m_green = green;
411 m_blue = blue;
412 }
413
414 void wxCanvasText::SetFlag( int flag )
415 {
416 m_flag = flag;
417 }
418
419 void wxCanvasText::Render( int clip_x, int clip_y, int clip_width, int clip_height )
420 {
421 if (!m_alpha) return;
422
423 wxImage *image = m_owner->GetBuffer();
424
425 // local coordinates
426 int start_x = clip_x - m_area.x;
427 int end_x = clip_width + start_x;
428 int start_y = clip_y - m_area.y;
429 int end_y = clip_height + start_y;
430
431 for (int y = start_y; y < end_y; y++)
432 for (int x = start_x; x < end_x; x++)
433 {
434 int alpha = m_alpha[y*m_area.width + x];
435 if (alpha)
436 {
437 int image_x = m_area.x+x;
438 int image_y = m_area.y+y;
439 if (alpha == 255)
440 {
441 image->SetRGB( image_x, image_y, m_red, m_green, m_blue );
442 continue;
443 }
444 int red1 = (m_red * alpha) / 255;
445 int green1 = (m_green * alpha) / 255;
446 int blue1 = (m_blue * alpha) / 255;
447
448 alpha = 255-alpha;
449 int red2 = image->GetRed( image_x, image_y );
450 int green2 = image->GetGreen( image_x, image_y );
451 int blue2 = image->GetBlue( image_x, image_y );
452 red2 = (red2 * alpha) / 255;
453 green2 = (green2 * alpha) / 255;
454 blue2 = (blue2 * alpha) / 255;
455
456 image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
457 }
458 }
459 }
460
461 void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
462 {
463 }
464
465 void wxCanvasText::Recreate()
466 {
467 if (m_alpha) delete [] m_alpha;
468
469 m_area.x = m_owner->GetDeviceX( m_x );
470 m_area.y = m_owner->GetDeviceY( m_y );
471
472 m_area.width = 100; // TODO, calculate length
473 m_area.height = m_size;
474 m_alpha = new unsigned char[100*m_size];
475 memset( m_alpha, 0, m_area.width*m_area.height );
476
477 #if wxUSE_FREETYPE
478 FT_Face face = ((wxFaceData*)m_faceData)->m_face;
479 FT_GlyphSlot slot = face->glyph;
480 int pen_x = 0;
481 int pen_y = m_size;
482
483 for (int n = 0; n < (int)m_text.Len(); n++)
484 {
485 FT_UInt index = FT_Get_Char_Index( face, m_text[n] );
486
487 int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
488 if (error) continue;
489
490 error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
491 if (error) continue;
492
493 FT_Bitmap *bitmap = &slot->bitmap;
494 unsigned char* buffer = bitmap->buffer;
495 for (int y = 0; y < bitmap->rows; y++)
496 for (int x = 0; x < bitmap->width; x++)
497 {
498 unsigned char alpha = buffer[ y*bitmap->pitch + x ];
499 if (alpha == 0) continue;
500
501 int xx = pen_x + slot->bitmap_left + x;
502 int yy = pen_y - slot->bitmap_top + y;
503 m_alpha[ yy * m_area.width + xx ] = alpha;
504 }
505
506 pen_x += slot->advance.x >> 6;
507 pen_y += slot->advance.y >> 6;
508 }
509 #endif
510 }
511
512 //----------------------------------------------------------------------------
513 // wxCanvas
514 //----------------------------------------------------------------------------
515
516 IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow)
517
518 BEGIN_EVENT_TABLE(wxCanvas,wxScrolledWindow)
519 EVT_CHAR( wxCanvas::OnChar )
520 EVT_PAINT( wxCanvas::OnPaint )
521 EVT_SIZE( wxCanvas::OnSize )
522 EVT_IDLE( wxCanvas::OnIdle )
523 EVT_MOUSE_EVENTS( wxCanvas::OnMouse )
524 EVT_SET_FOCUS( wxCanvas::OnSetFocus )
525 EVT_KILL_FOCUS( wxCanvas::OnKillFocus )
526 END_EVENT_TABLE()
527
528 wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
529 const wxPoint &position, const wxSize& size, long style ) :
530 wxScrolledWindow( parent, id, position, size, style )
531 {
532 m_needUpdate = FALSE;
533 m_objects.DeleteContents( TRUE );
534 m_red = 0;
535 m_green = 0;
536 m_blue = 0;
537 m_lastMouse = (wxCanvasObject*)NULL;
538 m_captureMouse = (wxCanvasObject*)NULL;
539 m_frozen = FALSE;
540 }
541
542 wxCanvas::~wxCanvas()
543 {
544 wxNode *node = m_updateRects.First();
545 while (node)
546 {
547 wxRect *rect = (wxRect*) node->Data();
548 delete rect;
549 m_updateRects.DeleteNode( node );
550 node = m_updateRects.First();
551 }
552 }
553
554 void wxCanvas::SetArea( int width, int height )
555 {
556 m_buffer = wxImage( width, height );
557 SetScrollbars( 10, 10, width/10, height/10 );
558 }
559
560 void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char blue )
561 {
562 m_red = red;
563 m_green = green;
564 m_blue = blue;
565
566 if (m_frozen) return;
567
568 unsigned char *data = m_buffer.GetData();
569
570 for (int y = 0; y < m_buffer.GetHeight(); y++)
571 for (int x = 0; x < m_buffer.GetWidth(); x++)
572 {
573 data[0] = red;
574 data++;
575 data[0] = green;
576 data++;
577 data[0] = blue;
578 data++;
579 }
580 }
581
582 void wxCanvas::CaptureMouse( wxCanvasObject *obj )
583 {
584 wxWindow::CaptureMouse();
585 m_captureMouse = obj;
586 }
587
588 void wxCanvas::ReleaseMouse()
589 {
590 m_captureMouse = (wxCanvasObject*) NULL;
591 wxWindow::ReleaseMouse();
592 }
593
594 void wxCanvas::Freeze()
595 {
596 m_frozen = TRUE;
597 }
598
599 void wxCanvas::Thaw()
600 {
601 wxNode *node = m_updateRects.First();
602 while (node)
603 {
604 wxRect *rect = (wxRect*) node->Data();
605 delete rect;
606 m_updateRects.DeleteNode( node );
607 node = m_updateRects.First();
608 }
609
610 m_frozen = FALSE;
611
612 Update( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() );
613 }
614
615 void wxCanvas::Update( int x, int y, int width, int height )
616 {
617 if (m_frozen) return;
618
619 // clip to buffer
620 if (x < 0)
621 {
622 width -= x;
623 x = 0;
624 }
625 if (width < 0) return;
626
627 if (y < 0)
628 {
629 height -= y;
630 y = 0;
631 }
632 if (height < 0) return;
633
634 if (x+width > m_buffer.GetWidth())
635 {
636 width = m_buffer.GetWidth() - x;
637 }
638 if (width < 0) return;
639
640 if (y+height > m_buffer.GetHeight())
641 {
642 height = m_buffer.GetHeight() - y;
643 }
644 if (height < 0) return;
645
646 // update is within the buffer
647 m_needUpdate = TRUE;
648
649 // has to be blitted to screen later
650 m_updateRects.Append(
651 (wxObject*) new wxRect( x,y,width,height ) );
652
653 // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b)
654 for (int yy = y; yy < y+height; yy++)
655 for (int xx = x; xx < x+width; xx++)
656 m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue );
657
658 // cycle through all objects
659 wxNode *node = m_objects.First();
660 while (node)
661 {
662 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
663
664 if (!obj->IsControl())
665 {
666 // If we have 10.000 objects, we will go through
667 // this 10.000 times for each update, so we have
668 // to optimise carefully.
669 int clip_x = obj->GetX();
670 int clip_width = obj->GetWidth();
671 if (clip_x < x)
672 {
673 clip_width -= x-clip_x;
674 clip_x = x;
675 }
676 if (clip_width > 0)
677 {
678 if (clip_x + clip_width > x + width)
679 clip_width = x+width-clip_x;
680
681 if (clip_width > 0)
682 {
683 int clip_y = obj->GetY();
684 int clip_height = obj->GetHeight();
685 if (clip_y < y)
686 {
687 clip_height -= y-clip_y;
688 clip_y = y;
689 }
690 if (clip_height > 0)
691 {
692 if (clip_y + clip_height > y + height)
693 clip_height = y+height-clip_y;
694
695 if (clip_height > 0)
696 obj->Render( clip_x, clip_y, clip_width, clip_height );
697 }
698 }
699 }
700 }
701
702 node = node->Next();
703 }
704 }
705
706 void wxCanvas::BlitBuffer( wxDC &dc )
707 {
708 wxNode *node = m_updateRects.First();
709 while (node)
710 {
711 wxRect *rect = (wxRect*) node->Data();
712 wxImage sub_image( m_buffer.GetSubImage( *rect ) );
713
714 // DirectDraw here, please
715
716 #ifdef __WXGTK__
717 int bpp = wxDisplayDepth();
718 if (bpp > 8)
719 {
720 // the init code is doubled in wxImage
721 static bool s_hasInitialized = FALSE;
722
723 if (!s_hasInitialized)
724 {
725 gdk_rgb_init();
726 s_hasInitialized = TRUE;
727 }
728
729 int x = rect->x;
730 int y = rect->y;
731 CalcScrolledPosition( x, y, &x, &y );
732
733 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow)->bin_window,
734 m_wxwindow->style->black_gc,
735 x, y,
736 sub_image.GetWidth(), sub_image.GetHeight(),
737 GDK_RGB_DITHER_NONE,
738 sub_image.GetData(),
739 sub_image.GetWidth()*3 );
740 }
741 else
742 {
743 wxBitmap bitmap( sub_image.ConvertToBitmap() );
744 dc.DrawBitmap( bitmap, rect->x, rect->y );
745 }
746 #endif
747
748 #ifndef __WXGTK__
749 wxBitmap bitmap( sub_image.ConvertToBitmap() );
750 dc.DrawBitmap( bitmap, rect->x, rect->y );
751 #endif
752
753 delete rect;
754 m_updateRects.DeleteNode( node );
755 node = m_updateRects.First();
756 }
757
758 m_needUpdate = FALSE;
759 }
760
761 void wxCanvas::UpdateNow()
762 {
763 if (!m_needUpdate) return;
764
765 wxClientDC dc( this );
766 PrepareDC( dc );
767
768 BlitBuffer( dc );
769 }
770
771 int wxCanvas::GetDeviceX( double x )
772 {
773 return (int) x;
774 }
775
776 int wxCanvas::GetDeviceY( double y )
777 {
778 return (int) y;
779 }
780
781 int wxCanvas::GetDeviceWidth( double width )
782 {
783 return (int) width;
784 }
785
786 int wxCanvas::GetDeviceHeight( double height )
787 {
788 return (int) height;
789 }
790
791 void wxCanvas::Recreate()
792 {
793 wxNode *node = m_objects.First();
794 while (node)
795 {
796 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
797
798 obj->Recreate();
799
800 node = node->Next();
801 }
802 }
803
804 void wxCanvas::Prepend( wxCanvasObject* obj )
805 {
806 m_objects.Insert( obj );
807
808 obj->SetOwner( this );
809 obj->Recreate();
810
811 if (!obj->IsControl())
812 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
813 }
814
815 void wxCanvas::Append( wxCanvasObject* obj )
816 {
817 m_objects.Append( obj );
818
819 obj->SetOwner( this );
820 obj->Recreate();
821
822 if (!obj->IsControl())
823 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
824 }
825
826 void wxCanvas::Insert( size_t before, wxCanvasObject* obj )
827 {
828 m_objects.Insert( before, obj );
829
830 obj->SetOwner( this );
831 obj->Recreate();
832
833 if (!obj->IsControl())
834 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
835 }
836
837 void wxCanvas::Remove( wxCanvasObject* obj )
838 {
839 int x = obj->GetX();
840 int y = obj->GetY();
841 int w = obj->GetWidth();
842 int h = obj->GetHeight();
843 bool ic = obj->IsControl();
844
845 m_objects.DeleteObject( obj );
846
847 if (!ic)
848 Update( x, y, w, h );
849 }
850
851 void wxCanvas::OnPaint(wxPaintEvent &event)
852 {
853 wxPaintDC dc(this);
854 PrepareDC( dc );
855
856 m_needUpdate = TRUE;
857
858 wxRegionIterator it( GetUpdateRegion() );
859 while (it)
860 {
861 int x = it.GetX();
862 int y = it.GetY();
863 CalcUnscrolledPosition( x, y, &x, &y );
864
865 int w = it.GetWidth();
866 int h = it.GetHeight();
867
868 if (x+w > m_buffer.GetWidth())
869 w = m_buffer.GetWidth() - x;
870 if (y+h > m_buffer.GetHeight())
871 h = m_buffer.GetHeight() - y;
872
873 if ((w > 0) && (h > 0))
874 m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) );
875
876 it++;
877 }
878
879 BlitBuffer( dc );
880 }
881
882 void wxCanvas::OnMouse(wxMouseEvent &event)
883 {
884 // should we implement mouse capture ?
885
886 int x = event.GetX();
887 int y = event.GetY();
888 CalcUnscrolledPosition( x, y, &x, &y );
889
890 if (event.GetEventType() == wxEVT_MOTION)
891 {
892 wxNode *node = m_objects.Last();
893 while (node)
894 {
895 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
896
897 if (!obj->IsControl())
898 {
899 if (obj->IsHit(x,y))
900 {
901 wxMouseEvent child_event( wxEVT_MOTION );
902 child_event.SetEventObject( obj );
903 child_event.m_x = x - obj->GetX();
904 child_event.m_y = y - obj->GetY();
905 child_event.m_leftDown = event.m_leftDown;
906 child_event.m_rightDown = event.m_rightDown;
907 child_event.m_middleDown = event.m_middleDown;
908 child_event.m_controlDown = event.m_controlDown;
909 child_event.m_shiftDown = event.m_shiftDown;
910 child_event.m_altDown = event.m_altDown;
911 child_event.m_metaDown = event.m_metaDown;
912
913 if ((obj != m_lastMouse) && (m_lastMouse != NULL))
914 {
915 child_event.SetEventType( wxEVT_LEAVE_WINDOW );
916 child_event.SetEventObject( m_lastMouse );
917 child_event.m_x = x - m_lastMouse->GetX();
918 child_event.m_y = y - m_lastMouse->GetY();
919 m_lastMouse->ProcessEvent( child_event );
920
921 m_lastMouse = obj;
922 child_event.SetEventType( wxEVT_ENTER_WINDOW );
923 child_event.SetEventObject( m_lastMouse );
924 child_event.m_x = x - m_lastMouse->GetX();
925 child_event.m_y = y - m_lastMouse->GetY();
926 m_lastMouse->ProcessEvent( child_event );
927
928 child_event.SetEventType( wxEVT_MOTION );
929 child_event.SetEventObject( obj );
930 }
931 obj->ProcessEvent( child_event );
932 return;
933 }
934 }
935 node = node->Previous();
936 }
937 if (m_lastMouse)
938 {
939 wxMouseEvent child_event( wxEVT_LEAVE_WINDOW );
940 child_event.SetEventObject( m_lastMouse );
941 child_event.m_x = x - m_lastMouse->GetX();
942 child_event.m_y = y - m_lastMouse->GetY();
943 child_event.m_leftDown = event.m_leftDown;
944 child_event.m_rightDown = event.m_rightDown;
945 child_event.m_middleDown = event.m_middleDown;
946 child_event.m_controlDown = event.m_controlDown;
947 child_event.m_shiftDown = event.m_shiftDown;
948 child_event.m_altDown = event.m_altDown;
949 child_event.m_metaDown = event.m_metaDown;
950 m_lastMouse->ProcessEvent( child_event );
951
952 m_lastMouse = (wxCanvasObject*) NULL;
953 return;
954 }
955 }
956 event.Skip();
957 }
958
959 void wxCanvas::OnSize(wxSizeEvent &event)
960 {
961 event.Skip();
962 }
963
964 void wxCanvas::OnIdle(wxIdleEvent &event)
965 {
966 UpdateNow();
967 event.Skip();
968 }
969
970 void wxCanvas::OnSetFocus(wxFocusEvent &event)
971 {
972 }
973
974 void wxCanvas::OnKillFocus(wxFocusEvent &event)
975 {
976 }
977
978 void wxCanvas::OnChar(wxKeyEvent &event)
979 {
980 event.Skip();
981 }
982
983 //--------------------------------------------------------------------
984 // wxCanvasModule
985 //--------------------------------------------------------------------
986
987 class wxCanvasModule : public wxModule
988 {
989 public:
990 virtual bool OnInit();
991 virtual void OnExit();
992
993 private:
994 DECLARE_DYNAMIC_CLASS(wxCanvasModule)
995 };
996
997 IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule)
998
999 bool wxCanvasModule::OnInit()
1000 {
1001 #if wxUSE_FREETYPE
1002 int error = FT_Init_FreeType( &g_freetypeLibrary );
1003 if (error) return FALSE;
1004 #endif
1005
1006 return TRUE;
1007 }
1008
1009 void wxCanvasModule::OnExit()
1010 {
1011 #if wxUSE_FREETYPE
1012 FT_Done_FreeType( g_freetypeLibrary );
1013 #endif
1014 }