Home > Object Pascal, OP4JS, Smart Mobile Studio > Sneak peek at the new Smart RTL – Part 2

Sneak peek at the new Smart RTL – Part 2

November 7, 2016 Leave a comment Go to comments

If you missed the last sneak peek, click here to catch the first part.

In the previous post we had a look at a handful of the new features of the upcoming RTL. This time we will look at a couple of more. There is quite a few to write about, so I could probably do 10 of these “peek posts” to be honest.

Fine tune control

Support for CreationFlags is something we finally got into the RTL. If you have created your own controls using Delphi or Lazarus you are probably familiar with them? In short, it’s a set of special values that defines how a control should behave. And they are very important.

CreationFlags is defined as a class function, so this is a method you override when defining your own controls. It looks like this:

class function TW3TagObj.CreationFlags:TW3CreationFlags;
begin
  result := [
    cfAllowSelection,
    cfSupportAdjustment,
    cfReportChildAddition,
    cfReportChildRemoval,
    cfReportMovement,
    cfReportReSize
    ];
end;

The flags themselves are defined as such:

  TW3CreationFlags = set of
    (
    cfIgnoreReadyState,     // Ignore waiting for readystate
    cfSupportAdjustment,    // Controls requires boxing adjustment (default!)
    cfReportChildAddition,  // Dont call ChildAdded() on element insertion
    cfReportChildRemoval,   // Dont call ChildRemoved() on element removal
    cfReportMovement,       // Report movements? Managed call to Moved()
    cfReportResize,         // Report resize? Manages call to Resize()
    cfAllowSelection,       // Allow for text selection
    cfKeyCapture            // assign tabindex, causing the control to issue key and focus events
    );

