Home > CaseBook, CSS, JavaScript, Object Pascal, OP4JS, Smart Mobile Studio, Uncategorized > A better IPhone Header for Smart Mobile Studio

A better IPhone Header for Smart Mobile Studio

Welcome to casebook

Welcome to casebook

With the introduction of the QTX effects units, we can start to make some interesting components that feel more responsive and alive (for the lack of a better word). If the world of HTML5 apps is about anything – it’s flamboyant and exciting user interfaces which not only rival, but surpass the classical components of native languages.

Since writing your own components is often regarded as a black art, something you really dont want to do which is time consuming and boring – I have decided to show just how little it takes to make a completely new IOS header component for Smart Mobile Studio. The goals for this new header is simple, namely to mimic some of the native effects introduced in iOS 5.x – which in no particular order are:

  • When either back or next buttons are set to invisible, they slide out of view
  • When a button slides out, the caption follows suit – taking up the newly available space
  • When you alter the title of the header, the text fades out before setting the new text, then fades back in
  • The title font is not longer weight-bold, but plain and shaded

Sounds very complicated right? Well, under Delphi or C++ builder it would have required more than a fair share of black magic, but under Smart Mobile Studio – which were built for this very purpose, it’s a snap.

Isolating the parts

First, let’s look at what an IOS header consists of. It’s actually a very simple piece of engineering, with only two possible buttons visible at once, a gradient background (and buttons styled to match) and a caption. Depending on your IOS version the title is either centered or left oriented. We are going to opt for a centered caption.

So, what we end up with are just 3 custom controls. That’s all it’s going to take to make our new and exciting IOS header, which will look oh-so-clever in combination with sliding forms whizzing about the place. So let’s get to work.

First, we isolate the button classes:

  TQTXBackButton = Class(TW3CustomControl)
  private
    FOnVisible: TQTXButtonVisibleEvent;
  protected
    procedure setVisible(const aValue:Boolean);reintroduce;
  public
    property  OnVisibleChange:TQTXButtonVisibleEvent
              read FOnVisible write FOnVisible;
  published
    Property  Visible:Boolean read getVisible write setVisible;
  End;

  TQTXNextButton = Class(TW3CustomControl)
  protected
    procedure setVisible(const aValue:Boolean);reintroduce;
  End;

Since we want our buttons to be more responsive when they either appear or go-away, we target the visible property on our button components. We also need to inform our toolbar that a button has appeared or disappeared, so we add an event to the mix – simply called OnVisibleChange. This way, we can create a response which deals with re-positioning the title whenever a button is moving.

Next, we need the actual header control. This will be extremely simple since all it’s gonna do is to house 3 child components (two buttons and a label). So that looks like this:

  TQTXHeaderBar = Class(TW3CustomControl)
  private
    FBackButton:  TQTXBackButton;
    FNextButton:  TQTXNextButton;
    FCaption:     TQTXHeaderTitle;
    Procedure HandleBackButtonVisibleChange(sender:TObject;aVisible:Boolean);
  protected
    Procedure Resize;override;
    Procedure InitializeObject;override;
    Procedure FinalizeObject;Override;
  public
    Property  Title:TQTXHeaderTitle read FCaption;
    Property  BackButton:TQTXBackButton read FBackButton;
    property  NextButton:TQTXNextButton read FNextButton;
  End;

Using the force

With the classes clearly defined, we can start to add some meat to our spanking new component. But first, let’s talk a bit about timing.

When you change the title of what is ultimately a label, you want it execute the change in sequence. First, you want the label to quickly fade out using a smooth effect, then you want the actual text to be altered (invisible at this point), until we quickly fade the label back into view.

This probably sounds very complicated, but it’s really the most simple thing to deal with in this task. In fact, the entire label class is no larger than this:

Procedure TQTXHeaderTitle.SetInheritedCaption(const aValue:String);
Begin
  inherited setCaption(aValue);
end;

