Category: Firemonkey

Firemonkey TSpinBox height

I'm using C++ Builder 10.3 and my application is for Android, please note I'm very new to C++ Builder I'm trying to change the font size and height of a TSpinBox but i'm unable to change the height. I tried by best to port the following Delphi solution Firemonkey TEdit height but with no joy and i'm a total lose. AdjustFixedSize is declared private i dont think its being overridden, i have also tried creating a setter and calling it but yet again I was unable to get it to work. The biggest problem i have is my lack of C++ Builder knowledge. Header class TMySpinBox : public TSpinBox{ public: protected: virtual void AdjustFixedSize(const TControl Ref) ; }; CPP TMySpinBox::TMySpinBox() : TSpinBox(0){}; void TMySpinBox::AdjustFixedSize(const TControl Ref){ SetAdjustType(TAdjustType::None); Code TMySpinBox* SpinBox1 = new TMySpinBox(); SpinBox1->ControlType=TControlType::Platform; SpinBox1->Parent=Panel1->Parent; SpinBox1->Position->Y=16.0; SpinBox1->Position->X=16.0; SpinBox1->Min=2; SpinBox1->Max=99; SpinBox1->Font->Size=48; SpinBox1->Visible=true; SpinBox1->Value=2; SpinBox1->Align=TAlignLayout::None; SpinBox1->Height=100; Width=100;
Read More

What is the purpose of the ‘default’ platform marker in the list of tstylebook styles?

UPDATE : I made a new test project from scratch and this one DID apply the style inside the default platform marker on my mainform on windows and android, so the behaviour seen below might have something todo with rest of my project..I will do some more testing.( I have 1 style 'backgroundstyle' with rectangle brush fill color set to red ) UPDATE 2 : As soon as I added 1 specific style for e.g. android platform, none of the 'default' platform styles are considered anymore. Mainform suddenly not red anymore. In an heroic attempt to make a good styling design for my proof of concept multi-platform application, I'm was investigating the stylebook more closely. In general, separating the styling from the application logic is of course, very welcome. Although I'm more unsure if the fmx implementation of this principle is, sofar, optimal ( I'm losing myself in finding out which property of which styleresource I need to change to get what I want for anything beyond simple text or rectangles....but that might be up to me. ). I also understand that each target platform has it's own habits , and it's good practice to stick to them ( at least, if you want to be part of the hurd :-) . But I would say that , e.g. my main application colors is something that I decide, and should be consistent across platforms. It seems that in order to achieve that, I need to change that, possibly , on all the multiple individual style --resources-- ( everywhere a fill color is / might be specified in each of the 190 styles in the list and also in all the bitmaps in the bitmap map, and this for each scale and each sourcelinkname.. ) and , again, this for every target platform...The result is usually that I stick to the 'premium' out of the box styles :-) I had hoped that the 'default' platform marker would come to the rescue, and have this platform for all of the styles, and BY EXCEPTION, have only some platform specific styles repeated and changed, if really required on that platform. The documentation says : Note: There is also the "Default" platform marker. FireMonkey application loads > the Default style when the application cannot find the matching styles for the > current platform. But it doesn't seem to work this way. e.g. on android these default styles ( in runtime ) are always ignored and revert to the embedded platform specific style but in windows the styles are indeed used... ( in the IDE at design time, the same default style is shown as I expect for every platform that I choose -- ) In my example, I simply use the mainform background color ( = backgroundstyle brush fill color ) as an easy test setup : change the brush fill color on the 'backgroundstyle' for the default platform and run it on windows / android ). So what is the purpose of the default platform in the stylebook ? Is there something I do not understand ? Or is it a bug ? Is there a way to use one set of styles across platform via the stylebook ? If not, could you create and deploy a single style file and load at runtime and have it used on all platforms ? ( should there be a platform marker in this style file ? Would the styles be ignored if not 'really' the correct target platform ...) As a result, I find myself doing a lot of runtime styling in code afterall because I'm really sure it will be platform consistent, but that's not really the purpose I guess....
Read More

Delphi Debugger Error on Android 32-bit Platform

