Skip to content

Commit

Permalink
Merge pull request #249 from billyeatcookies/open-editors
Browse files Browse the repository at this point in the history
Open editors List
  • Loading branch information
tomlin7 authored Mar 18, 2024
2 parents 176e27d + 594a63b commit a400c9e
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 16 deletions.
1 change: 1 addition & 0 deletions biscuit/core/components/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .buttonsentry import ButtonsEntry
from .callername import caller_name
from .canvas import Canvas
from .closelistitem import CloseListItem
from .codicon import get_codicon
from .colorizer import colorize
from .entry import Entry
Expand Down
90 changes: 90 additions & 0 deletions biscuit/core/components/utils/closelistitem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import tkinter as tk

from biscuit.core.components.utils.iconbutton import IconButton

from .codicon import get_codicon
from .frame import Frame
from .icon import Icon


class CloseListItem(Frame):
"""
A varient of IconLabelButton that has a close icon on the right side of the button.
"""
def __init__(self, master, text=None, icon=None, function=lambda *_: None, closefn=lambda *_:None, iconside=tk.LEFT, padx=5, pady=1, *args, **kwargs) -> None:
super().__init__(master, padx=padx, pady=pady, *args, **kwargs)
self.function = function
self.closefn = closefn

self.bg, self.fg, self.hbg, self.hfg = self.base.theme.utils.iconlabelbutton.values()
self.config(bg=self.bg)
self.text = text
self.icon = icon

if icon:
self.icon_label = tk.Label(self, text=get_codicon(self.icon), anchor=tk.CENTER,
bg=self.bg, fg=self.fg, font=("codicon", 14))
self.icon_label.pack(side=iconside, fill=tk.BOTH, expand=True)

if text:
self.text_label = tk.Label(self, text=self.text, anchor=tk.CENTER, pady=2,
bg=self.bg, fg=self.fg, font=("Segoe UI", 10))
self.text_label.pack(side=iconside, fill=tk.BOTH, expand=True)

self.close_btn = IconButton(self, 'close', self.closefn)
self.close_btn.config(bg=self.bg, fg=self.fg)
self.close_btn.pack(side=tk.RIGHT, fill=tk.BOTH)

self.config_bindings()
self.visible = False

def config_bindings(self) -> None:
self.bind("<Enter>", self.on_enter)
self.bind("<Leave>", self.on_leave)

self.bind("<Button-1>", self.on_click)
if self.text:
self.text_label.bind("<Button-1>", self.on_click)
if self.icon:
self.icon_label.bind("<Button-1>", self.on_click)

def on_enter(self, *_) -> None:
self.config(bg=self.hbg)
if self.text:
self.text_label.config(bg=self.hbg, fg=self.hfg)
if self.icon:
self.icon_label.config(bg=self.hbg, fg=self.hfg)
self.close_btn.config(bg=self.hbg, fg=self.hfg)

def on_leave(self, *_) -> None:
self.config(bg=self.bg)
if self.text:
self.text_label.config(bg=self.bg, fg=self.fg)
if self.icon:
self.icon_label.config(bg=self.bg, fg=self.fg)
self.close_btn.config(bg=self.bg, fg=self.fg)

def on_click(self, *_) -> None:
self.function()

def change_text(self, text) -> None:
self.text_label.config(text=text)

def change_icon(self, icon) -> None:
self.icon_label.config(text=icon)

def set_pack_data(self, **kwargs) -> None:
self.pack_data = kwargs

def get_pack_data(self):
return self.pack_data

def show(self) -> None:
if not self.visible:
self.visible = True
self.pack(**self.get_pack_data())

def hide(self) -> None:
if self.visible:
self.visible = False
self.pack_forget()
14 changes: 13 additions & 1 deletion biscuit/core/components/views/sidebar/explorer/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import os
import tkinter as tk

from biscuit.core.components.floating.palette import ActionSet

from ..sidebarview import SidebarView
from .directorytree import DirectoryTree
from .menu import ExplorerMenu
from .open_editors import OpenEditors


class Explorer(SidebarView):
Expand All @@ -15,11 +17,14 @@ def __init__(self, master, *args, **kwargs) -> None:
self.name = 'Explorer'

self.menu = ExplorerMenu(self, 'files')
self.menu.add_item("Open Editors", self.base.events.show_active_editors)
self.menu.add_item("Open Editors", self.toggle_active_editors)
self.menu.add_separator(10)
self.menu.add_item("Search", self.base.events.show_file_search_palette)
self.add_button('ellipsis', self.menu.show)

self.active_editors_visible = True
self.open_editors = OpenEditors(self)
self.open_editors.pack(fill=tk.X)
self.directory = DirectoryTree(self, observe_changes=True)
self.add_widget(self.directory)

Expand All @@ -40,6 +45,13 @@ def __init__(self, master, *args, **kwargs) -> None:
)
self.base.palette.register_actionset(lambda: self.rename_actionset)

def toggle_active_editors(self):
if self.active_editors_visible:
self.open_editors.pack_forget()
else:
self.open_editors.pack(fill=tk.X, before=self.directory)
self.active_editors_visible = not self.active_editors_visible

def get_actionset(self, term: str) -> ActionSet:
self.filesearch_actionset.update(self.filesearch(term))
return self.filesearch_actionset
Expand Down
54 changes: 54 additions & 0 deletions biscuit/core/components/views/sidebar/explorer/open_editors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import tkinter as tk

from biscuit.core.components.floating.palette.actionset import ActionSet
from biscuit.core.components.utils import CloseListItem, Menubutton

