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