def __init__(self, **kwargs): super(Container, self).__init__(**kwargs) self.previous_text = open(self.kv_file).read() parser = Parser(content=self.previous_text) widget = Factory.get(parser.root.name)() Builder._apply_rule(widget, parser.root, parser.root) self.add_widget(widget)
def change_kv(self, *largs): '''Called when the update button is clicked. Needs to update the interface for the currently active kv widget, if there is one based on the kv file the user entered. If there is an error in their kv syntax, show a nice popup.''' kv_container = self.screen_manager.current_screen.content.children[0] try: parser = Parser(content=self.language_box.text.encode('utf8')) kv_container.clear_widgets() widget = Factory.get(parser.root.name)() Builder._apply_rule(widget, parser.root, parser.root) kv_container.add_widget(widget) except (SyntaxError, ParserException) as e: self.info_label.text = str(e) self.anim = Animation(top=190.0, opacity=1, d=2, t='in_back') +\ Animation(top=190.0, d=2) +\ Animation(top=0, opacity=0, d=2) self.anim.start(self.info_label) except: import traceback traceback.print_exc() popup = Popup( title="Boom", content=Label( text='Something horrible happened while parsing' + 'your Kivy Language', text_size=(350, None), size_hint=(None, None), size=(400, 400))) popup.open()
def change_kv(self, *largs): '''Called when the update button is clicked. Needs to update the interface for the currently active kv widget, if there is one based on the kv file the user entered. If there is an error in their kv syntax, show a nice popup.''' txt = self.language_box.text kv_container = self.screen_manager.current_screen.children[0] try: parser = Parser(content=txt) kv_container.clear_widgets() widget = Factory.get(parser.root.name)() Builder._apply_rule(widget, parser.root, parser.root) kv_container.add_widget(widget) except (SyntaxError, ParserException) as e: self.show_error(e) except Exception as e: self.show_error(e)
def change_kv(self, *largs): kv_container = self.screen_manager.current_screen.content.children[0] try: parser = Parser(content=self._kv_text.encode('utf8')) kv_container.clear_widgets() widget = Factory.get(parser.root.name)() Builder._apply_rule(widget, parser.root, parser.root) kv_container.add_widget(widget) except (SyntaxError, ParserException) as e: self.info_label.text = str(e) self.anim = Animation(top=190.0, opacity=1, d=2, t='in_back') +\ Animation(top=190.0, d=2) +\ Animation(top=0, opacity=0, d=2) self.anim.start(self.info_label) except: import traceback traceback.print_exc() popup = Popup(title="Boom", content=Label(text='Something horrible happened while parsing' + 'your Kivy Language', text_size=(350, None), size_hint=(None, None), size=(400, 400))) popup.open()
def change_kv_open_file(self, *largs): txt = self.language_box.text kv_container = self.screen_manager.current_screen.children[0] try: parser = Parser(content=txt) kv_container.clear_widgets() widget = Factory.get(parser.root.name)() Builder._apply_rule(widget, parser.root, parser.root) kv_container.add_widget(widget) name = self.ids.ui_name.text save_path = name dump = pickle.dumps(save_path) all = self.db.get_kvs() kvs = [x[0] for x in all] if dump not in kvs: self.db.add_kv(dump) with open(save_path, 'w') as f: f.write(txt) except: pass
def _build(self): ''' Construct the app from KV language lines if present. (Doing so here and now is likely not a Kivy-like way of doing things). ''' KT.indent = "" tabs = [] prevIndent = None stack = [] # ^ stack.append doesn't occur until the end of this method. # print("I am a {}.".format(str(type(self).__name__))) frame = inspect.stack()[2] cfp = frame[0].f_code.co_filename cf = os.path.split(cfp)[1] mod = importlib.import_module(os.path.splitext(cf)[0]) # print("The file with custom widgets is \"{}\".".format(cfp)) KT.APP = self self.frame = self.build() # ^ Ok since kivy-tkinter widget constructors always set the # parent to App.ROOT by default--so no matter how the client # code creates the root widget, the parent will be `App.ROOT`. if KT.FORM is not None: raise RuntimeError("kivy-tkinter built twice!") self.frame.pack(fill=tk.BOTH, expand=True) #self.frame.grid(row=0, column=0, sticky=tk.NSEW) #tk.Grid.rowconfigure(KT.APP, 0, weight=1) #tk.Grid.columnconfigure(KT.APP, 0, weight=1) KT.FORM = self.frame # self.frame.grid() self.frame.parent = KT.APP # ^ But technically, KT.APP is the root widget's # (KT.APP.frame's) parent lineN = 0 fn = "KV in {}".format(os.path.split(cfp)[1]) if self.parser.filename is not None: fn = self.parser.filename for i in range(len(self.parser.sourcecode)): lineN += 1 line = self.parser.sourcecode[i].rstrip() lineS = line.strip() if lineS.startswith("#"): continue # if len(stack) == 0: if len(lineS) == 0: continue dent = line[:(len(line) - len(lineS))] # print("indent: \"{}\"".format(dent)) if len(dent) < len(KT.indent): while len("".join(tabs)) > len(dent): if stack[-1].parent is None: raise SyntaxError(dent + "Line {} of {} has more" " than one root widget near `{}`" "".format(lineN, fn, line.strip())) if stack[-1].parent is not None: pass # add the widget AFTER setting all properties ? # stack[-1].parent.add_widget(stack[-1]) del stack[-1] del tabs[-1] ''' print(dent + "Line {} of {} starts a new object" " near `{}`.".format(lineN, fn, line.strip())) ''' if len("".join(tabs)) != len(dent): raise SyntaxError(dent + "Line {} of {} doesn't" " match a previous indent near `{}`." " thisTabSize={}, dent='{}', tabs={}" "".format(lineN, fn, line.strip(), thisTabSize, dent, tabs)) KT.indent = dent kvc = Parser.parserStatement(lineS) deeperO = None ThisClass = None # thisId = None # thisOr = None # methodName = None if kvc.lvalue.isCustomClass is True: try: ThisClass = getattr(mod, kvc.lvalue.className) except AttributeError as ex: view_traceback() raise SyntaxError(dent + "Line {} of {} has a" " custom type not defined in {}" " near `{}`" "".format(lineN, fn, cf, line.strip())) # deeperO = ThisClass() # print("Creating a new (custom) {}" # # "".format(ThisClass.__name__)) elif kvc.rvalue.value is None: # Syntax "ThisClass:" denotes class (could be null or # object declaration in YAML, but is an object # declaration in kv) try: ThisClass = eval(kvc.lvalue.value) except AttributeError as ex: raise SyntaxError(dent + "Line {} of {} has a" " Kivy type not defined in" " kivy-tkinter near `{}`" "".format(lineN, fn, line.strip())) # deeperO = ThisClass() # print("Creating a new {}" # # "".format(ThisClass.__name__)) else: if len(stack) == 0: raise SyntaxError(dent + "Line {} of {} has a" " member before an object near" " `{}`".format(lineN, fn, line.strip())) # Add events and properties for both KV and custom # classes (regardless of kvc.rvalue.className presence): if kvc.lvalue.value == "orientation": stack[-1].orientation = kvc.rvalue.value ''' print("[kivy-tkinter kivy app] set {} {}" " orientation to {}" "".format(type(stack[-1]).__name__, stack[-1].id, kvc.rvalue.value)) ''' elif kvc.lvalue.value == 'id': # thisId = kvc.rvalue.value stack[-1].id = kvc.rvalue.value self.frame.ids[kvc.rvalue.value] = stack[-1] elif kvc.lvalue.value == 'text': # thisId = kvc.rvalue.value if callable(stack[-1].text): raise RuntimeError("The text override failed due to a" " programming error in kivy-tkinter" " itself.") # stack[-1].text(kvc.rvalue.value) stack[-1].text = kvc.rvalue.value elif kvc.rvalue.methodName is not None: methodName = kvc.rvalue.methodName if methodName.startswith("root."): methodName = methodName.replace("root.", "self.frame.") ''' print(dent + "using method `{}`" "".format(methodName)) ''' elif methodName.startswith("self."): methodName = methodName.replace( "self.", "self.frame.ids." + stack[-1].id + ".") ''' print(dent + "using method `{}`" "".format(methodName)) ''' elif methodName.startswith("app."): methodName = methodName.replace("app.", "KT.APP.") ''' print(dent + "using method `{}`" "".format(methodName)) ''' else: raise NotImplementedError( "The object in the method call is not" " implemented: {}".format(methodName)) ''' print(dent + "trying to add {} to {}" "".format(kvc.lvalue.value, type(stack[-1]).__name__)) ''' if kvc.lvalue.value == 'on_press': stack[-1].bind(on_press=eval(methodName)) else: raise NotImplementedError( "The `{}` handler is not implemented." "".format(kvc.lvalue.value)) elif kvc.rvalue.className is not None: if not hasattr(stack[-1], kvc.lvalue.value): warn(dent + "Line {} of {} has a KV value `{}`" " for {}, which is not implemented, near" " `{}`".format(lineN, fn, kvc.rvalue, kvc.lvalue, line.strip())) key = kvc.lvalue.value value = kvc.rvalue.value # stack[-1].__dict__[key] = value # ^ Using dict overwrites a property with a plain # variable! setattr(stack[-1], key, value) else: key = kvc.lvalue.value value = kvc.rvalue.value # A literal None implies that the parser could not # detect the type. if not hasattr(stack[-1], kvc.lvalue.value): warn(dent + "Line {} of {} has an rvalue" " that will be taken literally: `{}` near" " `{}`".format(lineN, fn, kvc.rvalue, line.strip())) # stack[-1].__dict__[key] = value # ^ Using dict overwrites a property with a plain # variable! setattr(stack[-1], key, value) # TODO: implement KV rules such as: # right: self.parent.right # right: layout.right # where id of parent is layout if ThisClass is not None: if len(stack) == 0: deeperO = self.frame # ^ Make the child objects get appended to the frame # (root widget) else: ''' if thisOr is not None: deeperO = ThisClass( tkinterParent=stack[-1], orientation=thisOr, ) else: ''' deeperO = ThisClass(tkinterParent=stack[-1]) ''' print(dent + "tkinterParent is {}" "".format(stack[-1])) ''' ''' msgFmt = (dent + "adding {}" " to {} {} with orientation {}.") print( msgFmt.format( kvc.lvalue.value, type(stack[-1]).__name__, stack[-1].id, stack[-1].orientation, ) ) ''' if not hasattr(stack[-1], 'add_widget'): exFmt = (dent + "Line {} of {} has a `{}`" " inside of a `{}` near `{}`.") raise SyntaxError( exFmt.format(lineN, fn, kvc.lvalue.value, type(stack[-1]).__name__, line.strip())) stack[-1].add_widget(deeperO) # if thisId is not None: # self.frame.ids[thisId] = deeperO stack.append(deeperO) thisTabSize = len(dent) - len("".join(tabs)) ''' if thisTabSize < 1: exFmt = (dent + "[kivy-tkinter app] failed to" " correctly add to the indent on line {} " " of {} near `{}`. This is a failure in" " kivy-tkinter itself. thisTabSize={}," " dent='{}', tabs={}") raise RuntimeError( exFmt.format(lineN, fn, line.strip(), thisTabSize, dent, tabs) ) ''' if thisTabSize > 0: tabs.append(dent[-thisTabSize:])
def run(self): self.parser = Parser(content=Builder._loadedStr) self._build() KT.APP.mainloop()
def change_kv(self, *largs): '''Called when the update button is clicked. Needs to update the interface for the currently active kv widget, if there is one based on the kv file the user entered. If there is an error in their kv syntax, show a nice popup.''' txt = self.language_box.text kv_container = self.screen_manager.current_screen.children[0] try: parser = Parser(content=txt) kv_container.clear_widgets() widget = Factory.get(parser.root.name)() Builder._apply_rule(widget, parser.root, parser.root) kv_container.add_widget(widget) name = self.ids.ui_name.text print(f'The whatever name is {name}') if name == 'Untitled*': m = ModalView(size_hint=[.6, .7]) box = BoxLayout(orientation='vertical') m.add_widget(box) # Function to get user's current home directory from os.path import expanduser users_home = expanduser('~') user_home_dir = os.path.join(users_home, 'Desktop') try: os.mkdir(os.path.join(user_home_dir, 'KivyEditor')) user_home_dir = os.path.join(user_home_dir, 'KivyEditor') except FileExistsError: # user_home_dir = os.path.join(user_home_dir, 'KivyEditor') pass name_box = BoxLayout(size_hint_y=.1) fc = FileChooserListView(size_hint_y=.9, filters=['*kv'], rootpath=user_home_dir) box.add_widget(name_box) box.add_widget(fc) tinput = TextInput(multiline=False, size_hint_x=.8) submit = Button(text='Save', background_color=[1, 1, 1, 1], background_normal='', color=[0, 0, 0, 1], size_hint_x=.2) tinput.bind(on_text_validate=lambda x: self.update_name( os.path.join(fc.path, tinput.text), m)) submit.bind(on_release=lambda x: self.update_name( os.path.join(fc.path, tinput.text), m)) name_box.add_widget(tinput) name_box.add_widget(submit) m.open() else: save_path = name dump = pickle.dumps(save_path) all = self.db.get_kvs() kvs = [x[0] for x in all] if dump not in kvs: self.db.add_kv(dump) with open(save_path, 'w') as f: f.write(txt) except (SyntaxError, ParserException) as e: self.show_error(e) except Exception as e: self.show_error(e)
DS_ROOT = os.path.dirname(__file__) DS_KVS = os.path.join(DS_ROOT,'ds_kvs') DS_CLASSES = [c[:-3] for c in os.listdir(DS_KVS) class Root(FloatLayout): screen_manager = ObjectProperty(None) child = ObjectProperty(None) def change_kv(self,*largs): child = self.screen_manager.current_screen.children[0] with open(child.kv_file, 'rb') as file: text = file.read().decode('utf8') kv_container = self.screen_manager.current_screen try: parser = Parser(content = txt) kv_container.clear_widgets() widget = Factory.get(parser.root.name)() Builder._apply_rule(widget,parser.root,parser.root) kv_container.add_widget(widget) except (SyntaxError, ParserException) as e: self.show_error(e) except Exception as e: self.show_error(e) class DS(App): pass Factory.register('Root', cls=Root) if __name__=='__main__':