def create_button(self,label,callback):#,flag=None,widget=None): _btn = MTButton(multiline=True, label=label, anchor_x='left', halign='left', padding_x=8) _btn.connect('on_press', callback) _max = 1 for _s in label.splitlines(): _l = len(_s) if _l > _max: _max = _l _btn.width = min(int(_max * pixels),100) return _btn
def add_widget(self, widget, tab=None): if tab is None: if not hasattr(widget, 'tab'): raise Exception('Widget added without tab information') else: tab = widget.tab button = MTButton(label=tab, size=(120, 40)) button.tab_container = self button.connect('on_release', curry(self.select, tab)) self.topbar.add_widget(button) self.tabs[tab] = (button, widget)
def __init__(self, **kwargs): '''Kinetic object, the base object for every child in kineticlist. :Parameters: `deletable`: bool, default to True Indicate if object can be deleted or not ''' kwargs.setdefault('deletable', True) super(MTKineticObject, self).__init__(**kwargs) self.deletable = kwargs.get('deletable') self.register_event_type('on_animation_complete') self.push_handlers(on_animation_complete=self.on_animation_complete) # List of attributes that can be searched self.attr_search = ['label'] # In case the widget has to move itself # while still having kinetic movement applied self.xoffset = self.yoffset = 0 # The position values that the kinetic container edits. # We do this so we can break free and move ourself it necessary self.kx = self.ky = 0 self.db_alpha = 0.0 # Set to true if you want to break free from # the grasp of a kinetic widget self.free = False # Delete Button if self.deletable: self.db = MTButton(label='', size=(40, 40), pos=(self.x + self.width - 40, self.y + self.height - 40), style={'bg-color': (1, 0, 0, 0)}, visible=False) self.db.push_handlers(on_press=self._delete_callback) self.add_widget(self.db) self.a_delete = Animation(width=0, height=0, xoffset=self.kx + self.width / 2, yoffset=self.ky + self.height / 2, duration=0.5, f='ease_in_cubic') self.a_show = Animation(db_alpha=.5, duration=0.25) self.a_hide = Animation(db_alpha=0.0, duration=0.25)
def __init__(self, **kwargs): kwargs.setdefault('do_scale', False) kwargs.setdefault('size', (400, 400)) kwargs.setdefault('show_cancel', True) kwargs.setdefault('label_cancel', 'Cancel') kwargs.setdefault('label_submit', 'Ok') kwargs.setdefault('title', 'PyMT popup') kwargs.setdefault('exit_on_submit', True) super(MTPopup, self).__init__(**kwargs) self.register_event_type('on_submit') self.register_event_type('on_cancel') self.exit_on_submit = kwargs.get('exit_on_submit') # Create layouts self.layout = MTBoxLayout(size=self.size, orientation='vertical') self.l_content = MTBoxLayout(orientation='vertical') self.l_buttons = MTBoxLayout(size_hint=(1, None), orientation='horizontal') # Titles if kwargs.get('title'): self.w_title = MTLabel(label=kwargs.get('title'), autosize=True, cls='popup-title') # Buttons self.w_submit = MTButton(label=kwargs.get('label_submit'), size_hint=(0.5, None), height=40, cls='popup-button') self.w_submit.push_handlers(on_release=curry( self._dispatch_event, 'on_submit')) self.l_buttons.add_widget(self.w_submit) if kwargs.get('show_cancel'): self.w_cancel = MTButton(label=kwargs.get('label_cancel'), size_hint=(0.5, None), height=40, cls='popup-button') self.w_cancel.push_handlers(on_release=curry( self._dispatch_event, 'on_cancel')) self.l_buttons.add_widget(self.w_cancel) # Connect if kwargs.get('title'): self.layout.add_widget(self.w_title) self.layout.add_widget(self.l_content) self.layout.add_widget(self.l_buttons) super(MTPopup, self).add_widget(self.layout)
def fullscreen(self, *largs, **kwargs): root_win = self.parent.get_parent_window() # save state for restore self.old_children = root_win.children self.old_size = self.size # set new children root_win.children = SafeList() root_win.add_widget(self.container) btn_unfullscreen = MTButton(pos=(root_win.width-50, root_win.height-50), size=(50, 50), label='Back') btn_unfullscreen.push_handlers(on_release=self.unfullscreen) root_win.add_widget(btn_unfullscreen) self.size = root_win.size self.container.size = self.size
def fullscreen(self, *largs, **kwargs): root_win = self.parent.get_parent_window() # save state for restore self.old_children = root_win.children self.old_size = self.size # set new children root_win.children = SafeList() root_win.add_widget(self.container) btn_unfullscreen = MTButton(pos=(root_win.width - 50, root_win.height - 50), size=(50, 50), label='Back') btn_unfullscreen.push_handlers(on_release=self.unfullscreen) root_win.add_widget(btn_unfullscreen) self.size = root_win.size self.container.size = self.size
def __init__(self, **kwargs): kwargs.setdefault('anchor_x', 'left') kwargs.setdefault('anchor_y', 'center') kwargs.setdefault('halign', 'left') kwargs.setdefault('keyboard', None) kwargs.setdefault('keyboard_to_root', False) kwargs.setdefault('password', False) kwargs.setdefault('group', None) kwargs.setdefault('switch', True) kwargs.setdefault('keyboard_type', pymt_config.get('widgets', 'keyboard_type')) super(MTTextInput, self).__init__(**kwargs) self._keyboard = kwargs.get('keyboard') self.is_active_input = False self.password = kwargs.get('password') # initialize group on random if nothing is set self._groupname = kwargs.get('group') if self._groupname is None: MTTextInput._group_id += 1 self._groupname = 'uniqgroup%d' % MTTextInput._group_id # first time ? create the group if not self._groupname in self._group: self.group['keyboard'] = None self.group['widgets'] = [] self.group['widgets'].append(self) self.register_event_type('on_text_change') self.register_event_type('on_text_validate') # save original color for error self._notify_bg_color = self.style['bg-color'] self._notify_bg_color_active = self.style['bg-color-active'] self._notify_animation = None # switch button between vkeyboard or hardware self._switch = None if kwargs.get('switch'): self._switch = MTButton( label=kwargs.get('keyboard_type'), cls='switch-button', size=(60, 20), font_size=8, pos=(self.x + self.width - 60, self.y + self.height)) self.keyboard_type = kwargs.get('keyboard_type') self.keyboard_to_root = kwargs.get('keyboard_to_root') self.interesting_keys = {8: 'backspace', 13: 'enter', 127: 'del', 271: 'enter', 273: 'cursor_up', 274: 'cursor_down', 275: 'cursor_right', 276: 'cursor_left', 278: 'cursor_home', 279: 'cursor_end', 280: 'cursor_pgup', 281: 'cursor_pgdown'}
def __init__(self, **kwargs): '''Kinetic object, the base object for every child in kineticlist. :Parameters: `deletable`: bool, default to True Indicate if object can be deleted or not ''' kwargs.setdefault('deletable', True) super(MTKineticObject, self).__init__(**kwargs) self.deletable = kwargs.get('deletable') self.register_event_type('on_animation_complete') self.push_handlers(on_animation_complete=self.on_animation_complete) # List of attributes that can be searched self.attr_search = ['label'] # In case the widget has to move itself # while still having kinetic movement applied self.xoffset = self.yoffset = 0 # The position values that the kinetic container edits. # We do this so we can break free and move ourself it necessary self.kx = self.ky = 0 self.db_alpha = 0.0 # Set to true if you want to break free from # the grasp of a kinetic widget self.free = False # Delete Button if self.deletable: self.db = MTButton(label='', size=(40, 40), pos=(self.x + self.width-40, self.y + self.height-40), style={'bg-color':(1, 0, 0, 0)}, visible=False) self.db.push_handlers(on_press=self._delete_callback) self.add_widget(self.db) self.a_delete = Animation(width=0, height=0, xoffset=self.kx + self.width/2, yoffset=self.ky + self.height/2, duration=0.5, f='ease_in_cubic') self.a_show = Animation(db_alpha=.5, duration=0.25) self.a_hide = Animation(db_alpha=0.0, duration=0.25)
def __init__(self, **kwargs): kwargs.setdefault('hide', True) super(MTSidePanel, self).__init__(**kwargs) self.side = kwargs.get('side', 'left') self.align = kwargs.get('align', 'center') self.corner_size = kwargs.get('corner_size', 30) self.duration = kwargs.get('duration', .5) layout = kwargs.get('layout', None) corner = kwargs.get('corner', None) assert (self.side in ('bottom', 'top', 'left', 'right')) assert (self.align in ('bottom', 'top', 'left', 'right', 'middle', 'center')) if layout is None: from pymt.ui.widgets.layout import MTBoxLayout layout = MTBoxLayout() self.layout = layout super(MTSidePanel, self).add_widget(layout) if corner is None: from pymt.ui.widgets.button import MTButton if self.side == 'right': label = '<' elif self.side == 'left': label = '>' elif self.side == 'top': label = 'v' elif self.side == 'bottom': label = '^' corner = MTButton(label=label) else: self.corner_size = None self.corner = corner # Don't add to front or widgets added as children of layout will be occluded super(MTSidePanel, self).add_widget(self.corner, front=False) self.corner.connect('on_press', self._corner_on_press) self.initial_pos = self.pos self.need_reposition = True if kwargs.get('hide'): self.layout.visible = False self.hide()
class MTTextInput(MTButton): ''' A text input widget is a simple label widget that will pop up a virtual keyboard when touched any input of the virtual keyboard will then have effect on the TextInput widget. .. versionadded:: 0.5.1 Support of scrolling textarea, controlled by `scroll` attribute. You can now scroll inside the text area without editing text. :Parameters: `keyboard`: MTVkeyboard object, default to None Use another MTVKeyboard than the default one `keyboard_to_root`: bool, defaults to False. Indicate whether the keyboard should be attached to the root window. If True, this will have the effect of the keyboard being raised above other widgets. `keyboard_type`: str, default to config. Configuration section is 'widgets', token 'keyboard_type'. Can be one of 'virtual' or 'real'. If real, the virtual keyboard will be not showed `password`: bool, default to False If True, the label will be showed with star `group`: str, default to random If the group is the same for multiple text input You can switch between them with TAB, and use the same keyboard. `switch`: bool, default to True If True, a switch button will be show to switch from real or virtual keyboard `scroll`: bool, default to True If True, the scrolling of a text area is allowed. `scroll_trigger`: int, default to 10 If scrolling is detected, don't fire event to show/hide keyboard. :Events: `on_text_change` (text) Fired when the content of text input is changed `on_text_validate` () Fired when the text is validate (when ENTER is hit on keyboard) ''' _group_id = 0 _group = {} def __init__(self, **kwargs): kwargs.setdefault('anchor_x', 'left') kwargs.setdefault('anchor_y', 'center') kwargs.setdefault('halign', 'left') kwargs.setdefault('keyboard', None) kwargs.setdefault('keyboard_to_root', False) kwargs.setdefault('group', None) kwargs.setdefault('switch', True) kwargs.setdefault('keyboard_type', pymt_config.get('widgets', 'keyboard_type')) super(MTTextInput, self).__init__(**kwargs) self.register_event_type('on_text_change') self.register_event_type('on_text_validate') self._scroll_x = 0 self._can_deactive = True self._keyboard = kwargs.get('keyboard') self._is_active_input = False #: Boolean to activate the password mode on the textinput. #: If true, it will show star instead of real characters self.password = kwargs.get('password', False) #: Boolean to control the scrolling of the textinput content self.scroll = kwargs.get('scroll', True) #: If the scroll if more than scroll_trigger, no event will be #: dispatched, and no show/hide of keyboard. self.scroll_trigger = kwargs.get('scroll_trigger', 10) #: Keyboard type (virtual or real) self.keyboard_type = kwargs.get('keyboard_type') #: If True, the keyboard is added to root window, not to parent window. self.keyboard_to_root = kwargs.get('keyboard_to_root') # initialize group on random if nothing is set self._groupname = kwargs.get('group') if self._groupname is None: MTTextInput._group_id += 1 self._groupname = 'uniqgroup%d' % MTTextInput._group_id # first time ? create the group if not self._groupname in self._group: self.group['keyboard'] = None self.group['widgets'] = [] self.group['widgets'].append(self) # save original color for error self._notify_bg_color = self.style['bg-color'] self._notify_bg_color_active = self.style['bg-color-active'] self._notify_animation = None # switch button between vkeyboard or hardware self._switch = None if kwargs.get('switch'): self._switch = MTButton(label=kwargs.get('keyboard_type'), cls='switch-button', size=(60, 20), font_size=8, pos=(self.x + self.width - 60, self.y + self.height)) self.interesting_keys = { 8: 'backspace', 13: 'enter', 127: 'del', 271: 'enter', 273: 'cursor_up', 274: 'cursor_down', 275: 'cursor_right', 276: 'cursor_left', 278: 'cursor_home', 279: 'cursor_end', 280: 'cursor_pgup', 281: 'cursor_pgdown', 303: 'shift_L', 304: 'shift_R' } def on_resize(self, *largs): if hasattr(self, '_switch'): self._switch.pos = self.x + self.width - 60, self.y + self.height return super(MTTextInput, self).on_resize(*largs) def _get_keyboard(self): if not self._keyboard: self._keyboard = self.group['keyboard'] if self._keyboard is None: self._keyboard = MTVKeyboard() self.group['keyboard'] = self._keyboard return self._keyboard def _set_keyboard(self, value): if self._keyboard is not None: self._keyboard.remove_handlers( on_text_change=self._kbd_on_text_change, on_key_up=self._kbd_on_key_up, on_key_down=self._kbd_on_key_down) self._keyboard = value keyboard = property(_get_keyboard, _set_keyboard) def on_release(self, touch): if not self._can_deactive: return if self._is_active_input: self.hide_keyboard() else: self.show_keyboard() def _kbd_on_text_change(self, value): # reset scrolling when text is typed self._scroll_x = 0 self.label = value self.dispatch_event('on_text_change', value) def _kbd_on_key_down(self, key, repeat=False): displayed_str, internal_str, internal_action, scale = key if internal_action is None: return elif internal_action == 'enter': self.hide_keyboard() self.dispatch_event('on_text_validate') elif internal_action == 'escape': self.hide_keyboard() def _kbd_on_key_up(self, key, repeat=False): pass def on_text_validate(self): pass def on_text_change(self, text): pass @property def group(self): '''Return information (keyboard/widget list) from the current group of the widget''' if not self._groupname in self._group: self._group[self._groupname] = {} return self._group[self._groupname] def notify_error(self): '''Call this function to make animation on background as an error ''' error_color = self.style['bg-color-error'] if self._notify_animation is not None: self._notify_animation.stop() self.style['bg-color'] = self._notify_bg_color self.style['bg-color-active'] = self._notify_bg_color_active self._notify_animation = self.do( Animation(style={ 'bg-color': error_color, 'bg-color-active': error_color }, f=lambda x: 1 - AnimationAlpha.ease_in_out_quart(x))) def deactivate_group(self): '''Deactivate all widgets in the group''' for w in self.group['widgets']: w.hide_keyboard() def focus_next(self): '''Focus the next textinput in the list''' idx = (self.group['widgets'].index(self) + 1) idx = idx % len(self.group['widgets']) widget = self.group['widgets'][idx] widget.show_keyboard() def show_keyboard(self): '''Show the associed keyboard of this widget.''' if self._is_active_input: return self.deactivate_group() self._is_active_input = True # activate switch button if necessary if self._switch: self.add_widget(self._switch) # activate the real keyboard w = self.get_root_window() w.push_handlers(on_key_down=self._window_on_key_down, on_key_up=self._window_on_key_up) # activate the virtual keyboard if self.keyboard_type == 'virtual': to_root = self.keyboard_to_root w = self.get_root_window() if to_root else self.get_parent_window() w.add_widget(self.keyboard) if self.keyboard is not None: self._keyboard.reset_repeat() self._keyboard.push_handlers( on_text_change=self._kbd_on_text_change, on_key_up=self._kbd_on_key_up, on_key_down=self._kbd_on_key_down) self._keyboard.text = self.label def hide_keyboard(self): '''Hide the associed keyboard of this widget.''' if not self._is_active_input: return if self._switch: self.remove_widget(self._switch) parent = self.keyboard.parent if parent is not None: # If keyboard type is real, the keyboard is not attached to any # parent widget. parent.remove_widget(self.keyboard) w = self.get_root_window() w.remove_handlers(on_key_down=self._window_on_key_down, on_key_up=self._window_on_key_up) self._is_active_input = False if self._keyboard is not None: self._keyboard.reset_repeat() self._keyboard.remove_handlers( on_text_change=self._kbd_on_text_change, on_key_up=self._kbd_on_key_up, on_key_down=self._kbd_on_key_down) def _window_on_key_down(self, key, scancode=None, unicode=None): modifiers = getWindow().modifiers if key == ord('v') and 'ctrl' in modifiers: text = Clipboard.get('text/plain') if text: self.keyboard.text += text return True if key == 27: # escape self.hide_keyboard() return True elif key == 9: # tab self.focus_next() return True if not self.keyboard: return k = self.interesting_keys.get(key) if k: key = (None, None, k, 1) self.keyboard.dispatch_event('on_key_down', key) else: if unicode is not None: self.keyboard.text += unicode else: self.keyboard.text += chr(key) def _window_on_key_up(self, key, scancode=None, unicode=None): k = self.interesting_keys.get(key) if k and self.keyboard: key = (None, None, k, 1) self.keyboard.dispatch_event('on_key_up', key) def _get_value(self): return self.label def _set_value(self, value): self.label = value value = property(_get_value, _set_value, doc='Get/set the value of the label') def _get_keyboard_type(self): return self._keyboard_type def _set_keyboard_type(self, t): self.hide_keyboard() self._keyboard_type = t if self._is_active_input: self.show_keyboard() keyboard_type = property(_get_keyboard_type, _set_keyboard_type, doc='Get/set the keyboard type to use') @property def is_active_input(self): '''Return True if the input is active''' return self._is_active_input # # Overload the touch down/move/up for : # 1. handle the switch button # 2. be able to scroll inside the text input # def on_touch_down(self, touch): # check if it's the switch button that collide. if self._switch and self._switch.collide_point(*touch.pos): self.hide_keyboard() if self.keyboard_type == 'virtual': self.keyboard_type = 'real' else: self.keyboard_type = 'virtual' self._switch.label = self.keyboard_type self.show_keyboard() return True # reset scrolling when a touch is comming # FIXME: can be not accurate if many touch are comming. if self.collide_point(*touch.pos): self._scroll_x = 0 self._can_deactive = True # and only now, dispatch as usual. return super(MTTextInput, self).on_touch_down(touch) def on_touch_move(self, touch): if not super(MTTextInput, self).on_touch_move(touch): return # we got a valid touch, self._scroll_x += touch.dxpos - touch.x self._can_deactive = True if abs(touch.x - touch.oxpos) > self.scroll_trigger and self.scroll: self._can_deactive = False return True def on_touch_up(self, touch): if super(MTTextInput, self).on_touch_up(touch): if not self.is_active_input: self._scroll_x = 0 self._can_deactive = True return True def draw(self): if self._is_active_input and self.keyboard_type == 'virtual': set_color(*self.style.get('bg-color')) kx, ky = self.keyboard.to_window(*self.keyboard.center) kx, ky = self.to_widget(kx, ky) drawLine([self.center[0], self.center[1], kx, ky]) if self.password: pw = '*' * len(self.label) old_label = self.label self.label = pw super(MTTextInput, self).draw() if self.password: self.label = old_label def draw_background(self): set_color(*self.style.get('bg-color')) state = 'active' is self._is_active_input or None drawCSSRectangle(pos=self.pos, size=self.size, style=self.style, state=state) def draw_label(self, dx=0, dy=0): # before drawing label, adjust the viewport position of the label. it's # a new feature that permit to draw only a part of the label. width = self._used_label.width - self.width scroll_x = self._scroll_x if self.scroll else 0 if self.is_active_input: scroll_x = width + scroll_x if scroll_x > width: scroll_x = width if scroll_x < 0: scroll_x = 0 self.viewport_pos = (scroll_x, 0) super(MTTextInput, self).draw_label(dx, dy) def on_update(self): super(MTTextInput, self).on_update() if self._switch: self._switch.pos = self.x + self.width - 60, self.y + self.height
class MTKineticObject(MTWidget): def __init__(self, **kwargs): '''Kinetic object, the base object for every child in kineticlist. :Parameters: `deletable`: bool, default to True Indicate if object can be deleted or not ''' kwargs.setdefault('deletable', True) super(MTKineticObject, self).__init__(**kwargs) self.deletable = kwargs.get('deletable') self.register_event_type('on_animation_complete') self.push_handlers(on_animation_complete=self.on_animation_complete) # List of attributes that can be searched self.attr_search = ['label'] # In case the widget has to move itself # while still having kinetic movement applied self.xoffset = self.yoffset = 0 # The position values that the kinetic container edits. # We do this so we can break free and move ourself it necessary self.kx = self.ky = 0 self.db_alpha = 0.0 # Set to true if you want to break free from # the grasp of a kinetic widget self.free = False # Delete Button if self.deletable: self.db = MTButton(label='', size=(40, 40), pos=(self.x + self.width-40, self.y + self.height-40), style={'bg-color':(1, 0, 0, 0)}, visible=False) self.db.push_handlers(on_press=self._delete_callback) self.add_widget(self.db) self.a_delete = Animation(width=0, height=0, xoffset=self.kx + self.width/2, yoffset=self.ky + self.height/2, duration=0.5, f='ease_in_cubic') self.a_show = Animation(db_alpha=.5, duration=0.25) self.a_hide = Animation(db_alpha=0.0, duration=0.25) def show_delete(self): if not self.deletable: return self.db.show() self.a_show.animate(self) def hide_delete(self): if not self.deletable: return self.a_hide.animate(self) def on_animation_complete(self, anim): if anim == self.a_hide: self.db.hide() elif anim == self.a_delete: try: self.parent.remove_widget(self) except: pass def update(self): if not self.free: self.pos = self.kx + self.xoffset, self.ky + self.yoffset if self.deletable: self.db.pos = (self.x + self.width-40, self.y + self.height-40) self.db.style['bg-color'] = (1, 0, 0, self.db_alpha) def on_press(self, touch): if self.db.visible and self.db.on_touch_down(touch): return True def _delete_callback(self, touch): # So it doesn't poke out at the end(we aren't scaling it) self.db.hide() self.a_delete.animate(self)
def new_tab(self, label): '''fucntion that returns a new tab. return value must be of type MTButton or derive from it (must have on_press handler) if you overwrite the method. A Screenlayuot subclasses can overwrite this to create tabs based with own look and feel or do other custom things when a new tab is created''' return MTButton(label=label, size_hint=(1, 1), height=30)
class MTKineticObject(MTWidget): def __init__(self, **kwargs): '''Kinetic object, the base object for every child in kineticlist. :Parameters: `deletable`: bool, default to True Indicate if object can be deleted or not ''' kwargs.setdefault('deletable', True) super(MTKineticObject, self).__init__(**kwargs) self.deletable = kwargs.get('deletable') self.register_event_type('on_animation_complete') self.push_handlers(on_animation_complete=self.on_animation_complete) # List of attributes that can be searched self.attr_search = ['label'] # In case the widget has to move itself # while still having kinetic movement applied self.xoffset = self.yoffset = 0 # The position values that the kinetic container edits. # We do this so we can break free and move ourself it necessary self.kx = self.ky = 0 self.db_alpha = 0.0 # Set to true if you want to break free from # the grasp of a kinetic widget self.free = False # Delete Button if self.deletable: self.db = MTButton(label='', size=(40, 40), pos=(self.x + self.width - 40, self.y + self.height - 40), style={'bg-color': (1, 0, 0, 0)}, visible=False) self.db.push_handlers(on_press=self._delete_callback) self.add_widget(self.db) self.a_delete = Animation(width=0, height=0, xoffset=self.kx + self.width / 2, yoffset=self.ky + self.height / 2, duration=0.5, f='ease_in_cubic') self.a_show = Animation(db_alpha=.5, duration=0.25) self.a_hide = Animation(db_alpha=0.0, duration=0.25) def show_delete(self): if not self.deletable: return self.db.show() self.a_show.animate(self) def hide_delete(self): if not self.deletable: return self.a_hide.animate(self) def on_animation_complete(self, anim): if anim == self.a_hide: self.db.hide() elif anim == self.a_delete: try: self.parent.remove_widget(self) except: pass def update(self): if not self.free: self.pos = self.kx + self.xoffset, self.ky + self.yoffset if self.deletable: self.db.pos = (self.x + self.width - 40, self.y + self.height - 40) self.db.style['bg-color'] = (1, 0, 0, self.db_alpha) def on_press(self, touch): if self.db.visible and self.db.on_touch_down(touch): return True def _delete_callback(self, touch): # So it doesn't poke out at the end(we aren't scaling it) self.db.hide() self.a_delete.animate(self)
def __init__(self, **kwargs): kwargs.setdefault('anchor_x', 'left') kwargs.setdefault('anchor_y', 'center') kwargs.setdefault('halign', 'left') kwargs.setdefault('keyboard', None) kwargs.setdefault('keyboard_to_root', False) kwargs.setdefault('group', None) kwargs.setdefault('switch', True) kwargs.setdefault('keyboard_type', pymt_config.get('widgets', 'keyboard_type')) super(MTTextInput, self).__init__(**kwargs) self.register_event_type('on_text_change') self.register_event_type('on_text_validate') self._scroll_x = 0 self._can_deactive = True self._keyboard = kwargs.get('keyboard') self._is_active_input = False #: Boolean to activate the password mode on the textinput. #: If true, it will show star instead of real characters self.password = kwargs.get('password', False) #: Boolean to control the scrolling of the textinput content self.scroll = kwargs.get('scroll', True) #: If the scroll if more than scroll_trigger, no event will be #: dispatched, and no show/hide of keyboard. self.scroll_trigger = kwargs.get('scroll_trigger', 10) #: Keyboard type (virtual or real) self.keyboard_type = kwargs.get('keyboard_type') #: If True, the keyboard is added to root window, not to parent window. self.keyboard_to_root = kwargs.get('keyboard_to_root') # initialize group on random if nothing is set self._groupname = kwargs.get('group') if self._groupname is None: MTTextInput._group_id += 1 self._groupname = 'uniqgroup%d' % MTTextInput._group_id # first time ? create the group if not self._groupname in self._group: self.group['keyboard'] = None self.group['widgets'] = [] self.group['widgets'].append(self) # save original color for error self._notify_bg_color = self.style['bg-color'] self._notify_bg_color_active = self.style['bg-color-active'] self._notify_animation = None # switch button between vkeyboard or hardware self._switch = None if kwargs.get('switch'): self._switch = MTButton( label=kwargs.get('keyboard_type'), cls='switch-button', size=(60, 20), font_size=8, pos=(self.x + self.width - 60, self.y + self.height)) self.interesting_keys = {8: 'backspace', 13: 'enter', 127: 'del', 271: 'enter', 273: 'cursor_up', 274: 'cursor_down', 275: 'cursor_right', 276: 'cursor_left', 278: 'cursor_home', 279: 'cursor_end', 280: 'cursor_pgup', 281: 'cursor_pgdown'}
class MTTextInput(MTButton): ''' A text input widget is a simple label widget that will pop up a virtual keyboard when touched any input of the virtual keyboard will then have effect on the TextInput widget. .. versionadded:: 0.5.1 Support of scrolling textarea, controlled by `scroll` attribute. You can now scroll inside the text area without editing text. :Parameters: `keyboard`: MTVkeyboard object, default to None Use another MTVKeyboard than the default one `keyboard_to_root`: bool, defaults to False. Indicate whether the keyboard should be attached to the root window. If True, this will have the effect of the keyboard being raised above other widgets. `keyboard_type`: str, default to config. Configuration section is 'widgets', token 'keyboard_type'. Can be one of 'virtual' or 'real'. If real, the virtual keyboard will be not showed `password`: bool, default to False If True, the label will be showed with star `group`: str, default to random If the group is the same for multiple text input You can switch between them with TAB, and use the same keyboard. `switch`: bool, default to True If True, a switch button will be show to switch from real or virtual keyboard `scroll`: bool, default to True If True, the scrolling of a text area is allowed. `scroll_trigger`: int, default to 10 If scrolling is detected, don't fire event to show/hide keyboard. :Events: `on_text_change` (text) Fired when the content of text input is changed `on_text_validate` () Fired when the text is validate (when ENTER is hit on keyboard) ''' _group_id = 0 _group = {} def __init__(self, **kwargs): kwargs.setdefault('anchor_x', 'left') kwargs.setdefault('anchor_y', 'center') kwargs.setdefault('halign', 'left') kwargs.setdefault('keyboard', None) kwargs.setdefault('keyboard_to_root', False) kwargs.setdefault('group', None) kwargs.setdefault('switch', True) kwargs.setdefault('keyboard_type', pymt_config.get('widgets', 'keyboard_type')) super(MTTextInput, self).__init__(**kwargs) self.register_event_type('on_text_change') self.register_event_type('on_text_validate') self._scroll_x = 0 self._can_deactive = True self._keyboard = kwargs.get('keyboard') self._is_active_input = False #: Boolean to activate the password mode on the textinput. #: If true, it will show star instead of real characters self.password = kwargs.get('password', False) #: Boolean to control the scrolling of the textinput content self.scroll = kwargs.get('scroll', True) #: If the scroll if more than scroll_trigger, no event will be #: dispatched, and no show/hide of keyboard. self.scroll_trigger = kwargs.get('scroll_trigger', 10) #: Keyboard type (virtual or real) self.keyboard_type = kwargs.get('keyboard_type') #: If True, the keyboard is added to root window, not to parent window. self.keyboard_to_root = kwargs.get('keyboard_to_root') # initialize group on random if nothing is set self._groupname = kwargs.get('group') if self._groupname is None: MTTextInput._group_id += 1 self._groupname = 'uniqgroup%d' % MTTextInput._group_id # first time ? create the group if not self._groupname in self._group: self.group['keyboard'] = None self.group['widgets'] = [] self.group['widgets'].append(self) # save original color for error self._notify_bg_color = self.style['bg-color'] self._notify_bg_color_active = self.style['bg-color-active'] self._notify_animation = None # switch button between vkeyboard or hardware self._switch = None if kwargs.get('switch'): self._switch = MTButton( label=kwargs.get('keyboard_type'), cls='switch-button', size=(60, 20), font_size=8, pos=(self.x + self.width - 60, self.y + self.height)) self.interesting_keys = {8: 'backspace', 13: 'enter', 127: 'del', 271: 'enter', 273: 'cursor_up', 274: 'cursor_down', 275: 'cursor_right', 276: 'cursor_left', 278: 'cursor_home', 279: 'cursor_end', 280: 'cursor_pgup', 281: 'cursor_pgdown'} def on_resize(self, *largs): if hasattr(self, '_switch'): self._switch.pos = self.x + self.width - 60, self.y + self.height return super(MTTextInput, self).on_resize(*largs) def _get_keyboard(self): if not self._keyboard: self._keyboard = self.group['keyboard'] if self._keyboard is None: self._keyboard = MTVKeyboard() self.group['keyboard'] = self._keyboard return self._keyboard def _set_keyboard(self, value): if self._keyboard is not None: self._keyboard.remove_handlers( on_text_change=self._kbd_on_text_change, on_key_up=self._kbd_on_key_up ) self._keyboard = value keyboard = property(_get_keyboard, _set_keyboard) def on_release(self, touch): if not self._can_deactive: return if self._is_active_input: self.hide_keyboard() else: self.show_keyboard() def _kbd_on_text_change(self, value): # reset scrolling when text is typed self._scroll_x = 0 self.label = value self.dispatch_event('on_text_change', value) def _kbd_on_key_up(self, key, repeat=False): displayed_str, internal_str, internal_action, scale = key if internal_action is None: return elif internal_action == 'enter': self.hide_keyboard() self.dispatch_event('on_text_validate') elif internal_action == 'escape': self.hide_keyboard() def on_text_validate(self): pass def on_text_change(self, text): pass @property def group(self): '''Return information (keyboard/widget list) from the current group of the widget''' if not self._groupname in self._group: self._group[self._groupname] = {} return self._group[self._groupname] def notify_error(self): '''Call this function to make animation on background as an error ''' error_color = self.style['bg-color-error'] if self._notify_animation is not None: self._notify_animation.stop() self.style['bg-color'] = self._notify_bg_color self.style['bg-color-active'] = self._notify_bg_color_active self._notify_animation = self.do(Animation( style={'bg-color': error_color, 'bg-color-active': error_color}, f=lambda x: 1 - AnimationAlpha.ease_in_out_quart(x))) def deactivate_group(self): '''Deactivate all widgets in the group''' for w in self.group['widgets']: w.hide_keyboard() def focus_next(self): '''Focus the next textinput in the list''' idx = (self.group['widgets'].index(self) + 1) idx = idx % len(self.group['widgets']) widget = self.group['widgets'][idx] widget.show_keyboard() def show_keyboard(self): '''Show the associed keyboard of this widget.''' if self._is_active_input: return self.deactivate_group() self._is_active_input = True # activate switch button if necessary if self._switch: self.add_widget(self._switch) # activate the real keyboard w = self.get_root_window() w.push_handlers(on_key_down=self._window_on_key_down, on_key_up=self._window_on_key_up) # activate the virtual keyboard if self.keyboard_type == 'virtual': to_root = self.keyboard_to_root w = self.get_root_window() if to_root else self.get_parent_window() w.add_widget(self.keyboard) if self.keyboard is not None: self._keyboard.push_handlers( on_text_change=self._kbd_on_text_change, on_key_up=self._kbd_on_key_up ) self._keyboard.text = self.label def hide_keyboard(self): '''Hide the associed keyboard of this widget.''' if not self._is_active_input: return if self._switch: self.remove_widget(self._switch) parent = self.keyboard.parent if parent is not None: # If keyboard type is real, the keyboard is not attached to any # parent widget. parent.remove_widget(self.keyboard) w = self.get_root_window() w.remove_handlers(on_key_down=self._window_on_key_down, on_key_up=self._window_on_key_up) self._is_active_input = False if self._keyboard is not None: self._keyboard.remove_handlers( on_text_change=self._kbd_on_text_change, on_key_up=self._kbd_on_key_up ) def _window_on_key_down(self, key, scancode=None, unicode=None): if key == 27: # escape self.hide_keyboard() return True elif key == 9: # tab self.focus_next() return True if not self.keyboard: return k = self.interesting_keys.get(key) if k: key = (None, None, k, 1) self.keyboard.dispatch_event('on_key_down', key) else: if unicode is not None: self.keyboard.text += unicode else: self.keyboard.text += chr(key) def _window_on_key_up(self, key, scancode=None, unicode=None): k = self.interesting_keys.get(key) if k and self.keyboard: key = (None, None, k, 1) self.keyboard.dispatch_event('on_key_up', key) def _get_value(self): return self.label def _set_value(self, value): self.label = value value = property(_get_value, _set_value, doc='Get/set the value of the label') def _get_keyboard_type(self): return self._keyboard_type def _set_keyboard_type(self, t): self.hide_keyboard() self._keyboard_type = t if self._is_active_input: self.show_keyboard() keyboard_type = property(_get_keyboard_type, _set_keyboard_type, doc='Get/set the keyboard type to use') @property def is_active_input(self): '''Return True if the input is active''' return self._is_active_input # # Overload the touch down/move/up for : # 1. handle the switch button # 2. be able to scroll inside the text input # def on_touch_down(self, touch): # check if it's the switch button that collide. if self._switch and self._switch.collide_point(*touch.pos): self.hide_keyboard() if self.keyboard_type == 'virtual': self.keyboard_type = 'real' else: self.keyboard_type = 'virtual' self._switch.label = self.keyboard_type self.show_keyboard() return True # reset scrolling when a touch is comming # FIXME: can be not accurate if many touch are comming. if self.collide_point(*touch.pos): self._scroll_x = 0 self._can_deactive = True # and only now, dispatch as usual. return super(MTTextInput, self).on_touch_down(touch) def on_touch_move(self, touch): if not super(MTTextInput, self).on_touch_move(touch): return # we got a valid touch, self._scroll_x += touch.dxpos - touch.x self._can_deactive = True if abs(touch.x - touch.oxpos) > self.scroll_trigger and self.scroll: self._can_deactive = False return True def on_touch_up(self, touch): if super(MTTextInput, self).on_touch_up(touch): if not self.is_active_input: self._scroll_x = 0 self._can_deactive = True return True def draw(self): if self._is_active_input and self.keyboard_type == 'virtual': set_color(*self.style.get('bg-color')) kx, ky = self.keyboard.to_window(*self.keyboard.center) kx, ky = self.to_widget(kx, ky) drawLine([self.center[0], self.center[1], kx, ky]) if self.password: pw = '*' * len(self.label) old_label = self.label self.label = pw super(MTTextInput, self).draw() if self.password: self.label = old_label def draw_background(self): set_color(*self.style.get('bg-color')) state = 'active' is self._is_active_input or None drawCSSRectangle(pos=self.pos, size=self.size, style=self.style, state=state) def draw_label(self, dx=0, dy=0): # before drawing label, adjust the viewport position of the label. it's # a new feature that permit to draw only a part of the label. width = self._used_label.width - self.width scroll_x = self._scroll_x if self.scroll else 0 if self.is_active_input: scroll_x = width + scroll_x if scroll_x > width: scroll_x = width if scroll_x < 0: scroll_x = 0 self.viewport_pos = (scroll_x, 0) super(MTTextInput, self).draw_label(dx, dy) def on_update(self): super(MTTextInput, self).on_update() if self._switch: self._switch.pos = self.x + self.width - 60, self.y + self.height
class MTTextInput(MTButton): ''' A text input widget is a simple label widget that will pop up a virtual keyboard when touched any input of the virtual keyboard will then have effect on the TextInput widget. :Parameters: `keyboard`: MTVkeyboard object, default to None Use another MTVKeyboard than the default one `keyboard_to_root`: bool, defaults to False. Indicate whether the keyboard should be attached to the root window. If True, this will have the effect of the keyboard being raised above other widgets. `keyboard_type`: str, default to config. Configuration section is 'widgets', token 'keyboard_type'. Can be one of 'virtual' or 'real'. If real, the virtual keyboard will be not showed `password`: bool, default to False If True, the label will be showed with star `group`: str, default to random If the group is the same for multiple text input You can switch between them with TAB, and use the same keyboard. `switch`: bool, default to True If True, a switch button will be show to switch from real or virtual keyboard :Events: `on_text_change` (text) Fired when the content of text input is changed `on_text_validate` () Fired when the text is validate (when ENTER is hit on keyboard) ''' _group_id = 0 _group = {} def __init__(self, **kwargs): kwargs.setdefault('anchor_x', 'left') kwargs.setdefault('anchor_y', 'center') kwargs.setdefault('halign', 'left') kwargs.setdefault('keyboard', None) kwargs.setdefault('keyboard_to_root', False) kwargs.setdefault('password', False) kwargs.setdefault('group', None) kwargs.setdefault('switch', True) kwargs.setdefault('keyboard_type', pymt_config.get('widgets', 'keyboard_type')) super(MTTextInput, self).__init__(**kwargs) self._keyboard = kwargs.get('keyboard') self.is_active_input = False self.password = kwargs.get('password') # initialize group on random if nothing is set self._groupname = kwargs.get('group') if self._groupname is None: MTTextInput._group_id += 1 self._groupname = 'uniqgroup%d' % MTTextInput._group_id # first time ? create the group if not self._groupname in self._group: self.group['keyboard'] = None self.group['widgets'] = [] self.group['widgets'].append(self) self.register_event_type('on_text_change') self.register_event_type('on_text_validate') # save original color for error self._notify_bg_color = self.style['bg-color'] self._notify_bg_color_active = self.style['bg-color-active'] self._notify_animation = None # switch button between vkeyboard or hardware self._switch = None if kwargs.get('switch'): self._switch = MTButton( label=kwargs.get('keyboard_type'), cls='switch-button', size=(60, 20), font_size=8, pos=(self.x + self.width - 60, self.y + self.height)) self.keyboard_type = kwargs.get('keyboard_type') self.keyboard_to_root = kwargs.get('keyboard_to_root') self.interesting_keys = {8: 'backspace', 13: 'enter', 127: 'del', 271: 'enter', 273: 'cursor_up', 274: 'cursor_down', 275: 'cursor_right', 276: 'cursor_left', 278: 'cursor_home', 279: 'cursor_end', 280: 'cursor_pgup', 281: 'cursor_pgdown'} def on_resize(self, *largs): if hasattr(self, '_switch'): self._switch.pos = self.x + self.width - 60, self.y + self.height return super(MTTextInput, self).on_resize(*largs) def _get_keyboard(self): if not self._keyboard: self._keyboard = self.group['keyboard'] if self._keyboard is None: self._keyboard = MTVKeyboard() self.group['keyboard'] = self._keyboard return self._keyboard def _set_keyboard(self, value): if self._keyboard is not None: self._keyboard.remove_handlers( on_text_change=self._kbd_on_text_change, on_key_up=self._kbd_on_key_up ) self._keyboard = value keyboard = property(_get_keyboard, _set_keyboard) def on_press(self, touch): if self.is_active_input: self.hide_keyboard() else: self.show_keyboard() def _kbd_on_text_change(self, value): self.label = value self.dispatch_event('on_text_change', value) def _kbd_on_key_up(self, key, repeat=False): displayed_str, internal_str, internal_action, scale = key if internal_action is None: return elif internal_action == 'enter': self.hide_keyboard() self.dispatch_event('on_text_validate') elif internal_action == 'escape': self.hide_keyboard() def on_text_validate(self): pass def on_text_change(self, text): pass @property def group(self): '''Return information (keyboard/widget list) from the current group of the widget''' if not self._groupname in self._group: self._group[self._groupname] = {} return self._group[self._groupname] def notify_error(self): '''Call this function to make animation on background as an error ''' error_color = self.style['bg-color-error'] if self._notify_animation is not None: self._notify_animation.stop() self.style['bg-color'] = self._notify_bg_color self.style['bg-color-active'] = self._notify_bg_color_active self._notify_animation = self.do(Animation( style={'bg-color': error_color, 'bg-color-active': error_color}, f=lambda x: 1 - AnimationAlpha.ease_in_out_quart(x))) def deactivate_group(self): '''Deactivate all widgets in the group''' for w in self.group['widgets']: w.hide_keyboard() def focus_next(self): '''Focus the next textinput in the list''' idx = (self.group['widgets'].index(self) + 1) idx = idx % len(self.group['widgets']) widget = self.group['widgets'][idx] widget.show_keyboard() def show_keyboard(self): '''Show the associed keyboard of this widget.''' if self.is_active_input: return self.deactivate_group() self.is_active_input = True # activate switch button if necessary if self._switch: self.add_widget(self._switch) # activate the real keyboard w = self.get_root_window() w.push_handlers(on_key_down=self._window_on_key_down, on_key_up=self._window_on_key_up) # activate the virtual keyboard if self.keyboard_type == 'virtual': to_root = self.keyboard_to_root w = self.get_root_window() if to_root else self.get_parent_window() w.add_widget(self.keyboard) if self.keyboard is not None: self._keyboard.push_handlers( on_text_change=self._kbd_on_text_change, on_key_up=self._kbd_on_key_up ) self._keyboard.text = self.label def hide_keyboard(self): '''Hide the associed keyboard of this widget.''' if not self.is_active_input: return if self._switch: self.remove_widget(self._switch) parent = self.keyboard.parent if parent is not None: # If keyboard type is real, the keyboard is not attached to any # parent widget. parent.remove_widget(self.keyboard) w = self.get_root_window() w.remove_handlers(on_key_down=self._window_on_key_down, on_key_up=self._window_on_key_up) self.is_active_input = False if self._keyboard is not None: self._keyboard.remove_handlers( on_text_change=self._kbd_on_text_change, on_key_up=self._kbd_on_key_up ) def on_update(self): super(MTTextInput, self).on_update() if self._switch: self._switch.pos = self.x + self.width - 60, self.y + self.height def draw(self): if self.is_active_input and self.keyboard_type == 'virtual': set_color(*self.style.get('bg-color')) kx, ky = self.keyboard.to_window(*self.keyboard.center) kx, ky = self.to_widget(kx, ky) drawLine([self.center[0], self.center[1], kx, ky]) if self.password: pw = '*' * len(self.label) old_label = self.label self.label = pw super(MTTextInput, self).draw() if self.password: self.label = old_label def draw_background(self): if self.is_active_input: set_color(*self.style.get('bg-color')) drawCSSRectangle(pos=self.pos, size=self.size, style=self.style, state='active') else: set_color(*self.style.get('bg-color')) drawCSSRectangle(pos=self.pos, size=self.size, style=self.style) def _window_on_key_down(self, key, scancode=None, unicode=None): if key == 27: # escape self.hide_keyboard() return True elif key == 9: # tab self.focus_next() return True if not self.keyboard: return k = self.interesting_keys.get(key) if k: key = (None, None, k, 1) self.keyboard.dispatch_event('on_key_down', key) else: if unicode is not None: self.keyboard.text += unicode else: self.keyboard.text += chr(key) def _window_on_key_up(self, key, scancode=None, unicode=None): k = self.interesting_keys.get(key) if k and self.keyboard: key = (None, None, k, 1) self.keyboard.dispatch_event('on_key_up', key) def _get_value(self): return self.label def _set_value(self, value): self.label = value value = property( lambda self: self._get_value(), lambda self, x: self._set_value(x), doc='Get/set the value of the label') def _get_keyboard_type(self): return self._keyboard_type def _set_keyboard_type(self, t): self.hide_keyboard() self._keyboard_type = t if self.is_active_input: self.show_keyboard() keyboard_type = property( lambda self: self._get_keyboard_type(), lambda self, x: self._set_keyboard_type(x), doc='Get/set the keyboard type to use') # # Needed if the switch button must be replaced # def on_touch_down(self, touch): if self._switch and self._switch.collide_point(*touch.pos): self.hide_keyboard() if self.keyboard_type == 'virtual': self.keyboard_type = 'real' else: self.keyboard_type = 'virtual' self._switch.label = self.keyboard_type self.show_keyboard() return True return super(MTTextInput, self).on_touch_down(touch)
def __init__(self, **kwargs): kwargs.setdefault('anchor_x', 'left') kwargs.setdefault('anchor_y', 'center') kwargs.setdefault('halign', 'left') kwargs.setdefault('keyboard', None) kwargs.setdefault('keyboard_to_root', False) kwargs.setdefault('group', None) kwargs.setdefault('switch', True) kwargs.setdefault('keyboard_type', pymt_config.get('widgets', 'keyboard_type')) super(MTTextInput, self).__init__(**kwargs) self.register_event_type('on_text_change') self.register_event_type('on_text_validate') self._scroll_x = 0 self._can_deactive = True self._keyboard = kwargs.get('keyboard') self._is_active_input = False #: Boolean to activate the password mode on the textinput. #: If true, it will show star instead of real characters self.password = kwargs.get('password', False) #: Boolean to control the scrolling of the textinput content self.scroll = kwargs.get('scroll', True) #: If the scroll if more than scroll_trigger, no event will be #: dispatched, and no show/hide of keyboard. self.scroll_trigger = kwargs.get('scroll_trigger', 10) #: Keyboard type (virtual or real) self.keyboard_type = kwargs.get('keyboard_type') #: If True, the keyboard is added to root window, not to parent window. self.keyboard_to_root = kwargs.get('keyboard_to_root') # initialize group on random if nothing is set self._groupname = kwargs.get('group') if self._groupname is None: MTTextInput._group_id += 1 self._groupname = 'uniqgroup%d' % MTTextInput._group_id # first time ? create the group if not self._groupname in self._group: self.group['keyboard'] = None self.group['widgets'] = [] self.group['widgets'].append(self) # save original color for error self._notify_bg_color = self.style['bg-color'] self._notify_bg_color_active = self.style['bg-color-active'] self._notify_animation = None # switch button between vkeyboard or hardware self._switch = None if kwargs.get('switch'): self._switch = MTButton(label=kwargs.get('keyboard_type'), cls='switch-button', size=(60, 20), font_size=8, pos=(self.x + self.width - 60, self.y + self.height)) self.interesting_keys = { 8: 'backspace', 13: 'enter', 127: 'del', 271: 'enter', 273: 'cursor_up', 274: 'cursor_down', 275: 'cursor_right', 276: 'cursor_left', 278: 'cursor_home', 279: 'cursor_end', 280: 'cursor_pgup', 281: 'cursor_pgdown', 303: 'shift_L', 304: 'shift_R' }
class MTPopup(MTScatterWidget): '''Popup with customizable content. :Parameters: `show_cancel`: bool, default to True Show/hide the cancel button `label_cancel`: str, default to 'Cancel' Change the label of cancel button `label_submit`: str, default to 'Ok' Change the label of submit button `title`: str, default to 'PyMT popup' Title of the popup (if None, no title will be added.) `exit_on_submit`: bool, default to 'True' Title of the popup (if None, no title will be added.) :Events: `on_submit` Fired when the popup submit button is pressed. In default behavior, the widget remove himself from parent. `on_cancel` Fired when the popup cancel button is pressed. In default behavior, the widget remove himself from parent. ''' def __init__(self, **kwargs): kwargs.setdefault('do_scale', False) kwargs.setdefault('size', (400, 400)) kwargs.setdefault('show_cancel', True) kwargs.setdefault('label_cancel', 'Cancel') kwargs.setdefault('label_submit', 'Ok') kwargs.setdefault('title', 'PyMT popup') kwargs.setdefault('exit_on_submit', True) super(MTPopup, self).__init__(**kwargs) self.register_event_type('on_submit') self.register_event_type('on_cancel') self.exit_on_submit = kwargs.get('exit_on_submit') # Create layouts self.layout = MTBoxLayout(size=self.size, orientation='vertical') self.l_content = MTBoxLayout(orientation='vertical') self.l_buttons = MTBoxLayout(size_hint=(1, None), orientation='horizontal') # Titles if kwargs.get('title'): self.w_title = MTLabel(label=kwargs.get('title'), autosize=True, cls='popup-title') # Buttons self.w_submit = MTButton(label=kwargs.get('label_submit'), size_hint=(0.5, None), height=40, cls='popup-button') self.w_submit.push_handlers(on_release=curry( self._dispatch_event, 'on_submit')) self.l_buttons.add_widget(self.w_submit) if kwargs.get('show_cancel'): self.w_cancel = MTButton(label=kwargs.get('label_cancel'), size_hint=(0.5, None), height=40, cls='popup-button') self.w_cancel.push_handlers(on_release=curry( self._dispatch_event, 'on_cancel')) self.l_buttons.add_widget(self.w_cancel) # Connect if kwargs.get('title'): self.layout.add_widget(self.w_title) self.layout.add_widget(self.l_content) self.layout.add_widget(self.l_buttons) super(MTPopup, self).add_widget(self.layout) def _ensure_layout(self, force=False): while force or (self.size != self.layout.size): self.layout.do_layout() self.size = self.layout.size force = False def add_widget(self, widget, force=False): self.l_content.add_widget(widget) self._ensure_layout(force) def remove_widget(self, widget, force=False): self.l_content.remove_widget(widget) self._ensure_layout(force) def close(self): if self.exit_on_submit: self.parent.remove_widget(self) else: self.hide() def on_submit(self): self.close() def on_cancel(self): self.close() def _dispatch_event(self, event, *largs): self.dispatch_event(event) def draw(self): # draw background set_color(*self.style['bg-color']) drawCSSRectangle(size=self.size, style=self.style)