Dev Issue - Multiple roMessageDialog with back button

I’m trying to implement a quick way for the user to change search filter settings, and to accomplish this, I am using an roSearchScreen, and two roMessageDialog windows.

If the user presses the info button (*) on the roSearchScreen, I open the first roMessageDialog, and call EnableBackButton(false) before it is shown. I add two buttons to the first roMessageDialog, one to configure one option, and the other for another option. This window also has EnableBackButton(false) set.

If I open the first roMessageDialog and hit the ‘Back’ button, nothing happens, like I expect. If instead, I choose the option value I want, then return to the first roMessageDialog and hit ‘Back’, the channel returns to my Channel’s home screen, instead of the Search screen, which is unexpected, since I thought I had disabled the Back button.

At this point, my code is still in the first roMessageDialog’s event loop waiting for any kind of message, of course none come, so it is essentially locked. To work around this, I added a timeout to the wait call in the first dialog, and that un-locks my channel’s home screen. Of course this is a dirty workaround, and I can’t leave it that way.

Flow:

Issue:

Home
   -- Search (roSearchScreen)
      -- Options (roMessageDialog)
      -- Hit 'Back' button here = does nothing
         -- Option 1 (roMessageDialog)
            -- Option 1 dialog closes
      -- Options
      -- Hit 'Back' button here
Home

Okay case (as long as I don’t hit the back button after the 2nd roMessageDialog closes, it works fine):

Home
   -- Search (roSearchScreen)
      -- Options (roMessageDialog)
         -- Option 1 (roMessageDialog)
            -- Option 1 dialog closes
         -- Option 2 (roMessageDialog)
            -- Option 2 dialog closes
      -- Hit 'Done'
         -- Options dialog closes
   -- Search
Home

It looks like either I’m doing something incorrectly, or that the platform places roMessageDialogs in a special position atop the screen stack.

Any help would be appreciated!

Edit: Formatted the flows a little better

if you have some code that demonstrates the issue, perhaps you can post it here. In most cases the back button is a firmware action that will close whatever screen is open, so you always need to have a handler for isscreenclosed() events that includes a return statement, and of course, the calling function needs to be able to handle whatever is returned from the called function or sub.

  • Joel

Here’s a stripped-down version of the code that exhibits the issue:

Sub doSearchWindow()
    port = CreateObject("roMessagePort")
    searchScreen = CreateObject("roSearchScreen")
    searchScreen.SetMessagePort(port)

    history = CreateObject("roSearchHistory")
    searchScreen.SetSearchTerms(history.GetAsArray())
    searchScreen.Show()

    while (true)
        msg = wait(0, port)

        if (type(msg) = "roSearchScreenEvent") then
            if (msg.isScreenClosed()) then
                return
            else if (msg.isPartialResult()) then
                ' Unnecessary
            else if (msg.isFullResult()) then
                ' Unnecessary
            else if (msg.isCleared()) then
                ' Unnecessary
            else if ((msg.isRemoteKeyPressed() AND msg.GetIndex() = 10) OR msg.isButtonInfo()) then
                ' Shows the first roMessageDialog for search filters
                SearchOptionsDialog()
            end if
        end if
    end while
End Sub

Function SearchOptionsDialog() as Integer
    dialog = CreateObject("roMessageDialog")
    port = CreateObject("roMessagePort")
    dialog.SetMessagePort(port)
    dialog.SetTitle("Search Options")
    dialog.SetText("Some text")
    dialog.EnableBackButton(false)
    dialog.addButton(1, "Change Filter One")
    dialog.addButton(2, "Change Filter Two")
    dialog.addButton(3, "Done")
    dialog.Show()
    while true
        dlgMsg = wait(0, dialog.GetMessagePort())
        if (type(dlgMsg) = "roMessageDialogEvent") then
            if (dlgMsg.isButtonPressed()) then
                if (dlgMsg.GetIndex() = 1) then
                    ret = FilterOneClicked()
                    if (ret = "") then
                        ' Do other stuff
                    end if
                else if (dlgMsg.GetIndex() = 2) then
                    ret = FilterTwoClicked()
                    if (ret = "") then
                        ' do other stuff
                    end if
                else if (dlgMsg.GetIndex() = 3) then
                    dialog.Close()
                    exit while
                end if
            else if (dlgMsg.isScreenClosed()) then
                dialog.Close()
                exit while
            else
                exit while
            end if
        else
            exit while
        end if
    end while
    return 0
End Function

Function FilterOneClicked() as String
    dialog = CreateObject("roMessageDialog")
    port = CreateObject("roMessagePort")
    dialog.SetMessagePort(port)
    dialog.SetTitle("Filter One")
    dialog.EnableBackButton(false)
    dialog.addButton(1, "None")
    dialog.Show()
    toReturn = ""
    while true
        dlgMsg = wait(0, dialog.GetMessagePort())
        if (type(dlgMsg) = "roMessageDialogEvent") then
            if (dlgMsg.isButtonPressed()) then
                if (dlgMsg.GetIndex() = 1) then
                    toReturn = ""
                end if
                exit while
            else if (dlgMsg.isScreenClosed()) then
                exit while
            end if
        end if
    end while
    dialog.Close()
    return toReturn
