Skip to content

Commit 88b6888

Browse files
authored
Rewritten Tab System (#44)
1 parent d8f46bc commit 88b6888

File tree

3 files changed

+97
-123
lines changed

3 files changed

+97
-123
lines changed

src/main.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
import tkinter, ntkutils, pygments
44
from pathlib import Path
5+
from tkinter import ttk
56

67
import config, tabmanager
78
import settings.applysettings as a
89
import settings.UI as settingsui
9-
import generatesize as size
10+
import generatesize as size
1011
import vars as v
1112
import mdpreview as md
1213
from widgets.textwidget import ScrollText, ScrollCode
@@ -21,15 +22,15 @@
2122
root.update_idletasks()
2223
ntkutils.placeappincenter(root)
2324

24-
root.update()
25+
root.update_idletasks()
2526

2627
closeimg = tkinter.PhotoImage(file=Path("assets/close_light.png"))
2728
closeimg2 = tkinter.PhotoImage(file=Path("assets/close_dark.png"))
2829

2930
def settings_():
3031
settingsui.build()
3132
root.wait_window(settingsui.settings)
32-
33+
3334
if settingsui.save == True:
3435
v.cfg = settingsui.cfg
3536
a.applysettings()
@@ -38,9 +39,8 @@ def closepreview():
3839
md.close()
3940
textwidget.text.bind("<KeyPress>", refreshtitle)
4041

41-
tabbar = tkinter.Frame(root, height="75", bg="#202020")
42-
tabbar.pack(fill="both")
43-
tabbar.pack_propagate(False)
42+
notebook = ttk.Notebook(root)
43+
notebook.pack(fill="both", expand=True)
4444

4545
if cfg["linenumbers"] and not cfg["syntax-highlighting"]:
4646
textwidget = ScrollText(root, width=100, borderwidth=0, height=root.winfo_height() - 125)
@@ -61,7 +61,7 @@ def closepreview():
6161

6262

6363
footer = tkinter.Frame(root, width=root.winfo_width(), height=25)
64-
footer.update()
64+
footer.update_idletasks()
6565
footer.place(y=root.winfo_height() - 25)
6666
footer.pack_propagate(False)
6767

@@ -107,17 +107,19 @@ def refreshtitle(e):
107107
v.root = root
108108
v.textwidget = textwidget
109109
v.filedir = filedir
110-
v.tabbar = tabbar
110+
v.tabbar = notebook
111111
v.footer = footer
112112
v.closeimg = closeimg
113113
v.closeimg2 = closeimg2
114114

115115
a.applysettings()
116116

117-
tabmanager.cbuttons[0].place(x=71) # The first cbutton has to be placed like that because it seems like the winfo functions return wrong values the first time
118-
tabmanager.buildtabs()
117+
notebook.add(tkinter.Frame(), text=tabmanager.tabs[0][0], image=closeimg, compound="right")
118+
119+
120+
121+
notebook.bind('<ButtonRelease-1>', tabmanager.click, add="+") # Bind Left mouse button to write content of selected tab into the text widget
119122

120123
root.update_idletasks()
121124
root.deiconify()
122-
123125
root.mainloop()

src/settings/applysettings.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ def applysettings():
99
else: sv_ttk.set_theme(v.cfg["theme"].lower())
1010

1111
if v.cfg["theme"] == "Dark" or (v.cfg["theme"] == "System" and darkdetect.isDark()):
12-
v.tabbar.configure(bg="#202020")
1312
v.footer.configure(bg="#202020")
14-
1513
v.closeimg.configure(file="assets/close_light.png")
1614
v.closeimg2.configure(file="assets/close_dark.png")
1715

@@ -23,8 +21,6 @@ def applysettings():
2321
try: v.textwidget.numberLines.mode = "dark"
2422
except AttributeError: pass
2523
else:
26-
v.tabbar.configure(bg="#f3f3f3")
27-
2824
v.footer.configure(bg="#f3f3f3")
2925
v.closeimg.configure(file="assets/close_dark.png")
3026
v.closeimg2.configure(file="assets/close_light.png")
@@ -57,4 +53,4 @@ def applysettings():
5753

5854
try: v.textwidget.numberLines.redraw()
5955
except AttributeError: pass
60-
tabmanager.buildtabs()
56+
#tabmanager.buildtabs()

src/tabmanager.py

Lines changed: 83 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,161 +1,137 @@
1+
from __future__ import annotations
2+
13
import ntkutils, tkinter
2-
from tkinter import ttk, filedialog
4+
from tkinter import PhotoImage, ttk, filedialog, Event
35
from pygments.lexers import get_lexer_for_filename
46
import pygments.lexers
7+
import pyautogui
58

69
import vars as v
710
import filetype as f
811

9-
tabbuttons = []
10-
cbuttons = []
1112
tabs = [["Untitled", "", "unsaved", "*"]]
1213

13-
14-
def update(file):
14+
def updatetab(file):
1515
tabs[v.tabselected][0] = file.name.split("/")[-1]
1616
tabs[v.tabselected][2] = file.name
17-
tabs[v.tabselected][3] = ""
17+
tabs[v.tabselected][3] = ""
1818

1919
def updatetitle(): v.root.title("txt2 - {} {}".format(tabs[v.tabselected][0], tabs[v.tabselected][3]))
2020

21-
def _open(x):
21+
def new():
2222
tabs[v.tabselected][1] = v.textwidget.text.get("1.0", "end")
23-
v.tabselected = tabbuttons.index(x)
24-
2523
v.textwidget.text.delete("1.0", "end")
26-
v.textwidget.text.insert("1.0", tabs[v.tabselected][1])
27-
v.textwidget.text.delete("end-1c", "end")
28-
29-
v.filedir.configure(text=tabs[v.tabselected][2])
24+
tabs.append(["Untitled", "", "unsaved", "*"])
25+
v.filedir.configure(text="unsaved")
26+
v.tabselected = v.tabselected + 1
3027

31-
buildtabs()
32-
updatetitle()
33-
setlexer()
34-
35-
def close(e, x):
36-
if not v.tabselected == cbuttons.index(x):
37-
tabs.pop(cbuttons.index(x))
38-
if cbuttons.index(x) < v.tabselected: v.tabselected = v.tabselected - 1
39-
40-
buildtabs()
41-
else:
42-
if len(cbuttons) > 1:
43-
tabs.pop(v.tabselected)
44-
v.tabselected = v.tabselected - 1
28+
try: v.textwidget.redraw()
29+
except: pass
4530

46-
buildtabs()
31+
v.tabbar.add(tkinter.Frame(), text=tabs[v.tabselected][0], image=v.closeimg, compound="right")
32+
v.tabbar.select(v.tabselected)
4733

48-
v.textwidget.text.delete("1.0", "end")
49-
v.textwidget.text.insert("1.0", tabs[v.tabselected][1])
50-
updatetitle()
51-
v.filedir.configure(text=tabs[v.tabselected][2])
52-
else:
53-
v.root.destroy()
54-
55-
def new():
56-
if not len(tabs) == 10:
57-
tabs[v.tabselected][1] = v.textwidget.text.get("1.0", "end")
58-
v.textwidget.text.delete("1.0", "end")
59-
tabs.append(["Untitled", "", "unsaved", "*"])
60-
v.filedir.configure(text="unsaved")
61-
v.tabselected = len(tabbuttons)
62-
63-
buildtabs()
64-
updatetitle()
65-
if v.cfg["syntax-highlighting"]: v.textwidget.text._set_lexer(pygments.lexers.TextLexer)
66-
else: print("Tab limit reached")
34+
updatetitle()
35+
if v.cfg["syntax-highlighting"]: v.textwidget.text._set_lexer(pygments.lexers.TextLexer)
6736

6837
def save(e="", saveas=False):
6938
if tabs[v.tabselected][2] == "unsaved" or saveas:
7039
file = filedialog.asksaveasfile()
7140
if file == None: return
7241
else: file = open(tabs[v.tabselected][2], "w")
73-
42+
7443
if file != None:
7544
file.write(v.textwidget.text.get("1.0", "end"))
7645

77-
update(file)
46+
updatetab(file)
7847
v.filedir.configure(text=file.name)
7948

8049
file.close()
8150

82-
buildtabs()
8351
updatetitle()
8452
setlexer()
8553

8654
def openfile(e=""):
87-
if not len(tabs) == 10:
88-
file = filedialog.askopenfile()
89-
content = file.read()
90-
91-
if not v.textwidget.text.get("1.0", "end").replace("\n", "") == "": new()
92-
93-
update(file)
55+
file = filedialog.askopenfile()
56+
content = file.read()
9457

95-
file.close()
96-
97-
v.textwidget.text.insert("1.0", content)
98-
v.filedir.configure(text=tabs[v.tabselected][2])
99-
100-
buildtabs()
101-
updatetitle()
102-
setlexer()
103-
else:
104-
print("Tab limit reached")
58+
if v.textwidget.text.get("1.0", "end").replace("\n", "") != "":
59+
new()
10560

106-
def changetype():
107-
if tabs[v.tabselected][2] == "unsaved": save()
108-
else:
109-
result = f.get(tabs[v.tabselected][2])
110-
tabs[v.tabselected][2] = result
111-
tabs[v.tabselected][0] = result.split("/")[-1]
112-
v.filedir.configure(text=result)
61+
updatetab(file)
11362

114-
buildtabs()
115-
updatetitle()
116-
setlexer()
63+
file.close()
11764

118-
def on_enters(e, x): x.configure(bg=v.selected_hover)
119-
def on_leaves(e, x): x.configure(bg=v.selected)
120-
def on_enter(e, x): x.configure(bg=v.normal_hover)
121-
def on_leave(e, x): x.configure(bg=v.normal)
65+
v.tabbar.tab(v.tabselected, text=tabs[v.tabselected][0], image=v.closeimg, compound="right")
66+
v.textwidget.text.insert("1.0", content)
67+
v.filedir.configure(text=tabs[v.tabselected][2])
12268

123-
def buildtabs():
124-
ntkutils.clearwin(v.tabbar)
125-
tabbuttons.clear()
126-
cbuttons.clear()
69+
updatetitle()
70+
setlexer()
12771

128-
for i in tabs:
129-
button = ttk.Button(v.tabbar, text=i[0] + " ", image=v.closeimg, compound="right")
130-
button.pack(side="left", padx=10)
131-
button.configure(command=lambda x=button: _open(x))
132-
button.update()
72+
def opentab(event, tabdeleted=False):
73+
if not tabdeleted: tabs[v.tabselected][1] = v.textwidget.text.get("1.0", "end")
13374

134-
cbutton = tkinter.Label(v.tabbar, font=("", 15), image=v.closeimg, bg=v.normal)
135-
cbutton.place(x=button.winfo_x() + button.winfo_width() - 37, y=23)
136-
cbutton.bind("<1>", lambda event, x=cbutton:close(event, x)) # Execute closetab on click
75+
v.tabselected = v.tabbar.index(v.tabbar.select())
13776

138-
tabbuttons.append(button)
139-
cbuttons.append(cbutton)
77+
v.textwidget.text.delete("1.0", "end")
78+
v.textwidget.text.insert("1.0", tabs[v.tabselected][1])
79+
v.textwidget.text.delete("end-1c", "end")
14080

141-
tabbuttons[v.tabselected].configure(style="Accent.TButton")
81+
v.filedir.configure(text=tabs[v.tabselected][2])
14282

143-
# This makes the background change to the hover color when hovering over the button
144-
for i in tabbuttons:
145-
if tabbuttons.index(i) == v.tabselected:
146-
i.bind("<Enter>", lambda event, x=cbuttons[v.tabselected]: on_enters(event, x))
147-
i.bind("<Leave>", lambda event, x=cbuttons[v.tabselected]: on_leaves(event, x))
148-
else:
149-
i.bind("<Enter>", lambda event, x=cbuttons[tabbuttons.index(i)]: on_enter(event, x))
150-
i.bind("<Leave>", lambda event, x=cbuttons[tabbuttons.index(i)]: on_leave(event, x))
83+
try: v.textwidget.redraw()
84+
except: pass
15185

152-
cbuttons[v.tabselected].configure(bg=v.selected, image=v.closeimg2)
86+
updatetitle()
87+
setlexer()
15388

15489
def setlexer():
15590
if v.cfg["syntax-highlighting"]:
15691
try: lexer = get_lexer_for_filename(tabs[v.tabselected][0])
15792
except pygments.util.ClassNotFound: lexer = pygments.lexers.TextLexer
158-
lexer = "pygments.lexers." + str(lexer).split(".")[-1].removesuffix(">")
93+
lexer = "pygments.lexers." + str(lexer).split(".")[-1].removesuffix(">").removesuffix("'")
15994
v.textwidget.text._set_lexer(eval(lexer))
16095
try: v.textwidget.redraw()
161-
except: pass
96+
except: pass
97+
98+
# The following two functions contain code copied from https://github.com/Akuli/porcupine
99+
100+
def closetab(event):
101+
before = v.tabbar.index(f"@{event.x},{event.y}")
102+
after = before + 1
103+
104+
if v.tabbar.index(v.tabbar.tabs()[before:after][0]) < v.tabselected:
105+
v.tabselected = v.tabselected - 1
106+
107+
tabs.pop(v.tabbar.index(v.tabbar.tabs()[before:after][0]))
108+
v.tabbar.forget(v.tabbar.tabs()[before:after][0])
109+
opentab(event, True)
110+
111+
def click(event) -> None:
112+
if event.widget.identify(event.x, event.y) == "label":
113+
# find the right edge of the top label (including close button)
114+
right = event.x
115+
while event.widget.identify(right, event.y) == "label":
116+
right += 1
117+
118+
if event.x >= right - v.closeimg.width():
119+
if event.widget.index("end") != 1:
120+
closetab(event)
121+
else:
122+
v.root.destroy()
123+
else:
124+
opentab(event)
125+
else:
126+
opentab(event)
127+
128+
def changetype():
129+
if tabs[v.tabselected][2] == "unsaved": save()
130+
else:
131+
result = f.get(tabs[v.tabselected][2])
132+
tabs[v.tabselected][2] = result
133+
tabs[v.tabselected][0] = result.split("/")[-1]
134+
v.filedir.configure(text=result)
135+
136+
updatetitle()
137+
setlexer()

0 commit comments

Comments
 (0)