Smart Mobile Studio
  • News
  • Forums
  • Download
  • Store
  • Showcases
    • Featured demos
    • The Smart Contest 2013, Round 1 – Graphics
  • Documentation
    • Get the book
    • System requirements
    • Prerequisites
    • Getting started
      • Introduction
      • Application architecture
      • The application object
      • Forms and navigation
      • Message dialogs
      • Themes and styles
    • Project types
      • Visual project
      • Game project
      • Console project
    • Layout manager
    • Networking
      • TW3HttpRequest
      • TW3JSONP
      • Loading files
  • About

Scrollcontrol, creating a better menu

Posted on 18.01.2013 by Jon Lennart Posted in Developers log, News 2 Comments

Smart Mobile Studio comes with an implementation of the standard, round cornered, iPhone menu – but while handy, there are cases where you want to display more than just some options. What we really need is a scrolling menu that can be easily adapted to display more information. It’s time to dive deeper into the RTL and create a scrolling control.

Setting up a test project

First start by creating a new visual project. Give the project a name you like, in this case i just opted for an obvious name.

new_project

Next, add a new unit to the project. You do this by right-clicking on the project node in the project manager, then clicking “add unit” from the menu. You can also add a new unit directly from the menu or the toolbar. It’s the same function.

add_unit

Now you have to reference the new unit from your mainform, you do this just like in Delphi or FreePascal by adding unit1 to the uses clause:

uses
  w3system, w3ctrls, w3components, w3forms, w3application, form1;

Now that the project is ready for some code, let’s dig into what we need to achieve our goal. What we want is a horizontal list that is scrollable. We also want this list to be isolated (in component form) so that it can be re-used in later projects. We want the list items to have all the benefits of TCustomcontrol (which includes color, font, background and style infrastructure).

Smart Mobile Studio’s RTL have a lot in common with delphi and freepascal. We are delphi developers after all, so naturally most of the principles we have worked hard to realize under javascript, are delphi centric. In delphi there is a control called TScrollingWinControl. This control is special in that it provides mechanisms for changing the position of the content, hence giving the effect of “scrolling” around a landscape.

Under Smart Mobile Studio the same mechanism is provided by TW3ScrollControl. Since the DOM (document object model, or HTML structure) is less flexible than what delphi and winapi can muster, there are ofcourse large differences, but not as much as you might think.

Items first

Right, before we dive into the details of scrolling, we start by creating the item classes. Just like in delphi we use TW3CustomControl as a base, this gives our items the full spectrum of features that we desire. To start off easy we just add support for a caption, so each item (or line) in the list can display text.

  type

  (* Generic ancestor *)
  TLSTCustomMenuItem = Class(TW3CustomControl);

  (* Array type *)
  TLSTMenuItems = Array of TLSTCustomMenuItem;

  (* Menu item *)
  TLSTMenuItem = Class(TLSTCustomMenuItem)
  private
    FCaption: String;
    procedure setCaption(Const Value:String);
  protected
    procedure InitializeObject; override;
  public
    property  Caption:String read FCaption write setCaption;
  End;

Next, the implementation

  procedure TLSTMenuItem.InitializeObject;
  begin
    inherited;
    self.Color:=clWhite;
    self.Height:=32;
  end;

  procedure TLSTMenuItem.setCaption(Const Value:String);
  Begin
    FCaption:=Value;
    innerHTML:=Value;
  end;

As you can see from the code above, the setcaption() method simply injects the caption as raw html (the innherHTML property is direct access to the content of the control’s html tag, in this case the content of a DIV tag). Using innherHTML like this is not something you want to do with more complex controls, since altering this property erases the HTML completely. But for this quick example, it will do nicely.

menu_item

The menu

