]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/canvas/canvas.cpp
Made geometry classes link.
[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
f9032263
RR
20#include "wx/canvas/canvas.h"
21#include "wx/canvas/polygon.h"
22#include "wx/canvas/liner.h"
6a2c1874
RR
23
24#ifdef __WXGTK__
25 #include <gtk/gtk.h>
26 #include <gdk/gdkrgb.h>
27 #include "wx/gtk/win_gtk.h"
28#endif
29
1e1af41e 30#ifndef wxUSE_FREETYPE
84fba40b 31 #define wxUSE_FREETYPE 0
1e1af41e 32#endif
d1f9b206 33
1e1af41e
RR
34#if wxUSE_FREETYPE
35 #include <freetype/freetype.h>
d1f9b206
RR
36#endif
37
84fba40b
RR
38//#define CANVASDEBUG
39
d1f9b206
RR
40//----------------------------------------------------------------------------
41// globals
42//----------------------------------------------------------------------------
43
84fba40b
RR
44const double pi = 3.1415926535;
45
1e1af41e 46#if wxUSE_FREETYPE
d1f9b206
RR
47FT_Library g_freetypeLibrary;
48#endif
6a2c1874
RR
49
50//----------------------------------------------------------------------------
51// wxCanvasObject
52//----------------------------------------------------------------------------
4dbd4ee6 53wxCanvasObject::wxCanvasObject()
6a2c1874 54{
84fba40b
RR
55 // the default event handler is just this object
56 m_eventHandler=this;
57 m_admin = NULL;
4dbd4ee6
RR
58 m_isControl = FALSE;
59 m_isVector = FALSE;
60 m_isImage = FALSE;
84fba40b
RR
61 m_visible = TRUE;
62 m_dragmode = DRAG_ONTOP;
63// handy when debugging
64// m_dragmode = DRAG_RECTANGLE;
65 m_dragable = TRUE;
66}
67
68bool wxCanvasObject::ProcessCanvasObjectEvent(wxEvent& event)
69{
70 return m_eventHandler->ProcessEvent(event);
71}
72
73void wxCanvasObject::PushEventHandler(wxEvtHandler *handler)
74{
75 handler->SetNextHandler(GetEventHandler());
76 m_eventHandler=handler;
77}
78
79wxEvtHandler *wxCanvasObject::PopEventHandler(bool deleteHandler)
80{
81 wxEvtHandler *handlerA = m_eventHandler;
82 if ( handlerA )
83 {
84 wxEvtHandler *handlerB = handlerA->GetNextHandler();
85 handlerA->SetNextHandler((wxEvtHandler *)NULL);
86 m_eventHandler=handlerB;
87 if ( deleteHandler )
88 {
89 delete handlerA;
90 handlerA = (wxEvtHandler *)NULL;
91 }
92 }
93
94 return handlerA;
95}
96
97void wxCanvasObject::AppendEventHandler(wxEvtHandler *handler)
98{
99 GetEventHandler()->SetNextHandler(handler);
100}
101
102wxEvtHandler *wxCanvasObject::RemoveLastEventHandler(bool deleteHandler)
103{
104 //always the first in the row
105 wxEvtHandler *handlerA = m_eventHandler;
106 wxEvtHandler *handlerB=handlerA;
107 //goto the end
108 while ( handlerA->GetNextHandler() )
109 {
110 handlerB = handlerA;
111 handlerA = handlerA->GetNextHandler();
112 }
113
114 handlerB->SetNextHandler((wxEvtHandler *)NULL);
115 if ( deleteHandler )
116 {
117 delete handlerA;
118 }
119
120 return GetEventHandler();
121}
122
123wxRect wxCanvasObject::GetAbsoluteArea(const wxTransformMatrix& cworld)
124{
125
126 wxBoundingBox tmp=m_bbox;
127 tmp.MapBbox(cworld);
128
129
130 int x1 = m_admin->LogicalToDeviceX( tmp.GetMinX() );
131 int y1 = m_admin->LogicalToDeviceY( tmp.GetMinY() );
132 int x2 = m_admin->LogicalToDeviceX( tmp.GetMaxX() );
133 int y2 = m_admin->LogicalToDeviceY( tmp.GetMaxY() );
134
135 if (x1 > x2)
136 {
137 int tmp = x1;
138 x1 = x2;
139 x2 = tmp;
140 }
141 if (y1 > y2)
142 {
143 int tmp = y1;
144 y1 = y2;
145 y2 = tmp;
146 }
147
148 wxRect tmparea;
149 tmparea.x = x1;
150 tmparea.y = y1;
151 tmparea.width = x2-x1;
152 tmparea.height = y2-y1;
153
154 return tmparea;
155}
156
157void wxCanvasObject::MoveAbsolute( double x, double y )
158{
159 //save old position of boundingbox
160 double oldx = GetXMin();
161 double oldy = GetYMin();
162 double w = m_bbox.GetWidth();
163 double h = m_bbox.GetHeight();
164
165 SetPosXY(x,y);
166
167 double newx=GetXMin();
168 double newy=GetYMin();
169
170 double leftu,rightu,bottomu,topu ;
171 leftu = wxMin (oldx, newx ) ;
172 rightu = wxMax (oldx + w, newx + w) ;
173 topu = wxMin (oldy, newy) ;
174 bottomu = wxMax (oldy + h, newy + h) ;
175
176 if ( rightu - leftu < 2*w && bottomu - topu < 2*h )
177 {
178 m_admin->Update( this,leftu, topu, rightu - leftu, bottomu - topu);
179 }
180 else
181 {
182 m_admin->Update( this, oldx, oldy, w, h );
183 m_admin->Update( this, newx, newy, w, h );
184 }
4dbd4ee6
RR
185}
186
84fba40b 187void wxCanvasObject::MoveRelative( double x, double y )
4dbd4ee6 188{
84fba40b
RR
189 //save old position of boundingbox
190 double oldx = GetXMin();
191 double oldy = GetYMin();
192 double w = m_bbox.GetWidth();
193 double h = m_bbox.GetHeight();
194
195 TransLate(x,y);
196
197 double newx=GetXMin();
198 double newy=GetYMin();
199
200 double leftu,rightu,bottomu,topu ;
201 leftu = wxMin (oldx, newx ) ;
202 rightu = wxMax (oldx + w, newx + w) ;
203 topu = wxMin (oldy, newy) ;
204 bottomu = wxMax (oldy + h, newy + h) ;
205
206 if ( rightu - leftu < 2*w && bottomu - topu < 2*h )
207 {
208 m_admin->Update( this,leftu, topu, rightu - leftu, bottomu - topu);
209 }
210 else
211 {
212 m_admin->Update( this, oldx, oldy, w, h );
213 m_admin->Update( this, newx, newy, w, h );
214 }
4dbd4ee6
RR
215}
216
84fba40b
RR
217
218void wxCanvasObject::DragStart()
4dbd4ee6 219{
84fba40b
RR
220#if IMAGE_CANVAS
221#else
222 if (m_dragmode == DRAG_RECTANGLE)
223 {
224 this->SetVisible(FALSE);
225 wxTransformMatrix help;
226 double x = GetXMin();
227 double y = GetYMin();
228 double w = m_bbox.GetWidth();
229 double h = m_bbox.GetHeight();
230 m_admin->Update( this, x, y, w, h );
231 m_admin->UpdateNow();
232
233 wxRect recold=GetAbsoluteArea(help);
234 wxClientDC dc(m_admin->GetActive());
235 dc.SetPen(*wxBLACK_PEN);
236 dc.SetBrush(*wxTRANSPARENT_BRUSH);
237 dc.SetLogicalFunction(wxINVERT);
238 dc.DrawRectangle(recold);
239 dc.SetBrush(wxNullBrush);
240 dc.SetPen(wxNullPen);
241 }
242 else
243 {
244 this->SetVisible(FALSE);
245 wxTransformMatrix help;
246 double x = GetXMin();
247 double y = GetYMin();
248 double w = m_bbox.GetWidth();
249 double h = m_bbox.GetHeight();
250
251 wxRect recnew=GetAbsoluteArea(help);
252
253 //redraw in buffer what should be there without this object
254 m_admin->Update( this, x, y, w, h );
255 m_admin->GetActive()->Freeze();
256
257 //save the drawing (without the object itself to a bitmap)
258 m_atnewpos = wxBitmap(recnew.width,recnew.height);
259 wxMemoryDC dcm;
260 dcm.SelectObject(*m_admin->GetActive()->GetBuffer());
261 wxMemoryDC tmp;
262 tmp.SelectObject(m_atnewpos);
263 tmp.Blit(0,0,recnew.width,recnew.height,&dcm,recnew.x,recnew.y,wxCOPY,FALSE);
264 tmp.SelectObject(wxNullBitmap);
265 dcm.SelectObject(wxNullBitmap);
266 }
267#endif
6a2c1874
RR
268}
269
84fba40b
RR
270
271void wxCanvasObject::DragRelative( double x, double y)
6a2c1874 272{
84fba40b
RR
273#if IMAGE_CANVAS
274#else
275 if (m_dragmode == DRAG_RECTANGLE)
276 {
277 wxTransformMatrix help;
5143c96b 278
84fba40b 279 wxRect recold=GetAbsoluteArea(help);
dc16900b 280
84fba40b
RR
281 TransLate(x,y);
282
283 wxRect recnew=GetAbsoluteArea(help);
284
285 wxClientDC dc(m_admin->GetActive());
286 dc.SetPen(*wxBLACK_PEN);
287 dc.SetBrush(*wxTRANSPARENT_BRUSH);
288 dc.SetLogicalFunction(wxINVERT);
289 dc.DrawRectangle(recold);
290 dc.DrawRectangle(recnew);
291 dc.SetBrush(wxNullBrush);
292 dc.SetPen(wxNullPen);
293 }
294 else
6a2c1874 295 {
84fba40b
RR
296 wxClientDC dc(m_admin->GetActive());
297 wxMemoryDC tmp;
298
299 wxTransformMatrix help;
300 wxRect recold=GetAbsoluteArea(help);
301
302 //restore what was there (without the object itself)
303 wxMemoryDC dcm;
304 dcm.SelectObject(*m_admin->GetActive()->GetBuffer());
305 tmp.SelectObject(m_atnewpos);
306 dcm.Blit(recold.x,recold.y,recold.width,recold.height,&tmp,0,0,wxCOPY,FALSE);
307
308 TransLate(x,y);
309
310 wxRect recnew=GetAbsoluteArea(help);
311
312 //save the contents of the buffer at the new position
313 tmp.Blit(0,0,recnew.width,recnew.height,&dcm,recnew.x,recnew.y,wxCOPY,FALSE);
314 tmp.SelectObject(wxNullBitmap);
315
316 //m_atnewpos = m_admin->GetActive()->GetBuffer()->GetSubBitmap( recnew );
317
318 this->SetVisible(TRUE);
319 //redraw object into the buffer
320 m_admin->GetActive()->SetDC(&dcm);
321 Render(&help,recnew.x,recnew.y,recnew.width,recnew.height);
322
323 //draw the union or seperate to the canvas
324 double leftu,rightu,bottomu,topu ;
325 leftu = wxMin (recold.x, recnew.x ) ;
326 rightu = wxMax (recold.x + recold.width, recnew.x + recnew.width ) ;
327 topu = wxMin (recold.y, recnew.y) ;
328 bottomu = wxMax (recold.y + recold.height, recnew.y + recnew.height) ;
329
330 if ( rightu - leftu < 2*recold.width && bottomu - topu < 2*recold.height)
331 {
332 dc.Blit(leftu,topu,rightu - leftu,bottomu - topu,&dcm,leftu,topu,wxCOPY,FALSE);
333 }
334 else
335 {
336 //do them seperate
337 //first redraw what should be at the old position in the canvas
338 dc.Blit(recold.x,recold.y,recold.width,recold.height,&dcm,recold.x,recold.y,wxCOPY,FALSE);
339 //blit the new position of the object to the canvas
340 dc.Blit(recnew.x,recnew.y,recnew.width,recnew.height,&dcm,recnew.x,recnew.y,wxCOPY,FALSE);
341 }
342 dcm.SelectObject(wxNullBitmap);
343 this->SetVisible(FALSE);
6a2c1874 344 }
84fba40b
RR
345#endif
346}
347
348
349void wxCanvasObject::DragEnd()
350{
351#if IMAGE_CANVAS
352#else
353 m_atnewpos = wxBitmap(0,0);
354 m_admin->GetActive()->Thaw();
355 this->SetVisible(TRUE);
356 double x = GetXMin();
357 double y = GetYMin();
358 double w = m_bbox.GetWidth();
359 double h = m_bbox.GetHeight();
360 m_admin->Update( this, x, y, w, h );
361 m_admin->UpdateNow();
362#endif
363}
364
365wxCanvasObject* wxCanvasObject::IsHitWorld( double x, double y, double margin )
366{
367 if ((x >= m_bbox.GetMinX()-margin) &&
368 (x <= m_bbox.GetMaxX()+margin) &&
369 (y >= m_bbox.GetMinY()-margin) &&
370 (y <= m_bbox.GetMaxY()+margin)
371 )
372 return this;
373 return (wxCanvasObject*) NULL;
6a2c1874
RR
374}
375
84fba40b 376wxCanvasObject* wxCanvasObject::Contains( wxCanvasObject* obj )
239c1f50 377{
84fba40b
RR
378 if (obj == this)
379 return this;
380 return (wxCanvasObject*) NULL;
239c1f50
RR
381}
382
dc16900b
KH
383void wxCanvasObject::CaptureMouse()
384{
84fba40b 385 m_admin->GetActive()->SetCaptureMouse( this );
dc16900b
KH
386}
387
388void wxCanvasObject::ReleaseMouse()
389{
84fba40b 390 m_admin->GetActive()->SetCaptureMouse( NULL );
dc16900b
KH
391}
392
393bool wxCanvasObject::IsCapturedMouse()
394{
84fba40b 395 return m_admin->GetActive()->GetCaptured()==this;
dc16900b
KH
396}
397
398
84fba40b 399void wxCanvasObject::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
6a2c1874
RR
400{
401}
402
84fba40b 403void wxCanvasObject::CalcBoundingBox()
1e1af41e
RR
404{
405}
406
407void wxCanvasObject::WriteSVG( wxTextOutputStream &stream )
6a2c1874
RR
408{
409}
410
fcbb6b37
KH
411//----------------------------------------------------------------------------
412// wxCanvasObjectGroup
413//----------------------------------------------------------------------------
414
84fba40b 415wxCanvasObjectGroup::wxCanvasObjectGroup(double x, double y)
fcbb6b37 416{
84fba40b
RR
417 lworld.Translate(x,y);
418 //no objects make the bounding box the x,y and take care of it later
419 m_bbox.Expand(x,y);
21840a6c
RR
420}
421
422wxCanvasObjectGroup::~wxCanvasObjectGroup()
423{
fcbb6b37
KH
424}
425
84fba40b 426void wxCanvasObjectGroup::PushEventHandler(wxEvtHandler *handler)
fcbb6b37 427{
84fba40b 428 wxCanvasObject::PushEventHandler(handler);
fcbb6b37
KH
429 wxNode *node = m_objects.First();
430 while (node)
431 {
432 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
433
84fba40b 434 obj->PushEventHandler(handler);
fcbb6b37
KH
435
436 node = node->Next();
437 }
438}
439
84fba40b 440wxEvtHandler *wxCanvasObjectGroup::PopEventHandler(bool deleteHandler)
fcbb6b37 441{
84fba40b
RR
442 wxNode *node = m_objects.First();
443 while (node)
21840a6c 444 {
84fba40b
RR
445 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
446
447 obj->PopEventHandler(deleteHandler);
448
449 node = node->Next();
21840a6c 450 }
84fba40b
RR
451 return wxCanvasObject::PopEventHandler(deleteHandler);
452}
453
454void wxCanvasObjectGroup::AppendEventHandler(wxEvtHandler *handler)
455{
456 wxCanvasObject::AppendEventHandler(handler);
457 wxNode *node = m_objects.First();
458 while (node)
459 {
460 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
461
462 obj->AppendEventHandler(handler);
463
464 node = node->Next();
465 }
466}
467
468wxEvtHandler *wxCanvasObjectGroup::RemoveLastEventHandler(bool deleteHandler)
469{
470 wxNode *node = m_objects.First();
471 while (node)
472 {
473 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
474
475 obj->RemoveLastEventHandler(deleteHandler);
476
477 node = node->Next();
478 }
479 return wxCanvasObject::RemoveLastEventHandler(deleteHandler);
480}
481
482void wxCanvasObjectGroup::TransLate( double x, double y )
483{
484 lworld.Translate(x,y);
485 CalcBoundingBox();
486}
487
488void wxCanvasObjectGroup::SetAdmin(wxCanvasAdmin* admin)
489{
490 m_admin=admin;
491 wxNode *node = m_objects.First();
492 while (node)
21840a6c 493 {
84fba40b
RR
494 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
495
496 obj->SetAdmin(admin);
fcbb6b37 497
84fba40b 498 node = node->Next();
21840a6c 499 }
fcbb6b37
KH
500}
501
fcbb6b37
KH
502void wxCanvasObjectGroup::DeleteContents( bool flag)
503{
504 m_objects.DeleteContents( flag );
84fba40b
RR
505 m_bbox.SetValid(FALSE);
506 CalcBoundingBox();
fcbb6b37
KH
507}
508
fcbb6b37
KH
509void wxCanvasObjectGroup::Prepend( wxCanvasObject* obj )
510{
511 m_objects.Insert( obj );
84fba40b
RR
512 if (m_objects.First())
513 m_bbox.Expand(obj->GetBbox());
514 else
515 {
516 m_bbox.SetValid(FALSE);
517 CalcBoundingBox();
518 }
fcbb6b37
KH
519}
520
521void wxCanvasObjectGroup::Append( wxCanvasObject* obj )
522{
523 m_objects.Append( obj );
84fba40b
RR
524 if (m_objects.First())
525 m_bbox.Expand(obj->GetBbox());
526 else
527 {
528 m_bbox.SetValid(FALSE);
529 CalcBoundingBox();
530 }
fcbb6b37
KH
531}
532
533void wxCanvasObjectGroup::Insert( size_t before, wxCanvasObject* obj )
534{
535 m_objects.Insert( before, obj );
84fba40b
RR
536 m_bbox.SetValid(FALSE);
537 if (m_objects.First())
538 m_bbox.Expand(obj->GetBbox());
539 else
540 {
541 m_bbox.SetValid(FALSE);
542 CalcBoundingBox();
543 }
fcbb6b37
KH
544}
545
546void wxCanvasObjectGroup::Remove( wxCanvasObject* obj )
547{
548 m_objects.DeleteObject( obj );
84fba40b
RR
549 m_bbox.SetValid(FALSE);
550 CalcBoundingBox();
fcbb6b37
KH
551}
552
84fba40b 553void wxCanvasObjectGroup::CalcBoundingBox()
fcbb6b37 554{
84fba40b 555 m_bbox.SetValid(FALSE);
fcbb6b37
KH
556 wxNode *node = m_objects.First();
557 while (node)
558 {
559 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
560
fcbb6b37 561
84fba40b
RR
562 obj->CalcBoundingBox();
563 wxBoundingBox tmp;
564 tmp=obj->GetBbox();
565 tmp.MapBbox(lworld);
566
567 m_bbox.Expand( tmp );
fcbb6b37
KH
568 node = node->Next();
569 }
570}
571
84fba40b 572void wxCanvasObjectGroup::Render(wxTransformMatrix* cworld, int x, int y, int width, int height )
fcbb6b37 573{
84fba40b
RR
574 if (!m_visible) return;
575
576 wxTransformMatrix backup = *cworld;
577 *cworld *= lworld;
578
fcbb6b37 579 wxNode *node = m_objects.First();
84fba40b
RR
580
581 if (!node) return;
582
583
584#ifdef CANVASDEBUG
585 wxRect absarea=GetAbsoluteArea(*cworld);
586 wxDC *dc = m_admin->GetActive()->GetDC();
587 dc->SetPen(*wxBLACK_PEN);
588 dc->SetBrush(*wxTRANSPARENT_BRUSH);
589 dc->DrawRectangle( absarea.x , absarea.y , absarea.width , absarea.height );
590 dc->SetBrush(wxNullBrush);
591 dc->SetPen(wxNullPen);
592#endif
593 //TODO the next will only work if all boundingboxes stay up to date (problem when mowing currently
594 /*
595 if (! ( wxMax(absarea.x, x) < wxMin(absarea.x + absarea.width , x + width ) &&
596 wxMax(absarea.y, y) < wxMin(absarea.y + absarea.height , y + height )
597 )
598 )
599 return;
600 */
601
602 // cycle through all objects
fcbb6b37
KH
603 while (node)
604 {
605 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
606
84fba40b 607 if (!obj->IsControl() && obj->GetVisible())
fcbb6b37 608 {
84fba40b
RR
609
610 //get area at the absolute position
611 wxRect absareaobject=obj->GetAbsoluteArea(*cworld);
612
fcbb6b37
KH
613 // If we have 10.000 objects, we will go through
614 // this 10.000 times for each update, so we have
615 // to optimise carefully.
84fba40b
RR
616 int clip_x = absareaobject.x;
617 int clip_width = absareaobject.width;
fcbb6b37
KH
618 if (clip_x < x)
619 {
620 clip_width -= x-clip_x;
621 clip_x = x;
622 }
623 if (clip_width > 0)
624 {
625 if (clip_x + clip_width > x + width)
626 clip_width = x+width-clip_x;
627
628 if (clip_width > 0)
629 {
84fba40b
RR
630 int clip_y = absareaobject.y;
631 int clip_height = absareaobject.height;
fcbb6b37
KH
632 if (clip_y < y)
633 {
634 clip_height -= y-clip_y;
635 clip_y = y;
636 }
637 if (clip_height > 0)
638 {
639 if (clip_y + clip_height > y + height)
640 clip_height = y+height-clip_y;
641
642 if (clip_height > 0)
84fba40b
RR
643 {
644 obj->Render(cworld, clip_x, clip_y, clip_width, clip_height );
645 }
fcbb6b37
KH
646 }
647 }
648 }
649 }
650
651 node = node->Next();
652 }
84fba40b 653 *cworld = backup;
fcbb6b37
KH
654}
655
656void wxCanvasObjectGroup::WriteSVG( wxTextOutputStream &stream )
657{
658}
659
84fba40b 660wxCanvasObject* wxCanvasObjectGroup::IsHitWorld( double x, double y, double margin )
fcbb6b37 661{
84fba40b
RR
662 //KKKfirst check if within bbox
663 //will only work if they are always uptodate
664 //if (!m_bbox.PointInBox(x,y,margin))
665 // return (wxCanvasObject*) NULL;
666
667 wxTransformMatrix inverse = lworld;
668 double xh,yh;
669 inverse.Invert();
670 inverse.TransformPoint(x,y,xh,yh);
671
672 wxCanvasObject *obj=0;
fcbb6b37
KH
673 wxNode *node = m_objects.Last();
674 while (node)
675 {
84fba40b 676 obj=(wxCanvasObject*) node->Data();
fcbb6b37 677
84fba40b 678 if (!obj->IsControl() )
fcbb6b37 679 {
84fba40b 680 if (obj->IsHitWorld(x,y,margin))
fcbb6b37 681 {
84fba40b 682 return obj;
fcbb6b37
KH
683 }
684 }
685 node = node->Previous();
686 }
84fba40b
RR
687
688 return (wxCanvasObject*) NULL;
fcbb6b37
KH
689}
690
84fba40b 691wxCanvasObject* wxCanvasObjectGroup::Contains( wxCanvasObject* obj )
fcbb6b37 692{
84fba40b
RR
693 wxCanvasObject* cobj;
694 wxNode *node = m_objects.First();
fcbb6b37
KH
695 while (node)
696 {
84fba40b 697 cobj=(wxCanvasObject*) node->Data();
fcbb6b37 698
84fba40b 699 if (cobj->Contains(obj))
fcbb6b37 700 {
84fba40b 701 return obj;
fcbb6b37 702 }
84fba40b 703 node = node->Next();
fcbb6b37 704 }
5143c96b 705
21840a6c 706 return (wxCanvasObject*) NULL;
fcbb6b37
KH
707}
708
84fba40b
RR
709int wxCanvasObjectGroup::IndexOf( wxCanvasObject* obj )
710{
711 return m_objects.IndexOf( obj );
712}
713
714
715
fcbb6b37 716//----------------------------------------------------------------------------
84fba40b 717// wxCanvasObjectRef
fcbb6b37
KH
718//----------------------------------------------------------------------------
719
84fba40b 720wxCanvasObjectRef::wxCanvasObjectRef(double x, double y, wxCanvasObject* obj)
fcbb6b37
KH
721 : wxCanvasObject()
722{
84fba40b
RR
723 lworld.Translate(x,y);
724 m_obj = obj;
725
726 m_bbox.SetValid(FALSE);
727 wxBoundingBox tmp;
728 tmp=obj->GetBbox();
729 tmp.MapBbox(lworld);
730 m_bbox.Expand( tmp );
fcbb6b37
KH
731}
732
84fba40b 733void wxCanvasObjectRef::PushEventHandler(wxEvtHandler *handler)
fcbb6b37 734{
84fba40b
RR
735 wxCanvasObject::PushEventHandler(handler);
736 m_obj->PushEventHandler(handler);
fcbb6b37
KH
737}
738
84fba40b 739wxEvtHandler *wxCanvasObjectRef::PopEventHandler(bool deleteHandler)
fcbb6b37 740{
84fba40b
RR
741 m_obj->PopEventHandler(deleteHandler);
742 return wxCanvasObject::PopEventHandler(deleteHandler);
743}
fcbb6b37 744
84fba40b
RR
745void wxCanvasObjectRef::AppendEventHandler(wxEvtHandler *handler)
746{
747 wxCanvasObject::AppendEventHandler(handler);
748 m_obj->AppendEventHandler(handler);
749}
750
751wxEvtHandler *wxCanvasObjectRef::RemoveLastEventHandler(bool deleteHandler)
752{
753 m_obj->RemoveLastEventHandler(deleteHandler);
754 return wxCanvasObject::RemoveLastEventHandler(deleteHandler);
755}
756
757void wxCanvasObjectRef::TransLate( double x, double y )
758{
759 lworld.Translate(x,y);
760 CalcBoundingBox();
761}
762
763wxCanvasObject* wxCanvasObjectRef::Contains( wxCanvasObject* obj )
764{
765 if (obj == this || m_obj->Contains(obj))
766 return this;
767
768 return (wxCanvasObject*) NULL;
769}
770
771
772void wxCanvasObjectRef::SetRotation(double rotation)
773{
774 lworld.SetRotation(rotation);
775 CalcBoundingBox();
776}
777
778void wxCanvasObjectRef::SetScale(double scalex,double scaley)
779{
780 lworld.Scale(scalex,scaley,lworld.GetValue(2,0),lworld.GetValue(2,1));
781 CalcBoundingBox();
fcbb6b37
KH
782}
783
84fba40b 784void wxCanvasObjectRef::SetAdmin(wxCanvasAdmin* admin)
fcbb6b37 785{
84fba40b
RR
786 m_admin = admin;
787 m_obj->SetAdmin(admin);
788}
789
790void wxCanvasObjectRef::CalcBoundingBox()
791{
792 m_bbox.SetValid(FALSE);
793 m_obj->CalcBoundingBox();
fcbb6b37 794
84fba40b
RR
795 wxBoundingBox tmp;
796 tmp=m_obj->GetBbox();
797 tmp.MapBbox(lworld);
798 m_bbox.Expand( tmp );
fcbb6b37
KH
799}
800
84fba40b 801void wxCanvasObjectRef::Render(wxTransformMatrix* cworld, int x, int y, int width, int height )
fcbb6b37 802{
84fba40b
RR
803 if (!m_visible) return;
804
805 //get the absolute area (without the local matrix included)
806 //the boundingbox is relative to the parent.
807 wxRect absarea=GetAbsoluteArea(*cworld);
fcbb6b37 808
84fba40b
RR
809 wxTransformMatrix backup = *cworld;
810 *cworld *= lworld;
811
812#ifdef CANVASDEBUG
813 wxDC *dc = m_admin->GetActive()->GetDC();
814 dc->SetPen(*wxBLACK_PEN);
815 dc->SetBrush(*wxTRANSPARENT_BRUSH);
816 dc->DrawRectangle( absarea.x , absarea.y , absarea.width , absarea.height );
817 dc->SetBrush(wxNullBrush);
818 dc->SetPen(wxNullPen);
819#endif
820
821 int clip_x = absarea.x;
822 int clip_width = absarea.width;
fcbb6b37
KH
823 if (clip_x < x)
824 {
825 clip_width -= x-clip_x;
826 clip_x = x;
827 }
828 if (clip_width > 0)
829 {
830 if (clip_x + clip_width > x + width)
831 clip_width = x+width-clip_x;
832
833 if (clip_width > 0)
834 {
84fba40b
RR
835 int clip_y = absarea.y;
836 int clip_height = absarea.height;
fcbb6b37
KH
837 if (clip_y < y)
838 {
839 clip_height -= y-clip_y;
840 clip_y = y;
841 }
842 if (clip_height > 0)
843 {
844 if (clip_y + clip_height > y + height)
845 clip_height = y+height-clip_y;
846
847 if (clip_height > 0)
84fba40b 848 m_obj->Render(cworld, clip_x, clip_y, clip_width, clip_height );
fcbb6b37
KH
849 }
850 }
851 }
fcbb6b37 852
84fba40b 853 *cworld = backup;
fcbb6b37
KH
854}
855
84fba40b 856void wxCanvasObjectRef::WriteSVG( wxTextOutputStream &stream )
fcbb6b37 857{
fcbb6b37
KH
858}
859
84fba40b 860wxCanvasObject* wxCanvasObjectRef::IsHitWorld( double x, double y, double margin )
fcbb6b37 861{
84fba40b
RR
862 //KKKfirst check if within bbox
863 //will only work if they are always uptodate
864 //if (!m_bbox.PointInBox(x,y,margin))
865 // return (wxCanvasObject*) NULL;
fcbb6b37 866
84fba40b
RR
867 wxTransformMatrix inverse = lworld;
868 double xh,yh;
869 inverse.Invert();
870 inverse.TransformPoint(x,y,xh,yh);
fcbb6b37 871
84fba40b
RR
872 if (m_obj->IsHitWorld(xh,yh,margin))
873 return this;
5143c96b 874
84fba40b
RR
875 return (wxCanvasObject*) NULL;
876}
5143c96b 877
5143c96b 878
fcbb6b37 879
5143c96b 880//----------------------------------------------------------------------------
84fba40b 881// wxCanvasRect
5143c96b
KH
882//----------------------------------------------------------------------------
883
84fba40b 884wxCanvasRect::wxCanvasRect( double x, double y, double w, double h , double radius )
5143c96b
KH
885 : wxCanvasObject()
886{
84fba40b
RR
887 m_x = x;
888 m_y = y;
889 m_width = w;
890 m_height = h;
891 m_radius = radius;
892
893 m_brush = *wxBLACK_BRUSH;
894 m_pen = *wxTRANSPARENT_PEN;
895 CalcBoundingBox();
5143c96b
KH
896}
897
84fba40b 898void wxCanvasRect::TransLate( double x, double y )
5143c96b 899{
84fba40b
RR
900 m_x += x;
901 m_y += y;
902 CalcBoundingBox();
5143c96b
KH
903}
904
84fba40b 905void wxCanvasRect::CalcBoundingBox()
5143c96b 906{
84fba40b
RR
907 m_bbox.SetMin( m_x , m_y);
908 m_bbox.SetMax( m_x + m_width ,m_y + m_height );
5143c96b
KH
909
910 //include the pen width also
84fba40b
RR
911//KKK m_bbox.EnLarge(m_pen.GetWidth()+m_radius);
912 m_bbox.EnLarge(m_pen.GetWidth()/2);
5143c96b
KH
913}
914
84fba40b 915void wxCanvasRect::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
5143c96b 916{
84fba40b
RR
917 if (!m_visible) return;
918
919#if IMAGE_CANVAS
920 wxImage *image = m_admin->GetActive()->GetBuffer();
5143c96b 921
84fba40b
RR
922 int start_y = clip_y;
923 int end_y = clip_y+clip_height;
5143c96b 924
84fba40b
RR
925 int start_x = clip_x;
926 int end_x = clip_x+clip_width;
5143c96b 927
84fba40b
RR
928 // speed up later
929 for (int y = start_y; y < end_y; y++)
930 for (int x = start_x; x < end_x; x++)
931 {
932 int red=m_brush.GetColour().Red();
933 int green=m_brush.GetColour().Green();
934 int blue=m_brush.GetColour().Blue();
935 image->SetRGB( x, y, red, green, blue );
936 }
5143c96b 937#else
84fba40b 938 if (cworld->GetRotation())
5143c96b 939 {
84fba40b
RR
940 wxPoint *cpoints = new wxPoint[4];
941 double x;
942 double y;
943 cworld->TransformPoint( m_x, m_y, x, y );
944 cpoints[0].x = m_admin->LogicalToDeviceX(x);
945 cpoints[0].y = m_admin->LogicalToDeviceY(y);
946 cworld->TransformPoint( m_x , m_y + m_height, x, y );
947 cpoints[1].x = m_admin->LogicalToDeviceX(x);
948 cpoints[1].y = m_admin->LogicalToDeviceY(y);
949 cworld->TransformPoint( m_x + m_width, m_y + m_height, x, y );
950 cpoints[2].x = m_admin->LogicalToDeviceX(x);
951 cpoints[2].y = m_admin->LogicalToDeviceY(y);
952 cworld->TransformPoint( m_x + m_width, m_y , x, y );
953 cpoints[3].x = m_admin->LogicalToDeviceX(x);
954 cpoints[3].y = m_admin->LogicalToDeviceY(y);
955
956 wxDC *dc = m_admin->GetActive()->GetDC();
957 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
958 dc->SetBrush(m_brush);
959 int pw=m_pen.GetWidth();
960 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
961 dc->SetPen(m_pen);
962 dc->DrawPolygon(4, cpoints, 0,0,wxWINDING_RULE);
963 delete [] cpoints;
964 dc->SetBrush(wxNullBrush);
965 dc->SetPen(wxNullPen);
966 dc->DestroyClippingRegion();
967 m_pen.SetWidth(pw);
968 }
969 else
970 {
971 wxDC *dc = m_admin->GetActive()->GetDC();
972 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
973 dc->SetBrush(m_brush);
974 int pw=m_pen.GetWidth();
975 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
976 dc->SetPen(m_pen);
977 //yes the whole not only the clipping region, because we have a pen also
978 int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
979 int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
980 int w = m_admin->LogicalToDeviceXRel( m_width );
981 int h = m_admin->LogicalToDeviceYRel( m_height );
982 int r = m_admin->LogicalToDeviceYRel( m_radius );
983 if (w > 0 && w < 1) w=1;
984 if (w < 0 && w > -1) w=-1;
985 if (h > 0 && h < 1) h=1;
986 if (h < 0 && h > -1) h=-1;
987 if (m_radius)
988 dc->DrawRoundedRectangle( x,y,w,h,r);
989 else
990 dc->DrawRectangle( x,y,w,h);
991 dc->SetBrush(wxNullBrush);
992 dc->SetPen(wxNullPen);
993 dc->DestroyClippingRegion();
994 m_pen.SetWidth(pw);
5143c96b 995 }
5143c96b
KH
996#endif
997}
998
84fba40b 999void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
5143c96b
KH
1000{
1001}
1002
1003//----------------------------------------------------------------------------
84fba40b 1004// wxCanvasCircle
5143c96b
KH
1005//----------------------------------------------------------------------------
1006
84fba40b 1007wxCanvasCircle::wxCanvasCircle( double x, double y, double radius )
5143c96b
KH
1008 : wxCanvasObject()
1009{
84fba40b
RR
1010 m_x = x;
1011 m_y = y;
1012 m_radius = radius;
1013
27d1065d
RR
1014 m_brush = *wxBLACK_BRUSH;
1015 m_pen = *wxTRANSPARENT_PEN;
84fba40b 1016 CalcBoundingBox();
5143c96b
KH
1017}
1018
84fba40b 1019void wxCanvasCircle::TransLate( double x, double y )
5143c96b 1020{
84fba40b
RR
1021 m_x += x;
1022 m_y += y;
1023 CalcBoundingBox();
5143c96b
KH
1024}
1025
84fba40b 1026void wxCanvasCircle::CalcBoundingBox()
5143c96b 1027{
84fba40b
RR
1028 m_bbox.SetMin( m_x-m_radius , m_y-m_radius );
1029 m_bbox.SetMax( m_x+m_radius , m_y+m_radius );
5143c96b 1030
84fba40b
RR
1031 //include the pen width also
1032 m_bbox.EnLarge(m_pen.GetWidth()/2);
1033}
1034
1035void wxCanvasCircle::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
1036{
1037 if (!m_visible) return;
1038
1039#if IMAGE_CANVAS
1040#else
1041 wxDC *dc = m_admin->GetActive()->GetDC();
1042 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
1043 dc->SetBrush(m_brush);
1044 int pw=m_pen.GetWidth();
1045 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
1046 dc->SetPen(m_pen);
1047 //yes the whole not only the clipping region, because we have a pen also
1048 //and rotation on a circle is not important so only a shift with cworld
1049 int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
1050 int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
1051 int radius = m_admin->LogicalToDeviceXRel( m_radius );
1052 if (radius < 1) radius=1;
1053 dc->DrawCircle( x,y,radius);
1054 dc->SetBrush(wxNullBrush);
1055 dc->SetPen(wxNullPen);
1056 dc->DestroyClippingRegion();
1057 m_pen.SetWidth(pw);
1058#endif
5143c96b
KH
1059}
1060
84fba40b 1061void wxCanvasCircle::WriteSVG( wxTextOutputStream &stream )
5143c96b 1062{
84fba40b 1063}
5143c96b 1064
84fba40b
RR
1065wxCanvasObject* wxCanvasCircle::IsHitWorld( double x, double y, double margin )
1066{
1067 if ((x >= m_bbox.GetMinX()-margin) &&
1068 (x <= m_bbox.GetMaxX()+margin) &&
1069 (y >= m_bbox.GetMinY()-margin) &&
1070 (y <= m_bbox.GetMaxY()+margin)
1071 )
5143c96b 1072 {
84fba40b
RR
1073 if (m_radius+m_pen.GetWidth()/2+margin > sqrt(pow(m_x-x,2)+pow(m_y-y,2)))
1074 return this;
1075 else
1076 return (wxCanvasObject*) NULL;
5143c96b 1077 }
84fba40b
RR
1078 return (wxCanvasObject*) NULL;
1079}
5143c96b 1080
84fba40b
RR
1081//----------------------------------------------------------------------------
1082// wxCanvasEllipse
1083//----------------------------------------------------------------------------
1084
1085wxCanvasEllipse::wxCanvasEllipse( double x, double y, double width, double height )
1086 : wxCanvasObject()
1087{
1088 m_x = x;
1089 m_y = y;
1090 m_width = width;
1091 m_height = height;
1092
1093 m_brush = *wxBLACK_BRUSH;
1094 m_pen = *wxTRANSPARENT_PEN;
1095 CalcBoundingBox();
1096}
5143c96b 1097
84fba40b
RR
1098void wxCanvasEllipse::TransLate( double x, double y )
1099{
1100 m_x += x;
1101 m_y += y;
1102 CalcBoundingBox();
5143c96b
KH
1103}
1104
84fba40b 1105void wxCanvasEllipse::CalcBoundingBox()
5143c96b 1106{
84fba40b
RR
1107 m_bbox.SetMin( m_x, m_y );
1108 m_bbox.SetMax( m_x+m_width , m_y+m_height );
5143c96b 1109
84fba40b
RR
1110 //include the pen width also
1111 m_bbox.EnLarge(m_pen.GetWidth()/2);
1112}
5143c96b 1113
84fba40b
RR
1114void wxCanvasEllipse::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
1115{
1116 if (!m_visible) return;
5143c96b
KH
1117
1118#if IMAGE_CANVAS
1119#else
84fba40b
RR
1120 wxDC *dc = m_admin->GetActive()->GetDC();
1121 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
5143c96b 1122 dc->SetBrush(m_brush);
84fba40b
RR
1123 int pw=m_pen.GetWidth();
1124 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
5143c96b 1125 dc->SetPen(m_pen);
84fba40b
RR
1126 int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
1127 int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
1128 int w = m_admin->LogicalToDeviceXRel( m_width );
1129 int h = m_admin->LogicalToDeviceYRel( m_height );
1130 if (w > 0 && w < 1) w=1;
1131 if (w < 0 && w > -1) w=-1;
1132 if (h > 0 && h < 1) h=1;
1133 if (h < 0 && h > -1) h=-1;
1134 dc->DrawEllipse( x,y,w,h);
5143c96b
KH
1135 dc->SetBrush(wxNullBrush);
1136 dc->SetPen(wxNullPen);
1137 dc->DestroyClippingRegion();
84fba40b 1138 m_pen.SetWidth(pw);
5143c96b
KH
1139#endif
1140}
1141
84fba40b 1142void wxCanvasEllipse::WriteSVG( wxTextOutputStream &stream )
5143c96b
KH
1143{
1144}
1145
84fba40b
RR
1146wxCanvasObject* wxCanvasEllipse::IsHitWorld( double x, double y, double margin )
1147{
1148 if ((x >= m_bbox.GetMinX()-margin) &&
1149 (x <= m_bbox.GetMaxX()+margin) &&
1150 (y >= m_bbox.GetMinY()-margin) &&
1151 (y <= m_bbox.GetMaxY()+margin)
1152 )
1153 {
1154 double a=(m_width+m_pen.GetWidth())/2+margin ;
1155 double b=(m_height+m_pen.GetWidth())/2+margin;
1156 double c=pow((m_x+m_width/2-x)/a,2)+pow((m_y+m_height/2-y)/b,2);
1157 if ( 1 > c)
1158 return this;
1159 else
1160 return (wxCanvasObject*) NULL;
1161 }
1162 return (wxCanvasObject*) NULL;
1163}
fcbb6b37 1164
21544859 1165//----------------------------------------------------------------------------
84fba40b 1166// wxCanvasEllipticArc
21544859
RR
1167//----------------------------------------------------------------------------
1168
84fba40b 1169wxCanvasEllipticArc::wxCanvasEllipticArc( double x, double y, double width, double height, double start, double end )
4dbd4ee6 1170 : wxCanvasObject()
21544859 1171{
4dbd4ee6
RR
1172 m_x = x;
1173 m_y = y;
84fba40b
RR
1174 m_width = width;
1175 m_height = height;
1176 m_start = start;
1177 m_end = end;
dc16900b 1178
27d1065d
RR
1179 m_brush = *wxBLACK_BRUSH;
1180 m_pen = *wxTRANSPARENT_PEN;
84fba40b 1181 CalcBoundingBox();
21544859
RR
1182}
1183
84fba40b 1184void wxCanvasEllipticArc::TransLate( double x, double y )
4dbd4ee6 1185{
84fba40b
RR
1186 m_x += x;
1187 m_y += y;
1188 CalcBoundingBox();
4dbd4ee6
RR
1189}
1190
84fba40b 1191void wxCanvasEllipticArc::CalcBoundingBox()
21544859 1192{
84fba40b
RR
1193 m_bbox.SetMin( m_x, m_y );
1194 m_bbox.SetMax( m_x+m_width , m_y+m_height );
fcbb6b37 1195
84fba40b
RR
1196 //include the pen width also
1197 m_bbox.EnLarge(m_pen.GetWidth()/2);
1198}
fcbb6b37 1199
84fba40b
RR
1200void wxCanvasEllipticArc::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
1201{
1202 if (!m_visible) return;
fcbb6b37 1203
84fba40b 1204#if IMAGE_CANVAS
33ebcd80 1205#else
84fba40b
RR
1206 wxDC *dc = m_admin->GetActive()->GetDC();
1207 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
1208 dc->SetBrush(m_brush);
1209 int pw=m_pen.GetWidth();
1210 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
1211 dc->SetPen(m_pen);
1212 int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
1213 int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
1214 int w = m_admin->LogicalToDeviceXRel( m_width );
1215 int h = m_admin->LogicalToDeviceYRel( m_height );
1216 if (w > 0 && w < 1) w=1;
1217 if (w < 0 && w > -1) w=-1;
1218 if (h > 0 && h < 1) h=1;
1219 if (h < 0 && h > -1) h=-1;
1220 if (m_admin->GetActive()->GetYaxis())
1221 dc->DrawEllipticArc( x,y,w,h,-m_end,-m_start);
1222 else
1223 dc->DrawEllipticArc( x,y,w,h,m_start,m_end);
1224 dc->SetBrush(wxNullBrush);
1225 dc->SetPen(wxNullPen);
1226 dc->DestroyClippingRegion();
1227 m_pen.SetWidth(pw);
33ebcd80 1228#endif
21544859
RR
1229}
1230
84fba40b
RR
1231void wxCanvasEllipticArc::WriteSVG( wxTextOutputStream &stream )
1232{
1233}
1234
1235wxCanvasObject* wxCanvasEllipticArc::IsHitWorld( double x, double y, double margin )
21544859 1236{
84fba40b
RR
1237 if ((x >= m_bbox.GetMinX()-margin) &&
1238 (x <= m_bbox.GetMaxX()+margin) &&
1239 (y >= m_bbox.GetMinY()-margin) &&
1240 (y <= m_bbox.GetMaxY()+margin)
1241 )
1242 {
1243 double a=(m_width+m_pen.GetWidth())/2+margin ;
1244 double b=(m_height+m_pen.GetWidth())/2+margin;
1245 double c=pow((m_x+m_width/2-x)/a,2)+pow((m_y+m_height/2-y)/b,2);
1246 if ( 1 > c)
1247 return this;
1248 else
1249 return (wxCanvasObject*) NULL;
1250 }
1251 return (wxCanvasObject*) NULL;
21544859
RR
1252}
1253
239c1f50
RR
1254//----------------------------------------------------------------------------
1255// wxCanvasLine
1256//----------------------------------------------------------------------------
1257
27d1065d 1258wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2 )
4dbd4ee6 1259 : wxCanvasObject()
239c1f50 1260{
4dbd4ee6
RR
1261 m_x1 = x1;
1262 m_y1 = y1;
1263 m_x2 = x2;
1264 m_y2 = y2;
1265
27d1065d 1266 m_pen = *wxBLACK_PEN;
84fba40b 1267 CalcBoundingBox();
239c1f50
RR
1268}
1269
84fba40b 1270void wxCanvasLine::TransLate( double x, double y )
4dbd4ee6 1271{
84fba40b
RR
1272 m_x1 += x;
1273 m_y1 += y;
1274 m_x2 += x;
1275 m_y2 += y;
1276 CalcBoundingBox();
1277}
1278
1279void wxCanvasLine::CalcBoundingBox()
1280{
1281 m_bbox.SetMin( m_x1 , m_y1);
1282 m_bbox.SetMax( m_x2 , m_y2);
1283
1284 //include the pen width also
1285 m_bbox.EnLarge(m_pen.GetWidth()/2);
4dbd4ee6
RR
1286}
1287
84fba40b 1288void wxCanvasLine::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
239c1f50 1289{
84fba40b 1290 if (!m_visible) return;
fcbb6b37 1291
84fba40b
RR
1292 double x1,y1,x2,y2;
1293 cworld->TransformPoint( m_x1, m_y1, x1, y1 );
1294 cworld->TransformPoint( m_x2, m_y2, x2, y2 );
1295 x1 = m_admin->LogicalToDeviceX( x1 );
1296 y1 = m_admin->LogicalToDeviceY( y1 );
1297 x2 = m_admin->LogicalToDeviceX( x2 );
1298 y2 = m_admin->LogicalToDeviceY( y2 );
5143c96b 1299
33ebcd80 1300#if IMAGE_CANVAS
84fba40b
RR
1301 wxRect tmparea;
1302 tmparea.x = m_admin->LogicalToDeviceXRel( m_bbox.GetMinX());
1303 tmparea.y = m_admin->LogicalToDeviceYRel( m_bbox.GetMinY());
1304 tmparea.width = m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() );
1305 tmparea.height = m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() );
1306 wxImage *image = m_admin->GetActive()->GetBuffer();
1307 if ((tmparea.width == 0) && (tmparea.height == 0))
239c1f50 1308 {
84fba40b
RR
1309 int red=m_pen.GetColour().Red();
1310 int green=m_pen.GetColour().Green();
1311 int blue=m_pen.GetColour().Blue();
1312 image->SetRGB( tmparea.x, tmparea.y, red, green, blue );
239c1f50
RR
1313 }
1314 else
1315 {
84fba40b
RR
1316 int red=m_pen.GetColour().Red();
1317 int green=m_pen.GetColour().Green();
1318 int blue=m_pen.GetColour().Blue();
239c1f50
RR
1319 wxInt32 d, ii, jj, di, ai, si, dj, aj, sj;
1320 di = x1 - x2;
1321 ai = abs(di) << 1;
1322 si = (di < 0)? -1 : 1;
1323 dj = y1 - y2;
1324 aj = abs(dj) << 1;
1325 sj = (dj < 0)? -1 : 1;
1326
1327 ii = x2;
1328 jj = y2;
dc16900b 1329
239c1f50
RR
1330 if (ai > aj)
1331 {
1332 // iterate over i
dc16900b
KH
1333 d = aj - (ai >> 1);
1334
239c1f50
RR
1335 while (ii != x1)
1336 {
61b64bd9
RR
1337 if ((ii >= clip_x) && (ii < clip_x+clip_width) &&
1338 (jj >= clip_y) && (jj < clip_y+clip_height))
239c1f50 1339 {
84fba40b 1340 image->SetRGB( ii, jj, red, blue, green );
239c1f50
RR
1341 }
1342 if (d >= 0)
1343 {
1344 jj += sj;
dc16900b 1345 d -= ai;
239c1f50
RR
1346 }
1347 ii += si;
1348 d += aj;
1349 }
1350 }
1351 else
1352 {
1353 // iterate over j
1354 d = ai - (aj >> 1);
1355
1356 while (jj != y1)
1357 {
61b64bd9
RR
1358 if ((ii >= clip_x) && (ii < clip_x+clip_width) &&
1359 (jj >= clip_y) && (jj < clip_y+clip_height))
239c1f50 1360 {
84fba40b 1361 image->SetRGB( ii, jj, red, blue, green );
239c1f50
RR
1362 }
1363 if (d >= 0)
1364 {
1365 ii += si;
dc16900b 1366 d -= aj;
239c1f50
RR
1367 }
1368 jj += sj;
1369 d += ai;
1370 }
1371 }
1372 }
33ebcd80 1373#else
84fba40b
RR
1374 wxDC *dc = m_admin->GetActive()->GetDC();
1375 dc->SetClippingRegion( clip_x, clip_y, clip_width, clip_height );
1376 int pw=m_pen.GetWidth();
1377 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
27d1065d 1378 dc->SetPen( m_pen );
84fba40b 1379 dc->DrawLine( x1, y1, x2, y2 );
5143c96b 1380
33ebcd80 1381 dc->DestroyClippingRegion();
84fba40b 1382 m_pen.SetWidth(pw);
33ebcd80 1383#endif
239c1f50
RR
1384}
1385
1386void wxCanvasLine::WriteSVG( wxTextOutputStream &stream )
1387{
1e1af41e 1388 // no idea
239c1f50
RR
1389}
1390
84fba40b
RR
1391wxCanvasObject* wxCanvasLine::IsHitWorld( double x, double y, double margin )
1392{
1393 if ((x >= m_bbox.GetMinX()-margin) &&
1394 (x <= m_bbox.GetMaxX()+margin) &&
1395 (y >= m_bbox.GetMinY()-margin) &&
1396 (y <= m_bbox.GetMaxY()+margin)
1397 )
1398 {
1399 wxLine line1(m_x1,m_y1,m_x2,m_y2);
1400 wxPoint2DDouble P=wxPoint2DDouble(x,y);
1401 double distance;
1402 if (line1.PointInLine(P,distance,m_pen.GetWidth()/2+margin) == R_IN_AREA)
1403 return this;
1404 else
1405 return (wxCanvasObject*) NULL;
1406 }
1407 return (wxCanvasObject*) NULL;
1408}
1409
6a2c1874
RR
1410//----------------------------------------------------------------------------
1411// wxCanvasImage
1412//----------------------------------------------------------------------------
1413
4dbd4ee6
RR
1414wxCanvasImage::wxCanvasImage( const wxImage &image, double x, double y, double w, double h )
1415 : wxCanvasObject()
6a2c1874 1416{
4dbd4ee6
RR
1417 m_x = x;
1418 m_y = y;
1419 m_width = w;
1420 m_height = h;
dc16900b 1421
6a2c1874 1422 m_image = image;
84fba40b
RR
1423
1424 m_orgw=m_image.GetWidth();
1425 m_orgh=m_image.GetHeight();
1426
6a2c1874 1427 m_isImage = TRUE;
84fba40b
RR
1428 m_visible = FALSE;
1429//KKK m_visible=TRUE;
1430 CalcBoundingBox();
6a2c1874
RR
1431}
1432
84fba40b 1433void wxCanvasImage::TransLate( double x, double y )
4dbd4ee6 1434{
84fba40b
RR
1435 m_x += x;
1436 m_y += y;
1437 CalcBoundingBox();
1438}
1439
1440void wxCanvasImage::CalcBoundingBox()
1441{
1442 m_bbox.SetMin( m_x , m_y);
1443 m_bbox.SetMax( m_x + m_width , m_y + m_height);
1444}
1445
1446void wxCanvasImage::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
1447{
1448 if (!m_visible) return;
1449
1450 wxRect tmparea;
1451
1452 tmparea.x = m_admin->LogicalToDeviceXRel( m_bbox.GetMinX());
1453 tmparea.y = m_admin->LogicalToDeviceYRel( m_bbox.GetMinY());
1454 tmparea.width = m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() );
1455 tmparea.height = m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() );
1456
1457 double x;
1458 double y;
1459 cworld->TransformPoint( m_x, m_y, x, y );
1460 x = m_admin->LogicalToDeviceX(x);
1461 y = m_admin->LogicalToDeviceY(y);
1462
dc16900b 1463
33ebcd80 1464#if IMAGE_CANVAS
84fba40b
RR
1465 if ((clip_x == xabs + tmparea.x) &&
1466 (clip_y == yabs + tmparea.y) &&
1467 (clip_width == tmparea.width) &&
1468 (clip_height == tmparea.height))
33ebcd80 1469 {
84fba40b 1470 m_admin->GetActive()->GetBuffer()->Paste( m_tmp, clip_x, clip_y );
33ebcd80 1471 }
4dbd4ee6 1472 else
33ebcd80 1473 {
84fba40b
RR
1474 // local coordinates
1475 int start_x = clip_x - (xabs + tmparea.x);
1476 int start_y = clip_y - (yabs + tmparea.y);
1477
1478 wxRect rect( start_x, start_y, clip_width, clip_height );
1479 wxImage sub_image( m_tmp.GetSubImage( rect ) );
1480 m_admin->GetActive()->GetBuffer()->Paste( sub_image, clip_x, clip_y );
33ebcd80
RR
1481 }
1482#else
84fba40b
RR
1483 if ( m_orgw*5 < m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() ) ||
1484 m_orgw/5 > m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() ) ||
1485 m_orgh*5 < m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() ) ||
1486 m_orgh/5 > m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() )
1487 )
1488 {
1489 wxDC *dc = m_admin->GetActive()->GetDC();
1490 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
1491 dc->SetBrush(*wxTRANSPARENT_BRUSH);
1492 dc->SetPen(*wxBLACK_PEN);
1493 //yes the whole not only the clipping region, because we have a pen also
1494 int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
1495 int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
1496 int w = m_admin->LogicalToDeviceXRel( m_width );
1497 int h = m_admin->LogicalToDeviceYRel( m_height );
1498 if (w < 1) w=1;
1499 if (h < 1) h=1;
1500 dc->DrawRectangle( x,y,w,h);
1501 dc->SetBrush(wxNullBrush);
1502 dc->SetPen(wxNullPen);
1503 dc->DestroyClippingRegion();
1504 return;
1505 }
1506
1507 if ((m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() ) == m_image.GetWidth()) &&
1508 (m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() ) == m_image.GetHeight()))
33ebcd80 1509 {
84fba40b 1510 m_tmp = m_image;
33ebcd80
RR
1511 }
1512 else
1513 {
84fba40b
RR
1514 m_tmp = m_image.Scale( m_admin->LogicalToDeviceXRel( m_bbox.GetWidth()),
1515 m_admin->LogicalToDeviceYRel( m_bbox.GetHeight()) );
33ebcd80 1516 }
4dbd4ee6 1517
84fba40b
RR
1518 wxBitmap bmp;
1519// wxPoint centr(m_admin->LogicalToDeviceX(m_x),m_admin->LogicalToDeviceY(m_y));
1520 wxPoint centr(0,0);
fcbb6b37 1521
84fba40b 1522 if (cworld->GetRotation())
d1f9b206 1523 {
84fba40b 1524 bmp=m_tmp.Rotate(-cworld->GetRotation()/180.0 * pi,centr, TRUE, NULL).ConvertToBitmap();
d1f9b206
RR
1525 }
1526 else
1527 {
84fba40b 1528 bmp = m_tmp.ConvertToBitmap();
d1f9b206 1529 }
5143c96b 1530
84fba40b
RR
1531 wxDC *dc = m_admin->GetActive()->GetDC();
1532
1533 wxPoint centr2;
1534 if (cworld->GetRotation()> 0)
33ebcd80 1535 {
84fba40b
RR
1536 centr2.x= (int) (x+m_height*sin(-cworld->GetRotation()/180.0 * pi));
1537 centr2.y= (int) y;
33ebcd80
RR
1538 }
1539 else
1540 {
84fba40b
RR
1541 centr2.x= (int) x;
1542 centr2.y= (int) (y-m_width*sin(-cworld->GetRotation()/180.0 * pi));
1543 }
5143c96b 1544
84fba40b
RR
1545 if (cworld->GetRotation() != 0)
1546 {
1547 //TODO clipping not right
1548 dc->DrawBitmap(bmp,centr2,TRUE );
1549// dc->DrawPoint(centr2);
1550// dc->DrawPoint(x,y);
1551 }
1552 else
1553 {
1554 //TODO clipping not right
1555// dc->DrawPoint(centr2);
1556// dc->DrawPoint(x,y);
1557
1558 if ((clip_x == x) &&
1559 (clip_y == y) &&
1560 (clip_width == tmparea.width) &&
1561 (clip_height == tmparea.height))
1562 {
1563 dc->DrawBitmap( m_tmp, clip_x, clip_y, TRUE );
1564 }
1565 else
1566 {
1567 int start_x = clip_x - (int)x;
1568 int start_y = clip_y - (int)y;
1569
1570 //dc->DrawBitmap( bmp, x, y, TRUE );
1571 wxMemoryDC dcm;
1572 dcm.SelectObject(bmp);
1573 dc->Blit(clip_x, clip_y,clip_width, clip_height,&dcm,start_x,start_y,wxCOPY,TRUE);
1574 dcm.SelectObject(wxNullBitmap);
1575 }
33ebcd80
RR
1576 }
1577#endif
6a2c1874
RR
1578}
1579
1580void wxCanvasImage::WriteSVG( wxTextOutputStream &stream )
1581{
1582 // no idea
1583}
1584
3b111dbe
RR
1585//----------------------------------------------------------------------------
1586// wxCanvasCtrl
1587//----------------------------------------------------------------------------
1588
1589wxCanvasControl::wxCanvasControl( wxWindow *control )
4dbd4ee6 1590 : wxCanvasObject()
3b111dbe 1591{
21544859 1592 m_isControl = TRUE;
3b111dbe 1593 m_control = control;
84fba40b
RR
1594 CalcBoundingBox();
1595}
1596
1597double wxCanvasControl::GetPosX()
1598{
1599 int x,y ;
1600 m_control->GetPosition( &x, &y );
1601 return m_admin->DeviceToLogicalX(x);
1602}
1603
1604double wxCanvasControl::GetPosY()
1605{
1606 int x,y ;
1607 m_control->GetPosition( &x, &y );
1608 return m_admin->DeviceToLogicalY(y);
1609}
1610
1611void wxCanvasControl::SetPosXY( double x, double y)
1612{
1613 int xd = m_admin->LogicalToDeviceX(x);
1614 int yd = m_admin->LogicalToDeviceY(y);
1615 m_control->Move(xd,yd);
1616}
1617
1618
1619void wxCanvasControl::TransLate( double x, double y )
1620{
1621 int xdo,ydo;
1622 m_control->GetPosition( &xdo, &ydo );
1623 int xd = m_admin->LogicalToDeviceX(x)-xdo;
1624 int yd = m_admin->LogicalToDeviceY(y)-ydo;
1625 m_control->Move(xd,yd);
1626 CalcBoundingBox();
3b111dbe
RR
1627}
1628
1629wxCanvasControl::~wxCanvasControl()
1630{
1631 m_control->Destroy();
1632}
1633
84fba40b 1634void wxCanvasControl::CalcBoundingBox()
3b111dbe 1635{
84fba40b
RR
1636 wxRect tmparea;
1637
1638 m_control->GetSize( &tmparea.width, &tmparea.height );
1639 m_control->GetPosition( &tmparea.x, &tmparea.y );
1640
1641 m_bbox.SetMin( tmparea.x , tmparea.y);
1642 m_bbox.SetMax( tmparea.x + tmparea.width , tmparea.y + tmparea.height);
1643
3b111dbe
RR
1644}
1645
84fba40b 1646void wxCanvasControl::MoveRelative( double x, double y )
3b111dbe 1647{
84fba40b 1648 m_control->Move( m_admin->LogicalToDeviceX(x), m_admin->LogicalToDeviceX(y) );
3b111dbe
RR
1649}
1650
d1f9b206
RR
1651//----------------------------------------------------------------------------
1652// wxCanvasText
1653//----------------------------------------------------------------------------
1654
1655class wxFaceData
1656{
1657public:
1e1af41e 1658#if wxUSE_FREETYPE
d1f9b206
RR
1659 FT_Face m_face;
1660#else
1661 void *m_dummy;
dc16900b 1662#endif
d1f9b206
RR
1663};
1664
4dbd4ee6
RR
1665wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxString &fontFile, int size )
1666 : wxCanvasObject()
d1f9b206
RR
1667{
1668 m_text = text;
cb281cfc
RR
1669 m_fontFileName = fontFile;
1670 m_size = size;
dc16900b 1671
cb281cfc 1672 m_red = 0;
d1f9b206
RR
1673 m_green = 0;
1674 m_blue = 0;
dc16900b 1675
4dbd4ee6 1676 m_alpha = NULL;
dc16900b 1677
4dbd4ee6
RR
1678 m_x = x;
1679 m_y = y;
dc16900b
KH
1680
1681#if wxUSE_FREETYPE
d1f9b206
RR
1682 wxFaceData *data = new wxFaceData;
1683 m_faceData = data;
dc16900b 1684
d1f9b206 1685 int error = FT_New_Face( g_freetypeLibrary,
cb281cfc 1686 m_fontFileName,
d1f9b206
RR
1687 0,
1688 &(data->m_face) );
5143c96b 1689
d1f9b206
RR
1690 error = FT_Set_Char_Size( data->m_face,
1691 0,
cb281cfc
RR
1692 m_size*64,
1693 96, // screen dpi
d1f9b206
RR
1694 96 );
1695#endif
84fba40b 1696 CalcBoundingBox();
d1f9b206
RR
1697}
1698
1699wxCanvasText::~wxCanvasText()
1700{
fcbb6b37 1701#if wxUSE_FREETYPE
d1f9b206
RR
1702 wxFaceData *data = (wxFaceData*) m_faceData;
1703 delete data;
1704#endif
1705
1706 if (m_alpha) delete [] m_alpha;
1707}
1708
1709void wxCanvasText::SetRGB( unsigned char red, unsigned char green, unsigned char blue )
1710{
1711 m_red = red;
1712 m_green = green;
1713 m_blue = blue;
1714}
1715
1716void wxCanvasText::SetFlag( int flag )
1717{
1718 m_flag = flag;
1719}
1720
84fba40b 1721void wxCanvasText::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
d1f9b206 1722{
84fba40b
RR
1723 if (!m_visible) return;
1724
1725 wxRect tmparea;
1726 tmparea.x = m_admin->LogicalToDeviceX( m_bbox.GetMinX());
1727 tmparea.y = m_admin->LogicalToDeviceY( m_bbox.GetMinY());
1728 tmparea.width = m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() );
1729 tmparea.height = m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() );
1730
1731 m_alpha = new unsigned char[tmparea.width*tmparea.height];
1732 memset( m_alpha, 0, tmparea.width*tmparea.height );
1733
d1f9b206 1734 if (!m_alpha) return;
fcbb6b37 1735
84fba40b
RR
1736#if wxUSE_FREETYPE
1737 FT_Face face = ((wxFaceData*)m_faceData)->m_face;
1738 FT_GlyphSlot slot = face->glyph;
1739 int pen_x = 0;
1740 int pen_y = m_size;
1741
1742 for (int n = 0; n < (int)m_text.Len(); n++)
1743 {
1744 FT_UInt index = FT_Get_Char_Index( face, m_text[(unsigned int)n] );
1745
1746 int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
1747 if (error) continue;
1748
1749 error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
1750 if (error) continue;
1751
1752 FT_Bitmap *bitmap = &slot->bitmap;
1753 unsigned char* buffer = bitmap->buffer;
1754 for (int y = 0; y < bitmap->rows; y++)
1755 for (int x = 0; x < bitmap->width; x++)
1756 {
1757 unsigned char alpha = buffer[ y*bitmap->pitch + x ];
1758 if (alpha == 0) continue;
1759
1760 int xx = pen_x + slot->bitmap_left + x;
1761 int yy = pen_y - slot->bitmap_top + y;
1762 m_alpha[ yy * tmparea.width + xx ] = alpha;
1763 }
1764
1765 pen_x += slot->advance.x >> 6;
1766 pen_y += slot->advance.y >> 6;
1767 }
1768#endif
1769
96f5fca9 1770#if IMAGE_CANVAS
84fba40b 1771 wxImage *image = m_admin->GetActive()->GetBuffer();
d1f9b206 1772
21544859 1773 // local coordinates
84fba40b 1774 int start_x = clip_x - tmparea.x;
21544859 1775 int end_x = clip_width + start_x;
84fba40b 1776 int start_y = clip_y - tmparea.y;
21544859 1777 int end_y = clip_height + start_y;
fcbb6b37 1778
d1f9b206
RR
1779 for (int y = start_y; y < end_y; y++)
1780 for (int x = start_x; x < end_x; x++)
1781 {
84fba40b 1782 int alpha = m_alpha[y*tmparea.width + x];
d1f9b206
RR
1783 if (alpha)
1784 {
84fba40b
RR
1785 int image_x = tmparea.x+x;
1786 int image_y = tmparea.y+y;
cb281cfc 1787 if (alpha == 255)
d1f9b206
RR
1788 {
1789 image->SetRGB( image_x, image_y, m_red, m_green, m_blue );
1790 continue;
1791 }
cb281cfc
RR
1792 int red1 = (m_red * alpha) / 255;
1793 int green1 = (m_green * alpha) / 255;
1794 int blue1 = (m_blue * alpha) / 255;
dc16900b 1795
cb281cfc 1796 alpha = 255-alpha;
d1f9b206
RR
1797 int red2 = image->GetRed( image_x, image_y );
1798 int green2 = image->GetGreen( image_x, image_y );
1799 int blue2 = image->GetBlue( image_x, image_y );
cb281cfc
RR
1800 red2 = (red2 * alpha) / 255;
1801 green2 = (green2 * alpha) / 255;
1802 blue2 = (blue2 * alpha) / 255;
fcbb6b37 1803
d1f9b206
RR
1804 image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
1805 }
1806 }
96f5fca9 1807#else
84fba40b
RR
1808 wxBitmap *bitmap = m_admin->GetActive()->GetBuffer();
1809 wxRect sub_rect( clip_x, clip_y, clip_width, clip_height );
96f5fca9 1810 wxBitmap sub_bitmap( bitmap->GetSubBitmap( sub_rect ) );
84fba40b 1811
96f5fca9
RR
1812 wxImage image( sub_bitmap );
1813
1814 // local coordinates
84fba40b 1815 int start_x = clip_x - tmparea.x;
96f5fca9 1816 int end_x = clip_width + start_x;
84fba40b 1817 int start_y = clip_y - tmparea.y;
96f5fca9
RR
1818 int end_y = clip_height + start_y;
1819
1820 for (int y = start_y; y < end_y; y++)
1821 for (int x = start_x; x < end_x; x++)
1822 {
84fba40b 1823 int alpha = m_alpha[y*tmparea.width + x];
96f5fca9
RR
1824 if (alpha)
1825 {
1826 int image_x = x - start_x;
1827 int image_y = y - start_y;
1828 if (alpha == 255)
1829 {
1830 image.SetRGB( image_x, image_y, m_red, m_green, m_blue );
1831 continue;
1832 }
1833 int red1 = (m_red * alpha) / 255;
1834 int green1 = (m_green * alpha) / 255;
1835 int blue1 = (m_blue * alpha) / 255;
1836
1837 alpha = 255-alpha;
1838 int red2 = image.GetRed( image_x, image_y );
1839 int green2 = image.GetGreen( image_x, image_y );
1840 int blue2 = image.GetBlue( image_x, image_y );
1841 red2 = (red2 * alpha) / 255;
1842 green2 = (green2 * alpha) / 255;
1843 blue2 = (blue2 * alpha) / 255;
1844
1845 image.SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
1846 }
1847 }
84fba40b 1848
96f5fca9 1849 sub_bitmap = image.ConvertToBitmap();
84fba40b
RR
1850
1851 wxDC *dc = m_admin->GetActive()->GetDC();
1852 dc->DrawBitmap( sub_bitmap, clip_x, clip_y );
33ebcd80 1853#endif
d1f9b206
RR
1854}
1855
1856void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
1857{
1858}
1859
84fba40b 1860void wxCanvasText::TransLate( double x, double y )
d1f9b206 1861{
84fba40b
RR
1862 m_x += x;
1863 m_y += y;
1864 CalcBoundingBox();
1865}
dc16900b 1866
84fba40b
RR
1867void wxCanvasText::CalcBoundingBox()
1868{
1869 if (m_alpha) delete [] m_alpha;
dc16900b 1870
84fba40b
RR
1871 m_bbox.SetMin( m_x , m_y);
1872 m_bbox.SetMax( m_x + 100 , m_y + m_size + (m_size/2));
fcbb6b37 1873
fcbb6b37 1874
84fba40b 1875}
dc16900b 1876
84fba40b
RR
1877//----------------------------------------------------------------------------
1878// wxCanvas
1879//----------------------------------------------------------------------------
fcbb6b37 1880
84fba40b 1881IMPLEMENT_CLASS(wxCanvas,wxWindow)
fcbb6b37 1882
84fba40b
RR
1883BEGIN_EVENT_TABLE(wxCanvas,wxWindow)
1884 EVT_SCROLLWIN( wxCanvas::OnScroll )
6a2c1874
RR
1885 EVT_CHAR( wxCanvas::OnChar )
1886 EVT_PAINT( wxCanvas::OnPaint )
1887 EVT_SIZE( wxCanvas::OnSize )
1888 EVT_IDLE( wxCanvas::OnIdle )
1889 EVT_MOUSE_EVENTS( wxCanvas::OnMouse )
1890 EVT_SET_FOCUS( wxCanvas::OnSetFocus )
1891 EVT_KILL_FOCUS( wxCanvas::OnKillFocus )
61b64bd9 1892 EVT_ERASE_BACKGROUND( wxCanvas::OnEraseBackground )
6a2c1874
RR
1893END_EVENT_TABLE()
1894
84fba40b 1895wxCanvas::wxCanvas( wxCanvasAdmin* admin, wxWindow *parent, wxWindowID id,
6a2c1874 1896 const wxPoint &position, const wxSize& size, long style ) :
84fba40b 1897 wxWindow( parent, id, position, size, style )
6a2c1874 1898{
84fba40b
RR
1899 m_admin = admin;
1900 m_admin->Append(this);
6a2c1874 1901 m_needUpdate = FALSE;
84fba40b 1902 m_background = *wxWHITE;
239c1f50 1903 m_lastMouse = (wxCanvasObject*)NULL;
4dbd4ee6 1904 m_captureMouse = (wxCanvasObject*)NULL;
41328253 1905 m_frozen = TRUE;
27d1065d
RR
1906 m_oldDeviceX = 0;
1907 m_oldDeviceY = 0;
84fba40b
RR
1908 m_scrolled=FALSE;
1909 m_root=0;
1910 m_yaxis=FALSE;
6a2c1874
RR
1911}
1912
1913wxCanvas::~wxCanvas()
1914{
1915 wxNode *node = m_updateRects.First();
1916 while (node)
1917 {
1918 wxRect *rect = (wxRect*) node->Data();
1919 delete rect;
1920 m_updateRects.DeleteNode( node );
1921 node = m_updateRects.First();
1922 }
1923}
1924
84fba40b 1925void wxCanvas::SetColour( const wxColour& background )
cb281cfc 1926{
84fba40b
RR
1927 m_background=background;
1928 SetBackgroundColour( m_background );
61b64bd9 1929
239c1f50 1930 if (m_frozen) return;
dc16900b 1931
33ebcd80 1932#if IMAGE_CANVAS
84fba40b
RR
1933 unsigned char red = background.Red();
1934 unsigned char green = background.Green();
1935 unsigned char blue = background.Blue();
1936
cb281cfc 1937 unsigned char *data = m_buffer.GetData();
dc16900b 1938
cb281cfc
RR
1939 for (int y = 0; y < m_buffer.GetHeight(); y++)
1940 for (int x = 0; x < m_buffer.GetWidth(); x++)
1941 {
1942 data[0] = red;
1943 data++;
1944 data[0] = green;
1945 data++;
1946 data[0] = blue;
1947 data++;
1948 }
33ebcd80
RR
1949#else
1950 wxMemoryDC dc;
1951 dc.SelectObject( m_buffer );
1952 dc.SetPen( *wxTRANSPARENT_PEN );
84fba40b 1953 wxBrush brush( m_background, wxSOLID );
33ebcd80
RR
1954 dc.SetBrush( brush );
1955 dc.DrawRectangle( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() );
1956 dc.SelectObject( wxNullBitmap );
1957#endif
cb281cfc
RR
1958}
1959
dc16900b 1960void wxCanvas::SetCaptureMouse( wxCanvasObject *obj )
4dbd4ee6 1961{
dc16900b
KH
1962 if (obj)
1963 {
1964 wxWindow::CaptureMouse();
1965 m_captureMouse = obj;
1966 }
1967 else
1968 {
1969 wxWindow::ReleaseMouse();
1970 m_captureMouse = NULL;
1971 }
4dbd4ee6
RR
1972}
1973
239c1f50
RR
1974void wxCanvas::Freeze()
1975{
1976 m_frozen = TRUE;
1977}
1978
1979void wxCanvas::Thaw()
1980{
1981 wxNode *node = m_updateRects.First();
1982 while (node)
1983 {
1984 wxRect *rect = (wxRect*) node->Data();
1985 delete rect;
1986 m_updateRects.DeleteNode( node );
1987 node = m_updateRects.First();
1988 }
dc16900b 1989
239c1f50 1990 m_frozen = FALSE;
dc16900b 1991
41328253 1992 if (m_buffer.Ok())
84fba40b 1993 Update( 0,0, m_buffer.GetWidth(), m_buffer.GetHeight() );
239c1f50
RR
1994}
1995
41328253 1996void wxCanvas::Update( int x, int y, int width, int height, bool blit )
6a2c1874 1997{
84fba40b
RR
1998 m_admin->SetActive(this);
1999
2000 if (!m_root) return;
2001
239c1f50 2002 if (m_frozen) return;
fcbb6b37 2003
21544859 2004 // clip to buffer
84fba40b 2005 if (x < 0)
21544859 2006 {
84fba40b
RR
2007 width -= -x;
2008 x = 0;
21544859 2009 }
33ebcd80 2010 if (width <= 0) return;
dc16900b 2011
84fba40b 2012 if (y < 0)
21544859 2013 {
84fba40b
RR
2014 height -= -y;
2015 y = 0;
21544859 2016 }
33ebcd80 2017 if (height <= 0) return;
dc16900b 2018
84fba40b 2019 if (x+width > m_buffer.GetWidth())
21544859 2020 {
84fba40b 2021 width = m_buffer.GetWidth() - x;
21544859 2022 }
33ebcd80 2023 if (width <= 0) return;
dc16900b 2024
84fba40b 2025 if (y+height > m_buffer.GetHeight())
21544859 2026 {
84fba40b 2027 height = m_buffer.GetHeight() - y;
21544859 2028 }
33ebcd80 2029 if (height <= 0) return;
dc16900b 2030
21544859 2031 // update is within the buffer
6a2c1874 2032 m_needUpdate = TRUE;
dc16900b 2033
21544859 2034 // has to be blitted to screen later
41328253
RR
2035 if (blit)
2036 {
2037 m_updateRects.Append(
2038 (wxObject*) new wxRect( x,y,width,height ) );
2039 }
dc16900b 2040
84fba40b
RR
2041 wxTransformMatrix cworld;
2042
33ebcd80 2043#if IMAGE_CANVAS
21544859 2044 // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b)
84fba40b
RR
2045 int start_y = y;
2046 int end_y = y+height;
2047 int start_x = x;
2048 int end_x = x+width;
2049 int red=m_background.Red();
2050 int green=m_background.Green();
2051 int blue=m_background.Blue();
41328253
RR
2052 for (int yy = start_y; yy < end_y; yy++)
2053 for (int xx = start_x; xx < end_x; xx++)
84fba40b 2054 m_buffer.SetRGB( xx, yy, red, green, blue );
5143c96b 2055
84fba40b 2056 m_root->Render(&cworld, x, y, width, height );
33ebcd80
RR
2057#else
2058 wxMemoryDC dc;
2059 dc.SelectObject( m_buffer );
84fba40b 2060
33ebcd80 2061 dc.SetPen( *wxTRANSPARENT_PEN );
84fba40b 2062 wxBrush brush( m_background , wxSOLID );
33ebcd80 2063 dc.SetBrush( brush );
33ebcd80 2064
84fba40b
RR
2065 if (width != m_buffer.GetWidth() && height != m_buffer.GetHeight())
2066 {
2067 dc.SetLogicalFunction(wxCOPY);
2068 dc.SetClippingRegion(x,y,width,height);
2069 dc.DrawRectangle(x-2,y-2,width+4,height+4);
2070 dc.DestroyClippingRegion();
2071 }
2072 else
2073 {
2074 dc.Clear();
2075 dc.SetLogicalFunction(wxCOPY);
2076 dc.DrawRectangle(0,0,m_buffer.GetWidth(),m_buffer.GetHeight());
2077 }
2078 dc.SetBrush(wxNullBrush);
2079 dc.SetPen(wxNullPen);
2080
2081 m_renderDC=&dc;
2082
2083 m_root->Render(&cworld,x, y, width, height );
5143c96b 2084
84fba40b 2085 m_renderDC=0;
33ebcd80
RR
2086 dc.SelectObject( wxNullBitmap );
2087#endif
6a2c1874
RR
2088}
2089
3b111dbe 2090void wxCanvas::BlitBuffer( wxDC &dc )
6a2c1874 2091{
6a2c1874
RR
2092 wxNode *node = m_updateRects.First();
2093 while (node)
2094 {
2095 wxRect *rect = (wxRect*) node->Data();
6a2c1874 2096
33ebcd80 2097#if IMAGE_CANVAS
6a2c1874 2098
84fba40b 2099 wxImage sub_image( m_buffer.GetSubImage( *rect ) );
6a2c1874 2100#ifdef __WXGTK__
dc16900b 2101 int bpp = wxDisplayDepth();
6a2c1874
RR
2102 if (bpp > 8)
2103 {
2104 // the init code is doubled in wxImage
2105 static bool s_hasInitialized = FALSE;
2106
2107 if (!s_hasInitialized)
2108 {
2109 gdk_rgb_init();
2110 s_hasInitialized = TRUE;
2111 }
dc16900b 2112
6a2c1874
RR
2113 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow)->bin_window,
2114 m_wxwindow->style->black_gc,
41328253 2115 sub_rect.x, sub_rect.y,
6a2c1874
RR
2116 sub_image.GetWidth(), sub_image.GetHeight(),
2117 GDK_RGB_DITHER_NONE,
2118 sub_image.GetData(),
2119 sub_image.GetWidth()*3 );
2120 }
2121 else
2122 {
2123 wxBitmap bitmap( sub_image.ConvertToBitmap() );
2124 dc.DrawBitmap( bitmap, rect->x, rect->y );
2125 }
33ebcd80 2126#else
6a2c1874
RR
2127 wxBitmap bitmap( sub_image.ConvertToBitmap() );
2128 dc.DrawBitmap( bitmap, rect->x, rect->y );
2129#endif
dc16900b 2130
33ebcd80
RR
2131#else // IMAGE_CANVAS
2132
2133 // Maybe clipping use SetClipping() is faster than
2134 // getting the subrect first and drawing it then?
84fba40b
RR
2135
2136// wxBitmap sub_bitmap( m_buffer.GetSubBitmap( *rect ) );
2137// dc.DrawBitmap( sub_bitmap, rect->x, rect->y );
2138
2139 wxMemoryDC mdc;
2140 mdc.SelectObject( m_buffer );
2141 dc.Blit (rect->x, rect->y , rect->GetWidth(), rect->GetHeight(),&mdc, rect->x, rect->y );
2142 mdc.SelectObject( wxNullBitmap );
5143c96b 2143
33ebcd80 2144#endif
6a2c1874
RR
2145 delete rect;
2146 m_updateRects.DeleteNode( node );
2147 node = m_updateRects.First();
2148 }
dc16900b 2149
3b111dbe
RR
2150 m_needUpdate = FALSE;
2151}
2152
2153void wxCanvas::UpdateNow()
2154{
61b64bd9
RR
2155 if (m_frozen) return;
2156
3b111dbe 2157 if (!m_needUpdate) return;
dc16900b 2158
3b111dbe
RR
2159 wxClientDC dc( this );
2160 PrepareDC( dc );
dc16900b 2161
3b111dbe 2162 BlitBuffer( dc );
6a2c1874
RR
2163}
2164
6a2c1874
RR
2165void wxCanvas::OnPaint(wxPaintEvent &event)
2166{
6a2c1874 2167 wxPaintDC dc(this);
3b111dbe 2168 PrepareDC( dc );
dc16900b 2169
41328253 2170 if (!m_buffer.Ok()) return;
fcbb6b37 2171
b85cfb6f 2172 if (m_frozen) return;
41328253 2173
6a2c1874
RR
2174 m_needUpdate = TRUE;
2175
2176 wxRegionIterator it( GetUpdateRegion() );
2177 while (it)
2178 {
2179 int x = it.GetX();
2180 int y = it.GetY();
dc16900b 2181
6a2c1874
RR
2182 int w = it.GetWidth();
2183 int h = it.GetHeight();
dc16900b 2184
21544859
RR
2185 if (x+w > m_buffer.GetWidth())
2186 w = m_buffer.GetWidth() - x;
2187 if (y+h > m_buffer.GetHeight())
2188 h = m_buffer.GetHeight() - y;
dc16900b 2189
21544859 2190 if ((w > 0) && (h > 0))
41328253 2191 {
21544859 2192 m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) );
41328253 2193 }
dc16900b 2194
6a2c1874
RR
2195 it++;
2196 }
dc16900b 2197
3b111dbe 2198 BlitBuffer( dc );
6a2c1874
RR
2199}
2200
41328253
RR
2201void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
2202{
61b64bd9 2203 // If any updates are pending, do them now since they will
27d1065d 2204 // expect the previous m_bufferX and m_bufferY as well as
84fba40b 2205 // the previous device origin values.
27d1065d
RR
2206 wxClientDC dc( this );
2207 dc.SetDeviceOrigin( m_oldDeviceX, m_oldDeviceY );
2208 BlitBuffer( dc );
41328253 2209
84fba40b
RR
2210 if (dy != 0)
2211 {
2212 double dyv=DeviceToLogicalYRel(dy);
2213 m_virt_minY=m_virt_minY-dyv;
2214 m_virt_maxY=m_virt_maxY-dyv;
2215 }
2216 if (dx != 0)
2217 {
2218 double dxv=DeviceToLogicalXRel(dx);
2219 m_virt_minX=m_virt_minX-dxv;
2220 m_virt_maxX=m_virt_maxX-dxv;
2221 }
2222
2223 m_admin->SetActive(this);
2224 SetMappingScroll(m_virt_minX,m_virt_minY,m_virt_maxX,m_virt_maxY,FALSE);
41328253 2225
33ebcd80 2226#if IMAGE_CANVAS
41328253 2227 unsigned char* data = m_buffer.GetData();
fcbb6b37 2228
41328253
RR
2229 if (dy != 0)
2230 {
2231 if (dy > 0)
2232 {
2233 unsigned char *source = data;
2234 unsigned char *dest = data + (dy * m_buffer.GetWidth() * 3);
2235 size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()-dy));
2236 memmove( dest, source, count );
fcbb6b37 2237
61b64bd9
RR
2238 // We update the new buffer area, but there is no need to
2239 // blit (last param FALSE) since the ensuing paint event will
2240 // do that anyway.
84fba40b 2241 Update( 0, 0, m_buffer.GetWidth(), dy, FALSE );
41328253
RR
2242 }
2243 else
2244 {
2245 unsigned char *dest = data;
2246 unsigned char *source = data + (-dy * m_buffer.GetWidth() * 3);
2247 size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()+dy));
2248 memmove( dest, source, count );
fcbb6b37 2249
61b64bd9
RR
2250 // We update the new buffer area, but there is no need to
2251 // blit (last param FALSE) since the ensuing paint event will
2252 // do that anyway.
84fba40b 2253 Update( 0, m_buffer.GetHeight()+dy, m_buffer.GetWidth(), -dy, FALSE );
41328253
RR
2254 }
2255 }
fcbb6b37 2256
41328253
RR
2257 if (dx != 0)
2258 {
61b64bd9
RR
2259 if (dx > 0)
2260 {
2261 unsigned char *source = data;
2262 for (int y = 0; y < m_buffer.GetHeight(); y++)
2263 {
2264 unsigned char *dest = source + dx*3;
2265 memmove( dest, source, (m_buffer.GetWidth()-dx) * 3 );
2266 source += m_buffer.GetWidth()*3;
2267 }
fcbb6b37 2268
61b64bd9
RR
2269 // We update the new buffer area, but there is no need to
2270 // blit (last param FALSE) since the ensuing paint event will
2271 // do that anyway.
84fba40b 2272 Update( 0,0, dx, m_buffer.GetHeight(), FALSE );
61b64bd9
RR
2273 }
2274 else
2275 {
2276 unsigned char *dest = data;
2277 for (int y = 0; y < m_buffer.GetHeight(); y++)
2278 {
2279 unsigned char *source = dest - dx*3;
2280 memmove( dest, source, (m_buffer.GetWidth()+dx) * 3 );
2281 dest += m_buffer.GetWidth()*3;
2282 }
fcbb6b37 2283
61b64bd9
RR
2284 // We update the new buffer area, but there is no need to
2285 // blit (last param FALSE) since the ensuing paint event will
2286 // do that anyway.
84fba40b 2287 Update( m_buffer.GetWidth()+dx, 0, -dx, m_buffer.GetHeight(), FALSE );
61b64bd9 2288 }
41328253 2289 }
33ebcd80 2290#else
41328253 2291
84fba40b
RR
2292 if (dy != 0)
2293 {
2294 if (dy > 0 && dy < m_buffer.GetHeight())
2295 {
2296 wxRect rect( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight()-dy);
2297 wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2298 wxMemoryDC dcm;
2299 dcm.SelectObject( m_buffer );
2300 dcm.DrawBitmap( sub_bitmap, 0, dy, TRUE );
2301 dcm.SelectObject( wxNullBitmap );
2302
2303 Update( 0, 0, m_buffer.GetWidth(), dy, TRUE );
2304 }
2305 else if (dy < 0 && dy > -m_buffer.GetHeight())
2306 {
2307 wxRect rect( 0, -dy, m_buffer.GetWidth(), m_buffer.GetHeight()+dy);
2308 wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2309 wxMemoryDC dcm;
2310 dcm.SelectObject( m_buffer );
2311 dcm.DrawBitmap( sub_bitmap, 0, 0, TRUE );
2312 dcm.SelectObject( wxNullBitmap );
2313
2314 Update( 0, m_buffer.GetHeight()+dy, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
2315 }
2316 else
2317 Update( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
2318 }
2319
2320 if (dx != 0)
2321 {
2322 if (dx > 0 && dx < m_buffer.GetWidth())
2323 {
2324 wxRect rect( 0, 0, m_buffer.GetWidth()-dx, m_buffer.GetHeight());
2325 wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2326 wxMemoryDC dcm;
2327 dcm.SelectObject( m_buffer );
2328 dcm.DrawBitmap( sub_bitmap, dx, 0, TRUE );
2329 dcm.SelectObject( wxNullBitmap );
2330
2331 Update( 0, 0, dx, m_buffer.GetHeight(), TRUE );
2332 }
2333 else if (dx < 0 && dx > -m_buffer.GetWidth())
2334 {
2335 wxRect rect( -dx, 0, m_buffer.GetWidth()+dx, m_buffer.GetHeight());
2336 wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2337 wxMemoryDC dcm;
2338 dcm.SelectObject( m_buffer );
2339 dcm.DrawBitmap( sub_bitmap, 0, 0, TRUE );
2340 dcm.SelectObject( wxNullBitmap );
2341
2342 Update( m_buffer.GetWidth()+dx, 0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
2343 }
2344 else
2345 Update( 0,0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
2346 }
2347#endif
41328253 2348 wxWindow::ScrollWindow( dx, dy, rect );
84fba40b
RR
2349
2350 //must be done now because quick repeated scrolling will prevent wxPaint
2351 //from doing it properly
2352 UpdateNow();
41328253
RR
2353}
2354
6a2c1874
RR
2355void wxCanvas::OnMouse(wxMouseEvent &event)
2356{
84fba40b
RR
2357 m_admin->SetActive(this);
2358 if (!m_root)
2359 {
2360 event.Skip();
2361 return;
2362 }
2363
239c1f50
RR
2364 int x = event.GetX();
2365 int y = event.GetY();
84fba40b
RR
2366
2367 //to world coordinates to do hit test in world coordinates
2368 double xw = DeviceToLogicalX( x );
2369 double yw = DeviceToLogicalY( y );
2370
2371 //make a select margin of 2 pixels, so also zero line thickness will be hit
2372 double margin = DeviceToLogicalXRel( 2 );
dc16900b 2373
239c1f50
RR
2374 if (event.GetEventType() == wxEVT_MOTION)
2375 {
dc16900b 2376 if (m_captureMouse) //no matter what go to this one
239c1f50 2377 {
dc16900b
KH
2378 wxMouseEvent child_event( wxEVT_MOTION );
2379 child_event.SetEventObject(m_captureMouse);
84fba40b
RR
2380 child_event.m_x = x;
2381 child_event.m_y = y;
dc16900b
KH
2382 child_event.m_leftDown = event.m_leftDown;
2383 child_event.m_rightDown = event.m_rightDown;
2384 child_event.m_middleDown = event.m_middleDown;
2385 child_event.m_controlDown = event.m_controlDown;
2386 child_event.m_shiftDown = event.m_shiftDown;
2387 child_event.m_altDown = event.m_altDown;
2388 child_event.m_metaDown = event.m_metaDown;
84fba40b
RR
2389
2390 m_captureMouse->ProcessCanvasObjectEvent( child_event );
872f1044 2391 return;
dc16900b
KH
2392 }
2393 else
2394 {
84fba40b 2395 wxCanvasObject *obj = m_root->IsHitWorld(xw,yw,margin);
dc16900b 2396
fcbb6b37
KH
2397 if (obj && !obj->IsControl())
2398 {
2399 wxMouseEvent child_event( wxEVT_MOTION );
2400 child_event.SetEventObject( obj );
84fba40b
RR
2401 child_event.m_x = x;
2402 child_event.m_y = y;
fcbb6b37
KH
2403 child_event.m_leftDown = event.m_leftDown;
2404 child_event.m_rightDown = event.m_rightDown;
2405 child_event.m_middleDown = event.m_middleDown;
2406 child_event.m_controlDown = event.m_controlDown;
2407 child_event.m_shiftDown = event.m_shiftDown;
2408 child_event.m_altDown = event.m_altDown;
2409 child_event.m_metaDown = event.m_metaDown;
2410
2411 if ((obj != m_lastMouse) && (m_lastMouse != NULL))
239c1f50 2412 {
fcbb6b37
KH
2413 child_event.SetEventType( wxEVT_LEAVE_WINDOW );
2414 child_event.SetEventObject( m_lastMouse );
84fba40b
RR
2415 child_event.m_x = x;
2416 child_event.m_y = y;
2417 m_lastMouse->ProcessCanvasObjectEvent( child_event );
fcbb6b37
KH
2418
2419 m_lastMouse = obj;
2420 child_event.SetEventType( wxEVT_ENTER_WINDOW );
2421 child_event.SetEventObject( m_lastMouse );
84fba40b
RR
2422 child_event.m_x = x;
2423 child_event.m_y = y;
2424 m_lastMouse->ProcessCanvasObjectEvent( child_event );
fcbb6b37
KH
2425
2426 child_event.SetEventType( wxEVT_MOTION );
2427 child_event.SetEventObject( obj );
239c1f50 2428 }
84fba40b
RR
2429
2430 obj->ProcessCanvasObjectEvent( child_event );
fcbb6b37 2431 return;
239c1f50 2432 }
239c1f50
RR
2433 }
2434 if (m_lastMouse)
2435 {
2436 wxMouseEvent child_event( wxEVT_LEAVE_WINDOW );
2437 child_event.SetEventObject( m_lastMouse );
84fba40b
RR
2438 child_event.m_x = x;
2439 child_event.m_y = y;
239c1f50
RR
2440 child_event.m_leftDown = event.m_leftDown;
2441 child_event.m_rightDown = event.m_rightDown;
2442 child_event.m_middleDown = event.m_middleDown;
2443 child_event.m_controlDown = event.m_controlDown;
2444 child_event.m_shiftDown = event.m_shiftDown;
2445 child_event.m_altDown = event.m_altDown;
2446 child_event.m_metaDown = event.m_metaDown;
84fba40b 2447 m_lastMouse->ProcessCanvasObjectEvent( child_event );
dc16900b 2448
239c1f50
RR
2449 m_lastMouse = (wxCanvasObject*) NULL;
2450 return;
2451 }
2452 }
872f1044
RR
2453 else
2454 {
2455 if (m_captureMouse) //no matter what go to this one
2456 {
2457 wxMouseEvent child_event( event.GetEventType() );
2458 child_event.SetEventObject(m_captureMouse);
84fba40b
RR
2459 child_event.m_x = x;
2460 child_event.m_y = y;
872f1044
RR
2461 child_event.m_leftDown = event.m_leftDown;
2462 child_event.m_rightDown = event.m_rightDown;
2463 child_event.m_middleDown = event.m_middleDown;
2464 child_event.m_controlDown = event.m_controlDown;
2465 child_event.m_shiftDown = event.m_shiftDown;
2466 child_event.m_altDown = event.m_altDown;
2467 child_event.m_metaDown = event.m_metaDown;
84fba40b 2468 m_captureMouse->ProcessCanvasObjectEvent( child_event );
872f1044
RR
2469 }
2470 else
2471 {
84fba40b 2472 wxCanvasObject *obj = m_root->IsHitWorld(xw,yw,margin);
872f1044
RR
2473
2474 if (obj && !obj->IsControl())
2475 {
2476 wxMouseEvent child_event( event.GetEventType() );
2477 child_event.SetEventObject( obj );
84fba40b
RR
2478 child_event.m_x = x;
2479 child_event.m_y = y;
872f1044
RR
2480 child_event.m_leftDown = event.m_leftDown;
2481 child_event.m_rightDown = event.m_rightDown;
2482 child_event.m_middleDown = event.m_middleDown;
2483 child_event.m_controlDown = event.m_controlDown;
2484 child_event.m_shiftDown = event.m_shiftDown;
2485 child_event.m_altDown = event.m_altDown;
2486 child_event.m_metaDown = event.m_metaDown;
84fba40b
RR
2487
2488 obj->ProcessCanvasObjectEvent( child_event );
872f1044
RR
2489 return;
2490 }
2491 }
2492 }
fcbb6b37 2493
239c1f50 2494 event.Skip();
6a2c1874
RR
2495}
2496
2497void wxCanvas::OnSize(wxSizeEvent &event)
2498{
b85cfb6f 2499 int w,h;
84fba40b 2500
b85cfb6f 2501 GetClientSize( &w, &h );
84fba40b 2502
33ebcd80 2503#if IMAGE_CANVAS
b85cfb6f 2504 m_buffer = wxImage( w, h );
33ebcd80 2505#else
84fba40b 2506 wxMemoryDC dc;
33ebcd80 2507 m_buffer = wxBitmap( w, h );
84fba40b
RR
2508 dc.SelectObject( m_buffer );
2509 dc.SetPen( *wxTRANSPARENT_PEN );
2510 wxBrush brush( m_background , wxSOLID );
2511 dc.SetBrush( brush );
2512 dc.DrawRectangle( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() );
2513 dc.SelectObject( wxNullBitmap );
fcbb6b37 2514
84fba40b 2515#endif
fcbb6b37 2516
b85cfb6f
RR
2517 wxNode *node = m_updateRects.First();
2518 while (node)
2519 {
2520 wxRect *rect = (wxRect*) node->Data();
2521 delete rect;
2522 m_updateRects.DeleteNode( node );
2523 node = m_updateRects.First();
2524 }
2525
2526 m_frozen = FALSE;
2527
84fba40b
RR
2528 m_admin->SetActive(this);
2529 SetMappingScroll(m_virt_minX,m_virt_minY,m_virt_maxX,m_virt_maxY,FALSE);
2530
2531 Update( 0,0, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
41328253 2532
6a2c1874
RR
2533 event.Skip();
2534}
2535
2536void wxCanvas::OnIdle(wxIdleEvent &event)
2537{
84fba40b 2538 m_admin->SetActive(this);
6a2c1874
RR
2539 UpdateNow();
2540 event.Skip();
2541}
2542
2543void wxCanvas::OnSetFocus(wxFocusEvent &event)
2544{
84fba40b 2545 m_admin->SetActive(this);
6a2c1874
RR
2546}
2547
2548void wxCanvas::OnKillFocus(wxFocusEvent &event)
2549{
2550}
2551
84fba40b
RR
2552
2553void wxCanvas::OnEraseBackground(wxEraseEvent &event)
6a2c1874 2554{
6a2c1874
RR
2555}
2556
84fba40b
RR
2557
2558
2559// maps the virtual window (Real drawing to the window coordinates
2560// also used for zooming
2561void wxCanvas::SetMappingScroll( double vx1, double vy1, double vx2, double vy2, bool border)
2562{
2563 int dwxi,dwyi;
2564 GetClientSize(&dwxi,&dwyi);
2565
2566 if (vx2==vx1) vx2=vx1+100000;
2567 if (vy2==vy1) vy2=vy1+100000;
2568 m_virt_minX=vx1;
2569 m_virt_minY=vy1;
2570 m_virt_maxX=vx2;
2571 m_virt_maxY=vy2;
2572
2573 double dwx=dwxi;
2574 double dwy=dwyi;
2575 if (dwx==0) dwx=1;
2576 if (dwy==0) dwy=1;
2577
2578 double dvx = m_virt_maxX - m_virt_minX;
2579 double dvy = m_virt_maxY - m_virt_minY;
2580
2581 // calculate the scaling factor for the virtual window
2582 double temp_x=0;
2583 double temp_y=0;
2584 if ((dvy / dvx) < (dwy / dwx))
2585 {
2586 dvy = dvx * (dwy / dwx);
2587 // calculate the change in the coordinates
2588 temp_y = (dvy - (m_virt_maxY - m_virt_minY) )/ 2.0;
2589 }
2590 else
2591 {
2592 dvx = dvy * (dwx / dwy);
2593 // calculate the change in the coordinates
2594 temp_x = (dvx - (m_virt_maxX - m_virt_minX) )/ 2.0;
2595 }
2596
2597 // add or substract the change from the original coordinates
2598 m_virt_minX=m_virt_minX-temp_x;
2599 m_virt_minY=m_virt_minY-temp_y;
2600
2601 m_virt_maxX=m_virt_maxX+temp_x;
2602 m_virt_maxY=m_virt_maxY+temp_y;
2603
2604 // initialize the mapping_matrix used for mapping the
2605 // virtual windows to the drawing window
2606
2607 // make mappingmatrix
2608 m_mapping_matrix.Identity();
2609 if (!border)
2610 // translate the drawing to 0,0
2611 if (m_yaxis)
2612 m_mapping_matrix.Translate(-m_virt_minX,-m_virt_maxY);
2613 else
2614 m_mapping_matrix.Translate(-m_virt_minX,-m_virt_minY);
2615 else
2616 {
2617 // make a small white border around the drawing
2618 m_virt_minX=m_virt_minX- 0.05 * dvx;
2619 m_virt_minY=m_virt_minY- 0.05 * dvy;
2620
2621 m_virt_maxX=m_virt_maxX+ 0.05 * dvx;
2622 m_virt_maxY=m_virt_maxY+ 0.05 * dvy;
2623
2624 // translate the drawing to 0,0
2625 if (m_yaxis)
2626 m_mapping_matrix.Translate(-m_virt_minX,-m_virt_maxY);
2627 else
2628 m_mapping_matrix.Translate(-m_virt_minX,-m_virt_minY);
2629 }
2630
2631 double scalefactor_x = dwx;
2632 scalefactor_x /= (m_virt_maxX - m_virt_minX);
2633
2634 double scalefactor_y = dwy;
2635 scalefactor_y /= (m_virt_maxY - m_virt_minY);
2636
2637 // scale the drawing so it fit's in the window
2638 m_mapping_matrix.Scale(scalefactor_x, scalefactor_y, 0, 0);
2639
2640 // because of coordinate change mirror over X
2641 // 0,0 in graphic computerscreens: upperleft corner
2642 // 0,0 in cartesian: lowerleft corner
2643 if (m_yaxis)
2644 {
2645 m_mapping_matrix.Mirror();
2646 }
2647 // make inverse of mapping matrix
2648 // this is to set coordinates in the statusbar
2649 // and the calculate screencoordinates to world coordinates used
2650 // in zooming
2651 m_inverse_mapping=m_mapping_matrix;
2652 m_inverse_mapping.Invert();
2653
2654 if (m_scrolled)
2655 SetScroll(m_virtm_minX,m_virtm_minY,m_virtm_maxX,m_virtm_maxY);
2656
2657 int dx2,dy2;
2658 GetClientSize(&dx2,&dy2);
2659 if ( dwxi != dx2 || dwyi != dy2) //scrollbar is/became empty
2660 SetScroll(m_virtm_minX,m_virtm_minY,m_virtm_maxX,m_virtm_maxY);
2661}
2662
2663
2664void wxCanvas::SetScroll(double vx1,double vy1,double vx2,double vy2)
2665{
2666 m_virtm_minX=vx1;
2667 m_virtm_minY=vy1;
2668 m_virtm_maxX=vx2;
2669 m_virtm_maxY=vy2;
2670
2671 double dvx = m_virt_maxX - m_virt_minX;
2672 double dvy = m_virt_maxY - m_virt_minY;
2673 double dmvx = m_virtm_maxX - m_virtm_minX;
2674 double dmvy = m_virtm_maxY - m_virtm_minY;
2675
2676 SetScrollbar(wxHORIZONTAL,(m_virt_minX-m_virtm_minX)/dmvx *1000,dvx/dmvx *1000,1000,true);
2677 if (m_yaxis)
2678 {
2679 SetScrollbar(wxVERTICAL,(m_virtm_maxY-m_virt_maxY)/dmvy *1000,dvy/dmvy *1000,1000,true);
2680 }
2681 else
2682 {
2683 SetScrollbar(wxVERTICAL,(m_virt_minY-m_virtm_minY)/dmvy *1000,dvy/dmvy *1000,1000,true);
2684 }
2685
2686 m_scrolled=true;
2687}
2688
2689// coordinates conversions
2690// -----------------------
2691double wxCanvas::DeviceToLogicalX(int x) const
61b64bd9 2692{
84fba40b 2693 return m_inverse_mapping.GetValue(0,0) * x + m_inverse_mapping.GetValue(2,0);
61b64bd9
RR
2694}
2695
84fba40b
RR
2696double wxCanvas::DeviceToLogicalY(int y) const
2697{
2698 return m_inverse_mapping.GetValue(1,1) * y + m_inverse_mapping.GetValue(2,1);
2699}
2700
2701double wxCanvas::DeviceToLogicalXRel(int x) const
2702{
2703 return x*m_inverse_mapping.GetValue(0,0);
2704}
2705
2706double wxCanvas::DeviceToLogicalYRel(int y) const
2707{
2708 return y*m_inverse_mapping.GetValue(1,1);
2709}
2710
2711int wxCanvas::LogicalToDeviceX(double x) const
2712{
2713 return (int) (m_mapping_matrix.GetValue(0,0) * x + m_mapping_matrix.GetValue(2,0) + 0.5);
2714}
2715
2716int wxCanvas::LogicalToDeviceY(double y) const
2717{
2718 return (int) (m_mapping_matrix.GetValue(1,1) * y + m_mapping_matrix.GetValue(2,1) + 0.5);
2719}
2720
2721int wxCanvas::LogicalToDeviceXRel(double x) const
2722{
2723 return (int) (x*m_mapping_matrix.GetValue(0,0) + 0.5);
2724}
2725
2726int wxCanvas::LogicalToDeviceYRel(double y) const
2727{
2728 return (int) (y*m_mapping_matrix.GetValue(1,1) + 0.5);
2729}
2730
2731
2732
2733// return the inverse mapping matrix for zooming or coordinates
2734wxTransformMatrix wxCanvas::GetInverseMappingMatrix()
2735{
2736 return m_inverse_mapping;
2737}
2738
2739wxTransformMatrix wxCanvas::GetMappingMatrix()
2740{
2741 return m_mapping_matrix;
2742}
2743
2744
2745// ----------------------------------------------------------------------------
2746// scrolling behaviour
2747// ----------------------------------------------------------------------------
2748
2749void wxCanvas::OnScroll(wxScrollWinEvent& event)
2750{
2751 if (event.GetEventType()==wxEVT_SCROLLWIN_THUMBRELEASE)
2752 {
2753 if (event.GetOrientation()==wxHORIZONTAL)
2754 {
2755 double x=m_virtm_minX+event.GetPosition()/1000.0*(m_virtm_maxX-m_virtm_minX);
2756 x=LogicalToDeviceXRel(x-m_virt_minX);
2757 ScrollWindow(-x, 0, (const wxRect *) NULL);
2758 }
2759 else
2760 {
2761 double y=m_virtm_minY+event.GetPosition()/1000.0*(m_virtm_maxY-m_virtm_minY);
2762 y=LogicalToDeviceYRel(y-m_virt_minY);
2763 ScrollWindow(0, -y, (const wxRect *) NULL);
2764 }
2765 }
2766 else if (event.GetEventType()==wxEVT_SCROLLWIN_PAGEUP)
2767 {
2768 if (event.GetOrientation()==wxHORIZONTAL)
2769 {
2770 double x=GetBufferWidth();
2771 ScrollWindow(x, 0, (const wxRect *) NULL);
2772 }
2773 else
2774 {
2775 double y=GetBufferHeight();
2776 ScrollWindow(0, y, (const wxRect *) NULL);
2777 }
2778 }
2779 else if (event.GetEventType()==wxEVT_SCROLLWIN_PAGEDOWN)
2780 {
2781 if (event.GetOrientation()==wxHORIZONTAL)
2782 {
2783 double x=-GetBufferWidth();
2784 ScrollWindow(x, 0, (const wxRect *) NULL);
2785 }
2786 else
2787 {
2788 double y=-GetBufferHeight();
2789 ScrollWindow(0, y, (const wxRect *) NULL);
2790 }
2791 }
2792 else if (event.GetEventType()==wxEVT_SCROLLWIN_LINEUP)
2793 {
2794 if (event.GetOrientation()==wxHORIZONTAL)
2795 {
2796 int x=GetBufferWidth()/10;
2797 ScrollWindow(x, 0, (const wxRect *) NULL);
2798 }
2799 else
2800 {
2801 int y=GetBufferHeight()/10;
2802 ScrollWindow(0, y, (const wxRect *) NULL);
2803 }
2804 }
2805 else if (event.GetEventType()==wxEVT_SCROLLWIN_LINEDOWN)
2806 {
2807 if (event.GetOrientation()==wxHORIZONTAL)
2808 {
2809 int x=-GetBufferWidth()/10;
2810 ScrollWindow(x, 0, (const wxRect *) NULL);
2811 }
2812 else
2813 {
2814 int y=-GetBufferHeight()/10;
2815 ScrollWindow(0, y, (const wxRect *) NULL);
2816 }
2817 }
2818
2819}
2820
2821void wxCanvas::OnChar(wxKeyEvent& event)
2822{
2823 switch ( event.KeyCode() )
2824 {
2825 case WXK_PAGEUP:
2826 case WXK_PRIOR:
2827 {
2828 double y=GetBufferHeight();
2829 ScrollWindow(0, y, (const wxRect *) NULL);
2830 }
2831 break;
2832 case WXK_PAGEDOWN:
2833 case WXK_NEXT:
2834 {
2835 double y=-GetBufferHeight();
2836 ScrollWindow(0, y, (const wxRect *) NULL);
2837 }
2838 break;
2839 case WXK_HOME:
2840 {
2841 double y=m_virtm_minY;
2842 y=LogicalToDeviceYRel(y-m_virt_minY);
2843 ScrollWindow(0, -y, (const wxRect *) NULL);
2844 }
2845 break;
2846 case WXK_END:
2847 {
2848 double y=m_virtm_minY+(m_virtm_maxY-m_virtm_minY);
2849 y=LogicalToDeviceYRel(y-m_virt_minY);
2850 ScrollWindow(0, -y, (const wxRect *) NULL);
2851 }
2852 break;
2853 case WXK_UP:
2854 {
2855 int y;
2856 if (!event.ControlDown())
2857 y=GetBufferHeight()/10;
2858 else
2859 y=GetBufferHeight();
2860 ScrollWindow(0, y, (const wxRect *) NULL);
2861 }
2862 break;
2863
2864 case WXK_DOWN:
2865 {
2866 int y;
2867 if (!event.ControlDown())
2868 y=-GetBufferHeight()/10;
2869 else
2870 y=-GetBufferHeight();
2871 ScrollWindow(0, y, (const wxRect *) NULL);
2872 }
2873 break;
2874
2875 case WXK_LEFT:
2876 {
2877 int x;
2878 if (!event.ControlDown())
2879 x=GetBufferWidth()/10;
2880 else
2881 x=GetBufferWidth();
2882 ScrollWindow(x, 0, (const wxRect *) NULL);
2883 }
2884 break;
2885 case WXK_RIGHT:
2886 {
2887 int x;
2888 if (!event.ControlDown())
2889 x=-GetBufferWidth()/10;
2890 else
2891 x=-GetBufferWidth();
2892 ScrollWindow(x, 0, (const wxRect *) NULL);
2893 }
2894 break;
2895 default:
2896 // not for us
2897 event.Skip();
2898 }
2899}
2900
2901
2902
2903
d1f9b206
RR
2904//--------------------------------------------------------------------
2905// wxCanvasModule
2906//--------------------------------------------------------------------
2907
2908class wxCanvasModule : public wxModule
2909{
2910public:
2911 virtual bool OnInit();
2912 virtual void OnExit();
2913
2914private:
2915 DECLARE_DYNAMIC_CLASS(wxCanvasModule)
2916};
2917
2918IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule)
6a2c1874 2919
d1f9b206
RR
2920bool wxCanvasModule::OnInit()
2921{
1e1af41e 2922#if wxUSE_FREETYPE
d1f9b206
RR
2923 int error = FT_Init_FreeType( &g_freetypeLibrary );
2924 if (error) return FALSE;
2925#endif
2926
2927 return TRUE;
2928}
2929
2930void wxCanvasModule::OnExit()
2931{
1e1af41e 2932#if wxUSE_FREETYPE
cb281cfc 2933 FT_Done_FreeType( g_freetypeLibrary );
d1f9b206
RR
2934#endif
2935}
84fba40b
RR
2936
2937
2938wxCanvasAdmin::wxCanvasAdmin()
2939{
2940
2941}
2942
2943wxCanvasAdmin::~wxCanvasAdmin()
2944{
2945
2946
2947}
2948
2949
2950void wxCanvasAdmin::Append( wxCanvas* canvas )
2951{
2952 m_canvaslist.Append( canvas );
2953}
2954
2955void wxCanvasAdmin::Remove( wxCanvas* canvas )
2956{
2957 m_canvaslist.DeleteObject( canvas );
2958}
2959
2960void wxCanvasAdmin::Update(wxCanvasObject* obj, double x, double y, double width, double height)
2961{
2962 wxNode *node = m_canvaslist.First();
2963 while (node)
2964 {
2965
2966 wxCanvas *canvas = (wxCanvas*) node->Data();
2967
2968 if (m_active == canvas)
2969 {
2970 int xi = canvas->LogicalToDeviceX( x);
2971 int yi = canvas->LogicalToDeviceY( y);
2972 int wi = canvas->LogicalToDeviceXRel( width );
2973 int hi = canvas->LogicalToDeviceYRel( height);
2974 //update a little more then is strictly needed,
2975 //to get rid of the 1 bit bugs
2976 if (canvas->GetYaxis())
2977 canvas->Update( xi-2, yi+hi-2, wi+4, -hi+4);
2978 else
2979 canvas->Update( xi-2, yi-2, wi+4, hi+4);
2980 }
2981 else
2982 { wxCanvasObject* topobj=canvas->GetRoot()->Contains(obj);
2983 if (topobj)
2984 {
2985 wxCanvas* tcanvas = m_active;
2986 SetActive(canvas);
2987
2988 /*
2989 //KKK TODO somehow the next does not work for update i do not know why
2990 canvas->GetRoot()->CalcBoundingBox();
2991 int xi = topobj->GetX();
2992 int yi = topobj->GetY();
2993 int wi = topobj->GetWidth();
2994 int hi = topobj->GetHeight();
2995 */
2996 canvas->Update( 0,0, canvas->GetBufferWidth(),canvas->GetBufferHeight());
2997 SetActive(tcanvas);
2998 }
2999 }
3000
3001 node = node->Next();
3002 }
3003}
3004
3005void wxCanvasAdmin::UpdateNow()
3006{
3007 wxNode *node = m_canvaslist.First();
3008 while (node)
3009 {
3010 wxCanvas *canvas = (wxCanvas*) node->Data();
3011
3012 canvas->UpdateNow();
3013 node = node->Next();
3014 }
3015}
3016
3017// coordinates conversions
3018// -----------------------
3019double wxCanvasAdmin::DeviceToLogicalX(int x) const
3020{
3021 return m_active->DeviceToLogicalX(x);
3022}
3023
3024double wxCanvasAdmin::DeviceToLogicalY(int y) const
3025{
3026 return m_active->DeviceToLogicalY(y);
3027}
3028
3029double wxCanvasAdmin::DeviceToLogicalXRel(int x) const
3030{
3031 return m_active->DeviceToLogicalXRel(x);
3032}
3033
3034double wxCanvasAdmin::DeviceToLogicalYRel(int y) const
3035{
3036 return m_active->DeviceToLogicalYRel(y);
3037}
3038
3039int wxCanvasAdmin::LogicalToDeviceX(double x) const
3040{
3041 return m_active->LogicalToDeviceX(x);
3042}
3043
3044int wxCanvasAdmin::LogicalToDeviceY(double y) const
3045{
3046 return m_active->LogicalToDeviceY(y);
3047}
3048
3049int wxCanvasAdmin::LogicalToDeviceXRel(double x) const
3050{
3051 return m_active->LogicalToDeviceXRel(x);
3052}
3053
3054int wxCanvasAdmin::LogicalToDeviceYRel(double y) const
3055{
3056 return m_active->LogicalToDeviceYRel(y);
3057}
3058
3059void wxCanvasAdmin::SetActive(wxCanvas* activate)
3060{
3061 wxNode *node = m_canvaslist.First();
3062 while (node)
3063 {
3064 wxCanvas *canvas = (wxCanvas*) node->Data();
3065
3066 if (activate == canvas)
3067 {
3068 m_active=canvas;
3069 break;
3070 }
3071 node = node->Next();
3072 }
3073}
3074
3075