ObjectStore User Defined Menu

Hi -

Not sure how to do this, I've tried and it gave me a circular dependency error.
can I assign a variable as a function? e.g.:

var AAA = TODLabel;
var TODLabel = "TOD";
var BBB = CalcTOD();
...
...

function CalcTOD() {
var clockTime = Sys.getClockTime();
...
TOD = Lang.format("$1$:$2$",[hour, min.format("%02d")]);
Return TOD;
}

function onUpdate() {
// This works. it substitutes AAA with TODLabel and it correctly comes up as "TOD"
dc.drawText(65, 15, Gfx.FONT_XTINY, AAA,Gfx.TEXT_JUSTIFY_CENTER);

// This does not work. It gives me the Circular Dependency Error
dc.drawText(65, 15, Gfx.FONT_XTINY, BBB, Gfx.TEXT_JUSTIFY_CENTER);

// This is the original - which works fine.
dc.drawText(65, 15, Gfx.FONT_XTINY, CalcTOD(), Gfx.TEXT_JUSTIFY_CENTER);

}

  • I have yet to have found a solution to this and thus I am stucked.
    I can't move to next step in being able to create a user selectable data field.

    I guess one option is to global and to onUpdate all the SDK fields. All >10 of them at one go??
  • Do you get the circular dependency error on the sim or hardware? If it's on sim, do you get it only when looking at the memory window or when the app shuts down?
  • Do you get the circular dependency error on the sim or hardware? If it's on sim, do you get it only when looking at the memory window or when the app shuts down?


    in the Sim.
    The hardware circular depedency is there even w/o the above code.

    Anyways - Still need some help on how or is it possible to assign a variable w/ a function (substitute sort of)
    in linux it used to be able to do that, treated as a literal using the backpack ` `
  • You're talking dependencies, I'm talking references (even though I typed dependency). Sorry for the confusion. The error means that you're trying to use something from a module that hasn't finished initializing yet.

    If CalcTOD() and BBB are in the same module, then you get the circular dependency error. This is because while trying to initialize BBB it finds CalcTOD() in the same module, but it hasn't finished initializing yet (you're in the process of initializing the module).

    It's the same issue if you move CalcTOD() and BBB into your class. You end up trying to call a function on an object that hasn't finished initializing. If you put CalcTOD() into a module, then you can initialize BBB with it by calling <module name>.CalcTOD().
  • per right now BBB is a variable declared in as a Global. It points to CalcTOD()

    function CalcTOD() is a function within the Ui.View

    eg:

    class UDRF_View extends Ui.View {
    function initialise() {}
    function onLayout() {.. ...}

    function CalcTOD() {
    var clockTime = Sys.getClockTime();
    ...
    TOD = Lang.format("$1$:$2$",[hour, min.format("%02d")]);
    Return TOD;
    }

    function onUpdate() {
    // This works. it substitutes AAA with TODLabel and it correctly comes up as "TOD"
    dc.drawText(65, 15, Gfx.FONT_XTINY, AAA,Gfx.TEXT_JUSTIFY_CENTER);

    // This does not work. It gives me the Circular Dependency Error
    dc.drawText(65, 15, Gfx.FONT_XTINY, BBB, Gfx.TEXT_JUSTIFY_CENTER);

    // This is the original - which works fine.
    dc.drawText(65, 15, Gfx.FONT_XTINY, CalcTOD(), Gfx.TEXT_JUSTIFY_CENTER);

    }



    that's how I'm currently doing it. Essentially, what I'm trying to do is to create the same menu structure as a native garmin app and have user capability to pick/choose the data fields which he/she would like to go into specific locations within Data Screen 1 (DS1) / Data Screen 2(DS2) etc.

    Then build up a menu structure, again - following native garmin structure and have the resultant selection call a new View which will push a new DS into view.
    But.. i've not even been able to go to a 2nd DS as I'm still stuck wondering how to get the menu structure to be able to revert the correct selected Data Field and to be placed in the right location within the DS1

    hope you can understand. Nett-nett, I want to recreate the menu structure of a native garmin app and have users to be able to pick/choose the various available data fields to be plugged into the data screen Layout.

    Thanks.
  • Are you trying to have CalcTOD() invoked by using BBB in onUpdate()? If so, you should create a method object and use that:

    var BBB = method( :CalcTOD );
    dc.drawText(65, 15, Gfx.FONT_XTINY, BBB.invoke(), Gfx.TEXT_JUSTIFY_CENTER);
  • Are you trying to have CalcTOD() invoked by using BBB in onUpdate()? If so, you should create a method object and use that:

    var BBB = method( :invoke );
    dc.drawText(65, 15, Gfx.FONT_XTINY, BBB.invoke(), Gfx.TEXT_JUSTIFY_CENTER);


    im trying To Create the menu structure similar to garmin'native structure.
    I'm thinking that when I navigate to the menu, once user makes a selection for DataScreen1Field1 (DS1F1), to say TOD, I will assign BBB to be >> BBB = computeTOD().

    After this, it will get passed to onUpdate() and then gets executed in the drawText

    I'm trying to see how the invoke/method example u showed will work - but haven't understood it yet. I Also played around with the weather sample - but since it can't get a valid lat/Lon, I keep getting error 404 as the output so I can't do some trial and error.
  • Former Member
    Former Member over 10 years ago
    It sounds like you are trying to do something that needs method objects as Kyle described. (There was an error in his example that I corrected just now.)

    The problem with the code you have posted is that assigning the BBB variable to CalcTOD() just invokes the CalcTOD() function at that point and sets the BBB variable to the result of the call.

    This code:
    function onUpdate() {
    dc.drawText(65, 15, Gfx.FONT_XTINY, CalcTOD(), Gfx.TEXT_JUSTIFY_CENTER);
    }

    will print the current time of day each time onUpdate is called.

    But this code:
    var BBB = CalcTOD();

    function onUpdate() {
    dc.drawText(65, 15, Gfx.FONT_XTINY, BBB, Gfx.TEXT_JUSTIFY_CENTER);
    }

    Will call CalcTOD once when the app starts and then print the static time of day when the app started each time onUpdate us called.

    To set a variable to a function, and not the result of a function call, you need to use a method object. This is done as shown in Kyle's example. Providing the function symbol to the method API creates a method object. That object can then invoke the function using the .invoke() method.
  • Not expecting a response till US Monday since US guys should be off.
    I'm still having trouble with this. Not working.

    if I follow the recommendation of Method and invoke, I sort of works. but only within the onUpdate.
    class UDRF_View extends Ui.View {
    function initialize() {
    DS1F1 = method(:computeHR);
    }


    function onUpdate(dc) {
    dc.drawText(65, 15, Gfx.FONT_XTINY, TODLabel,Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(65, 20, Gfx.FONT_NUMBER_MEDIUM, DS1F1.invoke(),Gfx.TEXT_JUSTIFY_CENTER);
    }




    If I put it into the menu system hoping that once the user does his selection, I get errors

    class UDRF_DSFO_TimerDelegate extends Ui.MenuInputDelegate {
    hidden var DSFOS;

    function initialize(DSFO) {
    DSFOS = DSFO;
    }

    // now that managed to get user selection up to this point. I'm able to get piece together how we got here
    // We are at DS1F1 (DataScreen1Field1). Then when the user selects the menu Item, we would be able to then
    // piece together DS1F1 as the datafield of choice. We then call the computeX Function.
    function onMenuItem(item) {
    if (item == :DSFT1) {
    Sys.println("Timer selected1:" + DSFOS); // this will be DS1F1. Hence, datafield in DS1F1, user wants it to be TimerTime

    // This does not work !!!
    // DSFOS = UDRF_View.computeTimerTime();

    // This does not work either !!!
    //DSFOS = method (:UDRF_View.computeTimerTime);

    // This does not work either !!!
    //DSFOS = method (computeTimerTime);

    // This does not work either !!!
    //DS1F1 = method (computeTimerTime);

    // This does not work either !!!
    DSFOS = computeTimerTime();

    var HHH = DSFOS + " = computeTimerTime()"; // this creates --> DS1F1 = computeTimerTime()
    Sys.println(HHH);

    Ui.popView(Ui.SLIDE_IMMEDIATE);
    }
    Ui.requestUpdate();
    }
    }



    when the above is executed, as in once user starts playing w/ the menu and wanting to place specific Fields in Specific locations, I get this error

    Could not find symbol computeTimerTime.
    Symbol Not Found Error
    in onMenuItem (/Users/nikeow/Documents/ConnectIQ/UD_RunFields/source/UD_RunFieldsMenuDelegate.mc:142)



    I'm seriously stuck. Been stuck here for quite some time already and not sure how to proceed.
    main objective is just to enable users to do "user selectable" fields to be populated into the position that is wanted on the app.
    Again - Mimicking the native garmin menu structure look/feel etc.

    Note: I'm getting stumped here mainly due to I'm calling a function. If I were to assign a variable to a TEXT/String its OK. Meaning things like the background colour I could do a
    BG = Gfx.COLOR_BLACK


    and that will get substituted w no issues on the onUpdate() call.
  • There are two problems here. First off, you haven't given us enough information; none of the code posted has a function named computeTimerTime. The second problem is that I'm still not clear how you want this code to work.

    This untested code should get you closer to what you want.

    class UDRF_MethodSelectionDelegate extends Ui.MenuInputDelegate
    {
    hidden var _view;

    function initialize(view) {
    _view = view;
    }

    function onMenuItem(symbol) {
    _view.setFieldMethod(symbol);
    return true;
    }
    }

    class UDRF_MethodSelectionMenu extends Ui.Menu
    {
    function initialize() {
    Menu.setTitle("Data Fields");

    // note that the symbol names are the names of functions in
    // UDRF_View...
    Menu.addItem("Timer", :computeTimerTime);
    Menu.addItem("Ascent", :computeTotalAscent);
    Menu.addItem("Decent", :computeTotalDescent);
    }
    }

    class UDRF_View extends Ui.View
    {
    hidden var _method;

    function setFieldMethod(symbol) {
    // symbol is a function of this class. create a method object
    // that we can use to invoke that function on self.
    _method = self.method(symbol);
    }

    function onUpdate(dc) {

    dc.drawText(..., _method.invoke(), ...);

    }
    }


    You will most likely want to make _method an array of method objects, one for each data field that you're drawing.