I am experiencing the same error when running with debugging on Android 32-bit platform while on 64-bit has no issue. The debugger just stopped and exited but the app was able to open on my device. Here's the error: Can't open socket: Permission denied. Exiting. I thought this was within my app codes error but when I tried a new blank multi-device form, I was getting the same error. So, I suspect this issue is not from my code but a Delphi debugger glitch. Has anyone here experienced the same issue and was able to resolve this. Otherwise, I will take my chances with Embarcadero support.
Read More

FNC Hidden Gems: JSON persistence

Intro FNC has evolved over time. Each update brings new features, some of them are visible at designtime/runtime. Some of time are happening behind the screens. Some updates are bringing a lot of fixes to make FNC more stable across the multiple frameworks and platforms FNC supports. JSON persistence is one of those hidden gems that is available in TMS FNC Core. Today's blog brings a step by step tutorial on how to implement JSON persistence in your application, and how to import objects from JSON. Getting Started JSON formatted data can come from a REST service, a database, a local file, plain text ... . It's an easy to read/learn/use and consume format and in FNC we have added support for mapping objects to JSON and vice versa. The code below is a sample of JSON that we will map on an object in Delphi. We'll focus on having an object that can access the properties shown in this JSON: { "$type":"TPerson", "address":{ "$type":"TPersonAddress", "addressLocality":"Colorado Springs", "addressRegion":"CO", "postalCode":"80840", "streetAddress":"100 Main Street" }, "colleague":[ "http://www.example.com/JohnColleague.html", "http://www.example.com/JameColleague.html" ], "email":"info@example.com", "jobTitle":"Research Assistant", "name":"Jane Doe", "birthDate":"1979-10-12", "gender":"female", "nationality":"Albanian", "telephone":"(123) 456-6789", "url":"http://www.example.com", } For accessing this data we need to define our classes first: type TPersonAddress = class(TPersistent) private FPostalCode: string; FAddressLocality: string; FAddressRegion: string; FStreetAddress: string; published property AddressLocality: string read FAddressLocality write FAddressLocality; property AddressRegion: string read FAddressRegion write FAddressRegion; property PostalCode: string read FPostalCode write FPostalCode; property StreetAddress: string read FStreetAddress write FStreetAddress; end; TPerson = class(TPersistent) private FAddress: TPersonAddress; FColleague: TStringList; FBirthDate: string; FName: string; FEmail: string; FTelephone: string; FGender: string; FNationality: string; FJobTitle: string; FURL: string; public constructor Create; destructor Destroy; override; published property Address: TPersonAddress read FAddress; property Colleague: TStringList read FColleague; property Email: string read FEmail write FEmail; property JobTitle: string read FJobTitle write FJobTitle; property Name: string read FName write FName; property BirthDate: string read FBirthDate write FBirthDate; property Gender: string read FGender write FGender; property Nationality: string read FNationality write FNationality; property Telephone: string read FTelephone write FTelephone; property URL: string read FURL write FURL; end; And the JSON data (please note that linebreaks and whitespaces are currently not supported, but this is being worked on!. const jsonSample = '{' + '"$type": "TPerson",' + '"address":{' + '"$type": "TPersonAddress",' + '"addressLocality":"Colorado Springs",' + '"addressRegion":"CO",' + '"postalCode":"80840",' + '"streetAddress":"100 Main Street"' + '},' + '"colleague":[' + '"http://www.example.com/JohnColleague.html",' + '"http://www.example.com/JameColleague.html"' + '],' + '"email":"info@example.com",' + '"jobTitle":"Research Assistant",' + '"name":"Jane Doe",' + '"birthDate":"1979-10-12",' + '"gender":"female",' + '"nationality":"Albanian",' + '"telephone":"(123) 456-6789",' + '"url":"http://www.example.com"' + '}'; There are multiple ways to map the JSON onto the TPerson object. 1. Use the TTMSFNCPersistence class Add the unit *TMSFNCPersistence to the uses list (* = FMX., LCL, VCL., WEBLib.), and use the following code: var p: TPerson; s: TStringStream; begin p := TPerson.Create; s := TStringStream.Create(jsonSample); try TTMSFNCPersistence.LoadSettingsFromStream(p, s); finally s.Free; p.Free; end; end; 2. Use the object class helper in *TMSFNCTypes unit An alternative is to use the class helper that maps JSON to the object. var p: TPerson; begin p := TPerson.Create; try p.JSON := jsonSample; finally p.Free; end; end; Writing to JSON is as easy as reading. Simply use SaveSettingsToFile or SaveSettingsToStream or use the JSON object class helper to get the JSON from the object. p: TPerson; begin p := TPerson.Create; try p.JSON := jsonSample; p.Name := 'tmssoftware.com'; TTMSFNCUtils.Log(p.JSON); //or TTMSFNCPersistence.SaveSettingsToFile(p, 'TPerson.json'); finally p.Free; end; end; Note that this code will also work on other frameworks such as VCL, LCL and WEB. Below is the full code sample that demonstrates JSON persistence. Please let us know if you have suggestions on what to add to TMS FNC Core in the future! unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.fmx} uses FMX.TMSFNCTypes, FMX.TMSFNCPersistence; const jsonSample = '{' + '"$type": "TPerson",' + '"address":{' + '"$type": "TPersonAddress",' + '"addressLocality":"Colorado Springs",' + '"addressRegion":"CO",' + '"postalCode":"80840",' + '"streetAddress":"100 Main Street"' + '},' + '"colleague":[' + '"http://www.example.com/JohnColleague.html",' + '"http://www.example.com/JameColleague.html"' + '],' + '"email":"info@example.com",' + '"jobTitle":"Research Assistant",' + '"name":"Jane Doe",' + '"birthDate":"1979-10-12",' + '"gender":"female",' + '"nationality":"Albanian",' + '"telephone":"(123) 456-6789",' + '"url":"http://www.example.com"' + '}'; type TPersonAddress = class(TPersistent) private FPostalCode: string; FAddressLocality: string; FAddressRegion: string; FStreetAddress: string; published property AddressLocality: string read FAddressLocality write FAddressLocality; property AddressRegion: string read FAddressRegion write FAddressRegion; property PostalCode: string read FPostalCode write FPostalCode; property StreetAddress: string read FStreetAddress write FStreetAddress; end; TPerson = class(TPersistent) private FAddress: TPersonAddress; FColleague: TStringList; FBirthDate: string; FName: string; FEmail: string; FTelephone: string; FGender: string; FNationality: string; FJobTitle: string; FURL: string; public constructor Create; destructor Destroy; override; published property Address: TPersonAddress read FAddress; property Colleague: TStringList read FColleague; property Email: string read FEmail write FEmail; property JobTitle: string read FJobTitle write FJobTitle; property Name: string read FName write FName; property BirthDate: string read FBirthDate write FBirthDate; property Gender: string read FGender write FGender; property Nationality: string read FNationality write FNationality; property Telephone: string read FTelephone write FTelephone; property URL: string read FURL write FURL; end; { TPerson } constructor TPerson.Create; begin FAddress := TPersonAddress.Create; FColleague := TStringList.Create; end; destructor TPerson.Destroy; begin FreeAndNil(FAddress); FreeAndNil(FColleague); inherited; end; procedure TForm1.Button1Click(Sender: TObject); var p: TPerson; begin p := TPerson.Create; try p.JSON := jsonSample; finally p.Free; end; end; end.
Read More

