]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/canvas/canvas.cpp
Added various missing bits to scrolling wxCanvas.
[wxWidgets.git] / contrib / src / canvas / canvas.cpp
CommitLineData
6a2c1874
RR
1/////////////////////////////////////////////////////////////////////////////
2// Name: canvas.cpp
3// Author: Robert Roebling
4// Created: XX/XX/XX
5// Copyright: 2000 (c) Robert Roebling
6// Licence: wxWindows Licence
7/////////////////////////////////////////////////////////////////////////////
8
9#ifdef __GNUG__
10 #pragma implementation "canvas.cpp"
11#endif
12
13// For compilers that support precompilation, includes "wx/wx.h".
14#include "wx/wxprec.h"
15
16#ifdef __BORLANDC__
17 #pragma hdrstop
18#endif
19
20#include "wx/canvas/canvas.h"
21
22#ifdef __WXGTK__
23 #include <gtk/gtk.h>
24 #include <gdk/gdkrgb.h>
25 #include "wx/gtk/win_gtk.h"
26#endif
27
1e1af41e
RR
28#ifndef wxUSE_FREETYPE
29 #define wxUSE_FREETYPE 1
30#endif
d1f9b206 31
1e1af41e
RR
32#if wxUSE_FREETYPE
33 #include <freetype/freetype.h>
d1f9b206
RR
34#endif
35
36//----------------------------------------------------------------------------
37// globals
38//----------------------------------------------------------------------------
39
1e1af41e 40#if wxUSE_FREETYPE
d1f9b206
RR
41FT_Library g_freetypeLibrary;
42#endif
6a2c1874
RR
43
44//----------------------------------------------------------------------------
45// wxCanvasObject
46//----------------------------------------------------------------------------
47
4dbd4ee6 48wxCanvasObject::wxCanvasObject()
6a2c1874
RR
49{
50 m_owner = NULL;
4dbd4ee6
RR
51 m_area.x = -1;
52 m_area.y = -1;
53 m_area.width = -1;
54 m_area.height = -1;
55 m_isControl = FALSE;
56 m_isVector = FALSE;
57 m_isImage = FALSE;
58}
59
60void wxCanvasObject::SetArea( int x, int y, int width, int height )
61{
6a2c1874
RR
62 m_area.x = x;
63 m_area.y = y;
64 m_area.width = width;
65 m_area.height = height;
4dbd4ee6
RR
66}
67
68void wxCanvasObject::SetArea( wxRect rect )
69{
70 m_area.x = rect.x;
71 m_area.y = rect.y;
72 m_area.width = rect.width;
73 m_area.height = rect.height;
6a2c1874
RR
74}
75
76void wxCanvasObject::Move( int x, int y )
77{
78 int old_x = m_area.x;
79 int old_y = m_area.y;
dc16900b 80
6a2c1874
RR
81 m_area.x = x;
82 m_area.y = y;
dc16900b 83
6a2c1874
RR
84 if (!m_isControl)
85 {
86 // TODO: sometimes faster to merge into 1 Update or
87 // to break up into four
88 m_owner->Update( old_x, old_y, m_area.width, m_area.height );
89 m_owner->Update( x, y, m_area.width, m_area.height );
90 }
91}
92
239c1f50
RR
93bool wxCanvasObject::IsHit( int x, int y, int margin )
94{
95 return ((x >= m_area.x-margin) &&
96 (x <= m_area.x+m_area.width+margin) &&
97 (y >= m_area.y-margin) &&
98 (y <= m_area.y+m_area.height+margin));
99}
100
dc16900b
KH
101void wxCanvasObject::CaptureMouse()
102{
103 m_owner->SetCaptureMouse( this );
104}
105
106void wxCanvasObject::ReleaseMouse()
107{
108 m_owner->SetCaptureMouse( NULL );
109}
110
111bool wxCanvasObject::IsCapturedMouse()
112{
113 return m_owner->m_captureMouse==this;
114}
115
116
1e1af41e 117void wxCanvasObject::Render( int clip_x, int clip_y, int clip_width, int clip_height )
6a2c1874
RR
118{
119}
120
4dbd4ee6 121void wxCanvasObject::Recreate()
1e1af41e
RR
122{
123}
124
125void wxCanvasObject::WriteSVG( wxTextOutputStream &stream )
6a2c1874
RR
126{
127}
128
21544859
RR
129//----------------------------------------------------------------------------
130// wxCanvasRect
131//----------------------------------------------------------------------------
132
dc16900b 133wxCanvasRect::wxCanvasRect( double x, double y, double w, double h,
4dbd4ee6
RR
134 unsigned char red, unsigned char green, unsigned char blue )
135 : wxCanvasObject()
21544859 136{
4dbd4ee6
RR
137 m_x = x;
138 m_y = y;
139 m_width = w;
140 m_height = h;
dc16900b 141
21544859
RR
142 m_red = red;
143 m_green = green;
144 m_blue = blue;
145}
146
4dbd4ee6
RR
147void 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
21544859
RR
155void wxCanvasRect::Render( int clip_x, int clip_y, int clip_width, int clip_height )
156{
157 wxImage *image = m_owner->GetBuffer();
41328253
RR
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
21544859 167 // speed up later
41328253
RR
168 for (int y = start_y; y < end_y; y++)
169 for (int x = start_x; x < end_x; x++)
21544859
RR
170 image->SetRGB( x, y, m_red, m_green, m_blue );
171}
172
173void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
174{
175}
176
239c1f50
RR
177//----------------------------------------------------------------------------
178// wxCanvasLine
179//----------------------------------------------------------------------------
180
4dbd4ee6
RR
181wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2,
182 unsigned char red, unsigned char green, unsigned char blue )
183 : wxCanvasObject()
239c1f50 184{
4dbd4ee6
RR
185 m_x1 = x1;
186 m_y1 = y1;
187 m_x2 = x2;
188 m_y2 = y2;
189
239c1f50
RR
190 m_red = red;
191 m_green = green;
192 m_blue = blue;
193}
194
4dbd4ee6
RR
195void 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
239c1f50
RR
216void wxCanvasLine::Render( int clip_x, int clip_y, int clip_width, int clip_height )
217{
218 wxImage *image = m_owner->GetBuffer();
41328253
RR
219 int buffer_x = m_owner->GetBufferX();
220 int buffer_y = m_owner->GetBufferY();
61b64bd9 221
239c1f50
RR
222 if ((m_area.width == 0) && (m_area.height == 0))
223 {
41328253 224 image->SetRGB( m_area.x-buffer_x, m_area.y-buffer_y, m_red, m_green, m_blue );
239c1f50
RR
225 }
226 else
227 {
4dbd4ee6
RR
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 );
239c1f50
RR
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;
dc16900b 243
239c1f50
RR
244 if (ai > aj)
245 {
246 // iterate over i
dc16900b
KH
247 d = aj - (ai >> 1);
248
239c1f50
RR
249 while (ii != x1)
250 {
61b64bd9
RR
251 if ((ii >= clip_x) && (ii < clip_x+clip_width) &&
252 (jj >= clip_y) && (jj < clip_y+clip_height))
239c1f50 253 {
41328253 254 image->SetRGB( ii-buffer_x, jj-buffer_y, m_red, m_blue, m_green );
239c1f50
RR
255 }
256 if (d >= 0)
257 {
258 jj += sj;
dc16900b 259 d -= ai;
239c1f50
RR
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 {
61b64bd9
RR
272 if ((ii >= clip_x) && (ii < clip_x+clip_width) &&
273 (jj >= clip_y) && (jj < clip_y+clip_height))
239c1f50 274 {
41328253 275 image->SetRGB( ii-buffer_x, jj-buffer_y, m_red, m_blue, m_green );
239c1f50
RR
276 }
277 if (d >= 0)
278 {
279 ii += si;
dc16900b 280 d -= aj;
239c1f50
RR
281 }
282 jj += sj;
283 d += ai;
284 }
285 }
286 }
287}
288
289void wxCanvasLine::WriteSVG( wxTextOutputStream &stream )
290{
1e1af41e 291 // no idea
239c1f50
RR
292}
293
6a2c1874
RR
294//----------------------------------------------------------------------------
295// wxCanvasImage
296//----------------------------------------------------------------------------
297
4dbd4ee6
RR
298wxCanvasImage::wxCanvasImage( const wxImage &image, double x, double y, double w, double h )
299 : wxCanvasObject()
6a2c1874 300{
4dbd4ee6
RR
301 m_x = x;
302 m_y = y;
303 m_width = w;
304 m_height = h;
dc16900b 305
6a2c1874
RR
306 m_image = image;
307 m_isImage = TRUE;
308}
309
4dbd4ee6
RR
310void 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 ) );
dc16900b 316
4dbd4ee6
RR
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
6a2c1874
RR
324void wxCanvasImage::Render( int clip_x, int clip_y, int clip_width, int clip_height )
325{
41328253
RR
326 int buffer_x = m_owner->GetBufferX();
327 int buffer_y = m_owner->GetBufferY();
328
dc16900b
KH
329 if ((clip_x == m_area.x) &&
330 (clip_y == m_area.y) &&
21544859
RR
331 (clip_width == m_area.width) &&
332 (clip_height == m_area.height))
d1f9b206 333 {
41328253 334 m_owner->GetBuffer()->Paste( m_tmp, clip_x-buffer_x, clip_y-buffer_y );
d1f9b206
RR
335 }
336 else
337 {
21544859
RR
338 // local coordinates
339 int start_x = clip_x - m_area.x;
340 int start_y = clip_y - m_area.y;
dc16900b 341
21544859 342 wxRect rect( start_x, start_y, clip_width, clip_height );
4dbd4ee6 343 wxImage sub_image( m_tmp.GetSubImage( rect ) );
41328253 344 m_owner->GetBuffer()->Paste( sub_image, clip_x-buffer_x, clip_y-buffer_y );
d1f9b206 345 }
6a2c1874
RR
346}
347
348void wxCanvasImage::WriteSVG( wxTextOutputStream &stream )
349{
350 // no idea
351}
352
3b111dbe
RR
353//----------------------------------------------------------------------------
354// wxCanvasCtrl
355//----------------------------------------------------------------------------
356
357wxCanvasControl::wxCanvasControl( wxWindow *control )
4dbd4ee6 358 : wxCanvasObject()
3b111dbe 359{
21544859 360 m_isControl = TRUE;
3b111dbe 361 m_control = control;
3b111dbe
RR
362}
363
364wxCanvasControl::~wxCanvasControl()
365{
366 m_control->Destroy();
367}
368
4dbd4ee6 369void wxCanvasControl::Recreate()
3b111dbe 370{
4dbd4ee6
RR
371 m_control->GetSize( &m_area.width, &m_area.height );
372 m_control->GetPosition( &m_area.x, &m_area.y );
3b111dbe
RR
373}
374
4dbd4ee6 375void wxCanvasControl::Move( int x, int y )
3b111dbe 376{
4dbd4ee6 377 m_control->Move( x, y );
3b111dbe
RR
378}
379
d1f9b206
RR
380//----------------------------------------------------------------------------
381// wxCanvasText
382//----------------------------------------------------------------------------
383
384class wxFaceData
385{
386public:
1e1af41e 387#if wxUSE_FREETYPE
d1f9b206
RR
388 FT_Face m_face;
389#else
390 void *m_dummy;
dc16900b 391#endif
d1f9b206
RR
392};
393
4dbd4ee6
RR
394wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxString &fontFile, int size )
395 : wxCanvasObject()
d1f9b206
RR
396{
397 m_text = text;
cb281cfc
RR
398 m_fontFileName = fontFile;
399 m_size = size;
dc16900b 400
cb281cfc 401 m_red = 0;
d1f9b206
RR
402 m_green = 0;
403 m_blue = 0;
dc16900b 404
4dbd4ee6 405 m_alpha = NULL;
dc16900b 406
4dbd4ee6
RR
407 m_x = x;
408 m_y = y;
dc16900b
KH
409
410#if wxUSE_FREETYPE
d1f9b206
RR
411 wxFaceData *data = new wxFaceData;
412 m_faceData = data;
dc16900b 413
d1f9b206 414 int error = FT_New_Face( g_freetypeLibrary,
cb281cfc 415 m_fontFileName,
d1f9b206
RR
416 0,
417 &(data->m_face) );
418
419 error = FT_Set_Char_Size( data->m_face,
420 0,
cb281cfc
RR
421 m_size*64,
422 96, // screen dpi
d1f9b206
RR
423 96 );
424#endif
425}
426
427wxCanvasText::~wxCanvasText()
428{
1e1af41e 429#if wxUSE_FREETYPE
d1f9b206
RR
430 wxFaceData *data = (wxFaceData*) m_faceData;
431 delete data;
432#endif
433
434 if (m_alpha) delete [] m_alpha;
435}
436
437void 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
444void wxCanvasText::SetFlag( int flag )
445{
446 m_flag = flag;
447}
448
449void 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();
41328253
RR
454 int buffer_x = m_owner->GetBufferX();
455 int buffer_y = m_owner->GetBufferY();
d1f9b206 456
21544859
RR
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;
d1f9b206
RR
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 {
41328253
RR
469 int image_x = m_area.x+x - buffer_x;
470 int image_y = m_area.y+y - buffer_y;
cb281cfc 471 if (alpha == 255)
d1f9b206
RR
472 {
473 image->SetRGB( image_x, image_y, m_red, m_green, m_blue );
474 continue;
475 }
cb281cfc
RR
476 int red1 = (m_red * alpha) / 255;
477 int green1 = (m_green * alpha) / 255;
478 int blue1 = (m_blue * alpha) / 255;
dc16900b 479
cb281cfc 480 alpha = 255-alpha;
d1f9b206
RR
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 );
cb281cfc
RR
484 red2 = (red2 * alpha) / 255;
485 green2 = (green2 * alpha) / 255;
486 blue2 = (blue2 * alpha) / 255;
d1f9b206
RR
487
488 image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
489 }
490 }
491}
492
493void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
494{
495}
496
4dbd4ee6 497void wxCanvasText::Recreate()
d1f9b206 498{
4dbd4ee6 499 if (m_alpha) delete [] m_alpha;
dc16900b 500
4dbd4ee6
RR
501 m_area.x = m_owner->GetDeviceX( m_x );
502 m_area.y = m_owner->GetDeviceY( m_y );
dc16900b 503
4dbd4ee6
RR
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
1e1af41e 509#if wxUSE_FREETYPE
d1f9b206
RR
510 FT_Face face = ((wxFaceData*)m_faceData)->m_face;
511 FT_GlyphSlot slot = face->glyph;
512 int pen_x = 0;
cb281cfc 513 int pen_y = m_size;
d1f9b206 514
cb281cfc 515 for (int n = 0; n < (int)m_text.Len(); n++)
d1f9b206
RR
516 {
517 FT_UInt index = FT_Get_Char_Index( face, m_text[n] );
dc16900b 518
d1f9b206
RR
519 int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
520 if (error) continue;
521
cb281cfc 522 error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
d1f9b206
RR
523 if (error) continue;
524
cb281cfc
RR
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;
dc16900b 532
cb281cfc
RR
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
d1f9b206
RR
538 pen_x += slot->advance.x >> 6;
539 pen_y += slot->advance.y >> 6;
540 }
541#endif
542}
543
6a2c1874
RR
544//----------------------------------------------------------------------------
545// wxCanvas
546//----------------------------------------------------------------------------
547
548IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow)
549
550BEGIN_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 )
61b64bd9 558 EVT_ERASE_BACKGROUND( wxCanvas::OnEraseBackground )
6a2c1874
RR
559END_EVENT_TABLE()
560
561wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
562 const wxPoint &position, const wxSize& size, long style ) :
563 wxScrolledWindow( parent, id, position, size, style )
564{
41328253
RR
565 m_bufferX = 0;
566 m_bufferY = 0;
6a2c1874
RR
567 m_needUpdate = FALSE;
568 m_objects.DeleteContents( TRUE );
cb281cfc
RR
569 m_red = 0;
570 m_green = 0;
571 m_blue = 0;
239c1f50 572 m_lastMouse = (wxCanvasObject*)NULL;
4dbd4ee6 573 m_captureMouse = (wxCanvasObject*)NULL;
41328253
RR
574 m_frozen = TRUE;
575 m_requestNewBuffer = TRUE;
6a2c1874
RR
576}
577
578wxCanvas::~wxCanvas()
579{
580 wxNode *node = m_updateRects.First();
581 while (node)
582 {
583 wxRect *rect = (wxRect*) node->Data();
584 delete rect;
585 m_updateRects.DeleteNode( node );
586 node = m_updateRects.First();
587 }
588}
589
590void wxCanvas::SetArea( int width, int height )
591{
6a2c1874
RR
592 SetScrollbars( 10, 10, width/10, height/10 );
593}
594
cb281cfc
RR
595void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char blue )
596{
597 m_red = red;
598 m_green = green;
599 m_blue = blue;
dc16900b 600
61b64bd9
RR
601 SetBackgroundColour( wxColour( red, green, blue ) );
602
239c1f50 603 if (m_frozen) return;
dc16900b 604
cb281cfc 605 unsigned char *data = m_buffer.GetData();
dc16900b 606
cb281cfc
RR
607 for (int y = 0; y < m_buffer.GetHeight(); y++)
608 for (int x = 0; x < m_buffer.GetWidth(); x++)
609 {
610 data[0] = red;
611 data++;
612 data[0] = green;
613 data++;
614 data[0] = blue;
615 data++;
616 }
617}
618
dc16900b 619void wxCanvas::SetCaptureMouse( wxCanvasObject *obj )
4dbd4ee6 620{
dc16900b
KH
621 if (obj)
622 {
623 wxWindow::CaptureMouse();
624 m_captureMouse = obj;
625 }
626 else
627 {
628 wxWindow::ReleaseMouse();
629 m_captureMouse = NULL;
630 }
4dbd4ee6
RR
631}
632
239c1f50
RR
633void wxCanvas::Freeze()
634{
635 m_frozen = TRUE;
636}
637
638void wxCanvas::Thaw()
639{
640 wxNode *node = m_updateRects.First();
641 while (node)
642 {
643 wxRect *rect = (wxRect*) node->Data();
644 delete rect;
645 m_updateRects.DeleteNode( node );
646 node = m_updateRects.First();
647 }
dc16900b 648
239c1f50 649 m_frozen = FALSE;
dc16900b 650
41328253
RR
651 if (m_buffer.Ok())
652 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight() );
239c1f50
RR
653}
654
41328253 655void wxCanvas::Update( int x, int y, int width, int height, bool blit )
6a2c1874 656{
239c1f50 657 if (m_frozen) return;
41328253 658
21544859 659 // clip to buffer
41328253 660 if (x < m_bufferX)
21544859 661 {
41328253
RR
662 width -= m_bufferX-x;
663 x = m_bufferX;
21544859
RR
664 }
665 if (width < 0) return;
dc16900b 666
41328253 667 if (y < m_bufferY)
21544859 668 {
41328253
RR
669 height -= m_bufferY-y;
670 y = m_bufferY;
21544859
RR
671 }
672 if (height < 0) return;
dc16900b 673
41328253 674 if (x+width > m_bufferX+m_buffer.GetWidth())
21544859 675 {
41328253 676 width = m_bufferX+m_buffer.GetWidth() - x;
21544859
RR
677 }
678 if (width < 0) return;
dc16900b 679
41328253 680 if (y+height > m_bufferY+m_buffer.GetHeight())
21544859 681 {
41328253 682 height = m_bufferY+m_buffer.GetHeight() - y;
21544859
RR
683 }
684 if (height < 0) return;
dc16900b 685
21544859 686 // update is within the buffer
6a2c1874 687 m_needUpdate = TRUE;
dc16900b 688
21544859 689 // has to be blitted to screen later
41328253
RR
690 if (blit)
691 {
692 m_updateRects.Append(
693 (wxObject*) new wxRect( x,y,width,height ) );
694 }
dc16900b 695
21544859 696 // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b)
41328253
RR
697 int start_y = y - m_bufferY;
698 int end_y = y+height - m_bufferY;
699 int start_x = x - m_bufferX;
700 int end_x = x+width - m_bufferX;
701 for (int yy = start_y; yy < end_y; yy++)
702 for (int xx = start_x; xx < end_x; xx++)
cb281cfc 703 m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue );
6a2c1874 704
21544859 705 // cycle through all objects
6a2c1874
RR
706 wxNode *node = m_objects.First();
707 while (node)
708 {
709 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
dc16900b 710
21544859 711 if (!obj->IsControl())
6a2c1874 712 {
21544859
RR
713 // If we have 10.000 objects, we will go through
714 // this 10.000 times for each update, so we have
715 // to optimise carefully.
716 int clip_x = obj->GetX();
717 int clip_width = obj->GetWidth();
718 if (clip_x < x)
719 {
720 clip_width -= x-clip_x;
721 clip_x = x;
722 }
723 if (clip_width > 0)
724 {
725 if (clip_x + clip_width > x + width)
726 clip_width = x+width-clip_x;
dc16900b 727
21544859
RR
728 if (clip_width > 0)
729 {
730 int clip_y = obj->GetY();
731 int clip_height = obj->GetHeight();
732 if (clip_y < y)
733 {
734 clip_height -= y-clip_y;
735 clip_y = y;
736 }
737 if (clip_height > 0)
738 {
739 if (clip_y + clip_height > y + height)
740 clip_height = y+height-clip_y;
dc16900b 741
21544859
RR
742 if (clip_height > 0)
743 obj->Render( clip_x, clip_y, clip_width, clip_height );
744 }
745 }
746 }
6a2c1874 747 }
dc16900b 748
6a2c1874
RR
749 node = node->Next();
750 }
751}
752
3b111dbe 753void wxCanvas::BlitBuffer( wxDC &dc )
6a2c1874 754{
6a2c1874
RR
755 wxNode *node = m_updateRects.First();
756 while (node)
757 {
758 wxRect *rect = (wxRect*) node->Data();
6a2c1874 759
41328253
RR
760 wxRect sub_rect( *rect );
761 sub_rect.x -= m_bufferX;
762 sub_rect.y -= m_bufferY;
763
764 wxImage sub_image( m_buffer.GetSubImage( sub_rect ) );
6a2c1874
RR
765
766#ifdef __WXGTK__
dc16900b 767 int bpp = wxDisplayDepth();
6a2c1874
RR
768 if (bpp > 8)
769 {
770 // the init code is doubled in wxImage
771 static bool s_hasInitialized = FALSE;
772
773 if (!s_hasInitialized)
774 {
775 gdk_rgb_init();
776 s_hasInitialized = TRUE;
777 }
dc16900b 778
6a2c1874
RR
779 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow)->bin_window,
780 m_wxwindow->style->black_gc,
41328253 781 sub_rect.x, sub_rect.y,
6a2c1874
RR
782 sub_image.GetWidth(), sub_image.GetHeight(),
783 GDK_RGB_DITHER_NONE,
784 sub_image.GetData(),
785 sub_image.GetWidth()*3 );
786 }
787 else
788 {
789 wxBitmap bitmap( sub_image.ConvertToBitmap() );
790 dc.DrawBitmap( bitmap, rect->x, rect->y );
791 }
792#endif
793
794#ifndef __WXGTK__
795 wxBitmap bitmap( sub_image.ConvertToBitmap() );
796 dc.DrawBitmap( bitmap, rect->x, rect->y );
797#endif
dc16900b 798
6a2c1874
RR
799 delete rect;
800 m_updateRects.DeleteNode( node );
801 node = m_updateRects.First();
802 }
dc16900b 803
3b111dbe
RR
804 m_needUpdate = FALSE;
805}
806
807void wxCanvas::UpdateNow()
808{
61b64bd9
RR
809 if (m_frozen) return;
810
3b111dbe 811 if (!m_needUpdate) return;
dc16900b 812
3b111dbe
RR
813 wxClientDC dc( this );
814 PrepareDC( dc );
dc16900b 815
3b111dbe 816 BlitBuffer( dc );
6a2c1874
RR
817}
818
4dbd4ee6
RR
819int wxCanvas::GetDeviceX( double x )
820{
821 return (int) x;
822}
823
824int wxCanvas::GetDeviceY( double y )
825{
826 return (int) y;
827}
828
829int wxCanvas::GetDeviceWidth( double width )
830{
831 return (int) width;
832}
833
834int wxCanvas::GetDeviceHeight( double height )
835{
836 return (int) height;
837}
838
839void wxCanvas::Recreate()
840{
841 wxNode *node = m_objects.First();
842 while (node)
843 {
844 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
dc16900b 845
4dbd4ee6 846 obj->Recreate();
dc16900b 847
4dbd4ee6
RR
848 node = node->Next();
849 }
850}
851
6a2c1874
RR
852void wxCanvas::Prepend( wxCanvasObject* obj )
853{
854 m_objects.Insert( obj );
dc16900b 855
6a2c1874 856 obj->SetOwner( this );
4dbd4ee6 857 obj->Recreate();
dc16900b 858
6a2c1874
RR
859 if (!obj->IsControl())
860 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
861}
862
863void wxCanvas::Append( wxCanvasObject* obj )
864{
865 m_objects.Append( obj );
dc16900b 866
6a2c1874 867 obj->SetOwner( this );
4dbd4ee6 868 obj->Recreate();
dc16900b 869
6a2c1874
RR
870 if (!obj->IsControl())
871 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
872}
873
874void wxCanvas::Insert( size_t before, wxCanvasObject* obj )
875{
876 m_objects.Insert( before, obj );
dc16900b 877
6a2c1874 878 obj->SetOwner( this );
4dbd4ee6 879 obj->Recreate();
dc16900b 880
6a2c1874
RR
881 if (!obj->IsControl())
882 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
883}
884
885void wxCanvas::Remove( wxCanvasObject* obj )
886{
887 int x = obj->GetX();
888 int y = obj->GetY();
889 int w = obj->GetWidth();
890 int h = obj->GetHeight();
891 bool ic = obj->IsControl();
dc16900b 892
6a2c1874 893 m_objects.DeleteObject( obj );
dc16900b 894
6a2c1874
RR
895 if (!ic)
896 Update( x, y, w, h );
897}
898
899void wxCanvas::OnPaint(wxPaintEvent &event)
900{
6a2c1874 901 wxPaintDC dc(this);
3b111dbe 902 PrepareDC( dc );
dc16900b 903
41328253
RR
904 if (!m_buffer.Ok()) return;
905
6a2c1874
RR
906 m_needUpdate = TRUE;
907
908 wxRegionIterator it( GetUpdateRegion() );
909 while (it)
910 {
911 int x = it.GetX();
912 int y = it.GetY();
dc16900b 913
6a2c1874
RR
914 int w = it.GetWidth();
915 int h = it.GetHeight();
dc16900b 916
21544859
RR
917 if (x+w > m_buffer.GetWidth())
918 w = m_buffer.GetWidth() - x;
919 if (y+h > m_buffer.GetHeight())
920 h = m_buffer.GetHeight() - y;
dc16900b 921
21544859 922 if ((w > 0) && (h > 0))
41328253
RR
923 {
924 CalcUnscrolledPosition( x, y, &x, &y );
21544859 925 m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) );
41328253 926 }
dc16900b 927
6a2c1874
RR
928 it++;
929 }
dc16900b 930
3b111dbe 931 BlitBuffer( dc );
6a2c1874
RR
932}
933
41328253
RR
934void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
935{
61b64bd9
RR
936 // If any updates are pending, do them now since they will
937 // expect the previous m_bufferX and m_bufferY values.
41328253
RR
938 UpdateNow();
939
61b64bd9
RR
940 // The buffer always starts at the top left corner of the
941 // client area. Indeed, it is the client area.
41328253
RR
942 CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
943
944 unsigned char* data = m_buffer.GetData();
945
946 if (dy != 0)
947 {
948 if (dy > 0)
949 {
950 unsigned char *source = data;
951 unsigned char *dest = 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
61b64bd9
RR
955 // We update the new buffer area, but there is no need to
956 // blit (last param FALSE) since the ensuing paint event will
957 // do that anyway.
41328253
RR
958 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), dy, FALSE );
959 }
960 else
961 {
962 unsigned char *dest = data;
963 unsigned char *source = data + (-dy * m_buffer.GetWidth() * 3);
964 size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()+dy));
965 memmove( dest, source, count );
966
61b64bd9
RR
967 // We update the new buffer area, but there is no need to
968 // blit (last param FALSE) since the ensuing paint event will
969 // do that anyway.
41328253
RR
970 Update( m_bufferX, m_bufferY+m_buffer.GetHeight()+dy, m_buffer.GetWidth(), -dy, FALSE );
971 }
972 }
973
974 if (dx != 0)
975 {
61b64bd9
RR
976 if (dx > 0)
977 {
978 unsigned char *source = data;
979 for (int y = 0; y < m_buffer.GetHeight(); y++)
980 {
981 unsigned char *dest = source + dx*3;
982 memmove( dest, source, (m_buffer.GetWidth()-dx) * 3 );
983 source += m_buffer.GetWidth()*3;
984 }
985
986 // We update the new buffer area, but there is no need to
987 // blit (last param FALSE) since the ensuing paint event will
988 // do that anyway.
989 Update( m_bufferX, m_bufferY, dx, m_buffer.GetHeight(), FALSE );
990 }
991 else
992 {
993 unsigned char *dest = data;
994 for (int y = 0; y < m_buffer.GetHeight(); y++)
995 {
996 unsigned char *source = dest - dx*3;
997 memmove( dest, source, (m_buffer.GetWidth()+dx) * 3 );
998 dest += m_buffer.GetWidth()*3;
999 }
1000
1001 // We update the new buffer area, but there is no need to
1002 // blit (last param FALSE) since the ensuing paint event will
1003 // do that anyway.
1004 Update( m_bufferX+m_buffer.GetWidth()+dx, m_bufferY, -dx, m_buffer.GetHeight(), FALSE );
1005 }
41328253
RR
1006 }
1007
1008 wxWindow::ScrollWindow( dx, dy, rect );
1009}
1010
6a2c1874
RR
1011void wxCanvas::OnMouse(wxMouseEvent &event)
1012{
239c1f50
RR
1013 int x = event.GetX();
1014 int y = event.GetY();
1015 CalcUnscrolledPosition( x, y, &x, &y );
dc16900b 1016
239c1f50
RR
1017 if (event.GetEventType() == wxEVT_MOTION)
1018 {
dc16900b 1019 if (m_captureMouse) //no matter what go to this one
239c1f50 1020 {
dc16900b
KH
1021 wxMouseEvent child_event( wxEVT_MOTION );
1022 child_event.SetEventObject(m_captureMouse);
1023 child_event.m_x = x - m_captureMouse->GetX();
1024 child_event.m_y = y - m_captureMouse->GetY();
1025 child_event.m_leftDown = event.m_leftDown;
1026 child_event.m_rightDown = event.m_rightDown;
1027 child_event.m_middleDown = event.m_middleDown;
1028 child_event.m_controlDown = event.m_controlDown;
1029 child_event.m_shiftDown = event.m_shiftDown;
1030 child_event.m_altDown = event.m_altDown;
1031 child_event.m_metaDown = event.m_metaDown;
1032 m_captureMouse->ProcessEvent( child_event );
1033 }
1034 else
1035 {
1036 wxNode *node = m_objects.Last();
1037 while (node)
1038 {
1039 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
1040
1041 if (!obj->IsControl())
239c1f50 1042 {
dc16900b 1043 if (obj->IsHit(x,y))
239c1f50 1044 {
dc16900b 1045 wxMouseEvent child_event( wxEVT_MOTION );
239c1f50 1046 child_event.SetEventObject( obj );
dc16900b
KH
1047 child_event.m_x = x - obj->GetX();
1048 child_event.m_y = y - obj->GetY();
1049 child_event.m_leftDown = event.m_leftDown;
1050 child_event.m_rightDown = event.m_rightDown;
1051 child_event.m_middleDown = event.m_middleDown;
1052 child_event.m_controlDown = event.m_controlDown;
1053 child_event.m_shiftDown = event.m_shiftDown;
1054 child_event.m_altDown = event.m_altDown;
1055 child_event.m_metaDown = event.m_metaDown;
1056
1057 if ((obj != m_lastMouse) && (m_lastMouse != NULL))
1058 {
1059 child_event.SetEventType( wxEVT_LEAVE_WINDOW );
1060 child_event.SetEventObject( m_lastMouse );
1061 child_event.m_x = x - m_lastMouse->GetX();
1062 child_event.m_y = y - m_lastMouse->GetY();
1063 m_lastMouse->ProcessEvent( child_event );
1064
1065 m_lastMouse = obj;
1066 child_event.SetEventType( wxEVT_ENTER_WINDOW );
1067 child_event.SetEventObject( m_lastMouse );
1068 child_event.m_x = x - m_lastMouse->GetX();
1069 child_event.m_y = y - m_lastMouse->GetY();
1070 m_lastMouse->ProcessEvent( child_event );
1071
1072 child_event.SetEventType( wxEVT_MOTION );
1073 child_event.SetEventObject( obj );
1074 }
1075 obj->ProcessEvent( child_event );
1076 return;
239c1f50 1077 }
239c1f50 1078 }
dc16900b 1079 node = node->Previous();
239c1f50 1080 }
239c1f50
RR
1081 }
1082 if (m_lastMouse)
1083 {
1084 wxMouseEvent child_event( wxEVT_LEAVE_WINDOW );
1085 child_event.SetEventObject( m_lastMouse );
1e1af41e
RR
1086 child_event.m_x = x - m_lastMouse->GetX();
1087 child_event.m_y = y - m_lastMouse->GetY();
239c1f50
RR
1088 child_event.m_leftDown = event.m_leftDown;
1089 child_event.m_rightDown = event.m_rightDown;
1090 child_event.m_middleDown = event.m_middleDown;
1091 child_event.m_controlDown = event.m_controlDown;
1092 child_event.m_shiftDown = event.m_shiftDown;
1093 child_event.m_altDown = event.m_altDown;
1094 child_event.m_metaDown = event.m_metaDown;
1095 m_lastMouse->ProcessEvent( child_event );
dc16900b 1096
239c1f50
RR
1097 m_lastMouse = (wxCanvasObject*) NULL;
1098 return;
1099 }
1100 }
1101 event.Skip();
6a2c1874
RR
1102}
1103
1104void wxCanvas::OnSize(wxSizeEvent &event)
1105{
41328253
RR
1106 m_requestNewBuffer = TRUE;
1107 Freeze();
1108
6a2c1874
RR
1109 event.Skip();
1110}
1111
1112void wxCanvas::OnIdle(wxIdleEvent &event)
1113{
41328253
RR
1114 if (m_requestNewBuffer)
1115 {
1116 m_requestNewBuffer = FALSE;
1117
1118 int w,h;
1119 GetClientSize( &w, &h );
1120 m_buffer = wxImage( w, h );
1121
1122 CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
1123
1124 Thaw();
1125 }
1126
6a2c1874
RR
1127 UpdateNow();
1128 event.Skip();
1129}
1130
1131void wxCanvas::OnSetFocus(wxFocusEvent &event)
1132{
1133}
1134
1135void wxCanvas::OnKillFocus(wxFocusEvent &event)
1136{
1137}
1138
1139void wxCanvas::OnChar(wxKeyEvent &event)
1140{
1141 event.Skip();
1142}
1143
61b64bd9
RR
1144void wxCanvas::OnEraseBackground(wxEraseEvent &event)
1145{
1146}
1147
d1f9b206
RR
1148//--------------------------------------------------------------------
1149// wxCanvasModule
1150//--------------------------------------------------------------------
1151
1152class wxCanvasModule : public wxModule
1153{
1154public:
1155 virtual bool OnInit();
1156 virtual void OnExit();
1157
1158private:
1159 DECLARE_DYNAMIC_CLASS(wxCanvasModule)
1160};
1161
1162IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule)
6a2c1874 1163
d1f9b206
RR
1164bool wxCanvasModule::OnInit()
1165{
1e1af41e 1166#if wxUSE_FREETYPE
d1f9b206
RR
1167 int error = FT_Init_FreeType( &g_freetypeLibrary );
1168 if (error) return FALSE;
1169#endif
1170
1171 return TRUE;
1172}
1173
1174void wxCanvasModule::OnExit()
1175{
1e1af41e 1176#if wxUSE_FREETYPE
cb281cfc 1177 FT_Done_FreeType( g_freetypeLibrary );
d1f9b206
RR
1178#endif
1179}