home *** CD-ROM | disk | FTP | other *** search
/ Chip 2003 November / Chip_2003-11_cd1.bin / program / delphi / kompon / DIHtmlLabel.exe / Source / DIHtmlLabel.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2003-07-23  |  18.3 KB  |  606 lines

  1. unit DIHtmlLabel;
  2.  
  3. {$I DI.inc}
  4.  
  5. interface
  6.  
  7. uses
  8.   Windows, Messages, Classes, Graphics, Controls,
  9.  
  10.   DIHtmlRenderer;
  11.  
  12. const
  13.   DIHTMLLABEL_DEFAULT_AUTO_HEIGHT = True;
  14.   DIHTMLLABEL_DEFAULT_HOT_LINKS = True;
  15.   DIHTMLLABEL_DEFAULT_LINK_COLOR = clBlue;
  16.   DIHTMLLABEL_DEFAULT_LINK_COLOR_CLICKED = clRed;
  17.   DIHTMLLABEL_DEFAULT_LINK_COLOR_HOT = clPurple;
  18.   DIHTMLLABEL_DEFAULT_LINK_STYLE = [fsUnderline];
  19.  
  20. type
  21.   TDICustomHtmlLabel = class;
  22.  
  23.   TLinkClickEvent = procedure(
  24.     const Sender: TObject;
  25.     const LinkHref: WideString;
  26.     const LinkText: WideString) of object;
  27.  
  28.   TDynamicTagInitEvent = procedure(
  29.     const Sender: TObject;
  30.     const ID: WideString;
  31.     out Source: AnsiString) of object;
  32.  
  33.   { ---------------------------------------------------------------------------- }
  34.  
  35.   // TDICustomHtmlLabel = class(TGraphicControl, IDynamicNodeHandler)
  36.   TDICustomHtmlLabel = class(TCustomControl, IDynamicNodeHandler)
  37.   private
  38.     FCaption: AnsiString;
  39.     FRenderer: TDIHtmlRenderer;
  40.     FActiveLinkNode: TLinkNode;
  41.     FHotLinks: Boolean;
  42.     FRect: TRect;
  43.     FAutoHeight: Boolean;
  44.     FMarginWidth: Integer;
  45.     FMarginHeight: Integer;
  46.     FOriginalCursor: TCursor;
  47.     FOnLinkClick: TLinkClickEvent;
  48.     FOnDynamicTagInit: TDynamicTagInitEvent;
  49.     FOnAfterPaint: TNotifyEvent;
  50.     procedure SetTransparent(const Value: Boolean);
  51.     function GetLinkColor: TColor;
  52.     function GetLinkStyle: TFontStyles;
  53.     procedure SetLinkColor(const Value: TColor);
  54.     procedure SetLinkStyle(const Value: TFontStyles);
  55.     procedure SynchronizeRootAndFont;
  56.     function GetLinkColorClicked: TColor;
  57.     procedure SetLinkColorClicked(const Value: TColor);
  58.     function GetLinkColorHot: TColor;
  59.     procedure SetLinkColorHot(const Value: TColor);
  60.     procedure ActivateLinkNodeAtPos(const p: TPoint; State: TLinkState);
  61.     procedure DeactivateActiveLinkNode;
  62.     procedure HandleDynamicNode(const Node: TDynamicNode; out Source: AnsiString);
  63.     procedure SetCaption(const Value: AnsiString);
  64.     function GetTransparent: Boolean;
  65.     function IsActiveLinkNodeClicked: Boolean;
  66.     procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  67.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  68.     procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  69.     procedure SetAutoHeight(const Value: Boolean);
  70.     procedure SetMarginHeight(const Value: Integer);
  71.     procedure SetMarginWidth(const Value: Integer);
  72.     procedure SetOffsetY(const Value: Integer);
  73.     function GetOffsetY: Integer;
  74.     function GetTextHeight: Integer;
  75.   protected
  76.     FNodeTree: TNodeTree;
  77.     procedure Paint; override;
  78.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; x, y: Integer); override;
  79.     procedure MouseMove(Shift: TShiftState; x, y: Integer); override;
  80.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; x, y: Integer); override;
  81.     procedure Resize; override;
  82.     procedure DoLinkClicked(const LinkHref, LinkText: WideString); virtual;
  83.     procedure DoDynamicTagInit(const AID: WideString; out Source: AnsiString); virtual;
  84.     property Renderer: TDIHtmlRenderer read FRenderer;
  85.  
  86.     property OnAfterPaint: TNotifyEvent read FOnAfterPaint write FOnAfterPaint;
  87.     property OnDynamicTagInit: TDynamicTagInitEvent read FOnDynamicTagInit write FOnDynamicTagInit;
  88.     property OnLinkClick: TLinkClickEvent read FOnLinkClick write FOnLinkClick;
  89.  
  90.     property Caption: AnsiString read FCaption write SetCaption;
  91.     property Transparent: Boolean read GetTransparent write SetTransparent default False;
  92.     property LinkColor: TColor read GetLinkColor write SetLinkColor default DIHTMLLABEL_DEFAULT_LINK_COLOR;
  93.     property LinkColorClicked: TColor read GetLinkColorClicked write SetLinkColorClicked default DIHTMLLABEL_DEFAULT_LINK_COLOR_CLICKED;
  94.     property LinkColorHot: TColor read GetLinkColorHot write SetLinkColorHot default DIHTMLLABEL_DEFAULT_LINK_COLOR_HOT;
  95.     property LinkStyle: TFontStyles read GetLinkStyle write SetLinkStyle default DIHTMLLABEL_DEFAULT_LINK_STYLE;
  96.     property HotLinks: Boolean read FHotLinks write FHotLinks default DIHTMLLABEL_DEFAULT_HOT_LINKS;
  97.     property AutoHeight: Boolean read FAutoHeight write SetAutoHeight default DIHTMLLABEL_DEFAULT_AUTO_HEIGHT;
  98.     property MarginWidth: Integer read FMarginWidth write SetMarginWidth default 0;
  99.     property MarginHeight: Integer read FMarginHeight write SetMarginHeight default 0;
  100.     property OffsetY: Integer read GetOffsetY write SetOffsetY default 0;
  101.     property TextHeight: Integer read GetTextHeight;
  102.   public
  103.     constructor Create(AOwner: TComponent); override;
  104.     destructor Destroy; override;
  105.     function GetDynamicTagContents(const DynamicTagID: WideString): WideString;
  106.     procedure Loaded; override;
  107.     property NodeTree: TNodeTree read FNodeTree;
  108.     procedure UpdateDynamicTag(const AID: WideString; const Source: AnsiString);
  109.   end;
  110.  
  111.   { ---------------------------------------------------------------------------- }
  112.  
  113.   TDIHtmlLabel = class(TDICustomHtmlLabel)
  114.   public
  115.     property TextHeight;
  116.   published
  117.     property Align;
  118.     property Anchors;
  119.     property AutoHeight;
  120.     property Caption;
  121.     property Color;
  122.     property Constraints;
  123.     property DragCursor;
  124.     property DragMode;
  125.     property Font;
  126.     property HotLinks;
  127.     property LinkColor;
  128.     property LinkColorClicked;
  129.     property LinkColorHot;
  130.     property LinkStyle;
  131.     property MarginHeight;
  132.     property MarginWidth;
  133.     property OffsetY;
  134.     property ParentColor;
  135.     property ParentFont;
  136.     property ParentShowHint;
  137.     property PopupMenu;
  138.     property ShowHint;
  139.     property Transparent;
  140.     property Visible;
  141.     property OnAfterPaint;
  142.     property OnClick;
  143.     property OnDblClick;
  144.     property OnDragDrop;
  145.     property OnDynamicTagInit;
  146.     property OnDragOver;
  147.     property OnLinkClick;
  148.     property OnStartDrag;
  149.     property OnEndDrag;
  150.     property OnMouseUp;
  151.     property OnMouseDown;
  152.     property OnMouseMove;
  153.   end;
  154.  
  155. implementation
  156.  
  157. uses
  158.   Forms;
  159.  
  160. { ---------------------------------------------------------------------------- }
  161. { TDICustomHtmlLabel
  162. { ---------------------------------------------------------------------------- }
  163.  
  164. constructor TDICustomHtmlLabel.Create(AOwner: TComponent);
  165. begin
  166.   inherited Create(AOwner);
  167.   ControlStyle := ControlStyle + [csOpaque, csReplicatable];
  168.   Width := 65;
  169.   Height := 17;
  170.  
  171.   FAutoHeight := DIHTMLLABEL_DEFAULT_AUTO_HEIGHT;
  172.   FHotLinks := DIHTMLLABEL_DEFAULT_HOT_LINKS;
  173.  
  174.   FNodeTree := TNodeTree.Create;
  175.  
  176.   FRenderer := TDIHtmlRenderer.Create; ;
  177.   FRenderer.LinkColor := DIHTMLLABEL_DEFAULT_LINK_COLOR;
  178.   FRenderer.LinkColorClicked := DIHTMLLABEL_DEFAULT_LINK_COLOR_CLICKED;
  179.   FRenderer.LinkColorHot := DIHTMLLABEL_DEFAULT_LINK_COLOR_HOT;
  180.   FRenderer.LinkStyle := DIHTMLLABEL_DEFAULT_LINK_STYLE;
  181. end;
  182.  
  183. { ---------------------------------------------------------------------------- }
  184.  
  185. destructor TDICustomHtmlLabel.Destroy;
  186. begin
  187.   FRenderer.Free;
  188.   FNodeTree.Free;
  189.   inherited Destroy;
  190. end;
  191.  
  192. { ---------------------------------------------------------------------------- }
  193.  
  194. procedure TDICustomHtmlLabel.ActivateLinkNodeAtPos(const p: TPoint; State: TLinkState);
  195. var
  196.   NodeAtPoint: TLinkNode;
  197.  
  198.   function IsNewNode: Boolean;
  199.   begin
  200.     { We must only redraw the TLinkNode if it either isn't the same as the
  201.       currently active TLinkNode (FActiveLinkNode), or if we're trying to change
  202.       the state (that is, alter the color). }
  203.     Result := (FActiveLinkNode <> NodeAtPoint);
  204.     if not Result and Assigned(FActiveLinkNode) then
  205.       Result := FActiveLinkNode.State <> State;
  206.   end;
  207.  
  208. begin
  209.   NodeAtPoint := TLinkNode(FNodeTree.GetNodeAtPointOfClass(p, TLinkNode));
  210.   if (NodeAtPoint <> nil) and IsNewNode then
  211.     begin
  212.       DeactivateActiveLinkNode;
  213.       NodeAtPoint.State := State;
  214.       FActiveLinkNode := NodeAtPoint;
  215.       FRenderer.RenderNode(Canvas, FRect, NodeAtPoint);
  216.     end;
  217. end;
  218.  
  219. { ---------------------------------------------------------------------------- }
  220.  
  221. procedure TDICustomHtmlLabel.CMFontChanged(var Message: TMessage);
  222. begin
  223.   inherited;
  224.   SynchronizeRootAndFont;
  225.   FNodeTree.ClearWordInfos;
  226.   Invalidate;
  227. end;
  228.  
  229. { ---------------------------------------------------------------------------- }
  230.  
  231. procedure TDICustomHtmlLabel.CMMouseLeave(var Message: TMessage);
  232. begin
  233.   inherited;
  234.   if FHotLinks and not IsActiveLinkNodeClicked then
  235.     DeactivateActiveLinkNode;
  236. end;
  237.  
  238. { ---------------------------------------------------------------------------- }
  239.  
  240. procedure TDICustomHtmlLabel.CMTextChanged(var Message: TMessage);
  241. begin
  242.   inherited;
  243.   Invalidate;
  244. end;
  245.  
  246. { ---------------------------------------------------------------------------- }
  247.  
  248. procedure TDICustomHtmlLabel.DeactivateActiveLinkNode;
  249. begin
  250.   if FActiveLinkNode <> nil then
  251.     try
  252.       FActiveLinkNode.State := lsNormal;
  253.       FRenderer.RenderNode(Canvas, FRect, FActiveLinkNode);
  254.     finally
  255.       FActiveLinkNode := nil;
  256.     end;
  257. end;
  258.  
  259. { ---------------------------------------------------------------------------- }
  260.  
  261. procedure TDICustomHtmlLabel.DoDynamicTagInit(const AID: WideString; out Source: AnsiString);
  262. begin
  263.   if Assigned(FOnDynamicTagInit) then FOnDynamicTagInit(Self, AID, Source);
  264. end;
  265.  
  266. { ---------------------------------------------------------------------------- }
  267.  
  268. procedure TDICustomHtmlLabel.DoLinkClicked(const LinkHref, LinkText: WideString);
  269. begin
  270.   if Assigned(FOnLinkClick) then
  271.     FOnLinkClick(Self, LinkHref, LinkText);
  272. end;
  273.  
  274. { ---------------------------------------------------------------------------- }
  275.  
  276. function TDICustomHtmlLabel.GetDynamicTagContents(const DynamicTagID: WideString): WideString;
  277. begin
  278.   Result := FNodeTree.GetDynamicTagText(DynamicTagID);
  279. end;
  280.  
  281. { ---------------------------------------------------------------------------- }
  282.  
  283. function TDICustomHtmlLabel.GetLinkColor: TColor;
  284. begin
  285.   Result := FRenderer.LinkColor;
  286. end;
  287.  
  288. { ---------------------------------------------------------------------------- }
  289.  
  290. function TDICustomHtmlLabel.GetLinkColorClicked: TColor;
  291. begin
  292.   Result := FRenderer.LinkColorClicked;
  293. end;
  294.  
  295. { ---------------------------------------------------------------------------- }
  296.  
  297. function TDICustomHtmlLabel.GetLinkColorHot: TColor;
  298. begin
  299.   Result := FRenderer.LinkColorHot;
  300. end;
  301.  
  302. { ---------------------------------------------------------------------------- }
  303.  
  304. function TDICustomHtmlLabel.GetLinkStyle: TFontStyles;
  305. begin
  306.   Result := FRenderer.LinkStyle;
  307. end;
  308.  
  309. { ---------------------------------------------------------------------------- }
  310.  
  311. function TDICustomHtmlLabel.GetTransparent: Boolean;
  312. begin
  313.   Result := not (csOpaque in ControlStyle);
  314. end;
  315.  
  316. { ---------------------------------------------------------------------------- }
  317.  
  318. procedure TDICustomHtmlLabel.HandleDynamicNode(const Node: TDynamicNode; out Source: AnsiString);
  319. begin
  320.   if Node <> nil then
  321.     DoDynamicTagInit(Node.ID, Source)
  322.   else
  323.     Source := '';
  324. end;
  325.  
  326. { ---------------------------------------------------------------------------- }
  327.  
  328. function TDICustomHtmlLabel.IsActiveLinkNodeClicked: Boolean;
  329. begin
  330.   Result := FActiveLinkNode <> nil;
  331.   if Result then
  332.     Result := FActiveLinkNode.State = lsClicked;
  333. end;
  334.  
  335. { ---------------------------------------------------------------------------- }
  336.  
  337. procedure TDICustomHtmlLabel.Loaded;
  338. begin
  339.   inherited;
  340.   FOriginalCursor := Cursor;
  341.   Resize;
  342. end;
  343.  
  344. { ---------------------------------------------------------------------------- }
  345.  
  346. procedure TDICustomHtmlLabel.MouseDown(Button: TMouseButton; Shift: TShiftState; x, y: Integer);
  347. begin
  348.   inherited;
  349.   ActivateLinkNodeAtPos(Point(x, y), lsClicked);
  350. end;
  351.  
  352. { ---------------------------------------------------------------------------- }
  353.  
  354. procedure TDICustomHtmlLabel.MouseMove(Shift: TShiftState; x, y: Integer);
  355. begin
  356.   inherited;
  357.   if FNodeTree.IsPointInNodeClass(Point(x, y), TLinkNode) then
  358.     begin
  359.       Cursor := crHandPoint;
  360.       if FHotLinks and not IsActiveLinkNodeClicked then
  361.         ActivateLinkNodeAtPos(Point(x, y), lsHot);
  362.     end
  363.   else
  364.     begin
  365.       Cursor := FOriginalCursor;
  366.       if FHotLinks and not IsActiveLinkNodeClicked then
  367.         DeactivateActiveLinkNode;
  368.     end;
  369. end;
  370.  
  371. { ---------------------------------------------------------------------------- }
  372.  
  373. procedure TDICustomHtmlLabel.MouseUp(Button: TMouseButton; Shift: TShiftState; x, y: Integer);
  374. var
  375.   NodeAtPoint: TLinkNode;
  376. begin
  377.   inherited;
  378.   if FNodeTree.IsPointInNodeClass(Point(x, y), TLinkNode) then
  379.     begin
  380.       NodeAtPoint := FNodeTree.GetNodeAtPointOfClass(Point(x, y), TLinkNode) as TLinkNode;
  381.       if Assigned(NodeAtPoint) then
  382.         DoLinkClicked(NodeAtPoint.Href, NodeAtPoint.Text);
  383.     end;
  384.  
  385.   DeactivateActiveLinkNode;
  386. end;
  387.  
  388. { ---------------------------------------------------------------------------- }
  389.  
  390. procedure TDICustomHtmlLabel.Paint;
  391. begin
  392.   inherited;
  393.   if Assigned(FNodeTree) then
  394.     begin
  395.       with Canvas do
  396.         begin
  397.           if not Transparent then
  398.             begin
  399.               Brush.Color := Color;
  400.               Brush.Style := bsSolid;
  401.               FillRect(ClientRect);
  402.             end;
  403.  
  404.           Brush.Style := bsClear;
  405.         end;
  406.  
  407.       Canvas.Font := Font;
  408.       FRenderer.RenderTree(Canvas, FRect, FNodeTree);
  409.  
  410.       if FAutoHeight and (Align in [alNone, alTop, alBottom]) then
  411.         ClientHeight := FRenderer.TextHeight + FMarginHeight;
  412.     end;
  413.   if Assigned(FOnAfterPaint) then
  414.     FOnAfterPaint(Self);
  415. end;
  416.  
  417. { ---------------------------------------------------------------------------- }
  418.  
  419. procedure TDICustomHtmlLabel.Resize;
  420. begin
  421.   inherited;
  422.   FRect := Rect(ClientRect.Left + FMarginWidth, ClientRect.Top + FMarginHeight,
  423.     ClientRect.Right - FMarginWidth, ClientRect.Bottom);
  424. end;
  425.  
  426. { ---------------------------------------------------------------------------- }
  427.  
  428. procedure TDICustomHtmlLabel.SetAutoHeight(const Value: Boolean);
  429. begin
  430.   if FAutoHeight <> Value then
  431.     begin
  432.       FAutoHeight := Value;
  433.       Invalidate;
  434.     end;
  435. end;
  436.  
  437. { ---------------------------------------------------------------------------- }
  438.  
  439. procedure TDICustomHtmlLabel.SetCaption(const Value: AnsiString);
  440. var
  441.   Parser: TDefaultParser;
  442. begin
  443.   if FCaption <> Value then
  444.     begin
  445.       FCaption := Value;
  446.  
  447.       FActiveLinkNode := nil; // We're about to free the tree containing the node it's pointing to
  448.       FNodeTree.Free;
  449.  
  450.       Parser := TDefaultParser.Create;
  451.       Parser.DynamicNodeHandler := Self;
  452.       FNodeTree := Parser.Parse(Value);
  453.       Parser.Free;
  454.  
  455.       SynchronizeRootAndFont;
  456.       Invalidate;
  457.     end;
  458. end;
  459.  
  460. { ---------------------------------------------------------------------------- }
  461.  
  462. procedure TDICustomHtmlLabel.SetLinkColor(const Value: TColor);
  463. begin
  464.   if FRenderer.LinkColor <> Value then
  465.     begin
  466.       FRenderer.LinkColor := Value;
  467.       Invalidate;
  468.     end;
  469. end;
  470.  
  471. { ---------------------------------------------------------------------------- }
  472.  
  473. procedure TDICustomHtmlLabel.SetLinkColorClicked(const Value: TColor);
  474. begin
  475.   if FRenderer.LinkColorClicked <> Value then
  476.     begin
  477.       FRenderer.LinkColorClicked := Value;
  478.       Invalidate;
  479.     end;
  480. end;
  481.  
  482. { ---------------------------------------------------------------------------- }
  483.  
  484. procedure TDICustomHtmlLabel.SetLinkColorHot(const Value: TColor);
  485. begin
  486.   if FRenderer.LinkColorHot <> Value then
  487.     begin
  488.       FRenderer.LinkColorHot := Value;
  489.       Invalidate;
  490.     end;
  491. end;
  492.  
  493. { ---------------------------------------------------------------------------- }
  494.  
  495. procedure TDICustomHtmlLabel.SetLinkStyle(const Value: TFontStyles);
  496. begin
  497.   if FRenderer.LinkStyle <> Value then
  498.     begin
  499.       FRenderer.LinkStyle := Value;
  500.       Invalidate;
  501.     end;
  502. end;
  503.  
  504. { ---------------------------------------------------------------------------- }
  505.  
  506. procedure TDICustomHtmlLabel.SetMarginHeight(const Value: Integer);
  507. begin
  508.   if FMarginHeight <> Value then
  509.     begin
  510.       FMarginHeight := Value;
  511.       Resize;
  512.       Invalidate;
  513.     end;
  514. end;
  515.  
  516. { ---------------------------------------------------------------------------- }
  517.  
  518. procedure TDICustomHtmlLabel.SetMarginWidth(const Value: Integer);
  519. begin
  520.   if FMarginWidth <> Value then
  521.     begin
  522.       FMarginWidth := Value;
  523.       Resize;
  524.       Invalidate;
  525.     end;
  526. end;
  527.  
  528. { ---------------------------------------------------------------------------- }
  529.  
  530. procedure TDICustomHtmlLabel.SetTransparent(const Value: Boolean);
  531. begin
  532.   if Transparent <> Value then
  533.     begin
  534.       if Value then
  535.         ControlStyle := ControlStyle - [csOpaque]
  536.       else
  537.         ControlStyle := ControlStyle + [csOpaque];
  538.       Invalidate;
  539.     end;
  540. end;
  541.  
  542. { ---------------------------------------------------------------------------- }
  543.  
  544. procedure TDICustomHtmlLabel.SynchronizeRootAndFont;
  545. begin
  546.   if Assigned(FNodeTree) then
  547.     with FNodeTree.Root do
  548.       begin
  549.         Styles := Font.Style;
  550.         Color := Font.Color;
  551.       end;
  552. end;
  553.  
  554. { ---------------------------------------------------------------------------- }
  555.  
  556. procedure TDICustomHtmlLabel.UpdateDynamicTag(const AID: WideString; const Source: AnsiString);
  557. var
  558.   NodeEnum: TTopLevelNodeEnumerator;
  559.   Parser: TDefaultParser;
  560.   Node: TDynamicNode;
  561. begin
  562.   NodeEnum := TTopLevelNodeEnumerator.Create;
  563.   NodeEnum.RootNode := FNodeTree.Root;
  564.   NodeEnum.NodeClass := TDynamicNode;
  565.  
  566.   Node := TDynamicNode(NodeEnum.NextNode);
  567.   while (Node <> nil) and (Node.ID <> AID) do
  568.     Node := TDynamicNode(NodeEnum.NextNode);
  569.   NodeEnum.Free;
  570.  
  571.   if Node <> nil then
  572.     begin
  573.       Parser := TDefaultParser.Create;
  574.       Parser.AddSourceTreeToDynamicNode(Node, Source);
  575.       Paint;
  576.     end;
  577. end;
  578.  
  579. { ---------------------------------------------------------------------------- }
  580.  
  581. function TDICustomHtmlLabel.GetOffsetY: Integer;
  582. begin
  583.   Result := FRenderer.TextOffsetY;
  584. end;
  585.  
  586. { ---------------------------------------------------------------------------- }
  587.  
  588. procedure TDICustomHtmlLabel.SetOffsetY(const Value: Integer);
  589. begin
  590.   if FRenderer.TextOffsetY <> Value then
  591.     begin
  592.       FRenderer.TextOffsetY := Value;
  593.       Invalidate;
  594.     end;
  595. end;
  596.  
  597. { ---------------------------------------------------------------------------- }
  598.  
  599. function TDICustomHtmlLabel.GetTextHeight: Integer;
  600. begin
  601.   Result := FRenderer.TextHeight;
  602. end;
  603.  
  604. end.
  605.  
  606.