TextTrayIcon.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:12k
源码类别:

Delphi控件源码

开发平台:

Delphi

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