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