home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 December / Chip_2002-12_cd1.bin / zkuste / delphi / kompon / d234567 / COOLTRAY.ZIP / TextTrayIcon.pas < prev   
Pascal/Delphi Source File  |  2002-04-11  |  12KB  |  451 lines

  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.  
  18. unit TextTrayIcon;
  19.  
  20. interface
  21.  
  22. uses
  23.   CoolTrayIcon, Windows, Graphics, Classes, Controls;
  24.  
  25. type
  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.  
  89. implementation
  90.  
  91. uses
  92.   SysUtils;
  93.  
  94. {------------------- TOffsetOptions -------------------}
  95.  
  96. procedure TOffsetOptions.Changed;
  97. begin
  98.   if Assigned(FOnChange) then FOnChange(Self);
  99. end;
  100.  
  101.  
  102. procedure TOffsetOptions.SetOffsetX(Value: Integer);
  103. begin
  104.   if Value <> FOffsetX then
  105.   begin
  106.     FOffsetX := Value;
  107.     Changed;
  108.   end;
  109. end;
  110.  
  111.  
  112. procedure TOffsetOptions.SetOffsetY(Value: Integer);
  113. begin
  114.   if Value <> FOffsetY then
  115.   begin
  116.     FOffsetY := Value;
  117.     Changed;
  118.   end;
  119. end;
  120.  
  121.  
  122. procedure TOffsetOptions.SetLineDistance(Value: Integer);
  123. begin
  124.   if Value <> FLineDistance then
  125.   begin
  126.     FLineDistance := Value;
  127.     Changed;
  128.   end;
  129. end;
  130.  
  131. {------------------- TTextTrayIcon --------------------}
  132.  
  133. constructor TTextTrayIcon.Create(AOwner: TComponent);
  134. begin
  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;
  160. end;
  161.  
  162.  
  163. destructor TTextTrayIcon.Destroy;
  164. begin
  165.   FFont.Free;
  166.   FTextBitmap.Free;
  167.   FOffsetOptions.Free;
  168.   inherited Destroy;
  169. end;
  170.  
  171.  
  172. procedure TTextTrayIcon.Loaded;
  173. begin
  174.   inherited Loaded;          // Always call inherited Loaded first
  175.   // No extra handling needed
  176. end;
  177.  
  178.  
  179. function TTextTrayIcon.LoadDefaultIcon: Boolean;
  180. { We don't want a default icon, so we override this method inherited
  181.   from CoolTrayIcon. }
  182. begin
  183.   Result := False;           // No thanks, no default icon
  184. end;
  185.  
  186.  
  187. function TTextTrayIcon.LoadDefaultBackgroundIcon: Boolean;
  188. { This method is called to determine whether to assign a default bg. icon
  189.   to the component. Descendant classes can override the method to change
  190.   this behavior. }
  191. begin
  192.   Result := False;           // No thanks, no default bg. icon
  193. end;
  194.  
  195.  
  196. procedure TTextTrayIcon.FontChanged(Sender: TObject);
  197. { This method is invoked when user assigns to Font (but not when Font is set
  198.   directly to another TFont var.) }
  199. begin
  200.   Draw;
  201. end;
  202.  
  203.  
  204. procedure TTextTrayIcon.SetText(Value: String);
  205. begin
  206.   FText := Value;
  207.   Draw;
  208. end;
  209.  
  210.  
  211. procedure TTextTrayIcon.SetTextBitmap(Value: TBitmap);
  212. begin
  213.   FTextBitmap := Value;      // Assign?
  214.   Draw;
  215. end;
  216.  
  217.  
  218. procedure TTextTrayIcon.SetFont(Value: TFont);
  219. begin
  220.   FFont.Assign(Value);
  221.   Draw;
  222. end;
  223.  
  224.  
  225. procedure TTextTrayIcon.SetColor(Value: TColor);
  226. begin
  227.   FColor := Value;
  228.   Draw;
  229. end;
  230.  
  231.  
  232. procedure TTextTrayIcon.SetBorder(Value: Boolean);
  233. begin
  234.   FBorder := Value;
  235.   Draw;
  236. end;
  237.  
  238.  
  239. procedure TTextTrayIcon.SetBorderColor(Value: TColor);
  240. begin
  241.   FBorderColor := Value;
  242.   Draw;
  243. end;
  244.  
  245.  
  246. procedure TTextTrayIcon.SetOffsetOptions(Value: TOffsetOptions);
  247. { This method will only be invoked if the user creates a new
  248.   TOffsetOptions object. User will probably just set the values
  249.   of the existing TOffsetOptions object. }
  250. begin
  251.   FOffsetOptions.Assign(Value);
  252.   Draw;
  253. end;
  254.  
  255.  
  256. procedure TTextTrayIcon.OffsetOptionsChanged(OffsetOptions: TObject);
  257. { This method will be invoked when the user changes the values of the
  258.   existing TOffsetOptions object. }
  259. begin
  260.   Draw;
  261. end;
  262.  
  263.  
  264. procedure TTextTrayIcon.SetBackgroundIcon(Value: TIcon);
  265. begin
  266.   FBackgroundIcon.Assign(Value);
  267.   Draw;
  268. end;
  269.  
  270.  
  271. procedure TTextTrayIcon.Draw;
  272. var
  273.   Ico: TIcon;
  274.   rc: Boolean;
  275. begin
  276.   CycleIcons := False;       // We cannot cycle and draw at the same time
  277.   Paint;                     // Render FTextBitmap
  278.   Ico := TIcon.Create;
  279.   if (Assigned(FBackgroundIcon)) and not (FBackgroundIcon.Empty) then
  280.     // Draw text transparently on background icon
  281.     rc := TransparentBitmapToIcon(FTextBitmap, Ico, FColor)
  282.   else
  283.   begin
  284.     // Just draw text; no background icon
  285.     if FColor <> clNone then
  286.       FInvertTextColor := clNone;
  287.     rc := BitmapToIcon(FTextBitmap, Ico, FInvertTextColor);
  288.   end;
  289.  
  290.   if rc then
  291.   begin
  292.     Icon.Assign(Ico);
  293. //    Refresh;                 // Always refresh after icon assignment
  294.     Ico.Free;
  295.   end;
  296. end;
  297.  
  298.  
  299. function TTextTrayIcon.TransparentBitmapToIcon(const Bitmap: TBitmap;
  300.   const Icon: TIcon; MaskColor: TColor): Boolean;
  301. { Render an icon from a 16x16 bitmap. Return false if error.
  302.   MaskColor is a color that will be rendered transparently. Use clNone for
  303.   no transparency. }
  304. var
  305.   BitmapImageList: TImageList;
  306.   Bmp: TBitmap;
  307.   FInvertColor: TColor;
  308. begin
  309.   BitmapImageList := TImageList.CreateSize(16, 16);
  310.   try
  311.     Result := False;
  312.     BitmapImageList.AddIcon(FBackgroundIcon);
  313.     Bmp := TBitmap.Create;
  314.  
  315.     if (FColor = clNone) or (FColor = FFont.Color) then
  316.       FInvertColor := ColorToRGB(FFont.Color) xor $00FFFFFF
  317.     else
  318.       FInvertColor := MaskColor;
  319.  
  320.     Bmp.Canvas.Brush.Color := FInvertColor;
  321.     BitmapImageList.GetBitmap(0, Bmp);
  322.     Bitmap.Transparent := True;
  323.     Bitmap.TransParentColor := FInvertTextColor;
  324.     Bmp.Canvas.Draw(0, 0, Bitmap);
  325.  
  326.     BitmapImageList.AddMasked(Bmp, FInvertColor);
  327.     BitmapImageList.GetIcon(1, Icon);
  328.     Bmp.Free;
  329.     Result := True;
  330.   finally
  331.     BitmapImageList.Free;
  332.   end;
  333. end;
  334.  
  335.  
  336. procedure TTextTrayIcon.Paint;
  337. var
  338.   Bitmap: TBitmap;
  339.   Left, Top, LinesTop, LineHeight: Integer;
  340.   Substr: PChar;
  341.   Strings: TList;
  342.   I: Integer;
  343. begin
  344.   Bitmap := TBitmap.Create;
  345.   try
  346.     Bitmap.Width := 16;
  347.     Bitmap.Height := 16;
  348. //    Bitmap.Canvas.TextFlags := 2;         // ETO_OPAQUE
  349.  
  350.     // Render background rectangle
  351.     if (FColor = clNone) or (FColor = FFont.Color) then
  352.       FInvertTextColor := ColorToRGB(FFont.Color) xor $00FFFFFF
  353.     else
  354.       FInvertTextColor := FColor;
  355.     Bitmap.Canvas.Brush.Color := FInvertTextColor;
  356.     Bitmap.Canvas.FillRect(Rect(0, 0, 16, 16));
  357.  
  358.     // Render text; check for line breaks
  359.     Bitmap.Canvas.Font.Assign(FFont);
  360.     Substr := StrPos(PChar(FText), #13);
  361.     if Substr = nil then
  362.     begin
  363.       // No line breaks
  364.       Left := (15 - Bitmap.Canvas.TextWidth(FText)) div 2;
  365.       if FOffsetOptions <> nil then
  366.         Left := Left + FOffsetOptions.OffsetX;
  367.       Top := (15 - Bitmap.Canvas.TextHeight(FText)) div 2;
  368.       if FOffsetOptions <> nil then
  369.         Top := Top + FOffsetOptions.OffsetY;
  370.       Bitmap.Canvas.TextOut(Left, Top, FText);
  371.     end
  372.     else
  373.     begin
  374.       // Line breaks
  375.       Strings := TList.Create;
  376.       SplitText(Strings);
  377.       LineHeight := Bitmap.Canvas.TextHeight(Substr);
  378.       if FOffsetOptions <> nil then
  379.         LineHeight := LineHeight + FOffsetOptions.LineDistance;
  380.       LinesTop := (15 - (LineHeight * Strings.Count)) div 2;
  381.       if FOffsetOptions <> nil then
  382.         LinesTop := LinesTop + FOffsetOptions.OffsetY;
  383.       for I := 0 to Strings.Count -1 do
  384.       begin
  385.         Substr := Strings[I];
  386.         Left := (15 - Bitmap.Canvas.TextWidth(Substr)) div 2;
  387.         if FOffsetOptions <> nil then
  388.           Left := Left + FOffsetOptions.OffsetX;
  389.         Top := LinesTop + (LineHeight * I);
  390.         Bitmap.Canvas.TextOut(Left, Top, Substr);
  391.       end;
  392.       for I := 0 to Strings.Count -1 do
  393.         StrDispose(Strings[I]);
  394.       Strings.Free;
  395.     end;
  396.  
  397.     // Render border
  398.     if FBorder then
  399.     begin
  400.       Bitmap.Canvas.Brush.Color := FBorderColor;
  401.       Bitmap.Canvas.FrameRect(Rect(0, 0, 16, 16));
  402.     end;
  403.  
  404.     // Assign the final bitmap
  405.     FTextBitmap.Assign(Bitmap);
  406.  
  407.   finally
  408.     Bitmap.Free;
  409.   end;
  410. end;
  411.  
  412.  
  413. procedure TTextTrayIcon.SplitText(const Strings: TList);
  414.  
  415.   function PeekedString(S: String): String;
  416.   var
  417.     P: Integer;
  418.   begin
  419.     P := Pos(#13, S);
  420.     if P = 0 then
  421.       Result := S
  422.     else
  423.       Result := Copy(S, 1, P-1);
  424.   end;
  425.  
  426. var
  427.   Substr: String;
  428.   P: Integer;
  429.   S: PChar;
  430. begin
  431.   Strings.Clear;
  432.   Substr := FText;
  433.   repeat
  434.     P := Pos(#13, Substr);
  435.     if P = 0 then
  436.     begin
  437.       S := StrNew(PChar(Substr));
  438.       Strings.Add(S);
  439.     end
  440.     else
  441.     begin
  442.       S := StrNew(PChar(PeekedString(Substr)));
  443.       Strings.Add(S);
  444.       Delete(Substr, 1, P);
  445.     end;
  446.   until P = 0;
  447. end;
  448.  
  449. end.
  450.  
  451.