Error running Multi Device App on Android platform using TFDLocalSQL of Delphi Community Version

I am setting up a TLocalSQL for my multi device app. I understand this component is using SQLite as backend while having my MySQL database sitting on server remotely. On my datamodule I have setup the following: TFDGUIxWaitCursor TFDConnection — for MySQL server connection TFDPhysMySQLDriverLink — MySQL driver TFDQuery — MySQL table query TFDConnection — for my LocalSQL (SQLite backend) TFDPhysMySQLDriverLink — SQLite driver TFDLocalSQL — my LocalSQL to handle embedded database of my app with dataset TFDQuery above TFDQuery — my LocalSQL query My data module RME: unit Unit10; interface uses System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.MySQL, FireDAC.Phys.MySQLDef, FireDAC.FMXUI.Wait, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, Data.DB, FireDAC.Stan.ExprFuncs, FireDAC.Phys.SQLiteDef, FireDAC.Phys.SQLite, Datasnap.DBClient, Datasnap.Provider, FireDAC.Comp.Client, FireDAC.Phys.SQLiteVDataSet, FireDAC.Comp.DataSet, FireDAC.Comp.UI; type TDataModule10 = class(TDataModule) con1: TFDConnection; dvr1: TFDPhysMySQLDriverLink; cur1: TFDGUIxWaitCursor; qry1: TFDQuery; loc1: TFDLocalSQL; dvr2: TFDPhysSQLiteDriverLink; con2: TFDConnection; qry2: TFDQuery; dsp1: TDataSetProvider; cds1: TClientDataSet; private { Private declarations } public { Public declarations } end; var DataModule10: TDataModule10; implementation {%CLASSGROUP 'FMX.Controls.TControl'} {$R *.dfm} end. Now, on my main form (below RME) where my TListView is sitting connects the TFDQuery of my TFDLocalSQL. unit Unit9; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.ListView.Types, FMX.ListView.Appearances, FMX.ListView.Adapters.Base, System.Rtti, System.Bindings.Outputs, Fmx.Bind.Editors, Data.Bind.EngExt, Fmx.Bind.DBEngExt, Data.Bind.Components, Data.Bind.DBScope, FMX.ListView; type TForm9 = class(TForm) lsv1: TListView; bdr1: TBindSourceDB; bdl1: TBindingsList; lcf1: TLinkListControlToField; private { Private declarations } public { Public declarations } end; var Form9: TForm9; implementation uses Unit10; {$R *.fmx} end. I ran it in Windows 64-bit platform without any issue. But when I tried it on my Android device platform, I am getting the following error: [DCC Fatal Error] dm_u.pas(10): F2613 Unit 'FireDAC.Phys.MySQL' not found. I am a bit confused because this is the purpose of TFDLocalSQL. It should handle different sources of data, be it coming from different servers, xml, etc and embed it in your application using the SQLite database. I hope my level of understanding got it right. Now, I am stuck on how to get around with the error. I cannot change the driver because my source data is actually from MySQL. Can anybody enlighten me more about TFDLocalSQL. It is my first time to use it and it serves well with my purpose. Am I missing something?
Read More