Procedure TQTXHeaderTitle.setCaption(const aValue:String);
begin
  if  ObjectReady
  and TQTXTools.getElementInDOM(Handle) then
  Begin
    self.fxZoomOut(0.3,
      procedure ()
      Begin
        setInheritedCaption(aValue);
        self.fxZoomIn(0.3);
      end);
  end else
  inherited setCaption(aValue);
end;

You may be wondering why there is a function called “setInheritedCaption” defined. To make a long story short, you can only call inherited methods inside a normal procedure, hence we cant call “inherited setCaption()” to change the caption inside a callback procedure. The only way to solve this is to isolate it outside the setCaption() method.

Now in the setCaption() method we first check if the object is ready to be used, that the handle has become a part of the DOM (document object model). If we omit this, you stand at risk of triggering an effect before the DOM is loaded – and your app wont work. You notice that if things are not ready, we call the ancestor directly, because the text being applied is set from the constructor – so no effect can be applied.

If everything is ready and the component is visible, then we use the QTX effects to zoom the label out in 0.3 seconds. We also provide a callback event (anonymous procedure) which is executed when the effect is done. Here we change the text via setInheritedCaption() and fade the component back in. Easy as apple pie.

Next is the button(s). Like mentioned we wanted an event to let us know whenever a button has it’s visible property changed. The event handler for that presently looks like this:

 

Procedure TQTXHeaderBar.HandleBackButtonVisibleChange
          (sender:TObject;aVisible:Boolean);
Begin
  case aVisible of
  false:
    Begin
      FCaption.fxMoveTo(2, (clientHeight div 2) - (FCaption.height div 2), 0.3);
    end;
  true:
    Begin
      FCaption.fxMoveTo((clientwidth div 2) - (FCaption.width div 2),
        (clientHeight div 2) - (FCaption.height div 2), 0.3);
    end;
  end;
end;

So, whenever you alter the visibility of the back-button (button on the left of the header), we either slide the header-label center, or backwards, to occupy the space BackButton used to have.

And lest we forget, here is the code for the actual header. All it does at the moment is to house the other controls, so it’s not that advanced. But it’s a lot more responsive than the default IOS header which ship with Smart Mobile Studio.

Procedure TQTXHeaderBar.InitializeObject;
Begin
  inherited;
  FBackButton:=TQTXBackButton.Create(self);
  FBackbutton.InnerHTML:='<b>Back</b>';
  FBackbutton.Background.FromColor(clRed);
  FBackButton.OnVisibleChange:=HandleBackButtonVisibleChange;

  FNextButton:=TQTXNextButton.Create(self);

  FCaption:=TQTXHeaderTitle.Create(self);
  FCaption.Background.FromColor(clRed);
end;

Procedure TQTXHeaderBar.FinalizeObject;
Begin
  FBackbutton.free;
  FNextButton.free;
  FCaption.free;
  inherited;
end;

Procedure TQTXHeaderBar.HandleBackButtonVisibleChange
          (sender:TObject;aVisible:Boolean);
Begin
  case aVisible of
  false:
    Begin
      FCaption.fxMoveTo(2, (clientHeight div 2) - (FCaption.height div 2), 0.3);
    end;
  true:
    Begin
      FCaption.fxMoveTo((clientwidth div 2) - (FCaption.width div 2),
        (clientHeight div 2) - (FCaption.height div 2), 0.3);
    end;
  end;
end;

Procedure TQTXHeaderBar.Resize;
Begin
  inherited;
  FBackbutton.setbounds(2,2,100,24);
  FNextButton.setBounds((clientwidth-2)-100,2,100,24);

  if FBackbutton.Visible then
  FCaption.MoveTo((clientwidth div 2) - (FCaption.width div 2),
    (clientHeight div 2) - (FCaption.height div 2)) else
  Begin
    FCaption.moveto(2,
    (clientHeight div 2) - (FCaption.height div 2) );
  end;
end;

Adding some bling

