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