Now that we have setup a rudimentary but flexible base item class, let’s dig into TW3ScrollControl. As always InitializeObject and FinalizeObject plays the role of Create and Destroy under delphi, other than that – it’s plain pascal:

  (* selection event *)
  TMenuItemSelectedEvent = procedure (Sender:TObject;Const aItem:TLSTCustomMenuItem);

  (* Our menu *)
  TLSTMenu = Class(TW3ScrollControl)
  private
    FItems:       TLSTMenuItems;
    FLastY:       Integer;
    FSelected:    TLSTMenuItem;
    FOnSelected:  TMenuItemSelectedEvent;
    Procedure     HandleTouchBegins(Sender:TObject;Info:TW3TouchData);
    Procedure     HandleTouchEnds(Sender:TObject;Info:TW3TouchData);
  protected
    Procedure     HandleItemTapped(Const aItem:TLSTMenuItem);
    procedure     InitializeObject; override;
    procedure     FinalizeObject; override;
    Procedure     ReSize;override;
  public
    Property      OnItemSelected:TMenuItemSelectedEvent
                  read FOnSelected write FOnSelected;
    Property      Items:TLSTMenuItems read FItems;
    function      Add(Const aItem:TLSTCustomMenuItem):TLSTCustomMenuItem;overload;
    function      Add:TLSTMenuItem;overload;
  End;

And finally, it’s implementation:

  procedure TLSTMenu.InitializeObject;
  Begin
    inherited;
    FItems.SetLength(0);
  end;

  procedure TLSTMenu.FinalizeObject;
  Begin
    FItems.Clear;
    inherited;
  end;

  Procedure TLSTMenu.HandleTouchBegins(Sender:TObject;Info:TW3TouchData);
  Begin
    (* remember current scroll position *)
    if (sender<>NIL)
    and (sender is TLSTMenuItem) then
    begin
      FLastY:=Content.Top;
      FSelected:=TLSTMenuItem(sender);
    end else
    Begin
      FLastY:=-1;
      FSelected:=NIL;
    end;
  end;

  Procedure TLSTMenu.HandleTouchEnds(Sender:TObject;Info:TW3TouchData);
  Begin
    (* No scrolling but touched? Its a tap *)
    if Content.Top=FLastY then
    Begin
      if (FSelected<>NIL) then
      Begin
        if (FSelected=sender) then
        begin
          HandleItemTapped(FSelected);
          FLastY:=-1;
          FSelected:=NIL;
        end;
      end;
    end;
  end;

  Procedure TLSTMenu.HandleItemTapped(Const aItem:TLSTMenuItem);
  Begin
    if assigned(FOnSelected) then
    FOnSelected(self,aItem);
  end;

  function TLSTMenu.Add:TLSTMenuItem;
  Begin
    result:=TLSTMenuItem(Add(TLSTMenuItem.Create(Content)));
    result.OnTouchBegin:=HandleTouchBegins;
    result.OnTouchEnd:=HandleTouchEnds;
  end;

  function TLSTMenu.Add(Const aItem:TLSTCustomMenuItem):TLSTCustomMenuItem;
  Begin
    if aItem<>NIL then
    Begin
      if FItems.IndexOf(aItem)<0 then
      Begin
        BeginUpdate;
        FItems.Add(aItem);
        EndUpdate;
        content.LayoutChildren;
      end;
    end;
    result:=aItem;
  end;

  Procedure TLSTMenu.ReSize;
  var
    mItem:  TLSTCustomMenuItem;
    mSize:  Integer;
    x:  Integer;
    dy: Integer;
  Begin
    inherited;
    for x:=0 to FItems.Length-1 do
    Begin
      mItem:=FItems[x];
      if mItem.visible then
      inc(mSize,mItem.height);
    end;
    Content.Height:=mSize;

    dy:=0;
    for x:=0 to FItems.Length-1 do
    Begin
      mItem:=FItems[x];
      if mItem.visible then
      Begin
        mItem.SetBounds(0,dy,width,mItem.Height);
        inc(dy,mItem.Height);
      end;
    end;
  end;

The result is a list of items that can be styled, scrolled and tapped. It can (and should) be optimized for more speed. You may also want to use a more lightweight base-control for the items (i’ll leave the tweaking to you), but basically – creating custom user controls that are re-usable amoung your projects is just as straight forward under Smart Mobile Studio as it is under Delphi.