Before we start working on the NextButton (right on the header), let’s have a peek at what we got so far, and let’s add some dummy events to the mix to make sure the effects are working. First, add the following to InitializeComponent:

  FCaption.OnClick:=Procedure (sender:TObject)
    Begin
      FBackButton.Visible:=not FBackbutton.Visible;
    end;

So whenever you click on the title-label, this code will toggle the visibility of our back-button. Next, let’s create an instance of our header and add another event, just for fun. So in the initializeObject on your form, create the IOS header like this:

  mTemp:=TQTXHeaderBar.Create(display);
  mTemp.height:=40;
  mTemp.BackButton.OnClick:=Procedure (sender:TObject)
    Begin
      mTemp.Title.Caption:='Testing changes';
      w3_callback( procedure ()
        Begin
          mTemp.title.caption:='And this is cool stuff';
        end,
        1000);
    end;

This means that whenever we click the back-button, we alter the caption twice after each other. Now let’s have a peek at what it looks like.

Not much to look at

Not much to look at

Meeeh.. let’s try that again, and this time with the CSS used by TW3HeaderControl

That's better

That’s better

Final touches

As you probably anticipate already, the Next-Button is more or less a clone of what we did with the first, so I wont cover that. The difference is that the label wont move so much – as resize itself to the new available size.

What we must do however, is to change the ancestor for the button classes to TW3ToolButton (as opposed to TW3CustomControl) – and basically, that’s it! Less than 100 lines of code and you have a fully effect driven clone of the IOS form header.

Now when we navigate our forms the GUI feels so much more alive and responsive. It’s just an optical effect really, but it gives that special “feel” to it which we recognize from native, Objective C components under IOS.

After thought

This example of writing components was extremely simple, but still the topics involved, like using GPU powered CSS effects is right up there with the best of code. Under native Delphi or C++ we would have to code even that, so naturally the amount of source-code we have to write under those languages would be much, much larger.

But that is also the point, namely to point out how simple, elegant and even enjoying it is to write your own HTML5 components. I know it sounds like i’m just basking in my own ideas, but Smart Mobile Studio is the only product which made me feel like I was 15 years old again, hacking away on my Amiga. Nothing is nicer than waking up, grabbing a fresh pot of coffey and sit down with SMS to code something you love working on.

As always, remember to download the Quartex library (which is needed for the effects), this can be found here: https://code.google.com/p/qtxlibrary/ (and check it out into the SMS/Libraries folder).

Here is the full source so far (the finished version will be on QTX tomorrow):

unit qtxheader;

//#############################################################################
//
//  Unit:       qtxheader.pas
//  Author:     Jon Lennart Aasenden [Cipher Diaz of Quartex]
//  Company:    Jon Lennart Aasenden LTD
//  Copyright:  Copyright Jon Lennart Aasenden, all rights reserved
//
//  About:      This unit introduces a replacement for TW3HeaderControl.
//              It uses CSS3 animation effects to slide and fade header
//              elements out of view, which makes for a more responsive
//              and living UI experience.
//
//
//  _______           _______  _______ _________ _______
// (  ___  )|\     /|(  ___  )(  ____ )\__   __/(  ____ \|\     /|
// | (   ) || )   ( || (   ) || (    )|   ) (   | (    \/( \   / )
// | |   | || |   | || (___) || (____)|   | |   | (__     \ (_) /
// | |   | || |   | ||  ___  ||     __)   | |   |  __)     ) _ (
// | | /\| || |   | || (   ) || (\ (      | |   | (       / ( ) \
// | (_\ \ || (___) || )   ( || ) \ \__   | |   | (____/\( /   \ )
// (____\/_)(_______)|/     \||/   \__/   )_(   (_______/|/     \|
//
//
//
//#############################################################################


interface

uses 
  W3System, w3components, w3graphics, w3ToolButton, w3borders,
  qtxutils,
  qtxeffects,
  qtxlabel;

{.$DEFINE USE_ANIMFRAME_SYNC}

const
CNT_ANIM_DELAY  = 0.22;

