Jump to content

lynkfs

Moderators
  • Content Count

    740
  • Joined

  • Last visited

  • Days Won

    146

Reputation Activity

  1. Like
    lynkfs got a reaction from Tim Koscielski in css styling   
    Browsers are certainly talented as multi-language processors. They have to understand html, css, javascript, svg and lately web-assembly as a fifth language. XML and Json are format specifiers, but could be borderline categorised as languages as well.
    Smart elevates javascript to great heights, but sort of leaves the other ones at the periphery. Especially css.
    Css can be used for a) component styling including colours, fonts etc, b) visual layout of pages/forms and reacting responsively to screen size and orientation and c) interactivity in various forms. Some of this overlaps with the js domain. Smart basically uses css for a) but not for b) or c).
    Looking at various css frameworks out there, I would categorise these as
    on one end of the scale there are many UI kit frameworks where the emphasis is on components - buttons, accordions, cards etc. Sometimes as css stand-alone files, sometimes in conjunction with js. Most of these also have functionality for layout purposes, usually based on flexbox or internal grid structures. on the other end of the scale there are frameworks which forego the component focus, but instead provide a large number of elementary styling functions, which can be applied to any component. and many which occupy a space in between This post is about the open source Tailwind framework, belonging in the second category above, just to see how that would work in the Smart environment.
    Tailwind comes in 2 flavours : a static framework which can be accessed locally or from a cdn, and a more dynamic version. The latter can be tailored dynamically for any specific project and basically needs to be part of the build toolchain. To keep it simple I used the static version.
    Change the res/app.css reference to the tailwind css file (either just replace it or change the reference in the index.html file). Now any component can be made to use this styling. Because this is not more (or less) than a list of individual styling functions, the use boils down to defining what you want. Tell a story as in "give me a button with a green background, which turns to blue on hover, has rounded corners and white text and a shadow effect which makes it seem floating". In code :
      W3Button1.handle.className := "bg-green-500 hover:bg-blue-700 text-white rounded shadow-2xl"; The second button in the demo project (see below) has a different story (className sequence), which gives it a totally different look and feel.
    I kind of like this approach, it works very well with any component, thus also with the built in Smart components.
    It is a bit of a drag specifying these className sequences by hand, so it would be nice if this would be supported in the IDE. There are after all only a small number of categories of these elementary styling bits : backgrounds, typography, borders, spacing, sizing, svg, interactivity and effects. And a relatively limited list of functions per category (bg-green-500 means a green background, 500 is the fifth shade in the green colour scheme. So there will be a bg-green-600, a bg-blue-200 etc). Doable I think.
    Apart from these styling functions, Tailwind also has a number of layout functions. Smart has its own layout mechanism, however the Tailwind functions can be used as well. See the 'card' component in the demo.
    Demo and source
     
     
  2. Like
    lynkfs got a reaction from IElite in css styling   
    Thanks
    There are however a couple of minor / major (?) caveats doing it like this :
    I made up some more metro components, and it becomes apparent that it is unavoidable to use more modifier classes: TagStyle.Add('primary image-button outline icon-left rounded etc). this type of styling is not supported by the visual designer in the ide, so styling can be done in code only. Even though only one-liners (TagStayle.Add( ) (most rtl components (but not all) have a component, a border and a background theme class baked in. Not all of these can be reused, so sometimes the border and/or background classes may end up being empty) probably the second bullet (visual designer) is the most important one for future enhancements
     
  3. Thanks
    lynkfs got a reaction from Czar in css styling   
    Thanks
    There are however a couple of minor / major (?) caveats doing it like this :
    I made up some more metro components, and it becomes apparent that it is unavoidable to use more modifier classes: TagStyle.Add('primary image-button outline icon-left rounded etc). this type of styling is not supported by the visual designer in the ide, so styling can be done in code only. Even though only one-liners (TagStayle.Add( ) (most rtl components (but not all) have a component, a border and a background theme class baked in. Not all of these can be reused, so sometimes the border and/or background classes may end up being empty) probably the second bullet (visual designer) is the most important one for future enhancements
     
  4. Like
    lynkfs reacted to DavidRM in Node.JS WebSocket Client Socket   
    This is me sharing again.
    The NodeJS WebSocket server socket is implemented in SMS. But I didn't find an implementation of the WebSocket client socket.
    Sometimes an SMS NodeJS server needs to connect to another server. So I kinda hacked this together using the server socket as a guide.
    unit UPBNCommonNJWebSocket; interface uses System.Types, System.Types.Convert, System.Time, System.Streams, System.Reader, System.Writer, System.Device.Storage, System.Objects, SmartNJ.System, SmartNJ.Streams, SmartNJ.Device.Storage, SmartNJ.Application, NodeJS.Core, NodeJS.WebSocket, SmartNJ.Server.WebSocket; type // Forward declarations TNJWebSocket = class; TNJWebSocketOpenEvent = procedure (Sender: TNJWebSocket); TNJWebSocketCloseEvent = procedure (Sender: TNJWebSocket; Code: integer; const Reason: string); TNJWebSocketErrorEvent = procedure (Sender: TNJWebSocket; Error: TJSErrorObject); TNJWebSocketMessageEvent = procedure (Sender: TNJWebSocket; Message: TNJWebsocketMessage); TNJWebSocket = class(TW3ErrorObject) private FSocket: JWsSocket; public property WSSocket: JWsSocket read FSocket; function SocketState: JWsReadyState; function Connected: boolean; function URL: string; function Protocol: string; procedure Connect(URL: string; Protocols: array of string); overload; procedure Connect(URL: string); overload; procedure Disconnect; overload; procedure Send(const Data: variant); overload; procedure Send(const Text: string); overload; procedure Send(const Data: TStream); overload; property TagData: variant; constructor Create; override; destructor Destroy; override; procedure Ping; published property OnOpen: TNJWebSocketOpenEvent; property OnClosed: TNJWebSocketCloseEvent; property OnMessage: TNJWebSocketMessageEvent; property OnError: TNJWebSocketErrorEvent; end; implementation constructor TNJWebSocket.Create; begin inherited Create; // We dont want to throw exceptions whenever SetLastError() is called ErrorOptions.ThrowExceptions := false; end; destructor TNJWebSocket.Destroy; begin FSocket := nil; inherited; end; procedure TNJWebSocket.Ping; begin if FSocket <> nil then asm (@FSocket).ping(function() {}); end; end; function TNJWebSocket.Protocol: string; begin if FSocket <> nil then Result := FSocket.protocol; end; function TNJWebSocket.URL:String; begin if FSocket <> nil then Result:=FSocket.url; end; function TNJWebSocket.SocketState: JWsReadyState; begin if FSocket <> nil then Result := JWsReadyState( integer( FSocket.readyState) ) else Result := rsClosed; end; function TNJWebSocket.Connected: boolean; begin Result := SocketState = rsOpen; end; procedure TNJWebSocket.Connect(URL: string); begin Connect(Url, []); end; procedure TNJWebSocket.Connect(URL: string; Protocols: Array of string); begin ClearLastError(); (* disconnect socket if already connected *) if connected then disconnect(); (* Allocate new socket *) var WebSocket = WebSocketAPI; asm (@self.FSocket) = new (@WebSocket)(@URL, @Protocols); end; // initialize standard socket events FSocket.on("open", procedure begin if assigned(OnOpen) then OnOpen(self); end); FSocket.on("error", procedure (error: variant) begin SetLastError("internal websocket error"); if assigned(OnError) then OnError(self, TJSErrorObject(error)); end); FSocket.on("message", procedure (message: variant) var ResData: TNJWebsocketMessage; begin if message.IsUint8Array then begin ResData.wiType := mtBinary; ResData.wiBuffer := JBuffer(message); end else begin ResData.wiType := mtText; ResData.wiText := message; end; if assigned(OnMessage) then OnMessage(self, ResData); end); Variant(FSocket).on("close", procedure (code: integer; reason: string) begin if assigned(OnClosed) then OnClosed(self, code, reason); end); end; procedure TNJWebSocket.Disconnect; begin ClearLastError(); if Connected then begin try FSocket.close(); finally FSocket := nil; end; end; end; procedure TNJWebSocket.Send(const Data: variant); begin FSocket.send(data); end; procedure TNJWebSocket.Send(const Text: string); begin FSocket.send(Text); end; procedure TNJWebSocket.Send(const Data: TStream); begin if Data <> nil then begin if Data.position < Data.Size then begin // Get bytes from stream var Bytes := Data.Read(Data.Size - Data.Position); // Convert to typed-array var TypedArray := TDataType.BytesToTypedArray(bytes); // Send as binary FSocket.Send(TypedArray); end; end; end; end.  
    It might be a bit simplified, and it doesn't really follow the SMS component name convention, but it does what I need. And I figured I would share.
    -David
     
  5. Like
    lynkfs got a reaction from jarto in css styling   
    Easy to use...
    Suppose we want to develop a Metro theme
    To take buttons as an example, the official metro style has a number of predefined buttons :

     
    To replicate the above, and do it in such a way that :
    the component code (TW3Button) does not need any change the standard theming classes still apply (TW3Button TW3ButtonBorder TW3ButtonBackground), but with different content of course while allowing for these different predefined component versions is to do something like this
    procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components   var Button1 : TW3Button := TW3Button.Create(self);   Button1.SetBounds(20,20,83,40);   Button1.Caption := 'Default';   var Button2 : TW3Button := TW3Button.Create(self);   Button2.SetBounds(110,20,83,40);   Button2.Caption := 'Primary';   Button2.TagStyle.Add('primary');   var Button3 : TW3Button := TW3Button.Create(self);   Button3.SetBounds(200,20,83,40);   Button3.Caption := 'Secondary';   Button3.TagStyle.Add('secondary');   var Button4 : TW3Button := TW3Button.Create(self);   Button4.SetBounds(290,20,83,40);   Button4.Caption := 'Success';   Button4.TagStyle.Add('success'); end;  
    result :

     
    with the metro css file for the above looking like this
    /* ////////////////////////////////////////// // TW3Button (default) ////////////////////////////////////////// */ .TW3Button {     font-weight: 400;     text-align: center;     white-space: nowrap;     vertical-align: middle;     -webkit-user-select: none;     -moz-user-select: none;     -ms-user-select: none;     user-select: none;     border: 1px solid transparent;     padding: 0 0.75rem;     -webkit-transition: all 0.15s ease-in-out;     transition: all 0.15s ease-in-out;     background-color: #ebebeb;     color: #1d1d1d;     cursor: pointer;     outline: none;     -ms-touch-action: manipulation;     touch-action: manipulation;     -webkit-appearance: button;     /*     font-size: 0.875rem;     line-height: 34px;     height: 36px;     */ } .TW3Button:focus, .TW3Button:active {     text-decoration: none;     -webkit-box-shadow: 0 0 0 3px rgba(228, 228, 228, 0.45);     box-shadow: 0 0 0 3px rgba(228, 228, 228, 0.45); } .TW3Button:hover {     background-color: rgba(29, 29, 29, 0.1); } .TW3ButtonBackground { } .TW3ButtonBorder { } /* ////////////////////////////////////////// // TW3Button Primary ////////////////////////////////////////// */ .TW3Button.primary {     outline-color: #75b5fd;     background-color: #0366d6;     color: #ffffff; } .TW3Button.primary:hover {     color: #ffffff;     background-color: #024ea4;     border-color: #023671; } .TW3Button.primary:focus, .TW3Button.primary:active {     -webkit-box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.45);     box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.45); } /* ////////////////////////////////////////// // TW3Button Secondary ////////////////////////////////////////// */ .TW3Button.secondary {     outline-color: #b7c6cd;     background-color: #607d8b;     color: #ffffff; } .TW3Button.secondary:hover {     color: #ffffff;     background-color: #4b626d;     border-color: #36474f; } .TW3Button.secondary:focus, .TW3Button.secondary:active {     -webkit-box-shadow: 0 0 0 3px rgba(96, 125, 139, 0.45);     box-shadow: 0 0 0 3px rgba(96, 125, 139, 0.45); } /* ////////////////////////////////////////// // TW3Button Success ////////////////////////////////////////// */ .TW3Button.success {     outline-color: #adeb6e;     background-color: #60a917;     color: #ffffff; } .TW3Button.success:hover {     color: #ffffff;     background-color: #477c11;     border-color: #2d4f0b; } .TW3Button.success:focus, .TW3Button.success:active {     -webkit-box-shadow: 0 0 0 3px rgba(96, 169, 23, 0.45);     box-shadow: 0 0 0 3px rgba(96, 169, 23, 0.45); } see demo (check click and hover states)
    What do you think ?
     
    By the way, this css file is made up by screenscraping, which is actually not too bad / timeconsuming. 
    Alternatively it could also be composed out of relevant Tailwind functions, results would be very similar.
     
     
  6. Like
    lynkfs reacted to jarto in Sorting arrays and lists   
    This is a tutorial for sorting arrays and lists in Smart Mobile Studio.
    String arrays and TStringList are pretty easy to sort. You only need to call Sort:
    var strarr: array of String; ... strarr.Sort; var strlist: TStringList; strlist:=TStringList.Create; ... strlist.Sort; But how do you sort arrays of records or arrays of classes? For example:
    TSortData = record Id: Integer; Data: String; end; You can't simply call Sort as your application does not know how you want to sort the records. You solve this by using a comparison function:
    function CompareSortData(Item1, Item2: TSortData): Integer; begin result:=CompareStr(Item1.Data, Item2.Data); end; . . . var objarr: array of TSortData; ... objarr.Sort(@CompareSortData); The comparison function should return a negative number if Item1 is smaller, positive number if Item1 is bigger and 0 if they are equal.
    In Smart Mobile Studio you can also use anonymous methods:
    var objarr: array of TSortData; ... objarr.Sort( function(Item1, Item2: TSortData): Integer begin result:=CompareStr(Item1.Data,Item2.Data); end); Comparison functions can also be used for TList and even for TStringList. For example, you may want to have greater control over how names are sorted (eliminating prefixes like von):
    function EliminatePrefix(Name: String): String; const Prefixes: array[0..1] of String = ['von ','af ']; begin result:=Name; for var a:=0 to High(Prefixes) do begin if pos(Prefixes[a],result)=1 then begin Delete(result,1,Length(Prefixes[a])); exit; end; end; end; . . . var StrList:=TStringList.Create; StrList.Add('Perry'); StrList.Add('Miller'); StrList.Add('von Essen'); StrList.Add('Stockton'); StrList.Add('af Trolle'); StrList.Sort( function(Name1,Name2: String): Integer begin result:=CompareStr(EliminatePrefix(Name1),EliminatePrefix(Name2)); end); for var a:=0 to StrList.Count-1 do WriteLn(StrList[a]);  
  7. Like
    lynkfs got a reaction from Czar in css styling   
    Easy to use...
    Suppose we want to develop a Metro theme
    To take buttons as an example, the official metro style has a number of predefined buttons :

     
    To replicate the above, and do it in such a way that :
    the component code (TW3Button) does not need any change the standard theming classes still apply (TW3Button TW3ButtonBorder TW3ButtonBackground), but with different content of course while allowing for these different predefined component versions is to do something like this
    procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components   var Button1 : TW3Button := TW3Button.Create(self);   Button1.SetBounds(20,20,83,40);   Button1.Caption := 'Default';   var Button2 : TW3Button := TW3Button.Create(self);   Button2.SetBounds(110,20,83,40);   Button2.Caption := 'Primary';   Button2.TagStyle.Add('primary');   var Button3 : TW3Button := TW3Button.Create(self);   Button3.SetBounds(200,20,83,40);   Button3.Caption := 'Secondary';   Button3.TagStyle.Add('secondary');   var Button4 : TW3Button := TW3Button.Create(self);   Button4.SetBounds(290,20,83,40);   Button4.Caption := 'Success';   Button4.TagStyle.Add('success'); end;  
    result :

     
    with the metro css file for the above looking like this
    /* ////////////////////////////////////////// // TW3Button (default) ////////////////////////////////////////// */ .TW3Button {     font-weight: 400;     text-align: center;     white-space: nowrap;     vertical-align: middle;     -webkit-user-select: none;     -moz-user-select: none;     -ms-user-select: none;     user-select: none;     border: 1px solid transparent;     padding: 0 0.75rem;     -webkit-transition: all 0.15s ease-in-out;     transition: all 0.15s ease-in-out;     background-color: #ebebeb;     color: #1d1d1d;     cursor: pointer;     outline: none;     -ms-touch-action: manipulation;     touch-action: manipulation;     -webkit-appearance: button;     /*     font-size: 0.875rem;     line-height: 34px;     height: 36px;     */ } .TW3Button:focus, .TW3Button:active {     text-decoration: none;     -webkit-box-shadow: 0 0 0 3px rgba(228, 228, 228, 0.45);     box-shadow: 0 0 0 3px rgba(228, 228, 228, 0.45); } .TW3Button:hover {     background-color: rgba(29, 29, 29, 0.1); } .TW3ButtonBackground { } .TW3ButtonBorder { } /* ////////////////////////////////////////// // TW3Button Primary ////////////////////////////////////////// */ .TW3Button.primary {     outline-color: #75b5fd;     background-color: #0366d6;     color: #ffffff; } .TW3Button.primary:hover {     color: #ffffff;     background-color: #024ea4;     border-color: #023671; } .TW3Button.primary:focus, .TW3Button.primary:active {     -webkit-box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.45);     box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.45); } /* ////////////////////////////////////////// // TW3Button Secondary ////////////////////////////////////////// */ .TW3Button.secondary {     outline-color: #b7c6cd;     background-color: #607d8b;     color: #ffffff; } .TW3Button.secondary:hover {     color: #ffffff;     background-color: #4b626d;     border-color: #36474f; } .TW3Button.secondary:focus, .TW3Button.secondary:active {     -webkit-box-shadow: 0 0 0 3px rgba(96, 125, 139, 0.45);     box-shadow: 0 0 0 3px rgba(96, 125, 139, 0.45); } /* ////////////////////////////////////////// // TW3Button Success ////////////////////////////////////////// */ .TW3Button.success {     outline-color: #adeb6e;     background-color: #60a917;     color: #ffffff; } .TW3Button.success:hover {     color: #ffffff;     background-color: #477c11;     border-color: #2d4f0b; } .TW3Button.success:focus, .TW3Button.success:active {     -webkit-box-shadow: 0 0 0 3px rgba(96, 169, 23, 0.45);     box-shadow: 0 0 0 3px rgba(96, 169, 23, 0.45); } see demo (check click and hover states)
    What do you think ?
     
    By the way, this css file is made up by screenscraping, which is actually not too bad / timeconsuming. 
    Alternatively it could also be composed out of relevant Tailwind functions, results would be very similar.
     
     
  8. Like
    lynkfs reacted to jarto in RoadMap 2019   
    Well, I believe that open sourcing is not a silver bullet that will magically bring new resources to the project. If there are people who are interested in participating, I'll be more than happy to actually offer them contract work.
    Before I joined this project, SMS was in an eternal "coming soon" -stage. A new update was just around the corner but days turned into weeks and weeks to months and years. I didn't like that as a customer. So when I've been running this development, I've not wanted to make promises that I can't keep. Before this my family owned and ran a very succesfull software company that developed the best and most used School Administration software in Finland. We did constant development making new features. We used constant evolution. I've been doing that same thing with Smart Mobile Studio and we really have seen a lot of development and improvements. And we will see constant and good development in the future too.
    When it comes to a roadmap, I've noticed that I'm really bad at making one. A software project is a moving target. A lot of features are being worked on. In the end, it's not clear when a feature will be finished and delivered. That's because priorities do change and sometimes (for example the new Grid) technology throws us a hard challenge that takes a very long time to solve.
    At the moment our top priorities are:
    Improve documentation, tutorials, demos. Update internal browser to a newer version of Chromium. Upgrade compiler to use a newer version of DWScript. Improve IDE (Designer, Wizards) On top of that we keep a keen eye on the needs and requests of our users and add new features/components to the RTL based on that.
    @Czar Thanks for the tip about the events related bug in the IDE. I was able to reproduce it. There are restrictions on what the IDE can do at the moment. And some restrictions actually depend on what's the best way of developing for the browser. For example, it's a lot better to have fonts and font sizes in CSS instead of setting them in the Object Inspector.
    @IElite Let me know what you want to see regarding mobile devices.
  9. Like
    lynkfs got a reaction from IElite in css styling   
    Wow, you guys are funny.
    The question I had was : what is the easiest way to style Smart components.
    Smart ships with a couple of standard stylesheets, or themes, so styling is a matter of selecting one of these. To change the styling of a specific component in a theme, just change the css specifications in the stylesheet, either manually or through code.
    A different topic altogether is to develop new themes. It is not a simple task to f.i. develop a Metro theme stylesheet which covers all of the current Smart visual components.
    That's why I had a look at externally available css frameworks, to see if any of those would help with developing themes, or even work within the Smart development environment and if they are useful to begin with. I focused on one particular framework : Tailwindcss 
    One of the problems with themes is when it becomes necessary to deviate from it. Say a project has chosen the default theme (default.css), but for some legitimate reason somewhere in the project a standard component has to be styled differently. Example : colour a button green to amplify a positive choice and colour it red to amplify dangerous choices ("do you really want to download these files from an unknown source ?" and then display a green "No" button and a red "Yes" button).
    It's not that simple to make this actually happen.
    Lets say we change the styling of the green button (based on the standard button), and opt to do that in code :
      var Button2 : TW3Button := TW3Button.Create(self);   Button2.SetBounds(20,120,150,40);   Button2.Caption := 'No';   //   Button2.handle.style.background := '#48bb78';          //Button2.Color := clTeal;   Button2.handle.style.border := '1px solid #48bb78';    //Button2.Border.Color := clTeal;   Button2.handle.style.borderRadius := '0px';            //Button2.borderradius := 0;   Button2.handle.style.color := 'white';   // //simulate hover   Button2.handle.onmouseover := procedure(event: variant)   begin     event.target.style.background := 'orange';   end;   Button2.handle.onmouseout := procedure(event: variant)   begin     event.target.style.background := '#48bb78';   end; works sort of ok, but requires a bit of effort
    Alternatively we can change the stylesheet, so if we opt to do that for the red button then this requires
      var Button3 : TW3Button := TW3Button.Create(self);   Button3.SetBounds(200,120,150,40);   Button3.Caption := 'Yes';   //   Button3.TagStyle.Clear;   Button3.TagStyle.Add('TW3Button TW3ButtonRed');   var cssProperties := 'background-color: red;';   browserapi.document.styleSheets[0].insertRule(".TW3ButtonRed { " + cssProperties + " }", 0);   /*   .TW3ButtonRed {     background-color: red;   }   */   cssProperties := 'background-color: orange;';   browserapi.document.styleSheets[0].insertRule(".TW3ButtonRed:hover { " + cssProperties + " }", 0); either in code or adding the .TW3ButtonRed and the .TW3ButtonRed:hover manually to the stylesheet
    Again, works but requires some effort
    Using the Tailwind css framework, the above would be simplified to
    //green var Button4 : TW3Button := TW3Button.Create(self);   Button4.SetBounds(20,220,150,40);   Button4.Caption := 'No';   Button4.handle.className := "bg-green-500 hover:bg-blue-700 px-6 text-white rounded shadow-xl"; //red   var Button5 : TW3Button := TW3Button.Create(self);   Button5.SetBounds(200,220,150,40);   Button5.Caption := 'Yes';   Button5.TagStyle.Clear;   Button5.TagStyle.Add("bg-red-500 hover:bg-blue-700 px-6 text-white rounded shadow-xl");  
    Button1 : standard styling
    Button2 : changing standard styling in code
    Button3 : changing standard styling using css
    Button4/5 : using Tailwind

     
    I've probably confused everyone even more now
    Anyway, these are my thoughts : Tailwind has the advantage that it can style any of the standard Smart components. As such it could be used to make up a f.i. Metro theme. Still a significant task, but doable. Apart from that, I actually quite like Tailwind to style components on a need-to-do basis, their styling functions make the standard SMS buttons, panels, editboxes, memos etc look really good and modern.
    (A card btw is just a panel with a certain layout, where usually multiple of these panels appear on a form or page.)
     
  10. Like
    lynkfs got a reaction from Czar in css styling   
    Wow, you guys are funny.
    The question I had was : what is the easiest way to style Smart components.
    Smart ships with a couple of standard stylesheets, or themes, so styling is a matter of selecting one of these. To change the styling of a specific component in a theme, just change the css specifications in the stylesheet, either manually or through code.
    A different topic altogether is to develop new themes. It is not a simple task to f.i. develop a Metro theme stylesheet which covers all of the current Smart visual components.
    That's why I had a look at externally available css frameworks, to see if any of those would help with developing themes, or even work within the Smart development environment and if they are useful to begin with. I focused on one particular framework : Tailwindcss 
    One of the problems with themes is when it becomes necessary to deviate from it. Say a project has chosen the default theme (default.css), but for some legitimate reason somewhere in the project a standard component has to be styled differently. Example : colour a button green to amplify a positive choice and colour it red to amplify dangerous choices ("do you really want to download these files from an unknown source ?" and then display a green "No" button and a red "Yes" button).
    It's not that simple to make this actually happen.
    Lets say we change the styling of the green button (based on the standard button), and opt to do that in code :
      var Button2 : TW3Button := TW3Button.Create(self);   Button2.SetBounds(20,120,150,40);   Button2.Caption := 'No';   //   Button2.handle.style.background := '#48bb78';          //Button2.Color := clTeal;   Button2.handle.style.border := '1px solid #48bb78';    //Button2.Border.Color := clTeal;   Button2.handle.style.borderRadius := '0px';            //Button2.borderradius := 0;   Button2.handle.style.color := 'white';   // //simulate hover   Button2.handle.onmouseover := procedure(event: variant)   begin     event.target.style.background := 'orange';   end;   Button2.handle.onmouseout := procedure(event: variant)   begin     event.target.style.background := '#48bb78';   end; works sort of ok, but requires a bit of effort
    Alternatively we can change the stylesheet, so if we opt to do that for the red button then this requires
      var Button3 : TW3Button := TW3Button.Create(self);   Button3.SetBounds(200,120,150,40);   Button3.Caption := 'Yes';   //   Button3.TagStyle.Clear;   Button3.TagStyle.Add('TW3Button TW3ButtonRed');   var cssProperties := 'background-color: red;';   browserapi.document.styleSheets[0].insertRule(".TW3ButtonRed { " + cssProperties + " }", 0);   /*   .TW3ButtonRed {     background-color: red;   }   */   cssProperties := 'background-color: orange;';   browserapi.document.styleSheets[0].insertRule(".TW3ButtonRed:hover { " + cssProperties + " }", 0); either in code or adding the .TW3ButtonRed and the .TW3ButtonRed:hover manually to the stylesheet
    Again, works but requires some effort
    Using the Tailwind css framework, the above would be simplified to
    //green var Button4 : TW3Button := TW3Button.Create(self);   Button4.SetBounds(20,220,150,40);   Button4.Caption := 'No';   Button4.handle.className := "bg-green-500 hover:bg-blue-700 px-6 text-white rounded shadow-xl"; //red   var Button5 : TW3Button := TW3Button.Create(self);   Button5.SetBounds(200,220,150,40);   Button5.Caption := 'Yes';   Button5.TagStyle.Clear;   Button5.TagStyle.Add("bg-red-500 hover:bg-blue-700 px-6 text-white rounded shadow-xl");  
    Button1 : standard styling
    Button2 : changing standard styling in code
    Button3 : changing standard styling using css
    Button4/5 : using Tailwind

     
    I've probably confused everyone even more now
    Anyway, these are my thoughts : Tailwind has the advantage that it can style any of the standard Smart components. As such it could be used to make up a f.i. Metro theme. Still a significant task, but doable. Apart from that, I actually quite like Tailwind to style components on a need-to-do basis, their styling functions make the standard SMS buttons, panels, editboxes, memos etc look really good and modern.
    (A card btw is just a panel with a certain layout, where usually multiple of these panels appear on a form or page.)
     
  11. Thanks
    lynkfs got a reaction from IgorSavkic in css styling   
    Browsers are certainly talented as multi-language processors. They have to understand html, css, javascript, svg and lately web-assembly as a fifth language. XML and Json are format specifiers, but could be borderline categorised as languages as well.
    Smart elevates javascript to great heights, but sort of leaves the other ones at the periphery. Especially css.
    Css can be used for a) component styling including colours, fonts etc, b) visual layout of pages/forms and reacting responsively to screen size and orientation and c) interactivity in various forms. Some of this overlaps with the js domain. Smart basically uses css for a) but not for b) or c).
    Looking at various css frameworks out there, I would categorise these as
    on one end of the scale there are many UI kit frameworks where the emphasis is on components - buttons, accordions, cards etc. Sometimes as css stand-alone files, sometimes in conjunction with js. Most of these also have functionality for layout purposes, usually based on flexbox or internal grid structures. on the other end of the scale there are frameworks which forego the component focus, but instead provide a large number of elementary styling functions, which can be applied to any component. and many which occupy a space in between This post is about the open source Tailwind framework, belonging in the second category above, just to see how that would work in the Smart environment.
    Tailwind comes in 2 flavours : a static framework which can be accessed locally or from a cdn, and a more dynamic version. The latter can be tailored dynamically for any specific project and basically needs to be part of the build toolchain. To keep it simple I used the static version.
    Change the res/app.css reference to the tailwind css file (either just replace it or change the reference in the index.html file). Now any component can be made to use this styling. Because this is not more (or less) than a list of individual styling functions, the use boils down to defining what you want. Tell a story as in "give me a button with a green background, which turns to blue on hover, has rounded corners and white text and a shadow effect which makes it seem floating". In code :
      W3Button1.handle.className := "bg-green-500 hover:bg-blue-700 text-white rounded shadow-2xl"; The second button in the demo project (see below) has a different story (className sequence), which gives it a totally different look and feel.
    I kind of like this approach, it works very well with any component, thus also with the built in Smart components.
    It is a bit of a drag specifying these className sequences by hand, so it would be nice if this would be supported in the IDE. There are after all only a small number of categories of these elementary styling bits : backgrounds, typography, borders, spacing, sizing, svg, interactivity and effects. And a relatively limited list of functions per category (bg-green-500 means a green background, 500 is the fifth shade in the green colour scheme. So there will be a bg-green-600, a bg-blue-200 etc). Doable I think.
    Apart from these styling functions, Tailwind also has a number of layout functions. Smart has its own layout mechanism, however the Tailwind functions can be used as well. See the 'card' component in the demo.
    Demo and source
     
     
  12. Haha
    lynkfs got a reaction from Czar in css styling   
    I think sometimes I'm very bad at explaining things. I'll respond over the weekend
  13. Like
    lynkfs reacted to Czar in RoadMap 2019   
    I too would love to see a roadmap plan for the next 12 months. The efforts have been going into special projects that not many people will probably have a use for and the bread-and-butter has been left at a usable but not great state. For example, the IDE could do with love. The fact that the visual components don't surface basics like font size/colour etc and requires work arounds and non-intuitive knowledge suggests low hanging fruit for improvements. The ide has lots of bugs and irritating issues. for example events on buttons will often be reoved or doubled up. e.g., OnSubmitClick for button can be set once but if double click on it again often it breaks.
    Would the team consider open sourcing the IDE? Or maybe looking at a completly different model. I am invested in using SMS but I did so in the hope of meaningful improvements. Jarto I believe you are only active owner and I really appreciate your efforts but you are one person and this project could be so much more with greater input from more people.
     
  14. Thanks
    lynkfs got a reaction from sektor in JQWidget integration   
    and here is the Grid - JQWidgets implementation

     
    working sms demo here
     
    Notes :
    there are 2 different formats of defining the grid, one using jQuery explicitly and one as a web-component. The latter format has a bug somewhere and comes up consistently with a runtime error. The former format works fine. the 'export to Excel' button actually fires up Excel if installed and run locally (sms demo is grid only but take my word)
  15. Like
    lynkfs got a reaction from IgorSavkic in JQWidget integration   
    and here is the Grid - JQWidgets implementation

     
    working sms demo here
     
    Notes :
    there are 2 different formats of defining the grid, one using jQuery explicitly and one as a web-component. The latter format has a bug somewhere and comes up consistently with a runtime error. The former format works fine. the 'export to Excel' button actually fires up Excel if installed and run locally (sms demo is grid only but take my word)
  16. Like
    lynkfs got a reaction from IElite in JQWidget integration   
    I got asked to have a look at how to integrate jqxWidgets in SMS
    There are a heap of ready-made widgets under the name of jQuery UI Widgets, ranging from grids to calendars to tooltips and many more.
    The example here is a jqxButton with an image in the left top corner.
    The vanilla html file for this looks like
    <!DOCTYPE html> <html lang="en"> <head>     <meta name="keywords" content="jQuery Button, CheckBox, Toggle Button, Repeat Button, Radio Button, Link Button, Button" />     <meta name="description" content="The jqxButton widget allows you to display a button on the Web page." />     <title id='Description'>The jqxButton widget allows you to display a button on the Web         page.</title>     <link rel="stylesheet" href="../../jqwidgets/styles/jqx.base.css" type="text/css" />     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />     <meta name="viewport" content="width=device-width, initial-scale=1 maximum-scale=1 minimum-scale=1" />          <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/scripts/jquery-1.11.1.min.js"></script>     <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxcore.js"></script>     <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxbuttons.js"></script>     <script type="text/javascript">         $(document).ready(function ()         {             // Create jqxButton widgets.             $("#jqxButton").jqxButton({ width: 120, height: 40 });             // Subscribe to Click events.             $("#jqxButton").on('click', function ()             {                 $("#events").find('span').remove();                 $("#events").append('<span>Button Clicked</span');             });         });     </script> </head> <body class='default'>     <div>         <input type="button" value="Button" id='jqxButton' />     </div>     <div style='font-size: 12px; font-family: Verdana; margin-top: 10px;'>         <div>Events:</div>         <div id='events'>         </div>     </div> </body> </html> which requires a number of external js and css files. These can be local or reside on a cdn server somewhere. Make sure they are served from either http or https, same as the platform the app is executed on.
    The widgets are created first, immediately after the document is dom-ready, and they will be rendered on a placeholder element with the same element.id as the created widgets.
    This can be simplified considerably in SMS :
    All functions can be recoded using this function tied to the ubiquitous jQuery "$" directive :
    function jqxQuery(aTagObj: string): Variant; external '$'; which results in this code :
        var props : variant := new JObject;     props.height := 40;     props.width  := 120;     props.imgSrc := "https://www.jqwidgets.com/jquery-widgets-demo/images/twitter.png";     props.imgPosition := "topLeft";     jqxQuery( "#jqxButton1" ).jqxButton(props);     jqxQuery( "#jqxButton1" ).on('click', procedure() begin       browserapi.window.alert('clicked button1');     end); and the placeholder element 
      jqxButton1 := TW3Panel.Create(self);   jqxButton1.SetBounds(30,20,126,46);   jqxButton1.handle.style.border := '1px solid grey';   jqxButton1.handle.innerHTML := '<input type="button" value="Button" id="jqxButton1" />'; Sort of a rough and tumble approach, but it does work.
     
    A better way is to encapsulate these widgets in a dedicated component :
    unit jqxButton; { **************************************************************************** } {                                                                              } { Smart Mobile Studio                                                          } {                                                                              } { **************************************************************************** } interface {$I 'Smart.inc'} uses   System.Types,   {$IFDEF THEME_AUTOSTYLE}   SmartCL.Theme,   {$ENDIF}   SmartCL.System,   SmartCL.Components; type   TJQXButton = class(TW3CustomControl)   protected     function  MakeElementTagObj: THandle; override;     procedure InitializeObject; override;   published     property caption: string;  // read GetCaption write SetCaption;   end; function jqxQuery(aTagObj: string): Variant; external '$'; implementation //############################################################################# // TJQXButton //############################################################################# procedure TJQXButton.InitializeObject; begin   inherited;   Caption := 'Button';     //default   Handle.ReadyExecute( procedure ()   begin     var Script := browserapi.document.createElement('script');     Script.src := 'https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxcore.js';     browserapi.document.head.appendChild(Script);     Script.onload := procedure     begin       writeln('jqxcore loaded');       var props : variant := new JObject;       props.height := self.height-2;       props.width  := self.width-2;       props.imgSrc := "https://www.jqwidgets.com/jquery-widgets-demo/images/twitter.png";       props.imgPosition := "topLeft";       jqxQuery( "#jqx" + self.handle.id ).jqxButton(props);     end;     handle.innerHTML := '<input type="button" value="' + Caption + '" id="jqx' +       self.handle.id + '" />';   end); end; function TJQXButton.MakeElementTagObj: THandle; begin   result := w3_createHtmlElement('div'); end; end. which can be instantiated as simple as
      jqxButton2 := TJQXButton.Create(self);   jqxButton2.SetBounds(230,20,130,50);   jqxButton2.Caption := 'Button2';   jqxButton2.OnClick := procedure(Sender:TObject) begin     browserapi.window.alert('clicked button2');   end; Project demo here and source code here
     
     
  17. Like
    lynkfs got a reaction from IElite in JQWidget integration   
    and here is the Grid - JQWidgets implementation

     
    working sms demo here
     
    Notes :
    there are 2 different formats of defining the grid, one using jQuery explicitly and one as a web-component. The latter format has a bug somewhere and comes up consistently with a runtime error. The former format works fine. the 'export to Excel' button actually fires up Excel if installed and run locally (sms demo is grid only but take my word)
  18. Like
    lynkfs got a reaction from jarto in JQWidget integration   
    and here is the Grid - JQWidgets implementation

     
    working sms demo here
     
    Notes :
    there are 2 different formats of defining the grid, one using jQuery explicitly and one as a web-component. The latter format has a bug somewhere and comes up consistently with a runtime error. The former format works fine. the 'export to Excel' button actually fires up Excel if installed and run locally (sms demo is grid only but take my word)
  19. Like
    lynkfs got a reaction from Czar in Font size and style in buttons   
    it is a difficult job to develop themes.
    If you have an example of a theme you prefer, I might have a look (depending on the bounty)
    Cheers
  20. Like
    lynkfs got a reaction from DavidRM in JQWidget integration   
    I got asked to have a look at how to integrate jqxWidgets in SMS
    There are a heap of ready-made widgets under the name of jQuery UI Widgets, ranging from grids to calendars to tooltips and many more.
    The example here is a jqxButton with an image in the left top corner.
    The vanilla html file for this looks like
    <!DOCTYPE html> <html lang="en"> <head>     <meta name="keywords" content="jQuery Button, CheckBox, Toggle Button, Repeat Button, Radio Button, Link Button, Button" />     <meta name="description" content="The jqxButton widget allows you to display a button on the Web page." />     <title id='Description'>The jqxButton widget allows you to display a button on the Web         page.</title>     <link rel="stylesheet" href="../../jqwidgets/styles/jqx.base.css" type="text/css" />     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />     <meta name="viewport" content="width=device-width, initial-scale=1 maximum-scale=1 minimum-scale=1" />          <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/scripts/jquery-1.11.1.min.js"></script>     <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxcore.js"></script>     <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxbuttons.js"></script>     <script type="text/javascript">         $(document).ready(function ()         {             // Create jqxButton widgets.             $("#jqxButton").jqxButton({ width: 120, height: 40 });             // Subscribe to Click events.             $("#jqxButton").on('click', function ()             {                 $("#events").find('span').remove();                 $("#events").append('<span>Button Clicked</span');             });         });     </script> </head> <body class='default'>     <div>         <input type="button" value="Button" id='jqxButton' />     </div>     <div style='font-size: 12px; font-family: Verdana; margin-top: 10px;'>         <div>Events:</div>         <div id='events'>         </div>     </div> </body> </html> which requires a number of external js and css files. These can be local or reside on a cdn server somewhere. Make sure they are served from either http or https, same as the platform the app is executed on.
    The widgets are created first, immediately after the document is dom-ready, and they will be rendered on a placeholder element with the same element.id as the created widgets.
    This can be simplified considerably in SMS :
    All functions can be recoded using this function tied to the ubiquitous jQuery "$" directive :
    function jqxQuery(aTagObj: string): Variant; external '$'; which results in this code :
        var props : variant := new JObject;     props.height := 40;     props.width  := 120;     props.imgSrc := "https://www.jqwidgets.com/jquery-widgets-demo/images/twitter.png";     props.imgPosition := "topLeft";     jqxQuery( "#jqxButton1" ).jqxButton(props);     jqxQuery( "#jqxButton1" ).on('click', procedure() begin       browserapi.window.alert('clicked button1');     end); and the placeholder element 
      jqxButton1 := TW3Panel.Create(self);   jqxButton1.SetBounds(30,20,126,46);   jqxButton1.handle.style.border := '1px solid grey';   jqxButton1.handle.innerHTML := '<input type="button" value="Button" id="jqxButton1" />'; Sort of a rough and tumble approach, but it does work.
     
    A better way is to encapsulate these widgets in a dedicated component :
    unit jqxButton; { **************************************************************************** } {                                                                              } { Smart Mobile Studio                                                          } {                                                                              } { **************************************************************************** } interface {$I 'Smart.inc'} uses   System.Types,   {$IFDEF THEME_AUTOSTYLE}   SmartCL.Theme,   {$ENDIF}   SmartCL.System,   SmartCL.Components; type   TJQXButton = class(TW3CustomControl)   protected     function  MakeElementTagObj: THandle; override;     procedure InitializeObject; override;   published     property caption: string;  // read GetCaption write SetCaption;   end; function jqxQuery(aTagObj: string): Variant; external '$'; implementation //############################################################################# // TJQXButton //############################################################################# procedure TJQXButton.InitializeObject; begin   inherited;   Caption := 'Button';     //default   Handle.ReadyExecute( procedure ()   begin     var Script := browserapi.document.createElement('script');     Script.src := 'https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxcore.js';     browserapi.document.head.appendChild(Script);     Script.onload := procedure     begin       writeln('jqxcore loaded');       var props : variant := new JObject;       props.height := self.height-2;       props.width  := self.width-2;       props.imgSrc := "https://www.jqwidgets.com/jquery-widgets-demo/images/twitter.png";       props.imgPosition := "topLeft";       jqxQuery( "#jqx" + self.handle.id ).jqxButton(props);     end;     handle.innerHTML := '<input type="button" value="' + Caption + '" id="jqx' +       self.handle.id + '" />';   end); end; function TJQXButton.MakeElementTagObj: THandle; begin   result := w3_createHtmlElement('div'); end; end. which can be instantiated as simple as
      jqxButton2 := TJQXButton.Create(self);   jqxButton2.SetBounds(230,20,130,50);   jqxButton2.Caption := 'Button2';   jqxButton2.OnClick := procedure(Sender:TObject) begin     browserapi.window.alert('clicked button2');   end; Project demo here and source code here
     
     
  21. Thanks
    lynkfs got a reaction from IgorSavkic in visual processing   
    See previous post : any type of no-code / lo-code solution requires a visual ide, not only for the visual components like buttons etc but also for the non-visual process components.  Such an ide allows for both visual and non-visual components to be connected according to the principles of FBP. See previous post and link here.
    To see how this would pan out, I made this proof of concept no-code / lo-code web-based ide. (Proof of concept not being a full fledged finished product, but at least gives some insights)
    To diminish the strain on the brain a bit, the layout is based on the Smart ide, including the shameless reuse of its icons. 
    Some highlights :
    - drag and drop placement of components rather than point and select
    - the usual component move and resize facilities but now including Delphi-type align options
    - drag and drop fbp connections between components using jsPlumb
    A quick rundown :
    1) drag a button on the design pane
    2) select 'Database' from the top tab-control, and drag both a grid and mySQL component on the design pane. Note the property pane is updated in realtime
    3) (optionally click-select any dragged component to resize them. Select both grid and button, right-click on either for alignment options)

    4) switch to the No-code tab and connect the button to the mySQL component, and the mySQL component to the grid
    5) right-click the mySQL component and provide details (user-id, server, passwords etc). Not shown
     
    6) switch to the Preview tab and click the button
    This project compiles to 63 KB (0.06 M. Not bad
    Project code here
     
     
     
     
  22. Thanks
    lynkfs got a reaction from LuckyLuke in JQWidget integration   
    I got asked to have a look at how to integrate jqxWidgets in SMS
    There are a heap of ready-made widgets under the name of jQuery UI Widgets, ranging from grids to calendars to tooltips and many more.
    The example here is a jqxButton with an image in the left top corner.
    The vanilla html file for this looks like
    <!DOCTYPE html> <html lang="en"> <head>     <meta name="keywords" content="jQuery Button, CheckBox, Toggle Button, Repeat Button, Radio Button, Link Button, Button" />     <meta name="description" content="The jqxButton widget allows you to display a button on the Web page." />     <title id='Description'>The jqxButton widget allows you to display a button on the Web         page.</title>     <link rel="stylesheet" href="../../jqwidgets/styles/jqx.base.css" type="text/css" />     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />     <meta name="viewport" content="width=device-width, initial-scale=1 maximum-scale=1 minimum-scale=1" />          <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/scripts/jquery-1.11.1.min.js"></script>     <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxcore.js"></script>     <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxbuttons.js"></script>     <script type="text/javascript">         $(document).ready(function ()         {             // Create jqxButton widgets.             $("#jqxButton").jqxButton({ width: 120, height: 40 });             // Subscribe to Click events.             $("#jqxButton").on('click', function ()             {                 $("#events").find('span').remove();                 $("#events").append('<span>Button Clicked</span');             });         });     </script> </head> <body class='default'>     <div>         <input type="button" value="Button" id='jqxButton' />     </div>     <div style='font-size: 12px; font-family: Verdana; margin-top: 10px;'>         <div>Events:</div>         <div id='events'>         </div>     </div> </body> </html> which requires a number of external js and css files. These can be local or reside on a cdn server somewhere. Make sure they are served from either http or https, same as the platform the app is executed on.
    The widgets are created first, immediately after the document is dom-ready, and they will be rendered on a placeholder element with the same element.id as the created widgets.
    This can be simplified considerably in SMS :
    All functions can be recoded using this function tied to the ubiquitous jQuery "$" directive :
    function jqxQuery(aTagObj: string): Variant; external '$'; which results in this code :
        var props : variant := new JObject;     props.height := 40;     props.width  := 120;     props.imgSrc := "https://www.jqwidgets.com/jquery-widgets-demo/images/twitter.png";     props.imgPosition := "topLeft";     jqxQuery( "#jqxButton1" ).jqxButton(props);     jqxQuery( "#jqxButton1" ).on('click', procedure() begin       browserapi.window.alert('clicked button1');     end); and the placeholder element 
      jqxButton1 := TW3Panel.Create(self);   jqxButton1.SetBounds(30,20,126,46);   jqxButton1.handle.style.border := '1px solid grey';   jqxButton1.handle.innerHTML := '<input type="button" value="Button" id="jqxButton1" />'; Sort of a rough and tumble approach, but it does work.
     
    A better way is to encapsulate these widgets in a dedicated component :
    unit jqxButton; { **************************************************************************** } {                                                                              } { Smart Mobile Studio                                                          } {                                                                              } { **************************************************************************** } interface {$I 'Smart.inc'} uses   System.Types,   {$IFDEF THEME_AUTOSTYLE}   SmartCL.Theme,   {$ENDIF}   SmartCL.System,   SmartCL.Components; type   TJQXButton = class(TW3CustomControl)   protected     function  MakeElementTagObj: THandle; override;     procedure InitializeObject; override;   published     property caption: string;  // read GetCaption write SetCaption;   end; function jqxQuery(aTagObj: string): Variant; external '$'; implementation //############################################################################# // TJQXButton //############################################################################# procedure TJQXButton.InitializeObject; begin   inherited;   Caption := 'Button';     //default   Handle.ReadyExecute( procedure ()   begin     var Script := browserapi.document.createElement('script');     Script.src := 'https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxcore.js';     browserapi.document.head.appendChild(Script);     Script.onload := procedure     begin       writeln('jqxcore loaded');       var props : variant := new JObject;       props.height := self.height-2;       props.width  := self.width-2;       props.imgSrc := "https://www.jqwidgets.com/jquery-widgets-demo/images/twitter.png";       props.imgPosition := "topLeft";       jqxQuery( "#jqx" + self.handle.id ).jqxButton(props);     end;     handle.innerHTML := '<input type="button" value="' + Caption + '" id="jqx' +       self.handle.id + '" />';   end); end; function TJQXButton.MakeElementTagObj: THandle; begin   result := w3_createHtmlElement('div'); end; end. which can be instantiated as simple as
      jqxButton2 := TJQXButton.Create(self);   jqxButton2.SetBounds(230,20,130,50);   jqxButton2.Caption := 'Button2';   jqxButton2.OnClick := procedure(Sender:TObject) begin     browserapi.window.alert('clicked button2');   end; Project demo here and source code here
     
     
  23. Like
    lynkfs got a reaction from jarto in JQWidget integration   
    I got asked to have a look at how to integrate jqxWidgets in SMS
    There are a heap of ready-made widgets under the name of jQuery UI Widgets, ranging from grids to calendars to tooltips and many more.
    The example here is a jqxButton with an image in the left top corner.
    The vanilla html file for this looks like
    <!DOCTYPE html> <html lang="en"> <head>     <meta name="keywords" content="jQuery Button, CheckBox, Toggle Button, Repeat Button, Radio Button, Link Button, Button" />     <meta name="description" content="The jqxButton widget allows you to display a button on the Web page." />     <title id='Description'>The jqxButton widget allows you to display a button on the Web         page.</title>     <link rel="stylesheet" href="../../jqwidgets/styles/jqx.base.css" type="text/css" />     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />     <meta name="viewport" content="width=device-width, initial-scale=1 maximum-scale=1 minimum-scale=1" />          <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/scripts/jquery-1.11.1.min.js"></script>     <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxcore.js"></script>     <script type="text/javascript" src="https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxbuttons.js"></script>     <script type="text/javascript">         $(document).ready(function ()         {             // Create jqxButton widgets.             $("#jqxButton").jqxButton({ width: 120, height: 40 });             // Subscribe to Click events.             $("#jqxButton").on('click', function ()             {                 $("#events").find('span').remove();                 $("#events").append('<span>Button Clicked</span');             });         });     </script> </head> <body class='default'>     <div>         <input type="button" value="Button" id='jqxButton' />     </div>     <div style='font-size: 12px; font-family: Verdana; margin-top: 10px;'>         <div>Events:</div>         <div id='events'>         </div>     </div> </body> </html> which requires a number of external js and css files. These can be local or reside on a cdn server somewhere. Make sure they are served from either http or https, same as the platform the app is executed on.
    The widgets are created first, immediately after the document is dom-ready, and they will be rendered on a placeholder element with the same element.id as the created widgets.
    This can be simplified considerably in SMS :
    All functions can be recoded using this function tied to the ubiquitous jQuery "$" directive :
    function jqxQuery(aTagObj: string): Variant; external '$'; which results in this code :
        var props : variant := new JObject;     props.height := 40;     props.width  := 120;     props.imgSrc := "https://www.jqwidgets.com/jquery-widgets-demo/images/twitter.png";     props.imgPosition := "topLeft";     jqxQuery( "#jqxButton1" ).jqxButton(props);     jqxQuery( "#jqxButton1" ).on('click', procedure() begin       browserapi.window.alert('clicked button1');     end); and the placeholder element 
      jqxButton1 := TW3Panel.Create(self);   jqxButton1.SetBounds(30,20,126,46);   jqxButton1.handle.style.border := '1px solid grey';   jqxButton1.handle.innerHTML := '<input type="button" value="Button" id="jqxButton1" />'; Sort of a rough and tumble approach, but it does work.
     
    A better way is to encapsulate these widgets in a dedicated component :
    unit jqxButton; { **************************************************************************** } {                                                                              } { Smart Mobile Studio                                                          } {                                                                              } { **************************************************************************** } interface {$I 'Smart.inc'} uses   System.Types,   {$IFDEF THEME_AUTOSTYLE}   SmartCL.Theme,   {$ENDIF}   SmartCL.System,   SmartCL.Components; type   TJQXButton = class(TW3CustomControl)   protected     function  MakeElementTagObj: THandle; override;     procedure InitializeObject; override;   published     property caption: string;  // read GetCaption write SetCaption;   end; function jqxQuery(aTagObj: string): Variant; external '$'; implementation //############################################################################# // TJQXButton //############################################################################# procedure TJQXButton.InitializeObject; begin   inherited;   Caption := 'Button';     //default   Handle.ReadyExecute( procedure ()   begin     var Script := browserapi.document.createElement('script');     Script.src := 'https://www.jqwidgets.com/jquery-widgets-demo/jqwidgets/jqxcore.js';     browserapi.document.head.appendChild(Script);     Script.onload := procedure     begin       writeln('jqxcore loaded');       var props : variant := new JObject;       props.height := self.height-2;       props.width  := self.width-2;       props.imgSrc := "https://www.jqwidgets.com/jquery-widgets-demo/images/twitter.png";       props.imgPosition := "topLeft";       jqxQuery( "#jqx" + self.handle.id ).jqxButton(props);     end;     handle.innerHTML := '<input type="button" value="' + Caption + '" id="jqx' +       self.handle.id + '" />';   end); end; function TJQXButton.MakeElementTagObj: THandle; begin   result := w3_createHtmlElement('div'); end; end. which can be instantiated as simple as
      jqxButton2 := TJQXButton.Create(self);   jqxButton2.SetBounds(230,20,130,50);   jqxButton2.Caption := 'Button2';   jqxButton2.OnClick := procedure(Sender:TObject) begin     browserapi.window.alert('clicked button2');   end; Project demo here and source code here
     
     
  24. Thanks
    lynkfs reacted to warleyalex in vendor prefix   
    The CSS browser prefixes that you can use are:
    Android:
    -webkit-
    Chrome:
    -webkit-
    Firefox:
    -moz-
    Internet Explorer:
    -ms-
    iOS:
    -webkit-
    Opera:
    -o-
    Safari:
    -webkit-
    Please, fix the smartCL.System 
    --> unitFCSSToken := 'Moz'; ---> I think should be lowecase
    w3_setStyle(FParticles.Handle, BrowserAPI.PrefixDef('transform'), 'scale(0.5,0.5)'); w3_setStyle(FParticles.Handle, BrowserAPI.PrefixDef('transform-origin'), 'left top');  
  25. Like
    lynkfs got a reaction from jarto in visual processing   
    See previous post : any type of no-code / lo-code solution requires a visual ide, not only for the visual components like buttons etc but also for the non-visual process components.  Such an ide allows for both visual and non-visual components to be connected according to the principles of FBP. See previous post and link here.
    To see how this would pan out, I made this proof of concept no-code / lo-code web-based ide. (Proof of concept not being a full fledged finished product, but at least gives some insights)
    To diminish the strain on the brain a bit, the layout is based on the Smart ide, including the shameless reuse of its icons. 
    Some highlights :
    - drag and drop placement of components rather than point and select
    - the usual component move and resize facilities but now including Delphi-type align options
    - drag and drop fbp connections between components using jsPlumb
    A quick rundown :
    1) drag a button on the design pane
    2) select 'Database' from the top tab-control, and drag both a grid and mySQL component on the design pane. Note the property pane is updated in realtime
    3) (optionally click-select any dragged component to resize them. Select both grid and button, right-click on either for alignment options)

    4) switch to the No-code tab and connect the button to the mySQL component, and the mySQL component to the grid
    5) right-click the mySQL component and provide details (user-id, server, passwords etc). Not shown
     
    6) switch to the Preview tab and click the button
    This project compiles to 63 KB (0.06 M. Not bad
    Project code here
     
     
     
     
×
×
  • Create New...