How to determine button state?

Hello all!

I am trying to get some help on how to determine a button state.

I have the button(s) setup in Layout.xml:

<layout id="RHButtonLayout">
    <button x="60" y="55" width="100" height="100" behavior="onRHUp">
        <state id="stateDefault" bitmap="@Drawables.RH_MuSelected" />
        <state id="stateHighlighted" bitmap="@Drawables.RH_MuRegular" />
        <state id="stateSelected" bitmap="@Drawables.RH_MuRegular" />
        <state id="stateDisabled" color="Graphics.COLOR_BLACK" />
    </button>
</layout>

in my View i have:

using Toybox.Graphics as Gfx;
using Toybox.WatchUi as Ui;
using Toybox.Lang as Lang;
using Toybox.System as Sys;

class ButtonView extends Ui.View {

    var buttonlayout;

    //! Constructor
    public function initialize(index as Lang.Number) {

        View.initialize();
        buttonlayout = index;

    }

    public function onLayout(dc as Gfx.Dc) as Void {
        if (buttonlayout == 0){
           setLayout($.Rez.Layouts.RHButtonLayout(dc));
        } 
    }
    
    .
    .
    .
    }

And for the Delegate:

class ButtonDelegate extends Ui.BehaviorDelegate {

    //! Constructor
    public function initialize() {

    }

    //! Vibrate on event
    //! @return true if handled, false otherwise
    public function onRHUp() as Lang.Boolean {


        if (Att has :vibrate) {
            var vibrateData = [new Att.VibeProfile(25, 100),
                    new Att.VibeProfile(50, 100),
                    new Att.VibeProfile(75, 100),
                    new Att.VibeProfile(100, 100),
                    new Att.VibeProfile(75, 100),
                    new Att.VibeProfile(50, 100),
                    new Att.VibeProfile(25, 100)] as Lang.Array<Att.VibeProfile>;
            Att.vibrate(vibrateData);
        }


        return true;
    }

This works great.  The button is placed where I want it, it does vibrate (used as a test).

However I want it to function WHILE pressed.

How can I get the state of the press and act accordingly?  (e.g. while selected, when released, etc.)

I also fail to understand how to make it selectable by default when defining the button in Layout.

I would like to be able to select between buttons using the up/down keys on the watch.

my Delegate extends WatchUi.BehaviorDelegate in this case.  is this the correct use for a button delegate here?  it seems to make it selectable i need to change this.

  • So i was able to figure this out, using the selectable example.

    I am now scratching my head trying to figure out what is selected.  I cannot seem to have a parameter like 'id', so that i can use it as a button.

    Any ideas?   if you look at just the selectable example, how can you tell which checkbox is selected?

    I am able to create an additional parameter in the dictionary but i am not able to reference it.  (i am sure there must be an easy solution).  For example, in the selectable example, how can you determine something simple like 'width' of the item selected ??

  • Disclaimer: I haven't used any of this stuff in a real app, I'm just basing my answer on reading the docs and playing with the Selectable example.

    if you look at just the selectable example, how can you tell which checkbox is selected?

    The Drawable class (which is an ancestor of Selectable and Button) has an identifier member, which is a string:

    [https://developer.garmin.com/connect-iq/api-docs/Toybox/WatchUi/Drawable.html#identifier-var]

    If you are creating your Selectable using layout xml, it is the same as the id property. If you are creating your layout programmatically, pass in the value using the :identifier key of the settings dictionary.

    In the Selectable example, you could modify CheckboxView.mc as follows:

    diff --git a/selectable/source/CheckboxView.mc b/selectable copy/source/CheckboxView.mc
    index 51673d1..ce9a188 100755
    --- a/selectable/source/CheckboxView.mc
    +++ b/selectable copy/source/CheckboxView.mc
    @@ -148,13 +148,16 @@ class CheckBoxList {
                 :width=>dims[0],
                 :height=>dims[1]
                 };
    +        options[:identifier] = "checkbox_1";
             _list[0] = new CheckBox(options);
    
             // Create the second check-box
    +        options[:identifier] = "checkbox_2";
             options.put(slideSymbol, 2 * spacing - offset);
             _list[1] = new CheckBox(options);
    
             // Create the third check-box
    +        options[:identifier] = "checkbox_3";
             options.put(slideSymbol, 3 * spacing - offset + BORDER_PAD);
             _list[2] = new CheckBox(options);
         }
    @@ -169,6 +172,7 @@ class CheckBoxList {
         //! @param instance The check box
         //! @param previousState The previous check box state
         public function handleEvent(instance as CheckBox, previousState as Symbol) as Void {
    +        System.println("handleEvent - checkbox identifier = " + instance.identifier);
             // Handle all cases except disabled (handled implicitly)
             if (instance.getState() == :stateHighlighted) {
                 // Only one CheckBox may be highlighted

    For example, in the selectable example, how can you determine something simple like 'width' of the item selected

    Drawable has a width member too.

    [https://developer.garmin.com/connect-iq/api-docs/Toybox/WatchUi/Drawable.html#width-var]

    If you want to define your own custom parameter, you will have to handle it in the initialize() function of your custom class e.g. (Checkbox).

    For example, we can pass in a custom param to the buttons in the ButtonLayout and save it in a custom class that extends WatchUi.Button. (Of course it wouldn't be very helpful since the ButtonDelegate code in the sample doesn't get an instance to a button, but I just wanted to provide a different example that uses an XML layout instead of programmatically creating a layout.) For the Selectable example, it would make more sense to add a custom parameter to the checkboxes.

    Sorry for the screenshot of code, but the forum still doesn't like certain kinds of code, like XML.

    https://postimg.cc/1fdD3W7G

    diff --git a/selectable/source/ButtonView.mc b/selectable copy/source/ButtonView.mc
    index d0709c5..c8ae277 100755
    --- a/selectable/source/ButtonView.mc
    +++ b/selectable copy/source/ButtonView.mc
    @@ -6,6 +6,35 @@
    
     import Toybox.Graphics;
     import Toybox.WatchUi;
    +import Toybox.Lang;
    +
    +class CustomButton extends WatchUi.Button {
    +    public var customParam as Lang.String;
    +    function initialize(
    +        settings as
    +        {
    +            :behavior as Lang.Symbol,
    +            :background as Graphics.ColorType or WatchUi.Drawable,
    +            :locX as Lang.Number,
    +            :locY as Lang.Number,
    +            :width as Lang.Number,
    +            :height as Lang.Number,
    +            :stateDefault as Graphics.ColorType or WatchUi.Drawable,
    +            :stateHighlighted as Graphics.ColorType or WatchUi.Drawable,
    +            :stateSelected as Graphics.ColorType or WatchUi.Drawable,
    +            :stateDisabled as Graphics.ColorType or WatchUi.Drawable,
    +            :identifier as Lang.Object,
    +            :visible as Lang.Boolean,
    +            :customParam as Lang.String
    +        }
    +    ) {
    +        Button.initialize(settings);
    +        customParam = settings[:customParam];
    +        System.println("button id = " + identifier);
    +        System.println("button width = " + width);
    +        System.println("button customParam = " + customParam);
    +    }
    +}

  • If any mods or Garmin employees are reading this, I'd like to say that the forum UX is terrible and there's a bunch of issues that will obviously never be fixed. Sorry to say, but it matches my perception of CIQ and, to a certain extent, Garmin products in general. Just to participate in the dev forums at a certain level, I have to deal with all kinds of quirks, such as:

    - Some code triggers a forum error, so we have to use an external text host or insert an image

    - Sometimes pasting images doesn't work, so we have to use an external image host

    - In the bug reports forum, you can't insert an image in the post body, you have to use a link to an external image, or insert an image in a comment

    - You can't edit comments in the bug reports forum

    - You can't quote emojis

    - If someone edits their post/comment while you're replying to it, it interrupts your edit (and you could lose your work)

    - Sometimes buttons such as More aren't responsive (so I have to reload the page just to edit a comment)

    - You can't preview code blocks (Insert > Code)

    - If a code block is long enough to have a horizontal scrollbar, the scrollbar blocks the final line code, which is especially terrible for one-liners or short snippets

    - You can only focus on one code block at a time, since the code block editor is a modal dialog, unlike every other modern dev-focused editor, which allows code blocks to be entered inline either with markdown or rich text controls. See: Slack, github, etc. Good luck trying to edit multiple code blocks

    Then there's the fact that the mobile experience is bad, and the forum is slow in any case.

    Just a very frustrating experience (like Spotify on Garmin watches.) It "works" but not very well.

  • Awesome FlowState!  Great explanation and solution.

    It works!  I have tried it and everything seems to work as I wanted now.