|
|
import wx from gooey.gui.components.widgets.bases import BaseWidget from gooey.gui.lang.i18n import _ from gooey.gui.util import wx_util from gooey.gui.components.widgets import CheckBox from gooey.util.functional import getin, findfirst, merge
class RadioGroup(BaseWidget):
def __init__(self, parent, widgetInfo, *args, **kwargs): super(RadioGroup, self).__init__(parent, *args, **kwargs) self._parent = parent self.info = widgetInfo self._id = widgetInfo['id'] self._options = widgetInfo['options'] self.widgetInfo = widgetInfo self.error = wx.StaticText(self, label='') self.radioButtons = self.createRadioButtons() self.selected = None self.widgets = self.createWidgets() self.arrange()
for button in self.radioButtons: button.Bind(wx.EVT_LEFT_DOWN, self.handleButtonClick)
initialSelection = getin(self.info, ['options', 'initial_selection'], None) if initialSelection is not None: self.selected = self.radioButtons[initialSelection] self.selected.SetValue(True) self.handleImplicitCheck()
self.applyStyleRules()
def getValue(self): for button, widget in zip(self.radioButtons, self.widgets): if button.GetValue(): # is Checked return merge(widget.getValue(), {'id': self._id}) else: # just return the first widget's value even though it's # not active so that the expected interface is satisfied return self.widgets[0].getValue()
def setErrorString(self, message): for button, widget in zip(self.radioButtons, self.widgets): if button.GetValue(): # is Checked widget.setErrorString(message) self.Layout()
def showErrorString(self, b): for button, widget in zip(self.radioButtons, self.widgets): if button.GetValue(): # is Checked widget.showErrorString(b)
def arrange(self, *args, **kwargs): title = getin(self.widgetInfo, ['options', 'title'], _('choose_one')) if getin(self.widgetInfo, ['options', 'show_border'], False): boxDetails = wx.StaticBox(self, -1, title) boxSizer = wx.StaticBoxSizer(boxDetails, wx.VERTICAL) else: title = wx_util.h1(self, title) title.SetForegroundColour(self._options['label_color']) boxSizer = wx.BoxSizer(wx.VERTICAL) boxSizer.AddSpacer(10) boxSizer.Add(title, 0)
for btn, widget in zip(self.radioButtons, self.widgets): sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(btn,0, wx.RIGHT, 4) sizer.Add(widget, 1, wx.EXPAND) boxSizer.Add(sizer, 0, wx.ALL | wx.EXPAND, 5) self.SetSizer(boxSizer)
def handleButtonClick(self, event): currentSelection = self.selected nextSelection = event.EventObject
if not self.isSameRadioButton(currentSelection, nextSelection): self.selected = nextSelection self.selected.SetValue(True) else: # user clicked on an already enabled radio button. # if it is not in the required section, allow it to be deselected if not self.widgetInfo['required']: self.selected.SetValue(False) self.selected = None
self.applyStyleRules() self.handleImplicitCheck()
def isSameRadioButton(self, radioButton1, radioButton2): return (getattr(radioButton1, 'Id', 'r1-not-found') == getattr(radioButton2, 'Id', 'r2-not-found'))
def applyStyleRules(self): """
Conditionally disabled/enables form fields based on the current section in the radio group """
# for reasons I have been completely unable to figure out # or understand, IFF you've interacted with one of the radio Buttons's # child components, then the act of disabling that component will # reset the state of the radioButtons thus causing it to forget # what should be selected. So, that is why we're collected the initial # state of all the buttons and resetting each button's state as we go. # it's wonky as hell states = [x.GetValue() for x in self.radioButtons] for button, selected, widget in zip(self.radioButtons, states, self.widgets): if isinstance(widget, CheckBox): widget.hideInput() if not selected: # not checked widget.Disable() else: widget.Enable() button.SetValue(selected)
def handleImplicitCheck(self): """
Checkboxes are hidden when inside of a RadioGroup as a selection of the Radio button is an implicit selection of the Checkbox. As such, we have to manually "check" any checkbox as needed. """
for button, widget in zip(self.radioButtons, self.widgets): if isinstance(widget, CheckBox): if button.GetValue(): # checked widget.setValue(True) else: widget.setValue(False)
def createRadioButtons(self): # button groups in wx are statefully determined via a style flag # on the first button (what???). All button instances are part of the # same group until a new button is created with the style flag RG_GROUP # https://wxpython.org/Phoenix/docs/html/wx.RadioButton.html # (What???) firstButton = wx.RadioButton(self, style=wx.RB_GROUP) firstButton.SetValue(False) buttons = [firstButton]
for _ in getin(self.widgetInfo, ['data','widgets'], [])[1:]: buttons.append(wx.RadioButton(self)) return buttons
def createWidgets(self): """
Instantiate the Gooey Widgets that are used within the RadioGroup """
from gooey.gui.components import widgets widgets = [getattr(widgets, item['type'])(self, item) for item in getin(self.widgetInfo, ['data', 'widgets'], [])] # widgets should be disabled unless # explicitly selected for widget in widgets: widget.Disable() return widgets
|