Forum Archive

Examples for dialogs.form_dialog() ?

yas

Can anyone give me examples on dialogs.form() ?

Thanks in Advance

yas
dialogs.form_dialog(title='fu',fields=[{'type':'switch','key':'chrc','title':'yas','tint_color':'linen'}])

How do I use sections?

enceladus

Look at this discussion
https://forum.omz-software.com/topic/4260/dialogs-form_dialog-wrapper-helper

cvp

@yas

import dialogs
sections = []
fields = []
field = {'type':'switch','key':'chrc1','title':'yas','tint_color':'linen'}
fields.append(field)
sections.append(('title section 1', fields))
fields = []
field = {'type':'switch','key':'chrc2','title':'ying','tint_color':'linen'}
fields.append(field)
sections.append(('title section 2', fields))
dialogs.form_dialog(title='fu',sections=sections)
enceladus

You could have footer also in the sections

import dialogs
import datetime

form_list_of_sections = []

sectionA_dicts = []
sectionA_dicts.append(dict(type = 'text', title = 'First Name',
key = 'first', placeholder = 'John'))

sectionA_dicts.append(dict(type = 'text', title = 'Last Name',
key = 'last', placeholder = 'Doe')) 

sectionA_dicts.append(dict(type = 'number', title = 'age',
key = 'age', placeholder='30')) 

form_list_of_sections.append(('Section A', sectionA_dicts, 'Section A ends'))

sectionB_dicts = []
sectionB_dicts.append(dict(type = 'date', title = 'Date Of Birth',
key = 'DOB', value = datetime.date.today()))

sectionB_dicts.append(dict(type = 'url', title = 'Home Page',
    key = 'homepage', placeholder = 'http://example.com')) 

form_list_of_sections.append(('Section B', sectionB_dicts, 'Section B ends'))

sectionC_dicts = []
sectionC_dicts.append(dict(type = 'email', title = 'email',
key = 'email', placeholder = 'name@mailserver.com')) 

sectionC_dicts.append(dict(type = 'switch', title = 'is_married',
key = 'is_married', value = True))  

sectionC_dicts.append(dict(type = 'check', title = 'is_registered',
key = 'is_registered', value = False))  

form_list_of_sections.append(('Section C', sectionC_dicts, 'Section C ends'))

diag = dialogs.form_dialog(title = 'Form Dialog', sections=form_list_of_sections)
print(diag)
madivad

Not sure what’s happening here, if it is intended or something is broken in iOS, but a lot of fields appear to have their alignment broken. This is on the iPad with iPad os. Is there a way to force right alignment?

example

cvp

@madivad True, I also remarked this problem but with the beta version of Pythonista3

Édit: temporarily, I've added some blanks at end of each field title

madivad

@cvp Do you mean it’s only a problem with the beta? I am on the beta.

cvp

@madivad said:

Do you mean it’s only a problem with the beta?

I think so

madivad

@cvp do you think there would be a workaround using the objc tools?

cvp

@madivad I think that Objectivec is not needed and that you could use tableview_cell_for_row delegate

Édit: but you need to have your own form_dialog, I think 😢

madivad

@cvp ok, thx

cvp

@madivad try this, waiting that @omz correct it

import dialogs
import datetime

#================ copy dialogs.form_dialog: 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')

    #========== modify textfield frame: begin
    c = dialogs._FormDialogController(title, sections, done_button_title=done_button_title)
    for s in range(0,len(c.sections)):
        for i in range(0,len(c.cells[s])):          # loop on rows of section s
            cell = c.cells[s][i]                                    
            print(cell.text_label.text)
            if len(cell.content_view.subviews) > 0:
                tf = cell.content_view.subviews[0]      # ui.TextField of value in row
                tf.x += 20
                tf.width -= 20
    #========== modify textfield frame: 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
    return c.values
#================ copy dialogs.form_dialog: end

form_list_of_sections = []

sectionA_dicts = []
sectionA_dicts.append(dict(type = 'text', title = 'First Name',
key = 'first', placeholder = 'John'))

sectionA_dicts.append(dict(type = 'text', title = 'Last Name',
key = 'last', placeholder = 'Doe')) 

sectionA_dicts.append(dict(type = 'number', title = 'age',
key = 'age', placeholder='30')) 

form_list_of_sections.append(('Section A', sectionA_dicts, 'Section A ends'))

