|FXRUBY] contextual menu in an Icon List

Dear rubyists,

has any of you ever managed to Build a FXIconList with a contextual menu
over every item in the list (contextual menu which would change
depending on which item you right-clicked on)

So far, all my attempts have given something not really usable.

If so, a code snippet would be really welcomed…

TIA,

···


Pierre Baillet
In the words of the ancients, one should make his decision within the space of
seven breaths. It is a matter of being determined and having the spirit to
break through to the other side.
Ghost Dog - The Way of the Samouraï

Pierre Baillet wrote:

Dear rubyists,

has any of you ever managed to Build a FXIconList with a contextual menu
over every item in the list (contextual menu which would change
depending on which item you right-clicked on)

So far, all my attempts have given something not really usable.

If so, a code snippet would be really welcomed…

I have a file browser class based on FXFileList which has a
context-sensitive popup. FXFileList is based on FXIconList, so the same
technique would work. I’ll try to extract a snippet, but if you want the
full code it’s in my foxtails package on RAA. Look at
lib/foxtails/FTFileBrowser.rb and examples/file-browser.rb.

When initializing, you connect the icon list with this method call:

   connect(SEL_RIGHTBUTTONRELEASE, method(:onPopupMenu))

and define onPopupMenu as in FXFileSelector::onPopupMenu in the fox source:

 def onPopupMenu sender, sel, event
   if event.moved then return 1 end

   index = getItemAt(event.win_x, event.win_y)

   filemenu = FXMenuPane.new(self)

   ### Add your menu items here ###

   FXMenuCommand.new(filemenu, ...)

   filemenu.create()
   filemenu.popup(nil, event.root_x, event.root_y)
   filemenu.grabKeyboard
   getApp().runModalWhileShown(filemenu)
   return 1
 end

I haven’t noticed any delay whatsoever in dynamically creating panes
like this. YMMV.

FoxTails also has dynamically generated popup menu buttons (see
examples/simple.rb and lib/foxtails/FTPopupButton.rb).

Forgot to say:

  index = getItemAt(event.win_x, event.win_y)

Use index to set up your context.

  filemenu.grabKeyboard

This is not in the fox source version, but I like being able to use
arrow keys and Enter to select from the menu.

Joel,

thanks for your tips, it works perfectly !

···

On Sun, Mar 16, 2003, Joel VanderWerf wrote:

[the solution to have contextual menus using a FXIconList in Ruby]

Cheers!

Pierre Baillet
Among the maxims on Lord Naoshige’s wall, there was this one: “Matters of great
concern should be treated lightly.” Master Ittei commented, “Matters of small
concern should be treated seriously.”
Ghost Dog - The Way of the Samouraï

Joel VanderWerf wrote:

Pierre Baillet wrote:

Dear rubyists,

has any of you ever managed to Build a FXIconList with a contextual menu
over every item in the list (contextual menu which would change
depending on which item you right-clicked on)

So far, all my attempts have given something not really usable.

If so, a code snippet would be really welcomed…

I have a file browser class based on FXFileList which has a
context-sensitive popup. FXFileList is based on FXIconList, so the same
technique would work. I’ll try to extract a snippet, but if you want the
full code it’s in my foxtails package on RAA. Look at
lib/foxtails/FTFileBrowser.rb and examples/file-browser.rb.

When initializing, you connect the icon list with this method call:

  connect(SEL_RIGHTBUTTONRELEASE, method(:onPopupMenu))

and define onPopupMenu as in FXFileSelector::onPopupMenu in the fox source:

def onPopupMenu sender, sel, event
  if event.moved then return 1 end

  index = getItemAt(event.win_x, event.win_y)

  filemenu = FXMenuPane.new(self)

  ### Add your menu items here ###

  FXMenuCommand.new(filemenu, ...)

  filemenu.create()
  filemenu.popup(nil, event.root_x, event.root_y)
  filemenu.grabKeyboard
  getApp().runModalWhileShown(filemenu)
  return 1
end

I haven’t noticed any delay whatsoever in dynamically creating panes
like this. YMMV.

FoxTails also has dynamically generated popup menu buttons (see
examples/simple.rb and lib/foxtails/FTPopupButton.rb).

That part about “filemenu.grabKeyboard” is really nice. Thanks much
for the tip also.

If the menu is complex and shows some delay, I’d split the menu pane
instantiation part out, and only bind the create/popup/run to the
right click event.

