source: tags/1.2.0/Packages/CevoComponents/BaseWin.pas

Last change on this file was 188, checked in by chronos, 4 years ago
  • Modified: Simplified code by replacing BitBlt which uses always handles by BitBltCanvas which uses directly TCanvas objects. Used default ROP SRCCOPY.
File size: 15.5 KB
Line 
1unit BaseWin;
2
3interface
4
5uses
6 ScreenTools, LCLIntf, LCLType, SysUtils, Classes, Graphics, Controls, Forms,
7 DrawDlg;
8
9type
10 TShowNewContent = procedure (NewMode: Integer; HelpContext: string) of object;
11
12 { TBufferedDrawDlg }
13
14 TBufferedDrawDlg = class(TDrawDlg)
15 public
16 UserLeft, UserTop: integer;
17 constructor Create(AOwner: TComponent); override;
18 destructor Destroy; override;
19 procedure FormClose(Sender: TObject; var Action: TCloseAction);
20 procedure FormPaint(Sender: TObject);
21 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
22 procedure FormDeactivate(Sender: TObject);
23 procedure SmartUpdateContent(ImmUpdate: boolean = false);
24 procedure StayOnTop_Workaround;
25 protected
26 FWindowMode, ModalFrameIndent: integer;
27 HelpContext: string;
28 procedure ShowNewContent(NewMode: integer; forceclose: boolean = false);
29 procedure MarkUsedOffscreen(xMax, yMax: integer);
30 procedure OffscreenPaint; virtual;
31 procedure VPaint; virtual;
32 public
33 UsedOffscreenWidth, UsedOffscreenHeight: integer;
34 Offscreen: TBitmap;
35 OffscreenUser: TForm;
36 property WindowMode: integer read FWindowMode;
37 end;
38
39 TFramedDlg = class(TBufferedDrawDlg)
40 public
41 constructor Create(AOwner: TComponent); override;
42 procedure FormCreate(Sender: TObject);
43 procedure SmartInvalidate; override;
44 protected
45 CaptionLeft: Integer;
46 CaptionRight: Integer;
47 InnerWidth: Integer;
48 InnerHeight: integer;
49 WideBottom: Boolean;
50 FullCaption: Boolean;
51 TexOverride: Boolean;
52 ModalIndication: Boolean;
53 procedure InitWindowRegion;
54 procedure VPaint; override;
55 procedure FillOffscreen(Left, Top, Width, Height: integer);
56 end;
57
58var
59 ShowNewContentProc: TShowNewContent;
60 MainFormKeyDown: TKeyEvent;
61
62const
63 // window modes
64 wmNone = 0;
65 wmModal = $1;
66 wmPersistent = $2;
67 wmSubmodal = $3;
68
69 yUnused = 161;
70 NarrowFrame = 11;
71 WideFrame = 36;
72 SideFrame = 9;
73
74procedure CreateOffscreen(var Offscreen: TBitmap);
75procedure Register;
76
77
78implementation
79
80uses
81 ButtonBase, Area;
82
83procedure Register;
84begin
85 RegisterNoIcon([TBufferedDrawDlg]);
86 RegisterNoIcon([TFramedDlg]);
87end;
88
89
90constructor TBufferedDrawDlg.Create(AOwner: TComponent);
91begin
92 BaseWin.CreateOffscreen(Offscreen);
93 OnClose := FormClose;
94 OnPaint := FormPaint;
95 OnKeyDown := FormKeyDown;
96 OnDeactivate := FormDeactivate;
97 inherited;
98 FWindowMode := wmNone;
99 HelpContext := 'CONCEPTS';
100 TitleHeight := WideFrame;
101 ModalFrameIndent := 45;
102 UserLeft := (Screen.Width - Width) div 2;
103 UserTop := (Screen.Height - Height) div 2;
104end;
105
106destructor TBufferedDrawDlg.Destroy;
107begin
108 Offscreen.Free;
109 inherited Destroy;
110end;
111
112procedure TBufferedDrawDlg.FormClose(Sender: TObject; var Action: TCloseAction);
113begin
114 if FWindowMode = wmPersistent then
115 begin
116 UserLeft := Left;
117 UserTop := Top
118 end;
119 if OffscreenUser = self then
120 OffscreenUser := nil;
121end;
122
123procedure TBufferedDrawDlg.FormPaint(Sender: TObject);
124begin
125 if OffscreenUser <> self then
126 OffscreenPaint;
127 VPaint;
128end;
129
130procedure TBufferedDrawDlg.FormKeyDown(Sender: TObject; var Key: Word;
131 Shift: TShiftState);
132begin
133 if Key = VK_ESCAPE then
134 begin
135 if fsModal in FormState then
136 ModalResult := mrCancel
137 end
138 else if Key = VK_RETURN then
139 begin
140 if fsModal in FormState then
141 ModalResult := mrOK
142 end
143 else if Key = VK_F1 then begin
144 if Assigned(ShowNewContentProc) then
145 ShowNewContentProc(FWindowMode or wmPersistent, HelpContext);
146 end else if FWindowMode = wmPersistent then begin
147 if Assigned(MainFormKeyDown) then
148 MainFormKeyDown(Sender, Key, Shift);
149 end;
150end;
151
152procedure TBufferedDrawDlg.FormDeactivate(Sender: TObject);
153begin
154 if FWindowMode = wmSubmodal then
155 Close
156end;
157
158procedure TBufferedDrawDlg.OffscreenPaint;
159begin
160 if (OffscreenUser <> nil) and (OffscreenUser <> self) then
161 OffscreenUser.Update; // complete working with old owner to prevent rebound
162 OffscreenUser := self;
163end;
164
165procedure TBufferedDrawDlg.VPaint;
166begin
167 BitBltCanvas(Canvas, 0, 0, ClientWidth, ClientHeight, Offscreen.Canvas, 0, 0);
168end;
169
170procedure TBufferedDrawDlg.ShowNewContent(NewMode: integer;
171 forceclose: boolean);
172begin
173 if Visible then
174 begin
175 assert((NewMode = wmModal) or (FWindowMode <> wmModal));
176 // don't make modal window non-modal
177 if (NewMode = wmModal) and (forceclose or (FWindowMode <> wmModal)) then
178 begin // make modal
179 UserLeft := Left;
180 UserTop := Top;
181 Visible := false;
182 FWindowMode := NewMode;
183 ShowModal;
184 end
185 else if forceclose then
186 begin // make modal
187 Visible := false;
188 FWindowMode := NewMode;
189 Left := UserLeft;
190 Top := UserTop;
191 Show;
192 end
193 else
194 begin
195 FWindowMode := NewMode;
196 if @OnShow <> nil then
197 OnShow(nil);
198 Invalidate;
199 BringToFront
200 end
201 end
202 else
203 begin
204 FWindowMode := NewMode;
205 Left := UserLeft;
206 Top := UserTop;
207 if FWindowMode = wmModal then
208 ShowModal
209 else
210 Show
211 end
212end;
213
214procedure TBufferedDrawDlg.SmartUpdateContent(ImmUpdate: boolean);
215begin
216 if Visible then
217 begin
218 OffscreenPaint;
219 SmartInvalidate;
220 if ImmUpdate then
221 Update;
222 end;
223end;
224
225procedure TBufferedDrawDlg.MarkUsedOffscreen(xMax, yMax: integer);
226begin
227 if xMax > UsedOffscreenWidth then
228 UsedOffscreenWidth := xMax;
229 if yMax > UsedOffscreenHeight then
230 UsedOffscreenHeight := yMax;
231end;
232
233procedure TBufferedDrawDlg.StayOnTop_Workaround;
234// stayontop doesn't work when window is shown for the first time
235// after application lost focus, so show all stayontop-windows in first turn
236var
237 SaveOnShow, SaveOnPaint: TNotifyEvent;
238begin
239 Top := Screen.Height;
240 SaveOnShow := OnShow;
241 OnShow := nil;
242 SaveOnPaint := OnPaint;
243 OnPaint := nil;
244 FWindowMode := wmNone;
245 Show;
246 Hide;
247 OnShow := SaveOnShow;
248 OnPaint := SaveOnPaint;
249end;
250
251constructor TFramedDlg.Create;
252begin
253 OnCreate := FormCreate;
254 inherited;
255end;
256
257procedure TFramedDlg.FormCreate(Sender: TObject);
258begin
259 CaptionLeft := 0;
260 CaptionRight := $FFFF;
261 WideBottom := false;
262 FullCaption := true;
263 TexOverride := false;
264 ModalIndication := true;
265 Canvas.Brush.Style := bsClear;
266 InnerWidth := Width - 2 * SideFrame;
267 InnerHeight := Height - TitleHeight - NarrowFrame;
268end;
269
270procedure TFramedDlg.SmartInvalidate;
271var
272 i, BottomFrame: integer;
273 r0, r1: HRgn;
274begin
275 if WideBottom then
276 BottomFrame := WideFrame
277 else
278 BottomFrame := NarrowFrame;
279 r0 := CreateRectRgn(SideFrame, TitleHeight, ClientWidth - SideFrame,
280 ClientHeight - BottomFrame);
281 for i := 0 to ControlCount - 1 do
282 if not(Controls[i] is TArea) and Controls[i].Visible then
283 begin
284 with Controls[i].BoundsRect do
285 r1 := CreateRectRgn(Left, Top, Right, Bottom);
286 CombineRgn(r0, r0, r1, RGN_DIFF);
287 DeleteObject(r1);
288 end;
289 InvalidateRgn(Handle, r0, false);
290 DeleteObject(r0);
291end;
292
293procedure TFramedDlg.VPaint;
294
295 procedure CornerFrame(x0, y0, x1, y1: integer);
296 begin
297 Frame(Canvas, x0 + 1, y0 + 1, x1 - 2, y1 - 2, MainTexture.clBevelLight,
298 MainTexture.clBevelShade);
299 Frame(Canvas, x0 + 2, y0 + 2, x1 - 3, y1 - 3, MainTexture.clBevelLight,
300 MainTexture.clBevelShade);
301 Corner(Canvas, x0 + 1, y0 + 1, 0, MainTexture);
302 Corner(Canvas, x1 - 9, y0 + 1, 1, MainTexture);
303 Corner(Canvas, x0 + 1, y1 - 9, 2, MainTexture);
304 Corner(Canvas, x1 - 9, y1 - 9, 3, MainTexture);
305 end;
306
307var
308 i, l, FrameTop, FrameBottom, InnerBottom, Cut, xTexOffset,
309 yTexOffset: integer;
310 R: TRect;
311begin
312 if not TexOverride then
313 begin
314 if (FWindowMode = wmModal) and ModalIndication then
315 MainTexture := MainTexture
316 else
317 MainTexture := MainTexture;
318 MainTexture := MainTexture
319 end;
320 Canvas.Font.Assign(UniFont[ftCaption]);
321 l := BiColorTextWidth(Canvas, Caption);
322 Cut := (ClientWidth - l) div 2;
323 xTexOffset := (wMaintexture - ClientWidth) div 2;
324 yTexOffset := (hMaintexture - ClientHeight) div 2;
325 if WideBottom then
326 InnerBottom := ClientHeight - WideFrame
327 else
328 InnerBottom := ClientHeight - NarrowFrame;
329 if FullCaption then
330 begin
331 FrameTop := 0;
332 FrameBottom := ClientHeight
333 end
334 else
335 begin
336 FrameTop := TitleHeight - NarrowFrame;
337 if WideBottom then
338 FrameBottom := ClientHeight - (WideFrame - NarrowFrame)
339 else
340 FrameBottom := ClientHeight
341 end;
342 Fill(Canvas, 3, InnerBottom + 1, ClientWidth - 6, ClientHeight - InnerBottom -
343 4, xTexOffset, yTexOffset);
344 Fill(Canvas, 3, TitleHeight - 2, SideFrame - 3, InnerBottom - TitleHeight + 4,
345 xTexOffset, yTexOffset);
346 Fill(Canvas, ClientWidth - SideFrame, TitleHeight - 2, SideFrame - 3,
347 InnerBottom - TitleHeight + 4, xTexOffset, yTexOffset);
348 Frame(Canvas, 0, FrameTop, ClientWidth - 1, FrameBottom - 1, 0, 0);
349 Frame(Canvas, SideFrame - 1, TitleHeight - 1, ClientWidth - SideFrame,
350 InnerBottom, MainTexture.clBevelShade, MainTexture.clBevelLight);
351 // RFrame(Canvas,SideFrame-2,TitleHeight-2,ClientWidth-SideFrame+1,
352 // InnerBottom+1,MainTexture.clBevelShade,MainTexture.clBevelLight);
353 if FullCaption then
354 begin
355 if (FWindowMode <> wmModal) or not ModalIndication then
356 begin
357 Fill(Canvas, 3, 3 + FrameTop, ClientWidth - 6, TitleHeight - FrameTop - 4,
358 xTexOffset, yTexOffset);
359 CornerFrame(0, FrameTop, ClientWidth, FrameBottom);
360 end
361 else
362 with Canvas do
363 begin
364 Fill(Canvas, 3 + ModalFrameIndent, 3 + FrameTop,
365 ClientWidth - 6 - 2 * ModalFrameIndent, TitleHeight - FrameTop - 4,
366 xTexOffset, yTexOffset);
367 Fill(Canvas, ClientWidth - 3 - ModalFrameIndent, 3 + FrameTop,
368 ModalFrameIndent, TitleHeight - FrameTop - 4, xTexOffset, yTexOffset);
369 Fill(Canvas, 3, 3 + FrameTop, ModalFrameIndent, TitleHeight - FrameTop -
370 4, xTexOffset, yTexOffset);
371 CornerFrame(0, FrameTop, ClientWidth, FrameBottom);
372 Pen.Color := MainTexture.clBevelShade;
373 MoveTo(3 + ModalFrameIndent, 2);
374 LineTo(3 + ModalFrameIndent, TitleHeight);
375 Pen.Color := MainTexture.clBevelShade;
376 MoveTo(4 + ModalFrameIndent, TitleHeight - 1);
377 LineTo(ClientWidth - 4 - ModalFrameIndent, TitleHeight - 1);
378 LineTo(ClientWidth - 4 - ModalFrameIndent, 1);
379 Pen.Color := MainTexture.clBevelLight;
380 MoveTo(ClientWidth - 5 - ModalFrameIndent, 2);
381 LineTo(4 + ModalFrameIndent, 2);
382 LineTo(4 + ModalFrameIndent, TitleHeight);
383 MoveTo(ClientWidth - 4 - ModalFrameIndent, 1);
384 LineTo(3 + ModalFrameIndent, 1);
385 Pen.Color := MainTexture.clBevelLight;
386 MoveTo(ClientWidth - 3 - ModalFrameIndent, 3);
387 LineTo(ClientWidth - 3 - ModalFrameIndent, TitleHeight);
388 end
389 end
390 else
391 begin
392 Fill(Canvas, 3, 3 + FrameTop, ClientWidth - 6, TitleHeight - FrameTop - 4,
393 xTexOffset, yTexOffset);
394 CornerFrame(0, FrameTop, ClientWidth, FrameBottom);
395
396 Frame(Canvas, CaptionLeft, 0, ClientWidth - CaptionLeft - 1,
397 FrameTop, 0, 0);
398 Fill(Canvas, CaptionLeft + 3, 3, ClientWidth - 2 * (CaptionLeft) - 6,
399 TitleHeight - 4, xTexOffset, yTexOffset);
400
401 Frame(Canvas, CaptionLeft + 1, 0 + 1, ClientWidth - CaptionLeft - 2,
402 TitleHeight - 1, MainTexture.clBevelLight, MainTexture.clBevelShade);
403 Frame(Canvas, CaptionLeft + 2, 0 + 2, ClientWidth - CaptionLeft - 3,
404 TitleHeight - 1, MainTexture.clBevelLight, MainTexture.clBevelShade);
405 Corner(Canvas, CaptionLeft + 1, 0 + 1, 0, MainTexture);
406 Corner(Canvas, ClientWidth - CaptionLeft - 9, 0 + 1, 1, MainTexture);
407
408 with Canvas do
409 begin
410 Pen.Color := MainTexture.clBevelShade;
411 MoveTo(CaptionLeft + 1, FrameTop + 2);
412 LineTo(CaptionLeft + 1, TitleHeight);
413 Pen.Color := MainTexture.clBevelLight;
414 MoveTo(ClientWidth - CaptionLeft - 2, FrameTop + 2);
415 LineTo(ClientWidth - CaptionLeft - 2, TitleHeight);
416 end;
417 if WideBottom then
418 begin
419 Frame(Canvas, CaptionLeft, FrameBottom, ClientWidth - CaptionLeft - 1,
420 ClientHeight - 1, 0, 0);
421 Fill(Canvas, CaptionLeft + 3, ClientHeight - 3 - (WideFrame - 5),
422 ClientWidth - 2 * (CaptionLeft) - 6, WideFrame - 5, xTexOffset,
423 yTexOffset);
424 Frame(Canvas, CaptionLeft + 1, ClientHeight - WideFrame - 1 + 1,
425 ClientWidth - CaptionLeft - 2, ClientHeight - 2,
426 MainTexture.clBevelLight, MainTexture.clBevelShade);
427 Frame(Canvas, CaptionLeft + 2, ClientHeight - WideFrame - 1 + 1,
428 ClientWidth - CaptionLeft - 3, ClientHeight - 3,
429 MainTexture.clBevelLight, MainTexture.clBevelShade);
430 Corner(Canvas, CaptionLeft + 1, ClientHeight - 9, 2, MainTexture);
431 Corner(Canvas, ClientWidth - CaptionLeft - 9, ClientHeight - 9, 3,
432 MainTexture);
433
434 with Canvas do
435 begin
436 Pen.Color := MainTexture.clBevelShade;
437 MoveTo(CaptionLeft + 1, ClientHeight - WideFrame);
438 LineTo(CaptionLeft + 1, FrameBottom - 2);
439 Pen.Color := MainTexture.clBevelLight;
440 MoveTo(ClientWidth - CaptionLeft - 2, ClientHeight - WideFrame);
441 LineTo(ClientWidth - CaptionLeft - 2, FrameBottom - 2);
442 end;
443 end
444 end;
445 RisedTextOut(Canvas, Cut - 1, 7, Caption);
446
447 for i := 0 to ControlCount - 1 do
448 if Controls[i].Visible and (Controls[i] is TButtonBase) then
449 begin
450 R := Controls[i].BoundsRect;
451 if (R.Bottom <= TitleHeight) or (R.Top >= InnerBottom) then
452 BtnFrame(Canvas, R, MainTexture);
453 end;
454
455 BitBltCanvas(Canvas, SideFrame, TitleHeight, ClientWidth - 2 * SideFrame,
456 InnerBottom - TitleHeight, Offscreen.Canvas, 0, 0);
457end;
458
459procedure TFramedDlg.InitWindowRegion;
460var
461 r0, r1: HRgn;
462begin
463 if FullCaption then
464 exit;
465 r0 := CreateRectRgn(0, 0, ClientWidth, ClientHeight);
466 r1 := CreateRectRgn(0, 0, CaptionLeft, TitleHeight - NarrowFrame);
467 CombineRgn(r0, r0, r1, RGN_DIFF);
468 // DeleteObject(r1);
469 r1 := CreateRectRgn(ClientWidth - CaptionLeft, 0, ClientWidth,
470 TitleHeight - NarrowFrame);
471 CombineRgn(r0, r0, r1, RGN_DIFF);
472 // DeleteObject(r1);
473 if WideBottom then
474 begin
475 r1 := CreateRectRgn(0, ClientHeight - (WideFrame - NarrowFrame),
476 CaptionLeft, ClientHeight);
477 CombineRgn(r0, r0, r1, RGN_DIFF);
478 // DeleteObject(r1);
479 r1 := CreateRectRgn(ClientWidth - CaptionLeft,
480 ClientHeight - (WideFrame - NarrowFrame), ClientWidth, ClientHeight);
481 CombineRgn(r0, r0, r1, RGN_DIFF);
482 // DeleteObject(r1);
483 end;
484 SetWindowRgn(Handle, r0, false);
485 // DeleteObject(r0); // causes crash with Windows 95
486end;
487
488procedure TFramedDlg.FillOffscreen(Left, Top, Width, Height: integer);
489begin
490 Fill(Offscreen.Canvas, Left, Top, Width, Height,
491 SideFrame + (wMaintexture - ClientWidth) div 2,
492 TitleHeight + (hMaintexture - ClientHeight) div 2);
493end;
494
495procedure CreateOffscreen(var Offscreen: TBitmap);
496begin
497 if Offscreen <> nil then
498 exit;
499 Offscreen := TBitmap.Create;
500 Offscreen.PixelFormat := pf24bit;
501 if Screen.Height - yUnused < 480 then
502 Offscreen.SetSize(Screen.Width, 480)
503 else
504 Offscreen.SetSize(Screen.Width, Screen.Height - yUnused);
505 Offscreen.Canvas.FillRect(0, 0, Offscreen.Width, OffScreen.Height);
506 Offscreen.Canvas.Brush.Style := bsClear;
507end;
508
509initialization
510
511ShowNewContentProc := nil;
512MainFormKeyDown := nil;
513
514finalization
515
516end.
Note: See TracBrowser for help on using the repository browser.