sectionB_dicts = []
sectionB_dicts.append(dict(type = 'date', title = 'Date Of Birth',
key = 'DOB', value = datetime.date.today()))

sectionB_dicts.append(dict(type = 'url', title = 'Home Page',
    key = 'homepage', placeholder = 'http://example.com')) 

form_list_of_sections.append(('Section B', sectionB_dicts, 'Section B ends'))

sectionC_dicts = []
sectionC_dicts.append(dict(type = 'email', title = 'email',
key = 'email', placeholder = 'name@mailserver.com')) 

sectionC_dicts.append(dict(type = 'switch', title = 'is_married',
key = 'is_married', value = True))  

sectionC_dicts.append(dict(type = 'check', title = 'is_registered',
key = 'is_registered', value = False))  

form_list_of_sections.append(('Section C', sectionC_dicts, 'Section C ends'))

diag = my_form_dialog(title = 'Form Dialog', sections=form_list_of_sections)
print(diag) 
cvp

@madivad better with

            if len(cell.content_view.subviews) > 0:
                tf = cell.content_view.subviews[0]      # ui.TextField of value in row
                if type(tf) is ui.TextField:
                    tf.x += 20
                    tf.width -= 20 
ccc

@cvp said:

if type(tf) is ui.TextField:

PEP8: Avoid directly comparing types. Use isinstance(tf, ui.TextField) instead.

cvp

@ccc ok, PEP are conventions. Why "Avoid directly comparing types"? Is there a technical reason? You have to agree that "type(tf) is xxx" is more readable than the PEP code 😀

cvp

@ccc found that, and I like it, thus, forget my previous post 😀

isinstance caters for inheritance (an instance of a derived class is an instance of a base class, too), while checking for equality of type does not (it demands identity of types and rejects instances of subtypes, AKA subclasses).

Normally, in Python, you want your code to support inheritance, of course (since inheritance is so handy, it would be bad to stop code using yours from using it!), so isinstance is less bad than checking identity of types because it seamlessly supports inheritance.

It's not that isinstance is good, mind you—it's just less bad than checking equality of types

madivad

@cvp but but but...
It's a text field, why not just align it right?

I did just that and it's perfect now:

tf.alignment=ui.ALIGN_RIGHT

:)

Is there a way to do that without creating our own custom dialogue type?

cvp

@madivad said:

Is there a way to do that without creating our own custom dialogue type?

I don't think so because dialogs.form_dialog does the "present" and you can't modify something after the view presentation. But perhaps somebody else could find another way.

cvp

@madivad said:

tf.alignment=ui.ALIGN_RIGHT

Good idea but sometimes, user may prefer a left alignment for text and a right alignment for numbers, thus, up to you 😀

madivad

@cvp maybe, but in any case, left aligned to the fields title is ugly to me. I can't think of a usecase where you would want it like that. Maybe in an RTL language, but I wouldn't know.

About the modifying after the present, yes makes sense. Having the custom dialogue type is no big issue. I'll use that.

Thanks for your help!

cvp

For info, in all my big scripts I always use my own form_dialog, while keeping the standard dialogs._FormDialogController, because in my dialog views I add some buttons or I add some types like SegmentedControl or ImageView or even MkMapView, so...

madivad

@cvp you are a machine! Great work.

cvp

@madivad said:

left aligned to the fields title is ugly to me.

I can understand that.
I have cases where I want left alignment but I add spaces to titles to force that all titles have same width and thus all TextFields begin at same x.

cvp

I always use my own form_dialog,

So, you can even change font, color and... of your fields, by example, in function of their name.

cvp

Other solution without using an own form_dialog,
but by monkey patching the class method tableview_cell_for_row of the dialogs._FormDialogController class

def my_tableview_cell_for_row(self,tv, section, row):
    cell = self.cells[section][row]
    if len(cell.content_view.subviews) > 0:
        tf = cell.content_view.subviews[0]      # ui.TextField of value in row
        if type(tf) is ui.TextField:
            tf.alignment=ui.ALIGN_RIGHT
    return cell

dialogs._FormDialogController.tableview_cell_for_row = my_tableview_cell_for_row

diag = dialogs.form_dialog(title = 'Form Dialog', sections=form_list_of_sections) 
madivad

@cvp ahh, I thought something like that would be possible. Just no idea how. Awesome, thanks.

cvp

@madivad for the fun, thanks to this marvelous app and ObjectiveC, you can even have a dialog field type of UISegmentedControl with images as segments:

segments = [ui.Image.named('test:Lenna').with_rendering_mode(ui.RENDERING_MODE_ORIGINAL), ui.Image.named('IMG_7923.JPG').with_rendering_mode(ui.RENDERING_MODE_ORIGINAL)]
sectionA_dicts.append(dict(type = 'text', title = 'My segmented images',
key = 'segm_img', segments = segments))

.
.
.

def objcsegmentselection_(_self, _cmd, _sender):
    idx = ObjCInstance(_sender).selectedSegmentIndex()
    if idx >= 0:    
        c.values[ObjCInstance(_sender).name] = idx

def my_tableview_cell_for_row(self,tv, section, row):
    global c
    #print('section=',section,'row=',row)
    c = self
    cell = self.cells[section][row]
    if len(cell.content_view.subviews) > 0:
        tf = cell.content_view.subviews[0]      # ui.TextField of value in row
        item = self.sections[section][1][row]   
        new_type = False
        if 'segments' in item:
            if isinstance(item['segments'][0],str):
                # segments are strings
                # check if ui.SegmentedControl already added
                for sv in cell.content_view.subviews:
                    if isinstance(tf, ui.SegmentedControl):
                        return cell
                segmented = ui.SegmentedControl()
                segmented.name = cell.text_label.text
                segmented.action = segmented_action
                segmented.frame = tf.frame
                segmented.x = c.view.width - segmented.width - 8
                segmented.segments = item['segments']
                cell.content_view.add_subview(segmented)
            elif isinstance(item['segments'][0],ui.Image):
                # segments are ui.Image
                # we will create an UISegmentedControl instead of tf
                # thus we will never more see it as subview of cell.content_view
                items = []
                for ui_image in item['segments']:
                    items.append(ObjCInstance(ui_image))
                segmented = ObjCClass('UISegmentedControl').alloc().initWithItems_(items)
                x = c.view.width - tf.width - 8
                frame = CGRect(CGPoint(x,tf.y), CGSize(tf.width,tf.height))
                segmented.name = tf.name # used in action
                segmented.setFrame_(frame)
                for sv in segmented.subviews():
                    # UIImageView of each UISegment
                    sv.subviews()[0].setContentMode_(1) # scaleAspectFit

                ActionTarget = create_objc_class('ActionTarget', methods=[objcsegmentselection_])
                target = ActionTarget.new().autorelease()
                segmented.addTarget_action_forControlEvents_(target, 'objcsegmentselection:',1 << 12) # UIControlEventValueChanged

                ObjCInstance(cell.content_view).addSubview_(segmented) 

sam rod

this topic is good to prove a posible fix for collect prívate data before to miss in trouble shoting

madivad

@cvp amazing content as usual! That is cool (the images).

Something interesting, what happens when you run one of these on your phone? For me, the segmented control is largely off the screen (form/dialog).

segmented control off screen

cvp

@madivad weird. I only use my iPad and form_dialog is a sheet of (0,0,500,500) in standard dialogs module. Normally, the code sets the width of the segmentedcontrol equal to the TetxField width, unless you did change something.

cvp

@madivad I just try on my (old 5S) iPhone and no problem at all, the dialog is full screen.
The only thing is that my script did not import the needed objc_util module.

from objc_util import * 

madivad

@cvp just because this has got a little disjointed and long and a few edits have been made here and there, could you paste the entire source in the next response please?

I’m about to test something else, downloading pythonista on one of my old phones... I want to rule something out :)

cvp

@madivad sorry for the delay gist

cvp

@madivad Christmas gift, updated gist

Ui.Slider

madivad

I’d forgotten about your repos!

I ended up working it out, for me it’s the custom dialog where the control is misaligned, with the inbuilt control it aligns correctly

Edit: just confirmed, I downloaded that git, comment out line 89 (and join 90 back to the end of 89) and then edit the 'diag' at the end of the doc from:

diag = dialogs.form_dialog(title = 'Form Dialog', sections=form_list_of_sections)

To

diag = my_form_dialog(title = 'Form Dialog', sections=form_list_of_sections)

And run that on a smaller screen

cvp

@madivad All my last added fields types are processed in my_tableview_cell_for_row, thus they only work with the standard form_dialog.

dialogs._FormDialogController.tableview_cell_for_row = my_tableview_cell_for_row

diag = dialogs.form_dialog(title = 'Form Dialog', sections=form_list_of_sections)