type

  TQTXButtonVisibleEvent = Procedure (sender:TObject;aVisible:Boolean);

  (* Isolate commonalities for Back/Next buttons in ancestor class *)
  TQTXHeaderButton = Class(TW3ToolButton)
  private
    FOnVisible: TQTXButtonVisibleEvent;
  public
    property  OnVisibleChange:TQTXButtonVisibleEvent
              read FOnVisible write FOnVisible;
  Protected
    Procedure setInheritedVisible(const aValue:Boolean);
  End;

  (* Back-button, slides to the left out of view *)
  TQTXBackButton = Class(TQTXHeaderButton)
  protected
    procedure setVisible(const aValue:Boolean);reintroduce;
  published
    Property  Visible:Boolean read getVisible write setVisible;
  End;

  (* Next-button, slides to the right out of view *)
  TQTXNextButton = Class(TQTXHeaderButton)
  protected
    procedure setVisible(const aValue:Boolean);reintroduce;
  published
    Property  Visible:Boolean read getVisible write setVisible;
  End;

  (* Header title label, uses fx to change text *)
  TQTXHeaderTitle = Class(TQTXLabel)
  private
    Procedure SetInheritedCaption(const aValue:String);
  protected
    procedure setCaption(const aValue:String);override;
  End;

  (* Header control, dynamically resizes and positions caption and
     button based on visibility. Otherwise identical to TW3HeaderControl *)
  TQTXHeaderBar = Class(TW3CustomControl)
  private
    FBackButton:  TQTXBackButton;
    FNextButton:  TQTXNextButton;
    FCaption:     TQTXHeaderTitle;
    FMargin:  Integer = 4;
    FFader:   Boolean = false;
    Procedure HandleBackButtonVisibleChange(sender:TObject;aVisible:Boolean);
    Procedure HandleNextButtonVisibleChange(sender:TObject;aVisible:Boolean);
  protected
    Procedure setMargin(const aValue:Integer);
    Procedure Resize;override;
    Procedure InitializeObject;override;
    Procedure FinalizeObject;Override;
  public
    Property  FadeTitle:Boolean read FFader write FFader;
    Property  Margin:Integer read FMargin write setMargin;
    Property  Title:TQTXHeaderTitle read FCaption;
    Property  BackButton:TQTXBackButton read FBackButton;
    property  NextButton:TQTXNextButton read FNextButton;
  End;

implementation

//#############################################################################
// TQTXHeaderButton
//#############################################################################

(* This method simply exposes access to the inherited version of
   setVisible. Since inherited method cannot be called from
   anonymous event-handlers, we expose it here. *)
Procedure TQTXHeaderButton.setInheritedVisible(const aValue:Boolean);
Begin
  inherited setVisible(aValue);
end;

//#############################################################################
// TQTXBackButton
//#############################################################################

procedure TQTXBackButton.setVisible(const aValue:Boolean);
var
  mParent:  TQTXHeaderBar;
  dx: Integer;
Begin
  (* Make sure object is ready and that the
     button is injected into the DOM *)
  if  ObjectReady
  and Handle.Ready
  and TQTXTools.getDocumentReady then
  Begin
    (* Make sure parent is valid *)
    if Parent<>NIL then
    Begin
      (* get parent by ref *)
      mParent:=TQTXHeaderBar(Parent);

      if aValue<>getVisible then
      begin

        case aValue of
        false:
          Begin
            if mParent.ObjectReady
            and mParent.Handle.Ready then
            Begin

              dx:=-Width;

              {$IFDEF USE_ANIMFRAME_SYNC}
              w3_requestAnimationFrame( procedure ()
              begin
              {$ENDIF}
                self.fxMoveTo(dx,top,CNT_ANIM_DELAY,
                procedure ()
                begin
                  setInheritedVisible(false);
                end);
              {$IFDEF USE_ANIMFRAME_SYNC}
              end);
              {$ENDIF}

            end else
            setInheritedVisible(false);
          end;
        True:
          Begin
            setInheritedVisible(true);
            self.MoveTo(-Width,
             (mParent.ClientHeight div 2) - self.height div 2);

            if mParent.ObjectReady
            and mParent.Handle.Ready then
            {$IFDEF USE_ANIMFRAME_SYNC}
            w3_requestAnimationFrame( procedure ()
            {$ENDIF}
            Begin
              self.fxMoveTo(mParent.margin,
              (mParent.ClientHeight div 2) - self.height div 2,CNT_ANIM_DELAY);
            {$IFDEF USE_ANIMFRAME_SYNC}
            end);
            {$ELSE}
            end;
            {$ENDIF}
          end;
        end;

        if assigned(OnVisibleChange)
        and mParent.Handle.Ready then
        OnVisibleChange(self,aValue);
      end;
    end;
  end else
  inherited setVisible(aValue);
