Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Reputation Activity

  1. Like
    jorn got a reaction from piXelicidio in Auto payment for SMS   
    Mail received, and mission accomplished ūüôā
  2. Thanks
    jorn reacted to Daniel Eiszele in NodeJS Route Manager   
    The attached uRouter.pas file is something I've been playing with for the last couple of days. It is basically a route manager (think ExpressJS) for Smart Mobile Studio.  It isn't fully baked at this point in time and I probably won't progress it far past this point as it already meets my needs from a REST Service perspective. Feel free to use it as a base for your own efforts though. It works in both http and https environments.  Just create a global var on your NodeProgram object to hold it and instantiate it after the server object is created with the following call:
    FRouter := TRouteManager.Create(FServer); Do not manually set the request handler as the constructor sets that up for you.
    To create routes, use the following syntax:
    FRouter.get('/', procedure (const Request: TNJHttpRequest; const Response: TNJHttpResponse; data : TRequestData; data : TRequestData) begin Response.end('You Selected the Root Directory'); end); FRouter.post('/', procedure (const Request: TNJHttpRequest; const Response: TNJHttpResponse; data : TRequestData; data : TRequestData) begin Response.end('You Selected a post request'); end); FRouter.put('/', procedure (const Request: TNJHttpRequest; const Response: TNJHttpResponse; data : TRequestData; data : TRequestData) begin Response.end('You Selected a put request'); end); FRouter.delete('/', procedure (const Request: TNJHttpRequest; const Response: TNJHttpResponse; data : TRequestData; data : TRequestData) begin Response.end('You Selected a delete request'); end); To access data when it's available, you may manually retrieve it from the request object or use one of two functions on the data / TRequestdata object as per below.
    data.BodyAsBuffer(procedure (_Buffer : JNodeBuffer) begin Response.End('Here is the buffer: ' + _Buffer.toString('utf8'); end); or
    data.BodyToFile('C:\temp\aFile.pdf',procedure(err : JError) begin if assigned(err) then begin Response.end('Something went wrong'); end else begin Response.end('File has been saved'); end end); Similarly, url parameters can be read off the TRequestdata object as follows.
    Response.end('You requested id: ' + data.Params.ReadString('id')); Let me know what you think
  3. Thanks
    jorn reacted to JimKueneman in Converting a Lazarus/Delphi library   
    With the help of Jarto and a few here I have almost 5000 lines of a Lazarus/Delphi library that implements a mature custom TCP protocol compiling with SMS with just a few {$IFDEF DWSCRIPT}'s required so far.  I have about 1000 more line to go before I can give it a full test but I do have a Websocket connected to the library and have sent messages to the library from a Lazarus program and it received and decoded them correctly.  I was only working on it for a few hours on and off yesterday so I am amazed and very happy.  Hopefully it will all run correctly in the end but at least the compiler thinks it should.
    The key websites that have helped me get handle on thing are here but so far I have not used them directly, SMS has handled everything in the compile so far but I do have a few dynamic byte array that I need to mimic which will need this information....
    The ultimate goal is to create phone apps 
  4. Like
    jorn reacted to DavidRM in License Serial Number invalid   
    Just to mention it... I had this problem too. I never received an email with my new information. I was able to get it from clientarea.*, though.
  5. Like
    jorn reacted to jarto in SMS and the Ionic Framework   
    Hi Thomas,
    Thank you for an interesting idea. At the moment we are working on the new Visual Designer. Once it's finished, it's way easier to create beautiful and functional PWA apps without having to create all by code. So, the plan is:
    Finish the Designer and have it support all current Visual components. (90% ready) Add non-visual components to the component palette Release a version Once we have that out, we'll be able to plan our next steps.
  6. Like
    jorn reacted to Daniel Eiszele in Learning Smart Mobile Studio   
    I would also suggest Jon Lennart Aasenden's blog, https://jonlennartaasenden.wordpress.com/news/ as invaluable for understanding the Smart Mobile studio paradigm. His blog is not solely about Smart Mobile Studio but putting them in as search terms should return a wealth of knowledge on the subject.
  7. Like
    jorn reacted to lynkfs in Learning Smart Mobile Studio   
    Look at¬†PrimoŇĺ Gabrijelńćińć's¬†book¬†on SMS, available on¬†https://leanpub.com/asmartbook
    Very valuable and I still consult it on a regular basis
    There is some info on http://www.pp4s.co.uk/main/smart-gettingstarted.html as well
  8. Like
    jorn reacted to lynkfs in menu component   
    Probably not the most inspiring topic, but just sharing a menu component I needed for some project.
    There are quite a few css based menu components around, but I wanted to have a pure smart one.
    This one has an unlimited number of submenus and is instantiated as a hamburger menu on a toolbar

      Hamburger := TCHMenu.Create(self);   //nodes : id,parent,description,procedure   Hamburger.Add('root','','Hamburger menu');       //root   Hamburger.Add(  'projects','root','Projects');   Hamburger.Add(    'project0','projects','New project');   Hamburger.Add(    'project1','projects','Open project');   Hamburger.Add(    'project2','projects','Delete project');   Hamburger.Add(  'designers','root','Designer');   Hamburger.Add(    'designer0','designers','Domain info',clickproc);   //<== execproc   Hamburger.Add(    'designer1','designers','Data development'); ...   Hamburger.Add(    'designer5','designers','Goal Metrics'); //some test cases below   Hamburger.Add(      'test','project0','test3'); // test level 3   Hamburger.Add(    'designer5','designers','Goal Metrics');     //test on double entries   Hamburger.Add(  'test0','root','test',procedure begin writeln('clickproc'); end);  //test on no children   Hamburger.Add(    'designer6','designers','extra test');       //test on out of order demo and project files on the .../Menu subdir

  9. Thanks
    jorn reacted to jarto in Another GumRoad License Problem   
    @KultiVator A license was generated and sent in the morning of May 30th. Can you please check if the license happens to have gone to your spam folder? I'll forward you the e-mail containing the license also now.
    Edit: I also sent you a private message here with the license key
  10. Thanks
    jorn reacted to jarto in TW3StringGrid is available   
    A new update is available in the development-channel of SmartUpdate. It contains a completely new Grid: TW3StringGrid. It's a completely new design, which was made to be very fast and able to handle lots of data. This is achieved through dynamic drawing: Only the visible grid lines are rendered.ÔĽŅ
    There is a new StringGrid-demo in the Featured Demos. It downloads a json file and populates the grid with data from it.
    TW3StringGrid supports six different column types:
    Text (column class TW3StringGridTextColumn) Numeric (column class  TW3StringGridNumericColumn) EditBox (column class TW3StringGridEditColumn) ComboBox (column class TW3StringGridComboColumn) Checkmark (column class TW3StringGridCheckmarkColumn) Button (column class TW3StringGridButtonColumn) Columns are created by calling:
    If no ColumnClass is given, a Text column is created.
    Column properties:
    Caption Width BorderType Default is btLightBorderRight. Set to btNone if you don't want any vertical borders. Backgroundtype Default is btNone to let the line color through. AlignText (The same way as in TW3Label) taLeft (default) taCenter taRight SelectOptions (for TW3StringGridComboColumn only) This is an array of selectable values. First value (index 0) is the value for no selection. For example: SelectOptions:=['','First','Second','Third']; RowBorderType: Default is btLightBorderBottom. Set to btNone if you don't want any horizontal borders. RowBackgroundType: Default is bsListItemBackground. Set to bsDecorativeListItemBackground (or test other backgrounds) to change the background style for even rows. RowOddBorderType: Default is btLightBorderBottom. Set to btNone if you don't want any horizontal borders. Affects odd rows. RowOddBackgroundType: Default is bsListItemBackground. Set to bsDecorativeListItemBackground (or test other backgrounds) to change the background style for odd rows. Grid properties:
    RowCount: Set number of rows to show FixedColumns: How many columns should be fixed (aka not scrollable horizontally) LineHeight MultiSelect Events:
    OnCellClick: Is triggered when the row is clicked. OnCellChanged: Is triggered when cell content changes through editing (for example: through editing) OnDrawGridLineTheme: Can be used to set custom backgrounds and borders for a row. (for example, set background to bsErrorBackground for lines that should be highlighted to the user) Methods:
    InvalidateGrid: Triggers a repaint of the grid. Sort Sorting
    TW3StringGrid supports sorting based on one of multiple columns. Clicking on the column headers sets or reverses sort order. You can also control sorting in code:
    procedure AddSortColumn(Index: Integer; SortOrder: TW3SortOrder = soNormal); overload; procedure AddSortColumn(Col: TW3StringGridColumn; SortOrder: TW3SortOrder = soNormal); overload; procedure SetSortColumn(Index: Integer; SortOrder: TW3SortOrder = soNormal); overload; procedure SetSortColumn(Col: TW3StringGridColumn; SortOrder: TW3SortOrder = soNormal); overload; procedure ToggleSortColumn(Index: Integer); For example:
    Grid.SortOptions.AddSortColumn(3,soReverse); //Set primary sort column Grid.SortOptions.AddSortColumn(1); //Add secondary sort columns Grid.Sort; Working with sorted data
    When the Grid is sorted, it only affects how data is shown. Sorting does not change Grid data itself at all. When you work with a sorted grid events and indexes (for example SelectedIndex) always refer to the index in the grid data itself and NOT the visible line number.
    TW3StringGrid uses these events:
    TW3StringGridColumnEvent = procedure(const Sender: TW3StringGridColumn; const Row: Integer); TW3StringGridEvent = procedure(const Sender: TObject; const Row, Col: Integer); If you have a Grid where "Australia" is on line 2, SelectedIndex:=2 selects that row regardless of how the grid is sorted. Clicking on that row or changing data on that row also returns Row=2 regardless of how the grid is sorted.
  11. Like
    jorn got a reaction from IElite in Embed SMS Form Project in WordPress Page?   
    I can't tell exactly what's wrong in your case, but it's perfectly doable.
    We have done it here, for example:
  12. Thanks
    jorn reacted to jarto in Beware of box shadows!   
    I have been working on a new TW3StringGrid for Smart Mobile Studio. The original plan was to include it in 3.0, but there was a problem: It was slow on iOS. So, ever since the release, I've tried to crack this problem. How can Javascript that works beautifully on every other platform and browser be absolutely horrible on iOS? It was extremely fast on desktop browsers and  Android tablets. On iOS it took seconds to draw the grid and scrolling it was close to unusable.   After countless of hours of testing and trying, I finally found the reason: Box shadows in CSS. For example: .TW3ContainerBorder { border-radius: <?pas=EdgeRounding?>; border-top: 1px solid rgba(250, 250, 250, 0.7); border-left: 1px solid rgba(250, 250, 250, 0.7); border-right: 1px solid rgba(240, 240, 240, 0.5); border-bottom: 1px solid rgba(240, 240, 240, 0.5); -webkit-box-shadow: 0px 0px 1px 1px <?pas=GetRGBA(clDlgShadowBaseColor, 0.3)?>; -moz-box-shadow: 0px 0px 1px 1px <?pas=GetRGBA(clDlgShadowBaseColor, 0.3)?>; -ms-box-shadow: 0px 0px 1px 1px <?pas=GetRGBA(clDlgShadowBaseColor, 0.3)?>; -o-box-shadow: 0px 0px 1px 1px <?pas=GetRGBA(clDlgShadowBaseColor, 0.3)?>; box-shadow: 0px 0px 1px 1px <?pas=GetRGBA(clDlgShadowBaseColor, 0.3)?>; } .TW3FlatBorder { border-radius: <?pas=EdgeRounding?>; border-top: 1px solid rgba(44, 44, 44, 0.8); border-left: 1px solid rgba(44, 44, 44, 0.8); border-right: 1px solid rgba(44, 44, 44, 0.8); border-bottom: 1px solid rgba(44, 44, 44, 0.8); } I had used a TW3ContainerBorder for every cell in the grid. Replacing them with a flat border improved performance dramatically on iOS. Something like an order of magnitude faster.
      So if you've been having performance problems with iOS, that's most likely the reason.
  13. Thanks
    jorn reacted to lynkfs in visual processing   
    A while ago I posted some ideas and a demo on the subject of 'nocode' or 'locode' development. The idea was to do a domain modelling exercise, and extract or generate an application from that with no or minimal coding required. The demo put a couple of the proposed models through its paces.
    After that post I put the subject back in the incubator for a bit.
    Sort of recently I realised that having an rtl with visual components and an ide with a form painter is a good thing to have, but only covers part of what is necessary if we need to cover process logic, or business rules, without having to resort to coding. 
    Various computing packages (datamining, visual analytics etc) model business logic by providing specialised components, which can be strung together and parametrised.
    I tried this approach out (using KNIME) with the following (nonsensical) example process :
    "from the NorthWind database get all companies, and from the FishFacts database extract all species, collate only those entries from both datasources where the name starts with the letter 'L'  and list them. Also produce a pie-chart of all fish species showing their length in cm."

    This (nonsense) process translates to the node structure above. Nodes typically can be selected from a list of available nodes and right-clicking gives parametrisation forms, f.i. the MYSQL connector asks for a host, database name, credentials etc.
    Stringing these components together is a simple process in itself, and the output produces something like

    Not too bad.
    I've coded a couple of these type of components in Smart, which works really well.
    For the technical architecture I've based these on the principles of FBP (flow based programming) where every node is a webworker, and the connectors between these nodes/webworkers are defined by channel-objects. Data transfer between these nodes/channels is done by messaging. See post here.
    It would be nice to extend the rtl with these types of components, including a process painter
  14. Like
    jorn reacted to jarto in Endpoints & Resources ?   
    Well, you should always take what Jon says or writes with a grain of salt.
  15. Like
    jorn reacted to lynkfs in Quantum computing with Smart   
    Is it possible to do a bit of quantum computing using SMS ?
    The answer looks to be yes, using IBM's quantum computer resources which are partly made available for developers
    Basics first : IBM has released it's SDK to program these quantum computers using a visual composer, Python, a proprietary assembler QASM format and some run and execute utilities.
    There is however a second way of using its quantum resources, using the entry-points of is Q-experience REST server. Most if not all of the visual composer functions can be done by ajax-calls !
    To demonstrate : the first thing is to acquire an api-token. 
    (Create an account on https://quantumexperience.ng.bluemix.net/qx/experience. Log in and navigate to the Composer. Username > My Account, and then Advanced on the upper right. Then generate API Token. Api Tokens are personal and are not supposed to be shared.)
    The next thing is to generate a session token (access token). This can be done in code.
    This screenshot
    shows a couple of these REST server calls and its results :
    The first button (get access) generates a session token The second button queries which quantum computers are available, how many qubits can be used, if it is online and what type of system it is. Current results show 3 quantum systems - 2 real ones and 1 simulator The third button (current Temp) gives some processor info of the selected system. In this case the current temperature in Kelvin : the Melbourne processor is cooled to just above the absolute minimum. Next : the next button to implement will be to submit some code to one of the available processors for processing. Below is the project code for these REST calls
    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, SmartCL.Net.Http, ECMA.Json, SmartCL.Controls.Button,   SmartCL.Controls.Label, HTMLTableElement, SmartCL.Controls.ScrollBox,   SmartCL.Controls.Panel, SmartCL.Controls.ComboBox; type   TForm1 = class(TW3Form)     procedure W3Button3Click(Sender: TObject);     procedure W3Button2Click(Sender: TObject);     procedure W3Button1Click(Sender: TObject);   private     {$I 'Form1:intf'}   protected     procedure InitializeForm; override;     procedure InitializeObject; override;     procedure Resize; override;     DBRows : integer := 0;     FHttp : TW3HttpRequest;     smscursor: variant;     procedure GetAccessToken(Sender: TW3HttpRequest);     procedure ListAvailableSystems(Sender: TW3HttpRequest);     procedure GetTempKelvin(Sender: TW3HttpRequest);     AccessToken : string;   end; implementation { TForm1 } procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components end; procedure TForm1.InitializeObject; begin   inherited;   {$I 'Form1:impl'} end; { Button1 } procedure TForm1.W3Button1Click(Sender: TObject); begin //Get Access Token   var FHttp := TW3HttpRequest.Create;   FHttp.OnDataReady := GetAccessToken;   FHttp.open("POST",'https://quantumexperience.ng.bluemix.net/api/users/loginWithToken');   FHttp.RequestHeaders.Add("Content-type","application/json");   var api : variant := new JObject;   api.apiToken := TString.encodeURIComponent('a59d26ebf........1d6d6d4a28c430b5336aba');   FHttp.send(json.stringify(api)); end; procedure TForm1.GetAccessToken(Sender: TW3HttpRequest); begin   smscursor := JSON.parse(Sender.ResponseText);   AccessToken := smscursor.id;   W3Label1.Caption:= 'Access Token : ' + AccessToken; end; { Button2 } procedure TForm1.W3Button2Click(Sender: TObject); begin //List available Q systems   var FHttp := TW3HttpRequest.Create;   FHttp.OnDataReady := ListAvailableSystems;   FHttp.open("GET",'https://quantumexperience.ng.bluemix.net/api/Backends?access_token=' + AccessToken);   FHttp.RequestHeaders.Add("Content-type","application/json");   FHttp.send; end; procedure TForm1.ListAvailableSystems(Sender: TW3HttpRequest); begin   var W3TableElement1 : TW3TableElement := TW3TableElement.Create(W3Panel1); //add 5 columns to the grid   W3TableElement1.AddColumn('Name',200);      //title, width   W3TableElement1.AddColumn('Description',200);   W3TableElement1.AddColumn('Qubits',50);   W3TableElement1.AddColumn('System type',150);   W3TableElement1.AddColumn('Status',50);   smscursor := JSON.parse(Sender.ResponseText);   W3ComboBox1.Clear;   for var i := 0 to smscursor.length -1 do begin     W3TableElement1.AddCell(i+1,1,smscursor[i].name);     W3TableElement1.AddCell(i+1,2,smscursor[i].description);     W3TableElement1.AddCell(i+1,3,smscursor[i].nQubits);     if smscursor[i].simulator = true       then W3TableElement1.AddCell(i+1,4,'quantum simulator')       else W3TableElement1.AddCell(i+1,4,'quantum system');     W3TableElement1.AddCell(i+1,5,smscursor[i].status);     W3ComboBox1.add(smscursor[i].name);   end;   W3Panel1.NativeScrolling := true;   W3ComboBox1.OnChanged := procedure (Sender: TObject)   begin     writeln(W3ComboBox1.Items[W3ComboBox1.SelectedIndex]);   end; end; { Button3 } procedure TForm1.W3Button3Click(Sender: TObject); begin //Get Temp   var FHttp := TW3HttpRequest.Create;   FHttp.OnDataReady := GetTempKelvin;   //'https://quantumexperience.ng.bluemix.net/api/Backends/NAME/parameters?access_token=ACCESS-TOKEN';   FHttp.open("GET",'https://quantumexperience.ng.bluemix.net/api/Backends/' +                    W3ComboBox1.Items[W3ComboBox1.SelectedIndex] +                    '/parameters?access_token=' +                    AccessToken);   FHttp.RequestHeaders.Add("Content-type","application/json");   FHttp.send; end; procedure TForm1.GetTempKelvin(Sender: TW3HttpRequest); begin   If Sender.ResponseText = '{}' then   begin     W3Label3.Caption := 'Simulators are not cooled to (close to) absolute minimum';   end else   begin     smscursor := JSON.parse(Sender.ResponseText);     if smscursor.fridgeParameters.Temperature.value = ''       then W3Label3.Caption := 'Processor does not support Temp reading'       else W3Label3.Caption:= 'Current Temp : ' + smscursor.fridgeParameters.Temperature.value + ' Kelvin';   end; end; procedure TForm1.Resize; begin   inherited; end;   initialization   Forms.RegisterForm({$I %FILE%}, TForm1); end.  
    In the end hopefully it will be possible to recreate the classic Battleships game using quantum computing, as described here
  16. Like
    jorn reacted to jarto in Development updates   
    New update available:
    TW3ListMenu: Add Items-property, so items can created in Object Inspector. Add OnSelected-event. IDE:
    Bug fix to renaming of units Show form source instead of designer when form is selected from Project Manager  
  17. Like
    jorn reacted to jarto in Yikes!!!   
    My plan is to do it today. I will post when it's done.
    Edit: It's already available in the master-channel on SmartUpdate. A real setup will also be available today.
  18. Like
    jorn reacted to IgorSavkic in SMS and MORMOT   
    > Hmmm - I'm a beginner at this.
    I still use old SMS myself with old mORMot so it will take some time till I switch to latest versions.
    > Just so I'm clear - do you mean use the LATEST SMS version with the old mormot ?ÔĽŅ
    Yes, I haven't tested that myself but one user in mORMot forum tried it and it worked for him.
  19. Like
    jorn reacted to jarto in 5-minute with SMS overview   
    @EWB Muito obrigado
    If you create a package and register your component in the component palette, the published properties will work automatically in the Object Inspector. When looking at your example,
    This would not show up as the OI does not understand TCustomStyle, but TStrArray does work and show up. Also sets like TMyStyle do work.
    Live preview did not work at all, so it was disabled. In 3.0 I did fix many bad bugs in the designer. So now the designer works, but it's not pretty.
    You're right that he was running too many races at once. When it came to posts he did, Smart Desktop actually does work very well and if you try running it with some dirt cheap Raspberry PI, it delivers very nice performance. So yes, it can be used as a basis for a kiosk or embedded system where costs per device can be extremely low.
    Jon also had a habit of writing blog posts of something he was working on or what will be released in the future. I tried to get him to stop that as it's annoying to not be able to test it yourself.
  20. Thanks
    jorn reacted to DavidRM in IDE & Documentation   
    If you need someone to help with proofreading, let me know. I can carve out a few hours.
  21. Like
    jorn reacted to jarto in component creation   
    Let me start by commenting on Jon's blog post. For the most part it's accurate, but he makes a small mistake with the "common mistake":
    ObjectReady() calls ReadySync() which actually does check if the child elements are ready. So, when you override ObjectReady(), the child controls you created in InitializeObject should also be ready. And when ObjectReady() happens, it also triggers the first Resize for the component.
    Let me comment on these three lines:
    Users don't need to write as complex checking routines as ReadySync() is. Let the RTL take care of that. It does it very well. However, do always check your controls in Resize(). Minimum is to check that they are not nil. And if you want to be extra sure, check the ready state too.
    And by far the best way to do this all is pretty simple:
    In your Resize() procedure, always check if your controls are ready If they are not, call Self.Invalidate(). Do not call Resize() directly or via TW3Dispatch as Jon suggests. Think about Invalidate() as a request for a new Resize(). It calls an internal procedure in the RTL called ResizeWhenReady() and it does exactly what it says: It will call Resize() with a short delay and it will check that any new child components you added after the previous resize are also ready. The delay helps to minimize the number of Resize()-calls and it simply makes sense to not let a Resize() happen before your child components are ready.
    I think Jon is explaining how the RTL did work before I got involved. It makes sense to rely on ObjectReady() when you have a simple, static control but when you have a control like TW3ListBox, it does not work at all as the TW3ListBox dynamically creates new child components while you use the control.
  22. Like
    jorn reacted to lynkfs in component creation   
    Question : is this article still the preferred way to develop visual components ?
    I developed some Material Design components some years ago (here and here) but they need to be ported to the latest rtl as they don't compile anymore.
    Hence this question.
    As an example I ported a simple component (switch) using the recipe in Jon's article and it works ok, see below
    Just a bit elaborate.
    unit Switch; /****************************************************************************** LynkFS / 20 - 11 - 2018 The Switch component consists of - a W3Panel as the main container for the Switch - a W3Panel for the Switch - a W3Panel for the sliderline - a W3Panel as the highlighter The component is by default styled according to the css theme of the project. Styling can be modified by overriding the following css classes : The Switch CSS classes in BEM notation are .TSwitch .TSwitch__Panel .TSwitch__Panel__Line .TSwitch__Panel__Line--StateOn .TSwitch__Panel__Line--StateOff .TSwitch__Panel__Knob .TSwitch__Panel__Knob--StateOn .TSwitch__Panel__Knob--StateOff .TSwitch__Panel__HighLight .TSwitch__Panel__HighLight--Active .TSwitch__Panel__HighLight--InActive */ interface uses   W3C.DOM,   System.Types,   System.Time,   System.Colors,   System.Events,   {$IFDEF THEME_AUTOSTYLE}   SmartCL.Theme,   {$ENDIF}   SmartCL.System,   SmartCL.Touch,   SmartCL.Effects,   SmartCL.borders,   SmartCL.Components,   SmartCL.Controls.Panel,   SmartCl.Css.StyleSheet; type   TSwitch = class(TW3CustomControl)   private     Panel0   : TW3Panel;       //background     Panel1   : TW3Panel;       //sliderline     Panel2   : TW3Panel;       //indicator     Panel3   : TW3Panel;       //Switch knob     procedure SetStateOn(StateOn: Boolean);     function  GetStateOn: Boolean;     IsStateOn: Boolean := false;   protected        // see https://jonlennartaasenden.wordpress.com/2018/05/07/     function  MakeElementTagObj: THandle; override;       //1     procedure StyleTagObject; override;                   //2     procedure ObjectReady; override;                      //3     procedure InitializeObject; override;                 //4     procedure Resize; override;                           //5     procedure FinalizeObject; override;     Procedure ShowSwitch; //included in 5     Procedure InsertCSS; //included in 2   public     property StateOn: Boolean read getStateOn write setStateOn;   end; implementation { TSwitch } function TSwitch.MakeElementTagObj: THandle;          //1 begin   result := w3_createHtmlElement('div');              //div = default, so could be omitted end; procedure TSwitch.StyleTagObject;                     //2 begin   inherited;   {$IFDEF THEME_AUTOSTYLE}   ThemeBorder := btDecorativeBorder;   {$ENDIF}   InsertCSS; //insert all styling in stylesheet end; procedure TSwitch.ObjectReady;                        //3 begin   inherited;   //set some initial properties   Panel0.SetBounds(0,0,self.width,self.height);       //background   Panel1.SetBounds(round(self.height/2),              //slider line                    round(self.height/2)-round(self.height*0.2),                    self.Width-self.height,                    round(self.height*0.4));   Panel2.SetBounds(0,0,self.height,self.height);      //highlight circle   var x : integer := round(self.height/5);            //switch knob   Panel3.SetBounds(x,x,Panel2.width-2*x,Panel2.height-2*x);   TW3Dispatch.WaitFor([Panel0, Panel1, Panel2, Panel3], 5,     procedure (Success: boolean)     begin       if Success then       begin         // set some initial properties         If IsStateOn then begin           Panel2.Left := self.Width - Panel2.Width;           Panel3.Left := self.Width - Panel2.Width + round((Panel2.Width-Panel3.Width)/2);         end;         // Do an immediate resize         Resize();       end;     end); end; procedure TSwitch.InitializeObject;              //4 begin   inherited; //creating sub-components   Self.TagStyle.Add('TSwitch');       //superfluous, will be auto generated   Panel0 := TW3Panel.Create(self);   Panel0.TagStyle.Clear;              //dont inherit css from TW3Panel   Panel0.TagStyle.Add('TSwitch__Panel');   Panel1 := TW3Panel.Create(Panel0);   Panel1.TagStyle.Clear;              //dont inherit css from TW3Panel   Panel1.TagStyle.Add('TSwitch__Panel__Line TSwitch__Panel__Line--StateOff');   Panel2 := TW3Panel.Create(Panel0);   Panel2.TagStyle.Clear;              //dont inherit css from TW3Panel   Panel2.TagStyle.Add('TSwitch__Panel__HighLight TSwitch__Panel__HighLight--InActive');   Panel3 := TW3Panel.Create(Panel0);   Panel3.TagStyle.Clear;              //dont inherit css from TW3Panel   self.SimulateMouseEvents := True;   //touch enable   self.handle.addEventListener("click", procedure()   begin     IsStateOn := not IsStateOn;     If IsStateOn then begin       Panel3.fxMoveBy(self.width - self.height, 0, 0.5);       Panel2.fxMoveBy(self.width - self.height, 0, 0.5);     end else begin       Panel3.fxMoveBy(-self.width + self.height, 0, 0.5);       Panel2.fxMoveBy(-self.width + self.height, 0, 0.5);     end;     Panel2.TagStyle.Clear;            //dont inherit css from TW3Panel     Panel2.TagStyle.Add('TSwitch__Panel__HighLight TSwitch__Panel__HighLight--Active');     TW3Dispatch.Execute (Procedure()     begin       Panel2.TagStyle.Clear;          //dont inherit css from TW3Panel       Panel2.TagStyle.Add('TSwitch__Panel__HighLight TSwitch__Panel__HighLight--InActive');     end, 80);     ReSize;   end); end; procedure TSwitch.Resize; begin   inherited;   if not (csDestroying in ComponentState) then   begin     // Make sure we have ready state     if (csReady in ComponentState) then     begin       // Check that child elements are all assigned       // and that they have their csReady flag set in       // ComponentState. This can be taxing. A more lightweight       // version is TW3Dispatch.Assigned() that doesnt check       // the ready state (see class declaration for more info)       if TW3Dispatch.AssignedAndReady([Panel0, Panel1, Panel2, Panel3]) then       begin         // Finally: layout the controls.         ShowSwitch;       end;     end;   end; end; Procedure TSwitch.ShowSwitch; begin //   Panel1.TagStyle.Clear;   Panel3.TagStyle.Clear;   If IsStateOn then begin     Panel3.TagStyle.Add('TSwitch__Panel__Knob TSwitch__Panel__Knob--StateOn');     Panel1.TagStyle.Add('TSwitch__Panel__Line TSwitch__Panel__Line--StateOn');   end else begin     Panel3.TagStyle.Add('TSwitch__Panel__Knob TSwitch__Panel__Knob--StateOff');     Panel1.TagStyle.Add('TSwitch__Panel__Line TSwitch__Panel__Line--StateOff');   end; // end; procedure TSwitch.InsertCSS; var   cssProperties : string; begin   //make stylesheet   var styleSheet : TW3StyleSheet := TW3StyleSheet.Create;   styleSheet.Add(".TSwitch", '');   styleSheet.Add(".TSwitch__Panel", '');   cssProperties := 'cursor: pointer; border: 0px; border-radius: 6px;';   styleSheet.Add(".TSwitch__Panel__Line", cssProperties);   cssProperties := 'background-color: rgba(164,114,234,.50);';   styleSheet.Add(".TSwitch__Panel__Line--StateOn", cssProperties);   cssProperties := 'background-color: rgba(0,0,0,.26);';   styleSheet.Add(".TSwitch__Panel__Line--StateOff", cssProperties);   cssProperties := 'cursor: pointer; border: 0px; border-radius: 50%;';   styleSheet.Add(".TSwitch__Panel__HighLight", cssProperties);   cssProperties := 'background-color: rgba(164,114,234,.50);';   styleSheet.Add(".TSwitch__Panel__HighLight--Active", cssProperties);   cssProperties := 'background-color: transparent;';   styleSheet.Add(".TSwitch__Panel__HighLight--InActive", cssProperties);   cssProperties := 'cursor: pointer; border-radius: 50%; box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);';   styleSheet.Add(".TSwitch__Panel__Knob", cssProperties);   cssProperties := 'background-color: rgba(164,114,234,.90);';   styleSheet.Add(".TSwitch__Panel__Knob--StateOn", cssProperties);   cssProperties := 'background-color: white;';   styleSheet.Add(".TSwitch__Panel__Knob--StateOff", cssProperties); /* Alternatively add this to a custom stylesheet : .TSwitch { } .TSwitch__Panel { } .TSwitch__Panel__Line {     cursor: pointer;     border: 0px;   border-radius: 6px; } .TSwitch__Panel__Line--StateOn {   background-color: rgba(164,114,234,.50); } .TSwitch__Panel__Line--StateOff {   background-color: rgba(0,0,0,.26); } .TSwitch__Panel__HighLight {     cursor: pointer;     border: 0px;   border-radius: 12px; } .TSwitch__Panel__HighLight--Active {   background-color: rgba(164,114,234,.50); } .TSwitch__Panel__HighLight--InActive {   background-color: transparent; } .TSwitch__Panel__Knob {     cursor: pointer;      border-radius: 10px;   box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12); } .TSwitch__Panel__Knob--StateOn {   background-color: rgba(164,114,234,.90); } .TSwitch__Panel__Knob--StateOff {   background-color: white; } */ end; procedure TSwitch.FinalizeObject; begin   Panel0.Free;   Panel0 := nil;   inherited; end; procedure TSwitch.SetStateOn(StateOn: Boolean); begin   IsStateOn := StateOn; end; function  TSwitch.GetStateOn: Boolean; begin   Result := IsStateOn; end; end. usage
    procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components   Switch1 := TSwitch.Create(self); //  Switch1.StateOn := true;    //default false   Switch1.SetBounds(50,50,60,35); end;  
  23. Like
    jorn reacted to jarto in Development updates   
    Changes to handling of Cursor: Style definitions moved from basic html elements to control styles GetCursor and SetCursor can now be overridden Bug fixes to how many controls handle cursor. Especially TW3Label. Themes: Add missing styles TW3CheckBox, TW3CheckMark, TW3RadioButton, TW3RadioToggle and TW3RadioGroup Two new backgrounds: TW3DecorativeListItemBackground and TW3TransparentBackground RTL optimizations to creation of controls, GetBoundsRect, SetBounds, MoveTo and SetSize. Bug fix to SmartCL.Graphics.pas: Changing of canvas font, size and styles did not work. Bug fix to System.DateUtils.DecodeDate. IDE:
    Delete key works now Search dialog and other dialogs. Bug fix: Internal Browser Window showed only a white screen if Execute was clicked while it was open. Compiler:
    Now(), EncodeDate() and EncodeTime() returns now the same values as Delphi and FPC All time/date -functions fixed to work with the new TDateTime-values
  24. Like
    jorn reacted to jarto in Development updates   
    Now it should be possible for everyone to use SmartUpdate with the development-channel.
  25. Like
    jorn reacted to jarto in Development updates   
    The Development-channel in SmartUpdate contains all the latest changes in Smart Mobile Studio. It's a good channel to follow for those who want all the new features and bug fixes right away, instead of waiting for the next formal release.
    To follow the Development-channel:
    Make a new folder and add: SmartUpdate.exe Your own user.lic from your current Smart Mobile Studio folder. To get all the latest changes in the Development-channel:
    Run: SmartUpdate /changechannel /showhidden When asked for which channel to follow, choose Development The purpose of this topic is to inform about all the new features and fixes.
  • Create New...