source: components/CoolTrayIcon/TextTrayIcon.pas

Last change on this file was 1, checked in by maron, 16 years ago

3.1 verze, první revize

File size: 12.4 KB
Line 
1{*****************************************************************}
2{ This is a component for placing icons in the notification area }
3{ of the Windows taskbar (aka. the traybar). }
4{ }
5{ It is an expanded version of my CoolTrayIcon component, which }
6{ you will need to make this work. The expanded features allow }
7{ you to easily draw text in the tray icon. }
8{ }
9{ The component is freeware. Feel free to use and improve it. }
10{ I would be pleased to hear what you think. }
11{ }
12{ Troels Jakobsen - delphiuser@get2net.dk }
13{ Copyright (c) 2002 }
14{ }
15{ Portions by Jouni Airaksinen - mintus@codefield.com }
16{*****************************************************************}
17
18unit TextTrayIcon;
19
20interface
21
22uses
23 CoolTrayIcon, Windows, Graphics, Classes, Controls;
24
25type
26 TOffsetOptions = class(TPersistent)
27 private
28 FOffsetX,
29 FOffsetY,
30 FLineDistance: Integer;
31 FOnChange: TNotifyEvent; // Procedure var.
32 procedure SetOffsetX(Value: Integer);
33 procedure SetOffsetY(Value: Integer);
34 procedure SetLineDistance(Value: Integer);
35 protected
36 procedure Changed; dynamic;
37 published
38 property OffsetX: Integer read FOffsetX write SetOffsetX;
39 property OffsetY: Integer read FOffsetY write SetOffsetY;
40 property LineDistance: Integer read FLineDistance write SetLineDistance;
41 property OnChange: TNotifyEvent read FOnChange write FOnChange;
42 end;
43
44 TTextTrayIcon = class(TCoolTrayIcon)
45 private
46 FFont: TFont;
47 FColor: TColor;
48 FInvertTextColor: TColor;
49 FBorder: Boolean;
50 FBorderColor: TColor;
51 FText: String;
52 FTextBitmap: TBitmap;
53 FOffsetOptions: TOffsetOptions;
54 FBackgroundIcon: TIcon;
55 procedure FontChanged(Sender: TObject);
56 procedure SplitText(const Strings: TList);
57 procedure OffsetOptionsChanged(OffsetOptions: TObject);
58 procedure SetBackgroundIcon(Value: TIcon);
59 protected
60 procedure Loaded; override;
61 function LoadDefaultIcon: Boolean; override;
62 function LoadDefaultBackgroundIcon: Boolean; virtual;
63 procedure Paint; virtual;
64 procedure SetText(Value: String);
65 procedure SetTextBitmap(Value: TBitmap);
66 procedure SetFont(Value: TFont);
67 procedure SetColor(Value: TColor);
68 procedure SetBorder(Value: Boolean);
69 procedure SetBorderColor(Value: TColor);
70 procedure SetOffsetOptions(Value: TOffsetOptions);
71 function TransparentBitmapToIcon(const Bitmap: TBitmap; const Icon: TIcon;
72 MaskColor: TColor): Boolean;
73 public
74 constructor Create(AOwner: TComponent); override;
75 destructor Destroy; override;
76 procedure Draw;
77 published
78 property BackgroundIcon: TIcon read FBackgroundIcon write SetBackgroundIcon;
79 property Text: String read FText write SetText;
80 property Font: TFont read FFont write SetFont;
81 property Color: TColor read FColor write SetColor default clBtnFace;
82 property Border: Boolean read FBorder write SetBorder;
83 property BorderColor: TColor read FBorderColor write SetBorderColor
84 default clBlack;
85 property Options: TOffsetOptions read FOffsetOptions write SetOffsetOptions;
86 end;
87
88
89implementation
90
91uses
92 SysUtils;
93
94{------------------- TOffsetOptions -------------------}
95
96procedure TOffsetOptions.Changed;
97begin
98 if Assigned(FOnChange) then FOnChange(Self);
99end;
100
101
102procedure TOffsetOptions.SetOffsetX(Value: Integer);
103begin
104 if Value <> FOffsetX then
105 begin
106 FOffsetX := Value;
107 Changed;
108 end;
109end;
110
111
112procedure TOffsetOptions.SetOffsetY(Value: Integer);
113begin
114 if Value <> FOffsetY then
115 begin
116 FOffsetY := Value;
117 Changed;
118 end;
119end;
120
121
122procedure TOffsetOptions.SetLineDistance(Value: Integer);
123begin
124 if Value <> FLineDistance then
125 begin
126 FLineDistance := Value;
127 Changed;
128 end;
129end;
130
131{------------------- TTextTrayIcon --------------------}
132
133constructor TTextTrayIcon.Create(AOwner: TComponent);
134begin
135 inherited Create(AOwner);
136 FBackgroundIcon := TIcon.Create;
137 FTextBitmap := TBitmap.Create;
138 FFont := TFont.Create;
139 FFont.OnChange := FontChanged;
140 FColor := clBtnFace;
141 FBorderColor := clBlack;
142 FOffsetOptions := TOffsetOptions.Create;
143 FOffsetOptions.OnChange := OffsetOptionsChanged;
144
145 { Assign a default bg. icon if BackgroundIcon property is empty.
146 This will assign a bg. icon to the component when it is created for
147 the very first time. When the user assigns another icon it will not
148 be overwritten next time the project loads.
149 This is similar to the default Icon in parent class CoolTrayIcon. }
150 { On second thought: do we really want a default bg. icon? Probably not.
151 For this reason the class method LoadDefaultBackgroundIcon will
152 return false. }
153 if (csDesigning in ComponentState) then
154 if FBackgroundIcon.Handle = 0 then
155 if LoadDefaultBackgroundIcon then
156 begin
157 FBackgroundIcon.Handle := LoadIcon(0, IDI_WINLOGO);
158 Draw;
159 end;
160end;
161
162
163destructor TTextTrayIcon.Destroy;
164begin
165 try
166 FFont.Free;
167 FTextBitmap.Free;
168 FOffsetOptions.Free;
169 try
170 if FBackgroundIcon <> nil then
171 FBackgroundIcon.Free;
172 except
173 on Exception do
174 // Do nothing; the background icon seems to be invalid
175 end;
176 finally
177 inherited Destroy;
178 end;
179end;
180
181
182procedure TTextTrayIcon.Loaded;
183begin
184 inherited Loaded; // Always call inherited Loaded first
185 // No extra handling needed
186end;
187
188
189function TTextTrayIcon.LoadDefaultIcon: Boolean;
190{ We don't want a default icon, so we override this method inherited
191 from CoolTrayIcon. }
192begin
193 Result := False; // No thanks, no default icon
194end;
195
196
197function TTextTrayIcon.LoadDefaultBackgroundIcon: Boolean;
198{ This method is called to determine whether to assign a default bg. icon
199 to the component. Descendant classes can override the method to change
200 this behavior. }
201begin
202 Result := False; // No thanks, no default bg. icon
203end;
204
205
206procedure TTextTrayIcon.FontChanged(Sender: TObject);
207{ This method is invoked when user assigns to Font (but not when Font is set
208 directly to another TFont var.) }
209begin
210 Draw;
211end;
212
213
214procedure TTextTrayIcon.SetText(Value: String);
215begin
216 FText := Value;
217 Draw;
218end;
219
220
221procedure TTextTrayIcon.SetTextBitmap(Value: TBitmap);
222begin
223 FTextBitmap := Value; // Assign?
224 Draw;
225end;
226
227
228procedure TTextTrayIcon.SetFont(Value: TFont);
229begin
230 FFont.Assign(Value);
231 Draw;
232end;
233
234
235procedure TTextTrayIcon.SetColor(Value: TColor);
236begin
237 FColor := Value;
238 Draw;
239end;
240
241
242procedure TTextTrayIcon.SetBorder(Value: Boolean);
243begin
244 FBorder := Value;
245 Draw;
246end;
247
248
249procedure TTextTrayIcon.SetBorderColor(Value: TColor);
250begin
251 FBorderColor := Value;
252 Draw;
253end;
254
255
256procedure TTextTrayIcon.SetOffsetOptions(Value: TOffsetOptions);
257{ This method will only be invoked if the user creates a new
258 TOffsetOptions object. User will probably just set the values
259 of the existing TOffsetOptions object. }
260begin
261 FOffsetOptions.Assign(Value);
262 Draw;
263end;
264
265
266procedure TTextTrayIcon.OffsetOptionsChanged(OffsetOptions: TObject);
267{ This method will be invoked when the user changes the values of the
268 existing TOffsetOptions object. }
269begin
270 Draw;
271end;
272
273
274procedure TTextTrayIcon.SetBackgroundIcon(Value: TIcon);
275begin
276 FBackgroundIcon.Assign(Value);
277 Draw;
278end;
279
280
281procedure TTextTrayIcon.Draw;
282var
283 Ico: TIcon;
284 rc: Boolean;
285begin
286 CycleIcons := False; // We cannot cycle and draw at the same time
287 Paint; // Render FTextBitmap
288 Ico := TIcon.Create;
289 if (Assigned(FBackgroundIcon)) and not (FBackgroundIcon.Empty) then
290 // Draw text transparently on background icon
291 rc := TransparentBitmapToIcon(FTextBitmap, Ico, FColor)
292 else
293 begin
294 // Just draw text; no background icon
295 if FColor <> clNone then
296 FInvertTextColor := clNone;
297 rc := BitmapToIcon(FTextBitmap, Ico, FInvertTextColor);
298 end;
299
300 if rc then
301 begin
302 Icon.Assign(Ico);
303// Refresh; // Always refresh after icon assignment
304 Ico.Free;
305 end;
306end;
307
308
309function TTextTrayIcon.TransparentBitmapToIcon(const Bitmap: TBitmap;
310 const Icon: TIcon; MaskColor: TColor): Boolean;
311{ Render an icon from a 16x16 bitmap. Return false if error.
312 MaskColor is a color that will be rendered transparently. Use clNone for
313 no transparency. }
314var
315 BitmapImageList: TImageList;
316 Bmp: TBitmap;
317 FInvertColor: TColor;
318begin
319 BitmapImageList := TImageList.CreateSize(16, 16);
320 try
321 Result := False;
322 BitmapImageList.AddIcon(FBackgroundIcon);
323 Bmp := TBitmap.Create;
324
325 if (FColor = clNone) or (FColor = FFont.Color) then
326 FInvertColor := ColorToRGB(FFont.Color) xor $00FFFFFF
327 else
328 FInvertColor := MaskColor;
329
330 Bmp.Canvas.Brush.Color := FInvertColor;
331 BitmapImageList.GetBitmap(0, Bmp);
332 Bitmap.Transparent := True;
333 Bitmap.TransParentColor := FInvertTextColor;
334 Bmp.Canvas.Draw(0, 0, Bitmap);
335
336 BitmapImageList.AddMasked(Bmp, FInvertColor);
337 BitmapImageList.GetIcon(1, Icon);
338 Bmp.Free;
339 Result := True;
340 finally
341 BitmapImageList.Free;
342 end;
343end;
344
345
346procedure TTextTrayIcon.Paint;
347var
348 Bitmap: TBitmap;
349 Left, Top, LinesTop, LineHeight: Integer;
350 Substr: PChar;
351 Strings: TList;
352 I: Integer;
353begin
354 Bitmap := TBitmap.Create;
355 try
356 Bitmap.Width := 16;
357 Bitmap.Height := 16;
358// Bitmap.Canvas.TextFlags := 2; // ETO_OPAQUE
359
360 // Render background rectangle
361 if (FColor = clNone) or (FColor = FFont.Color) then
362 FInvertTextColor := ColorToRGB(FFont.Color) xor $00FFFFFF
363 else
364 FInvertTextColor := FColor;
365 Bitmap.Canvas.Brush.Color := FInvertTextColor;
366 Bitmap.Canvas.FillRect(Rect(0, 0, 16, 16));
367
368 // Render text; check for line breaks
369 Bitmap.Canvas.Font.Assign(FFont);
370 Substr := StrPos(PChar(FText), #13);
371 if Substr = nil then
372 begin
373 // No line breaks
374 Left := (15 - Bitmap.Canvas.TextWidth(FText)) div 2;
375 if FOffsetOptions <> nil then
376 Left := Left + FOffsetOptions.OffsetX;
377 Top := (15 - Bitmap.Canvas.TextHeight(FText)) div 2;
378 if FOffsetOptions <> nil then
379 Top := Top + FOffsetOptions.OffsetY;
380 Bitmap.Canvas.TextOut(Left, Top, FText);
381 end
382 else
383 begin
384 // Line breaks
385 Strings := TList.Create;
386 SplitText(Strings);
387 LineHeight := Bitmap.Canvas.TextHeight(Substr);
388 if FOffsetOptions <> nil then
389 LineHeight := LineHeight + FOffsetOptions.LineDistance;
390 LinesTop := (15 - (LineHeight * Strings.Count)) div 2;
391 if FOffsetOptions <> nil then
392 LinesTop := LinesTop + FOffsetOptions.OffsetY;
393 for I := 0 to Strings.Count -1 do
394 begin
395 Substr := Strings[I];
396 Left := (15 - Bitmap.Canvas.TextWidth(Substr)) div 2;
397 if FOffsetOptions <> nil then
398 Left := Left + FOffsetOptions.OffsetX;
399 Top := LinesTop + (LineHeight * I);
400 Bitmap.Canvas.TextOut(Left, Top, Substr);
401 end;
402 for I := 0 to Strings.Count -1 do
403 StrDispose(Strings[I]);
404 Strings.Free;
405 end;
406
407 // Render border
408 if FBorder then
409 begin
410 Bitmap.Canvas.Brush.Color := FBorderColor;
411 Bitmap.Canvas.FrameRect(Rect(0, 0, 16, 16));
412 end;
413
414 // Assign the final bitmap
415 FTextBitmap.Assign(Bitmap);
416
417 finally
418 Bitmap.Free;
419 end;
420end;
421
422
423procedure TTextTrayIcon.SplitText(const Strings: TList);
424
425 function PeekedString(S: String): String;
426 var
427 P: Integer;
428 begin
429 P := Pos(#13, S);
430 if P = 0 then
431 Result := S
432 else
433 Result := Copy(S, 1, P-1);
434 end;
435
436var
437 Substr: String;
438 P: Integer;
439 S: PChar;
440begin
441 Strings.Clear;
442 Substr := FText;
443 repeat
444 P := Pos(#13, Substr);
445 if P = 0 then
446 begin
447 S := StrNew(PChar(Substr));
448 Strings.Add(S);
449 end
450 else
451 begin
452 S := StrNew(PChar(PeekedString(Substr)));
453 Strings.Add(S);
454 Delete(Substr, 1, P);
455 end;
456 until P = 0;
457end;
458
459end.
460
Note: See TracBrowser for help on using the repository browser.