End Function

Function FilterTwoClicked() as String
    dialog = CreateObject("roMessageDialog")
    port = CreateObject("roMessagePort")
    dialog.SetMessagePort(port)
    dialog.SetTitle("Filter Two")
    dialog.EnableBackButton(false)
    dialog.addButton(1, "None")
    dialog.Show()
    toReturn = ""
    while true
        dlgMsg = wait(0, dialog.GetMessagePort())
        if (type(dlgMsg) = "roMessageDialogEvent") then
            if (dlgMsg.isButtonPressed()) then
                if (dlgMsg.GetIndex() = 1) then
                    toReturn = ""
                end if
                exit while
            else if (dlgMsg.isScreenClosed()) then
                exit while
            end if
        end if
    end while
    dialog.Close()
    return toReturn
End Function

I modified your code so that it doesn’t call a second dialog.close() on the isScreenClosed() event - (the dialog is already closed, but then you are calling dialog.close() again any time there is an exit while. )

    Sub doSearchWindow()
    			
        port = CreateObject("roMessagePort")
        searchScreen = CreateObject("roSearchScreen")
        searchScreen.SetMessagePort(port)

        history = CreateObject("roSearchHistory")
        searchScreen.SetSearchTerms(["test","west","best","lest","vest"]	)
        searchScreen.Show()

        while (true)
            msg = wait(0, port)

            if (type(msg) = "roSearchScreenEvent") then
                if (msg.isScreenClosed()) then
                
                    return
                else if (msg.isPartialResult()) then
                    ' Unnecessary
                else if (msg.isFullResult()) then
                    ' Unnecessary
                else if (msg.isCleared()) then
                    ' Unnecessary
                else if ((msg.isRemoteKeyPressed() AND msg.GetIndex() = 10) OR msg.isButtonInfo()) then
                    ' Shows the first roMessageDialog for search filters
                    SearchOptionsDialog()
                end if
            end if
        end while
    End Sub

    Function SearchOptionsDialog() as Integer
        dialog = CreateObject("roMessageDialog")
        port = CreateObject("roMessagePort")
        dialog.SetMessagePort(port)
        dialog.SetTitle("Search Options")
        dialog.SetText("Some text")
        dialog.EnableBackButton(false)
        dialog.addButton(1, "Change Filter One")
        dialog.addButton(2, "Change Filter Two")
        dialog.addButton(3, "Done")
        dialog.Show()
        while true
            dlgMsg = wait(0, dialog.GetMessagePort())
            if (type(dlgMsg) = "roMessageDialogEvent") then
                if (dlgMsg.isButtonPressed()) then
                    if (dlgMsg.GetIndex() = 1) then
                        ret = FilterOneClicked()
                        if (ret = "") then
                            ' Do other stuff
                        end if
                    else if (dlgMsg.GetIndex() = 2) then
                        ret = FilterTwoClicked()
                        if (ret = "") then
                            ' do other stuff
                        end if
                    else if (dlgMsg.GetIndex() = 3) then
                        'dialog.Close()
                        return 0
                    end if
                else if (dlgMsg.isScreenClosed()) then
                    return 0
                    exit while
                else
                    exit while
                end if
            else
                exit while
            end if
        end while
        return 0
    End Function

    Function FilterOneClicked() as String
        dialog = CreateObject("roMessageDialog")
        port = CreateObject("roMessagePort")
        dialog.SetMessagePort(port)
        dialog.SetTitle("Filter One")
        dialog.EnableBackButton(false)
        dialog.addButton(1, "None")
        dialog.Show()
        toReturn = ""
        while true
            dlgMsg = wait(0, dialog.GetMessagePort())
            if (type(dlgMsg) = "roMessageDialogEvent") then
                if (dlgMsg.isButtonPressed()) then
                    if (dlgMsg.GetIndex() = 1) then
                        toReturn = ""
                    end if
                    return toreturn
                else if (dlgMsg.isScreenClosed()) then
                    return toreturn
                end if
            end if
        end while
        dialog.Close()
        return toReturn
    End Function

    Function FilterTwoClicked() as String
        dialog = CreateObject("roMessageDialog")
        port = CreateObject("roMessagePort")
        dialog.SetMessagePort(port)
        dialog.SetTitle("Filter Two")
        dialog.EnableBackButton(false)
        dialog.addButton(1, "None")
        dialog.Show()
        toReturn = ""
        while true
            dlgMsg = wait(0, dialog.GetMessagePort())
            if (type(dlgMsg) = "roMessageDialogEvent") then
                if (dlgMsg.isButtonPressed()) then
                	?"button pressed:";dlgmsg.getindex()
                    if (dlgMsg.GetIndex() = 1) then
                        toReturn = ""
                    end if
                    return toreturn
                else if (dlgMsg.isScreenClosed()) then
                	?"screen closed"
                    return toreturn
                end if
            end if
        end while
    End Function

