]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/canvas/canvas.cpp
27fe98cb4a8ea5a8cd5efc41d4c6ba8d97d9ae7c
[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
22 #ifdef __WXGTK__
23 #include <gtk/gtk.h>
24 #include <gdk/gdkrgb.h>
25 #include "wx/gtk/win_gtk.h"
26 #endif
27
28 #define USE_FREETYPE 1
29
30 #if USE_FREETYPE
31 #include <freetype/freetype.h>
32 #endif
33
34 //----------------------------------------------------------------------------
35 // globals
36 //----------------------------------------------------------------------------
37
38 #if USE_FREETYPE
39 FT_Library g_freetypeLibrary;
40 #endif
41
42 //----------------------------------------------------------------------------
43 // wxCanvasObject
44 //----------------------------------------------------------------------------
45
46 wxCanvasObject::wxCanvasObject( int x, int y, int width, int height )
47 {
48 m_owner = NULL;
49 m_area.x = x;
50 m_area.y = y;
51 m_area.width = width;
52 m_area.height = height;
53 m_isControl = FALSE;
54 m_isVector = FALSE;
55 m_isImage = FALSE;
56 }
57
58 void wxCanvasObject::Move( int x, int y )
59 {
60 int old_x = m_area.x;
61 int old_y = m_area.y;
62
63 m_area.x = x;
64 m_area.y = y;
65
66 if (!m_isControl)
67 {
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 );
72 }
73 }
74
75 void wxCanvasObject::WriteSVG( wxTextOutputStream &stream )
76 {
77 }
78
79 void wxCanvasObject::Render( int clip_x, int clip_y, int clip_width, int clip_height )
80 {
81 }
82
83 //----------------------------------------------------------------------------
84 // wxCanvasImage
85 //----------------------------------------------------------------------------
86
87 wxCanvasImage::wxCanvasImage( const wxImage &image, int x, int y )
88 : wxCanvasObject( x, y, image.GetWidth(), image.GetHeight() )
89 {
90 m_image = image;
91 m_isImage = TRUE;
92 }
93
94 void wxCanvasImage::Render( int clip_x, int clip_y, int clip_width, int clip_height )
95 {
96 int start_x = wxMax( 0, clip_x-m_area.x );
97 int end_x = wxMin( m_area.width, clip_width+clip_x-m_area.x );
98 int start_y = wxMax( 0, clip_y-m_area.y );
99 int end_y = wxMin( m_area.height, clip_height+clip_y-m_area.y );
100
101 if (end_x < start_x) return;
102 if (end_y < start_y) return;
103
104 if ((start_x == 0) &&
105 (start_y == 0) &&
106 (end_x == m_area.width) &&
107 (end_y == m_area.height))
108 {
109 m_owner->GetBuffer()->Paste( m_image, m_area.x, m_area.y );
110 }
111 else
112 {
113 wxRect rect( start_x, start_y, end_x-start_x, end_y-start_y );
114 wxImage sub_image( m_image.GetSubImage( rect ) );
115 m_owner->GetBuffer()->Paste( sub_image, m_area.x+start_x, m_area.y+start_y );
116 }
117 }
118
119 void wxCanvasImage::WriteSVG( wxTextOutputStream &stream )
120 {
121 // no idea
122 }
123
124 //----------------------------------------------------------------------------
125 // wxCanvasCtrl
126 //----------------------------------------------------------------------------
127
128 wxCanvasControl::wxCanvasControl( wxWindow *control )
129 : wxCanvasObject( -1, -1, -1, -1 )
130 {
131 m_control = control;
132 UpdateSize();
133 }
134
135 wxCanvasControl::~wxCanvasControl()
136 {
137 m_control->Destroy();
138 }
139
140 void wxCanvasControl::Move( int x, int y )
141 {
142 m_control->Move( x, y );
143 }
144
145 void wxCanvasControl::UpdateSize()
146 {
147 m_control->GetSize( &m_area.width, &m_area.height );
148 m_control->GetPosition( &m_area.x, &m_area.y );
149 }
150
151 //----------------------------------------------------------------------------
152 // wxCanvasText
153 //----------------------------------------------------------------------------
154
155 class wxFaceData
156 {
157 public:
158 #if USE_FREETYPE
159 FT_Face m_face;
160 #else
161 void *m_dummy;
162 #endif
163 };
164
165 wxCanvasText::wxCanvasText( const wxString &text, int x, int y, const wxString &fontFile, int size )
166 : wxCanvasObject( x, y, -1, -1 )
167 {
168 m_text = text;
169 m_fontFileName = fontFile;
170 m_size = size;
171
172 m_red = 0;
173 m_green = 0;
174 m_blue = 0;
175
176 // test
177 m_area.width = 100;
178 m_area.height = m_size;
179 m_alpha = new unsigned char[100*m_size];
180 memset( m_alpha, 0, m_area.width*m_area.height );
181
182 #if USE_FREETYPE
183 wxFaceData *data = new wxFaceData;
184 m_faceData = data;
185
186 int error = FT_New_Face( g_freetypeLibrary,
187 m_fontFileName,
188 0,
189 &(data->m_face) );
190
191 error = FT_Set_Char_Size( data->m_face,
192 0,
193 m_size*64,
194 96, // screen dpi
195 96 );
196 CreateBuffer();
197 #endif
198 }
199
200 wxCanvasText::~wxCanvasText()
201 {
202 #if USE_FREETYPE
203 wxFaceData *data = (wxFaceData*) m_faceData;
204 delete data;
205 #endif
206
207 if (m_alpha) delete [] m_alpha;
208 }
209
210 void wxCanvasText::SetRGB( unsigned char red, unsigned char green, unsigned char blue )
211 {
212 m_red = red;
213 m_green = green;
214 m_blue = blue;
215 }
216
217 void wxCanvasText::SetFlag( int flag )
218 {
219 m_flag = flag;
220 }
221
222 void wxCanvasText::Render( int clip_x, int clip_y, int clip_width, int clip_height )
223 {
224 if (!m_alpha) return;
225
226 wxImage *image = m_owner->GetBuffer();
227
228 int start_x = wxMax( 0, clip_x-m_area.x );
229 int end_x = wxMin( m_area.width, clip_width+clip_x-m_area.x );
230 int start_y = wxMax( 0, clip_y-m_area.y );
231 int end_y = wxMin( m_area.height, clip_height+clip_y-m_area.y );
232
233 for (int y = start_y; y < end_y; y++)
234 for (int x = start_x; x < end_x; x++)
235 {
236 int alpha = m_alpha[y*m_area.width + x];
237 if (alpha)
238 {
239 int image_x = m_area.x+x;
240 int image_y = m_area.y+y;
241 if (alpha == 255)
242 {
243 image->SetRGB( image_x, image_y, m_red, m_green, m_blue );
244 continue;
245 }
246 int red1 = (m_red * alpha) / 255;
247 int green1 = (m_green * alpha) / 255;
248 int blue1 = (m_blue * alpha) / 255;
249
250 alpha = 255-alpha;
251 int red2 = image->GetRed( image_x, image_y );
252 int green2 = image->GetGreen( image_x, image_y );
253 int blue2 = image->GetBlue( image_x, image_y );
254 red2 = (red2 * alpha) / 255;
255 green2 = (green2 * alpha) / 255;
256 blue2 = (blue2 * alpha) / 255;
257
258 image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
259 }
260 }
261 }
262
263 void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
264 {
265 }
266
267 void wxCanvasText::CreateBuffer()
268 {
269 #if USE_FREETYPE
270 FT_Face face = ((wxFaceData*)m_faceData)->m_face;
271 FT_GlyphSlot slot = face->glyph;
272 int pen_x = 0;
273 int pen_y = m_size;
274
275 for (int n = 0; n < (int)m_text.Len(); n++)
276 {
277 FT_UInt index = FT_Get_Char_Index( face, m_text[n] );
278
279 int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
280 if (error) continue;
281
282 error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
283 if (error) continue;
284
285 FT_Bitmap *bitmap = &slot->bitmap;
286 unsigned char* buffer = bitmap->buffer;
287 for (int y = 0; y < bitmap->rows; y++)
288 for (int x = 0; x < bitmap->width; x++)
289 {
290 unsigned char alpha = buffer[ y*bitmap->pitch + x ];
291 if (alpha == 0) continue;
292
293 int xx = pen_x + slot->bitmap_left + x;
294 int yy = pen_y - slot->bitmap_top + y;
295 m_alpha[ yy * m_area.width + xx ] = alpha;
296 }
297
298 pen_x += slot->advance.x >> 6;
299 pen_y += slot->advance.y >> 6;
300 }
301 #endif
302 }
303
304 //----------------------------------------------------------------------------
305 // wxCanvas
306 //----------------------------------------------------------------------------
307
308 IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow)
309
310 BEGIN_EVENT_TABLE(wxCanvas,wxScrolledWindow)
311 EVT_CHAR( wxCanvas::OnChar )
312 EVT_PAINT( wxCanvas::OnPaint )
313 EVT_SIZE( wxCanvas::OnSize )
314 EVT_IDLE( wxCanvas::OnIdle )
315 EVT_MOUSE_EVENTS( wxCanvas::OnMouse )
316 EVT_SET_FOCUS( wxCanvas::OnSetFocus )
317 EVT_KILL_FOCUS( wxCanvas::OnKillFocus )
318 END_EVENT_TABLE()
319
320 wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
321 const wxPoint &position, const wxSize& size, long style ) :
322 wxScrolledWindow( parent, id, position, size, style )
323 {
324 m_needUpdate = FALSE;
325 m_objects.DeleteContents( TRUE );
326 m_red = 0;
327 m_green = 0;
328 m_blue = 0;
329 }
330
331 wxCanvas::~wxCanvas()
332 {
333 wxNode *node = m_updateRects.First();
334 while (node)
335 {
336 wxRect *rect = (wxRect*) node->Data();
337 delete rect;
338 m_updateRects.DeleteNode( node );
339 node = m_updateRects.First();
340 }
341 }
342
343 void wxCanvas::SetArea( int width, int height )
344 {
345 m_buffer = wxImage( width, height );
346 SetScrollbars( 10, 10, width/10, height/10 );
347 }
348
349 void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char blue )
350 {
351 m_red = red;
352 m_green = green;
353 m_blue = blue;
354
355 unsigned char *data = m_buffer.GetData();
356
357 for (int y = 0; y < m_buffer.GetHeight(); y++)
358 for (int x = 0; x < m_buffer.GetWidth(); x++)
359 {
360 data[0] = red;
361 data++;
362 data[0] = green;
363 data++;
364 data[0] = blue;
365 data++;
366 }
367 }
368
369 void wxCanvas::Update( int x, int y, int width, int height )
370 {
371 m_needUpdate = TRUE;
372
373 m_updateRects.Append(
374 (wxObject*) new wxRect( x,y,width,height ) );
375
376 // speed up with direct access, maybe add wxImage::Clear(x,y,w,h)
377 int xx,yy,ww,hh;
378 for (yy = y; yy < y+height; yy++)
379 for (xx = x; xx < x+width; xx++)
380 m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue );
381
382 wxNode *node = m_objects.First();
383 while (node)
384 {
385 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
386 xx = obj->GetX();
387 yy = obj->GetY();
388 ww = obj->GetWidth();
389 hh = obj->GetHeight();
390
391 if (!obj->IsControl()) // calc intersection !
392 {
393 obj->Render( x, y, width, height );
394 }
395
396 node = node->Next();
397 }
398 }
399
400 void wxCanvas::BlitBuffer( wxDC &dc )
401 {
402 wxNode *node = m_updateRects.First();
403 while (node)
404 {
405 wxRect *rect = (wxRect*) node->Data();
406 wxImage sub_image( m_buffer.GetSubImage( *rect ) );
407
408 // DirectDraw here, please
409
410 #ifdef __WXGTK__
411 int bpp = wxDisplayDepth();
412 if (bpp > 8)
413 {
414 // the init code is doubled in wxImage
415 static bool s_hasInitialized = FALSE;
416
417 if (!s_hasInitialized)
418 {
419 gdk_rgb_init();
420 s_hasInitialized = TRUE;
421 }
422
423 int x = rect->x;
424 int y = rect->y;
425 CalcScrolledPosition( x, y, &x, &y );
426
427 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow)->bin_window,
428 m_wxwindow->style->black_gc,
429 x, y,
430 sub_image.GetWidth(), sub_image.GetHeight(),
431 GDK_RGB_DITHER_NONE,
432 sub_image.GetData(),
433 sub_image.GetWidth()*3 );
434 }
435 else
436 {
437 wxBitmap bitmap( sub_image.ConvertToBitmap() );
438 dc.DrawBitmap( bitmap, rect->x, rect->y );
439 }
440 #endif
441
442 #ifndef __WXGTK__
443 wxBitmap bitmap( sub_image.ConvertToBitmap() );
444 dc.DrawBitmap( bitmap, rect->x, rect->y );
445 #endif
446
447 delete rect;
448 m_updateRects.DeleteNode( node );
449 node = m_updateRects.First();
450 }
451
452 m_needUpdate = FALSE;
453 }
454
455 void wxCanvas::UpdateNow()
456 {
457 if (!m_needUpdate) return;
458
459 wxClientDC dc( this );
460 PrepareDC( dc );
461
462 BlitBuffer( dc );
463 }
464
465 void wxCanvas::Prepend( wxCanvasObject* obj )
466 {
467 m_objects.Insert( obj );
468
469 obj->SetOwner( this );
470
471 if (!obj->IsControl())
472 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
473 }
474
475 void wxCanvas::Append( wxCanvasObject* obj )
476 {
477 m_objects.Append( obj );
478
479 obj->SetOwner( this );
480
481 if (!obj->IsControl())
482 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
483 }
484
485 void wxCanvas::Insert( size_t before, wxCanvasObject* obj )
486 {
487 m_objects.Insert( before, obj );
488
489 obj->SetOwner( this );
490
491 if (!obj->IsControl())
492 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
493 }
494
495 void wxCanvas::Remove( wxCanvasObject* obj )
496 {
497 int x = obj->GetX();
498 int y = obj->GetY();
499 int w = obj->GetWidth();
500 int h = obj->GetHeight();
501 bool ic = obj->IsControl();
502
503 m_objects.DeleteObject( obj );
504
505 if (!ic)
506 Update( x, y, w, h );
507 }
508
509 void wxCanvas::OnPaint(wxPaintEvent &event)
510 {
511 wxPaintDC dc(this);
512 PrepareDC( dc );
513
514 m_needUpdate = TRUE;
515
516 wxRegionIterator it( GetUpdateRegion() );
517 while (it)
518 {
519 int x = it.GetX();
520 int y = it.GetY();
521 CalcUnscrolledPosition( x, y, &x, &y );
522
523 int w = it.GetWidth();
524 int h = it.GetHeight();
525 if (x + w > m_buffer.GetWidth())
526 w = m_buffer.GetWidth()-x;
527 if (y + h > m_buffer.GetHeight())
528 h = m_buffer.GetHeight()-y;
529
530 m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) );
531
532 it++;
533 }
534
535 BlitBuffer( dc );
536 }
537
538 void wxCanvas::OnMouse(wxMouseEvent &event)
539 {
540 // Propagate to objects here
541 }
542
543 void wxCanvas::OnSize(wxSizeEvent &event)
544 {
545 event.Skip();
546 }
547
548 void wxCanvas::OnIdle(wxIdleEvent &event)
549 {
550 UpdateNow();
551 event.Skip();
552 }
553
554 void wxCanvas::OnSetFocus(wxFocusEvent &event)
555 {
556 }
557
558 void wxCanvas::OnKillFocus(wxFocusEvent &event)
559 {
560 }
561
562 void wxCanvas::OnChar(wxKeyEvent &event)
563 {
564 event.Skip();
565 }
566
567 //--------------------------------------------------------------------
568 // wxCanvasModule
569 //--------------------------------------------------------------------
570
571 class wxCanvasModule : public wxModule
572 {
573 public:
574 virtual bool OnInit();
575 virtual void OnExit();
576
577 private:
578 DECLARE_DYNAMIC_CLASS(wxCanvasModule)
579 };
580
581 IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule)
582
583 bool wxCanvasModule::OnInit()
584 {
585 #if USE_FREETYPE
586 int error = FT_Init_FreeType( &g_freetypeLibrary );
587 if (error) return FALSE;
588 #endif
589
590 return TRUE;
591 }
592
593 void wxCanvasModule::OnExit()
594 {
595 #if USE_FREETYPE
596 FT_Done_FreeType( g_freetypeLibrary );
597 #endif
598 }