items_browser

Using the control

To create an instance of your new user-control on your main-form, initialize it from the constructor:

procedure TForm1.InitializeObject;
var
  x:  Integer;
begin
  inherited;
  {$I 'Form1:impl'}

  FMenu:=TLSTMenu.Create(self);
  FMenu.Color:=clWhite;
  FMenu.StyleClass:='TPDFMenu'; //use this css style :)
  FMenu.Content.height:=120;
  FMenu.Content.color:=clGreen;
  FMenu.OnItemSelected:=HandleItemSelected;

  // Add dummy items
  FMenu.BeginUpdate;
  try
    for x:=1 to 20 do
    FMenu.Add.Caption:='List item #' + IntToStr(x);
  finally
    FMenu.EndUpdate;
  end;
end;

procedure TForm1.Resize;
var
  dy: Integer;
begin
  dy:=W3HeaderControl1.top + W3HeaderControl1.height + 2;
  FMenu.SetBounds(0,dy,width,height-dy);
  inherited;
end;


Download the OPP project here (zipped)

« The Smart Contest 2013 – Topic for the first round
Smart Mobile Studio v1.1 (beta-2) »

2 thoughts on “Scrollcontrol, creating a better menu”

  1. IElite says:
    19.01.2013 at 16:25

    Some things I noticed while following along with your intructions:

    1.) With the new 1.1 beta, a unit1 is already automatically created

    2.) w3components, w3graphics, w3Scroll, w3Touch need to be added to Unit 1

    3.) <> is HTML for

    4.) need to add a TW3HeaderControl to main form

    5.) need to add procedure HandleItemSelected(Sender: TObject; Const aItem:TLSTCustomMenuItem); to main form and implementation

    procedure TForm1.HandleItemSelected(Sender: TObject; Const aItem:TLSTCustomMenuItem);
    begin
    ShowMessage(‘ok’);
    end;

    however, having done all that, it compiles and runs, but it does not work. I can’t get an item to select

  2. Jon Lennart says:
    21.01.2013 at 15:56

    Added the project as a zip file, you can download it directly above 🙂

Comments are closed.

Pages

  • About
  • Feature Matrix
  • Forums
  • News
  • Release History
  • Download
  • Showcases
    • The Smart Contest 2013, Round 1 – Graphics
  • Store
  • Documentation
    • Creating your own controls
    • Debugging, exceptions and error handling
    • Differences between Delphi and Smart
    • Get the book
    • Getting started
      • Introduction
      • Local storage, session storage and global storage
      • Application architecture
      • The application object
      • Forms and navigation
      • Message dialogs
      • pmSmart Box Model
      • Themes and styles
    • Layout manager
    • Networking
      • Loading files
      • TW3HttpRequest
      • TW3JSONP
    • Prerequisites
    • Real data, talking to sqLite
    • System requirements
    • Project types
      • Visual project
      • Game project
      • Console project

Archives

  • December 2019
  • December 2018
  • November 2018
  • July 2018
  • June 2018
  • February 2018
  • September 2017
  • April 2017
  • November 2016
  • October 2016
  • September 2016
  • April 2016
  • March 2016
  • January 2016
  • October 2015
  • September 2015
  • July 2015
  • April 2015
  • January 2015
  • December 2014
  • October 2014
  • September 2014
  • August 2014
  • July 2014
  • June 2014
  • March 2014
  • February 2014
  • January 2014
  • December 2013
  • November 2013
  • October 2013
  • August 2013
  • July 2013
  • June 2013
  • May 2013
  • April 2013
  • March 2013
  • February 2013
  • January 2013
  • December 2012
  • November 2012
  • August 2012
  • July 2012
  • June 2012
  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • November 2011
  • October 2011
  • September 2011

Categories

  • Announcements (25)
  • Developers log (119)
  • Documentation (26)
  • News (104)
  • News and articles (16)

WordPress

  • Register
  • Log in
  • WordPress

Subscribe

  • Entries (RSS)
  • Comments (RSS)
© Optimale Systemer AS