Deleting Buttons from TPanel, Firemonkey Edition

Using Delphi 10.2 (under Windows 10 "19H2"), I can create a new app, drop a single panel on it, and an action list with two items. Both items call the same routine whose purpose is to remove any buttons on the panel, and then add the new ones in: procedure TForm1.CreateNavPanelButtons(Action: TAction); begin NavPanel.RemoveObject(Btn); Btn.DisposeOf; //problem line Btn := MakeButton(Action); NavPanel.AddObject(Btn); end; (I've simplified to just use one button here.) Remove the existing button, add the new button in. If I call DisposeOf (to free up the button's memory), the Window object becomes unresponsive (can't resize, move, close) until I shift focus away from the app. I've included the entire code below: unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMX.Controls.Presentation, System.Actions, FMX.ActnList; type TForm1 = class(TForm) NavPanel: TPanel; ActionList: TActionList; acNextMenu: TAction; acBackToMainMenu: TAction; procedure FormCreate(Sender: TObject); procedure acNextMenuExecute(Sender: TObject); private { Private declarations } public Btn: TButton; procedure CreateNavPanelButtons(Action: TAction); end; var Form1: TForm1; implementation {$R *.fmx} function MakeButton(A: TAction): TButton; begin Result := TButton.Create(nil); Result.Action := A; Result.Text := (A as TAction).Text; end; procedure TForm1.acNextMenuExecute(Sender: TObject); begin CreateNavPanelButtons(acBackToMainMenu); end; procedure TForm1.CreateNavPanelButtons(Action: TAction); begin NavPanel.RemoveObject(Btn); Btn.DisposeOf; Btn := MakeButton(Action); NavPanel.AddObject(Btn); end; procedure TForm1.FormCreate(Sender: TObject); begin CreateNavPanelButtons(acNextMenu); end; end. Here's the form: object Form1: TForm1 Left = 0 Top = 0 Caption = 'Form1' ClientHeight = 480 ClientWidth = 640 FormFactor.Width = 320 FormFactor.Height = 480 FormFactor.Devices = [Desktop] OnCreate = FormCreate DesignerMasterStyle = 0 object NavPanel: TPanel Align = Top Size.Width = 640.000000000000000000 Size.Height = 73.000000000000000000 Size.PlatformDefault = False TabOrder = 0 end object ActionList: TActionList Left = 392 Top = 192 object acNextMenu: TAction Category = 'Navigation' Text = 'NextMenu' OnExecute = acNextMenuExecute end object acBackToMainMenu: TAction Category = 'Navigation' Text = 'Back To &Main Menu' OnExecute = FormCreate end end end
Read More

