| 1 | unit DrawDlg;
|
|---|
| 2 |
|
|---|
| 3 | interface
|
|---|
| 4 |
|
|---|
| 5 | uses
|
|---|
| 6 | Classes, SysUtils, LCLIntf, LCLType, {$IFDEF UNIX}LMessages,{$ENDIF}
|
|---|
| 7 | Messages, ButtonBase, ButtonA, ButtonB, Area, ScreenTools
|
|---|
| 8 | {$IFDEF LCLGTK2}, Gtk2Globals{$ENDIF},
|
|---|
| 9 | {$IFDEF DPI}Dpi.Forms, Dpi.Common, Dpi.Graphics, Dpi.Controls{$ELSE}
|
|---|
| 10 | Forms, Graphics, Controls{$ENDIF};
|
|---|
| 11 |
|
|---|
| 12 | type
|
|---|
| 13 | { TDrawDlg }
|
|---|
| 14 |
|
|---|
| 15 | TDrawDlg = class(TForm)
|
|---|
| 16 | private
|
|---|
| 17 | MoveFormPos: TPoint;
|
|---|
| 18 | MoveMousePos: TPoint;
|
|---|
| 19 | MoveActive: Boolean;
|
|---|
| 20 | procedure VisibleChangedHandler(Sender: TObject);
|
|---|
| 21 | procedure DoDeactivate(Sender: TObject);
|
|---|
| 22 | protected
|
|---|
| 23 | // Defines area to grip the window for moving (from top)
|
|---|
| 24 | TitleHeight: Integer;
|
|---|
| 25 | procedure InitButtons;
|
|---|
| 26 | procedure OnEraseBkgnd(var Msg: TMessage); message WM_ERASEBKGND;
|
|---|
| 27 | procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|---|
| 28 | override;
|
|---|
| 29 | procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
|
|---|
| 30 | procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
|---|
| 31 | procedure MouseLeave; override;
|
|---|
| 32 | procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|---|
| 33 | public
|
|---|
| 34 | constructor Create(AOwner: TComponent); override;
|
|---|
| 35 | destructor Destroy; override;
|
|---|
| 36 | procedure SmartInvalidate; virtual;
|
|---|
| 37 | procedure CenterToScreen; overload;
|
|---|
| 38 | procedure CenterToScreen(AWidth, AHeight: Integer); overload;
|
|---|
| 39 | end;
|
|---|
| 40 |
|
|---|
| 41 | { TBaseMessgDlg }
|
|---|
| 42 |
|
|---|
| 43 | TBaseMessgDlg = class(TDrawDlg)
|
|---|
| 44 | procedure FormCreate(Sender: TObject);
|
|---|
| 45 | procedure FormPaint(Sender: TObject);
|
|---|
| 46 | protected
|
|---|
| 47 | Lines: Integer;
|
|---|
| 48 | TopSpace: Integer;
|
|---|
| 49 | procedure SplitText(Preview: Boolean);
|
|---|
| 50 | procedure CorrectHeight;
|
|---|
| 51 | public
|
|---|
| 52 | MessgText: string;
|
|---|
| 53 | end;
|
|---|
| 54 |
|
|---|
| 55 | const
|
|---|
| 56 | Border = 3;
|
|---|
| 57 | MessageLineSpacing = 20;
|
|---|
| 58 |
|
|---|
| 59 | procedure Register;
|
|---|
| 60 |
|
|---|
| 61 |
|
|---|
| 62 | implementation
|
|---|
| 63 |
|
|---|
| 64 | procedure Register;
|
|---|
| 65 | begin
|
|---|
| 66 | RegisterNoIcon([TDrawDlg]);
|
|---|
| 67 | RegisterNoIcon([TBaseMessgDlg]);
|
|---|
| 68 | end;
|
|---|
| 69 |
|
|---|
| 70 | { TDrawDlg }
|
|---|
| 71 |
|
|---|
| 72 | constructor TDrawDlg.Create(AOwner: TComponent);
|
|---|
| 73 | begin
|
|---|
| 74 | inherited;
|
|---|
| 75 |
|
|---|
| 76 | // Make all dialogs resizable
|
|---|
| 77 | //BorderStyle := TBorderStyle.bsSizeable;
|
|---|
| 78 | //BorderIcons := [TBorderIcon.biSystemMenu, TBorderIcon.biMinimize, TBorderIcon.biMaximize];
|
|---|
| 79 |
|
|---|
| 80 | Color := clBlack;
|
|---|
| 81 | TitleHeight := 0;
|
|---|
| 82 | MoveActive := False;
|
|---|
| 83 | AddHandlerOnVisibleChanged(VisibleChangedHandler);
|
|---|
| 84 | {$IFDEF UNIX}
|
|---|
| 85 | OnDeactivate := DoDeactivate;
|
|---|
| 86 | {$ENDIF}
|
|---|
| 87 | end;
|
|---|
| 88 |
|
|---|
| 89 | destructor TDrawDlg.Destroy;
|
|---|
| 90 | begin
|
|---|
| 91 | RemoveHandlerOnVisibleChanged(VisibleChangedHandler);
|
|---|
| 92 | inherited;
|
|---|
| 93 | end;
|
|---|
| 94 |
|
|---|
| 95 | procedure TDrawDlg.OnEraseBkgnd(var Msg: TMessage);
|
|---|
| 96 | begin
|
|---|
| 97 | // Full area should be covered by Paint method
|
|---|
| 98 | end;
|
|---|
| 99 |
|
|---|
| 100 | procedure TDrawDlg.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
|
|---|
| 101 | Y: Integer);
|
|---|
| 102 | var
|
|---|
| 103 | MousePos1: TPoint;
|
|---|
| 104 | MousePos2: TPoint;
|
|---|
| 105 | NewFormPos: TPoint;
|
|---|
| 106 | begin
|
|---|
| 107 | MousePos1 := Mouse.CursorPos;
|
|---|
| 108 | inherited;
|
|---|
| 109 | MousePos2 := Mouse.CursorPos;
|
|---|
| 110 | if not Assigned(OnMouseDown) or not Assigned(OnMouseMove) or not Assigned(OnMouseUp) then begin
|
|---|
| 111 | NewFormPos := ScreenToClient(Mouse.CursorPos);
|
|---|
| 112 | if (NewFormPos.X >= 0) and (NewFormPos.X < Width) and
|
|---|
| 113 | (NewFormPos.Y >= 0) and (NewFormPos.Y < Height) and
|
|---|
| 114 | (NewFormPos.Y < TitleHeight) then begin
|
|---|
| 115 | MoveMousePos := ClientToScreen(Point(X, Y));
|
|---|
| 116 | MoveFormPos := Point(Left, Top);
|
|---|
| 117 | // Activate move only if mouse position was not changed during inherited call
|
|---|
| 118 | if (MousePos1.X = MousePos2.X) and (MousePos1.Y = MousePos2.Y) then begin
|
|---|
| 119 | MoveActive := True;
|
|---|
| 120 | end;
|
|---|
| 121 | end else MoveActive := False;
|
|---|
| 122 | end;
|
|---|
| 123 | end;
|
|---|
| 124 |
|
|---|
| 125 | procedure TDrawDlg.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|---|
| 126 | var
|
|---|
| 127 | MousePos: TPoint;
|
|---|
| 128 | begin
|
|---|
| 129 | inherited;
|
|---|
| 130 | if MoveActive then begin
|
|---|
| 131 | MousePos := Mouse.CursorPos;
|
|---|
| 132 | SetBounds(MoveFormPos.X + MousePos.X - MoveMousePos.X,
|
|---|
| 133 | MoveFormPos.Y + MousePos.Y - MoveMousePos.Y, Width, Height);
|
|---|
| 134 | end;
|
|---|
| 135 | end;
|
|---|
| 136 |
|
|---|
| 137 | procedure TDrawDlg.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
|
|---|
| 138 | Y: Integer);
|
|---|
| 139 | begin
|
|---|
| 140 | MoveActive := False;
|
|---|
| 141 | inherited;
|
|---|
| 142 | end;
|
|---|
| 143 |
|
|---|
| 144 | procedure TDrawDlg.MouseLeave;
|
|---|
| 145 | begin
|
|---|
| 146 | MoveActive := False;
|
|---|
| 147 | inherited;
|
|---|
| 148 | end;
|
|---|
| 149 |
|
|---|
| 150 | procedure TDrawDlg.KeyDown(var Key: Word; Shift: TShiftState);
|
|---|
| 151 | begin
|
|---|
| 152 | if Key = VK_ESCAPE then Close;
|
|---|
| 153 | inherited;
|
|---|
| 154 | end;
|
|---|
| 155 |
|
|---|
| 156 | procedure TDrawDlg.VisibleChangedHandler(Sender: TObject);
|
|---|
| 157 | begin
|
|---|
| 158 | // LCL hides all StayOnTop forms during ShowModal.
|
|---|
| 159 | // Fix this to keep them visible.
|
|---|
| 160 | if (TFormStateType.fsModal in FormState) and Visible then
|
|---|
| 161 | Application.RestoreStayOnTop(True);
|
|---|
| 162 |
|
|---|
| 163 | MoveActive := False;
|
|---|
| 164 |
|
|---|
| 165 | {$IFDEF LCLGTK2}
|
|---|
| 166 | // GTK2 bug workaround https://bugs.freepascal.org/view.php?id=35720
|
|---|
| 167 | {$IFDEF DPI}
|
|---|
| 168 | if Visible then LastMouse.WinControl := Self.NativeForm;
|
|---|
| 169 | {$ELSE}
|
|---|
| 170 | if Visible then LastMouse.WinControl := Self;
|
|---|
| 171 | {$ENDIF}
|
|---|
| 172 | {$ENDIF}
|
|---|
| 173 | end;
|
|---|
| 174 |
|
|---|
| 175 | procedure TDrawDlg.DoDeactivate(Sender: TObject);
|
|---|
| 176 | begin
|
|---|
| 177 | MoveActive := False;
|
|---|
| 178 | end;
|
|---|
| 179 |
|
|---|
| 180 | procedure TDrawDlg.InitButtons;
|
|---|
| 181 | var
|
|---|
| 182 | cix: Integer;
|
|---|
| 183 | // ButtonDownSound, ButtonUpSound: string;
|
|---|
| 184 | begin
|
|---|
| 185 | // ButtonDownSound := Sounds.Lookup('BUTTON_DOWN');
|
|---|
| 186 | // ButtonUpSound := Sounds.Lookup('BUTTON_UP');
|
|---|
| 187 | for cix := 0 to ComponentCount - 1 do
|
|---|
| 188 | if Components[cix] is TButtonBase then
|
|---|
| 189 | begin
|
|---|
| 190 | TButtonBase(Components[cix]).Graphic := HGrSystem.Data;
|
|---|
| 191 | // if ButtonDownSound <> '*' then
|
|---|
| 192 | // DownSound := GetSoundsDir + DirectorySeparator + ButtonDownSound + '.wav';
|
|---|
| 193 | // if ButtonUpSound <> '*' then
|
|---|
| 194 | // UpSound := GetSoundsDir + DirectorySeparator + ButtonUpSound + '.wav';
|
|---|
| 195 | if Components[cix] is TButtonA then
|
|---|
| 196 | TButtonA(Components[cix]).Font := UniFont[ftButton];
|
|---|
| 197 | if Components[cix] is TButtonB then
|
|---|
| 198 | TButtonB(Components[cix]).Mask := HGrSystem.Mask;
|
|---|
| 199 | end;
|
|---|
| 200 | end;
|
|---|
| 201 |
|
|---|
| 202 | procedure TDrawDlg.SmartInvalidate;
|
|---|
| 203 | var
|
|---|
| 204 | I: Integer;
|
|---|
| 205 | R0, R1: HRgn;
|
|---|
| 206 | begin
|
|---|
| 207 | R0 := CreateRectRgn(0, 0, Width, Height);
|
|---|
| 208 | for I := 0 to ControlCount - 1 do
|
|---|
| 209 | if not (Controls[I] is TArea) and Controls[I].Visible then begin
|
|---|
| 210 | with Controls[I].BoundsRect do
|
|---|
| 211 | R1 := CreateRectRgn(Left, Top, Right, Bottom);
|
|---|
| 212 | CombineRgn(R0, R0, R1, RGN_DIFF);
|
|---|
| 213 | DeleteObject(R1);
|
|---|
| 214 | end;
|
|---|
| 215 | InvalidateRgn(Handle, R0, False);
|
|---|
| 216 | DeleteObject(R0);
|
|---|
| 217 | end;
|
|---|
| 218 |
|
|---|
| 219 | procedure TDrawDlg.CenterToScreen;
|
|---|
| 220 | begin
|
|---|
| 221 | BoundsRect := Bounds(
|
|---|
| 222 | Screen.PrimaryMonitor.Left + (Screen.PrimaryMonitor.Width - Width) div 2,
|
|---|
| 223 | Screen.PrimaryMonitor.Top + (Screen.PrimaryMonitor.Height - Height) div 2,
|
|---|
| 224 | Width, Height);
|
|---|
| 225 | end;
|
|---|
| 226 |
|
|---|
| 227 | procedure TDrawDlg.CenterToScreen(AWidth, AHeight: Integer);
|
|---|
| 228 | begin
|
|---|
| 229 | BoundsRect := Bounds(
|
|---|
| 230 | Screen.PrimaryMonitor.Left + (Screen.PrimaryMonitor.Width - AWidth) div 2,
|
|---|
| 231 | Screen.PrimaryMonitor.Top + (Screen.PrimaryMonitor.Height - AHeight) div 2,
|
|---|
| 232 | Width, Height);
|
|---|
| 233 | end;
|
|---|
| 234 |
|
|---|
| 235 | { TBaseMessgDlg }
|
|---|
| 236 |
|
|---|
| 237 | procedure TBaseMessgDlg.FormCreate(Sender: TObject);
|
|---|
| 238 | begin
|
|---|
| 239 | Left := Screen.PrimaryMonitor.Left + (Screen.PrimaryMonitor.Width - Width) div 2;
|
|---|
| 240 | Canvas.Font.Assign(UniFont[ftNormal]);
|
|---|
| 241 | Canvas.Brush.Style := TBrushStyle.bsClear;
|
|---|
| 242 | MessgText := '';
|
|---|
| 243 | TopSpace := 0;
|
|---|
| 244 | TitleHeight := Screen.PrimaryMonitor.Height;
|
|---|
| 245 | if csDesigning in ComponentState then Exit;
|
|---|
| 246 | InitButtons;
|
|---|
| 247 | end;
|
|---|
| 248 |
|
|---|
| 249 | procedure TBaseMessgDlg.FormPaint(Sender: TObject);
|
|---|
| 250 | var
|
|---|
| 251 | I, cix: Integer;
|
|---|
| 252 | begin
|
|---|
| 253 | if csDesigning in ComponentState then Exit;
|
|---|
| 254 | PaintBackground(Canvas, 3 + Border, 3 + Border, Width - (6 + 2 * Border),
|
|---|
| 255 | Height - (6 + 2 * Border), Width, Height);
|
|---|
| 256 | for I := 0 to Border do
|
|---|
| 257 | Frame(Canvas, I, I, Width - 1 - I, Height - 1 - I, $000000, $000000);
|
|---|
| 258 | Frame(Canvas, Border + 1, Border + 1, Width - (2 + Border),
|
|---|
| 259 | Height - (2 + Border), MainTexture.ColorBevelLight,
|
|---|
| 260 | MainTexture.ColorBevelShade);
|
|---|
| 261 | Frame(Canvas, 2 + Border, 2 + Border, Width - (3 + Border),
|
|---|
| 262 | Height - (3 + Border), MainTexture.ColorBevelLight,
|
|---|
| 263 | MainTexture.ColorBevelShade);
|
|---|
| 264 | SplitText(False);
|
|---|
| 265 |
|
|---|
| 266 | for cix := 0 to ControlCount - 1 do
|
|---|
| 267 | if (Controls[cix].Visible) and (Controls[cix] is TButtonBase) then
|
|---|
| 268 | BtnFrame(Canvas, Controls[cix].BoundsRect, MainTexture);
|
|---|
| 269 | end;
|
|---|
| 270 |
|
|---|
| 271 | procedure TBaseMessgDlg.SplitText(Preview: Boolean);
|
|---|
| 272 | var
|
|---|
| 273 | Start, Stop, OrdinaryStop, LinesCount: Integer;
|
|---|
| 274 | S: string;
|
|---|
| 275 | begin
|
|---|
| 276 | Start := 1;
|
|---|
| 277 | LinesCount := 0;
|
|---|
| 278 | while Start < Length(MessgText) do
|
|---|
| 279 | begin
|
|---|
| 280 | Stop := Start;
|
|---|
| 281 | while (Stop < Length(MessgText)) and (MessgText[Stop] <> '\') and
|
|---|
| 282 | (BiColorTextWidth(Canvas, Copy(MessgText, Start, Stop - Start + 1)) <
|
|---|
| 283 | Width - 56) do
|
|---|
| 284 | Inc(Stop);
|
|---|
| 285 | if Stop <> Length(MessgText) then
|
|---|
| 286 | begin
|
|---|
| 287 | OrdinaryStop := Stop;
|
|---|
| 288 | repeat
|
|---|
| 289 | Dec(OrdinaryStop)
|
|---|
| 290 | until (MessgText[OrdinaryStop + 1] = ' ') or
|
|---|
| 291 | (MessgText[OrdinaryStop + 1] = '\');
|
|---|
| 292 | if (OrdinaryStop + 1 - Start) * 2 >= Stop - Start then
|
|---|
| 293 | Stop := OrdinaryStop;
|
|---|
| 294 | end;
|
|---|
| 295 | if not Preview then
|
|---|
| 296 | begin
|
|---|
| 297 | S := Copy(MessgText, Start, Stop - Start + 1);
|
|---|
| 298 | LoweredTextOut(Canvas, -1, MainTexture,
|
|---|
| 299 | (Width - BiColorTextWidth(Canvas, S)) div 2,
|
|---|
| 300 | 19 + Border + TopSpace + LinesCount * MessageLineSpacing, S);
|
|---|
| 301 | end;
|
|---|
| 302 | Start := Stop + 2;
|
|---|
| 303 | Inc(LinesCount);
|
|---|
| 304 | end;
|
|---|
| 305 | if Preview then
|
|---|
| 306 | Lines := LinesCount;
|
|---|
| 307 | end;
|
|---|
| 308 |
|
|---|
| 309 | procedure TBaseMessgDlg.CorrectHeight;
|
|---|
| 310 | var
|
|---|
| 311 | I: Integer;
|
|---|
| 312 | NewHeight: Integer;
|
|---|
| 313 | NewTop: Integer;
|
|---|
| 314 | begin
|
|---|
| 315 | NewHeight := 72 + Border + TopSpace + Lines * MessageLineSpacing;
|
|---|
| 316 | NewTop := Screen.PrimaryMonitor.Top + (Screen.PrimaryMonitor.Height - NewHeight) div 2;
|
|---|
| 317 | BoundsRect := Bounds(Left, NewTop, Width, NewHeight);
|
|---|
| 318 | for I := 0 to ControlCount - 1 do
|
|---|
| 319 | Controls[I].Top := NewHeight - (34 + Border);
|
|---|
| 320 | end;
|
|---|
| 321 |
|
|---|
| 322 | end.
|
|---|
| 323 |
|
|---|
| 324 |
|
|---|