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