]>
Commit | Line | Data |
---|---|---|
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 | } |