What the purpose of the variable StepSize in TStrokeBuilder.BuildSolidPolygon?

I have a problem, under GPU engine (so under android/ios) we can not draw an Arc (Canvas.DrawArc) with an angle that is lower than it's stroke thickness. that a problem especially if you have a big stroke thickness. So I look the delphi source code and the code of the function TStrokeBuilder.BuildSolidPolygon : procedure TStrokeBuilder.BuildSolidPolygon(const Points: TPolygon; const Opacity: Single; BreakAtEnd: Boolean); var StepSize, Distance: Single; CurScale, SrcPos, DestPos, PieceDirVec, ThickPerp: TPointF; SrcPosValid, DestPosValid, PrevVerticesPlaced: Boolean; CurIndex: Integer; begin if Length(Points) < 2 then begin InitArrays(0, 0); Exit; end; CurScale := GetMatrixScale; FThickness := FBrush.Thickness * (CurScale.X + CurScale.Y) * 0.5; FHalfThickness := FThickness * 0.5; FStrokeColor := PremultiplyAlpha(MakeColor(FBrush.Color, Opacity)); FUndeterminedMode := True; InitArrayPointers; StepSize := FThickness; if StepSize < 2 then StepSize := 2; CurIndex := 0; SrcPosValid := False; DestPosValid := False; PrevVerticesPlaced := False; while CurIndex < Length(Points) do begin if (CurIndex >= Length(Points) - 1) and BreakAtEnd and (Points[0] <> Points[Length(Points) - 1]) then Break; if not SrcPosValid then begin SrcPos := Points[CurIndex]; if (SrcPos.X >= $FFFF) or (SrcPos.Y >= $FFFF) then begin DestPosValid := False; PrevVerticesPlaced := False; Inc(CurIndex); Continue; end; SrcPos := SrcPos * FMatrix; end else SrcPosValid := False; if not DestPosValid then begin DestPos := Points[(CurIndex + 1) mod Length(Points)]; if (DestPos.X >= $FFFF) or (DestPos.Y >= $FFFF) then begin DestPos := Points[CurIndex]; if (DestPos.X >= $FFFF) or (DestPos.Y >= $FFFF) then begin PrevVerticesPlaced := False; Inc(CurIndex); Continue; end; DestPos := DestPos * FMatrix; end else DestPos := DestPos * FMatrix; end else DestPosValid := False; Distance := DestPos.Distance(SrcPos); if Distance >= StepSize then begin PieceDirVec := (DestPos - SrcPos).Normalize; ThickPerp := TPointF.Create(-PieceDirVec.Y, PieceDirVec.X) * FHalfThickness; InsertVertex(SrcPos - ThickPerp, FStrokeColor); InsertVertex(SrcPos + ThickPerp, FStrokeColor); if PrevVerticesPlaced then begin InsertIndex(FCurrentVertex - 3); InsertIndex(FCurrentVertex - 1); InsertIndex(FCurrentVertex - 2); InsertIndex(FCurrentVertex - 2); InsertIndex(FCurrentVertex - 4); InsertIndex(FCurrentVertex - 3); end; PrevVerticesPlaced := True; SrcPos := SrcPos + (PieceDirVec * StepSize); SrcPosValid := True; DestPosValid := True; Continue; end; if ((CurIndex < Length(Points) - 2) and (Points[CurIndex + 1].X < $FFFF) and (Points[CurIndex + 1].Y < $FFFF) and (Points[CurIndex + 2].X < $FFFF) and (Points[CurIndex + 2].Y < $FFFF) and (Points[CurIndex + 1].Distance(Points[CurIndex + 2]) > StepSize)) then begin PieceDirVec := (DestPos - SrcPos).Normalize; ThickPerp := TPointF.Create(-PieceDirVec.Y, PieceDirVec.X) * FHalfThickness; InsertVertex(DestPos - ThickPerp, FStrokeColor); InsertVertex(DestPos + ThickPerp, FStrokeColor); if PrevVerticesPlaced then begin InsertIndex(FCurrentVertex - 3); InsertIndex(FCurrentVertex - 1); InsertIndex(FCurrentVertex - 2); InsertIndex(FCurrentVertex - 2); InsertIndex(FCurrentVertex - 4); InsertIndex(FCurrentVertex - 3); end; if CurIndex < Length(Points) - 1 then begin Inc(CurIndex); Continue; end else Break; end; if (CurIndex = Length(Points) - 1) or (Points[CurIndex + 1].X >= $FFFF) or (Points[CurIndex + 1].Y >= $FFFF) then begin PieceDirVec := (DestPos - SrcPos).Normalize; ThickPerp := TPointF.Create(-PieceDirVec.Y, PieceDirVec.X) * FHalfThickness; InsertVertex(DestPos - ThickPerp, FStrokeColor); InsertVertex(DestPos + ThickPerp, FStrokeColor); if PrevVerticesPlaced then begin InsertIndex(FCurrentVertex - 3); InsertIndex(FCurrentVertex - 1); InsertIndex(FCurrentVertex - 2); InsertIndex(FCurrentVertex - 2); InsertIndex(FCurrentVertex - 4); InsertIndex(FCurrentVertex - 3); end; PrevVerticesPlaced := False; if CurIndex < Length(Points) - 1 then begin Inc(CurIndex); Continue; end else Break; end; SrcPosValid := True; Inc(CurIndex); end; FinalizeArrays; end; What i don't understand it's why they did : if StepSize < 2 then StepSize := 2; Why 2 and not 1? Don't even also quite understand the purpose of the variable StepSize...
Read More

