Struggling a bit with Views and how stuff gets on the screen

I'm trying to get a layer working and I'm hitting an error/warning that seems.. off.

WARNING: fenix6xpro: /home/ciq/src/source/views/OverlayView.mc:54: Unable to detect scope for the symbol reference 'width'.
WARNING: fenix6xpro: /home/ciq/src/source/views/OverlayView.mc:54: Unable to detect scope for the symbol reference 'height'.

I've assumed I'm doing something wrong but the example code in WatchfaceAnimation in the samples directory seems to do the same and runs without this error. 


// lines 106-110 in source/AnimationWatchFaceView.mc

        _drawLayer = new WatchUi.Layer({
            :locX=>_drawLayerArea[0],
            :locY=>_drawLayerArea[1],
            :width=>_drawLayerArea[2],
            :height=>_drawLayerArea[3]});
            
// My code
    var layer = new Ui.Layer({
      :locX       => 140,
      :locY       => 140,
      :width      => 140,
      :height     => 140,
      :visibility => true,
    });

Now when I leave out the width/height it doesn't complain but I can't seem to get anything on the screen. I paint the whole screen blue and than I want the layer to be white and be painted.. yet my screen stays all blue.

Full code can be found here: gitlab.com/.../OverlayView.mc

  • I'm running /home/ciq/.Garmin/ConnectIQ/Sdks/connectiq-sdk-lin-4.1.4-2022-06-07-f86da2dee/16 with typechecking 1

  • That's weird, it should show you something. Maybe it bugged out because i just pushed something?

  • I'm still a bit baffled tho. Why does it DO paint the dc for the view with clearScreen() in onLayout(), but it doesn't do anything for the layer. Yet, when we move the whole shebang to onUpdate() it works. They both have access to the dc object, they both call the same code, one would expect the exact same result..

    Great question. I will just make another wild guess (since those always turn out so well >_>) that onLayout() is called too early to do any layout rendering, although drawing stuff on the (main) dc works at that point.

    It's a moot point since, as discussed, you need to render everything in onUpdate(), so there's basically no point in drawing anything in onLayout.

    https://developer.garmin.com/connect-iq/api-docs/Toybox/WatchUi/View.html#addLayer-instance_function

    Add a WatchUi.Layer on the top of view's layer stack. Users do not need to draw the layer on the screen manually, instead, once a layer is added to the view, the system will draw all layers during screen updates which include View update (e.g. onUpdate/onPartialUpdate) and animation playback.

    Kind of interesting that you don't need to call View.onUpdate() though. It would work if you called it *first* (and that would be necessary if you had a layout and you also wanted to do other stuff programmatically.)

    e.g. typically in onUpdate, you would:

    1) Clear the screen (literally just clearing the screen in this case)

    2) call View.onUpdate()

    3) render other stuff

  • Ha, Device Context, Drawing Canvas.. Patato, tomato :)

  • I'm running /home/ciq/.Garmin/ConnectIQ/Sdks/connectiq-sdk-lin-4.1.4-2022-06-07-f86da2dee/16 with typechecking 1

    I had to make a bunch of other changes to squash some errors, but I finally got the same warnings as you did.

  • But those shouldn't be symbols in the context of :symbol... 

    Let me try it and introduce a var called locX.

    Omg, the namespacing in MonkeyC is somewhat interesting to say the least. You can call System.println() from anywhere in your code without using Toybox.System statements. Plop, there goes my logic for the day Airplane departure Smiley

  • But those shouldn't be symbols in the context of :symbol... 

    Unfortunately, they are. Any kind of non-local name declaration is also a symbol declaration. (If you reuse an existing name, I believe the symbol value will be reused).

  • I'm not 100% agreeing with you. onLayout is when the view first get's displayed on the screen. So it is actually a thing of beauty because you know when you are in there your whole View is in a blank state. You don't need to keep track of counters, etc. You just paint your initial picture and be done with it.

    But I'll just accept that onLayout is the actual constructor and shouldn't do any painting what so ever and just deal with that in onUpdate(). 

  • I'm not 100% agreeing with you. onLayout is when the view first get's displayed on the screen. So it is actually a thing of beauty because you know when you are in there your whole View is in a blank state. You don't need to keep track of counters, etc. You just paint your initial picture and be done with it.

    But I'll just accept that onLayout is the actual constructor and shouldn't do any painting what so ever and just deal with that in onUpdate(). 

    Yeah I was just describing how things are, not how I think they should be.

    Some people have tried to get away with not rendering *everything* in onUpdate(), and it comes back to bite them because of notifications and other issues (I think view slide animations have a similar issue - if you don't clear the screen after an animation, then part of the animation might linger on the screen.)