end;

//#############################################################################
// TQTXNextButton
//#############################################################################

procedure TQTXNextButton.setVisible(const aValue:Boolean);
var
  dy: Integer;
  dx: Integer;
  mParent:  TQTXHeaderBar;
Begin
  (* Make sure element is ready and inserted into the DOM *)
  if  ObjectReady
  and TQTXTools.getDocumentReady
  and Handle.Ready then
  Begin
    (* make sure parent is valid *)
    if parent<>NIL then
    begin
      (* Make sure this represents a change in state *)
      if aValue<>getVisible then
      Begin
        (* cast parent to local variable *)
        mParent:=TQTXHeaderBar(Parent);

        case aValue of
        false:
          begin
            (* move button out to the right *)
            dy:=top;
            dx:=mParent.Width;

            {$IFDEF USE_ANIMFRAME_SYNC}
            w3_requestAnimationFrame( procedure ()
            begin
            {$ENDIF}
              self.fxMoveTo(dx,dy,CNT_ANIM_DELAY,
              procedure ()
              begin
                setInheritedVisible(false);
              end);
            {$IFDEF USE_ANIMFRAME_SYNC}
            end);
            {$ENDIF}
          end;

        true:
          begin
            (* move button in to the left *)
            setInheritedVisible(true);
            dy:=top;
            dx:=(mParent.ClientWidth - mparent.margin) - self.Width;

            {$IFDEF USE_ANIMFRAME_SYNC}
            w3_requestAnimationFrame( procedure ()
            begin
            {$ENDIF}
              self.fxMoveTo(dx,dy,CNT_ANIM_DELAY);
            {$IFDEF USE_ANIMFRAME_SYNC}
            end);
            {$ENDIF}
          end;
        end;

        if assigned(OnVisibleChange) then
        OnVisibleChange(self,aValue);
      end;
    end;
  end else
  inherited setVisible(aValue);
end;

//#############################################################################
// TQTXHeaderTitle
//#############################################################################

Procedure TQTXHeaderTitle.SetInheritedCaption(const aValue:String);
Begin
  inherited setCaption(aValue);
end;

Procedure TQTXHeaderTitle.setCaption(const aValue:String);
begin
  (* Make sure we can do this *)
  if  ObjectReady
  and TQTXTools.getDocumentReady
  and Handle.Ready then
  Begin
    (* Check valid parent *)
    if Parent<>NIL then
    Begin
      (* Use fading at all? *)
      if TQTXHeaderBar(Parent).FadeTitle then
      Begin
        {$IFDEF USE_ANIMFRAME_SYNC}
        w3_requestAnimationFrame( procedure ()
        begin
        {$ENDIF}
          self.fxFadeOut(CNT_ANIM_DELAY,
            procedure ()
            Begin
              setInheritedCaption(aValue);
              self.fxFadeIn(CNT_ANIM_DELAY);
            end);
        {$IFDEF USE_ANIMFRAME_SYNC}
        end);
        {$ENDIF}
      end else
      setInheritedCaption(aValue);
    end else
    inherited setCaption(aValue);
  end else
  inherited setCaption(aValue);
