Button UI problem

I have an HTMLViewer with foward and back buttons. I’m trying to mimic the behavior in Safari where a long click brings up a popup menu from which you can select pages you’ve viewed. I achieve this by starting a timer on the MouseDown event, and if a certain period is reached before the mouse is released a popup menu is created. It works well except that once the popup appears, regardless of whether a selection is made or not, the pushbutton stays pressed even when the mouse is released. I have to click in the window again to make the button resume its normal receptive state.

This is true for normal pushbuttons and SegmentedButtons.

This seems like a simple problem, but I haven’t found a solution that reverts the button to its “up” state programmatically. Any advice?

Use a ContextualMenu to achieve your goal ?
(instead of a button)

Yes, of course, and I’ve done that as well. But as I said, I want to mimic the behavior of Safari, which Safari users are used to.

Are you using MouseExit? When the mouse leaves the button you reset its state.

How does one reset the state programmatically? I’ve tried various approaches when the popup is about to be opened, but nothing has worked.

In my buttons, in MouseDown I set a flag and then refresh the button (which is a canvas). Then in the Paint event I set the button’s background colour slightly so I can see it is pressed (this is based on the flag set earlier). In mouse exit I clear the flag and refresh the button to get the background colour reset.

In mouseUp I do the button’s action if the flag is set, and clear the flag.

In your case in mouse exit you could cancel the timer. Otherwise, what state are you referring to when you say “How does one reset the state programmatically”?

I’m using pushbuttons, not a canvas. And MBS methods to set the images (forward and back arrows) as templates and other UI features. I’m not looking for other approaches, I want to understand why the button maintains its depressed state when a popup menu is invoked rather than assuming the unpressed state when the mouse is released, and how to avoid that.

Are you using the MouseUp or MouseExit events?

I can reproduce the effect by calling MenuItem.PopUp in the MouseDown event. Other weird effects also occur (menu shortcuts no longer work). This does not happen if I move MenuItem.PopUp to the Action event.

What is the methodology you use to determine the hold time and actually pop up the menu?

In the MouseDown event a timer is set to mode = 1 and a delay of 300 ms. If the mouse is still down when the timer fires a popup menu is created. That works just fine. But the button remains in the pressed state and remains that way even when the mouse is released. And yes, I’ve seen those weird effects, too.

Compare this to Safari, where the button assumes the unpressed state when the user has dealt with the popup (either by selecting a destination or clicking elsewhere).

Is having the visual state become pressed important? If I return true from MouseDown none of the ill-effects occur.

Yes, because a normal click on a forward or back arrow changes the page – it’s a real button, so you should see the button pressed appearance. An a long press shows the button is being held down prior to the popup appearing. Maintaining the macOS UI is important.

BTW, it’s not just the appearance of the button that is pressed, the button remains actually functionally pressed. That’s why keyboard shortcuts don’t work while it’s in that state.

Well interrupting the MouseDown event with a modal function like MenuItem.PopUp seems to be causing a problem. I can’t say I’m surprised.

Xojo doesn’t provide us access to the button state, but setting it with a declare after the call to MenuItem.PopUp seems to be resolving the issue. You should double check the behavior on Windows if you plan to deploy there.

declare sub setHighlighted lib "AppKit" selector "setHighlighted" (oTarget as Integer, bValue as Boolean)
setHighlighted(btnTest.Handle, false)

Which is why I created my own buttons based on a canvas. That gives the required control over the button’s behaviour.

1 Like

I don’t have anything good to say about using Canvas as a button. You’re alienating users who need accessibility devices.

@Tim_Parnell Thanks, Tim, it looks like that does the trick! I’ll see if I can apply this, or an equivalent, to SegmentedControls as well. As for using canvases as buttons, yeah, that has its problems, too. In addition to accessibility, real buttons (plus MBS) handle the pressed state and dark mode for templates much more easily.