from ..item import SidebarViewItem


class OpenEditors(SidebarViewItem):
def __init__(self, master, startpath=None, itembar=True, *args, **kwargs) -> None:
self.title = 'Open Editors'
self.__buttons__ = (('new-file', lambda: self.base.palette.show('newfile:')),)
super().__init__(master, itembar, *args, **kwargs)
self.path = startpath
self.nodes = {}

def refresh(self):
if not self.nodes:
self.itembar.hide_content()
else:
self.itembar.show_content()
self.update()

def add_item(self, editor):
temp = CloseListItem(self.content, editor.filename, function=lambda p=editor.path: self.openfile(p),
closefn=lambda p=editor.path: self.closefile(p), padx=10)
temp.text_label.config(anchor=tk.W)
temp.pack(fill=tk.X, expand=True)

self.nodes[editor.path] = temp
self.refresh()

def remove_item(self, editor):
e = self.nodes.pop(editor.path)
e.pack_forget()
e.destroy()
self.refresh()

def set_active(self, editor):
# TODO: set highlight, clear highlight on others
...

def clear(self):
for node in self.nodes.values():
node.destroy()
self.nodes = {}
self.refresh()

def openfile(self, path) -> None:
self.base.editorsmanager.tabs.switch_tabs(path)

def closefile(self, path) -> None:
e = self.base.editorsmanager.close_editor_by_path(path)
self.base.editorsmanager.tabs.close_tab_helper(e)
2 changes: 1 addition & 1 deletion biscuit/core/components/views/sidebar/sidebarview.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class SidebarView(View):

def __init__(self, master, *args, **kwargs) -> None:
super().__init__(master, *args, **kwargs)
self.__buttons__: list[tuple(str, typing.Callable)] = []
self.__buttons__: list[tuple(str, typing.Callable)] = [] # type: ignore
self.__icon__ = 'preview'
self.name = "View"
self.__name__ = self.__class__.__name__
Expand Down
24 changes: 13 additions & 11 deletions biscuit/core/layout/base/content/editors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
"""
Holds the editors and provides an interface to manage the editor tabs.
+---------------------------------+
| File1.txt | File2.py | |
+---------------------------------+
| \ \ \ \ \ \ \ |
| \ \ \ \ \ \ \|
| \ \ \ \ \ \ |
| \ \ \ \ \ \ |
|\ \ \ \ \ \ \ |
+---------------------------------+
"""
from __future__ import annotations

Expand Down Expand Up @@ -88,6 +78,7 @@ def add_editor(self, editor: Union[Editor,BaseEditor]) -> Editor | BaseEditor:
if editor.content:
editor.content.create_buttons(self.editorsbar.container)
self.tabs.add_tab(editor)
self.base.explorer.open_editors.add_item(editor)
self.refresh()
return editor

Expand All @@ -99,6 +90,7 @@ def delete_all_editors(self) -> None:
self.editorsbar.clear()
self.tabs.clear_all_tabs()
self.active_editors.clear()
self.base.explorer.open_editors.clear()
self.refresh()

def reopen_active_editor(self) -> None:
Expand Down Expand Up @@ -139,17 +131,25 @@ def open_game(self, name: str) -> None:
def close_editor(self, editor: Editor) -> None:
"removes an editor, keeping it in cache."
self.active_editors.remove(editor)
editor.grid_forget()

if editor.content and editor.content.editable:
self.base.language_server_manager.tab_closed(editor.content.text)

# not keeping diff/games in cache
if not editor.diff and editor.content:
self.closed_editors[editor.path] = editor
self.closed_editors[editor.path] = editor
else:
editor.destroy()
self.base.explorer.open_editors.remove_item(editor)
self.refresh()

def close_editor_by_path(self, path: str) -> None:
"removes an editor by path, keeping it in cache."
e = self.get_editor(path)
self.close_editor(e)
return e

def get_editor(self, path: str) -> Editor:
"Get editor by path"
for editor in self.active_editors:
Expand All @@ -168,13 +168,15 @@ def delete_editor(self, editor: Editor) -> None:
self.closed_editors.remove(editor)

editor.destroy()
self.base.explorer.open_editors.remove_item(editor)
self.refresh()

def set_active_editor(self, editor: Editor) -> Editor:
"set an existing editor to currently shown one"
for tab in self.tabs.tabs:
if tab.editor == editor:
self.tabs.set_active_tab(tab)
self.base.explorer.open_editors.set_active(editor)

return editor

Expand Down
13 changes: 10 additions & 3 deletions biscuit/core/layout/base/content/editors/tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,14 @@ def close_active_tab(self) -> None:
self.close_tab(self.active_tab)

def close_tab(self, tab: Tab) -> None:
tab.editor.grid_forget()
tab.destroy()

try:
i = self.tabs.index(tab)
except ValueError:
# most probably in case of diff editors, not handled
return

self.tabs.remove(tab)
tab.destroy()
self.master.master.close_editor(tab.editor)

if self.tabs:
Expand All @@ -53,6 +51,15 @@ def close_tab(self, tab: Tab) -> None:
self.active_tab = None
self.master.master.refresh()

def close_tab_helper(self, editor: str) -> None:
for tab in self.tabs:
if tab.editor == editor:
try:
self.tabs.remove(tab)
tab.destroy()
except ValueError:
return

def delete_tab(self, editor):
for tab in self.tabs:
if tab.editor == editor:
Expand Down

0 comments on commit a400c9e

Please sign in to comment.