Jump to content

svg icons in Toolbar


Recommended Posts

svg icons override TW3Toolbar TW3ToolbarButton

 

hello,

I needed to place svg icons as glyph into TW3ToolbarButton.

The advantages of using svg icons are:

image quality, small size, possibility to define the states (standard, active, disabled, hover) as independent layers within svg file.

 

There is only one thing that is needed to change to achieve my goal - to enable to add new buttons into FButtons array

Either using special protected procedure

  procedure  TW3Toolbar.addToButtonsArray(pButton : TW3ToolbarButton);
  begin
     FButtons.Add(pButton );
  end;
or by moving FButtons from private section into protected section.

  TW3Toolbar = class(TW3CustomControl)
  private
    fGlyphSize : integer;
    FBtnWidth: Integer;
    FBtnHeight: Integer;
    FBtnSpacing: Integer;
//    FButtons: array of TW3ToolbarButton;
  protected
    FButtons: array of TW3ToolbarButton;
   ...
  end;

(this change is also neccessary for creating of Vertical toolbar (on the base of overriding of TW3Toolbar))

 

Now to the implementation of svg icons ( I have chousen to display svg file using <object> tag- it is supported in all five browsers: IE, FF, Safari, Chrome, and Opera.

 

 

 

define TW3ImageSVG class

 

 TW3ImageSVG = class(TW3Image)
   private
     FSVGOnLoad:  TNotifyEvent;
     procedure _setOnLoad(aValue: TNotifyEvent);
   protected
     function  makeElementTagObj: THandle; override;
     procedure setSrc(Value: String);override;
     function  getSrc: String;override;
     procedure InitializeObject; override;
   published
     property SVGOnLoad: TNotifyEvent read FSVGOnLoad write _setOnLoad;
  end;

  implementation
     procedure TW3ImageSVG.InitializeObject;
     begin
       inherited InitializeObject;
     end;

     function  TW3ImageSVG.getSrc: String;
     begin
      if (Handle) then
        Result := Handle.data;
     end;

     function TW3ImageSVG.makeElementTagObj: THandle;
     begin
       asm
         var svg   = document.documentElement;
//         var svgNS = svg.namespaceURI;
//         @Result = document.createElementNS(svgNS,'object');
         @Result = document.createElement('object');
       end;
       w3_setAttrib(Result,  'type','image/svg+xml' );   
       w3_setAttrib(Result,  'data','' );   
     end;

     procedure TW3ImageSVG.setSrc(Value: String);
     var lHandle : THandle;
     begin
       if Value<>getSrc then
       begin
         lHandle := Handle;
         asm
            lH = @lHandle;
            lH.setAttribute('data', @Value);
         end;
       end;
     end;

     procedure TW3ImageSVG._setOnLoad(aValue: TNotifyEvent);
     begin
       fSVGOnLoad := aValue;
       w3_bind2(Handle, 'onload',
            if Assigned(aValue) then
               @CBOnLoad
            else @CBNoBehavior);
     end;
ok, a class for svg icons is prepared. Now is defined button TW3SVGToolbarButton that overrides TW3ToolbarButton.

 

  TW3SVGToolbarButton = class(TW3ToolbarButton)
  private
    fState    : string;
    fGlyphSVG : TW3ImageSVG;
    function getGlyph: TW3ImageSVG;
    procedure setState(pState : string; pOn : boolean);
  protected
    procedure CBClick(eventObj: JEvent); override;
    procedure InitializeObject; override;
    procedure HandleGlyphReady(Sender: TObject);
    procedure ChangeCaption(aNewCaption: String); override;
    function getSVGDown: Boolean;
    procedure setSVGDown(Value: Boolean);
    function  GetEnabled: Boolean; override;
    procedure SetEnabled(aValue: Boolean); override;
    procedure MakeGroupUp(aGroupIndex: Integer);
  public
    property State : string read fState write fState ;
    property Glyph: TW3ImageSVG read getGlyph;
  published
    property Down: Boolean read getSVGDown write setSVGDown;
    property Enabled: Boolean read GetEnabled write SetEnabled;
  end;

  implementation

    procedure TW3SVGToolbarButton.InitializeObject;  
    begin
       // to skip TW3ToolbarButton.InitializeObject
       // I cannot skip TW3ToolbarButton by other way
       asm
         TW3CustomControl.InitializeObject(Self);
       end;
       FGlyphSVG := TW3ImageSVG.Create(Self);
       FGlyphSVG.OnLoad := HandleGlyphReady;
    end;
    
    procedure TW3SVGToolbarButton.CBClick(eventObj: JEvent);
    begin
      if GroupIndex > 0 then 
      begin
        if not Down then begin
           MakeGroupUp(GroupIndex);
           Down := True;
        end
        else if AllowAllUp then
          Down := False;
      end;
      inherited CBClick(eventObj);
    end;

    procedure TW3SVGToolbarButton.ChangeCaption(aNewCaption: String);
    var
      lH : THandle;
    begin
       if aNewCaption <> '' then
       begin
         lH := Handle;
         asm
           h = @lH;
           for (var i=h.children.length-1;i>=0;i--){
             if (!((typeof h.children[i] ==='object') && 
                   (h.children[i].getAttribute('class')==='TW3ImageSVG'))){
                 h.removeChild(h.children[i]);
             }
           }
           h.insertAdjacentHTML('beforeend', '<br>'+@aNewCaption );
         end;
       end; 
    end;  

    procedure TW3SVGToolbarButton.HandleGlyphReady(Sender: TObject);
    var lHG : THandle;
        lGS : integer;
    begin
      lHG := Glyph.Handle;
      lGS := GlyphSize;
      asm
        var lhso = @lHG;
        lhso.setAttribute("style",'pointer-events:none;display:inline-block;background-clip:padding-box' );    
        lhso.setAttribute('width',@lGS + 'px');
        lhso.setAttribute('height',@lGS + 'px');
      end;
      if Pos('svgToolbarButton',StyleClass) <= 0 then
        StyleClass := StyleClass +' svgToolbarButton';       
      if Pos('TW3ToolbarButton',StyleClass) <= 0 then
        StyleClass := StyleClass +' TW3ToolbarButton';
    end;

    function TW3SVGToolbarButton.getGlyph: TW3ImageSVG;
    begin
      result := fGlyphSVG;
    end;

    function TW3SVGToolbarButton.getSVGDown: Boolean;
    begin
      Result := CSSClasses.IndexOf('ButtonDown') >= 0;
    end;

    procedure TW3SVGToolbarButton.setSVGDown(Value: Boolean);
    var lState : string;
    begin
      lState :=  BtnActiveState;
      if Value then 
      begin
        if not getDown then
        begin
          CSSClasses.Add('ButtonDown');
          setState(lState,true);
      end
    end
    else if getDown then
    begin
      CSSClasses.RemoveByName('ButtonDown');
      setState(lState,false);
    end
  end;


    // setState sets visible only the layer with id = pState 
    // the svg files are created such way to contain layer for each statethat should be displayed 
    // by different way . Id of each layer is agreed and stored also in predefined strings 
    // (f.e. BtnStandardState, BtnActiveState, BtnHoverState, BtnDisabledState) in SMS application
    // i.e. - 
    // in svg file is <g id="disabled">...</g>   and this group of paths can be accessible 
    // via BtnDisabledState='disabled' in SMS application;


    procedure TW3SVGToolbarButton.setState(pState : string; pOn : boolean);
    var lH : THandle;
    begin
      lH := Handle;
      asm
        var h = @lH;
        var btnState = h.getAttribute('btnstate');
        if (typeof btnState ==='undefined') {
            btnState = @BtnStandardState;
        }
        var lState=@pState;
        if (!(@pOn)) {
          if ((lState == @BtnDisabledState) && (btnState==@BtnActiveState)) {
             return true;
          } else {
            lState =  @BtnStandardState;
          }
        }
        if (!(h.getAttribute( 'class').indexOf('svgToolbarButton')>=0   )&&
            !(h.getAttribute( 'class').indexOf('TW3SVGToolbarButton')>=0   )) {            
          return false;
        }
        var svg;
        var svgs = h.getElementsByTagName('object');
        if ( svgs) {
          svg = svgs[0];
          if (typeof svg === 'undefined') {
            return false;
          }
        }
        if ((!lState)||(typeof lState === 'undefined')) {
          lState = @BtnStandardState;
        }

        var svgDoc = svg.contentDocument;
        var lId;
        var elb = svgDoc.getElementsByTagName('g');
        for (var i=0; i < elb.length; i++) {
          lId = elb[i].getAttribute('id');
          if ((lId==@BtnStandardState)||(lId==@BtnHoverState)||
              (lId==@BtnActiveState)|(lId==@BtnDisabledState)) {
            elb[i].style.display = (lId == lState) ? 'inline' : 'none';
          } 
         }
         h.setAttribute('btnstate', lState);
      end;
   end;

   function  TW3SVGToolbarButton.GetEnabled: Boolean;
   begin
      Result := Handle.disabled <> True
   end;


   procedure TW3SVGToolbarButton.SetEnabled(aValue: Boolean);
   var lState : string;
   begin
      inherited SetEnabled(aValue);
      asm
         @lState =  @BtnDisabledState;
      end;
      setState(lState, not aValue);
   end;
   
   procedure TW3SVGToolbarButton.MakeGroupUp(aGroupIndex: Integer);
   var btn    : TW3ToolbarButton;
       btnSVG : TW3SVGToolbarButton;
   begin
     for var i := 0 to Toolbar.ButtonCount - 1 do 
     begin
        btn := nil;
        if Toolbar[i] is TW3SVGToolbarButton then
           btnSVG := Toolbar[i] as TW3SVGToolbarButton
        else
           btn := Toolbar[i];
        if assigned(btn) then
        begin
           if (btn.GroupIndex = aGroupIndex) and btn.Down then
              btn.Down := False;
        end
       else
         if (btnSVG.GroupIndex = aGroupIndex) and btnSVG.Down then
           btnSVG.Down := False;
     end;
   end;
and override TW3Toolbar to enable both png,jpg.. icons and svg icons

 

TW3ToolbarHorizontal = class(TW3Toolbar)

  protected
    procedure InitializeObject; override;
    function getSVGButton(idx: Integer): TW3ToolbarButton;
  public
    function AddSVG: TW3SVGToolbarButton;
    function Add: TW3ToolbarButton;
    function isSVG(idx: Integer):boolean;

    property Buttons[idx: Integer]: TW3ToolbarButton read getSVGButton;default;
  end;

implementation
  procedure TW3ToolbarHorizontal.InitializeObject;
  begin
    inherited InitializeObject;
  end;

  function TW3ToolbarHorizontal.Add: TW3ToolbarButton;
  begin
    result := inherited Add;
  end;

  function TW3ToolbarHorizontal.AddSVG: TW3SVGToolbarButton;
  begin
    BeginUpdate;
    try
      Result := TW3SVGToolbarButton.Create(Self,
        lambda(Sender  ) Remove(Sender as TW3SVGToolbarButton); end);
      Result.GlyphSize := GlyphSize;
      Result.Height := ButtonHeight;
      Result.Width := ButtonWidth;

      FButtons.Add(TW3ToolbarButton(Result));
      // or addToButtonsArray(result); see above  
    finally
      AddToComponentState([csSized]);
      EndUpdate;
    end;
  end;

  function TW3ToolbarHorizontal.isSVG(idx: Integer): boolean;
  begin
    result :=  Pos('svgToolbarButton',Buttons[idx].styleClass) > 0 ;
  end;

  function TW3ToolbarHorizontal.getSVGButton(idx: Integer): TW3ToolbarButton;
  begin
    if Pos('svgToolbarButton',FButtons[idx].styleClass) > 0 then
      result := FButtons[idx] as TW3SVGToolbarButton
    else
      Result := FButtons[idx];
  end;
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...