So what is the big deal? Well, lets say you want keyboard support for a control (and under Smart Pascal you are expected to write your own controls all the time, it’s a part of how you work with the RTL. Just like C# expects you to inherit and implement your own classes) — now previously you could only capture input from traditional input controls. Like a Textbox or Memo. Which is quite limiting to say the least.

Now however, all you have to do to get keyboard support is to add cfKeyCapture and the OnKeyPress (and associated events) will fire, no matter if the control is based on a DIV (standard) or some other HTML element.

win8cat

The Windows 10 category header is fully animated. It can also be navigated using the arrow keys.

As you can see from the list of flags you can now disable some of the inner mechanics for a control if you don’t need it. Things like automatic calls to Resize() whenever the width or height is changed, the call to Moved() whenever a control is (drumroll) moved can also be disabled.

If you are wondering why this should be good news then consider this: Imagine you are implementing a really cool DB grid in Smart Pascal. One that needs to display 10.000 records just as fast as 100 records. When dealing with presentation of this amount of items, every call your code makes count (!) In fact, fast and responsive grids has been something of a holy grail for JavaScript over the years. Its only in the past 3 years we are starting to see high quality grids that is en-par with their native counterparts (like Developer Express, TMS and others).

Just like in Delphi or C# there are functions that the average developer don’t really care about or have to know to use the product – so its is with Smart. There will be functions that makes little sense to the average developer, but who are super important to people who make and sell components.

Ready, set, Action!

The core unit for visual controls in the RTL, SmartCL.Components.pas, have a number of additions, but the most important one is without a doubt the support for Actions. A feature of Delphi that has distinguished it from other RAD tools for decades (C# only recently got support for this, believe it or not).

But Actions is not so simple as you may think. It’s not just a matter of adding an Action property to our control-base. Actions also have to be reflected in the IDE, and it brings with it another feature that has been on our wish-list for a while now: namely non-visible controls!

  TW3TagObj = class(TW3CustomWidget, IW3ActionSubscriber)
  private
    FOwner:     TControlHandle;
    FHandle:    TControlHandle;
    FTagId:     string;
    FUpdating:  integer;
    FAttributes: TW3ElementAttributes;
    FComponentState:  TComponentState;

    {$IFDEF USE_ACTIONS}
    FAction:  TW3Action;
    function GetActionObject: TW3Action;
    procedure SetActionObject(const ActionObj: TW3Action);

    (* Implements:: IW3ActionSubscriber interface *)
    procedure RegisterAction(const Action: TW3Action);
    procedure UnRegisterAction(const Action: TW3Action);
    procedure ActionStateChanged(const Action: TW3Action);
    {$ENDIF}

Notice how TW3TagObj suddenly have a new ancestor? It used to inherit directly from TObject, but now suddenly it inherits from TW3CustomWidget (name is not yet carved in stone, we may call it something else since “widget” is often used for visual elements under QT C++). So indeed — non visual, drag & drop components is finally in the making.

But rather than cluttering up your forms we will go for a visual-studio like drop-zone at the bottom of your forms. This does a world of good for the size of your binaries. First of all, had we moved non-visual controls up to TComponent like Delphi and Lazarus do, it would mean a lot of useless code would be involved. TW3Component is designed to deal with child elements, child elements that have handles or map to the document object model. To avoid bloat we have introduced non-visual code earlier in the inheritance chain. Most non visual controls dont create or map to handles, nor do they create visual elements at all, so why have all that extra code attached to it?

GPU power

As you probably know, modern browser engines like Webkit are GPU powered. This means that a DIV or PRE tag (which our controls create when you call the constructor) can be marked for hardware acceleration. This was earlier a manual thing, something you would add to the stylesheet of your application.

Well, you can now call the method TW3TagObj.SetInitialTransformationStyles() in your constructor, and the control is marked for GPU rendering. Just remember: to much of a good thing is not cool. So think about what you accelerate. You would for example, not call this function on a DB grid, but rather on the rows being displayed.

Controllers

This is a new concept for Smart. A controller is a class that allows you to add extra features to a component indirectly (by proxy. Even existing controls). A controller is typically small and aims at delivering specialized features. Stuff that would be overkill to place in a TW3Widget (non visual control), yet to large for a utility unit. Since its all about control over something, we just let it name itself.

The base-class for a controller is very lightweight:

  TW3Controller = class(TW3OwnedObject, IW3Controller, IW3ControllerEventAccess)
  private
    (* IW3Controller Implementation *)
    function GetAttachedEventHandler:TW3ControllerAttachedEvent;
    procedure SetAttachedEventHandler(const EventHandler: TW3ControllerAttachedEvent);
    function GetDetachedEventHandler:TW3ControllerDetachedEvent;
    procedure SetDetachedEventHandler(const EventHandler: TW3ControllerDetachedEvent);
  protected
    function  QueryAttachment:Boolean;virtual;abstract;
    procedure DoAttach;virtual;
    procedure DoDetach;virtual;

    property OnAttached:TW3ControllerAttachedEvent;
    property OnDetached:TW3ControllerDetachedEvent;
  public
    Property  AutoDetach:Boolean;
    property  Attached:Boolean read QueryAttachment;
    procedure Attach(const AOwner: TObject);virtual;
    procedure Detach;virtual;

    constructor Create(AOwner: TObject);override;
    destructor Destroy;Override;
  end;

As of writing we have these controllers implemented:

  • Edge Sense
  • Swipe
  • Attributes
  • PlainScroll
  • MomentumScroll
  • iScroll

Edge-sense adds code to sensing when the mousepointer is within range of a controls edge. This controller is what you would use to deal with live resizing. It’s actually used in our new DB grid to deal with resize of column headers. As a controller it can be created on the fly and just attached to any custom control. It targets the handle and works with it from the JavaScript side of things, so it doesn’t interfere or override any code in the control it targets.

Our swipe-controller is a simple way to deal with horizontal or vertical swipes. The most common gestures on mobile devices. So if you are displaying information that can be swiped – like pages in a book, or scrolling in a new item — then this is a quick and easy solution. The alternative is to deal with gestures through events. But if all you need is swipe left/right or top/bottom (or both) – this controller is the ticket.

The scroll controllers are very cool. Let’s say you have a normal listbox right. Well, now you can chose what type of scrolling that listbox should use. If you want vanilla scrolling without any momentum, then you just attach a TW3PlainScrollController and it will scroll without any bouncing or acceleration. If you want acceleration, you create a TW3MomentumScrollController and attach that. Then it will scroll like an “iPhone list” (more or less). We have also wrapped iScroll, which is a JS library that emulates iPhone scrolling down to the letter (and then some).

Attributes allows you to store information in a tag. When you create a visual control, the RTL creates a tag via JavaScript. Traditionally these tags can only contain attributes they support. A while back this was extended so you can now add as many attributes as you like to a tag, providing it starts with “db-“. What is the use for this you ponder? Well let’s say you need some way of marking a control as active, or being processed. Rather than having to keep track of that state in a dictionary or array — you can now just mark the html tag directly.

We use this in our SmartCL.effects.pas unit. When you apply an effect to a control, the control is marked as “busy” while the effect is running. That way you don’t accidentally execute more than one effect on the same control (which would have unpredictable results). Instead the framework will cache up the effects you have applied, and execute them in sequence. And all of it is very efficient since the info is stored in the tag itself rather than in a JavaScript array of dictionary.

Mousewheel support

Indeed another tiny but very important feature! This has been added to TW3Scrollbar and thus all our scrolling controls now support this out of the box.

Any new components?

Oh yes, there is plenty of new components and quite a few JavaScript libraries for you to enjoy. Pretty much all of the QTX components have been given an overhaul and is now a part of the standard library. This includes:

  • TW3SimpleLabel
  • TW3EdgeNavigation
  • TW3CategoryHeader
  • TW3DBGrid
  • TW3DesignSurface
  • .. and much more (!)
Need a design surface? Perhaps you need to display a document, or create a real form designer? Well inherit from this and style it to your wishes

Need a design surface? Perhaps you need to display a document, or create a real form designer? Well inherit from this and style it to your wishes

Some of the more awesome libraries we have ported over are:

Wait a minute, ACE? What is that?

Ace is the #1 Javascript code editor, implemented in JavaScript (naturally). Basically it does the exact same thing that SynEdit or TBoneCode editor does for Delphi. Except that it does more than SynEdit, have better support for different languages and dialects, syntax highlighting, code proposal, code folding — all of it! And now it’s a control you can drop on a form.

Just to demonstrate what you can do with Smart Mobile Studio, we created a real compiler. A compiler that takes the legendary Amos Basic language of the 90’s, and generates assembly bytecodes for a virtual machine. All of it written in Smart Mobile Studio. Fancy a bit of retro game coding? Well at least the editor wont hold you back!

Amos Basic for the Amiga, recreated in HTML5. And it generates bytecodes as well! Programs can be executed both in the browser and for node.js

Amos Basic for the Amiga, recreated in HTML5. And it generates bytecodes as well! Programs can be executed both in the browser and for node.js

Pixie? Eh.. fairy dust much?

You can say that. Actually its the #1 multimedia content engine for JavaScript. It uses WebGL to render 2D graphics at incredible speed and with features normally found only in high-end game engines. Want to impress someone with your Smart skills? Whip out Pixie and knock ’em dead with effects they wont even believe is coming out of JavaScript!

You really should see this live, so pay them a visit and get blown away by the power you can now control from pascal!

You really should see this live, so pay them a visit and get blown away by the power you can now control from pascal!

Is there more?

Hell yeah, I have just scratched the surface! But my fingers hurt now so I’ll take a break and post more inside information in the days and weeks to come.

Stay tuned!

Advertisements
  1. November 7, 2016 at 8:21 pm

    Awesome! Looking forward to it!

  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: