From 08988820818c7f4a9a337fab6783685ba187dc69 Mon Sep 17 00:00:00 2001 From: Billy Date: Tue, 25 Jul 2023 20:43:28 +0800 Subject: [PATCH 1/3] feat: Buttons for editors (editor bar) --- biscuit/core/components/editors/editor.py | 5 ++++- biscuit/core/components/games/__init__.py | 9 ++++----- biscuit/core/components/games/game.py | 8 +++++--- biscuit/core/layout/base/content/editors/__init__.py | 9 +++++---- biscuit/core/layout/base/content/editors/editorsbar.py | 10 +++++----- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/biscuit/core/components/editors/editor.py b/biscuit/core/components/editors/editor.py index f90b5e62..8c3d9c62 100644 --- a/biscuit/core/components/editors/editor.py +++ b/biscuit/core/components/editors/editor.py @@ -1,4 +1,4 @@ -from biscuit.core.components.utils import Frame +from biscuit.core.components.utils import Frame, IconButton class BaseEditor(Frame): @@ -20,5 +20,8 @@ def __init__(self, master, path=None, exists=None, editable=True, *args, **kwarg self.__buttons__ = () + def create_buttons(self, editorbar): + self.__buttons__ = [IconButton(editorbar, *button) for button in self.__buttons__] + def save(self, *_): ... diff --git a/biscuit/core/components/games/__init__.py b/biscuit/core/components/games/__init__.py index 2c6c10bf..d9c7bd8e 100644 --- a/biscuit/core/components/games/__init__.py +++ b/biscuit/core/components/games/__init__.py @@ -30,7 +30,7 @@ def register_game(game): class Game(Frame): """ - responsible for picking the right game + Responsible for picking the right game name - name of game to opened """ @@ -43,12 +43,11 @@ def __init__(self, master, name, *args, **kwargs): self.exists = False self.diff = False self.showpath = False - self.content = None self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) - self.game = get_game(name=name)(self) - self.game.grid(row=0, column=0, sticky=tk.NSEW) + self.content = get_game(name=name)(self) + self.content.grid(row=0, column=0, sticky=tk.NSEW) def focus(self): - self.game.focus_get() + self.content.focus_get() diff --git a/biscuit/core/components/games/game.py b/biscuit/core/components/games/game.py index 783088dd..64eb08eb 100644 --- a/biscuit/core/components/games/game.py +++ b/biscuit/core/components/games/game.py @@ -1,6 +1,6 @@ import tkinter as tk -from biscuit.core.components.utils import Frame +from biscuit.core.components.utils import Frame, IconButton class BaseGame(Frame): @@ -15,11 +15,13 @@ def __init__(self, master, path=None, *args, **kwargs): self.exists = False self.showpath = False - self.content = None self.diff = False self.editable = False - self.__buttons__ = () + self.__buttons__ = (('refresh', self.reload), ) + + def create_buttons(self, editorbar): + self.__buttons__ = [IconButton(editorbar, *button) for button in self.__buttons__] def reload(self, *_): ... diff --git a/biscuit/core/layout/base/content/editors/__init__.py b/biscuit/core/layout/base/content/editors/__init__.py index 1da6bc57..7bc165e4 100644 --- a/biscuit/core/layout/base/content/editors/__init__.py +++ b/biscuit/core/layout/base/content/editors/__init__.py @@ -1,13 +1,12 @@ import tkinter as tk - -from .editorsbar import Editorsbar -from .empty import Empty - from biscuit.core.components.editors import Editor from biscuit.core.components.games import Game from biscuit.core.components.utils import Frame +from .editorsbar import Editorsbar +from .empty import Empty + class EditorsPane(Frame): """ @@ -54,6 +53,8 @@ def add_editors(self, editors): def add_editor(self, editor): "Appends a editor to list. Create a tab." self.editors.append(editor) + if editor.content: + editor.content.create_buttons(self.editorsbar.container) self.tabs.add_tab(editor) def delete_all_editors(self): diff --git a/biscuit/core/layout/base/content/editors/editorsbar.py b/biscuit/core/layout/base/content/editors/editorsbar.py index c520c187..3bb19a58 100644 --- a/biscuit/core/layout/base/content/editors/editorsbar.py +++ b/biscuit/core/layout/base/content/editors/editorsbar.py @@ -1,8 +1,9 @@ import tkinter as tk from tkinter.constants import * +from biscuit.core.components.utils import Frame, IconButton + from .tabs import Tabs -from biscuit.core.components.utils import IconButton, Frame class Editorsbar(Frame): @@ -16,12 +17,11 @@ def __init__(self, master, *args, **kwargs): self.buttons = [] self.default_buttons = (('ellipsis',),) - # TODO like panelbar, add __buttons__ to BaseEditor - self.buttonframe = Frame(self) - self.buttonframe.pack(fill=BOTH, side=RIGHT, pady=5, padx=10) + self.container = Frame(self, **self.base.theme.layout.base.content.editors.bar) + self.container.pack(fill=BOTH, side=RIGHT, padx=(0, 10)) for button in self.default_buttons: - IconButton(self.buttonframe, *button).pack(side=RIGHT) + IconButton(self.container, *button).pack(side=RIGHT) def add_buttons(self, buttons): for button in buttons: From 06233b2087278d1aaacc99a3bb3c6f09a80642fb Mon Sep 17 00:00:00 2001 From: Billy Date: Wed, 26 Jul 2023 18:29:18 +0800 Subject: [PATCH 2/3] test: codefolding demo --- .../editors/texteditor/codefolding_demo.py | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 biscuit/core/components/editors/texteditor/codefolding_demo.py diff --git a/biscuit/core/components/editors/texteditor/codefolding_demo.py b/biscuit/core/components/editors/texteditor/codefolding_demo.py new file mode 100644 index 00000000..3d934a09 --- /dev/null +++ b/biscuit/core/components/editors/texteditor/codefolding_demo.py @@ -0,0 +1,122 @@ +import tkinter as tk +from tkinter import INSERT, NE, Canvas, Menubutton +from tkinter.font import Font + + +class LineNumbers(Canvas): + def __init__(self, master, text=None, *args, **kwargs): + super().__init__(master, *args, **kwargs) + self.config(width=50, bd=0, highlightthickness=0) + self.text = text + self.text.config(bd=0, highlightthickness=0) + self.text.tag_config("sel", background="#48484f", foreground="#e1e1e6") + self.text.bind("", self.redraw) + self.text.bind("<>", self.redraw) + + def attach(self, text): + self.text = text + + def set_bar_width(self, width): + self.configure(width=width) + + def get_indentation_level(self, line): + """Get the indentation level of a given line.""" + return len(line) - len(line.lstrip()) + + def redraw(self, *_): + self.delete(tk.ALL) + + prev_indent = 0 + i = self.text.index("@0,0") + while True: + dline = self.text.dlineinfo(i) + if dline is None: + break + + y = dline[1] + linenum = str(i).split(".")[0] + + # Get the text content of the current line + line_content = self.text.get(f"{linenum}.0", f"{linenum}.end") + current_indent = self.get_indentation_level(line_content) + + # Determine if the current line has more indentation than the previous line + if current_indent > prev_indent: + line_num_with_indent = f"+ {linenum}" + elif current_indent < prev_indent: + line_num_with_indent = f"- {linenum}" + else: + line_num_with_indent = linenum + + # to highlight the current line + curline = self.text.dlineinfo(tk.INSERT) + cur_y = curline[1] if curline else None + + if not cur_y: + i = self.text.index(f"{i}+1line") + continue + + if y == cur_y: + self.create_text(40, y, anchor=tk.NE, text=line_num_with_indent, font=("Consolas", 14), fill="#83838f", tag=i) + else: + self.create_text(40, y, anchor=tk.NE, text=line_num_with_indent, font=("Consolas", 14), fill="#525259", tag=i) + + + # Update the previous indentation level + prev_indent = current_indent + i = self.text.index(f"{i}+1line") + +class Text(tk.Text): + def __init__(self, master=None, **kw): + super().__init__(master, **kw) + self.mark_set('input', 'insert') + self.mark_gravity('input', 'left') + + self._orig = self._w + "_orig" + self.tk.call("rename", self._w, self._orig) + self.tk.createcommand(self._w, self._proxy) + + def _proxy(self, *args): + if args[0] == 'get' and (args[1] == tk.SEL_FIRST and args[2] == tk.SEL_LAST) and not self.tag_ranges(tk.SEL): + return + if args[0] == 'delete' and (args[1] == tk.SEL_FIRST and args[2] == tk.SEL_LAST) and not self.tag_ranges(tk.SEL): + return + + cmd = (self._orig,) + args + result = self.tk.call(cmd) + + if (args[0] in ("insert", "replace", "delete") or args[0:3] == ("mark", "set", "insert") + or args[0:2] == ("xview", "moveto") or args[0:2] == ("yview", "moveto") + or args[0:2] == ("xview", "scroll") or args[0:2] == ("yview", "scroll")): + self.event_generate("<>", when="tail") + + return result + + +class ExampleApp: + def __init__(self, root): + self.font = ("Consolas", 14) + + self.text_widget = Text(root, wrap=tk.NONE, font=self.font, bg="#2e2e32", fg="#e1e1e6") + self.line_numbers = LineNumbers(root, text=self.text_widget, bg="#2e2e32") + + self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) + self.text_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + + # Sample text with indentation for testing code folding + sample_code = """\ +def foo(): + print("Hello,") + print("World!") + if True: + print("This is a nested block.") + print("Indented lines are foldable.") +print("Code folding based on indentation.") +""" + self.text_widget.insert(tk.END, sample_code) + self.line_numbers.redraw() + +if __name__ == "__main__": + root = tk.Tk() + app = ExampleApp(root) + root.mainloop() From ca1ab38fe1ef01b96acb0f5fd22c3c9582613fc3 Mon Sep 17 00:00:00 2001 From: Billy Date: Wed, 26 Jul 2023 18:31:53 +0800 Subject: [PATCH 3/3] fix: ModuleNotFoundError: No module named `biscuit.core.components.games.stackengineer'` --- .../core/components/games/{StackEngineer.py => stackengineer.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename biscuit/core/components/games/{StackEngineer.py => stackengineer.py} (100%) diff --git a/biscuit/core/components/games/StackEngineer.py b/biscuit/core/components/games/stackengineer.py similarity index 100% rename from biscuit/core/components/games/StackEngineer.py rename to biscuit/core/components/games/stackengineer.py