end;

//#############################################################################
// TQTXHeaderBar
//#############################################################################

Procedure TQTXHeaderBar.InitializeObject;
Begin
  inherited;

  StyleClass:='TW3HeaderControl';

  FBackButton:=TQTXBackButton.Create(self);
  FBackButton.setInheritedVisible(false);
  FBackbutton.styleClass:='TW3ToolButton';
  FBackbutton.Caption:='Back';
  FBackbutton.Height:=28;

  FNextButton:=TQTXNextButton.Create(self);
  FNextButton.setInheritedVisible(false);
  FNextButton.styleClass:='TW3ToolButton';
  FNextButton.Caption:='Next';
  FNextButton.height:=28;

  FCaption:=TQTXHeaderTitle.Create(self);
  FCaption.Autosize:=False;
  FCaption.Caption:='Welcome';
  //FCaption.handle.style['border']:='1px solid #444444';
  //FCaption.handle.style['background-color']:='rgba(255,255,255,0.3)';

  (* hook up events when element is injected in the DOM *)
  TQTXTools.ExecuteOnElementReady(Handle, procedure ()
    Begin
      (* Use update mechanism, which forces an internal
         resize when sized flag is set *)
      beginUpdate;
      try
        FBackButton.OnVisibleChange:=HandleBackButtonVisibleChange;
        FNextButton.OnVisibleChange:=HandleNextButtonVisibleChange;
        setWasMoved;
        setWasSized;
      finally
        EndUpdate;
      end;
    end);
end;

Procedure TQTXHeaderBar.FinalizeObject;
Begin
  FBackbutton.free;
  FNextButton.free;
  FCaption.free;
  inherited;
end;

Procedure TQTXHeaderBar.setMargin(const aValue:Integer);
Begin
  if aValue<>FMargin then
  begin
    (* If the element is not ready, try again
       in 100 ms *)
    if  ObjectReady
    and TQTXTools.getDocumentReady
    and Handle.Ready then
    Begin
      BeginUpdate;
      FMargin:=TInteger.EnsureRange(aValue,1,MAX_INT);
      setWasSized;
      endUpdate;
    end else
    w3_callback(procedure ()
      begin
        setMargin(aValue);
      end,100);
  end;
end;

Procedure TQTXHeaderBar.HandleNextButtonVisibleChange
          (sender:TObject;aVisible:Boolean);
var
  wd,dx:  Integer;
Begin
  case aVisible of
  false:
    begin
      wd:=clientwidth;
      dec(wd,FMargin);
      if FBackButton.Visible then
      dec(wd,FBackButton.width + FMargin);

      dx:=FMargin;
      if FBackButton.visible then
      inc(dx,FBackButton.Width + FMargin);

      if ObjectReady
      and Handle.Ready then
      Begin
        wd:=wd - FMargin;

        {$IFDEF USE_ANIMFRAME_SYNC}
        w3_requestAnimationFrame( procedure ()
        begin
        {$ENDIF}
          FCaption.fxScaleTo(dx,
            (clientHeight div 2) - FCaption.Height div 2,
            wd,
            FCaption.height,
            CNT_ANIM_DELAY,
            NIL);
        {$IFDEF USE_ANIMFRAME_SYNC}
        end);
        {$ENDIF}
      end;

    end;
  true:
    Begin

        dx:=FMargin;
        if FBackButton.visible then
        inc(dx,FBackButton.Width + FMargin);

        wd:=ClientWidth - (2 * FMargin);
        if FBackButton.Visible then
        dec(wd,FBackButton.width);
        dec(wd,FNextButton.Width);

        dec(wd,FMargin * 2);

        {$IFDEF USE_ANIMFRAME_SYNC}
        w3_requestAnimationFrame( procedure ()
        begin
        {$ENDIF}
          FCaption.fxSizeTo(wd,FCaption.Height,CNT_ANIM_DELAY,
          procedure ()
          Begin
            FCaption.fxMoveTo(dx,
            (clientHeight div 2) - FCaption.Height div 2, CNT_ANIM_DELAY);
          end);
        {$IFDEF USE_ANIMFRAME_SYNC}
        end);
        {$ENDIF}

    end;
  end;
  Resize;