Honestly, I added those after I saw this issue happening. Removing/moving them changes nothing, the first roMessageDialog does not get any events when I hit the back button after opening, then closing the second roMessageDialog.

If I add debug prints, I can see when the associated functions are returning and when I get events, everything is returning/exiting as I would expect, except when I hit the back button.

You can see in the code I explicitly disable the back button, so why is it still firing after the 2nd roMessageDialog closes? The first roMessageDialog shouldn’t allow the back button either, and it doesn’t unless I open/close the 2nd.

Generally, stacking multiple dialogs is not a great idea. Best practice is to close one before opening the other.

I was also able to make it work the way I think you intended by opening a blank roImageCanvas between the two dialogs.

I decided to take your advice RokuChris, and have modified the code to be similar to this (of course I don’t like the delay after closing the 2nd dialog for the window to reappear, but whatever):

        Sub doSearchWindow()
                 
            port = CreateObject("roMessagePort")
            searchScreen = CreateObject("roSearchScreen")
            searchScreen.SetMessagePort(port)

            history = CreateObject("roSearchHistory")
            searchScreen.SetSearchTerms(["test","west","best","lest","vest"]   )
            searchScreen.Show()

            while (true)
                msg = wait(0, port)

                if (type(msg) = "roSearchScreenEvent") then
                    if (msg.isScreenClosed()) then
                   
                        return
                    else if (msg.isPartialResult()) then
                        ' Unnecessary
                    else if (msg.isFullResult()) then
                        ' Unnecessary
                    else if (msg.isCleared()) then
                        ' Unnecessary
                    else if ((msg.isRemoteKeyPressed() AND msg.GetIndex() = 10) OR msg.isButtonInfo()) then
                        ' Shows the first roMessageDialog for search filters
                        while (SearchOptionsDialog() = 2)
                        end while
                    end if
                end if
            end while
        End Sub

        Function SearchOptionsDialog() as Integer
            dialog = CreateObject("roMessageDialog")
            port = CreateObject("roMessagePort")
            dialog.SetMessagePort(port)
            dialog.SetTitle("Search Options")
            dialog.SetText("Some text")
            dialog.EnableBackButton(false)
            dialog.addButton(1, "Change Filter One")
            dialog.addButton(2, "Change Filter Two")
            dialog.addButton(3, "Done")
            dialog.Show()
            while true
                dlgMsg = wait(0, dialog.GetMessagePort())
                if (type(dlgMsg) = "roMessageDialogEvent") then
                    if (dlgMsg.isButtonPressed()) then
                        if (dlgMsg.GetIndex() = 1) then
                            dialog.Close()
                            ret = FilterOneClicked()
                            if (ret = "") then
                                ' Do other stuff
                            end if
                            return 2
                        else if (dlgMsg.GetIndex() = 2) then
                            dialog.Close()
                            ret = FilterTwoClicked()
                            if (ret = "") then
                                ' do other stuff
                            end if
                            return 2
                        else if (dlgMsg.GetIndex() = 3) then
                            'dialog.Close()
                            return 0
                        end if
                    else if (dlgMsg.isScreenClosed()) then
                        return 0
                        exit while
                    else
                        exit while
                    end if
                else
                    exit while
                end if
            end while
            return 0
        End Function

        Function FilterOneClicked() as String
            dialog = CreateObject("roMessageDialog")
            port = CreateObject("roMessagePort")
            dialog.SetMessagePort(port)
            dialog.SetTitle("Filter One")
            dialog.EnableBackButton(false)
            dialog.addButton(1, "None")
            dialog.Show()
            toReturn = ""
            while true
                dlgMsg = wait(0, dialog.GetMessagePort())
                if (type(dlgMsg) = "roMessageDialogEvent") then
                    if (dlgMsg.isButtonPressed()) then
                        if (dlgMsg.GetIndex() = 1) then
                            toReturn = ""
                        end if
                        return toreturn
                    else if (dlgMsg.isScreenClosed()) then
                        return toreturn
                    end if
                end if
            end while
            dialog.Close()
            return toReturn
        End Function

        Function FilterTwoClicked() as String
            dialog = CreateObject("roMessageDialog")
            port = CreateObject("roMessagePort")
            dialog.SetMessagePort(port)
            dialog.SetTitle("Filter Two")
            dialog.EnableBackButton(false)
            dialog.addButton(1, "None")
            dialog.Show()
            toReturn = ""
            while true
                dlgMsg = wait(0, dialog.GetMessagePort())
                if (type(dlgMsg) = "roMessageDialogEvent") then
                    if (dlgMsg.isButtonPressed()) then
                       ?"button pressed:";dlgmsg.getindex()
                        if (dlgMsg.GetIndex() = 1) then
                            toReturn = ""
                        end if
                        return toreturn
                    else if (dlgMsg.isScreenClosed()) then
                       ?"screen closed"
                        return toreturn
                    end if
                end if
            end while
        End Function