-
Notifications
You must be signed in to change notification settings - Fork 6
/
untERDEllipseLedClock.pas
405 lines (346 loc) · 10.6 KB
/
untERDEllipseLedClock.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
{
untERDEllipseLedClock v1.0.0 - a led clock like found in radio studio's
for Delphi 2010 - 10.4 by Ernst Reidinga
https://erdesigns.eu
This unit is part of the ERDesigns Audio Toolkit Components Pack.
(c) Copyright 2020 Ernst Reidinga <ernst@erdesigns.eu>
Bugfixes / Updates:
- Initial Release 1.0.0
If you use this unit, please give credits to the original author;
Ernst Reidinga.
}
unit untERDEllipseLedClock;
interface
uses
System.SysUtils, System.Classes, Winapi.Windows, Vcl.Controls, Vcl.Graphics,
Winapi.Messages, System.Types, Vcl.ExtCtrls, GDIPlus;
type
TERDEllipseLedClockTimeEvent = procedure(Sender: TObject; Hours, Minutes, Seconds: Integer) of object;
TERDEllipseLedClockStyle = (csSimple, csLed);
TERDEllipseLedClock = class(TGraphicControl)
private
{ Private declarations }
FStyle : TERDEllipseLedClockStyle;
FOnColor : TColor;
FOffColor : TColor;
FTickSize : Integer;
FPosition : Integer;
{ Buffer - Avoid flickering }
FBuffer : TBitmap;
FRedraw : Boolean;
{ Clock Timer }
FTime : TTime;
FClockTimer : TTimer;
FOnTimeEvent : TERDEllipseLedClockTimeEvent;
procedure SetStyle(const S: TERDEllipseLedClockStyle);
procedure SetOnColor(const C: TColor);
procedure SetOffColor(const C: TColor);
procedure SetTickSize(const I: Integer);
procedure SetPosition(const I: Integer);
function GetActive : Boolean;
procedure SetActive(const B: Boolean);
protected
{ Protected declarations }
procedure SetTime(T: TTime);
procedure OnClockTimer(Sender: TObject);
procedure Paint; override;
procedure Resize; override;
procedure WndProc(var Message: TMessage); override;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Redraw: Boolean read FRedraw write FRedraw;
published
{ Published declarations }
property Active: Boolean read GetActive write SetActive default False;
property Style: TERDEllipseLedClockStyle read FStyle write SetStyle default csSimple;
property OnColor: TColor read FOnColor write SetOnColor default $005C86FF;
property OffColor: TColor read FOffColor write SetOffColor default $00EAA900;
property TickSize: Integer read FTickSize write SetTickSize default 4;
property Position: Integer read FPosition write SetPosition default 1;
property OnTime: TERDEllipseLedClockTimeEvent read FOnTimeEvent write FOnTimeEvent;
property Align;
property Anchors;
property Color;
property Constraints;
property Enabled;
property ParentColor;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Touch;
property Visible;
property OnClick;
property OnGesture;
property OnMouseActivate;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnResize;
end;
implementation
uses System.Math, untERDMidiCommon;
(******************************************************************************)
(*
(* ERD Ellipse Led Clock (TERDEllipseLedClock)
(*
(******************************************************************************)
constructor TERDEllipseLedClock.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
{ Transparent background }
ControlStyle := ControlStyle + [csOpaque];
{ Create Buffers }
FBuffer := TBitmap.Create;
FBuffer.PixelFormat := pf32bit;
{ Defaults }
FStyle := csSimple;
FOnColor := $00EAA900;
FOffColor := $008F8A87;
FTickSize := 4;
FPosition := 1;
{ Set default width and height }
Width := 201;
Height := 201;
{ Clock Timer }
FClockTimer := TTimer.Create(Self);
FClockTimer.OnTimer := OnClockTimer;
FClockTimer.Enabled := False;
{ Draw for the first time }
Redraw := True;
end;
destructor TERDEllipseLedClock.Destroy;
begin
{ Free Buffer }
FBuffer.Free;
{ Free Clock Timer }
FClockTimer.Free;
inherited Destroy;
end;
procedure TERDEllipseLedClock.SetStyle(const S: TERDEllipseLedClockStyle);
begin
if Style <> S then
begin
FStyle := S;
Redraw := True;
Invalidate;
end;
end;
procedure TERDEllipseLedClock.SetOnColor(const C: TColor);
begin
if OnColor <> C then
begin
FOnColor := C;
Redraw := True;
Invalidate;
end;
end;
procedure TERDEllipseLedClock.SetOffColor(const C: TColor);
begin
if OffColor <> C then
begin
FOffColor := C;
Redraw := True;
Invalidate;
end;
end;
procedure TERDEllipseLedClock.SetTickSize(const I: Integer);
begin
if TickSize <> I then
begin
FTickSize := I;
Redraw := True;
Invalidate;
end;
end;
procedure TERDEllipseLedClock.SetPosition(const I: Integer);
begin
if Position <> I then
begin
if (I < 0) then
FPosition := 0
else
if I > 59 then
FPosition := 59
else
FPosition := I;
Redraw := True;
Invalidate;
end;
end;
function TERDEllipseLedClock.GetActive : Boolean;
begin
Result := FClockTimer.Enabled;
end;
procedure TERDEllipseLedClock.SetActive(const B: Boolean);
begin
if B then FTime := Now;
FClockTimer.Enabled := B;
end;
procedure TERDEllipseLedClock.SetTime(T: TTime);
var
Hours: Word;
Mins: Word;
Secs: Word;
MSecs: Word;
begin
if FTime <> T then
begin
FTime := T;
DecodeTime(FTime, Hours, Mins, Secs, MSecs);
if Assigned(FOnTimeEvent) then FOnTimeEvent(Self, Hours, Mins, Secs);
Position := Secs;
end;
end;
procedure TERDEllipseLedClock.OnClockTimer(Sender: TObject);
begin
SetTime(FTime + 1/SecsPerDay);
end;
procedure TERDEllipseLedClock.Paint;
const
TAU = PI * 2;
var
WorkRect : TRect;
TickOffset : Double;
TS : Integer;
procedure DrawBackground;
begin
with FBuffer.Canvas do
begin
Brush.Color := Color;
FillRect(ClipRect);
end;
end;
procedure DrawTick(var FGraphics: IGPGraphics; const Rect: TRect; const TickColor: TColor);
var
Brush : IGPSolidBrush;
begin
{ Create Solid Brush }
Brush := TGPSolidBrush.Create(TGPColor.CreateFromColorRef(TickColor));
{ Draw Tick }
FGraphics.FillEllipse(Brush, TGPRect.Create(Rect));
end;
procedure DrawTickLed(var FGraphics: IGPGraphics; const Rect: TRect; const TickColor: TColor);
var
FFromColor : TGPColor;
FToColor : TGPColor;
FLedBrush : IGPLinearGradientBrush;
FLightColor : TGPColor;
FLightToColor : TGPColor;
FLedLight : IGPLinearGradientBrush;
FLightRect : TRect;
FLedBorderBrush : IGPSolidBrush;
LedRect : TRect;
begin
LedRect := Rect;
FLedBorderBrush := TGPSolidBrush.Create(TGPColor.CreateFromColorRef(Darken(TickColor, 50)));
{ Draw background and border }
FGraphics.FillEllipse(FLedBorderBrush, TGPRect.Create(LedRect));
InflateRect(LedRect, -1, -1);
{ Create Solid Border Brush }
FLedBorderBrush := TGPSolidBrush.Create(TGPColor.CreateFromColorRef(Darken(TickColor, 20)));
{ Draw background and border }
FGraphics.FillEllipse(FLedBorderBrush, TGPRect.Create(LedRect));
InflateRect(LedRect, -1, -1);
{ Create colors for gradient led face }
FFromColor := TGPColor.CreateFromColorRef(TickColor);
FToColor := TGPColor.CreateFromColorRef(Brighten(TickColor, 80));
FLedBrush := TGPLinearGradientBrush.Create(TGPRect.Create(Rect), FFromColor, FToColor, 90);
FGraphics.FillEllipse(FLedBrush, TGPRect.Create(LedRect));
{ Create light overlay on the top of the led face }
FLightColor := TGPColor.CreateFromColorRef(Brighten(TickColor, 65));
FLightColor.Alpha := 125;
FLightToColor := TGPColor.CreateFromColorRef(Brighten(TickColor, 20));
FlightColor.Alpha := 125;
FLightRect := LedRect;
InflateRect(FLightRect, -((Ceil(LedRect.Width / 5) * 4) - 4), -1);
FLightRect.Height := Ceil(LedRect.Height / 4);
FLedLight := TGPLinearGradientBrush.Create(TGPRect.Create(Rect), FLightColor, FLightToColor, 90);
FGraphics.FillEllipse(FLedLight, TGPRect.Create(FLightRect));
end;
procedure DrawTicks(var FGraphics: IGPGraphics);
var
A : Double;
I, X, Y, R : Integer;
C : TColor;
begin
R := Round(WorkRect.Width / 2);
for I := 0 to 59 do
begin
A := TAU * I / 60;
X := (R + Ceil(Cos(A - TickOffset) * R) + TickSize);
Y := (R + Ceil(Sin(A - TickOffset) * R) + TickSize);
if Position <= I -1 then
C := OffColor
else
C := OnColor;
case Style of
csSimple:
begin
if (I mod 5 = 0) or (Position >= I) then
DrawTick(FGraphics, Rect(X - TickSize, Y - TickSize, X + TickSize, Y + TickSize), C)
else
DrawTick(FGraphics, Rect(X - TS, Y - TS, X + TS, Y + TS), C);
end;
csLed:
begin
if (I mod 5 = 0) or (Position >= I ) then
DrawTickLed(FGraphics, Rect(X - TickSize, Y - TickSize, X + TickSize, Y + TickSize), C)
else
DrawTickLed(FGraphics, Rect(X - TS, Y - TS, X + TS, Y + TS), C);
end;
end;
end;
end;
var
FGraphics : IGPGraphics;
begin
{ Redraw Buffer}
if Redraw then
begin
Redraw := False;
{ Set Buffer size }
FBuffer.SetSize(ClientWidth, ClientHeight);
{ Create GDI+ Graphic }
FGraphics := TGPGraphics.Create(FBuffer.Canvas.Handle);
FGraphics.SmoothingMode := SmoothingModeAntiAlias;
FGraphics.InterpolationMode := InterpolationModeHighQualityBicubic;
WorkRect := ClientRect;
TS := Round(TickSize / 2);
InflateRect(WorkRect, -(TickSize +1), -(TickSize +1));
{ Tick Offset }
TickOffset := PI * 4 / 8;
{ Draw the clock to the buffer }
DrawBackground;
DrawTicks(FGraphics);
end;
{ Draw the whole buffer to the surface }
BitBlt(Canvas.Handle, 0, 0, ClientWidth, ClientHeight, FBuffer.Canvas.Handle, 0, 0, SRCCOPY);
inherited;
end;
procedure TERDEllipseLedClock.Resize;
begin
Redraw := True;
inherited;
end;
procedure TERDEllipseLedClock.WndProc(var Message: TMessage);
begin
inherited;
case Message.Msg of
{ Enabled/Disabled - Redraw }
CM_ENABLEDCHANGED:
begin
{ }
end;
{ The color changed }
CM_COLORCHANGED:
begin
Redraw := True;
Invalidate
end;
end;
end;
end.