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

  • huh? But that makes tons of code cause namespace collisions because of.. a var being a symbol somewhere... ok. 

  • Right. I get it. Thanks for the help, its been fun :) 

  • huh? But that makes tons of code cause namespace collisions because of.. a var being a symbol somewhere... ok. 

    Well this has only been an issue since compile-time type checking was implemented (very new, relatively speaking). Seems like a bug or design issue to me.

    At runtime, there's absolutely no issue with reusing a symbol value like this.

    In this specific case, it doesn't seem to matter what the scope of "width" and "height" are, since they're not actually being used to resolve a class member, but they're just used as keys for a dictionary (as per an existing Monkey C API, which is hilarious).

  • https://developer.garmin.com/connect-iq/reference-guides/monkey-c-reference/#symbols

    Symbol objects are lightweight constant identifiers. When the Monkey C compiler finds a new symbol, it will assign it a new unique value. This allows symbols to be used as constants without explicitly declaring a constant

    ...

    Symbols are also useful as keys in data structures like dictionaries:

    ...

    One other important use for symbols is to reference method implementations for calls to Object.method() or when assigning callbacks with Method. In this instances, if a method myMethod{...} has been implemented, it can be referenced as a callbacks using the symbol :myMethod.

    IMO, the problem here is the use of a symbol in the 2nd case (key for dictionary), but the compiler is freaking out bc it's worried about the 3rd case (a method lookup) or something like it.

    (side note: the usability of these forums is sooo bad, whether it's just trying to format text as blockquote followed by the regular paragraph style, or pasting images inline without making them tiny, or really doing anything that's isn't just basic text.)

  • Right. I get it. Thanks for the help, its been fun :) 

    No worries.

    Yeah, I get that you get it haha. I'm super idealistic too, but I've given up on getting Garmin to change certain things. To be fair there are many entrenched design decisions which are probably impossible to change. Also to be fair, that doesn't change the impact of these decisions on devs.

  • function width() {
       return self._width;
    }
    System.println("My width is " + width()); // My width is 280
    System.println("My width is " + :_width.toString()); // My width is _width

    Learned something new today.

  • Would that also require you to call View.onLayout() in your onLayout() if you use a layout? Or is just setting the layout sufficient?

  • Yeah :width is just a symbol that refers to the member width (in the context of self/OverlayView); it's not the member itself. Since it's actually just a number, it doesn't matter if it's reused in this manner.

    You can try this, to see the numerical values of :width and :locX:

    System.println(:width.toString());
    System.println(:width.toNumber()); // 8389066
    System.println(:locX.toString());
    System.println(:locX.toNumber()); // 8389064

  • Would that also require you to call View.onLayout() in your onLayout() if you use a layout? Or is just setting the layout sufficient?

    I don't use layouts, but I do think you have to call setLayout() explicitly (in onLayout()), as there's no concept of a default layout that gets automatically loaded. You don't have to call View.onLayout() (none of the samples do so.)

    I also see that in the AnimationWatchface example you mentioned), the screen is only cleared in onLayout() and not onUpdate(). I think this is a bad idea in general because of the possibility that a system notification could draw somewhere on the screen that isn't rendered in onUpdate(). I think in the case of the AnimationWatchface sample, it doesn't matter at all, since the entire screen is redrawn anyway.

    In most or all of the other samples, dc.clear() is called in onUpdate(), after setting the background and foreground colors.

  • 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

    Yeah, I think this came up years ago in the forums. In some contexts, it's like there's an implicit "using Toybox.System" statement at the top of your file. I think there are certain contexts where you need an explicit using/import tho.

    EDIT: forum still doesn't allow us to quote emojis, while hilariously rendering them at giant size in the quote preview. I always know this will happen, yet it's still kinda funny to see that it hasn't been fixed.