]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/bitmap.cpp
wxDC scaling fix patch (Derry Bryson)
[wxWidgets.git] / src / gtk1 / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: bitmap.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "bitmap.h"
12 #endif
13
14 #include "wx/bitmap.h"
15 #include "wx/icon.h"
16 #include "wx/filefn.h"
17 #include "wx/image.h"
18 #include "wx/dcmemory.h"
19
20 #include <gdk/gdk.h>
21 #include <gtk/gtk.h>
22
23 extern void gdk_wx_draw_bitmap (GdkDrawable *drawable,
24 GdkGC *gc,
25 GdkDrawable *src,
26 gint xsrc,
27 gint ysrc,
28 gint xdest,
29 gint ydest,
30 gint width,
31 gint height);
32
33 //-----------------------------------------------------------------------------
34 // data
35 //-----------------------------------------------------------------------------
36
37 extern GtkWidget *wxRootWindow;
38
39 //-----------------------------------------------------------------------------
40 // wxMask
41 //-----------------------------------------------------------------------------
42
43 IMPLEMENT_DYNAMIC_CLASS(wxMask,wxObject)
44
45 wxMask::wxMask()
46 {
47 m_bitmap = (GdkBitmap *) NULL;
48 }
49
50 wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
51 {
52 m_bitmap = (GdkBitmap *) NULL;
53 Create( bitmap, colour );
54 }
55
56 wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
57 {
58 m_bitmap = (GdkBitmap *) NULL;
59 Create( bitmap, paletteIndex );
60 }
61
62 wxMask::wxMask( const wxBitmap& bitmap )
63 {
64 m_bitmap = (GdkBitmap *) NULL;
65 Create( bitmap );
66 }
67
68 wxMask::~wxMask()
69 {
70 if (m_bitmap)
71 gdk_bitmap_unref( m_bitmap );
72 }
73
74 bool wxMask::Create( const wxBitmap& bitmap,
75 const wxColour& colour )
76 {
77 if (m_bitmap)
78 {
79 gdk_bitmap_unref( m_bitmap );
80 m_bitmap = (GdkBitmap*) NULL;
81 }
82
83 wxImage image( bitmap );
84 if (!image.Ok()) return FALSE;
85
86 m_bitmap = gdk_pixmap_new( wxRootWindow->window, image.GetWidth(), image.GetHeight(), 1 );
87 GdkGC *gc = gdk_gc_new( m_bitmap );
88
89 GdkColor color;
90 color.red = 65000;
91 color.green = 65000;
92 color.blue = 65000;
93 color.pixel = 1;
94 gdk_gc_set_foreground( gc, &color );
95 gdk_gc_set_fill( gc, GDK_SOLID );
96 gdk_draw_rectangle( m_bitmap, gc, TRUE, 0, 0, image.GetWidth(), image.GetHeight() );
97
98 unsigned char *data = image.GetData();
99 int index = 0;
100
101 unsigned char red = colour.Red();
102 unsigned char green = colour.Green();
103 unsigned char blue = colour.Blue();
104
105 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
106 wxASSERT( visual );
107
108 int bpp = visual->depth;
109 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
110 if (bpp == 15)
111 {
112 red = red & 0xf8;
113 green = green & 0xf8;
114 blue = blue & 0xf8;
115 }
116 if (bpp == 16)
117 {
118 red = red & 0xf8;
119 green = green & 0xfc;
120 blue = blue & 0xf8;
121 }
122
123 color.red = 0;
124 color.green = 0;
125 color.blue = 0;
126 color.pixel = 0;
127 gdk_gc_set_foreground( gc, &color );
128
129 for (int j = 0; j < image.GetHeight(); j++)
130 {
131 int start_x = -1;
132 int i;
133 for (i = 0; i < image.GetWidth(); i++)
134 {
135 if ((data[index] == red) &&
136 (data[index+1] == green) &&
137 (data[index+2] == blue))
138 {
139 if (start_x == -1)
140 start_x = i;
141 }
142 else
143 {
144 if (start_x != -1)
145 {
146 gdk_draw_line( m_bitmap, gc, start_x, j, i-1, j );
147 start_x = -1;
148 }
149 }
150 index += 3;
151 }
152 if (start_x != -1)
153 gdk_draw_line( m_bitmap, gc, start_x, j, i, j );
154 }
155
156 gdk_gc_unref( gc );
157
158 return TRUE;
159 }
160
161 bool wxMask::Create( const wxBitmap& WXUNUSED(bitmap),
162 int WXUNUSED(paletteIndex) )
163 {
164 if (m_bitmap)
165 {
166 gdk_bitmap_unref( m_bitmap );
167 m_bitmap = (GdkBitmap*) NULL;
168 }
169
170 wxFAIL_MSG( wxT("not implemented") );
171
172 return FALSE;
173 }
174
175 bool wxMask::Create( const wxBitmap& bitmap )
176 {
177 if (m_bitmap)
178 {
179 gdk_bitmap_unref( m_bitmap );
180 m_bitmap = (GdkBitmap*) NULL;
181 }
182
183 if (!bitmap.Ok()) return FALSE;
184
185 wxCHECK_MSG( bitmap.GetBitmap(), FALSE, wxT("Cannot create mask from colour bitmap") );
186
187 m_bitmap = gdk_pixmap_new( wxRootWindow->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
188
189 if (!m_bitmap) return FALSE;
190
191 GdkGC *gc = gdk_gc_new( m_bitmap );
192
193 gdk_wx_draw_bitmap( m_bitmap, gc, bitmap.GetBitmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight() );
194
195 gdk_gc_unref( gc );
196
197 return TRUE;
198 }
199
200 GdkBitmap *wxMask::GetBitmap() const
201 {
202 return m_bitmap;
203 }
204
205 //-----------------------------------------------------------------------------
206 // wxBitmap
207 //-----------------------------------------------------------------------------
208
209 class wxBitmapRefData: public wxObjectRefData
210 {
211 public:
212 wxBitmapRefData();
213 ~wxBitmapRefData();
214
215 GdkPixmap *m_pixmap;
216 GdkBitmap *m_bitmap;
217 wxMask *m_mask;
218 int m_width;
219 int m_height;
220 int m_bpp;
221 wxPalette *m_palette;
222 };
223
224 wxBitmapRefData::wxBitmapRefData()
225 {
226 m_pixmap = (GdkPixmap *) NULL;
227 m_bitmap = (GdkBitmap *) NULL;
228 m_mask = (wxMask *) NULL;
229 m_width = 0;
230 m_height = 0;
231 m_bpp = 0;
232 m_palette = (wxPalette *) NULL;
233 }
234
235 wxBitmapRefData::~wxBitmapRefData()
236 {
237 if (m_pixmap) gdk_pixmap_unref( m_pixmap );
238 if (m_bitmap) gdk_bitmap_unref( m_bitmap );
239 if (m_mask) delete m_mask;
240 if (m_palette) delete m_palette;
241 }
242
243 //-----------------------------------------------------------------------------
244
245 #define M_BMPDATA ((wxBitmapRefData *)m_refData)
246
247 IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
248
249 wxBitmap::wxBitmap()
250 {
251 if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
252 }
253
254 wxBitmap::wxBitmap( int width, int height, int depth )
255 {
256 Create( width, height, depth );
257
258 if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
259 }
260
261 bool wxBitmap::Create( int width, int height, int depth )
262 {
263 UnRef();
264
265 wxCHECK_MSG( (width > 0) && (height > 0), FALSE, wxT("invalid bitmap size") )
266
267 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
268 wxASSERT( visual );
269
270 if (depth == -1) depth = visual->depth;
271
272 wxCHECK_MSG( (depth == visual->depth) ||
273 (depth == 1), FALSE, wxT("invalid bitmap depth") )
274
275 m_refData = new wxBitmapRefData();
276 M_BMPDATA->m_mask = (wxMask *) NULL;
277 M_BMPDATA->m_width = width;
278 M_BMPDATA->m_height = height;
279 if (depth == 1)
280 {
281 M_BMPDATA->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
282 M_BMPDATA->m_bpp = 1;
283 }
284 else
285 {
286 M_BMPDATA->m_pixmap = gdk_pixmap_new( wxRootWindow->window, width, height, depth );
287 M_BMPDATA->m_bpp = visual->depth;
288 }
289
290 return Ok();
291 }
292 bool wxBitmap::CreateFromXpm( const char **bits )
293 {
294 wxCHECK_MSG( bits != NULL, FALSE, wxT("invalid bitmap data") )
295
296 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
297 wxASSERT( visual );
298
299 m_refData = new wxBitmapRefData();
300
301 GdkBitmap *mask = (GdkBitmap*) NULL;
302
303 M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm_d( wxRootWindow->window, &mask, NULL, (gchar **) bits );
304
305 wxCHECK_MSG( M_BMPDATA->m_pixmap, FALSE, wxT("couldn't create pixmap") );
306
307 if (mask)
308 {
309 M_BMPDATA->m_mask = new wxMask();
310 M_BMPDATA->m_mask->m_bitmap = mask;
311 }
312
313 gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
314
315 M_BMPDATA->m_bpp = visual->depth; // ?
316
317 if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
318
319 return TRUE;
320 }
321
322 wxBitmap::wxBitmap( const wxBitmap& bmp )
323 {
324 Ref( bmp );
325
326 if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
327 }
328
329 wxBitmap::wxBitmap( const wxString &filename, int type )
330 {
331 LoadFile( filename, type );
332
333 if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
334 }
335
336 wxBitmap::wxBitmap( const char bits[], int width, int height, int WXUNUSED(depth))
337 {
338 m_refData = new wxBitmapRefData();
339
340 M_BMPDATA->m_mask = (wxMask *) NULL;
341 M_BMPDATA->m_bitmap =
342 gdk_bitmap_create_from_data( wxRootWindow->window, (gchar *) bits, width, height );
343 M_BMPDATA->m_width = width;
344 M_BMPDATA->m_height = height;
345 M_BMPDATA->m_bpp = 1;
346
347 wxCHECK_RET( M_BMPDATA->m_bitmap, wxT("couldn't create bitmap") );
348
349 if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
350 }
351
352 wxBitmap::~wxBitmap()
353 {
354 if (wxTheBitmapList) wxTheBitmapList->DeleteObject(this);
355 }
356
357 wxBitmap& wxBitmap::operator = ( const wxBitmap& bmp )
358 {
359 if (*this == bmp) return (*this);
360 Ref( bmp );
361 return *this;
362 }
363
364 bool wxBitmap::operator == ( const wxBitmap& bmp ) const
365 {
366 return m_refData == bmp.m_refData;
367 }
368
369 bool wxBitmap::operator != ( const wxBitmap& bmp ) const
370 {
371 return m_refData != bmp.m_refData;
372 }
373
374 bool wxBitmap::Ok() const
375 {
376 return (m_refData != NULL);
377 }
378
379 int wxBitmap::GetHeight() const
380 {
381 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
382
383 return M_BMPDATA->m_height;
384 }
385
386 int wxBitmap::GetWidth() const
387 {
388 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
389
390 return M_BMPDATA->m_width;
391 }
392
393 int wxBitmap::GetDepth() const
394 {
395 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
396
397 return M_BMPDATA->m_bpp;
398 }
399
400 wxMask *wxBitmap::GetMask() const
401 {
402 wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") );
403
404 return M_BMPDATA->m_mask;
405 }
406
407 void wxBitmap::SetMask( wxMask *mask )
408 {
409 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
410
411 if (M_BMPDATA->m_mask) delete M_BMPDATA->m_mask;
412
413 M_BMPDATA->m_mask = mask;
414 }
415
416 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
417 {
418 wxCHECK_MSG( Ok() &&
419 (rect.x >= 0) && (rect.y >= 0) &&
420 (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
421 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
422
423 wxBitmap ret( rect.width, rect.height, M_BMPDATA->m_bpp );
424 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
425
426 if (ret.GetPixmap())
427 {
428 GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
429 gdk_draw_pixmap( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
430 gdk_gc_destroy( gc );
431 }
432 else
433 {
434 GdkGC *gc = gdk_gc_new( ret.GetBitmap() );
435 gdk_wx_draw_bitmap( ret.GetBitmap(), gc, GetBitmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
436 gdk_gc_destroy( gc );
437 }
438
439 if (GetMask())
440 {
441 wxMask *mask = new wxMask;
442 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, rect.width, rect.height, 1 );
443
444 GdkGC *gc = gdk_gc_new( mask->m_bitmap );
445 gdk_wx_draw_bitmap( mask->m_bitmap, gc, M_BMPDATA->m_mask->m_bitmap, 0, 0, rect.x, rect.y, rect.width, rect.height );
446 gdk_gc_destroy( gc );
447
448 ret.SetMask( mask );
449 }
450
451 return ret;
452 }
453
454 bool wxBitmap::SaveFile( const wxString &name, int type, wxPalette *WXUNUSED(palette) )
455 {
456 wxCHECK_MSG( Ok(), FALSE, wxT("invalid bitmap") );
457
458 // Try to save the bitmap via wxImage handlers:
459 {
460 wxImage image( *this );
461 if (image.Ok()) return image.SaveFile( name, type );
462 }
463
464 return FALSE;
465 }
466
467 bool wxBitmap::LoadFile( const wxString &name, int type )
468 {
469 UnRef();
470
471 if (!wxFileExists(name)) return FALSE;
472
473 GdkVisual *visual = gdk_window_get_visual( wxRootWindow->window );
474 wxASSERT( visual );
475
476 if (type == wxBITMAP_TYPE_XPM)
477 {
478 m_refData = new wxBitmapRefData();
479
480 GdkBitmap *mask = (GdkBitmap*) NULL;
481
482 M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm( wxRootWindow->window, &mask, NULL, name.fn_str() );
483
484 if (mask)
485 {
486 M_BMPDATA->m_mask = new wxMask();
487 M_BMPDATA->m_mask->m_bitmap = mask;
488 }
489
490 gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
491
492 M_BMPDATA->m_bpp = visual->depth;
493 }
494 else // try if wxImage can load it
495 {
496 wxImage image;
497 if (!image.LoadFile( name, type )) return FALSE;
498 if (image.Ok()) *this = image.ConvertToBitmap();
499 else return FALSE;
500 }
501
502 return TRUE;
503 }
504
505 wxPalette *wxBitmap::GetPalette() const
506 {
507 if (!Ok()) return (wxPalette *) NULL;
508
509 return M_BMPDATA->m_palette;
510 }
511
512 void wxBitmap::SetHeight( int height )
513 {
514 if (!m_refData) m_refData = new wxBitmapRefData();
515
516 M_BMPDATA->m_height = height;
517 }
518
519 void wxBitmap::SetWidth( int width )
520 {
521 if (!m_refData) m_refData = new wxBitmapRefData();
522
523 M_BMPDATA->m_width = width;
524 }
525
526 void wxBitmap::SetDepth( int depth )
527 {
528 if (!m_refData) m_refData = new wxBitmapRefData();
529
530 M_BMPDATA->m_bpp = depth;
531 }
532
533 void wxBitmap::SetPixmap( GdkPixmap *pixmap )
534 {
535 if (!m_refData) m_refData = new wxBitmapRefData();
536
537 M_BMPDATA->m_pixmap = pixmap;
538 }
539
540 void wxBitmap::SetBitmap( GdkPixmap *bitmap )
541 {
542 if (!m_refData) m_refData = new wxBitmapRefData();
543
544 M_BMPDATA->m_bitmap = bitmap;
545 }
546
547 GdkPixmap *wxBitmap::GetPixmap() const
548 {
549 wxCHECK_MSG( Ok(), (GdkPixmap *) NULL, wxT("invalid bitmap") );
550
551 return M_BMPDATA->m_pixmap;
552 }
553
554 GdkBitmap *wxBitmap::GetBitmap() const
555 {
556 wxCHECK_MSG( Ok(), (GdkBitmap *) NULL, wxT("invalid bitmap") );
557
558 return M_BMPDATA->m_bitmap;
559 }