-
• #2
Not really... but you can draw a filled rectangle (https://www.espruino.com/Reference#l_Graphics_fillRect) with the background color... of course, you have to know what the font / font size was, the text you want to remove ("Hello Word"). Font / Font size gives you the height and the width you can ask the Espruino Graphics object: https://www.espruino.com/Reference#t_l_Graphics_stringWidth.
To do such things efficiently, you build yourself a DOM - Display Object Model - just as every browser does, so you can find by different means the things you want to erase or override, etc. It's quite a daunting task... but you can do that. That also allows you then to redraw / restore a screen that you have (partially) overwritten with, for example, a pop-up / menu, etc. - on close of that particular pop-up or menu. An other option of handling pop-up like overwrites is to save the graphics buffer - either full or just what is overwritten... but that's not that easy and with colors or grey scale it's also memory consuming - as you calculate yourself - and slow...
-
• #3
@allObjects thanks. I was brain storming an idea. Code an object called "pages" and store text, font size for different pages. Each pcb button will be a different page that contains graphic data(text, color, font and etc)
-
• #4
Just to add that another option is just to change the foreground colour to the background colour and to then write exactly the same text at 30,30 :) It's not as fast as a rectangle clear, but potentially it might make your code tidier
-
• #5
@d0773d, a lot of work if you have not a generic support system / framework that helps with keeping track of this (pages, etc.). You can find conversations of mine related to TFT displays where I was looking into save and restore of display (memory) content to support temporary, regional overwrites... but it is slow - even though @JumJum made it much faster and more recent Espruino and display controller features could be used to accelerate it even more - and memory consuming... understandably.
-
• #7
Howdy. I have a lot of research ahead of me :-)
-
• #8
The complexity depends on your use. From the idea that you want partial update, I assume you do not use the display real estate in a scrolling manner. In other words, each information is always displayed in the same space, but sometimes it uses less and sometimes it uses more of that space. After all, you have to manage anyway that not too much is displayed because it would overwrite / reach into something else - when you have things side by side - and 'fall off the cliff' because it is too long to fit. and will get cut off.
With these assumption you create a function for each information you display. The first thing that this function does is clearing out the space using
.fillRect(...)
.This pattern can then be generalized, as you said that you are thinking of pages with fields on it. Create a
Renderer
that uses the visitor pattern to traverse aPageDefinition
, which consists of an array ofDisplayItems
. EachDisplayItems
contains just what you need:- for fix text: the x/y position and extend (x2/y2 or w(idth) and h(eight)), the text and - if not default font, font-size and colors - those are added.
- for variable info: the
x
/y
position and extend (x2
/y2
orw
(idth) andh
(eight)),dotted.path.info
from global to your value you want to display. To simplify this, you just put your data items as properties into a single global object when you calculate or read it. Thedotted.path.info
is then just this property name. I'll follow up w/ an example. I do exactly the same in my ui stuff (check your dm in forum).
- for fix text: the x/y position and extend (x2/y2 or w(idth) and h(eight)), the text and - if not default font, font-size and colors - those are added.
-
• #9
...something like that: a
RENDERER
singleton for rendering on a display of a particularX
andY
sizepanes
- (full) pages and pop-ups w/ display nodes/items - in variousstyles
:var panes = // declaration of your pages/popups w/ content { start: // a page (covers all of display) { id: "start", no: 0, title: "Start Page", s: 0 // s-tyle obj , nodes: // node displays label or property value [ { id: "s01", x: 0, y: 0, w: 30, h: 20, , l: "ip:" , s: 0 // label "ip:" in default s-tyle , { id: "s02", x: 35, y: 0, w: 30, h: 20, , p: "ip" , s: 0 // property "ip" in model obj (see: MVC pattern) ] } , msg: // a pop-up pane (covers area of display) { id: "msg", no: 0, title: "Message", s: 0, x: 20, y: 20, w: 80, h: 28, , nodes: [ { id: "m01", x: 0, y: 0, w: 30, h: 20, , l: "message:" // label "message:" , { id: "m02", x: 35, y: 0, w: 30, h: 20, , p: "msg" // property "msg" in model object ] } }; var styles = // indexed 0,1,... define font, -size and colors [ { font: "...", size: 9, fg: [1,1,1], bg: [0,0,0] } // 0: default ]; // f(ore)g(round) and b(ack)g(round) color var RENDERER = // Singleton (google it) { g: null, d: null // graphics and display objects , X: 0, Y: 0 // display size, set in init() , ps: null // p(ane)s set in init() , ss: null // s(tyle)s set in inbit() , cpid: null // current p(ane) id, for optimization , cs: -1 // current style (index0, for optimization , doPane: function(pid) { // render pane w/ p(ane)id if (pid != this.cpid) this._initP(pid); // initP(ane) if not current this.ps[this.cpid = pid].nodes.forEach(function(n){ // for each node in pane this._doN(n,0); }); // render node w/ node object w/o clear-first return this; } , doNode: function(nid) { // render node w/ n(ode) id // code here... if node found on other than current pane, doPane(), // else do node w/ node object w/ clear-first: this._doN(n,1); return this; } , _doN: function(n,c) { // render node w/ n(node) object and c(lear-first, truthy) // code here... change style if other than current, remember new current style return this; } , _initP: function(pid) { // init - clear w/ style bg and put title var p = this.ps[pid]; if (p.p) { // page (no frame around) /* page init code here... if title present, set title bar and title */ } else { // pop-up (do frame around) /* popup init code here... if title present, set title bar and title */ } return this; } , _clear: function(x,y,x2,y2,s,b) { // s(tyle index), b(order, truthy) for pop-up // code here... consider b(border) and adjust x,y,x2,y2 accordingly // remember cs - c(urrent) s(tyle) - for optimiztion return this; } , getN(nid) { var n; // get n(ode) by n(ode) id; returns node object n // code here... return n; } , setS(sx) { if (sx !== this.cs) { var s = this.ss[this.cs = sx]; // set stile // set style from s code here ... font / font-size / fore / background colors } return this; } , init: function(g,d,X,Y,panes,styles) { var p, xo, yo; // p(ane) // init and optimize this.g=g, this.d=d, this.X=X; this.Y=Y, this.ps=panes; this.ss=styles; for (pid in panes) { p = panes[pid]; // for each pane w/ p(ane) id in panes if (p.p = (p["x"] === undefined)) { // page - set x,y,x2,y2 & offset for nodes p.x = xo = 0; p.y = 0; p.x2 = this.X-1; p.y2 = this.Y-1; } else { // pop-up - set x,y,x2,y2 & offset for nodes pop-up adjusted p.x2 = (xo = p.x)+p.w-1; p.y2 = (yo = p.y)+p.h-1; } p.nodes.forEach(function(n){ // for each n(ode) in pane: n.p = p; n.x = n.x+xo; n.y = n.y+yo; // - set pane & adjust x, y n.x2 = n.x+ n.w-1; n.y2 = n.y+n.h-1; }); } // - extend for fill_Rect return this; } } // other application code here... function onInit() { // other init code here... // get graphics object g and display object d setup RENDERER.init(g,d,128,64,panes,styles).doPane("start"); // other init code here... }
Still a good amount of coding work left, but that's how I would get started.
The panes and styles definitions use real objects that use more variable space than other constructs, such as arrays... If you see fit, you can make them plain array objects and use the index as the variable name. I do that in my ui stuff. This then changes some of the condition coding, because 'existence' of a value has to be defined differently: length check of array, or if a place holder for the value has to be there to not mess up the indices, a application specific 'undefined' / 'absent' indicator value has to be defined, 0, -1, null, etc. and the test has to consider this 'absent' indicator definition. *Note: X and Y may be retrieved from g(raphics) or d(isplay) object and need then not to be passed... and same applies for either g(raphics) or d(isplay) object.
If the display has no immediate / transparent update when writing to the Espruino Graphics object - in other words when a
.flip()
is required - theRENDERER
needs to get a.flip()
method.
Lets say i have "Hello Word" at 30,30.Is it possible to g.clear(); just that section?