def set_pol_entries(self, choices, default): """ Create radio buttons to switch between pol positions within legend. If only one pol pos present in data, display pol pos as static text. :param choices: polarization positions found in data """ self.clear() if len(choices) > 1: # if we have multiple choices -> select between choices with radio button self.pol_display = GraphicalRadioButtonControl(self, choices=choices, labels=choices) self.pol_display.SetToolTip("Select a polarization direction for display.") self.pol_display.Bind(wx.EVT_BUTTON, self.OnPolarizationButton) self.pol_display.SetValue(default) else: self.pol_display = wx.TextCtrl(self, style=wx.NO_BORDER | wx.CB_READONLY) self.pol_display.SetBackgroundColour(self.bg_color) self.pol_display.SetForegroundColour(self.fg_color) # if only one choice -> only text displayed self.pol_display.SetValue(next(iter(choices))) self.control_sizer.Add(self.text, 0, border=10, flag=wx.ALIGN_CENTER | wx.RIGHT) self.control_sizer.Add(self.pol_display, 1, border=10, flag=wx.ALIGN_CENTER | wx.RIGHT) # refresh layout self.border_sizer.Layout() self.Parent.Layout() # need to be called as method is called after self.Layout im main thread
def createRadioButtons(self, choices, value=None): """ Creates the radio buttons in the legend. :param choices: (list or tuple) Choices to be set for the radio buttons. :param value: (str or None) Radio button that should be active. """ self.pos_display = GraphicalRadioButtonControl(self, choices=choices, labels=choices) self.pos_display.SetToolTip("Select a position for display.") self.pos_display.Bind(wx.EVT_BUTTON, self.OnPositionButton) if value: self.pos_display.SetValue(value) # set the value
def add_radio_control(self, label_text, value=None, conf=None): """ Add a series of radio buttons to the settings panel :param label_text: (str) Label text to display :param value: (None or float) Value to display :param conf: (None or dict) Dictionary containing parameters for the control """ if conf is None: conf = {} lbl_ctrl = self._add_side_label(label_text) value_ctrl = GraphicalRadioButtonControl(self, -1, style=wx.NO_BORDER, **conf) self.gb_sizer.Add(value_ctrl, (self.num_rows, 1), flag=wx.ALL | wx.EXPAND | wx.ALIGN_CENTER_VERTICAL, border=5) if value is not None: value_ctrl.SetValue(value) return lbl_ctrl, value_ctrl
class RadioLegend(wx.Panel): """ This class describes a legend containing radio buttons, where each button represents a possible selection of a VA. """ def __init__(self, parent, wid=-1, pos=(0, 0), size=wx.DefaultSize, style=wx.NO_BORDER): wx.Panel.__init__(self, parent, wid, pos, size, style) # Store the colours now, as we'll need them whenever the radio button choices change, and by that time the # parent (ARViewport) might be focused, which causes it to have a different background colour. self.bg_color = parent.GetBackgroundColour() self.fg_color = parent.GetForegroundColour() self.SetBackgroundColour(self.bg_color) self.SetForegroundColour(self.fg_color) # descriptive VA text self.text = wx.TextCtrl(self, value="Polarization", style=wx.NO_BORDER | wx.CB_READONLY) self.text.SetBackgroundColour(self.bg_color) self.text.SetForegroundColour(self.fg_color) self.text.SetToolTip("Polarization direction currently displayed") # current polarization displayed in the legend (or None) # can be radio buttons or text only depending on the number of polarization directions self.pol_display = None self.control_sizer = wx.BoxSizer(wx.HORIZONTAL) # border_sizer is needed to add a border around the legend self.border_sizer = wx.BoxSizer(wx.VERTICAL) self.border_sizer.Add(self.control_sizer, border=8, flag=wx.ALL | wx.EXPAND) self.SetSizer(self.border_sizer) def clear(self): """Remove the display widget, to not show anything. It will be added again next time the polarization entries are set.""" self.control_sizer.Clear() # destroy the old widgets (otherwise they are still displayed in the GUI) if self.pol_display: self.pol_display.Destroy() self.Refresh() @wxlimit_invocation(0.2) def Refresh(self): """ Refresh, which can be called safely from other threads """ if self: wx.Panel.Refresh(self) def OnPolarizationButton(self, event): """ In the case of an event (select a button), the radio button selection is requested and the callback function, which changes the position is called. The _callback function can be overwritten by the viewport. """ pol = self.pol_display.GetValue() self._callback(pol) def set_pol_callback(self, func): self._callback = func def set_pol_value(self, pol): self.pol_display.SetValue(pol) @call_in_wx_main def set_pol_entries(self, choices, default): """ Create radio buttons to switch between pol positions within legend. If only one pol pos present in data, display pol pos as static text. :param choices: polarization positions found in data """ self.clear() if len(choices) > 1: # if we have multiple choices -> select between choices with radio button self.pol_display = GraphicalRadioButtonControl(self, choices=choices, labels=choices) self.pol_display.SetToolTip("Select a polarization direction for display.") self.pol_display.Bind(wx.EVT_BUTTON, self.OnPolarizationButton) self.pol_display.SetValue(default) else: self.pol_display = wx.TextCtrl(self, style=wx.NO_BORDER | wx.CB_READONLY) self.pol_display.SetBackgroundColour(self.bg_color) self.pol_display.SetForegroundColour(self.fg_color) # if only one choice -> only text displayed self.pol_display.SetValue(next(iter(choices))) self.control_sizer.Add(self.text, 0, border=10, flag=wx.ALIGN_CENTER | wx.RIGHT) self.control_sizer.Add(self.pol_display, 1, border=10, flag=wx.ALIGN_CENTER | wx.RIGHT) # refresh layout self.border_sizer.Layout() self.Parent.Layout() # need to be called as method is called after self.Layout im main thread
class RadioLegend(wx.Panel): """ This class describes a legend containing radio buttons, where each button represents a possible selection of a VA. Optionally, for a larger selection of possible VA values, the VA values can be sorted according to functionality in a dict and the legend will represent grouped values in a combination of a drop down menu and radio buttons. """ def __init__(self, parent, wid=-1, pos=(0, 0), size=wx.DefaultSize, style=wx.NO_BORDER): wx.Panel.__init__(self, parent, wid, pos, size, style) # Store the colours now, as we'll need them whenever the radio button choices change, and by that time the # parent (ARViewport) might be focused, which causes it to have a different background colour. self.bg_color = parent.GetBackgroundColour() self.fg_color = parent.GetForegroundColour() self.SetBackgroundColour(self.bg_color) self.SetForegroundColour(self.fg_color) # descriptive VA text self.text = wx.StaticText(self, label="", style=wx.NO_BORDER) self.text.SetBackgroundColour(self.bg_color) self.text.SetForegroundColour(self.fg_color) self.text.SetToolTip("Position currently displayed") # current position displayed in the legend (or None) # can be radio buttons or text only depending on the number of positions self.pos_display = None self.pos_display_combo = None self.control_sizer = wx.BoxSizer(wx.HORIZONTAL) # border_sizer is needed to add a border around the legend self.border_sizer = wx.BoxSizer(wx.VERTICAL) self.border_sizer.Add(self.control_sizer, border=8, flag=wx.ALL | wx.EXPAND) self.SetSizer(self.border_sizer) # dict used if legend consists of combo box (keys) plus radio buttons (values) self._choices_dict = None # (dict str -> tuple of str) self._legend_on = False # keeps track of, if a new value was requested via the legend or the stream panel self._callback = None # (callable): function called when the value of the legend changes def clear(self): """ Remove the display widget, to not show anything. It will be added again next time the entries are set. """ self.control_sizer.Clear() # destroy the old widgets (otherwise they are still displayed in the GUI) if self.pos_display: self.pos_display.Destroy() if self.pos_display_combo: self.pos_display_combo.Destroy() self.Refresh() @wxlimit_invocation(0.2) def Refresh(self): """ Refresh, which can be called safely from other threads. """ if self: wx.Panel.Refresh(self) def OnGroupSelectionCombo(self, evt=None): """ The combo box selection is requested and the corresponding radio buttons are created. The callback function, which changes the position VA on the stream/projection is called. The _callback function can be overwritten by the viewport. In the case of an event, this method was called by selecting a new position in the combo box (dropdown menu). :param evt: (wx.EVT_COMBOBOX or None) If event, the method was triggered via changing the current value of the combo box. """ if self.pos_display: self.pos_display.Destroy() key = self.pos_display_combo.GetValue() choices_radio = self._choices_dict[key] self.createRadioButtons(choices_radio) if self._legend_on: # only call callback fct when change requested via legend (and not e.g. settings panel) self._callback( choices_radio[0] ) # set first value as default when combo box value was changed via legend self.control_sizer.Add(self.pos_display, 2, border=10, flag=wx.ALIGN_CENTER | wx.RIGHT) # refresh layout self.border_sizer.Layout() self.Parent.Layout( ) # need to be called as method is called after self.Layout im main thread def OnPositionButton(self, event): """ In the case of an event (select a button), the radio button selection is requested and the callback function, which changes the position is called. The _callback function can be overwritten by the viewport. :param event: (wx.EVT_BUTTON) Event triggered by selecting a radio button in the legend. """ pos = self.pos_display.GetValue() self._callback(pos) def set_callback(self, func): """ Sets the callback function that is executed when a new radio button selection is requested (in OnPositionButton). The _callback function can be overwritten by the viewport. :param func: (callable) Callback function that is called when a new pos is requested. Function param is "pos" (string): The position to be set in the legend. """ self._callback = func def set_value(self, pos): """ Sets the new position requested in the legend. Method should be called from the main GUI thread only. :param pos: (str) New radio button selection to be set active. """ # Only called when the position is changed externally to update the widgets state. # Changing the value via the settings panel widgets, needs a bit special handling. # Note: No need to call the callback function as the stream VA is connected to settings panel widget. if self.pos_display_combo and pos not in self.pos_display.choices: self._legend_on = False # Get the matching combo box pos for the requested pos via the settings panel. # This is also the pos that needs to be active in the radio buttons. pos_combo, _ = self._matchRadioPosWithComboPos( self._choices_dict, pos) self.pos_display_combo.SetValue( pos_combo) # set the value on the combo box self.OnGroupSelectionCombo( ) # create the corresponding radio buttons self.pos_display.SetValue( pos) # set the value on the radio button explicitly self._legend_on = True else: self.pos_display.SetValue(pos) def createRadioButtons(self, choices, value=None): """ Creates the radio buttons in the legend. :param choices: (list or tuple) Choices to be set for the radio buttons. :param value: (str or None) Radio button that should be active. """ self.pos_display = GraphicalRadioButtonControl(self, choices=choices, labels=choices) self.pos_display.SetToolTip("Select a position for display.") self.pos_display.Bind(wx.EVT_BUTTON, self.OnPositionButton) if value: self.pos_display.SetValue(value) # set the value def createComboBox(self, choices, value): """ Creates the combo box in the legend. :param choices: (list or tuple) Choices to be set for the combo box. :param value: (str) Combo box value that should be selected. :returns: (tuple) Choices for creating the corresponding radio buttons. """ choices_combo = choices.keys() self.pos_display_combo = ComboBox( self, wx.ID_ANY, choices=choices_combo, labels=choices_combo, style=wx.NO_BORDER | wx.TE_PROCESS_ENTER | wx.CB_READONLY, pos=(0, 0), size=(290, 16)) self.pos_display_combo.SetToolTip("Select a position for display.") self.pos_display_combo.Bind(wx.EVT_COMBOBOX, self.OnGroupSelectionCombo) pos_combo, choices_radio = self._matchRadioPosWithComboPos( choices, value) self.pos_display_combo.SetValue(pos_combo) # set value return choices_radio def _matchRadioPosWithComboPos(self, choices, value): """ Match the value for the radio button with the value to be set on the combo box. :param choices: (dict) Dictionary, whose keys are the choices for the combo box, and whose values are the choices for the radio buttons. :param value: (str) Combo box value that should be selected. :returns: pos_combo (str) Value to be selected on the combo box. choices_radio (tuple): Choices used to create the corresponding radio buttons. """ for pos_combo, choices_radio in choices.items(): if value in choices_radio: return pos_combo, choices_radio def createStaticText(self, value): """ Creates the static text in the legend. Used, if only one choice (aka one image) needs to be displayed. :param value: (str) Value that should be displayed in the text. """ self.pos_display = wx.TextCtrl(self, value=value, style=wx.NO_BORDER | wx.CB_READONLY) self.pos_display.SetBackgroundColour(self.bg_color) self.pos_display.SetForegroundColour(self.fg_color) @call_in_wx_main def set_pos_entries(self, choices, default_value, name): """ Create radio buttons or a combination of radio buttons and a combo box, to switch between positions within legend. If only one pos present in data, display pos as static text. :param choices: (set or dict -> tuple or dict) Positions found in data. If too many choices, it is possible to sort them in a dict and pass it to the radio legend. Radio legend will then create a legend consisting of a drop down menu/combo box (keys of dict) combined with radio buttons (values of dict). :param default_value: (str) Default value that should be active. :param name: (str) Text to be displayed describing the radio legend. """ self.clear() # add descriptive text to legend self.control_sizer.Add(self.text, 0, border=10, flag=wx.ALIGN_CENTER | wx.RIGHT) self.text.SetLabel(name) # set the descriptive text for the legend if len(choices) > 1: if isinstance( choices, collections.Mapping): # create combo box + radio buttons self._choices_dict = choices choices_radio = self.createComboBox(choices, default_value) self.createRadioButtons(choices_radio, default_value) # create radio buttons self.control_sizer.Add(self.pos_display_combo, 1, border=10, flag=wx.ALIGN_CENTER | wx.RIGHT) self.control_sizer.Add(self.pos_display, 2, border=10, flag=wx.ALIGN_CENTER | wx.RIGHT) self._legend_on = True # True while not changes requested via stream panel elif isinstance(choices, collections.Iterable): # only create radio buttons # if we have multiple choices -> select between choices with radio button self.createRadioButtons(choices, default_value) # create radio buttons self.control_sizer.Add(self.pos_display, 1, border=10, flag=wx.ALIGN_CENTER | wx.RIGHT) else: raise TypeError( "Choices for radio legend must be of type 'frozenset' or 'dict'." ) else: # if only one choice -> only text displayed self.createStaticText(default_value) self.control_sizer.Add(self.pos_display, 1, border=10, flag=wx.ALIGN_CENTER | wx.RIGHT) # refresh layout self.border_sizer.Layout() self.Parent.Layout( ) # need to be called as method is called after self.Layout im main thread