Skip to content

Commit

Permalink
feat: Custom list widget for open editors
Browse files Browse the repository at this point in the history
  • Loading branch information
tomlin7 committed Mar 18, 2024
1 parent 3f3c6ca commit d0369a1
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 40 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()
67 changes: 27 additions & 40 deletions biscuit/core/components/views/sidebar/explorer/open_editors.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import os
import platform
import shutil
import subprocess
import threading
import tkinter as tk

import pyperclip

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

from ..item import SidebarViewItem

Expand All @@ -18,49 +11,43 @@ def __init__(self, master, startpath=None, itembar=True, *args, **kwargs) -> Non
self.title = 'Open Editors'
self.__buttons__ = (('new-file', lambda: self.base.palette.show('newfile:')),)
super().__init__(master, itembar, *args, **kwargs)

self.tree = Tree(self.content, startpath, singleclick=self.openfile, *args, **kwargs)
self.tree.bind("<Configure>", self.adjust_frame_size)
self.tree.grid(row=0, column=0, sticky=tk.NSEW)
self.tree.bind("<<Open>>", self.openfile)

self.path = startpath
self.nodes = {}

def adjust_frame_size(self, *_):
if items := self.tree.get_children():
frame_height = len(items) * 25 + 5
def refresh(self):
if not self.nodes:
self.itembar.hide_content()
else:
frame_height = 1
self.tree.config(height=frame_height)
self.itembar.show_content()
self.update()

def add_item(self, editor):
self.tree.insert('', 'end', text=editor.filename, values=(editor.path, 'file'))
self.adjust_frame_size()
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):
for child in self.tree.get_children():
if self.tree.item_fullpath(child) == editor.path:
self.tree.delete(child)
self.adjust_frame_size()
if not len(self.base.editorsmanager.active_editors):
self.disable()
return
e = self.nodes.pop(editor.path)
e.pack_forget()
e.destroy()
self.refresh()

def set_active(self, editor):
for child in self.tree.get_children():
if self.tree.item_fullpath(child) == editor.path:
self.tree.tree.selection_set(child)
self.adjust_frame_size()
return
# TODO: set highlight, clear highlight on others
...

def clear(self):
self.tree.delete(*self.tree.get_children())
self.adjust_frame_size()
for node in self.nodes.values():
node.destroy()
self.nodes = {}

def openfile(self, _) -> None:
if self.tree.selected_type() != 'file':
return
def openfile(self, path) -> None:
self.base.editorsmanager.set_active_editor_by_path(path)

path = self.tree.selected_path()
self.base.open_editor(path)
def closefile(self, path) -> None:
self.base.editorsmanager.close_editor_by_path(path)

4 changes: 4 additions & 0 deletions biscuit/core/layout/base/content/editors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ def close_editor(self, editor: Editor) -> None:
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."
self.close_editor(self.get_editor(path))

def get_editor(self, path: str) -> Editor:
"Get editor by path"
for editor in self.active_editors:
Expand Down

0 comments on commit d0369a1

Please sign in to comment.