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