Sorry. I just read again your post and realized my mistake.
I do not know how you process the value of the popupmenus, but just an idea :
Sub Change()
static oldindex as integer = 0
if instr(me.text,"?") = 1 then
me.listindex = oldindex
return
end if
dim oldtext as string = me.text
dim zindex as integer = me.listindex
me.RemoveRow(zindex)
me.InsertRow(zindex,"? "+oldtext)
oldindex = me.listindex
End Sub
This way when a row has been selected it starts with ?, so when one tries to select it a second time you can revert to the previous choice and ignore it. Just an idea to keep the code in the PopupMenu.
I think what he’s asking for is when a menu option is selected for the gray color, for example, it either disables or removes it from the lists of all the OTHER popups.
Since you can initialize the PopupMenu in MouseDown when the user clicks on it, you can maintain a central multi-dimensions array containing all the options for all the PopMenus, so you can manage selected colors for all.
Since is not possible to disable a single item in a popupmenu control, you have to build the popup in the mouseDown event.
So the open event of your colorPopup control set :
if v.Ubound=-1 then
v.Append "":"Unassigned"
v.Append "U":"Unmodified"
v.Append "A":"Acetil"
v.Append "O":"Oxidation"
v.Append "P":"Propionyl"
end if
me.AddRow v(0).Right.StringValue
me.RowTag(0)=v(0).Left.StringValue
me.ListIndex=0
where v is v() as pair a window property
then in the mouseDown event:
#Pragma Unused x
#Pragma Unused y
dim t() as String
dim c as String=me.RowTag(me.ListIndex)
for i as integer=0 to kLastIndexOfColorPopup
if i<>index and colorPopup(i).RowTag(colorPopup(i).ListIndex).StringValue<>"" then
t.Append colorPopup(i).RowTag(colorPopup(i).ListIndex)
end if
next
me.DeleteAllRows
dim r as integer
for i as integer=0 to v.Ubound
if t.IndexOf(v(i).Left.StringValue)=-1 then
me.AddRow v(i).Right.StringValue
me.RowTag(r)=v(i).Left.StringValue
if c=v(i).Left.StringValue then me.ListIndex=r
r=r+1
end if
next
This code will not work on linux since the mouseDown event is never called. In that case you have to use a flag to “block” the change event and rebuild all the popupmenu in the change event.
[quote=122439:@Antonio Rinaldi]This code will not work on linux since the mouseDown event is never called. In that case you have to use a flag to “block” the change event and rebuild all the popupmenu in the change event.
[/quote]
It s possible to implement a workaround MouseDown for the PopMenu in Linux through a 100 ms multiple timer with this code in the Action event :
Sub Action()
if System.MouseDown then
if System.MouseX > PopupMenu1.left+self.left and system.MouseX < PopupMenu1.left+self.left+PopupMenu1.width _
and System.MouseY > PopupMenu1.Top+self.top and System.MouseY < PopupMenu1.Top+self.top+PopupMenu1.Height then
msgbox "mousedown !"
end if
end if
End Sub
Thanks for all the suggestions - I think I have a very nice solution now involving two methods in a custom PopupMenu and two arrays on the window (to keep track of the controls).
your solution works
But is not really reusable (think about all the window1 cast the you make)
A better solution is:
create the container control with the canvas and the popup (as you did)
create 2 computed property theText and theColor
in theColor set add the canvas invalidate command
in theText get return if(popupMenu1.listIndex>0,popupMenu1.text, kNotAssigned)
in theText set verify set the popup listIndex to the proper value (0 if the same value or based on the list)
This “rule” is the core function since if the passed value is the same as the current then it will change the list index to the non assigned index otherwise it will change to the listIndex value (if exist)
create a method to reassign the values list with a string array
create a method to initialize the values (color, list and current text) (if you add the component via code otherwise call the reassign list in the window open event)
define an event with the newText as parameter to be called from the popupmenu change event if the current text is not kNotAssigned
Use this event in the window to tell to all the other containers that the new text has been selected so who has that value must reset to kNotAssigned. To do this simply set the other container property theText to the newText value.
Thanks, Antonio. Not sure yet how that second bit works though
[quote=123161:@Antonio Rinaldi]
create a method to reassign the values list with a string array
create a method to initialize the values (color, list and current text) (if you add the component via code otherwise call the reassign list in the window open event)
define an event with the newText as parameter to be called from the popupmenu change event if the current text is not kNotAssigned
Use this event in the window to tell to all the other containers that the new text has been selected so who has that value must reset to kNotAssigned. To do this simply set the other container property theText to the newText value.
This way your container is self contained.[/quote]
define an event in the container control (for example TextChanged(newText as string)
in the popupmenu change event write if me.text<> kNotAssigned then raiseEvent TextChanged me.text
How to use this event in your window is based on how you put the container control (via IDE o by code)
In general the strategy is:
tell to all this containerControl except the one that raised this event to set theText to the newText parameter.
For example (if you used the IDE to put the CCs and they are named cc1,cc2,cc3 etc)
in cc2 TextChanged event you have to write:
cc1.theText=newText
cc3.theText=newText
instead if you use addHandler to set the EventAction and you have a cc() array of cc you have to define a window method like:
doTextChanged(c as myCC, newText as string)
for i as integer=0 to cc.ubound
if cc(i)<>c then cc(i).theText=newText
next