end;

Procedure TQTXHeaderBar.HandleBackButtonVisibleChange
          (sender:TObject;aVisible:Boolean);
var
  dx: Integer;
  wd: Integer;
Begin

  case aVisible of
  false:
    begin
      {$IFDEF USE_ANIMFRAME_SYNC}
      w3_requestAnimationFrame( procedure ()
      begin
      {$ENDIF}
        FBackButton.fxMoveTo(-FBackButton.width,
          (clientheight div 2) - FBackButton.height div 2,
          CNT_ANIM_DELAY);
      {$IFDEF USE_ANIMFRAME_SYNC}
      end);
      {$ENDIF}
    end;
  true:
    Begin
      {$IFDEF USE_ANIMFRAME_SYNC}
      w3_requestAnimationFrame( procedure ()
      begin
      {$ENDIF}
        FBackButton.fxMoveTo(FMargin,
          (clientheight div 2) - FBackButton.height div 2,
          CNT_ANIM_DELAY);
      {$IFDEF USE_ANIMFRAME_SYNC}
      end);
      {$ENDIF}
    end;
  end;

  case aVisible of
  false:
    Begin
      wd:=ClientWidth - (FMargin * 2);

      if FNextButton.Visible then
      Begin
        dec(wd,FNextButton.Width);
        dec(wd,FMargin);
      end;

      {$IFDEF USE_ANIMFRAME_SYNC}
      w3_requestAnimationFrame( procedure ()
      begin
      {$ENDIF}
        FCaption.fxScaleTo(Fmargin,
        (clientHeight div 2) - (FCaption.height div 2),
        wd,FCaption.Height,CNT_ANIM_DELAY,NIL);
      {$IFDEF USE_ANIMFRAME_SYNC}
      end);
      {$ENDIF}
    end;
  true:
    Begin
      dx:=FMargin + BackButton.Width + FMargin;

      wd:=ClientWidth - (FMargin * 2);
      dec(wd,FBackButton.width);

      if FNextButton.visible then
      Begin
        dec(wd,FNextButton.Width);
        dec(wd,FMargin * 2);
      end else
      dec(wd,FMargin);

      {$IFDEF USE_ANIMFRAME_SYNC}
      w3_requestAnimationFrame( procedure ()
      begin
      {$ENDIF}
        FCaption.fxScaleTo(dx,
          (clientHeight div 2) - (FCaption.height div 2),
          wd,FCaption.Height,
          CNT_ANIM_DELAY,
          NIL);
      {$IFDEF USE_ANIMFRAME_SYNC}
      end);
      {$ENDIF}
    end;
  end;
end;

Procedure TQTXHeaderBar.Resize;
var
  dx: Integer;
  wd: Integer;
Begin
  inherited;
  if FBackbutton.visible then
  FBackbutton.setbounds(FMargin,
    (clientheight div 2) - FBackButton.height div 2,
    FBackButton.width,
    FBackbutton.height);

  if FNextButton.visible then
  FNextButton.setBounds((clientwidth-FMargin)-FNextButton.width,
    (clientHeight div 2) - FNextButton.height div 2,
    FNextButton.width,
    FNextButton.Height);

  dx:=FMargin;
  if FBackButton.visible then
  inc(dx,FBackButton.Width + FMargin);

  wd:=ClientWidth - FMargin;
  if FBackButton.visible then
  dec(wd,FBackButton.Width + FMargin);

  if FNextButton.visible then
  begin
    dec(wd,FNextButton.width + FMargin);
    dec(wd,FMargin);
  end else
  dec(wd,FMargin);

  FCaption.SetBounds(dx,
     (clientHeight div 2) - (FCaption.height div 2),
     wd,FCaption.Height);
end;

end.

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: