Archive
Smart Mobile Studio, Creating a TScrollbox
What would Delphi be without TScrollbox? Well probably just as great, but we all know how helpful TScrollbox is and how (with a bit of subclassing) what it can do. But what about Smart Mobile Studio and Smart pascal? Can we get the same functionality in the browser? Indeed we can, and here is the latest addition to the growing list of standard Smart Mobile Studio component palette: TW3Scrollbox.
With the scrollbars under wraps it’s actually not that hard to make. I must warn you though that the upcoming 1.1 final release of Smart Mobile Studio have some minor changes behind the scenes. So you wont be able to compile this without removing the childAdded override and the w3_DOMReady call). Also, as so many have requested, we have separated each component into their own units – this gives you even more compact apps when you compile (although the linker is actually very, very good at removing code that is not used).
The interface for our scrollbox is fairly straight forward:
unit w3scrollbox; interface uses w3system, w3components, w3graphics, w3scrollbar; //Default size of the scrollbars const CNT_SCROLLBAR_SIZE = 18; type TW3ScrollBoxContainer = Class(TW3CustomControl) End; TW3Scrollbox = Class(TW3CustomControl) Private FHScroll: TW3HorizontalScrollbar; FVScroll: TW3VerticalScrollbar; FContent: TW3ScrollBoxContainer; Procedure HandleScroll(sender:TObject); Procedure UpdateWhenReady; protected procedure ChildAdded(Const aChild:TW3Component);override; procedure InitializeObject; override; procedure FinalizeObject; override; procedure Resize; override; public Property Content:TW3ScrollBoxContainer read FContent; Procedure Update; End;
And as expected, so is the implementation. You may wonder what the “updateWhenReady” method does? Well, since your child objects will be created via the constructor under smart – the JavaScript browser code might not be ready when ChildAdded() is called (which is invoked whenever a child control attach as a child). So what we do here is that we wait until both the DOM (document object model) and TApplication instance is truly ready – then we automatically update the scrollbars if there is any content that is larger than the client-area.
implementation //########################################################################### // TW3Scrollbox //########################################################################### procedure TW3Scrollbox.InitializeObject; Begin inherited; FContent:=TW3ScrollBoxContainer.Create(self); FHScroll:=TW3HorizontalScrollbar.Create(self); FHScroll.OnChanged:=HandleScroll; FHScroll.visible:=False; FVScroll:=TW3VerticalScrollbar.create(self); FVScroll.OnChanged:=HandleScroll; FVScroll.visible:=False; //UpdateWhenReady; end; procedure TW3Scrollbox.FinalizeObject; Begin FHScroll.free; FVScroll.free; FContent.free; inherited; end; procedure TW3Scrollbox.ChildAdded(Const aChild:TW3Component); Begin inherited ChildAdded(aChild); UpdateWhenReady; end; Procedure TW3Scrollbox.UpdateWhenReady; begin if (w3_DOMReady=False) or (ObjectReady=False) then w3_callback(updateWhenReady,10) else w3_callback(Update,1); end; procedure TW3Scrollbox.Resize; var wd,hd: Integer; begin inherited; wd:=clientWidth; hd:=clientHeight; if FHScroll.visible then dec(hd,CNT_SCROLLBAR_SIZE); if FVScroll.Visible then dec(wd,CNT_SCROLLBAR_SIZE); if FHScroll.Visible then FHScroll.setBounds(0,hd,wd,CNT_SCROLLBAR_SIZE); if FVScroll.Visible then FVScroll.setBounds(wd,0,CNT_SCROLLBAR_SIZE,hd); FContent.SetBounds(1,1,wd-2,hd-2); end; Procedure TW3Scrollbox.HandleScroll(sender:TObject); Begin FContent.ScrollInfo.ScrollTo(FHScroll.Position,FVScroll.Position); end; Procedure TW3Scrollbox.Update; begin BeginUpdate; try if FContent.ScrollInfo.ScrollWidth>FContent.ClientWidth then Begin FHScroll.Total:=FContent.ScrollInfo.ScrollWidth; FHScroll.PageSize:=FContent.ClientWidth; If not FHScroll.Visible then Begin FHScroll.Visible:=True; self.SetWasSized; end; end; if FContent.ScrollInfo.ScrollHeight>FContent.clientHeight then Begin FVScroll.Total:=FContent.ScrollInfo.ScrollHeight; FVScroll.PageSize:=FContent.clientHeight; If not FVScroll.Visible then Begin FVScroll.Visible:=True; SetWasSized; end; end; FContent.SendToBack; finally EndUpdate; end; end; end.
Using the scrollbox (without the designer) is straight forward. In this case i added a beatles poster i found on google to the project as a resource, inserted an image into the content of the scrollbox – and used the image as a background (as opposed to the image itself. Neat trick!).
FBox:=TW3Scrollbox.Create(self); FBox.SetBounds(10,200,600,500); FBox.StyleClass:='TW3CustomControl'; FTest:=TW3Image.Create(FBox.Content); FTest.Background.FromURL('res/beatles.jpg'); FTest.setBounds(0,0,1644 * 2, 1086 * 2);
Smart Mobile Studio, creating a scrollbar
What HTML5 really needs is a proper, native scrollbar that doesnt suck. I’ve had a look around the internet but the native javascript versions are either dependent on some hyped up library, rendering it almost useless (i dont need 40k of javascript just to get things scrolling) – or a part of a large framework that i have no time or patience to wrap.
Since we are adding more and more user controls to smart these days, why not add good o’l TScrollBar to the mix?
It took me less than one hour to knock this one together. That included making breakfast, having a latte and brushing my teeth. If you are looking for a serious toolbox for your HTML5 development kit — then no other development studio will save you as much time as Smart Mobile Studio (he said blatantly promoting his own creation). Ok, here goes:
Analyzing the problem
So, what is a scrollbar? In short it consists of 4 parts: an up arrow, a region to move a handle, the handle – and last but not least: a down arrow. The hard part is not to draw or setup the actual control, but rather to translate between screen coordinates and the values the scrollbar represents. The scrollbar might represent 100000 items of “something”, but since you have (for instance) only 400 pixels to represent that sum – you have to translate between the visual and the abstract.
I started by isolating the math in 3 methods:
function TW3CustomScrollBar.calcSizeOfHandle:Integer; var mTemp: Integer; Begin mTemp:=TInteger.PercentOfValue(PageSize,Total); result:=round( mTemp * getArea / 100); end; function TW3CustomScrollBar.PositionToPixelOffset(aPosition:Integer):Integer; var mTemp: Integer; Begin mTemp:=TInteger.PercentOfValue(aPosition,Total); result:=round( mTemp * getArea / 100); end; function TW3CustomScrollBar.PixelOffsetToPosition(aPxPos:Integer):Integer; var mTemp: Integer; Begin mTemp:=TInteger.PercentOfValue(aPxPos,getarea); result:=trunc( (mTemp * Total) / 100 ); end;
I know, I know – this could have been made so much simpler. But it was 06:45 in the morning and I had just woken up and I was out of redbull. So just go with it. Here is the baseclass in all it’s humble glory:
type TW3ScrollbarLowerBtn = Class(TW3CustomControl); TW3ScrollbarHigherBtn = class(TW3CustomControl); TW3ScrollbarHandle = class(TW3CustomControl); TW3CustomScrollBar = Class(TW3CustomControl) private FUpBtn: TW3ScrollbarLowerBtn; FDownBtn: TW3ScrollbarHigherBtn; FHandle: TW3ScrollbarHandle; FTotal: Integer; FPageSize: Integer; FPosition: Integer; protected Procedure setTotal(aValue:Integer);virtual; procedure setPageSize(aValue:Integer);virtual; Procedure setPosition(aValue:Integer);virtual; Procedure setPositionNoCalc(aValue:Integer);virtual; procedure InitializeObject; override; procedure FinalizeObject; override; function calcSizeOfHandle:Integer; function PositionToPixelOffset(aPosition:Integer):Integer; function PixelOffsetToPosition(aPxPos:Integer):Integer; Procedure Recalculate;virtual;abstract; function getArea:Integer;virtual;abstract; public class function supportAdjustment:Boolean;override; Property MinButton:TW3ScrollbarLowerBtn read FUpBtn; property MaxButton:TW3ScrollbarHigherBtn read FDownBtn; Property DragHandle:TW3ScrollbarHandle read FHandle; published Property Total:Integer read FTotal write setTotal; Property PageSize:Integer read FPageSize write setPageSize; Property Position:Integer read FPosition write setPosition; End;
Now you might be wondering, why do i bother declaring customcontrols that will, after all, be hidden inside the new control? Because that means that you can style them. Smart automatically maps your classnames to the styles in your stylesheet. So if you define a CSS class called TW3ScrollbarLowerBtn, it will be automatically applied to that control. This means you can alter the scrollbars with your own global theme if you have some css skills.
Next, we have the implementation for our baseclass, which couldnt be simpler:
//########################################################################### // TW3CustomScrollBar //########################################################################### procedure TW3CustomScrollBar.InitializeObject; Begin inherited; FUpBtn:=TW3ScrollbarLowerBtn.Create(self); FDownBtn:=TW3ScrollbarHigherBtn.Create(self); FHandle:=TW3ScrollbarHandle.Create(self); end; procedure TW3CustomScrollBar.FinalizeObject; Begin FUpBtn.free; FDownBtn.free; FHandle.free; inherited; end; class function TW3CustomScrollBar.supportAdjustment:Boolean; Begin result:=true; end; Procedure TW3CustomScrollBar.setTotal(aValue:Integer); Begin aValue:=TInteger.EnsureRange(aValue,0,MAX_INT); if aValue<>FTotal then Begin Ftotal:=aValue; if FPageSize>FTotal then FPageSize:=FTotal; if FPosition>FTotal-FPageSize then Begin if (FTotal-FPageSize)<1 then FPosition:=0 else FPosition:=FTotal-FPageSize; end; ReCalculate; LayoutChildren; end; end; procedure TW3CustomScrollBar.setPageSize(aValue:Integer); Begin aValue:=TInteger.EnsureRange(aValue,0,FTotal); if aValue<>FPageSize then Begin FPageSize:=aValue; if FTotal>0 then Begin ReCalculate; LayoutChildren; end; end; end; Procedure TW3CustomScrollBar.setPosition(aValue:Integer); Begin aValue:=TInteger.EnsureRange(aValue,0,FTotal-FPageSize); if aValue<>FPosition then Begin FPosition:=aValue; if FTotal>0 then Begin ReCalculate; LayoutChildren; end; end; end; Procedure TW3CustomScrollBar.setPositionNoCalc(aValue:Integer); Begin aValue:=TInteger.EnsureRange(aValue,0,FTotal-FPageSize); if aValue<>FPosition then FPosition:=aValue; end; function TW3CustomScrollBar.calcSizeOfHandle:Integer; var mTemp: Integer; Begin mTemp:=TInteger.PercentOfValue(PageSize,Total); result:=round( mTemp * getArea / 100); end; function TW3CustomScrollBar.PositionToPixelOffset(aPosition:Integer):Integer; var mTemp: Integer; Begin mTemp:=TInteger.PercentOfValue(aPosition,Total); result:=round( mTemp * getArea / 100); end; function TW3CustomScrollBar.PixelOffsetToPosition(aPxPos:Integer):Integer; var mTemp: Integer; Begin mTemp:=TInteger.PercentOfValue(aPxPos,getarea); result:=trunc( (mTemp * Total) / 100 ); end;
The vertical bar
Deriving from this skelleton class we can now easily derive both horizontal and vertical scrollbars. Let’s start with the vertical. This one is a bit more complex since we need to dig into javascript events directly. I did this not to hijack the published events (like mousedown etc) making sure these can still be used. Here is the interface
TW3VerticalScrollbar = Class(TW3CustomScrollBar) private FDragSize: Integer; FDragPos: Integer; FMoving: Boolean; FEntry: Integer; procedure jsmousedown(eventObj:JMouseEvent); procedure jsmousemove(eventObj:JMouseEvent); procedure jsmouseup(eventObj:JMouseEvent); Procedure doMouseDown(button:TMouseButton; shiftState:TShiftState;x,y:Integer); procedure doMouseUp(button:TMouseButton; shiftState:TShiftState;x,y:Integer); procedure doMouseMove(shiftState:TShiftState;x,y:Integer); protected procedure InitializeObject; override; procedure Resize;Override; function getArea:Integer;override; Procedure Recalculate;override; End;
And here is the implementation. Never mind the colors, I havent done the CSS yet 🙂
procedure TW3VerticalScrollbar.InitializeObject; Begin inherited; (* minbutton.color:=clGreen; maxButton.color:=clCyan; draghandle.Color:=clRed; *) (* Avoid using up the exposed event handlers *) handle.addEventListener('mousedown',@jsmousedown,false); handle.addEventListener('mousemove',@jsmousemove,false); handle.addEventListener('mouseup',@jsmouseup,false); end; procedure TW3VerticalScrollbar.jsmousedown(eventObj:JMouseEvent); Begin eventObj.preventDefault(); var sr := ScreenRect; var shiftState := TShiftState.Current; shiftState.MouseButtons := shiftState.MouseButtons or (1 shl eventObj.button); shiftState.MouseEvent := eventObj; doMouseDown(eventObj.button, shiftState, eventObj.clientX-sr.Left, eventObj.clientY-sr.Top); end; procedure TW3VerticalScrollbar.jsmousemove(eventObj:JMouseEvent); Begin eventObj.preventDefault(); var sr := ScreenRect; var shiftState := TShiftState.Current; shiftState.MouseEvent := eventObj; doMouseMove(shiftState, eventObj.clientX-sr.Left, eventObj.clientY-sr.Top); end; procedure TW3VerticalScrollbar.jsmouseup(eventObj:JMouseEvent); Begin eventObj.preventDefault(); var sr := ScreenRect; var shiftState := TShiftState.Current; shiftState.MouseButtons := shiftState.MouseButtons and not (1 shl eventObj.button); shiftState.MouseEvent := eventObj; doMouseUp(eventObj.button, shiftState, eventObj.clientX-sr.Left, eventObj.clientY-sr.Top); end; function TW3VerticalScrollbar.getArea:Integer; Begin result:=Height; result:=MaxButton.top - minbutton.boundsRect.bottom; exit; if minButton.Visible then dec(result,MinButton.Height); if maxButton.Visible then dec(result,MaxButton.height); end; Procedure TW3VerticalScrollbar.doMouseDown(button:TMouseButton; shiftState:TShiftState;x,y:Integer); Begin if button=mbLeft then begin if dragHandle.BoundsRect.ContainsPos(x,y) then begin FEntry:=y - dragHandle.top; FMoving:=True; end; end; end; procedure TW3VerticalScrollbar.doMouseMove(shiftState:TShiftState; x,y:Integer); var mNewPos: Integer; dy: Integer; Begin if FMoving then Begin (* take offset on draghandle into account *) dy:=y - FEntry; (* position draghandle *) draghandle.top:=TInteger.EnsureRange(dy, minButton.top + minButton.height, maxButton.top - FDragSize); (* Update position based on draghandle *) mNewPos:=PixelOffsetToPosition(draghandle.top-MinButton.BoundsRect.Bottom); setpositionNoCalc(mNewPos); end; end; procedure TW3VerticalScrollbar.doMouseUp(button:TMouseButton; shiftState:TShiftState;x,y:Integer); Begin if FMoving then Begin FMoving:=False; setPosition(PixelOffsetToPosition (draghandle.top-MinButton.BoundsRect.Bottom)); end; end; procedure TW3VerticalScrollbar.Resize; var mTop: Integer; Begin inherited; MinButton.SetBounds(0,0,width,width); MaxButton.setBounds(0,(height-width),width,width); Recalculate; mTop:=MinButton.top + minButton.Height + FDragPos; DragHandle.SetBounds(2,mTop,width-4,FDragSize + Border.getVSpace); end; Procedure TW3VerticalScrollbar.Recalculate; Begin FDragSize:=calcSizeOfHandle; FDragPos:=PositionToPixelOffset(Position); end;
And voila — we have a scrollbar!
Not much to look at, so let’s put some skin on this puppy! Paste this into the application CSS file:
.TW3ScrollbarLowerBtn, .TW3ScrollbarHigherBtn { border: 2px ridge rgba(0,0,0,0.3); background-color: #FFFFFF; overflow: hidden; border-radius: 25px; -webkit-border-radius: 25px; -moz-border-radius: 25px; -ms-border-radius: 25px; -o-border-radius: 25px; } .TW3ScrollbarHandle { border: 2px ridge rgba(0,0,0,0.3); background-color: #FFFFFF; overflow: hidden; border-radius: 25px; -webkit-border-radius: 25px; -moz-border-radius: 25px; -ms-border-radius: 25px; -o-border-radius: 25px; } .TW3VerticalScrollbar { border: 2px ridge rgba(0,0,0,0.3); background-color: #FFFFFF; overflow: hidden; -webkit-touch-callout: none; -webkit-user-select: none; border-radius: 25px; -webkit-border-radius: 25px; -moz-border-radius: 25px; -ms-border-radius: 25px; -o-border-radius: 25px; }
Now let’s run the example again and we have a much better looking scrollbar 🙂
Well I’m sure you see where this is going – so I wont bother skinning it any more on this blog, but making user controls that are 100% javascript, no dependencies on the OS or any other tricks, is pretty darn easy. The scrollbars (properly skinned) will be in the next Smart Mobile Studio update — enjoy!
Smart Mobile Studio, creating a toggle switch
As work continues from the release candidate to the final release – we are busy polishing the product, adding missing bits and pieces, tweaking the css and making things better.
One of the latest controls to be added is the classical iPhone toggle-box (on-off switch) that has been lacking from Smart Mobile Studio. So it’s about time we got it in there 🙂
Creating controls
Smart Mobile Studio component writing is actually very simple. It’s much easier than under Delphi – but it involves one aspect that to some Spartans can feel.. well, a bit odd. Namely the fact that you have to take CSS into account. In this short article i’ll post the code for the TW3ToggleSwitch control (which will be in the next hotfix or update before we officially hit the 1.1 mark).
The CSS code for TW3Switchbox is fairly straight-forward:
/* ########################################################################## # TW3ToggleSwitch ########################################################################## */ .TW3ToggleSwitch { background-color: #FFFFFF; border:1px solid #AAA; border-radius:6px; color:#FFF; font-weight:700; overflow:hidden; box-shadow:0 1px 0 #FFF; -webkit-user-select: none; -webkit-tap-highlight-color: transparent; } .TW3ToggleOnLabel { border-radius: 6px; text-align:center; background:#007FEA; text-shadow:0 -1px 0 #093B5C; box-shadow:0 4px 5px -2px rgba(0,0,0,0.3) inset; } .TW3ToggleOffLabel { border-radius: 6px; text-align:center; box-shadow:0 4px 5px -2px rgba(0,0,0,0.3) inset; } .TW3ToggleKnob { cursor: pointer; background-color: #FFFFFF; border:1px solid #AAA; border-radius:4px; color:#FFF; font-weight:700; overflow:hidden; box-shadow:0 4px 0 -2px #F1F1F1 inset, 0 2em 2em -2em #AAA inset, 0 0 2px rgba(0,0,0,.5); } .TW3ToggleKnob:hover { background:#E5E5E5; }
If you are wondering why i have divided the toggle-box into 4 parts (the box, the knob, the on/off labels) there is a good reason for this. It means that you can alter the look of the control without us getting involved. If you dont like the way the control looks – then you are free to alter the CSS and make your own style. Freedom baby 😉
And then there is the pascal classes:
TW3ToggleKnob = Class(TW3CustomControl) protected procedure InitializeObject; override; End; TW3ToggleOnLabel = Class(TW3Label) public class function supportAdjustment:Boolean;override; end; TW3ToggleOffLabel = Class(TW3Label) public class function supportAdjustment:Boolean;override; end; TW3ToggleSwitch = Class(TW3CustomControl) private FKnob: TW3ToggleKnob; FOnText: TW3ToggleOnLabel; FOffText: TW3ToggleOffLabel; Procedure HandleTouch(Sender: TObject; Info: TW3TouchData); procedure HandleMouseDown(sender:Tobject;button:TMouseButton; shiftState:TShiftState;x,y:Integer); function getChecked:Boolean; procedure setChecked(Const aValue:Boolean); protected procedure InitializeObject; override; Procedure FinalizeObject;Override; procedure Resize; override; public Property Checked:Boolean read getChecked write setChecked; Procedure Toggle; End;
And ofcourse, the implementation. Note: the methods “supportAdjustment
” is not in the current RTL. All in all it controls the way the method AdjustToParentBox affects it’s sub controls. You dont really have to care about that at this point, it’s taken care of.
//########################################################################### // TW3ToggleOnLabel //########################################################################### class function TW3ToggleOnLabel.supportAdjustment:Boolean; Begin result:=False; end; //########################################################################### // TW3ToggleOffLabel //########################################################################### class function TW3ToggleOffLabel.supportAdjustment:Boolean; Begin result:=False; end; //########################################################################### // TW3ToggleKnob //########################################################################### procedure TW3ToggleKnob.InitializeObject; begin inherited; w3_setStyle(Handle,w3_CSSPrefix('Transition'),'left .12s'); end; //########################################################################### // TW3ToggleSwitch //########################################################################### procedure TW3ToggleSwitch.InitializeObject; begin inherited; (* Create the "ON" label *) FOnText:=TW3ToggleOnLabel.Create(self); FOnText.Caption:='ON'; FOnText.AlignText:=taCenter; FOnText.Font.Color:=clWhite; (* Create the "OFF" label *) FOffText:=TW3ToggleOffLabel.Create(self); FOffText.Caption:='OFF'; FOffText.Font.Color:=clBlack; FOffText.AlignText:=taCenter; (* Create our leaver knob *) FKnob:=TW3ToggleKnob.create(self); (* setup internal handlers *) self.OnMouseDown:=HandleMouseDown; self.OnTouchBegin:=HandleTouch; end; Procedure TW3ToggleSwitch.FinalizeObject; Begin FKnob.free; FOffText.free; FOnText.free; inherited; end; function TW3ToggleSwitch.getChecked:Boolean; Begin result:=FKnob.left>0; end; procedure TW3ToggleSwitch.setChecked(Const aValue:Boolean); Begin if aValue<>getChecked then Toggle; end; Procedure TW3ToggleSwitch.Toggle; Begin case getChecked of True: FKnob.Left:=0; False: FKnob.Left:=(width div 2)-8; end; w3_callback( procedure () begin if assigned(OnChanged) then onChanged(self); end, 300); end; Procedure TW3ToggleSwitch.HandleTouch(Sender: TObject; Info: TW3TouchData); Begin Toggle; end; procedure TW3ToggleSwitch.HandleMouseDown(sender:TObject; button:TMouseButton; shiftState:TShiftState; x, y : Integer); Begin if button=mbLeft then Toggle; end; procedure TW3ToggleSwitch.Resize; var mTemp: Integer; wd: Integer; hd: Integer; Begin wd:=width; hd:=height; if (wd>0) and (hd>0) then begin mTemp:=(wd div 2); if (FKnob.width<>mTemp) or (FKnob.height<>hd) then FKnob.SetSize(mTemp + 8,hd); FOnText.SetBounds(0,0,mTemp,hd); FOffText.SetBounds(mTemp,0,mTemp,hd); end; end;
The magic movement
How exactly did we animate the button? It slides fluently from left to right (and visa versa)? The magic is in this simple line:
w3_setStyle(Handle,w3_CSSPrefix('Transition'),'left .12s');
In this line we tell the browser that it should apply a transition on a css value, in this case the “left” property of the knob control. So whenever you alter the left position of that control, it will apply a 0.12s delay in the movement. Voila — that’s how you create a very simple and smooth scrolling effect (doesn’t get much simpler than that).
You could also apply it to any other css value, like width/height or background color. It’s really simple to create hardware accelerated effects with very little effort under Smart Mobile Studio. Once you have some CSS under your belt – it’s a piece of cake.
Smart Mobile Studio 1.1 RC build 400 “sneak peak”
It’s been two years in the making, 400.000+ lines of Delphi code, and it’s now in the last stages of testing before release. I give you Smart Mobile Studio 1.1.400 RC:
So what’s new?
You will have to wait for the press release to get the full low-down, but since this is my personal blog I’m free to write whatever i want. So what really excites me about this release are the general IDE improvements. We have been so fortunate to have both Primoz and Christian playing around with the codebase – so things like multithreading and background compilation (which is how the IDE extracts information regarding your code) is now faster than ever.
In the previous versions one bottleneck was the code-insight feature (code proposal window that pops up while you type). It worked but it was slow and had the unfortunate tendency to pick up information from an earlier compile sequence. So it was not as accurate as we Spartans are used to. Well this has been taken care of and it’s now spot on, extremely fast and uses its own thread to do its thing.
The same goes for the unit structure tab, which shows a full overview of the current unit including classes, methods, fields and properties. This to was suffering from having to share a symbol dictionary with the code-insight function. Well that is now a thing of the past and both of them now have their own thread and business logic.
Christian decided to go commando and added a very handy feature: macro recording. So we now have some mysterious new buttons just over the unit structure tab (these should be known by Delphi and freepascal users alike):
With the new background threading in place, handy features like gabelou hints is now available, you can activate that in the preferences dialog and enjoy the hints and parameter insights that brings. And of course – compiler metrics which will give you more detailed insight into how fast the compiler really is:
You will also find it handy to be able to add your own form-factor sizes directly from the IDE. With so many new mobile devices being launched these days – it’s best to avoid hardcoding anything:
The component palette has also been expanded. We decided to add more tabs and organize the components in groups. Three new components have been added: Steema Teechart (tw3chart), Listbox (Primoz) and a css animated progressbar.
We also have dependency validation for components now — so whenever you add a control to your design, it will check if the required units are in your source-code, if not: it will add the units directly. So no more having to add the units yourself 🙂
And finally, the classbrowser. You can now click on the ancestor class and navigate there directly, you can also double-click on a method and the IDE will open up the unit in the back so you can look at the code. We have also added a couple of new tabs — these will be implemented as we move along, and they will give you some idea of what the final classbrowser is about. This is the place where you (once we get support for packages) can edit your docs and .. well, you get the idea. Much better than documenting in the code which is a nightmare to maintain. But for this release: ancestor navigation, unit access – as requested by many users.
Compiler
I wont blow the whistle on all the features but needless to say we have the most evolved object pascal to JavaScript compiler on the planet. In our labs we call Eric “the stig” of Delphi programming (“the stig” is the nickname for the anonymous and brilliant race car driver, as featured on the Top-Gear british television show). Needless to say we got guns: operator overloading, interface expressions, lambdas, class property expressions, pseudo sets .. the list goes on. What is more important is that the generated code is produced faster (much faster), is more efficient and gives you *ALL* the high-level advantages of traditional object pascal — running in the browser under a language that has no concept of neither class nor interface. That is no small feat ladies and gentlemen.
- VMT based javascript (true OOP)
- var parameters
- Initialization / Finalization support
- Records, nested records, array of records (et al)
- Classes, inheritance
- Partial classes
- class helpers
- record helpers
- lambda support
- operator overloading
- speed improvements
- direct JS object access via variants
- external classes (map JS classes directly)
- external functions
- .. for a full low-down on the compiler, buy the smart mobile studio book here
Soon the compiler will have a new switch, to use java script’s native datatypes. One of the hidden gems of JavaScript is that it does have typed data, but most people don’t use them. So you can allocate arrays of UInt32 (unsigned integer, 32 bits) for instance. By taking advantage of typed arrays you get a phenomenal speed boost if you deal with large and complex numbers.
The RTL
Andre Mucche, the ever creative Spartan which provided Smart Mobile Studio with direct Remobjects support, is currently busy porting over datasnap. Yes, you read right: datasnap support. While it wont make it into the release candidate, we hope to have it done for the final release (but no promises, we are only human). The remobjects import wizard have also been updated with the latest remobjects headers. The phonegap units is also updated and completed, webGL is up to date – and we have added more components and expanded the RTL with too much to list here. Way to much.
For those into large numbers, Christian have ported over Halvard Vassbotn‘s unit for that very thing. We called Halvard up and asked of course, which is proper, and he gave us his blessing. Hopefully we will see Halvard joining the Smart Pascal consortium soon 😉
I also started the conversion of CODEF to smart, so you will notice some new additions to TW3Canvas. If you are wondering what CODEF can do for you, check out this demo (use chromium! or safari — mozilla cant handle the speed).
Credits go out to the team: eric, primoz, christian and andre! Cheers guys!
Embedding images in Smart Mobile Studio
If you have a lot of images (glyphs, sprites, whatever) in either a Smart Mobile game or a demo – you can actually reduce loading time quite dramatically by embedding the images directly in your source.
Here is how you do it
Under the tools menu you will find a menu item called “image converter”. This is a simple wizard that loads in a picture and converts it to source-code. The resulting string is an URL image which can be used by the fromImageURL methods.
Now simply paste the generated code into your source-unit and load it up with “FImage.loadFromUrl(cnt_imagedata)” and voila 🙂
Here is the chrome logo converted to text:
const CNT_IMAGEDATA ='data:image/png;base64,'+ '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' + 'dgAAAABJRU5ErkJggg==';
You must be logged in to post a comment.