What’s coming in TMS WEB Core v1.4 Ravenna

The world of web development is evolving fast, it comes as no surprise that TMS WEB Core evolves fast.
When we embarked on this exciting adventure in 2017, we knew the road would be long. There is simply an abundance of things to do in the world of web development and we made it our mission to put Delphi developers in a front seat to apply the well known RAD approach to create web applications with an unparalleled productivity.

When we first released TMS WEB Core v1.0 on July 26, 2018, we named version 1.0 Brescia after the city where the famous car race Mille Miglia starts. And with each subsequent version, we name it after a city across the legendary Mille Miglia track of 1955. We visited meanwhile Verona with v1.1, Padua with v1.2 and Ferrara for v1.3. So, now we are heading to version v1.4 that will be named Ravenna.

The theme for TMS WEB Core v1.4 Ravenna is:

  • widening the UI control offerings with controls for frequently used UI patterns
  • enhancing the HTML-first approach
  • increasing easy interfacing to additional popular back-end services

Widening the UI control offerings

We have added two brand new UI controls in TMS WEB Core v1.4 Ravenna:

TWebImageSlider

In many scenarios, people want to show various pictures of things for specific items. Think about a product on Amazon that might have different pictures taken from different angles, think about an online real-estate broker presenting different houses with picture sets of the house on sale or a car dealer showing cars for sale accompanied by pictures of the car in various positions.

If you have such a use-case in your application, TWebImageSlider is the shortcut to achieve this. Basically this is a container control where you add the links to the images to be displayed and the control does everything else. It shows the picture thumbnails, a left / right slider button and you can click on thumbnails to see the large version of a specific picture.

Now, to integrate this kind of functionality should not take much more than a couple of minutes.

var
  i: Integer;
begin
   for i := 1 to 8 do
    ImageSlider.ImageURLs.add(Format('./images/nature-%d.jpg', [i]));
  ImageSlider.RefreshImages;
  ImageSlider.Appearance.TransitionEffect := tefSlide;
end;

TWebContinuousScroll

Another often used pattern is to show lists of items filling the viewing area of the browser only and after this, only load additional items when the user decides to scroll down. The reasoning behind such UI control is simple. By loading only the items in view, the initial display of the page is very fast and only when the user wants to see additional items, extra items are loaded asynchronously in the list.

TWebContinuousScroll is again a shortcut to this pattern. Drop the control on the form, add the event handler code for the event that is triggered when a new page of items is needed and return the requested items. TWebContinuousScroll does the rest, it handles the rendering, it handles the UI interaction (mouse dragging / touch scrolling) and just triggers the event when new items are needed.

procedure TForm1.WebContinuousScroll1FetchNextPage(Sender: TObject; APageSize,
  APageNumber: Integer; var AURL: string);
