This demo video
shows how to install the Skin Clock on a 'virgin' device, then how
to quickly load and use the Skin Clock, but there is much more useful
information included below.
filename$ = "/program/settings.ini" 'path and filename of optional settings file (root-relative path is required)
The program reads the specified file if found, then parses the contents for any recognised settings to over-ride any corresponding defaults.
Here is the Load subroutine to explain what is happening:
load:
a$ = "" if FILE.EXISTS(filename$) > 0 then a$ = FILE.READ$(filename$) gosub getpars gosub makestyle refresh gosub paint return The settings file contents are read into a$, then the getpars subroutine is called to parse a$ for any required 'commands=data" pairs.
Checks are made to ensure the embedded default values are only overwritten with valid new data, eg:
if WORD.GETPARAM$(a$,"fontsize$") <> "" then fontsize$ = WORD.GETPARAM$(a$,"fontsize$")
The makestyle subroutine is called to add any new style data into the 'mystyle$' css var, then the screen is repainted with the new loaded styles.
Here is the Skin Clock script, save it as /program/skinclock.bas
Basic:
' Skin Clock - V1.a
filename$ = "/program/skinclock.ini" 'path and filename of optional settings file fonts$ = "default,dig7monoitalic.ttf,dig7mono.ttf,scoreboard.ttf" 'list of available fonts fontpath$ = "/font/" 'path to optional font file 'fontfile$ = "dig7mono.ttf" 'filename.ext of optional font file fontfile$ = "" 'filename.ext of optional font file fontsize$ = "4" 'font size (in em) fontcol$ = "#000000" 'font colour fontbak$ = "#ffffff" 'font background colour fontgrad$ = "#888888" '2nd value for gradient if present - else use "" for solid fontbak$ background colour fontstyles$ = "normal,italic" 'list of available fontstyles fontstyle$ = "normal" 'font style - normal,italic,oblique fontweights$ = "normal,bold" 'list of available fontweights fontweight$ = "normal" 'font weight - normal,bold fontpad$ = "2" 'font padding (in em) fontpad = val(fontpad$) lineheight$ = "1" bordsize$ = "2" 'border thickness (in em) bordsize = val(bordsize$) bordrad$ = "0" 'border corner radius (in em - dependent on border thickness bordcol$ = "#000000" 'border colour bakcol$ = "#ffffff" 'screen background colour voffset$ = "200" 'div top vertical offset in px menu = 0 grad = 0 vpos = 0 gosub makestyle gosub load onhtmlchange htmlchanged timer0 1000, clock 'jumps to refresh every second wait clock: refresh jscall "_$('clock').innerHTML = """ + time$ + """" ' updates the digital display return htmlchanged: wlog "HTMLchanged" fontsize$ = str$(fontsize) bordrad$ = str$(bordrad) bordsize$ = str$(bordsize) fontpad$ = str$(fontpad) voffset$ = str$(voffset) lineheight$ = str$(lineheight / 10) refresh gosub makestyle gosub paint return makestyle: mystyle$ = "font-family: myfont;" vpos$ = str$(val(voffset$) - val(fontsize$)*8) mystyle$ = mystyle$ + "position:relative; top:" + vpos$ + "px;" 'clock vertical centre face$ = fontbak$ if grad = 1 then face$ = "linear-gradient(" + fontbak$ + "," + fontgrad$ + ");" 'may need different syntax for your browser mystyle$ = mystyle$ + "font-size:" + fontsize$ + "em;" mystyle$ = mystyle$ + "font-style:" + fontstyle$ + ";" mystyle$ = mystyle$ + "font-weight:" + fontweight$ + ";" mystyle$ = mystyle$ + "color:" + fontcol$ + ";" mystyle$ = mystyle$ + "background:" + face$ + ";" mystyle$ = mystyle$ + "padding-left:." + fontpad$ + "em;" mystyle$ = mystyle$ + "padding-right:." + fontpad$ + "em;" mystyle$ = mystyle$ + "line-height:" + lineheight$ + ";" if fontstyle$ = "italic" then mystyle$ = mystyle$ + "padding-right:." + str$(fontpad + 1) + "em;" mystyle$ = mystyle$ + "border:" + bordsize$ + "px solid " + bordcol$ + ";" mystyle$ = mystyle$ + "border-radius:." + bordrad$ + "em;" return paint: cls a$ = |<style> @font-face { font-family: myfont; src: url('| + fontpath$ + fontfile$ + |');} | a$ = a$ + "body { background-color: " + bakcol$ + ";}" a$ = a$ + "</style>" a$ = a$ + |<div id='clock' data-var='clicked' onclick='cmdButton(this)' style='display: table; margin-right:auto;margin-left:auto;text-align:center;| a$ = a$ + mystyle$ 'this applies all of the style setting to the clock div a$ = a$ + |'>| a$ = a$ + time$ a$ = a$ + |<br>| a$ = a$ + |</div>| a$ = a$ + |<br><b><br><br>| a$ = a$ + |<div id="controls" style='display: table; margin-right:auto;margin-left:auto;text-align:center;| a$ = a$ + |position:relative; top: | + str$(val(vpos$)-50) + |px;| if menu = 0 then a$ = a$ + |visibility:hidden;| a$ = a$ + |'>| a$ = a$ + |show controls| a$ = a$ + checkbox$(menu) + |<br>| refresh voffset = val(voffset$) a$ = a$ + slider$(voffset,1,500) + |<br>| a$ = a$ + |vertical offset<br>| a$ = a$ + textbox$(filename$,"ftb") + |<br>| a$ = a$ + cssid$("ftb","text-align:center;color:darkblue;background:lightcyan;") a$ = a$ + button$("Save settings",save) + |<br><br>| fontsize = val(fontsize$) a$ = a$ + slider$(fontsize,1,18,1) a$ = a$ + |<br>| a$ = a$ + |font size<br>| a$ = a$ + |<input title="Font colour" type="color" data-var="fontcol$" onchange="cmdChange(event)" value="| + fontcol$ + |"><br>| a$ = a$ + |font colour<br>| a$ = a$ + |<input title="Background colour"type="color" data-var="fontbak$" onchange="cmdChange(event)" value="| + fontbak$ + |"><br>| a$ = a$ + |face colour<br>| a$ = a$ + checkbox$(grad) + |<br>| a$ = a$ + |<input title="Gradient colour"type="color" data-var="fontgrad$" onchange="cmdChange(event)" value="| + fontgrad$ + |"><br>| a$ = a$ + |gradient colour<br>| a$ = a$ + listbox$(fontfile$,fonts$) + |<br>| a$ = a$ + |font file<br>| a$ = a$ + listbox$(fontstyle$,fontstyles$) + |<br>| a$ = a$ + |font style<br>| a$ = a$ + listbox$(fontweight$,fontweights$) + |<br>| a$ = a$ + |font weight<br>| fontpad = val(fontpad$) a$ = a$ + slider$(fontpad,1,8) + |<br>| a$ = a$ + |horizontal padding<br>| lineheight = val(lineheight$) * 10 a$ = a$ + slider$(lineheight,7,25) + |<br>| a$ = a$ + |vertical padding<br>| bordrad = val(bordrad$) a$ = a$ + slider$(bordrad,0,9) + |<br>| a$ = a$ + |border radius<br>| a$ = a$ + |<input type="color" data-var="bordcol$" onchange="cmdChange(event)" value="| + bordcol$ + |"><br>| a$ = a$ + |border colour<br>| bordsize = val(bordsize$) a$ = a$ + slider$(bordsize,0,80) + |<br>| a$ = a$ + |border size<br><br>| a$ = a$ + |<input title="Screen background colour"type="color" data-var="bakcol$" onchange="cmdChange(event)" value="| + bakcol$ + |"><br>| a$ = a$ + |screen colour<br><br>| a$ = a$ + |</div>| html a$ a$ = "" return clicked: if menu = 0 then menu = 1 else menu = 0 gosub paint return getpars: if WORD.GETPARAM$(a$,"fontpath$") <> "" then fontpath$ = WORD.GETPARAM$(a$,"fontpath$") if WORD.GETPARAM$(a$,"fontfile$") <> "" then fontfile$ = WORD.GETPARAM$(a$,"fontfile$") if WORD.GETPARAM$(a$,"fontsize$") <> "" then fontsize$ = WORD.GETPARAM$(a$,"fontsize$") if WORD.GETPARAM$(a$,"fontcol$") <> "" then fontcol$ = WORD.GETPARAM$(a$,"fontcol$") if WORD.GETPARAM$(a$,"fontbak$") <> "" then fontbak$ = WORD.GETPARAM$(a$,"fontbak$") if WORD.GETPARAM$(a$,"fontstyle$") <> "" then fontstyle$ = WORD.GETPARAM$(a$,"fontstyle$") if WORD.GETPARAM$(a$,"fontweight$") <> "" then fontweight$ = WORD.GETPARAM$(a$,"fontweight$") if WORD.GETPARAM$(a$,"fontgrad$") <> "" then fontgrad$ = WORD.GETPARAM$(a$,"fontgrad$") if WORD.GETPARAM$(a$,"fontpad$") <> "" then fontpad$ = WORD.GETPARAM$(a$,"fontpad$") if WORD.GETPARAM$(a$,"lineheight$") <> "" then lineheight$ = WORD.GETPARAM$(a$,"lineheight$") if WORD.GETPARAM$(a$,"bordsize$") <> "" then bordsize$ = WORD.GETPARAM$(a$,"bordsize$") if WORD.GETPARAM$(a$,"bordrad$") <> "" then bordrad$ = WORD.GETPARAM$(a$,"bordrad$") if WORD.GETPARAM$(a$,"bordcol$") <> "" then bordcol$ = WORD.GETPARAM$(a$,"bordcol$") if WORD.GETPARAM$(a$,"bakcol$") <> "" then bakcol$ = WORD.GETPARAM$(a$,"bakcol$") if WORD.GETPARAM$(a$,"voffset$") <> "" then voffset$ = WORD.GETPARAM$(a$,"voffset$") if WORD.GETPARAM$(a$,"grad") <> "" then grad = val(WORD.GETPARAM$(a$,"grad")) if grad = 1 then fontbakcol$ = "linear-gradient(" + fontbak$ + "," + fontgrad$ + ")" else fontbakcol$ = fontbak$ return setpars: WORD.SETPARAM a$, "fontpath$", fontpath$ WORD.SETPARAM a$, "fontfile$", fontfile$ WORD.SETPARAM a$, "fontsize$", fontsize$ WORD.SETPARAM a$, "fontstyle$", fontstyle$ WORD.SETPARAM a$, "fontweight$", fontweight$ WORD.SETPARAM a$, "fontcol$", fontcol$ WORD.SETPARAM a$, "fontbak$", fontbak$ WORD.SETPARAM a$, "fontgrad$", fontgrad$ WORD.SETPARAM a$, "fontpad$", fontpad$ WORD.SETPARAM a$, "lineheight$", lineheight$ WORD.SETPARAM a$, "bordsize$", bordsize$ WORD.SETPARAM a$, "bordrad$", bordrad$ WORD.SETPARAM a$, "bordcol$", bordcol$ WORD.SETPARAM a$, "bakcol$", bakcol$ WORD.SETPARAM a$, "voffset$", voffset$ WORD.SETPARAM a$, "grad", str$(grad) return save: ' Saves settings to file a$ = "" if FILE.EXISTS(filename$) > 0 then a$ = FILE.READ$(filename$) gosub setpars FILE.SAVE filename$, a$ gosub paint return load: ' Loads settings from file a$ = "" if FILE.EXISTS(filename$) > 0 then a$ = FILE.READ$(filename$) gosub getpars gosub makestyle refresh gosub paint return '---------------------- END ----------------------- Run the script by itself to see what the embedded defaults look like when displayed in the Output window. Then click on the Advanced checkbox in the editor. We are going to create a settings file, so change the normally hidden File to Edit name to '/program/settings.ini' in readiness to save. Select All in the editor ready to be overwritten, then copy and paste the following settings from below, and click Save. Because Advanced is ticked, the clock script should still be loaded in the background, so switch to the Output window and click Run. The clock script should load the style settings from '/program/settings.ini' and display this 'Moonlight' skin. fontsize$=8 fontcol$=#ffffe6 fontbak$=#0000ff bordsize$=10 bordrad$=4 bordcol$=#666666 grad=1 Now let's give it hell... Copy and paste the following settings over the previous editor contents and click Save, then go to the Output tab, click Stop, then Run. fontsize$ = "14" fontcol$ = "#ffff00" fontbak$ = "#ff0000" bordsize$ = "25" bordrad$ = "0" bordcol$ = "#c60000" bakcol$ = "#000000" grad=1 Welcome to Hell. Click Stop, switch back to Editor, change bakcol$ from "black" to "white" then Save it, switch to Output and Run it.You can keep changing settings in the Editor tab and viewing the results in the Output tab. When done playing with settings, untick the Advanced checkbox and open /program/skinclock.bas into the editor again. The ability to manually save settings to a file for reading back later can be useful, but it would be better if the program could save its current settings, and ideally there might be a more convenient way to change settings rather than use a text editor. Easier said than done of course, and would be great if it all appeared like magic with a click of the fingers or a mouse button - and ABRACADABRA... it actually does ! Click on the clock and all the controls appear, click on the clock again (or untick the 'show controls' checkbox) and they disappear. The controls allow you to change any of the settings, then Save them to the displayed filename using the 'Save settings' button. If you change the settings filename showing in the window you need to press Enter to register the name change, then click Save settings button. All the controls are labelled underneath, so you should be able to find your way around (the 'vertical offset' slider moves the clock up or down). A word of warning - once you have saved a settings file, remember that those saved settings will always over-ride the embedded defaults. A stylish digital clock deserves a stylish digital display... so it has been given a facility to add embedded fonts of your own choosing. The same 'embedded font' facility could obviously offer tailored fonts for any of your other Annex-Wifi Basic projects if you wish.
NOTE: Fonts
The CSS3 @font-face Rule allows you to create your own font family name pointing to a font file that has been downloaded from the web and uploaded to the ESP device. The font style declaration takes the form of: <style> @font-face {
font-family: myfont; src: url('/path/fontname.ext') }
</style> <style>@font-face {font-family: myfont; src: url('/path/filename.ext');}</style>
Substitute the name 'myfont' for your own preferred name if you wish.
Substitute '/path/' for the 'root-relative' path to your font(s). eg: '/font/'
Substitute 'filename.ext' for the saved font filename and its extension (eg:ttf)
Or preferably use a pre-defined variable in place of the literal 'filename.ext'
NOTE: the default system font will be used if the specified font file is not found, as can be demonstrated by the following example.
myfontfile$ = "dig7mono.ttf"
html |<style>@font-face {font-family: myfont; src: url('/font/| + myfontfile$ + |');}</style>| html |<p style="font-family: myfont;">This line is just to show an example of what my font looks like.</p>| TIP:
A handy tip to remember... you don't need to lose your existing script
contents to quickly try something else such as the example above, simply
add END above your existing code, then add your new temporary code above
END so Annex-Wifi Basic will run the temporary code then terminate
without bothering about anything below. When done, just remove the
temporary test code and END and you are back as you were. The following website offers a top 10 list of free font download sites: Top of that list is https://www.dafont.com/ which offers many LED and 7-segment display fonts in the 'Techno' category - here are links to 2 fonts and their free for personal use licences - the 3 renamed font files used in these demos are include at the bottom of this page (upload them to /font/). TIP: Annex Toolkit now has a ZIP facility, so zip contents can be uploaded into the appropriate ESP folders (a zip is attached at bottom of page). ...you should refer to the gz file with its regular name, omitting the final .gz. Example: if the original file is named
dig7monoitalic.ttf the compressed gz version should be named
dig7monoitalic.ttf.gz BUT it must always be called in the program using its original name without the .gz extension. If the original file is present it will be loaded, but if the original filename is not found then the server will automatically try to send the corresponding compressed .gz version ... so in practice you can replace any file with the correspondeing compressed .gz version without any change in the code. TIP: Search for "7-zip portable" for a free archive utility which does not need to be installed and can even be run from a USB flash drive. NOTE: (Wiki quote:) "A monospaced font, also called a fixed-pitch, fixed-width, or non-proportional font, is a font whose letters and characters each occupy the same amount of horizontal space. This contrasts with variable-width fonts, where the letters and spacings have different widths." This is an important consideration for a digital clock display, because you don't want the clock width to keep changing according to the differing widths of the changing numbers, eg: 11 is narrower than 14 is narrower than 08 - but all digits of a Monospaced font occupy the same space. NOTE: Don't forget about the SPIFFS 31 character limit - a 6 chr path called '/font/' leaves 25 chrs max for the filename.ext, but fonts may have longer names and include characters that could give SPIFFS indigestion, so rename fonts to something reasonable that won't cause problems.
NOTE: The bigger the font, the longer to load... all the fonts I used were smaller than 50K (one is only 22K). TIP: Search for 'portable font viewer' if you need a free font-viewing app which doesn't require installation. HINT: Create a list of favourites skins - rename favourite settings files and add them to a list of skins, ie: skins$ = "moonlight, hell, steel, sleek" Then add a listbox which will allow you to select your choice of skin from the list, ie: html listbox$(choice$,skins$) You'll need to add path and .ext before loading the file... but the script offers an almost identical usage of selecting a font file from a list. Use the same principle of selecting different sets of parameters to add configuration options to any of your Annex-Wifi Basic projects.
|