Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Form dialogs: Add segmented control type
-
Hello,
Limited coding experience.
The forms dialog function accepts several types ('switch', 'text', 'url', 'email, etc...) but there is no option for segmented controls. Is it possible to write code that adds that option? In trying to do so, I wanted to look at the source code for the dialogs module but cannot find it.
help(dialogs) at the prompt tells me the file is in : /var/containers/Bundle/Application/D5B2.......
And I don't know how to get there... #EDIT: found a work around: in prompt type print(inspect.getsource(dialogs)) ==> gives you the source code of the module. Now in the _FormDialogController class definition, I feel there is a way to add a segmented control item somewhereAny pointers are appreciated
-
Try this
import ui import dialogs #==================== copied from dialogs: begin import collections import sys PY3 = sys.version_info[0] >= 3 if PY3: basestring = str def my_form_dialog(title='', fields=None, sections=None, done_button_title='Done'): if not sections and not fields: raise ValueError('sections or fields are required') if not sections: sections = [('', fields)] if not isinstance(title, basestring): raise TypeError('title must be a string') for section in sections: if not isinstance(section, collections.Sequence): raise TypeError('Sections must be sequences (title, fields)') if len(section) < 2: raise TypeError('Sections must have 2 or 3 items (title, fields[, footer]') if not isinstance(section[0], basestring): raise TypeError('Section titles must be strings') if not isinstance(section[1], collections.Sequence): raise TypeError('Expected a sequence of field dicts') for field in section[1]: if not isinstance(field, dict): raise TypeError('fields must be dicts') c = dialogs._FormDialogController(title, sections, done_button_title=done_button_title) #==================== dialogs.form_dialog modification 1: begin for i in range(0,len(c.cells[0])): # loop on rows of section 0 cell = c.cells[0][i] # ui.TableViewCell of row i # some fields types are subviews of the cell: # text,number,url,email,password,switch # but check, date and time are not set as subviews of cell.content_view if len(cell.content_view.subviews) > 0: tf = cell.content_view.subviews[0] # ui.TextField of value in row # attention: tf.name not set for date fields if tf.name == 'segmented': item = c.sections[0][1][i] # section 0, 1=items, row i segmented = ui.SegmentedControl() segmented.name = cell.text_label.text segmented.frame = tf.frame segmented.segments = item['segments'] cell.content_view.remove_subview(tf) del c.values[tf.name] del tf cell.content_view.add_subview(segmented) #==================== dialogs.form_dialog modification 1: end c.container_view.present('sheet') c.container_view.wait_modal() # Get rid of the view to avoid a retain cycle: c.container_view = None if c.was_canceled: return None #==================== dialogs.form_dialog modification 2: begin for i in range(0,len(c.cells[0])): # loop on rows of section 0 cell = c.cells[0][i] # ui.TableViewCell of row i # some fields types are subviews of the cell: # text,number,url,email,password,switch # but check, date and time are not set as subviews of cell.content_view for tf in cell.content_view.subviews: if 'SegmentedControl' in str(type(tf)): item = c.sections[0][1][i] # section 0, 1=items, row i c.values[tf.name] = item['segments'][tf.selected_index] #==================== dialogs.form_dialog modification 2: end return c.values #==================== copied from dialogs: end fields = [] field = {'title':'title 1','type':'text','value':'test 1'} fields.append(field) field = {'title':'title 2','type':'text','value':'test 1','key':'segmented','segments':['seg1','seg2']} fields.append(field) updated_fields = my_form_dialog(title='my dialog title', fields=fields) print(updated_fields)
-
Ok so first of all thank you cvp for the answer ! that works great.
I also "solved" it on my side with the following code:
I copied the _FormDialogController class and renamed it _SCFormDialogController - note: SC for segmented control
There, just beforeif t == 'switch'
I inserted:
if t == 'segmented': value = item.get('value', '') self.values[key] = value cell.selectable = False cell.text_label.text = title segment = ui.SegmentedControl() segment.segments = item.get('value', '').split("|") segment.value = value segment.name = key segment.action = self.segment_action label_width = ui.measure_string(title, font=cell.text_label.font)[0] cell_width, cell_height = cell.content_view.width, cell.content_view.height segment_width = max(40, cell_width - label_width - 32) segment.frame = (cell_width - segment_width, 5, segment_width, cell_height -10) segment.bordered = False segment.flex = 'W' cell.content_view.add_subview(segment)
I also added in that class:
def segment_action(self, sender): self.values[sender.name] = sender.segments[sender.selected_index]
and finally in form_dialog() just changed :
c = _SCFormDialogController(title, sections, done_button_title=done_button_title)
Again thanks for the help!
-
Good job
When I have to add a feature to form_dialog, I always hesitate between changing form_dialog or changing its controller... -
By the way, you can get to built in module source code by going to Modules->Standard Library(3.6)->site-packages. Thats where pythonista custom modules are.
You can also do
import editor editor.open_file(dialogs.__file__)
-
import sys PY3 = sys.version_info[0] >= 3 if PY3: basestring = str # could be rewritten as: try: basestring # Python 2 except NameError basestring = str # Python 3
This follows the Python best practice, use feature detection instead of version detection.
It usually works better with linters like flake8, etc.
-
Agree but these lines were copied from standard module...
-
Here is a simple dialog template that uses a pyui file created using designer. This helps to use ui controls like images, textviews, segmentedcontrol in dialogs. The gist with sample pyui file is here. I hope it helps
https://gist.github.com/73431fef1f00c462c3bee0551bd14be8
import ui class PyuiDialogController (object): def __init__(self, title='Pyui Dialog', pyui_dialog='pyui_dialog.pyui', cancel_button_title='Cancel', done_button_title='Done'): self.params = None self.view = ui.load_view(pyui_dialog) self.view.frame = (0, 0, 500, 500) self.view.name = title done_button = ui.ButtonItem(title=done_button_title) done_button.action = self.done_action cancel_button = ui.ButtonItem(title=cancel_button_title) cancel_button.action = self.cancel_action self.view.right_button_items = [done_button, cancel_button] def get_params(self): params = {} params['switch1'] = self.view['switch1'].value params['textfield1'] = self.view['textfield1'].text sg = self.view['segmentedcontrol1'] params['segmentedcontrol1'] = sg.segments[sg.selected_index] return params def cancel_action(self, sender): self.view.close() def done_action(self, sender): self.params = self.get_params() self.view.close() def pyui_dialog(): c = PyuiDialogController() c.view.present('sheet') c.view.wait_modal() return c.params def button_action(sender): print(pyui_dialog()) v = ui.View(frame=(0,0,600,600), name='Test Pyui Dialog') v.add_subview(ui.Button(frame=(200,300, 100,100), title='Test Dialog', action=button_action)) v.present('sheet')