begin
  AURL := 'https://tmswebcore.com:8082/?page=' + IntToStr(APageNumber) + '&per_page=' + IntToStr(APageSize);
end;

New TWebListControl demo

The TWebListControl is a very versatile list control that might not be well understood enough and therefore underused by TMS WEB Core developers. TWebListControl uses the bootstrap CSS library do its magic. From a list of items, it can create a breadcrumb, a tab list, an item list, a list with expanding/collapsing subitems. The new demo shows the various modes of the versatile TWebListControl

Electron 8 support

The fast evolving framework Electron for creating cross platform desktop applications reached meanwhile version 8. It is being polished & enhanced all the time to allow to create responsive installable & near-native experience desktop applications for Windows, macOS and Linux with the advantage that the UI is rendered from HTML/CSS, meaning that in terms of graphical appeal, there are no limits.
With TMS WEB Core v1.4, we did the necessary changes to the framework and the Electron specific controls to make these work as seamless as possible with Electron 8.

Enhancing the HTML-first approach

We’ve realized that not for all users looking at TMS WEB Core it was clear that using the Delphi IDE form designer for creating your web pages is by far not the only way to do it. While TMS WEB Core was developed from the ground up to facilitate this for Delphi developers familiar approach to create application forms, it was equally from the ground up built to enable the use of HTML/CSS based pages. This means that you can use existing HTML/CSS page templates which are not only created by web designers but can be obtained free or very cheap from various websites. Sometimes you get for $25 and extraordinary good looking web page template. Of course, we wanted to offer the capability to use such templates and from the Delphi IDE, you will basically just write the UI control logic and leave the page layout to HTML and CSS.

New TWebElementActionList

This new component, not to be confused with Delphi actions, facilitates easy hooking to events for all the HTML elements in page templates. It is a collection of actions that you define that happen when an event happens for a HTML element on the page. For example, the menu of your application could be a graphically very good looking HTML/CSS based animated menu and you can use the TWebElementActionList to define the actions that should happen when a specific item in this HTML/CSS menu is clicked. To do this, simple add the template HTML/CSS to your form, make sure to set a unique ID to each HTML element representing menu items and then add a TElementAction for each item in the menu. Define for the TElementAction.Event for example heClick and then the TElementAction.OnExecute event will be triggered when this menu item is clicked. In this OnExecute you could then for example add the UI control logic to show a DB grid with data, show a different form etc… As a Delphi developer, you have reused the graphical skills of a web designer and you just had to do a minimal effort to connect the logic in your application that is happening when the user interacts with the user-interface.

Increasing easy interfacing to additional popular back-end services

In TMS WEB Core we have already included the TWebClientConnecton, TWebClientDataSet, TWebDataSource to bring the pattern VCL Delphi developers have known ever since the inception of Delphi to bind data to UI controls. This concept also exists in TMS WEB Core. To make the binding to the back-end easy, we have a TWebXDataDataSet that shields all the complexities of communicating with a TMS XData REST server. We have the TWebmyCloudDataClientDataSet to shield this same complexity when our myCloudData cloud data storage service is used (free for all TMS ALL-ACCESS users). We also have the TWebSQLRestClientDataSet that interfaces to the Lazarus foundation open source SQLDBBridge REST server. And we TWebFirestoreClientDataSet for users wanting to use Google’s Firestore cloud data storage solutions.
With TMS WEB Core 1.4 Ravenna, we are pleased to offer 3 more easy out of the box solutions to connect to back-end services.

New TWebRadServerClientDataset

Delphi Enterprise or Delphi Architect SKU users have out of the box a license to Embarcadero Rad Server. Embarcadero Rad Server offers the technology to create REST services and is able to create a REST API for performing operations on databases in the back-end. While TMS WEB Core includes a component to perform REST requests to work with Embarcadero Rad Server out of the box, the new TWebRadServerClientDataset just makes it way easier to hook-up a UI with DB-aware controls to an Embarcadero Rad Server and perform through this dataset CRUD operations. Basically you set the URL to the data exposed as JSON based REST API from Embarcadero Rad Server and the TWebRadServerClientDataset middleware will perform all required HTTP GET,PUT,POST,DELETE requests, JSON handling behind the scenes and from the TMS WEB Core client you have just the DB-aware UI controls hooked up to it via a TWebDataSource.
We have added our todo-list demo that is using Embarcadero Rad Server just like we have this same todo-list demo. Other than the dataset, there is not much different from the demo using Firestore, TMS XData, SQLDBBridge, myCloudData. This shows how back-end agnostic TMS WEB Core web client applications can be.

