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