source: trunk/Packages/Graphics32/GR32_Backends_LCL_Gtk.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 15.0 KB
Line 
1unit GR32_Backends_LCL_Gtk;
2
3(* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1 or LGPL 2.1 with linking exception
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Alternatively, the contents of this file may be used under the terms of the
17 * Free Pascal modified version of the GNU Lesser General Public License
18 * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
19 * of this license are applicable instead of those above.
20 * Please see the file LICENSE.txt for additional information concerning this
21 * license.
22 *
23 * The Original Code is Backend Extension for Graphics32
24 *
25 * The Initial Developer of the Original Code is
26 * Felipe Monteiro de Carvalho <felipemonteiro.carvalho@gmail.com>
27 *
28 * Portions created by the Initial Developer are Copyright (C) 2007-2012
29 * the Initial Developer. All Rights Reserved.
30 *
31 * Contributor(s):
32 *
33 * ***** END LICENSE BLOCK ***** *)
34
35interface
36
37{$I GR32.inc}
38
39{$DEFINE VerboseGR32GTK}
40
41uses
42 LCLIntf, LCLType, types, Controls, SysUtils, Classes,
43{$IFDEF LCLGtk2}
44 gdk2, gtk2, gdk2pixbuf, glib2, gtk2Def,
45{$ELSE}
46 gdk, gtk, gdkpixbuf, glib, gtkdef,
47{$ENDIF}
48 Graphics, GR32, GR32_Backends, GR32_Containers, GR32_Image;
49
50type
51
52 { TLCLBackend }
53
54 TLCLBackend = class(TCustomBackend,
55 IPaintSupport, ITextSupport, IFontSupport, ICanvasSupport)
56 private
57 FFont: TFont;
58 FCanvas: TCanvas;
59 FCanvasHandle: TGtkDeviceContext;
60 FOnFontChange: TNotifyEvent;
61 FOnCanvasChange: TNotifyEvent;
62
63 { Gtk specific variables }
64 FPixbuf: PGdkPixBuf;
65
66 procedure CanvasChangedHandler(Sender: TObject);
67 procedure FontChangedHandler(Sender: TObject);
68 procedure CanvasChanged;
69 procedure FontChanged;
70 protected
71 FFontHandle: HFont;
72 FBitmapInfo: TBitmapInfo;
73 FHDC: HDC;
74
75 { BITS_GETTER }
76 function GetBits: PColor32Array; override;
77
78 procedure InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean); override;
79 procedure FinalizeSurface; override;
80 public
81 constructor Create; override;
82 destructor Destroy; override;
83
84 procedure Changed; override;
85
86 function Empty: Boolean; override;
87 public
88 { IPaintSupport }
89 procedure ImageNeeded;
90 procedure CheckPixmap;
91 procedure DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas; APaintBox: TCustomPaintBox32);
92
93 { ITextSupport }
94 procedure Textout(X, Y: Integer; const Text: string); overload;
95 procedure Textout(X, Y: Integer; const ClipRect: TRect; const Text: string); overload;
96 procedure Textout(var DstRect: TRect; const Flags: Cardinal; const Text: string); overload;
97 function TextExtent(const Text: string): TSize;
98
99 procedure TextoutW(X, Y: Integer; const Text: Widestring); overload;
100 procedure TextoutW(X, Y: Integer; const ClipRect: TRect; const Text: Widestring); overload;
101 procedure TextoutW(var DstRect: TRect; const Flags: Cardinal; const Text: Widestring); overload;
102 function TextExtentW(const Text: Widestring): TSize;
103
104 { IDeviceContextSupport }
105 function GetHandle: HDC;
106
107 procedure Draw(const DstRect, SrcRect: TRect; hSrc: HDC); overload;
108 procedure DrawTo(hDst: HDC; DstX, DstY: Integer); overload;
109 procedure DrawTo(hDst: HDC; const DstRect, SrcRect: TRect); overload;
110
111 property Handle: HDC read GetHandle;
112
113 { IFontSupport }
114 function GetOnFontChange: TNotifyEvent;
115 procedure SetOnFontChange(Handler: TNotifyEvent);
116 function GetFont: TFont;
117 procedure SetFont(const Font: TFont);
118 procedure UpdateFont;
119
120 property Font: TFont read GetFont write SetFont;
121 property OnFontChange: TNotifyEvent read FOnFontChange write FOnFontChange;
122
123 { ICanvasSupport }
124 function GetCanvasChange: TNotifyEvent;
125 procedure SetCanvasChange(Handler: TNotifyEvent);
126 function GetCanvas: TCanvas;
127
128 procedure DeleteCanvas;
129 function CanvasAllocated: Boolean;
130
131 property Canvas: TCanvas read GetCanvas;
132 property OnCanvasChange: TNotifyEvent read GetCanvasChange write SetCanvasChange;
133 end;
134
135implementation
136
137uses
138 GR32_LowLevel;
139
140resourcestring
141 RCStrCannotAllocateMemory = 'Can''t allocate memory for the DIB';
142 RCStrCannotAllocateThePixBuf = 'Can''t allocate the Pixbuf';
143
144var
145 StockFont: TFont;
146
147{ TLCLBackend }
148
149constructor TLCLBackend.Create;
150begin
151 {$IFDEF VerboseGR32GTK}
152 WriteLn('[TLCLBackend.Create]', ' Self: ', IntToHex(PtrUInt(Self), 8));
153 {$ENDIF}
154
155 inherited;
156
157 FFont := TFont.Create;
158 FFont.OnChange := FontChangedHandler;
159end;
160
161destructor TLCLBackend.Destroy;
162begin
163 {$IFDEF VerboseGR32GTK}
164 WriteLn('[TLCLBackend.Destroy]',
165 ' Self: ', IntToHex(PtrUInt(Self), 8));
166 {$ENDIF}
167
168 DeleteCanvas;
169 FFont.Free;
170
171 inherited;
172end;
173
174function TLCLBackend.GetBits: PColor32Array;
175begin
176 Result := FBits;
177end;
178
179procedure TLCLBackend.InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean);
180var
181 Stride: Integer;
182begin
183 {$IFDEF VerboseGR32GTK}
184 WriteLn('[TLCLBackend.InitializeSurface] BEGIN',
185 ' Self: ', IntToHex(PtrUInt(Self), 8),
186 ' NewWidth: ', NewWidth,
187 ' NewHeight: ', NewHeight
188 );
189 {$ENDIF}
190
191 { We allocate our own memory for the image, because otherwise it's
192 not guaranteed which Stride Gdk will use. }
193 Stride := NewWidth * 4;
194 FBits := GetMem(NewHeight * Stride);
195
196 FHDC := CreateCompatibleDC(0);
197 if FHDC = 0 then
198 begin
199 FBits := nil;
200 raise Exception.Create(RCStrCannotCreateCompatibleDC);
201 end;
202
203 if FBits = nil then
204 raise Exception.Create(RCStrCannotAllocateMemory);
205
206 { We didn't pass a memory freeing function, so we will have to take
207 care of that ourselves }
208 FPixbuf := gdk_pixbuf_new_from_data(pguchar(FBits),
209 GDK_COLORSPACE_RGB, True, 8, NewWidth, NewHeight, Stride, nil, nil);
210
211 if FPixbuf = nil then
212 raise Exception.Create(RCStrCannotAllocateThePixBuf);
213
214 { clear the image }
215 if ClearBuffer then
216 FillLongword(FBits[0], NewWidth * NewHeight, clBlack32);
217
218 {$IFDEF VerboseGR32GTK}
219 WriteLn('[TLCLBackend.InitializeSurface] END');
220 {$ENDIF}
221end;
222
223procedure TLCLBackend.FinalizeSurface;
224begin
225 {$IFDEF VerboseGR32GTK}
226 WriteLn('[TLCLBackend.FinalizeSurface]',
227 ' Self: ', IntToHex(PtrUInt(Self), 8));
228 {$ENDIF}
229
230{$IFDEF LCLGtk2}
231 if Assigned(FPixbuf) then g_object_unref(FPixbuf);
232 FPixbuf := nil;
233{$ELSE}
234 if Assigned(FPixbuf) then gdk_pixbuf_unref(FPixbuf);
235 FPixbuf := nil;
236{$ENDIF}
237
238 if FHDC <> 0 then DeleteDC(FHDC);
239 FHDC := 0;
240
241 if Assigned(FBits) then FreeMem(FBits);
242 FBits := nil;
243end;
244
245procedure TLCLBackend.Changed;
246begin
247 if FCanvas <> nil then FCanvas.Handle := Self.Handle;
248 inherited;
249end;
250
251procedure TLCLBackend.CanvasChanged;
252begin
253 if Assigned(FOnCanvasChange) then
254 FOnCanvasChange(Self);
255end;
256
257procedure TLCLBackend.FontChanged;
258begin
259 if Assigned(FOnFontChange) then
260 FOnFontChange(Self);
261end;
262
263function TLCLBackend.Empty: Boolean;
264begin
265 Result := (FPixBuf = nil) or (FBits = nil);
266end;
267
268procedure TLCLBackend.FontChangedHandler(Sender: TObject);
269begin
270 if FFontHandle <> 0 then
271 begin
272// if Handle <> 0 then SelectObject(Handle, StockFont);
273 FFontHandle := 0;
274 end;
275
276 FontChanged;
277end;
278
279procedure TLCLBackend.CanvasChangedHandler(Sender: TObject);
280begin
281 CanvasChanged;
282end;
283
284{ IPaintSupport }
285
286procedure TLCLBackend.ImageNeeded;
287begin
288
289end;
290
291procedure TLCLBackend.CheckPixmap;
292begin
293
294end;
295
296procedure TLCLBackend.DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList;
297 ACanvas: TCanvas; APaintBox: TCustomPaintBox32);
298begin
299 {$IFDEF VerboseGR32GTK}
300 WriteLn('[TLCLBackend.DoPaint]',
301 ' Self: ', IntToHex(PtrUInt(Self), 8));
302 {$ENDIF}
303
304 gdk_draw_rgb_32_image(
305 TGtkDeviceContext(ACanvas.Handle).Drawable,
306 TGtkDeviceContext(ACanvas.Handle).GC,
307 0,
308 0,
309 ABuffer.Width,
310 ABuffer.Height,
311 GDK_RGB_DITHER_NORMAL,
312 Pguchar(FBits),
313 ABuffer.Width * 4
314 );
315
316(*
317gdk_pixbuf_render_to_drawable(
318 FPixbuf,
319 TGtkDeviceContext(ACanvas.Handle).Drawable,
320 TGtkDeviceContext(ACanvas.Handle).GC,
321 0, // src_x
322 0, // src_y
323 0, // dest_x
324 0, // dest_y
325 ABuffer.Width, // width
326 ABuffer.Height, // height
327 GDK_RGB_DITHER_NONE, // dither
328 0, // x_dither
329 0); // y_dither
330*)
331end;
332
333{ ITextSupport }
334
335procedure TLCLBackend.Textout(X, Y: Integer; const Text: string);
336begin
337 {$IFDEF VerboseGR32GTK}
338 WriteLn('[TLCLBackend.Textout]', ' Self: ', IntToHex(PtrUInt(Self), 8));
339 {$ENDIF}
340
341 if not Assigned(FCanvas) then GetCanvas;
342
343 UpdateFont;
344
345 if not FOwner.MeasuringMode then
346 FCanvas.TextOut(X, Y, Text);
347
348 FOwner.Changed;
349end;
350
351procedure TLCLBackend.Textout(X, Y: Integer; const ClipRect: TRect; const Text: string);
352begin
353 {$IFDEF VerboseGR32GTK}
354 WriteLn('[TLCLBackend.Textout with ClipRect]', ' Self: ',
355 IntToHex(PtrUInt(Self), 8));
356 {$ENDIF}
357
358 if not Assigned(FCanvas) then GetCanvas;
359
360 UpdateFont;
361
362 LCLIntf.ExtTextOut(FCanvas.Handle, X, Y, ETO_CLIPPED, @ClipRect, PChar(Text),
363 Length(Text), nil);
364end;
365
366procedure TLCLBackend.Textout(var DstRect: TRect; const Flags: Cardinal; const Text: string);
367begin
368 {$IFDEF VerboseGR32GTK}
369 WriteLn('[TLCLBackend.Textout with Flags]',
370 ' Self: ', IntToHex(PtrUInt(Self), 8));
371 {$ENDIF}
372
373 if not Assigned(FCanvas) then GetCanvas;
374
375 UpdateFont;
376
377 LCLIntf.DrawText(FCanvas.Handle, PChar(Text), Length(Text), DstRect, Flags);
378end;
379
380function TLCLBackend.TextExtent(const Text: string): TSize;
381begin
382 {$IFDEF VerboseGR32GTK}
383 WriteLn('[TLCLBackend.TextExtent]',
384 ' Self: ', IntToHex(PtrUInt(Self), 8));
385 {$ENDIF}
386
387 if not Assigned(FCanvas) then GetCanvas;
388
389// UpdateFont;
390
391 Result := FCanvas.TextExtent(Text);
392end;
393
394{ Gtk uses UTF-8, so all W functions are converted to UTF-8 ones }
395
396procedure TLCLBackend.TextoutW(X, Y: Integer; const Text: Widestring);
397begin
398 TextOut(X, Y, Utf8Encode(Text));
399end;
400
401procedure TLCLBackend.TextoutW(X, Y: Integer; const ClipRect: TRect; const Text: Widestring);
402begin
403 TextOut(X, Y, ClipRect, Utf8Encode(Text));
404end;
405
406procedure TLCLBackend.TextoutW(var DstRect: TRect; const Flags: Cardinal; const Text: Widestring);
407begin
408 TextOut(DstRect, Flags, Utf8Encode(Text));
409end;
410
411function TLCLBackend.TextExtentW(const Text: Widestring): TSize;
412begin
413 Result := TextExtent(Utf8Encode(Text));
414end;
415
416{ IFontSupport }
417
418function TLCLBackend.GetOnFontChange: TNotifyEvent;
419begin
420 Result := FOnFontChange;
421end;
422
423procedure TLCLBackend.SetOnFontChange(Handler: TNotifyEvent);
424begin
425 FOnFontChange := Handler;
426end;
427
428function TLCLBackend.GetFont: TFont;
429begin
430 Result := FFont;
431end;
432
433function TLCLBackend.GetHandle: HDC;
434begin
435 {$IFDEF VerboseGR32GTK}
436 WriteLn('[TLCLBackend.GetHandle]',
437 ' Self: ', IntToHex(PtrUInt(Self), 8));
438 {$ENDIF}
439
440 if not Assigned(FCanvas) then GetCanvas;
441
442 Result := FCanvas.Handle;
443end;
444
445procedure TLCLBackend.SetFont(const Font: TFont);
446begin
447 {$IFDEF VerboseGR32GTK}
448 WriteLn('[TLCLBackend.SetFont]',
449 ' Self: ', IntToHex(PtrUInt(Self), 8));
450 {$ENDIF}
451
452 FFont.Assign(Font);
453end;
454
455procedure TLCLBackend.UpdateFont;
456begin
457 {$IFDEF VerboseGR32GTK}
458 WriteLn('[TLCLBackend.UpdateFont]',
459 ' Self: ', IntToHex(PtrUInt(Self), 8));
460 {$ENDIF}
461
462 FFontHandle := Font.Handle;
463 FFont.OnChange := FOnFontChange;
464
465 if Assigned(FCanvas) then FCanvas.Font := FFont;
466end;
467
468{ IDeviceContextSupport }
469
470procedure TLCLBackend.Draw(const DstRect, SrcRect: TRect; hSrc: HDC);
471begin
472 {$IFDEF VerboseGR32GTK}
473 WriteLn('[TLCLBackend.Draw]',
474 ' Self: ', IntToHex(PtrUInt(Self), 8));
475 {$ENDIF}
476
477 if FOwner.Empty then Exit;
478
479 if not FOwner.MeasuringMode then
480 LclIntf.StretchBlt(Handle, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left,
481 DstRect.Bottom - DstRect.Top, hSrc, SrcRect.Left, SrcRect.Top,
482 SrcRect.Right - SrcRect.Left, SrcRect.Bottom - SrcRect.Top, SRCCOPY);
483
484 FOwner.Changed(DstRect);
485end;
486
487procedure TLCLBackend.DrawTo(hDst: HDC; DstX, DstY: Integer);
488begin
489 {$IFDEF VerboseGR32GTK}
490 WriteLn('[TLCLBackend.DrawTo]',
491 ' Self: ', IntToHex(PtrUInt(Self), 8));
492 {$ENDIF}
493
494 LclIntf.BitBlt(hDst, DstX, DstY, FOwner.Width, FOwner.Height, Handle, DstX,
495 DstY, SRCCOPY);
496 (*
497 LclIntf.StretchDIBits(
498 hDst, DstX, DstY, FOwner.Width, FOwner.Height,
499 0, 0, FOwner.Width, FOwner.Height, Bits, FBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
500*)
501end;
502
503procedure TLCLBackend.DrawTo(hDst: HDC; const DstRect, SrcRect: TRect);
504begin
505 {$IFDEF VerboseGR32GTK}
506 WriteLn('[TLCLBackend.DrawTo with rects]',
507 ' Self: ', IntToHex(PtrUInt(Self), 8));
508 {$ENDIF}
509
510 LclIntf.StretchBlt(hDst,
511 DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, Handle,
512 SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left, SrcRect.Bottom - SrcRect.Top, SRCCOPY);
513 (*
514*)
515end;
516
517
518{ ICanvasSupport }
519
520function TLCLBackend.GetCanvasChange: TNotifyEvent;
521begin
522 {$IFDEF VerboseGR32GTK}
523 WriteLn('[TLCLBackend.GetCanvasChange]',
524 ' Self: ', IntToHex(PtrUInt(Self), 8));
525 {$ENDIF}
526
527 Result := FOnCanvasChange;
528end;
529
530procedure TLCLBackend.SetCanvasChange(Handler: TNotifyEvent);
531begin
532 {$IFDEF VerboseGR32GTK}
533 WriteLn('[TLCLBackend.SetCanvasChange]',
534 ' Self: ', IntToHex(PtrUInt(Self), 8));
535 {$ENDIF}
536
537 FOnCanvasChange := Handler;
538end;
539
540function TLCLBackend.GetCanvas: TCanvas;
541begin
542 {$IFDEF VerboseGR32GTK}
543 WriteLn('[TLCLBackend.GetCanvas] BEGIN',
544 ' Self: ', IntToHex(PtrUInt(Self), 8));
545 {$ENDIF}
546
547 if not Assigned(FCanvas) then
548 begin
549 FCanvas := TCanvas.Create;
550
551 FCanvasHandle := TGtkDeviceContext.Create;
552
553 FCanvas.Handle := HDC(FCanvasHandle);
554 FCanvas.OnChange := CanvasChangedHandler;
555 end;
556 Result := FCanvas;
557end;
558
559procedure TLCLBackend.DeleteCanvas;
560begin
561 {$IFDEF VerboseGR32GTK}
562 WriteLn('[TLCLBackend.DeleteCanvas]',
563 ' Self: ', IntToHex(PtrUInt(Self), 8),
564 ' FCanvas: ', PtrUInt(FCanvas));
565 {$ENDIF}
566
567 if Assigned(FCanvas) then
568 begin
569 FCanvas.Handle := 0;
570 FCanvas.Free;
571 FCanvas := nil;
572 end;
573end;
574
575function TLCLBackend.CanvasAllocated: Boolean;
576begin
577 Result := Assigned(FCanvas);
578
579 {$IFDEF VerboseGR32GTK}
580 WriteLn('[TLCLBackend.CanvasAllocated]',
581 ' Self: ', IntToHex(PtrUInt(Self), 8),
582 ' FCanvas: ', PtrUInt(FCanvas));
583 {$ENDIF}
584end;
585
586initialization
587 StockFont := TFont.Create;
588
589finalization
590 StockFont.Free;
591
592end.
Note: See TracBrowser for help on using the repository browser.