• Hello,

    I'm currently developing a watch face with a background image that covers the whole screen.

    But since I still want to support widgets, I have to draw them somehow after filling the display with my background image.

    However, the well-known sequence

      Bangle.loadWidgets();
      Bangle.drawWidgets();
    

    fills the widget area with white and, thus, destroys my background image.

    How can I draw widgets without clearing their area?

  • The Bangle.js 2 drawWidgets() code is here: https://github.com/espruino/Espruino/blo­b/master/libs/js/banglejs/Bangle_drawWid­gets_Q3.js

    So your app could override that with something like this:

    Bangle.drawWidgets = function() {
      // Same as default Bangle.drawWidgets
      var w=g.getWidth(), h=g.getHeight();
      var pos = {
    	  tl:{x:0, y:0, r:0, c:0}, // if r==1, we're right->left
    	  tr:{x:w-1, y:0, r:1, c:0},
    	  bl:{x:0, y:h-24, r:0, c:0},
    	  br:{x:w-1, y:h-24, r:1, c:0}
      };
      if (global.WIDGETS) {
        for (var wd of WIDGETS) {
      	  var p = pos[wd.area];
      	  if (!p) continue;
      	  wd.x = p.x - p.r*wd.width;
      	  wd.y = p.y;
      	  p.x += wd.width*(1-2*p.r);
      	  p.c++;
        }
        g.reset();
        // Changes start here:
        if (pos.tl.c || pos.tr.c) {
          g.setClipRect(0,0,w-1,23);
         // TODO: redraw top widget area background
         g.reset();
       }
       if (pos.bl.c || pos.br.c) {
         g.setClipRect(0,h-24,w-1,h-1);
         // TODO: redraw bottom widget area background
         g.reset();
       }
        try {
            for (wd of WIDGETS) {
                // clear individual widget background:
                g.clearRect(wd.x,wd.y, wd.x+wd.width-1,23);
                wd.draw(wd); 
           }
       } catch(e) {print(e);}
      }
    }
    

    You want to override Bangle.drawWidgets() instead of just drawing them yourself, because widgets tend to call Bangle.drawWidgets() to show/hide themself.
    And you need to redraw the background for the same reason: widgets can be shown/hidden, which moves other widgets around. (I guess you could keep track of widget positions to check if you really need to redraw)

  • Hi @Andreas_Rozek

    You can load the widgets but you dont have to draw them, or rather you can disable the drawing of the widgets.

    Bangle.loadWidgets();
    /*
     * we are not drawing the widgets as we are taking over the whole screen
     * so we will blank out the draw() functions of each widget and change the
     * area to the top bar doesn't get cleared.
     */
    for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
    

    What this code does is ensure that the area of the widget is set to blank and that the draw function of the widget (should it be called) does nothing.

    That will still leave the potential for the system to clear the widget line every now and again. It does this on the basis of the current theme, usually the background will be white or black. If you background is blue you want to ensure that the current theme background is also blue.

    A good exmaple of this is done in the waveclk, lines 56 and 56 set a custom background.

    // Clear the screen once, at startup
    g.setTheme({bg:"#f0f",fg:"#fff",dark:tru­e}).clear();
    
  • I know that I do not have to draw any Widgets - but I want to do so.

  • Perfect, thank you very much for your response (particularly the "TODO" comments in there)!

    This gives me the information I need to

    • draw my own background prior to any widgets and
    • then to draw all widgets on top of that

    Thanks a lot!

    Edit:

    • I followed your suggestion and implemented a modified version of "Bangle.drawWidgets" - it works like a charm!
    • what surprises me, though, is the call of g.setClipRectRect in line 27 - is this part of the original code or did you edit it?

    Edit 2:

    • I found it: you edited the original code! Thus, you may perhaps want to correct that line

    Thanks again for your effort!

  • Whoops, that was indeed one Rect too many, thanks for pointing it out. (edited now)

  • Glad you got this sorted! It's worth noting that sometimes Widgets do clear their own backgrounds so you may not be able to avoid this. If you just need to change the colour you can use setTheme - see Wave Clock for an example.

    Potentially there's another method which is to provide a 16 bit offscreen buffer for each widget, render to that (but with a custom background colour like 0x0001) and then use that as a transparent colour with g.drawImage. It's all extremely involved though! There is some code on the forum to do with doubling the size/relocating widgets that could be used as a base

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Bangle.js 2: how to draw Widgets without clearing Widget area?

Posted by Avatar for Andreas_Rozek @Andreas_Rozek

Actions