New TWebDreamFactoryClientDataSet

From all low code back-end technologies, Dream Factory is without a doubt the most flexible one. With Dream Factory you can create REST APIs for access to data on the back-end by doing all the settings and parameterizing via a web interface. No need to do any programming, no need to dive into all technical details of HTTP(s) request, authentication, JSON packets, … Dream Factory does this all for you. We had Dream Factory as a very interesting back-end for TMS WEB Core already on the radar even before the inception of TMS WEB Core in 2018 as it is a very interesting technology for offering cloud data access for VCL Windows applications or FMX cross-platform applications, possibly further facilitated via a TMS Cloud Pack component.
But now we embark with our first bridge component, the TWebDreamFactoryClientDataSet that you can configure with the URL of your Dream Factory REST API and this bridge component does all the required communication to perform CRUD operations via its dataset to a database with a Dream Factory REST API. This dataset is then easily hooked up via a TWebDataSource to the TMS WEB Core DB-aware UI controls. Also here, we have taken the same todo-list demo and with minimal effort (basically replacing the dataset) our todo-list application talks to a Dream Factory based back-end.
While TWebDreamFactoryClientDataSet is a first step for easy Dream Factory REST API back-end access from TMS WEB Core web client applications, we’re eager to offer even more integration with the Dream Factory APIs in future TMS WEB Core versions as well as in future versions of the TMS FNC Cloud Pack that can be used in native Windows applications as well as native cross platform Delphi FireMonkey applications.

New TWebFaunaDBClientDataSet

Where Dream Factory offers automatic codeless REST API creation for access to a multitude of databases or services, FaunaDB is a cloud data storage service that hosts the data for you and offers as REST API to access it. It has similarities with our own myCloudData.net service and a few interesting angles. As such, to offer yet more freedom of choice, we have added the TWebFaunaDBClientDataSet component. You can use the web interface on your account at FaunaDB to design your tables and this can automatically be consumed when setting the proper URL to the TWebFaunaDBClientDataSet component. There is not much more to it, go to FaunaDB.com, setup your tables, set the URL to TWebFaunaDBClientDataSet and hookup DB-aware TMS WEB Core controls to this dataset via a datasource and you are up & running to perform CRUD operations on these tables.
Similar as for Embarcadero Rad Server and the Dream Factory REST API, we have a version of the todo-list demo that works with FaunaDB.

Get ready

The beta for TMS WEB Core v1.4 is around the corner. We are doing the testing, finishing the demos and writing the new documentation. TMS ALL-ACCESS users are in the front seat and can expect this beta accessible from their account shortly and after a couple of weeks testing, we will release this new 1.4.

We hope you are as excited as we are about the new TMS WEB Core v1.4. And there is more! It is this v1.4 feature set that will also be included in TMS WEB Core for Visual Studio Code. The project to offer a TMS WEB Core version integrated in the Microsoft free and cross platform Visual Studio Code IDE has significantly advanced in the past couple of months. A select group of beta users is currently test-driving the newest builds. Very shortly, TMS ALL-ACCESS users will also get access to the beta and after a few more weeks of testing/feedback/updates we plan to release this version as well.

Read More

Read More

Delphi XE8 TBindSourceDB component using MasterSource

The question is what is the correctly usage of MasterSource for TBindSourceDB Ex. 1 ListView with departaments with a navigator linkeds to a TBindSourceDB (the master). When navigator Insert button is pressed another listview becomes active, the cities ListView. Now the cities ListView with another navigator links to another TBindSourceDB, the cities (the detail). I need cities be mastersourced to departaments. How and where must do it? Both, the master and detail TBindSourceDB are linked to Firedac TSimpleDataSet components which have MasterSource property. I've filled that property on detail pointing to master component. The problem is: when the "detail" navigator button insert is pressed , the OnBeforePost from TSimpleDataSet fires, because it wants to do a Post!! and not fires the OnAfterInsert event. Which is the correct mode for work master->detail data with Firemonkey and TBindSourceDB components?.
Read More