Blog
All Blog Posts | Next Post | Previous PostUsing CSS styles for FNC Components in TMS WEB Core
Tuesday, January 23, 2024
CSS, or Cascading Style Sheets, is a a de-facto standard in web development, used for defining the presentation of a document written in HTML. Its importance lies in its ability to separate content from design, allowing for greater flexibility and control over the appearance of a website. With CSS, developers and designers can specify styles for text, colors, spacing, layout, and responsive design features, ensuring that web pages look consistent across different browsers and devices.
TMS FNC (Framework Neutral Components) components from TMS Software are unique due to their cross-framework compatibility, enabling developers to use them across multiple development environments and frameworks including VCL (Visual Component Library for Delphi/C++Builder), FMX (FireMonkey for cross-platform), LCL (Lazarus Component Library), and Web. This versatility means that a single set of components can be used to develop applications for Windows, macOS, iOS, Android, Linux and web platforms, significantly reducing development time and effort.
Due to this universal character of FNC components, it must be perfectly possible to control the look & feel of the components in VCL, FMX, LCL frameworks where a concept such as CSS does not exist. Typically, this is the classic approach of having color, border, font properties for parts of the control. And with these various properties, it is also possible to control the look & feel of FNC controls in a TMS WEB Core web application.
Bringing CSS in the mix for FNC
Now, as through CSS we can define things as colors, borders, fonts, ... what if CSS information could be used to define the appearance of an FNC control? Well, by interpreting the value of such color, border, font settings from CSS, we can apply it directly to FNC control properties. With some helper functions, this can be easily achieved actually.
CSS helper classes
We introduce 3 class helpers for 3 essential FNC classes that control appearance: TTMSFNCGraphicsFill, TTMSFNCGraphicsFont & TTMSFNCGraphicsStroke. For these 3 classes, we will write a class helper that can initialize its settings from a CSS class. The classes are defined as:
TTMSFNCGraphicsFillHelper = class helper for TTMSFNCGraphicsFill procedure InitFromCSS(cssname: string); end; TTMSFNCGraphicsFontHelper = class helper for TTMSFNCGraphicsFont procedure InitFromCSS(cssname: string); end; TTMSFNCGraphicsStrokeHelper = class helper for TTMSFNCGraphicsStroke procedure InitFromCSS(cssname: string); end;
The implementation of these class helpers is:
{ TTMSFNCGraphicsFillHelper } procedure TTMSFNCGraphicsFillHelper.InitFromCSS(cssname: string); var atr: TCSSAttributes; begin atr := cssAttributes(cssname); Color := atr.bkcolor; end; { TTMSFNCGraphicsFontHelper } procedure TTMSFNCGraphicsFontHelper.InitFromCSS(cssname: string); var atr: TCSSAttributes; begin atr := cssAttributes(cssname); Color := atr.txtcolor; Name := atr.fntname; Height := -atr.fntsize; end; { TTMSFNCCustomGraphicsStrokeHelper } procedure TTMSFNCGraphicsStrokeHelper.InitFromCSS(cssname: string); var atr: TCSSAttributes; begin atr := cssAttributes(cssname); Color := atr.brdcolor; Width := atr.brdwidth; end;
As you can see, for the fill, we simply get the solid background color from the CSS. For the font we get font color, name and size. And for the borders, we get the border color and the border width.
Getting the CSS values for these parts is done with a helper function cssAttributes() that tries to extract these values from a CSS class and it stores what it can retrieve in a helper record:
TCSSAttributes = record brdcolor: TColor; brdwidth: integer; bkcolor: TColor; txtcolor: TColor; fntname: string; fntsize: integer; end;
The implementation of the function cssAttributes() is:
function cssAttributes(cssclass: string): TCSSAttributes; var dummy: TJSHTMLElement; cssstyle: TJSCSSStyleDeclaration; bkclr,txtclr,brdclr,fntsz,brdsz: string; re: TJSRegexp; ja: TStringDynArray; r,g,b: integer; begin // Create a dummy element dummy := TJSHTMLElement(document.createElement('div')); dummy['class'] := cssclass; // Append the element to the body to ensure the style is applied document.body.appendChild(dummy); // Use getComputedStyle to get the computed style values cssstyle := window.getComputedStyle(dummy); bkclr := cssstyle.getPropertyValue('background-color'); txtclr := cssstyle.getPropertyValue('color'); brdclr := cssstyle.getPropertyValue('border-color'); Result.fntname := cssstyle.getPropertyValue('font-family'); fntsz := cssstyle.getPropertyValue('font-size'); fntsz := copy(fntsz, 1, pos('px', fntsz) - 1); Result.fntsize := parseInt(fntsz); brdsz := cssstyle.getPropertyValue('border-width'); brdsz := copy(brdsz, 1, pos('px', brdsz) - 1); Result.brdwidth := parseInt(brdsz); // Remove the dummy element again document.body.removeChild(dummy); re := TJSRegexp.New('^rgb\((\d+),\s*(\d+),\s*(\d+)\)$'); ja := re.exec(bkclr); r := parseInt(ja[1]); g := parseInt(ja[2]); b := parseInt(ja[3]); Result.bkcolor := RGB(r,g,b); ja := re.exec(txtclr); r := parseInt(ja[1]); g := parseInt(ja[2]); b := parseInt(ja[3]); Result.txtcolor := RGB(r,g,b); ja := re.exec(brdclr); r := parseInt(ja[1]); g := parseInt(ja[2]); b := parseInt(ja[3]); Result.brdcolor := RGB(r,g,b); end;
Basically, this function inserts a dummy DIV element in the DOM, applies the CSS class and then gets the computed style from this element and then throws this element away again. The computed style values are returned as a record of the type TCSSAttributes.
These values can finally be used to set properties of the FNC classes TTMSFNCGraphicsFill, TTMSFNCGraphicsFont & TTMSFNCGraphicsStroke that control the appearance.
Putting it all together
For a TMS FNC grid, we'd like to use following CSS classes to set the appearance of cells with banding in the grid.
The CSS we can add for that is for example:
<style> .cellfg { background-color: red; color: white; border-width:2px; border-color: blue;} .cellbg { background-color: yellow; color: black; border-width: 1px; border-color: silver;} </style>
and then we extract the FNC control appearance properties from these CSS classes with:
begin TMSFNCGrid1.InitSample; TMSFNCGrid1.Appearance.NormalLayout.Fill.InitFromCSS('cellfg'); TMSFNCGrid1.Appearance.NormalLayout.Font.InitFromCSS('cellfg'); TMSFNCGrid1.Appearance.NormalLayout.Stroke.InitFromCSS('cellfg'); TMSFNCGrid1.Appearance.SelectedLayout.Font.InitFromCSS('cellfg'); TMSFNCGrid1.Appearance.FocusedLayout.Font.InitFromCSS('cellfg'); TMSFNCGrid1.Appearance.BandLayout.Fill.InitFromCSS('cellbg'); TMSFNCGrid1.Appearance.BandLayout.Font.InitFromCSS('cellbg'); TMSFNCGrid1.Appearance.BandLayout.Stroke.InitFromCSS('cellbg'); end;
The good news of this approach is that we loose nothing of the flexibility of FNC styling. We can apply this technique for every detail that is configurable in FNC controls. Downside is that it might mean a bit more work writing the CSS classes and the code to get settings from these classes.
The result before and after applying CSS based settings to the TMS FNC Grid is:
You can play with this yourself if you have the latest TMS WEB Core full or trial release and TMS FNC UI Pack full or trial installed by downloading this sample project here.
Further considerations
At this moment, these helper classes get basic colors, border widths and font information from the CSS. These helper classes could be extended to also get gradient fill information, border styles from CSS or things like text alignment. Let us know your thoughts and where you would want to see us take this!
Bruno Fierens
This blog post has not received any comments yet.
All Blog Posts | Next Post | Previous Post