1 /////////////////////////////////////////////////////////////////////////////
3 // Author: Robert Roebling
5 // Copyright: 2000 (c) Robert Roebling
6 // Licence: wxWindows Licence
7 /////////////////////////////////////////////////////////////////////////////
10 #pragma implementation "canvas.cpp"
13 // For compilers that support precompilation, includes "wx/wx.h".
14 #include "wx/wxprec.h"
20 #include "wx/canvas/canvas.h"
24 #include <gdk/gdkrgb.h>
25 #include "wx/gtk/win_gtk.h"
28 #define USE_FREETYPE 1
31 #include <freetype/freetype.h>
34 //----------------------------------------------------------------------------
36 //----------------------------------------------------------------------------
39 FT_Library g_freetypeLibrary
;
42 //----------------------------------------------------------------------------
44 //----------------------------------------------------------------------------
46 wxCanvasObject::wxCanvasObject( int x
, int y
, int width
, int height
)
52 m_area
.height
= height
;
58 void wxCanvasObject::Move( int x
, int y
)
68 // TODO: sometimes faster to merge into 1 Update or
69 // to break up into four
70 m_owner
->Update( old_x
, old_y
, m_area
.width
, m_area
.height
);
71 m_owner
->Update( x
, y
, m_area
.width
, m_area
.height
);
75 bool wxCanvasObject::IsHit( int x
, int y
, int margin
)
77 return ((x
>= m_area
.x
-margin
) &&
78 (x
<= m_area
.x
+m_area
.width
+margin
) &&
79 (y
>= m_area
.y
-margin
) &&
80 (y
<= m_area
.y
+m_area
.height
+margin
));
83 void wxCanvasObject::WriteSVG( wxTextOutputStream
&stream
)
87 void wxCanvasObject::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
91 //----------------------------------------------------------------------------
93 //----------------------------------------------------------------------------
95 wxCanvasRect::wxCanvasRect( int x
, int y
, int w
, int h
, unsigned char red
, unsigned char green
, unsigned char blue
)
96 : wxCanvasObject( x
, y
, w
, h
)
103 void wxCanvasRect::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
105 wxImage
*image
= m_owner
->GetBuffer();
107 for (int y
= clip_y
; y
< clip_y
+clip_height
; y
++)
108 for (int x
= clip_x
; x
< clip_x
+clip_width
; x
++)
109 image
->SetRGB( x
, y
, m_red
, m_green
, m_blue
);
112 void wxCanvasRect::WriteSVG( wxTextOutputStream
&stream
)
116 //----------------------------------------------------------------------------
118 //----------------------------------------------------------------------------
120 wxCanvasLine::wxCanvasLine( int x
, int y
, int w
, int h
, unsigned char red
, unsigned char green
, unsigned char blue
)
121 : wxCanvasObject( x
, y
, w
, h
)
128 void wxCanvasLine::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
130 wxImage
*image
= m_owner
->GetBuffer();
132 if ((m_area
.width
== 0) && (m_area
.height
== 0))
134 image
->SetRGB( m_area
.x
, m_area
.y
, m_red
, m_green
, m_blue
);
140 int x2
= m_area
.x
+m_area
.width
;
141 int y2
= m_area
.y
+m_area
.height
;
143 wxInt32 d
, ii
, jj
, di
, ai
, si
, dj
, aj
, sj
;
146 si
= (di
< 0)? -1 : 1;
149 sj
= (dj
< 0)? -1 : 1;
161 if ((ii
>= clip_x
) && (ii
<= clip_x
+clip_width
) &&
162 (jj
>= clip_y
) && (jj
<= clip_y
+clip_height
))
164 image
->SetRGB( ii
, jj
, m_red
, m_blue
, m_green
);
182 if ((ii
>= clip_x
) && (ii
<= clip_x
+clip_width
) &&
183 (jj
>= clip_y
) && (jj
<= clip_y
+clip_height
))
185 image
->SetRGB( ii
, jj
, m_red
, m_blue
, m_green
);
199 void wxCanvasLine::WriteSVG( wxTextOutputStream
&stream
)
203 //----------------------------------------------------------------------------
205 //----------------------------------------------------------------------------
207 wxCanvasImage::wxCanvasImage( const wxImage
&image
, int x
, int y
)
208 : wxCanvasObject( x
, y
, image
.GetWidth(), image
.GetHeight() )
214 void wxCanvasImage::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
216 if ((clip_x
== m_area
.x
) &&
217 (clip_y
== m_area
.y
) &&
218 (clip_width
== m_area
.width
) &&
219 (clip_height
== m_area
.height
))
221 m_owner
->GetBuffer()->Paste( m_image
, clip_x
, clip_y
);
226 int start_x
= clip_x
- m_area
.x
;
227 int start_y
= clip_y
- m_area
.y
;
229 wxRect
rect( start_x
, start_y
, clip_width
, clip_height
);
230 wxImage
sub_image( m_image
.GetSubImage( rect
) );
231 m_owner
->GetBuffer()->Paste( sub_image
, clip_x
, clip_y
);
235 void wxCanvasImage::WriteSVG( wxTextOutputStream
&stream
)
240 //----------------------------------------------------------------------------
242 //----------------------------------------------------------------------------
244 wxCanvasControl::wxCanvasControl( wxWindow
*control
)
245 : wxCanvasObject( -1, -1, -1, -1 )
252 wxCanvasControl::~wxCanvasControl()
254 m_control
->Destroy();
257 void wxCanvasControl::Move( int x
, int y
)
259 m_control
->Move( x
, y
);
262 void wxCanvasControl::UpdateSize()
264 m_control
->GetSize( &m_area
.width
, &m_area
.height
);
265 m_control
->GetPosition( &m_area
.x
, &m_area
.y
);
268 //----------------------------------------------------------------------------
270 //----------------------------------------------------------------------------
282 wxCanvasText::wxCanvasText( const wxString
&text
, int x
, int y
, const wxString
&fontFile
, int size
)
283 : wxCanvasObject( x
, y
, -1, -1 )
286 m_fontFileName
= fontFile
;
295 m_area
.height
= m_size
;
296 m_alpha
= new unsigned char[100*m_size
];
297 memset( m_alpha
, 0, m_area
.width
*m_area
.height
);
300 wxFaceData
*data
= new wxFaceData
;
303 int error
= FT_New_Face( g_freetypeLibrary
,
308 error
= FT_Set_Char_Size( data
->m_face
,
317 wxCanvasText::~wxCanvasText()
320 wxFaceData
*data
= (wxFaceData
*) m_faceData
;
324 if (m_alpha
) delete [] m_alpha
;
327 void wxCanvasText::SetRGB( unsigned char red
, unsigned char green
, unsigned char blue
)
334 void wxCanvasText::SetFlag( int flag
)
339 void wxCanvasText::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
341 if (!m_alpha
) return;
343 wxImage
*image
= m_owner
->GetBuffer();
346 int start_x
= clip_x
- m_area
.x
;
347 int end_x
= clip_width
+ start_x
;
348 int start_y
= clip_y
- m_area
.y
;
349 int end_y
= clip_height
+ start_y
;
351 for (int y
= start_y
; y
< end_y
; y
++)
352 for (int x
= start_x
; x
< end_x
; x
++)
354 int alpha
= m_alpha
[y
*m_area
.width
+ x
];
357 int image_x
= m_area
.x
+x
;
358 int image_y
= m_area
.y
+y
;
361 image
->SetRGB( image_x
, image_y
, m_red
, m_green
, m_blue
);
364 int red1
= (m_red
* alpha
) / 255;
365 int green1
= (m_green
* alpha
) / 255;
366 int blue1
= (m_blue
* alpha
) / 255;
369 int red2
= image
->GetRed( image_x
, image_y
);
370 int green2
= image
->GetGreen( image_x
, image_y
);
371 int blue2
= image
->GetBlue( image_x
, image_y
);
372 red2
= (red2
* alpha
) / 255;
373 green2
= (green2
* alpha
) / 255;
374 blue2
= (blue2
* alpha
) / 255;
376 image
->SetRGB( image_x
, image_y
, red1
+red2
, green1
+green2
, blue1
+blue2
);
381 void wxCanvasText::WriteSVG( wxTextOutputStream
&stream
)
385 void wxCanvasText::CreateBuffer()
388 FT_Face face
= ((wxFaceData
*)m_faceData
)->m_face
;
389 FT_GlyphSlot slot
= face
->glyph
;
393 for (int n
= 0; n
< (int)m_text
.Len(); n
++)
395 FT_UInt index
= FT_Get_Char_Index( face
, m_text
[n
] );
397 int error
= FT_Load_Glyph( face
, index
, FT_LOAD_DEFAULT
);
400 error
= FT_Render_Glyph( face
->glyph
, ft_render_mode_normal
);
403 FT_Bitmap
*bitmap
= &slot
->bitmap
;
404 unsigned char* buffer
= bitmap
->buffer
;
405 for (int y
= 0; y
< bitmap
->rows
; y
++)
406 for (int x
= 0; x
< bitmap
->width
; x
++)
408 unsigned char alpha
= buffer
[ y
*bitmap
->pitch
+ x
];
409 if (alpha
== 0) continue;
411 int xx
= pen_x
+ slot
->bitmap_left
+ x
;
412 int yy
= pen_y
- slot
->bitmap_top
+ y
;
413 m_alpha
[ yy
* m_area
.width
+ xx
] = alpha
;
416 pen_x
+= slot
->advance
.x
>> 6;
417 pen_y
+= slot
->advance
.y
>> 6;
422 //----------------------------------------------------------------------------
424 //----------------------------------------------------------------------------
426 IMPLEMENT_CLASS(wxCanvas
,wxScrolledWindow
)
428 BEGIN_EVENT_TABLE(wxCanvas
,wxScrolledWindow
)
429 EVT_CHAR( wxCanvas::OnChar
)
430 EVT_PAINT( wxCanvas::OnPaint
)
431 EVT_SIZE( wxCanvas::OnSize
)
432 EVT_IDLE( wxCanvas::OnIdle
)
433 EVT_MOUSE_EVENTS( wxCanvas::OnMouse
)
434 EVT_SET_FOCUS( wxCanvas::OnSetFocus
)
435 EVT_KILL_FOCUS( wxCanvas::OnKillFocus
)
438 wxCanvas::wxCanvas( wxWindow
*parent
, wxWindowID id
,
439 const wxPoint
&position
, const wxSize
& size
, long style
) :
440 wxScrolledWindow( parent
, id
, position
, size
, style
)
442 m_needUpdate
= FALSE
;
443 m_objects
.DeleteContents( TRUE
);
447 m_lastMouse
= (wxCanvasObject
*)NULL
;
451 wxCanvas::~wxCanvas()
453 wxNode
*node
= m_updateRects
.First();
456 wxRect
*rect
= (wxRect
*) node
->Data();
458 m_updateRects
.DeleteNode( node
);
459 node
= m_updateRects
.First();
463 void wxCanvas::SetArea( int width
, int height
)
465 m_buffer
= wxImage( width
, height
);
466 SetScrollbars( 10, 10, width
/10, height
/10 );
469 void wxCanvas::SetColour( unsigned char red
, unsigned char green
, unsigned char blue
)
475 if (m_frozen
) return;
477 unsigned char *data
= m_buffer
.GetData();
479 for (int y
= 0; y
< m_buffer
.GetHeight(); y
++)
480 for (int x
= 0; x
< m_buffer
.GetWidth(); x
++)
491 void wxCanvas::Freeze()
496 void wxCanvas::Thaw()
498 wxNode
*node
= m_updateRects
.First();
501 wxRect
*rect
= (wxRect
*) node
->Data();
503 m_updateRects
.DeleteNode( node
);
504 node
= m_updateRects
.First();
509 Update( 0, 0, m_buffer
.GetWidth(), m_buffer
.GetHeight() );
512 void wxCanvas::Update( int x
, int y
, int width
, int height
)
514 if (m_frozen
) return;
522 if (width
< 0) return;
529 if (height
< 0) return;
531 if (x
+width
> m_buffer
.GetWidth())
533 width
= m_buffer
.GetWidth() - x
;
535 if (width
< 0) return;
537 if (y
+height
> m_buffer
.GetHeight())
539 height
= m_buffer
.GetHeight() - y
;
541 if (height
< 0) return;
543 // update is within the buffer
546 // has to be blitted to screen later
547 m_updateRects
.Append(
548 (wxObject
*) new wxRect( x
,y
,width
,height
) );
550 // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b)
551 for (int yy
= y
; yy
< y
+height
; yy
++)
552 for (int xx
= x
; xx
< x
+width
; xx
++)
553 m_buffer
.SetRGB( xx
, yy
, m_red
, m_green
, m_blue
);
555 // cycle through all objects
556 wxNode
*node
= m_objects
.First();
559 wxCanvasObject
*obj
= (wxCanvasObject
*) node
->Data();
561 if (!obj
->IsControl())
563 // If we have 10.000 objects, we will go through
564 // this 10.000 times for each update, so we have
565 // to optimise carefully.
566 int clip_x
= obj
->GetX();
567 int clip_width
= obj
->GetWidth();
570 clip_width
-= x
-clip_x
;
575 if (clip_x
+ clip_width
> x
+ width
)
576 clip_width
= x
+width
-clip_x
;
580 int clip_y
= obj
->GetY();
581 int clip_height
= obj
->GetHeight();
584 clip_height
-= y
-clip_y
;
589 if (clip_y
+ clip_height
> y
+ height
)
590 clip_height
= y
+height
-clip_y
;
593 obj
->Render( clip_x
, clip_y
, clip_width
, clip_height
);
603 void wxCanvas::BlitBuffer( wxDC
&dc
)
605 wxNode
*node
= m_updateRects
.First();
608 wxRect
*rect
= (wxRect
*) node
->Data();
609 wxImage
sub_image( m_buffer
.GetSubImage( *rect
) );
611 // DirectDraw here, please
614 int bpp
= wxDisplayDepth();
617 // the init code is doubled in wxImage
618 static bool s_hasInitialized
= FALSE
;
620 if (!s_hasInitialized
)
623 s_hasInitialized
= TRUE
;
628 CalcScrolledPosition( x
, y
, &x
, &y
);
630 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow
)->bin_window
,
631 m_wxwindow
->style
->black_gc
,
633 sub_image
.GetWidth(), sub_image
.GetHeight(),
636 sub_image
.GetWidth()*3 );
640 wxBitmap
bitmap( sub_image
.ConvertToBitmap() );
641 dc
.DrawBitmap( bitmap
, rect
->x
, rect
->y
);
646 wxBitmap
bitmap( sub_image
.ConvertToBitmap() );
647 dc
.DrawBitmap( bitmap
, rect
->x
, rect
->y
);
651 m_updateRects
.DeleteNode( node
);
652 node
= m_updateRects
.First();
655 m_needUpdate
= FALSE
;
658 void wxCanvas::UpdateNow()
660 if (!m_needUpdate
) return;
662 wxClientDC
dc( this );
668 void wxCanvas::Prepend( wxCanvasObject
* obj
)
670 m_objects
.Insert( obj
);
672 obj
->SetOwner( this );
674 if (!obj
->IsControl())
675 Update( obj
->GetX(), obj
->GetY(), obj
->GetWidth(), obj
->GetHeight() );
678 void wxCanvas::Append( wxCanvasObject
* obj
)
680 m_objects
.Append( obj
);
682 obj
->SetOwner( this );
684 if (!obj
->IsControl())
685 Update( obj
->GetX(), obj
->GetY(), obj
->GetWidth(), obj
->GetHeight() );
688 void wxCanvas::Insert( size_t before
, wxCanvasObject
* obj
)
690 m_objects
.Insert( before
, obj
);
692 obj
->SetOwner( this );
694 if (!obj
->IsControl())
695 Update( obj
->GetX(), obj
->GetY(), obj
->GetWidth(), obj
->GetHeight() );
698 void wxCanvas::Remove( wxCanvasObject
* obj
)
702 int w
= obj
->GetWidth();
703 int h
= obj
->GetHeight();
704 bool ic
= obj
->IsControl();
706 m_objects
.DeleteObject( obj
);
709 Update( x
, y
, w
, h
);
712 void wxCanvas::OnPaint(wxPaintEvent
&event
)
719 wxRegionIterator
it( GetUpdateRegion() );
724 CalcUnscrolledPosition( x
, y
, &x
, &y
);
726 int w
= it
.GetWidth();
727 int h
= it
.GetHeight();
729 if (x
+w
> m_buffer
.GetWidth())
730 w
= m_buffer
.GetWidth() - x
;
731 if (y
+h
> m_buffer
.GetHeight())
732 h
= m_buffer
.GetHeight() - y
;
734 if ((w
> 0) && (h
> 0))
735 m_updateRects
.Append( (wxObject
*) new wxRect( x
, y
, w
, h
) );
743 void wxCanvas::OnMouse(wxMouseEvent
&event
)
745 // should we implement mouse capture ?
747 int x
= event
.GetX();
748 int y
= event
.GetY();
749 CalcUnscrolledPosition( x
, y
, &x
, &y
);
751 if (event
.GetEventType() == wxEVT_MOTION
)
753 wxNode
*node
= m_objects
.First();
756 wxCanvasObject
*obj
= (wxCanvasObject
*) node
->Data();
758 if (!obj
->IsControl())
762 wxMouseEvent
child_event( wxEVT_MOTION
);
763 child_event
.SetEventObject( obj
);
764 child_event
.m_x
= x
+ obj
->GetX();
765 child_event
.m_y
= y
+ obj
->GetY();
766 child_event
.m_leftDown
= event
.m_leftDown
;
767 child_event
.m_rightDown
= event
.m_rightDown
;
768 child_event
.m_middleDown
= event
.m_middleDown
;
769 child_event
.m_controlDown
= event
.m_controlDown
;
770 child_event
.m_shiftDown
= event
.m_shiftDown
;
771 child_event
.m_altDown
= event
.m_altDown
;
772 child_event
.m_metaDown
= event
.m_metaDown
;
774 if ((obj
!= m_lastMouse
) && (m_lastMouse
!= NULL
))
776 child_event
.SetEventType( wxEVT_LEAVE_WINDOW
);
777 child_event
.SetEventObject( m_lastMouse
);
778 child_event
.m_x
= x
+ m_lastMouse
->GetX();
779 child_event
.m_y
= y
+ m_lastMouse
->GetY();
780 m_lastMouse
->ProcessEvent( child_event
);
783 child_event
.SetEventType( wxEVT_ENTER_WINDOW
);
784 child_event
.SetEventObject( m_lastMouse
);
785 child_event
.m_x
= x
+ m_lastMouse
->GetX();
786 child_event
.m_y
= y
+ m_lastMouse
->GetY();
787 m_lastMouse
->ProcessEvent( child_event
);
789 child_event
.SetEventType( wxEVT_MOTION
);
790 child_event
.SetEventObject( obj
);
792 obj
->ProcessEvent( child_event
);
800 wxMouseEvent
child_event( wxEVT_LEAVE_WINDOW
);
801 child_event
.SetEventObject( m_lastMouse
);
802 child_event
.m_x
= x
+ m_lastMouse
->GetX();
803 child_event
.m_y
= y
+ m_lastMouse
->GetY();
804 child_event
.m_leftDown
= event
.m_leftDown
;
805 child_event
.m_rightDown
= event
.m_rightDown
;
806 child_event
.m_middleDown
= event
.m_middleDown
;
807 child_event
.m_controlDown
= event
.m_controlDown
;
808 child_event
.m_shiftDown
= event
.m_shiftDown
;
809 child_event
.m_altDown
= event
.m_altDown
;
810 child_event
.m_metaDown
= event
.m_metaDown
;
811 m_lastMouse
->ProcessEvent( child_event
);
813 m_lastMouse
= (wxCanvasObject
*) NULL
;
820 void wxCanvas::OnSize(wxSizeEvent
&event
)
825 void wxCanvas::OnIdle(wxIdleEvent
&event
)
831 void wxCanvas::OnSetFocus(wxFocusEvent
&event
)
835 void wxCanvas::OnKillFocus(wxFocusEvent
&event
)
839 void wxCanvas::OnChar(wxKeyEvent
&event
)
844 //--------------------------------------------------------------------
846 //--------------------------------------------------------------------
848 class wxCanvasModule
: public wxModule
851 virtual bool OnInit();
852 virtual void OnExit();
855 DECLARE_DYNAMIC_CLASS(wxCanvasModule
)
858 IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule
, wxModule
)
860 bool wxCanvasModule::OnInit()
863 int error
= FT_Init_FreeType( &g_freetypeLibrary
);
864 if (error
) return FALSE
;
870 void wxCanvasModule::OnExit()
873 FT_Done_FreeType( g_freetypeLibrary
);