Jump to content

All Activity

This stream auto-updates     

  1. Yesterday
  2. I am trying to pre-fill my editbox at runtime with todays date I know i can hardcode it and it works. As a matter of fact, it is how I found out that it requires the date in the format 'YYYY-MM-DD' However, I need to pre-fill my edit box with todays date (what ever it is at the time of runtime) e.g. W3EditBox1.InputType:= itDate W3EditBox1.Text:= getDate; I tried the following two routines but the first one does not return correct month & day and the second routine returns too much info (i need format such as "2018-01-18" function getDate: String; var Date: JDate; begin Date:= JDate.Create; result:= Date.toDateString; end; OR function getDate: String; var Date: JDate; begin Date:= JDate.Create; result:= FloatToStr(Date.getFullYear) + '-' + FloatToStr(Date.getMonth) + '-' + FloatToStr(Date.getDay); end; function getDate: String; function getJSDateTime:THandle; begin asm @result = new Date(); end; end; function JSDateToStr(const aValue:variant):String; Begin asm @result = (@aValue).toString(); end; end; begin result:= JSDateToStr(getJSDateTime); end; How can I get the correct date - e.g. 2018-01-18 to pre-fill my editbox?
  3. Allegro for Smart Mobile Studio (Yay!)

    So much time since my last login? Anyway, I should test that new alpha compiler from you. I'll tell you if it works. Thanks for the tips. The idea of Allegro4js is to add an abstraction layer that helps to port games, as you said. The original project is a bit out-of-date though.
  4. architecture

    For some this is the ultimate in application architecture, a set of completely separated layers with clearly defined tasks. One of the reasons would be that this type of application architecture facilitates client-server applications where these layers can be distributed over one or more servers. Like 'client'-'applicationserver'-'databaseserver'. In practice this is usually not so clear-cut. Business logic can be partly implemented on the client, partly on the server (and/or partly in the database as well). In case of server-side rendering most of the presentation tasks are transferred to the server, which leaves only razor-thin clients. And logical servers can be split over multiple physical servers too. Nevertheless it is a nice way of separating areas of concern. Having these separate layers, it must be possible to establish some kind of communication between them and this post is about some of the available mechanisms in Smart. Business Layer Let's say we have a completely separated business logic layer with a data-structure of sorts and all necessary functions to maintain this data. As an example see below the layer for a "ToDo" list type of application. type JToDoPerson = class id : integer; name : string; end; type JToDoTask = class id : integer; name : string; owner : string; statusidx : integer; end; type JToDoList = class tasks : Array of JToDoTask; persons : Array of JToDoPerson; statuses : array[0..2] of string := ['todo','in progress','done']; task : JToDoTask; person : JToDoPerson; constructor create; virtual; procedure addTask(TaskId: integer; TaskName, Source: string); procedure delTask(TaskId: integer; TaskName, Source: string); procedure updTask(TaskId: integer; owner: string; status: integer; Source: string); function getTask(TaskId: integer) : JToDoTask; procedure addPerson(PersonName, Source: string); procedure delPerson(PersonName, Source: string); end; In this demo, only the 'addPerson' method (adding a team-member to the team), is used. Procedure JToDoList.addPerson(PersonName, Source: string); begin person := JToDoPerson.Create; person.name := PersonName; inc(guid); person.id := guid; persons.add(person); end; Communication between Presentation layer and Business Logic layer. In Smart the presentation layer is the collection of Forms and their visual components. Assuming there is a form with a button somewhere which, when clicked, adds a new team-member, there are various ways in which communication between the business-logic and the presentation layer can happen. 1) simply call the appropriate method from the button onclick handler // 01 add person by method call todolist.addPerson('name01','W3Button1'); 2) use a custom event ('addPerson' event) // 02 add person by sending a custom event; asm @event = new CustomEvent('addPerson', { detail: ['name02','W3Button1'] }); end; browserapi.document.dispatchEvent(event); and in the constructor of the todo-list set up an event listener : // event listener for custom event browserapi.document.addEventListener('addPerson', procedure(e: variant) begin todolist.AddPerson(e.detail[0],e.detail[1]); end, false); 3) use a generic event ('businessLogic' event) and check for event-type // 03 add person by sending a generic event; var msg : variant := TVariant.CreateObject; msg.type := 'addPerson'; msg.payload01 := 'name03'; msg.payload02 := 'W3Button1'; var payload : variant := new JObject; payload.detail := JSON.stringify(msg); asm @event = new CustomEvent('businessLogic', @payload); end; browserapi.document.dispatchEvent(event); and in the constructor of the todo-list set up an event listener : // event listener for generic event browserapi.document.addEventListener('businessLogic', procedure(e: variant) begin var msg := JSON.parse(e.detail); If msg.type = 'addPerson' then begin todolist.addPerson(msg.payload01, msg.payload02); end; end, false); 4) use an inter-process event ('postMessage' event) // 04 add person by sending postMessage; browserapi.window.postMessage(['addPerson','name04','W3Button1'],'*'); and in the constructor of the todo-list set up an event listener : browserapi.window.onmessage := procedure(evt:variant) begin if evt.data[0] = 'addPerson' then begin todolist.AddPerson(evt.data[1],evt.data[2]); //'name01','W3Button1' end; end; There are subtle differences between event-methods 2-4, but essentially they perform very similar. I personally prefer using postMessage (4) as it involves the least amount of coding. All of these methods work for single-device type applications (all 3 layers on client) and on fat-client client/server type applications (data on server, rest on client). 5) use web-sockets as communication method between server and client // 05 add person by sending a 'message' message using websocket; var msg : variant := TVariant.CreateObject; msg.type := 'addPerson'; msg.payload01 := 'name05'; msg.payload02 := 'W3Button1'; ws.send(JSON.stringify(msg)); and in the constructor of the todo-list set up an event listener : asm @ws = new WebSocket('ws://localhost:1234', 'echo-protocol'); end; ws.addEventListener('message', procedure(e: variant) begin var msg := JSON.parse(e.data); If msg.type = 'addPerson' then begin todolist.AddPerson(msg.payload01, msg.payload02); end; end, false); This method works for both fat-client and thin-client client/server applications. The server used here is a simple node echo server ( see featured demos ) or, alternatively, in plain js : //Create server and listen var http = require('http'); var server = http.createServer(function(request, response) {}); server.listen(1234, function() { console.log((new Date()) + ' Server is listening on port 1234'); }); //Create Web Socket Server var WebSocketServer = require('websocket').server; wsServer = new WebSocketServer({ httpServer: server }); var count = 0; var clients = {}; //Listening for Connections wsServer.on('request', function(r){ // Code here to run on connection //Accept the connection var connection = r.accept('echo-protocol', r.origin); // Specific id for this client & increment count var id = count++; // Store the connection method so we can loop through & contact all clients clients[id] = connection; console.log((new Date()) + ' Connection accepted [' + id + ']'); //Listen for incoming messages and broadcast // Create event listener connection.on('message', function(message) { // The string message that was sent to us var msgString = message.utf8Data; console.log('received ' + msgString); // Loop through all clients for(var i in clients){ // Send a message to the client with the message clients[i].sendUTF(msgString); var j = i + 1; console.log('sent ' + msgString + ' to client ' + j); } }); //Listen for client disconnecting connection.on('close', function(reasonCode, description) { delete clients[id]; console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.'); }); }); The funny thing is that this server propagates these events to all connected clients. So adding a team-member on any client auto-updates the team array on all other clients, without any user interaction. Cool. Communication between Presentation layer and data layer. Data-binding is a mechanism which synchronises data-elements with UI-components. The above event-mechanisms could conceivably also be used to implement a simple data-binding mechanism. The addPerson method f.i., once invoked, can send a message to the presentation layer ('personAdded') person := JToDoPerson.Create; person.name := PersonName; inc(guid); person.id := guid; persons.add(person); asm @event = new CustomEvent('personAdded', { detail: PersonName }); end; browserapi.document.dispatchEvent(event); which in it's turn can sync UI-components (TMemo) with the new data : // a Form's 'InitializeObject' section browserapi.document.addEventListener('personAdded', procedure(e: variant) begin W3Memo1.Text := W3Memo1.Text + #10 + e.detail; end, false); Project-source : <SMART> <Project version="2" subversion="9"> <Name>temp</Name> <Created>T00:00:00.000</Created> <Modified>2018-01-17T14:26:47.488</Modified> <Version> <Major>0</Major> <Minor>0</Minor> <Revision>0</Revision> </Version> <VendorSpecific> <Apple> <FormatDetection>1</FormatDetection> <StatusBarStyle>black</StatusBarStyle> <WebAppCapable>1</WebAppCapable> </Apple> <ChromeApp> <Kiosk>0</Kiosk> <KioskOnly>1</KioskOnly> <OfflineEnabled>1</OfflineEnabled> </ChromeApp> <Cordova> <WidgetID></WidgetID> <AllowIntent>http://*/* https://*/* tel:* sms:* mailto:* geo:*</AllowIntent> </Cordova> </VendorSpecific> <Options> <Compiler> <Assertions>1</Assertions> <Optimize>1</Optimize> <HintsLevel>1</HintsLevel> <ProjectSearchPath></ProjectSearchPath> </Compiler> <Codegen> <Obfuscation>0</Obfuscation> <RangeChecking>0</RangeChecking> <InstanceChecking>0</InstanceChecking> <ConditionChecking>0</ConditionChecking> <LoopChecking>0</LoopChecking> <InlineMagics>1</InlineMagics> <IgnorePublishedInImplementation>0</IgnorePublishedInImplementation> <EmitSourceLocation>0</EmitSourceLocation> <EmitRTTI>0</EmitRTTI> <Devirtualize>1</Devirtualize> <MainBody>1</MainBody> <CodePacking>0</CodePacking> <SmartLinking>1</SmartLinking> <Verbosity>1</Verbosity> </Codegen> <ConditionalDefines> <HandleExceptions>1</HandleExceptions> <AutoRefresh>0</AutoRefresh> <LegacySupportForIE>0</LegacySupportForIE> </ConditionalDefines> <Linker> <SourceMap>0</SourceMap> <CompressCSS>0</CompressCSS> <GenerateAppCacheManifest>1</GenerateAppCacheManifest> <GenerateChromeAppManifest>0</GenerateChromeAppManifest> <GenerateFireFoxManifest>0</GenerateFireFoxManifest> <GenerateWebAppManifest>1</GenerateWebAppManifest> <GenerateWidgetPackageConfigXML>0</GenerateWidgetPackageConfigXML> <GenerateCordovaConfigXML>0</GenerateCordovaConfigXML> <ExternalCSS>1</ExternalCSS> <Theme>default.css</Theme> <CustomTheme>0</CustomTheme> <EmbedJavaScript>1</EmbedJavaScript> </Linker> <Output> <JavaScriptFileName>main.js</JavaScriptFileName> <HtmlFileName>index.html</HtmlFileName> <OutputFilePath>www\</OutputFilePath> </Output> <Import /> <Execute> <ServeManifest>0</ServeManifest> <Server>1</Server> <CustomFile></CustomFile> <LoadCustomFile>0</LoadCustomFile> <PauseAfterExecution>0</PauseAfterExecution> <ExecuteType>0</ExecuteType> </Execute> <WebFonts> <usewebfonts>1</usewebfonts> <webfontitem> <fontname>Ubuntu</fontname> <fonturl>https://fonts.googleapis.com/css?family=Ubuntu</fonturl> </webfontitem> <webfontitem> <fontname>Ubuntu</fontname> <fonturl>https://fonts.googleapis.com/css?family=Ubuntu</fonturl> </webfontitem> </WebFonts> </Options> <Files> <File type="main"> <Name>temp</Name> <Created>2018-01-16T18:32:05.128Z</Created> <Modified>2018-01-17T11:03:42.612</Modified> <Source> <![CDATA[uses Globals, ecma.json, SmartCL.System, Unit1; {$IFDEF SMART_INTERNAL_HANDLE_EXCEPTIONS} try {$ENDIF} var Application := TApplication.Create; Application.RunApp; /* //check if local storage exists. If yes then writeln('getting data'); var todolistjson := JSON.parse(browserapi.window.localStorage.getItem("todolist")); writeln(todolistjson.persons.length); //and then fill up todolist from todolistjson; browserapi.document.addEventListener('savedata', procedure(e: variant) begin writeln('saving data'); browserapi.window.localStorage.setItem("todolist", JSON.stringify(e.detail)); //todolist end, false); */ {$IFDEF SMART_INTERNAL_HANDLE_EXCEPTIONS} except on e: Exception do ShowMessage(e.Message); end; {$ENDIF} ]]> </Source> </File> <File type="unit"> <Name>Unit1</Name> <Created>2018-01-16T18:32:05.128Z</Created> <Modified>2018-01-16T20:46:22.946</Modified> <Source> <![CDATA[unit Unit1; interface uses Pseudo.CreateForms, // auto-generated unit that creates forms during startup System.Types, SmartCL.System, SmartCL.Components, SmartCL.Forms, SmartCL.Application, Form1; type TApplication = class(TW3CustomApplication) end; implementation end.]]> </Source> </File> <File type="form"> <Name>Form1</Name> <Created>2018-01-16T18:32:05.128Z</Created> <Modified>2018-01-17T14:26:47.486</Modified> <Source> <![CDATA[unit Form1; interface uses System.Types, System.Types.Convert, System.Objects, System.Time, SmartCL.System, SmartCL.Time, SmartCL.Graphics, SmartCL.Components, SmartCL.FileUtils, SmartCL.Forms, SmartCL.Fonts, SmartCL.Theme, SmartCL.Borders, SmartCL.Application, busLogic, Ecma.json, SmartCL.Controls.Button, SmartCL.Controls.Memo, SmartCL.Controls.RadioGroup; type TForm1 = class(TW3Form) procedure W3Button1Click(Sender: TObject); private {$I 'Form1:intf'} protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; end; implementation uses Globals; { TForm1 } procedure TForm1.W3Button1Click(Sender: TObject); begin If W3RadioGroup1.Items[0].Checked then begin // 01 add person by method call todolist.addPerson('name01','W3Button1'); end; If W3RadioGroup1.Items[1].Checked then begin // 02 add person by sending custom event; asm @event = new CustomEvent('addPerson', { detail: ['name02','W3Button1'] }); end; browserapi.document.dispatchEvent(event); end; If W3RadioGroup1.Items[2].Checked then begin // 03 add person by sending generic event; var msg : variant := TVariant.CreateObject; msg.type := 'addPerson'; msg.payload01 := 'name03'; msg.payload02 := 'W3Button1'; var payload : variant := new JObject; payload.detail := JSON.stringify(msg); asm @event = new CustomEvent('businessLogic', @payload); end; browserapi.document.dispatchEvent(event); end; If W3RadioGroup1.Items[3].Checked then begin // 04 add person by sending postMessage; browserapi.window.postMessage(['addPerson','name04','W3Button1'],'*'); end; If W3RadioGroup1.Items[4].Checked then begin // 05 add person by sending sendMessage using websocket; var msg : variant := TVariant.CreateObject; msg.type := 'addPerson'; msg.payload01 := 'name05'; msg.payload02 := 'W3Button1'; ws.send(JSON.stringify(msg)); end; end; procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} W3RadioGroup1.Add('01 - method call'); W3RadioGroup1.Add('02 - custom event'); W3RadioGroup1.Add('03 - generic event'); W3RadioGroup1.Add('04 - postMessage'); W3RadioGroup1.Add('05 - websocket'); W3Memo1.Text := 'List of persons'; browserapi.document.addEventListener('personAdded', procedure(e: variant) begin writeln('personAdded'); W3Memo1.Text := W3Memo1.Text + #10 + e.detail; end, false); end; procedure TForm1.Resize; begin inherited; end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end.]]> </Source> <Design> <![CDATA[<?xml version="1.0" encoding="utf-16"?> <Form version="2" subversion="9"> <Created>2018-01-16T18:32:05.128</Created> <Modified>2018-01-17T14:25:27.765</Modified> <object type="TW3Form"> <Caption>W3Form</Caption> <Name>Form1</Name> <object type="TW3Button"> <Caption>add person</Caption> <Width>134</Width> <Top>240</Top> <Left>104</Left> <Height>32</Height> <Name>W3Button1</Name> <OnClick>W3Button1Click</OnClick> </object> <object type="TW3Memo"> <Text>W3Memo</Text> <Width>184</Width> <Top>288</Top> <Left>80</Left> <Height>192</Height> <Name>W3Memo1</Name> </object> <object type="TW3RadioGroup"> <Width>285</Width> <Top>32</Top> <Left>32</Left> <Height>196</Height> <Name>W3RadioGroup1</Name> </object> </object> </Form>]]> </Design> <AutoCreate> <IsAutoCreate>1</IsAutoCreate> <IsMainForm>1</IsMainForm> <Order>1</Order> </AutoCreate> </File> <File type="unit"> <Name>busLogic</Name> <Created>2018-01-16T18:33:01.624Z</Created> <Modified>2018-01-17T11:29:14.034</Modified> <Source> <![CDATA[unit busLogic; interface uses System.Types, System.Types.Convert, SmartCL.System; type JToDoPerson = class id : integer; name : string; end; type JToDoTask = class id : integer; name : string; owner : string; statusidx : integer; end; type JToDoList = class tasks : Array of JToDoTask; persons : Array of JToDoPerson; statuses : array[0..2] of string := ['todo','in progress','done']; task : JToDoTask; person : JToDoPerson; constructor create; virtual; procedure addTask(TaskId: integer; TaskName, Source: string); procedure delTask(TaskId: integer; TaskName, Source: string); procedure updTask(TaskId: integer; owner: string; status: integer; Source: string); function getTask(TaskId: integer) : JToDoTask; procedure addPerson(PersonName, Source: string); procedure delPerson(PersonName, Source: string); function LoadList: JToDoList; function GetList: JToDoList; end; implementation uses Globals, Ecma.json; Constructor JToDoList.Create; begin inherited Create; // reacts to custom event browserapi.document.addEventListener('addPerson', procedure(e: variant) begin todolist.AddPerson(e.detail[0],e.detail[1]); end, false); // reacts to generic event browserapi.document.addEventListener('businessLogic', procedure(e: variant) begin var msg := JSON.parse(e.detail); If msg.type = 'addPerson' then begin todolist.addPerson(msg.payload01, msg.payload02); end; end, false); // reacts to postMessage browserapi.window.onmessage := procedure(evt:variant) begin if evt.data[0] = 'addPerson' then begin todolist.AddPerson(evt.data[1],evt.data[2]); //'name01','W3Button1' writeln(todolist.persons[todolist.persons.count-1].id); writeln(todolist.persons[todolist.persons.count-1].name); asm @event = new CustomEvent('savedata', { detail: todolist }); end; browserapi.document.dispatchEvent(event); end; end; // reacts to sendMessage using websockets asm @ws = new WebSocket('ws://localhost:1234', 'echo-protocol'); end; ws.addEventListener('message', procedure(e: variant) begin var msg := JSON.parse(e.data); If msg.type = 'addPerson' then begin todolist.AddPerson(msg.payload01, msg.payload02); end; end, false); end; Procedure JToDoList.addTask(TaskId: integer; TaskName, Source: string); begin task := JToDoTask.Create; task.id := TaskId; task.name := TaskName; task.owner := ''; task.statusidx := 0; tasks.add(task); end; Procedure JToDoList.delTask(TaskId: integer; TaskName, Source: string); begin for var i := 0 to tasks.length -1 do begin if tasks[i].id = TaskId then begin tasks.Delete(i); end; end; end; Procedure JToDoList.updTask(TaskId: integer; owner: string; status: integer; Source: string); begin for var i := 0 to tasks.length -1 do begin if tasks[i].id = TaskId then begin tasks[i].owner := owner; tasks[i].statusidx := status; end; end; end; Function JToDoList.getTask(TaskId: integer) : JToDoTask; begin for var i := 0 to tasks.length -1 do begin if tasks[i].id = TaskId then begin result := tasks[i]; end; end; end; Function JToDoList.LoadList: JToDoList; begin // end; Function JToDoList.GetList: JToDoList; begin // end; Procedure JToDoList.addPerson(PersonName, Source: string); begin person := JToDoPerson.Create; person.name := PersonName; inc(guid); person.id := guid; persons.add(person); asm @event = new CustomEvent('personAdded', { detail: PersonName }); end; browserapi.document.dispatchEvent(event); end; Procedure JToDoList.delPerson(PersonName, Source: string); begin for var i := 0 to persons.length -1 do begin if persons[i].name = PersonName then begin person := persons[i]; for var j := 0 to tasks.length -1 do begin if tasks[j].owner = PersonName then begin If tasks[j].statusidx = 1 then begin //if 'in progress' tasks[j].statusidx := 0; //reset to 'todo' tasks[j].owner := ''; //unassign task end; end; end; end; end; end; end. ]]> </Source> </File> <File type="unit"> <Name>globals</Name> <Created>2018-01-16T18:41:47.853Z</Created> <Modified>2018-01-17T11:12:16.808</Modified> <Source> <![CDATA[unit globals; interface uses System.Types, System.Types.Convert, SmartCL.System, busLogic; var todolist : JToDoList; event: variant; guid : integer; ws : variant; implementation initialization // ToDoList := JToDoList.Create; guid := 0; end. ]]> </Source> </File> </Files> <Target>Browser</Target> <Generator>Visual Components Project</Generator> </Project> </SMART>
  5. Last week
  6. When is the next contest?

    A repost from Facebook - dated January 9 "Mid february it's time for a Smart competition again! This time the winner recieves the Asus Tinkerboard which is an absolute power-house of a SBC (single board computer). We ourselves use this board for running Smart Mobile Studio via EXAGEAR (x86 emulation for ARM devices), and also as a node.js and Android deployment device. Like our sister group, Delphi Developer, we are printing a special edition white "retro case" for this fantastic little machine (fresh off the mint, they were done printing yesterday at 25 hours each). The lucky winner recieves the following (pre assembled ofcourse): 1 x "Special Edition" White Retro Case 1 x Asus Tinkerboard 1 x 32 Gb Samsung class 10 SD card 1 x Fan to ensure reliable operational temperature 1 x Red light diode power indicator 1 x Smart ready Ubuntu installation (*) Samba is setup and registers on the network as "SmartDevice". PM2 which is the node.js clustering software used to run large Smart Mobile Studio cloud services is also "ready to go". Sftp is likewise there, so you can upload your compiled code as part of your build process (Smart has project options for this). More information about the competition will be released in due time (at least a month from now), but if you have been waiting for a nice competition - now is the chance to create, port or implement something amazing 😎 Looking forward to the submissions. We are lucky to have so many fine developers using Smart!"
  7. Smart Test Framework

    Thank you, great (System.diagnostics ==> smartcl.diagnostics)
  8. Smart Test Framework

    Hey, here is the SMS test framework fixed! Projct download: ProjTester
  9. Currently, the listbox has events for handling items that have been clicked or selected......but I need a list box item that can be double clicked Would it be possible to add this to the RTL? e.g. TW3ListBox = class(TW3ScrollControl) private FOnItemDblClick: TW3ListBoxItemDataEvent; procedure SetOnItemDblClick(Value: TW3ListBoxItemDataEvent); protected procedure HandleItemDblClick(Sender: TObject); public published property OnItemDblClick: TW3ListBoxItemDataEvent read FOnItemDblClick write SetOnItemDblClick; end; implementation procedure TW3ListBox.HandleItemDblClick(Sender: TObject); begin if not (csDestroying in ComponentState) then begin for var i:=0 to FFilteredItems.Count-1 do begin var Item := TW3ListBoxItemData(FFilteredItems[i]); if Item.ItemObject=Sender then begin if MultiSelect then begin Item.Selected := not Item.Selected; if Item.Selected then FSelectedIndex := Item.Index else FSelectedIndex := -1; end else SelectedIndex := Item.Index; if Assigned(FOnItemDblClick) then FOnItemDblClick(Self, Item); if Assigned(FOnSelected) then FOnSelected(Self, Item.Index); break; end; end; end; end; procedure TW3ListBox.SetOnItemDblClick(Value: TW3ListBoxItemDataEvent); begin FOnItemDblClick := Value; end; procedure TW3ListBox.ShowListItem(Item: TW3ListBoxItemData); begin if Assigned(FOnShowItem) then FOnShowItem(Self,Item) else if Item.ItemObject is TW3Label then TW3Label(Item.ItemObject).Caption:=Item.Caption else TW3CustomControl(Item.ItemObject).InnerText:=Item.Caption; Item.ItemObject.OnClick:=@HandleItemClick; Item.ItemObject.OnDblClick:=@HandleItemDblClick; end; end.
  10. Vibration API

    If you make a Phonegap app, then it's simply: PhoneGap.Notification.vibrate(1000);
  11. shoestring framework

    The documentation for the native framework can be found here
  12. Earlier
  13. Vibration API

    try this browserapi.window.navigator.vibrate(200); // vibrate for 200ms browserapi.window.navigator.vibrate([100,30,100,30,100,200,200,30,200,30,200,200,100,30,100,30,100]); // Vibrate 'SOS' in Morse. The vibration api does not work on ios safari, opera and edge
  14. Vibration API

    I am trying to use the vibration API on android phone but it's not working - seems there is something I'm not doing right I have tried the code below, but none is working. Is there a way to create vibration using SMS code without cordova plugin? asm navigator.vibrate(500); end; and asm window.navigator.vibrate([500]); end; and asm function vib() { navigator.vibrate([500]); } vib(); end;
  15. Overriding TW3ListBoxItemData style

    hmmm, how'd i miss that? thanks
  16. Overriding TW3ListBoxItemData style

    And when you have a pretty short list like this, but with complicated items, it's a good idea to set W3Listbox1.RecycleControls := False;
  17. Overriding TW3ListBoxItemData style

    Found the problem in your CSS. Try this: .XListBoxItemSelectedStyle{ background-color: #000000; color: #FFFFFF } .XListBoxItemStyle{ color: #000000; background-color: #FFFFFF
  18. Database Examples

    @lennart What is "TW3WebSQLCustomTransaction" I only find "TW3WebSQLTransaction"....however, the GetWriteTransaction method expects a "TW3CustomDbTransaction" which seems to work. Also, is there a reason why you would NOT also put the "checking of database active property" and the "creation of table" in the Application object? e.g. procedure TApplication.ApplicationStarting; var Transaction: TW3CustomDbTransaction; begin //setup database engine FDatabase:=TW3WebSQLDatabase.Create; FDatabase.DBName:={$I 'app:name'}; FDatabase.DBDescription:='Database for ' + {$I 'app:name'}; FDatabase.DBSize:=(1024 * 1024) * 4; // activate database try if not Datastore.Active then Datastore.Active := True; except on e: exception do begin writeln("Failed to activate database: "); writeln(e.message); exit; end; end; // Create our table // Get new write transaction if Datastore.GetWriteTransaction(Transaction) then begin try Transaction.Execute("create table if not exists customers (id integer primary key asc, name string);",[]); finally if Transaction.LastFailed then WriteLn(Transaction.LastError); Transaction.Free; end; end else raise Exception.Create('Failed to create write transaction error'); inherited; end;
  19. Overriding TW3ListBoxItemData style

    @lennart, @jarto Testing the latest update, I am trying to override the TW3ListBoxItemData's "RemoveSelectedStyle" and "SetSelectedStyle" methods. However, I can't seem to get the StyleClass property to work. However, I can do color changes at runtime. procedure TXListBoxItemData.RemoveSelectedStyle; begin //TXListBoxItem(ItemObject).StyleClass:= 'XListBoxItemStyle'; //does not work //TXListBoxItem(ItemObject).Label.StyleClass:= 'XListBoxItemStyle'; //does not work TXListBoxItem(ItemObject).Label.Color:= clWhite; //works TXListBoxItem(ItemObject).Label.Font.Color:= clBlack; //works end; procedure TXListBoxItemData.SetSelectedStyle; begin //TXListBoxItem(ItemObject).StyleClass:= 'XListBoxItemSelectedStyle'; //does not work //TXListBoxItem(ItemObject).Label.StyleClass:= 'XListBoxItemSelectedStyle'; //does not work TXListBoxItem(ItemObject).Label.Color:= clBlack; //works TXListBoxItem(ItemObject).Label.Font.Color:= clWhite; //works end; It seems that the StyleClass will not happen instaneously. Is there a method that has to be called after setting StyleClass to get it to refresh immediately? When I select an item, I do not see the Style change until I select another item, then the previous item I selected, changes Download from Github Thanx
  20. New Alpha update

    New update available: 2.9.9.102 In this one I've fixed some bugs in TW3ListBox and TW3CheckListBox. @IElite Have a look at the TW3CheckListBox source to see how you can control the creation of TW3ListBoxItemData. I also added TW3ListBox.Selected[Index] so that you can easily toggle selected on/off for items.
  21. New Alpha update

    I'll try to write an example today. Edit: Actually, while doing it I found some bugs too. I will fix those too.
  22. Database Examples

    @lennart THANKS! Please, I would love to see a sqlite example when you find the time. Thats the one I have been working with the longest trying to do persistent data
  23. New Alpha update

    Thanks for the TW3ListBox and TW3CheckListBox changes! How do you override the creation of the TW3ListBoxItemData ? Specifically how to override the SetSelected? This is something I am very interested in doing Here is a ListBox example I created for demo purposes that uses a custom listbox item here is the code on github
  24. New Alpha update

    exciting to see the update. smartcl.pas needs // Implementation of storage-device "Browser:" //SmartCL.StorageDevice.Browser, as SmartCL.StorageDevice.Browser, file doesn't exist
  25. New Alpha update

    After a long break, a new update is available: 2.9.9.97 IDE: - Added support for search paths - Updated SynEdit - Bug fixes - ACE (TW3AceEditor) added to the Component Palette RTL: - New units: - System.Collections - System.StorageDevice - Marjor improvements to TW3Dataset, TW3DatasetFilter and WebSQL - Bug fixes and improvements to TextParser - Bug fixes to WebFonts support - Moved TCriticalSection to System.Types - Improvements to TW3ListBox and TW3CheckListBox: - Support for SelectedIndex and automatic change of style background for selected items - Support for MultiSelect - Possibility to override creation of TW3ListBoxItemData - Allows use of own classes and properties - Allows overriding SetSelected to control what styling changes should be made when items are selected Bug fixes to many demos
  26. Save and load SQLite Database to local storage

    ok thanks, I see lynkfs is also having troubles
  27. Requesting a trial key

    Hi Allen, Thank you for reporting this. We had some temporary server problems. I just tested this and now it does work.
  28. SQLite Loadfromstream

    This code snippet saves a SQLite database to local storage and reloads it again. All goes fine up till the end (LoadFromStream) but leaves the db in an inactive state Any suggestions ? var MyStream : TStringStream; MyStream := TStringStream.Create; db.SaveToStream(MyStream,true); var textdata3 := MyStream.DataString; //save textdata3 to local storage var LocalStorage2 := TW3LocalStorage.Create; LocalStorage2.Open('sqlite'); LocalStorage2.SetKeyStr('stream',textdata3); LocalStorage2.Close; //read textdata3 from local storage LocalStorage2.Open('sqlite'); textdata3 := LocalStorage2.GetKeyStr('stream','unknown'); LocalStorage2.Close; MyStream.DataString := textdata3; db.LoadFromStream(MyStream); //all good up to here writeln(db.active); //false
  1. Load more activity
×