Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by lennart

  1. I presume that event is called just before the dialog appears, like resize does. In html, a non visual elements will not have any width/height. Perhaps if you try to check for visibility (the "showing" method) that solves the problem. It may also be that the resize event has to be adjusted from our side. These events are quite new and was only recently added. Conceptually all such things should be dealt with through inheritance, but since onResize is helpful we added it. But based on the code i see above, i would think visibility is the problem. The dialog only becomes visible "after" the first call to resize. You could perhaps force a secondary resize by calling dialog.invalidate()?
  2. I will look into it, but based on the code you posted above - you are in fact running two effects that will collide. "webkit transition" is also used by the FX effect methods/classes, so unless the onload transition has finished when the fxMoveBy runs, they could in fact collide and cause problems. But I will have a look
  3. lennart

    Multi threading

    Yes you are correct. The only way for a thread to talk with the main program is via messages. While we can argue the logic of this, there is a bigger picture involved here. For instance, the same message broker is used when talking with cross-domain code (f.ex code running inside an IFrame). Now im not going to advocate how awesome this is, because I fully agree that they should have made thread synchronization possible, but sadly I have little influence on the collective wisdom of the WWW consortium. Wish I had, I have more than a few things I would like to say to them. I have had this topic in the back of my mind for a while, and have plans to implement a message-protocol class (or a set of classes) to simplify the whole process. But for now you can only send messages back & fourth like you have already outlined. To send binary data, just base64 encode a stream or a buffer. Its actually not that bad once you get used to it. I once used it to display a VNC feed live, having a thread connect and work with the server, then serializing the bitmap frames and pushing them to the main thread. There they were blitted to a canvas object. Note: Since this is a message based system, I strongly urge you to establish some standards for how you delegate tasks and data. The idea of generating JS that you send back to the browser is not going to work (or at least not for long), and it violates a ton of rules. I would use a MemoryStream and a TWriter and simply write the data quickly -- then serialize the content via the buffer class (look in the stream and memory units, you even have blue-pointers to play with). If you want JSON then its simpler, just populate a record and serialize an instance of it -- and post it as a string
  4. lennart


    Brilliant! Any code you might share?
  5. There are many ways to do this. You could use a timer to update it, or create a recursive TW3Dispatch.requestAnimationFrame () loop. You could also use more classical approaches, rendering to an off-screen bitmap and then attaching that to the background of any visual control. You can even do this "live" via the TW3BackgroundGraphicContext (SmartCL.Graphics.pas), which works great if you define a css-canvas as it's called. You can fin more info on that here: https://stackoverflow.com/questions/3397334/use-canvas-as-a-css-background The most friendly is obviously to use the Paintbox, which resolves to a <canvas> tag in the DOM, coupled with a requestAnimationFrame loop. For demanding stuff, use a TThread background worker to deal with the graphics, and just ship the pre-rendered graphics back to the main application via postmessage() with a binary attachment. You may also find the unit "SmartCL.Legacy.pas" interesting since that gives you TBitmap and TCanvas as close as we could to Delphi.
  6. TW3Button is not a toggle-button. It simply implements "Down" for futher use by decendants. You can also manually handle the DownState, but "TButton" was never a togglebutton. The reason I introduced this here was to simplify button code throughout the API. Instead of having 4 different implementation of "down" we now have 1. TW3ToolbarButton implements the toggle you are looking for, or you can just inherit and derive one yourself. But good idea for a new feature! Ill write it down and see if we can sneak the feature in later
  7. lennart

    From the labs

    Great! I have some standard tests I use on it ofcourse, but there will always be scenarios - so if you have some cases that can be replicated and fixed then please do share!
  8. lennart

    From the labs

    Yep! Also went over the code and optimized it a bit - so its a lot faster now When we have less to do I can add some SQL parsing. But right now our TW3Dataset beats SQLite by omitting SQL. SQLite is nice but its ultimately overkill for cache'd, local data in the browser. What you normally do is download a wad of JSON, parse and inject that into the dataset - then save that to the cache locally. On startup your application would collect changes to the dataset and post that back to the server. This is basically how TClientDataset in Delphi was/is used, as an intermediate storage medium - used primarily to keeping updates that should be posted to the server. Under node.js however, SQLite is compiled into the runtime, so there you should use that. Im also porting over the firebird native API so we can access firebird without any drivers from our node.js services.
  9. lennart

    From the labs

    Ill add another hint
  10. lennart

    From the labs

    A small snapshot from my developer machine today -- can you see what is being added and guess where?
  11. I just explained how it should be handled. And css is cascading, meaning that you define both for webkit, ffox etc. in the same file - you dont need the browserprefix in a static file. Just put it in a css file, add it as a resource and then load it in using TW3Storage functions.
  12. Someone posted a technique for injecting CSS, and while I normally dont go around correcting - the code posted was so bad that it could easily break the application. Smart has classes for css that are easy to use. Always check the RTL folder, and search in the class-browser. So if you are looking for CSS stuff, then search "CSS" in the class browser. Quick intro A stylesheet is just an object, like everything else in the DOM (document object model). The browser will take your css-files (if listed in the html) and load them in, then they turn up as objects you can access. But, you can also create these objects yourself and feed in the CSS as a string. You can even create single rules (or styles) as objects and manually populate them. Few does this since its easier to use a string. Loading CSS The easiest way to load an extra CSS file is to use the LoadCSS() method in TW3Storage. This is a class function in a static class, so you dont create an instance of TW3Storage first. You will find this class in SmartCL.FileUtils. An example for loading css looks like this: TW3Storage.LoadCss('thisurl', procedure (const FromUrl: string; const ObjectHandle: THandle; const Success: boolean) begin if success then begin writeln("css loaded"); end; end); Notice the parameter "objecthandle" in the anonymous callback. This is a handle to the created stylesheet object. You dont need to care about that, but if you should want to manually access the stylesheet DOM object after loading - then this is the easiest way to do it. The second method is to create a stylesheet class: var sheet := TW3StyleSheet.Create; sheet.append(#" .mystyle { background-color: #FFFFFF; }"); This class has several add methods, but it also has a very clear "Append" method, allowing you to add chunks of css style code. So as you can see, getting external css into its own stylesheet is very simple, and class based - rather than hacking into a stylesheet you simply presume will be there. The global stylesheet When your application starts a global stylesheet is created. This is not the theme stylesheet, but a secondary stylesheet that controls and units can use to stuff their dependencies into. All our effect css is stored in this secondary stylesheet. If you just need to store a couple of new styles or define some animation, then its overkill to create a third stylesheet object. Just append your code to the global stylesheet instead var globalstyles := TW3StyleSheet.GlobalStyleSheet(); globalstyles.append(#" .TMyCoolStuff { some-value: 12px; }"); The whole point of Smart is to create standard ways of accessing otherwise cumbersome things. Adding & removing styles from your controls TW3Stylesheet contains more class members that should be interesting: AddClassToElement RemoveClassFromElement FindClassInElement So whenever you want to add a style to a class, these are the best to use. You can also remove and check if a style is applied to an element with these. They take the control-handle as a parameter and should be fairly straight forward to understand. Well, hope it clears up a few things!
  13. lennart


    TW3Dispatch.Execute( procedure () begin // your code here end, 1000);
  14. OK, I have issued a fix which should go out with the build later today or tomorrow (not my table so the manager has to deal with that). I noticed several minor mistakes. For instance, the callback "prepare" in the overloaded ShowDialog method never fired. Delayed callback failed because the method was a class method, marked as static, which means the variables are killed on exit (hence the bug above). Everything is now moved into a normal class, TW3DialogManager, which is available from TW3CustomApplication (or just, application). The Showdialog methods are still exposed as usual, so you dont need to change anything. About adjusting a dialog You asked earlier how to change the glyph and glyph color on a dialog. I must apologize because I did not know the callback didnt fire. But the way you would do this is as such: W3Button1.OnClick := procedure (Sender: TObject) begin application.ShowDialog(aoYesNoCancel, procedure (const Dialog: TW3Dialog) begin Dialog.Header.Caption := 'The header'; Dialog.Text.Caption := 'The text!'; Dialog.Glyph.GlyphType := lgtFontAwesome; Dialog.Glyph.GlyphColor := clWhite; Dialog.Glyph.GlyphId := 'fa-5x fa-exclamation-triangle'; end, procedure (const Dialog: TW3Dialog; const DialogResult: TW3DialogResult) begin writeln("You picked:" + DialogResult.ToString()); end); end; The dialog contains a "glyph" child control, this is of type TW3GlyphContainer (so you must include the unit SmartCL.GlyphContainer if you want to play with this). As you see you have properties for everything here, like GlyphColor. And you need to use the normal Font-Awesome CSS codes to pick the image you want. Simply visit: http://fontawesome.io/icons/ for a list of available glyphs, and set the code(s) as you like. The size is determined by "fa-5x" (5 times the ordinary size). Note: You can also use this in labels. If you set the caption of a label or a button caption to: W3Label1.Caption := ' <i class="fa fa-free-code-camp" aria-hidden="true"></i> Hello world!'; You get a nice fire glyph before the text The fix should be in circulation shortly -- cheers!
  15. I think i can fix this. From what i see above, i have used TW3Dispatch to kill the dialog after the main procedure has been closed. As I look at it now, i realize that the garbage collector can actually eat the Dialog & BlockBox objects since our "free" code executes after the procedure has exited. It would have been different had the dialog + blockbox been fields in a class, then the values would have been safely stored there -- but since they are local variables, the JS runtime gobbles them up on exit and they are in effect "NIL" when i try to access them 100ms later
  16. This should be fixed now. Having said that, and had a look at the latest allegro sources, our code is actually faster! In the previous update I added lookup tables to make RGB -> Color .. Color -> RGB close to instantaneous. Allegro uses expensive and slow text-to-value conversion (or worse, variant which is the default value type in JavaScript). Seondly, allegro is just a thin wrapper over Canvas2d, which is exactly what we have as well - but we have added a lot more features. The tile/block copying code we have is from a demo library that is much faster than allegro ever was. We also give you direct pixel access via TW3ImageData, something allegro doesnt event support. It does a slow and simple setpixel() style call. You could probably inherit from TW3ImageData and implement line, circle, fillrect etc. like you would do with a DIB in delphi -- and it would beat the crap out of HTML5's canvas even. I was going to do that earlier but my time is limited with so much to do. If you look around the RTL you will find all the pieces you need that match and surpass allegro. But, the more the merrier, so I do see the idea of having support for it. Quite a few C games that could be ported I guess, as long as the logic is vanilla C and pointers is kept at a minimum. We have support for pointers btw -- check out the memory buffer classes and "blue-pointer" scheme. I dont think any JS system does what we do there at all. Just my two cents
  17. lennart

    New Themes ?

    If you want to handle everything yourself, then you can shortcircuit the system with: type TMyButton = class(TW3Button) protected procedure StyleTagObject; override; end; And then just reset the whole theme: procedure TMyButton.StyleTagObject; begin inherited; ThemeReset(); end; This will kill theming on that control. But it will still try to match with a CSS style with the same name (TMybutton). Here you can just load in a stylesheet you control instead: // This code goes well in your TApplication.ApplicationStarting() // In new projects there is a "unit1.pas" file that contains your unique application object uses SmartCL.FileUtils; TW3Storage.LoadCSS('res/mycssfile.css', procedure (const FromUrl: string; const ObjectHandle: THandle; const Success: boolean) begin if Success then writeln("My css is now loaded!"); end); Once loaded the control's name will match up with the .TMyButton {} style you have defined there, and voila - you have the best of both worlds.
  18. Ill add a callback with the dialog so things like this is easier to change
  19. It should already be included. It fails because you now have it in two places. PS: You can add webfonts in the project dialog, but font-awesome is a permanent part of the system. Its standard for JS based products like Indy is to delphi. When we go out of alpha we will drop the cloudflair link and include the actual file instead. The easiest way to set the color for the font, is to change the font color either in the themefile or in the font-awesome tag. If you look in the SmartCl.GlyphContainer unit you will see how i have done it there.
  20. lennart

    New Themes ?

    RecursiveElk: Im working on the documentation, but in general: no, there is no way to set a border for everything. You will have to write your own skin for that - or do a recursive function that clears the theming from a control, and then apply your style instead. You can call the thethod "ThemeReset()" to completely remove any theming from a control. If you also set StyleClass := "" then you essentially have a clean, non styled element. Perhaps that will be easier to style if you want something unique. What I would do is the following: Start with the Default skin (ubuntu) file and check the "Use custom css" to get a copy into your project Change the theme element to use whatever palette you want Add your border somewhere (you can also just load in a second stylesheet if you like) With this done I would simply inherit out the controls for my project and use those instead. Override StyleTagObject() in each and set the theme-border to "none" then add your custom borderstyle via TagStyle.AddStyleToControl(Handle, nameofstyle). This may sound like much, but we are talking one procedure per control. You may use a 100 buttons in your program, but you only have to define it once. Writing a new themefile and adapting to the regime sounds easier to be honest. IElite: A theme is made up of smaller parts. When you think of it, a theme engine is just a clever system that keeps track of these parts and makes them available to you. So in our theme scheme we have the following parts: 14 different borders 10 different background types 4 different font sizes Each of these parts is made to be used by one of our 3 control-types. When making the theme I found that we essentially have 3 types of controls, and this seem to be how others organize their systems as well. Both Apple, Android and Linux visually operate with 3 types of controls: Normal controls (button, editbox, checkbox etc) Toolbar controls (toolbutton, seperator and whatever we add in the future) Dialog controls (dialog button and controls styled to catch the users attention). Why should I use this stuff? The idea behind the theming are many, but the jist of it always bakes down to: Make your application look good Concurrency in style Ease of use, making it possible to create new controls that adapt to whatever theme is set The concurrency part is probably the most important to get here. All the theme elements (border, background and font) is made to match its counterpart. For example, DecorativeBorder and DecorativeBackground will always compliment eachother regardless of what skin you use. Same with ButtonBorder and ButtonBackground. The important part here is that each theme-file (css file) defines the same names, but they naturally look different from theme to theme. But if you stick to the regime and try to use the pre-defined borders etc. as much as possible in your own stuff - then your customcontrols will survive between skins. So you can change between Apple, Android and Linux without problems (and more in the future). While iOS seem to be utterly flat and soul-less these days, most UI styles need different borders and small changes to create a living, vibrant look and feel. The reason I prefer the older android theme is because it has a more solid feel than the latest, which is a poor mans copy of iOS. When we made the Apple skin we essentially had to delete most of the stuff in there, because iOS is just flat as a pancake. Button-borders and list-borders are not visible etc. etc. Clearly Apple dont care about older users who might not see too good (1/3 of their userbase) or people with color-blindness (which is 1 out of 10 in the world), When making an app its important to take that into account. Most users would rather use an application that has clear distinction between UI elements, than a UI that demands you to concentrate to navigate visually. But we had to ship themefiles that follows what is modern and good, so we did that. When I have more time I will make more themes. Both the Amiga OS 4.x theme (which is really good), Windows 10 and a couple of Debian based skins is what I personally would like. Cheers Jon
  21. Hi! The dialog has a second control, which is why the text is pushed to the right. This control contains the "alert glyph" from font-awesome. Make sure that this is visible and it should look more normal. Or just inherit from the dialog, set with width of the glyph panel to 0 and that should do the trick.
  22. You are mixing the purpose of these things up. Prefix and PrefixDef are used in two very different scenarios. The first does a prefix to create the qualified JS name. The second is used when altering css directly. I should know, I wrote the RTL
  23. You are looking for: BrowserAPI.Prefix() and BrowserAPI.PrefixDef(). These will give you the right prefixes for the browser currently running. I would strongly urge you to look at the SmartCl.Effects unit and see how css transitions are handled there. We have standard classes for this, so you dont have to manually do this. And even if you have your own CSS you just override and deliver it inside an effect class. You might also be interested in the SmartCL.Tween.** units if you want finer control. CSS is set in the style property of the handle: Handle.style[myproperty] := somevalue; Please note that "style[" is case sensitive, so "Handle.Style" wont work. JavaScript is picky that way. There is also W3_SetStyle() which is more pascal-ish if you like that
  24. lennart


    JSONP is a very obscure technology. Essentially you need to generate Javascript that is then downloaded and injected into the DOM, and then a callback fires ... its a long otello like they say in starwars. You should really use a WebSocket server, which just happens to be a normal http server with websocket on-top of it. Then you can use the much more powerful and stable TW3WebSocket client class instead. Best of luck!
  25. Good catch, will investigate this and have reported it to our project manager. There are a number of things this can be. It can be a clean bug, but somehow I doubt that since Android and vanilla desktop browsers doesnt show this behavior. As you probably know, Apple is not a friendly company towards HTML5 based applications. They imposed a number or restrictions in Safari to ensure that web apps couldnt compete with Appstore. That has sort of backfired on them, but there are a few things we cant get around without Cordova. So I have to ask: 1. Is this running in normal Safari on iOS? 2. What model of iPhone / iPad is it? 3. What version of the OS / Safari version do you have? This could be as simple as a tag declaration, to more complex solutions like how we deal with focus events and delegate event objects.
  • Create New...