Skip to content

Commit

Permalink
Merge pull request #29 from cid0rz/master
Browse files Browse the repository at this point in the history
fix scrollbar and make text readonly
  • Loading branch information
tomlin7 authored May 10, 2022
2 parents 86bb5b0 + a326d45 commit 88fbb32
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 7 deletions.
13 changes: 7 additions & 6 deletions src/lib/components/terminal/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sys import platform

from threading import Thread
from ..utils import AutoScrollbar
from ..utils import AutoScrollbar, TextWithReadonly


class Terminal(tk.Frame):
Expand All @@ -19,17 +19,18 @@ def __init__(self, master, *args, **kwargs):
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)

self.terminal = tk.Text(
self.terminal = TextWithReadonly(
self, wrap=tk.WORD, font=self.font, relief=tk.FLAT,
fg="#333333", bg="#ffffff", padx=10, pady=10
)
self.terminal.grid(row=0, column=0, sticky=tk.NSEW)

self.terminal_scrollbar = AutoScrollbar(self.terminal)
self.terminal_scrollbar.grid(row=0, column=1, sticky=tk.NS)
self.terminal_scrollbar = AutoScrollbar(self)
self.terminal_scrollbar.grid(row=0, column=1, sticky='NSW')


self.terminal.config(yscrollcommand=self.terminal_scrollbar.set)
self.terminal_scrollbar.config(command=self.terminal.yview)
self.terminal_scrollbar.config(command=self.terminal.yview, orient=tk.VERTICAL)

self.line_start = 0
self.alive = True
Expand Down Expand Up @@ -124,7 +125,7 @@ def write_loop(self):
self.alive = False

def write(self, output):
self.terminal.insert(tk.END, output)
self.terminal.insert(tk.END, output, "readonly")
self.terminal.see(tk.END)
self.line_start += len(output)

Expand Down
3 changes: 2 additions & 1 deletion src/lib/components/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .scrollbar import AutoScrollbar
from .label import WrappingLabel
from .filetype import FileType
from .filetype import FileType
from .text_with_readonly import TextWithReadonly
66 changes: 66 additions & 0 deletions src/lib/components/utils/text_with_readonly.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import tkinter as tk

class TextWithReadonly(tk.Text):
'''A text widget that doesn't permit inserts and deletes in regions tagged with "readonly"'''
def __init__(self, *args, **kwargs):
tk.Text.__init__(self, *args, **kwargs)

# this code creates a proxy that will intercept
# each actual insert and delete.
self.tk.eval(WIDGET_PROXY)

# this code replaces the low level tk widget
# with the proxy
widget = str(self)
self.tk.eval('''
rename {widget} _{widget}
interp alias {{}} ::{widget} {{}} widget_proxy _{widget}
'''.format(widget=widget))

WIDGET_PROXY = '''
if {[llength [info commands widget_proxy]] == 0} {
# Tcl code to implement a text widget proxy that disallows
# insertions and deletions in regions marked with "readonly"
proc widget_proxy {actual_widget args} {
set command [lindex $args 0]
set args [lrange $args 1 end]
if {$command == "insert"} {
set index [lindex $args 0]
if [_is_readonly $actual_widget $index "$index+1c"] {
bell
return ""
}
}
if {$command == "delete"} {
foreach {index1 index2} $args {
if {[_is_readonly $actual_widget $index1 $index2]} {
bell
return ""
}
}
}
# if we passed the previous checks, allow the command to
# run normally
$actual_widget $command {*}$args
}
proc _is_readonly {widget index1 index2} {
# return true if any text in the range between
# index1 and index2 has the tag "readonly"
set result false
if {$index2 eq ""} {set index2 "$index1+1c"}
# see if "readonly" is applied to any character in the
# range. There's probably a more efficient way to do this, but
# this is Good Enough
for {set index $index1} \
{[$widget compare $index < $index2]} \
{set index [$widget index "$index+1c"]} {
if {"readonly" in [$widget tag names $index]} {
set result true
break
}
}
return $result
}
}
'''

0 comments on commit 88fbb32

Please sign in to comment.