def _perform_buildozer_init(self, *args): '''Copies the spec from data/new_templates/default.spec to the project folder ''' get_designer().close_popup() proj_dir = get_current_project().path spec_file = os.path.join(proj_dir, 'buildozer.spec') templates_dir = os.path.join(get_kd_data_dir(), constants.DIR_NEW_TEMPLATE) shutil.copy(os.path.join(templates_dir, 'default.spec'), spec_file) self.designer.designer_content.update_tree_view(get_current_project())
def create_setup_py(self): '''Runs the GUI to create a setup.py file ''' d = get_designer() if d.popup: return False proj_dir = get_current_project().path designer_content = self.designer.designer_content setup_path = os.path.join(proj_dir, 'setup.py') if os.path.exists(setup_path): show_alert('Create setup.py', 'setup.py already exists!') return False content = ToolSetupPy(path=setup_path) d.popup = Popup(title='Create setup.py', content=content, size_hint=(None, None), size=(550, 350), auto_dismiss=False) content.bind(on_cancel=d.close_popup) def on_create(*args): designer_content.update_tree_view(get_current_project()) d.close_popup() content.bind(on_create=on_create) d.popup.open()
def check_pep8(self): '''Check the PEP8 from current project ''' proj_dir = get_current_project().path kd_dir = get_kd_dir() pep8_dir = os.path.join(kd_dir, 'tools', 'pep8checker', 'pep8kivy.py') python_path =\ self.designer.designer_settings.config_parser.getdefault( 'global', 'python_shell_path', '' ) if python_path == '': self.profiler.dispatch( 'on_error', 'Python Shell Path not ' 'specified.' '\n\nUpdate it on \'File\' -> \'Settings\'') return if sys.platform[0] == 'w': pep8_dir = u'"' + pep8_dir + u'"' cmd = '%s %s %s' % (python_path, pep8_dir, proj_dir) self.designer.ui_creator.tab_pannel.switch_to( self.designer.ui_creator.tab_pannel.tab_list[2]) self.designer.ui_creator.kivy_console.run_command(cmd)
def on_text(self, *args): '''Listen text changes ''' if self.focus: self.saved = False d = get_designer() get_current_project().saved = False
def recursive_insert(self, node, treenode): '''This function will add a node to TreeView, by recursively travelling through the Root Widget's Tree. ''' if node is None: return b = self._get_widget(node) self.tree.add_node(b, treenode) class_rules = get_current_project().app_widgets root_widget = self.playground.root is_child_custom = False for rule_name in class_rules: if rule_name == type(node).__name__: is_child_custom = True break is_child_complex = False for widget in toolbox_widgets: if widget[0] == type(node).__name__ and widget[1] == 'complex': is_child_complex = True break if root_widget == node or (not is_child_custom and not is_child_complex): if isinstance(node, TabbedPanel): self.insert_for_tabbed_panel(node, b) else: for child in node.children: self.recursive_insert(child, b)
def find_target(self, x, y, target, widget=None): '''This widget is used to find the widget which collides with x,y :param widget: widget to be added in target :param target: widget to search over :param x: position to search :param y: position to search ''' if target is None or not target.collide_point(x, y): return None x, y = target.to_local(x, y) class_rules = get_current_project().app_widgets for child in target.children: is_child_custom = False if child == widget: continue for rule_name in class_rules: if rule_name == type(child).__name__: is_child_custom = True break is_child_complex = False for _widget in widgets_common: if _widget[0] == type(child).__name__ and \ _widget[1] == 'complex': is_child_complex = True break # if point lies in custom wigdet's child then return custom widget if is_child_custom or is_child_complex: if not widget and self._custom_widget_collides(child, x, y): return child elif widget: if isinstance(child, TabbedPanel): if child.current_tab: _item = self.find_target( x, y, child.current_tab.content, widget) return _item else: return target elif isinstance(child.parent, Carousel): t = self.find_target(x, y, child, widget) return t else: if not child.collide_point(x, y): continue if not self.allowed_target_for(child, widget) and not \ child.children: continue return self.find_target(x, y, child, widget) return target
def _perform_load_widget(self, widget_name, update_kv_lang=True): '''Loads the widget if everything is ok :param widget_name name of the widget to display :param update_kv_lang if True, reloads the kv file. If False, keep the kv lang text ''' self.root_name = widget_name self.root = None self.sandbox.clear_widgets() widgets = get_current_project().app_widgets try: target = widgets[widget_name] if update_kv_lang: # updates kv lang text with file kv_path = target.kv_path if kv_path: self.kv_code_input.text = open(kv_path, encoding='utf-8').read() else: show_message( 'Could not found the associated .kv file with %s' ' widget' % widget_name, 5, 'error' ) self.kv_code_input.text = '' self.root_app_widget = target wdg = get_app_widget(target) if wdg is None: self.kv_code_input.have_error = True self.add_widget_to_parent(wdg, None, from_undo=True, from_kv=True) self.kv_code_input.path = target.kv_path except (KeyError, AttributeError): show_message( 'Failed to load %s widget' % widget_name, 5, 'error')
def do_paste(self): '''Paste the selected widget to the current widget ''' parent = self.selected_widget if parent and self.widget_to_paste: d = get_current_project() class_rules = d.app_widgets root_widget = self.root is_child_custom = False for rule_name in class_rules: if rule_name == type(parent).__name__: is_child_custom = True break # find appropriate parent to add widget_to_paste while parent: if isinstance(parent, Layout) and (not is_child_custom or root_widget == parent): break parent = parent.parent is_child_custom = False for rule_name in class_rules: if rule_name == type(parent).__name__: is_child_custom = True break if parent is not None: self.add_widget_to_parent(self.widget_to_paste, parent, kv_str=self._widget_str_to_paste) self.widget_to_paste = None
def check_pep8(self): '''Check the PEP8 from current project ''' proj_dir = get_current_project().path kd_dir = get_kd_dir() pep8_dir = os.path.join(kd_dir, 'tools', 'pep8checker', 'pep8kivy.py') python_path =\ self.designer.designer_settings.config_parser.getdefault( 'global', 'python_shell_path', '' ) if python_path == '': self.profiler.dispatch('on_error', 'Python Shell Path not ' 'specified.' '\n\nUpdate it on \'File\' -> \'Settings\'') return if sys.platform[0] == 'w': pep8_dir = u'"' + pep8_dir + u'"' cmd = '%s %s %s' % (python_path, pep8_dir, proj_dir) self.designer.ui_creator.tab_pannel.switch_to( self.designer.ui_creator.tab_pannel.tab_list[2]) self.designer.ui_creator.kivy_console.run_command(cmd)
def _perform_load_widget(self, widget_name, update_kv_lang=True): '''Loads the widget if everything is ok :param widget_name name of the widget to display :param update_kv_lang if True, reloads the kv file. If False, keep the kv lang text ''' self.root_name = widget_name self.root = None self.sandbox.clear_widgets() widgets = get_current_project().app_widgets try: target = widgets[widget_name] if update_kv_lang: # updates kv lang text with file kv_path = target.kv_path if kv_path: self.kv_code_input.text = open(kv_path).read() else: show_message( 'Could not found the associated .kv file with %s' ' widget' % widget_name, 5, 'error') self.kv_code_input.text = '' self.root_app_widget = target wdg = get_app_widget(target) if wdg is None: self.kv_code_input.have_error = True self.add_widget_to_parent(wdg, None, from_undo=True, from_kv=True) self.kv_code_input.path = target.kv_path except (KeyError, AttributeError): show_message('Failed to load %s widget' % widget_name, 5, 'error')
def _perform_create_spec(self, *args): '''Creates the default buildozer.spec file ''' templates_dir = os.path.join(get_kd_data_dir(), constants.DIR_NEW_TEMPLATE) shutil.copy(os.path.join(templates_dir, 'default.spec'), os.path.join(self.profiler.project_path, 'buildozer.spec')) self.designer.designer_content.update_tree_view(get_current_project()) self.designer.close_popup() self.last_command()
def create_event(self, txt): '''This function will create a new event given by 'txt' to the widget. ''' # Find the python file of widget py_file = None app_widgets = get_current_project().app_widgets for rule_name in app_widgets: if self.widget.__class__.__name__ == rule_name: py_file = app_widgets[rule_name].py_path break # Open it in DesignerTabbedPannel rel_path = py_file.replace(get_current_project().path, '') if rel_path[0] == '/' or rel_path[0] == '\\': rel_path = rel_path[1:] self.designer_tabbed_panel.open_file(py_file, rel_path, switch_to=True) self.rel_path = rel_path self.txt = txt Clock.schedule_once(self._add_event)
def load_widget(self, widget_name, update_kv_lang=True): '''Load and display and widget given its name. If widget is not found, shows information on status bar and clear the playground :param widget_name name of the widget to display :param update_kv_lang if True, reloads the kv file. If False, keep the kv lang text ''' d = get_designer() if d.popup: # if has a popup, it's not using playground return False widgets = get_current_project().app_widgets # if displaying no widget or this widget is not know if self.root is None or self.root_app_widget is None or \ widget_name not in widgets: self._perform_load_widget(widget_name, update_kv_lang) return # if a know widget, continue target = widgets[widget_name] # check if we are switching kv files if target.kv_path != self.root_app_widget.kv_path and \ not self.kv_code_input.saved: file_name = os.path.basename(self.root_app_widget.kv_path) _confirm_dlg = ConfirmationDialogSave( 'The %s was not saved. \n' 'If you continue, your modifications will be lost.\n' 'Do you want to save and continue?' % file_name) @ignore_proj_watcher def save_and_load(*args): get_current_project().save() self._perform_load_widget(widget_name, True) def dont_save(*args): d.close_popup() self._perform_load_widget(widget_name, True) _confirm_dlg.bind(on_save=save_and_load, on_dont_save=dont_save, on_cancel=d.close_popup) d.popup = Popup(title='Change Widget', content=_confirm_dlg, size_hint=(None, None), size=('400pt', '150pt'), auto_dismiss=False) d.popup.open() return self._perform_load_widget(widget_name, update_kv_lang)
def load_widget(self, widget_name, update_kv_lang=True): '''Load and display and widget given its name. If widget is not found, shows information on status bar and clear the playground :param widget_name name of the widget to display :param update_kv_lang if True, reloads the kv file. If False, keep the kv lang text ''' d = get_designer() if d.popup: # if has a popup, it's not using playground return False widgets = get_current_project().app_widgets # if displaying no widget or this widget is not know if self.root is None or self.root_app_widget is None or \ widget_name not in widgets: self._perform_load_widget(widget_name, update_kv_lang) return # if a know widget, continue target = widgets[widget_name] # check if we are switching kv files if target.kv_path != self.root_app_widget.kv_path and \ not self.kv_code_input.saved: file_name = os.path.basename(self.root_app_widget.kv_path) _confirm_dlg = ConfirmationDialogSave( 'The %s was not saved. \n' 'If you continue, your modifications will be lost.\n' 'Do you want to save and continue?' % file_name ) @ignore_proj_watcher def save_and_load(*args): get_current_project().save() self._perform_load_widget(widget_name, True) def dont_save(*args): d.close_popup() self._perform_load_widget(widget_name, True) _confirm_dlg.bind( on_save=save_and_load, on_dont_save=dont_save, on_cancel=d.close_popup) d.popup = Popup(title='Change Widget', content=_confirm_dlg, size_hint=(None, None), size=('400pt', '150pt'), auto_dismiss=False) d.popup.open() return self._perform_load_widget(widget_name, update_kv_lang)
def get_widget(self, widget_name, **default_args): '''This function is used to get the instance of class of name, widgetname. :param widget_name: name of the widget to be instantiated ''' widget = None for _widget in widgets_common: if _widget[0] == widget_name and _widget[1] == 'custom': app_widgets = get_current_project().app_widgets widget = get_app_widget(app_widgets[widget_name]) break if not widget: try: widget = Factory.get(widget_name)(**default_args) except: pass return widget
def _update_menu(self, *args): '''Update the Git ActionSubMenu content. If a valid repo is open, git tools will be available. Is not a git repo, git init is available. ''' self.remove_children() d = get_designer() loader = None if d: loader = get_current_project().path if loader: self.disabled = False if self.is_repo: btn_commit = DesignerSubActionButton(text='Commit') btn_commit.bind(on_press=self.do_commit) btn_add = DesignerSubActionButton(text='Add...') btn_add.bind(on_press=self.do_add) btn_branches = DesignerSubActionButton(text='Branches...') btn_branches.bind(on_press=self.do_branches) btn_diff = DesignerSubActionButton(text='Diff') btn_diff.bind(on_press=self.do_diff) btn_push = DesignerSubActionButton(text='Push') btn_push.bind(on_press=self.do_push) btn_pull = DesignerSubActionButton(text='Pull') btn_pull.bind(on_press=self.do_pull) self.add_widget(btn_commit) self.add_widget(btn_add) self.add_widget(btn_branches) self.add_widget(btn_diff) self.add_widget(btn_push) self.add_widget(btn_pull) else: btn_init = DesignerSubActionButton(text='Init repo') btn_init.bind(on_press=self.do_init) self.add_widget(btn_init) self._add_widget() else: self.disabled = True
def export_png(self): '''Export playground widget to png file. If there is a selected widget, export it. If not, export the root widget ''' playground = self.designer.ui_creator.playground proj_dir = get_current_project().path status = self.designer.statusbar wdg = playground.selected_widget if wdg is None: wdg = playground.root name = datetime.datetime.now().strftime("%m-%d-%Y_%H-%M-%S.png") if wdg.id: name = wdg.id + '_' + name wdg.export_to_png(os.path.join(proj_dir, name)) status.show_message('Image saved at ' + name, 5, 'info')
def create_gitignore(self): '''Create .gitignore ''' proj_dir = get_current_project().path status = self.designer.statusbar gitignore_path = os.path.join(proj_dir, '.gitignore') if os.path.exists(gitignore_path): show_alert('Create .gitignore', '.gitignore already exists!') return False gitignore = '''*.pyc *.pyo bin/ .designer/ .buildozer/ __pycache__/''' f = open(gitignore_path, 'w').write(gitignore) status.show_message('.gitignore created successfully', 5, 'info')
def on_widget_select_pressed(self, *args): '''Event handler to playground widget selector press ''' d = get_designer() if d.popup: return False widgets = get_current_project().app_widgets app_widgets = [] for name in widgets.keys(): widget = widgets[name] if widget.is_root: name = 'Root - ' + name app_widgets.append(name) fake_setting = FakeSettingList() fake_setting.allow_custom = False fake_setting.items = app_widgets fake_setting.desc = 'Select the Widget to edit on Playground' fake_setting.group = 'playground_widget' content = SettingListContent(setting=fake_setting) popup_width = min(0.95 * Window.width, 500) popup_height = min(0.95 * Window.height, 500) d.popup = Popup( content=content, title='Playground - Edit Widget', size_hint=(None, None), size=(popup_width, popup_height), auto_dismiss=False ) content.bind(on_apply=self._perform_select_root_widget, on_cancel=d.close_popup) content.selected_items = [self.root_name] if self.root_app_widget and self.root_app_widget.is_root: content.selected_items = ['Root - ' + self.root_name] content.show_items() d.popup.open()
def discover(self, value): '''To discover all properties and add their :class:`~designer.components.property_viewer.PropertyLabel` and :class:`~designer.components.property_viewer.PropertyBoolean`/ :class:`~designer.components.property_viewer.PropertyTextInput` to :data:`prop_list`. ''' add = self.prop_list.add_widget events = value.events() for event in events: ip = self.build_for(event) if not ip: continue add(EventLabel(text=event)) add(ip) # check if widget has a class to add custom events is_custom_widget = False app_widgets = get_current_project().app_widgets wdg_name = type(self.widget).__name__ for wdg in app_widgets: if wdg == wdg_name: widget = app_widgets[wdg] # if has a python file if widget.py_path: is_custom_widget = True break if is_custom_widget: # Allow adding a new event only if current widget is a custom rule add( EventLabel(text='Type and press enter to \n' 'create a new event')) txt = NewEventTextInput( multiline=False, info_message='Type and press enter to create a new event') txt.bind(on_create_event=self.create_event) add(txt)
def discover(self, value): '''To discover all properties and add their :class:`~designer.components.property_viewer.PropertyLabel` and :class:`~designer.components.property_viewer.PropertyBoolean`/ :class:`~designer.components.property_viewer.PropertyTextInput` to :data:`prop_list`. ''' add = self.prop_list.add_widget events = value.events() for event in events: ip = self.build_for(event) if not ip: continue add(EventLabel(text=event)) add(ip) # check if widget has a class to add custom events is_custom_widget = False app_widgets = get_current_project().app_widgets wdg_name = type(self.widget).__name__ for wdg in app_widgets: if wdg == wdg_name: widget = app_widgets[wdg] # if has a python file if widget.py_path: is_custom_widget = True break if is_custom_widget: # Allow adding a new event only if current widget is a custom rule add(EventLabel(text='Type and press enter to \n' 'create a new event')) txt = NewEventTextInput( multiline=False, info_message='Type and press enter to create a new event') txt.bind(on_create_event=self.create_event) add(txt)
def on_widget_select_pressed(self, *args): '''Event handler to playground widget selector press ''' d = get_designer() if d.popup: return False widgets = get_current_project().app_widgets app_widgets = [] for name in widgets.keys(): widget = widgets[name] if widget.is_root: name = 'Root - ' + name app_widgets.append(name) fake_setting = FakeSettingList() fake_setting.allow_custom = False fake_setting.items = app_widgets fake_setting.desc = 'Select the Widget to edit on Playground' fake_setting.group = 'playground_widget' content = SettingListContent(setting=fake_setting) popup_width = min(0.95 * Window.width, 500) popup_height = min(0.95 * Window.height, 500) d.popup = Popup(content=content, title='Playground - Edit Widget', size_hint=(None, None), size=(popup_width, popup_height), auto_dismiss=False) content.bind(on_apply=self._perform_select_root_widget, on_cancel=d.close_popup) content.selected_items = [self.root_name] if self.root_app_widget and self.root_app_widget.is_root: content.selected_items = ['Root - ' + self.root_name] content.show_items() d.popup.open()
def load_widget_from_file(self, kv_path): '''Loads first widget from a file :param kv_path: absolute kv path ''' self.sandbox.clear_widgets() proj = get_current_project() widgets = proj.app_widgets if not os.path.exists(kv_path): show_message(kv_path + ' not exists', 5, 'error') return self.kv_code_input.text = open(kv_path, 'r').read() self.kv_code_input.path = kv_path for key in widgets: wd = widgets[key] if wd.kv_path == kv_path: self.load_widget(wd.name, update_kv_lang=False) return # if not found a widget in the path, open the first one if len(widgets): first_wdg = widgets[list(widgets.keys())[-1]] self.load_widget(first_wdg.name, update_kv_lang=False) return show_message('No widget was found', 5, 'error')
def load_widget_from_file(self, kv_path): '''Loads first widget from a file :param kv_path: absolute kv path ''' self.sandbox.clear_widgets() proj = get_current_project() widgets = proj.app_widgets if not os.path.exists(kv_path): show_message(kv_path + ' not exists', 5, 'error') return self.kv_code_input.text = open(kv_path, 'r', encoding='utf-8').read() self.kv_code_input.path = kv_path for key in widgets: wd = widgets[key] if wd.kv_path == kv_path: self.load_widget(wd.name, update_kv_lang=False) return # if not found a widget in the path, open the first one if len(widgets): first_wdg = widgets[list(widgets.keys())[-1]] self.load_widget(first_wdg.name, update_kv_lang=False) return show_message('No widget was found', 5, 'error')
def on_reload_kv(self, kv_lang_area, text, force): '''Reloads widgets from kv lang input and update the visible widget. if force is True, all widgets must be reloaded before parsing the new kv :param force: if True, will parse the project again :param text: kv source :param kv_lang_area: instance of kivy lang area ''' proj = get_current_project() # copy of initial widgets widgets = dict(proj.app_widgets) try: if force: proj.parse() if self.root_name: kv_path = widgets[self.root_name].kv_path else: kv_path = self.kv_code_input.path proj.parse_kv(text, kv_path) # if was displaying one widget, but it was removed if self.root_name and self.root_name not in proj.app_widgets: self.load_widget_from_file(self.root_app_widget.kv_path) show_message( 'The %s is not available. Displaying another widget' % self.root_name, 5, 'info' ) elif not self.root_name and not widgets and proj.app_widgets: # if was not displaying a widget because there was no widget # and now a widget is available first_wdg = proj.app_widgets[list(proj.app_widgets.keys())[-1]] self.load_widget(first_wdg.name, update_kv_lang=False) else: # displaying an usual widget self.load_widget(self.root_name, update_kv_lang=False) except KeyError: show_message( 'Failed to load %s widget' % self.root_name, 5, 'error')
def buildozer_init(self): '''Checks if the .spec exists or not; and when possible, calls _perform_buildozer_init ''' d = get_designer() if d.popup: return False proj_dir = get_current_project().path spec_file = os.path.join(proj_dir, 'buildozer.spec') if os.path.exists(spec_file): confirm_dlg = ConfirmationDialog( message='The buildozer.spec file already exist.' '\nDo you want to create a new spec?') d.popup = Popup(title='Buildozer init', content=confirm_dlg, size_hint=(None, None), size=('250pt', '150pt'), auto_dismiss=False) confirm_dlg.bind(on_ok=self._perform_buildozer_init, on_cancel=d.close_popup) d.popup.open() else: self._perform_buildozer_init()
def on_reload_kv(self, kv_lang_area, text, force): '''Reloads widgets from kv lang input and update the visible widget. if force is True, all widgets must be reloaded before parsing the new kv :param force: if True, will parse the project again :param text: kv source :param kv_lang_area: instance of kivy lang area ''' proj = get_current_project() # copy of initial widgets widgets = dict(proj.app_widgets) try: if force: proj.parse() if self.root_name: kv_path = widgets[self.root_name].kv_path else: kv_path = self.kv_code_input.path proj.parse_kv(text, kv_path) # if was displaying one widget, but it was removed if self.root_name and self.root_name not in proj.app_widgets: self.load_widget_from_file(self.root_app_widget.kv_path) show_message( 'The %s is not available. Displaying another widget' % self.root_name, 5, 'info') elif not self.root_name and not widgets and proj.app_widgets: # if was not displaying a widget because there was no widget # and now a widget is available first_wdg = proj.app_widgets[list(proj.app_widgets.keys())[-1]] self.load_widget(first_wdg.name, update_kv_lang=False) else: # displaying an usual widget self.load_widget(self.root_name, update_kv_lang=False) except KeyError: show_message('Failed to load %s widget' % self.root_name, 5, 'error')
def find_target(self, x, y, target, widget=None): '''This widget is used to find the widget which collides with x,y :param widget: widget to be added in target :param target: widget to search over :param x: position to search :param y: position to search ''' if target is None or not target.collide_point(x, y): return None x, y = target.to_local(x, y) class_rules = get_current_project().app_widgets for child in target.children: is_child_custom = False if child == widget: continue for rule_name in class_rules: if rule_name == type(child).__name__: is_child_custom = True break is_child_complex = False for _widget in widgets_common: if _widget[0] == type(child).__name__ and \ _widget[1] == 'complex': is_child_complex = True break # if point lies in custom wigdet's child then return custom widget if is_child_custom or is_child_complex: if not widget and self._custom_widget_collides(child, x, y): return child elif widget: if isinstance(child, TabbedPanel): if child.current_tab: _item = self.find_target(x, y, child.current_tab.content, widget) return _item else: return target elif isinstance(child.parent, Carousel): t = self.find_target(x, y, child, widget) return t else: if not child.collide_point(x, y): continue if not self.allowed_target_for(child, widget) and not \ child.children: continue return self.find_target(x, y, child, widget) return target
def on_create(*args): designer_content.update_tree_view(get_current_project()) d.close_popup()
def push_operation(self, op): '''To push an operation into _undo_stack. ''' get_current_project().saved = False self._undo_stack_operation.append(op)
def save_and_load(*args): get_current_project().save() self._perform_load_widget(widget_name, True)
def add_widget_to_parent(self, widget, target, kv_str=''): '''This function is called when widget is added to target. It will search for line where parent is defined in text and will add widget there. ''' text = re.sub(r'#.+', '', self.text) lines = text.splitlines() total_lines = len(lines) if total_lines == 0: return self._reload = False # If target is not none then widget is not root widget if target: path_to_widget = self.get_widget_path(target) path_to_widget.reverse() root_lineno = 0 root_name = self.playground.root_name for lineno, line in enumerate(lines): pos = line.find(root_name) if pos != -1 and get_indentation(line) == 0: root_lineno = lineno break parent_lineno = self._find_widget_place(path_to_widget, lines, total_lines, root_lineno + 1) if parent_lineno >= total_lines: return # Get text of parents line parent_line = lines[parent_lineno] if not parent_line.strip(): return insert_after_line = -1 if parent_line.find(':') == -1: # If parent_line doesn't contain ':' then insert it # Also insert widget's rule after its properties insert_after_line = parent_lineno _line = 0 _line_pos = -1 _line_pos = self.text.find('\n', _line_pos + 1) while _line <= insert_after_line: _line_pos = self.text.find('\n', _line_pos + 1) _line += 1 self.text = self.text[:_line_pos] + ':' + self.text[_line_pos:] indent = len(parent_line) - len(parent_line.lstrip()) else: # If ':' in parent_line then, # find a place to insert widget's rule indent = len(parent_line) - len(parent_line.lstrip()) lineno = parent_lineno _indent = indent + 1 line = parent_line while (line.strip() == '' or _indent > indent): lineno += 1 if lineno >= total_lines: break line = lines[lineno] _indent = len(line) - len(line.lstrip()) insert_after_line = lineno - 1 line = lines[insert_after_line] while line.strip() == '': insert_after_line -= 1 line = lines[insert_after_line] to_insert = '' # counts indentation in the beginning of the string extra_indent = len(kv_str) - len(kv_str.lstrip()) if kv_str == '': to_insert = type(widget).__name__ + ':' else: to_insert = kv_str if insert_after_line == total_lines - 1: # if inserting at the last line _line_pos = len(self.text) - 1 indent = get_indent_str(indent + 4 - extra_indent) to_add = '' for line in to_insert.splitlines(): to_add += '\n' + indent + line self.text = self.text[:_line_pos + 1] + to_add else: # inserting somewhere else insert_after_line -= 1 _line = 0 _line_pos = -1 _line_pos = self.text.find('\n', _line_pos + 1) while _line <= insert_after_line: _line_pos = self.text.find('\n', _line_pos + 1) _line += 1 self.text = self.text[:_line_pos] + '\n' + \ get_indent_str(indent + 4) + to_insert + \ self.text[_line_pos:] else: # widget is a root widget parent_lineno = 0 self.cursor = (0, 0) type_name = type(widget).__name__ is_class = False app_widgets = get_current_project().app_widgets for rule_name in app_widgets: if rule_name == type_name: is_class = True break if not is_class: self.insert_text(type_name + ':\n') self.playground.load_widget(type_name)