You may also have to manage the selection a bit to give some feedbackk
on which items this is going to run on.

if !isItemSelected(index)
killSelection
setCurrentItem(index)
selectItem(index)
end

Thien Vuong wrote:

That part about “filemenu.grabKeyboard” is really nice. Thanks much
for the tip also.

You’re welcome.

If the menu is complex and shows some delay, I’d split the menu pane
instantiation part out, and only bind the create/popup/run to the
right click event.

How would you handle dynamic menu content then?

You may also have to manage the selection a bit to give some feedbackk
on which items this is going to run on.

if !isItemSelected(index)
killSelection
setCurrentItem(index)
selectItem(index)
end

That’s a good idea. I was thinking it would be better if right-click
didn’t change the selection and instead operated only on the clicked-on
object, but that’s probably bad GUI design. Also, I notice that at least
one file browser (konqueror) does change the selection as you suggest,
and it agrees with you even in the case of multiple selection.

Joel VanderWerf wrote:

Thien Vuong wrote:

If the menu is complex and shows some delay, I’d split the menu pane
instantiation part out, and only bind the create/popup/run to the
right click event.

How would you handle dynamic menu content then?

You should be able to use FXWindow#removeChild to remove menu commands
that are no longer needed, e.g.

 menuPane.removeChild(aMenuCommand)

and add new menu commands to an existing menu pane as usual, e.g.

 FXMenuCommand.new(menuPane, ...)

Don’t forget about the FXWindow#linkBefore and FXWindow#linkAfter
methods, if you need to rearrange the order of child windows. Also don’t
forget to call create on newly-added child windows if they’re being
added to an already-created menu pane, i.e.

 newItem = FXMenuCommand.new(menuPane, ...)
 newItem.create

Having said all of that… unless the menu is really, really complex,
it ought to be fast enough to just create these popup menus on-the-fly,
as needed.

You may also have to manage the selection a bit to give some feedbackk
on which items this is going to run on.

if !isItemSelected(index)
killSelection
setCurrentItem(index)
selectItem(index)
end

That’s a good idea. I was thinking it would be better if right-click
didn’t change the selection and instead operated only on the clicked-on
object, but that’s probably bad GUI design. Also, I notice that at least
one file browser (konqueror) does change the selection as you suggest,
and it agrees with you even in the case of multiple selection.

Also important to note that FXIconList#getItemAt will return -1 if they
don’t right-click on an item (i.e. they perhaps right-click in the
whitespace outside of any items). Your code should presumably handle
this possibility :wink:

Lyle Johnson wrote:

Joel VanderWerf wrote:

Thien Vuong wrote:

If the menu is complex and shows some delay, I’d split the menu pane
instantiation part out, and only bind the create/popup/run to the
right click event.

How would you handle dynamic menu content then?

You should be able to use FXWindow#removeChild to remove menu commands
that are no longer needed, e.g.

menuPane.removeChild(aMenuCommand)

and add new menu commands to an existing menu pane as usual, e.g.

FXMenuCommand.new(menuPane, ...)

But then you have to add them back when the context changes back to an
item that requires them. The logic is clearer if you just build up the
menus from scratch, isn’t it?

I suppose if you only had 2 or 3 kinds of items, you could precreate
menus for each…

Don’t forget about the FXWindow#linkBefore and FXWindow#linkAfter
methods, if you need to rearrange the order of child windows. Also don’t
forget to call create on newly-added child windows if they’re being
added to an already-created menu pane, i.e.

newItem = FXMenuCommand.new(menuPane, ...)
newItem.create

Having said all of that… unless the menu is really, really complex,
it ought to be fast enough to just create these popup menus on-the-fly,
as needed.

That’s been my experience too. Even with 3 cascades, checked items, icon
items, etc.

Also important to note that FXIconList#getItemAt will return -1 if they
don’t right-click on an item (i.e. they perhaps right-click in the
whitespace outside of any items). Your code should presumably handle
this possibility :wink:

In that case I go ahead and add “Delete…”, for example, but I disable
it to show it only applies when you actually manage to hit an item.

Joel VanderWerf wrote:

But then you have to add them back when the context changes back to an item that requires them. The logic is clearer if you just build up the menus from scratch, isn't it?

Oh, definitely. That's why I threw in the point later about on-the-fly menu creation being fast enough for most cases. Just playing devil's advocate here, I guess :wink: