11 Star 43 Fork 13

outersky / JingTerm

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
term_notebook.py 11.00 KB
一键复制 编辑 原始数据 按行查看 历史
import gi , os
# Since a system can have multiple versions
# of GTK + installed, we want to make
# sure that we are importing GTK + 3.
gi.require_version("Gtk", "3.0")
gi.require_version("Vte", "2.91")
from gi.repository import Gtk , Gdk, Vte, GLib
from common import confirm
# import sys
# sys.path.append(".")
import term, tab
class TermNotebook(Gtk.Notebook):
def __init__(self,window):
Gtk.Notebook.__init__(self)
self.set_scrollable(True)
self.popup_enable() #右键顶部可以弹出菜单,显示所有的标签页
self.window = window
self.counter = 0 # 终端编号计数器,每个终端有一个顺序编号,在顶部右键菜单的时候容易区分。
# Create Terms
self.new_term()
self.connect('show', self.init_focus)
mbox = self.init_drag_box()
btn = Gtk.Label(label='{ JingTerm }')
btn.set_name('tab-drag-btn')
# btn.set_hexpand(True) # 让可以拖拽的区域变大一点(貌似还是不能占用全部空闲空间)。 !暂时屏蔽了,占用空间太大!
event_box = Gtk.EventBox()
event_box.add(mbox)
event_box.connect("button_press_event",self.on_drag_label)
event_box.connect('enter_notify_event',self.on_enter_notify_event)
event_box.connect('leave_notify_event',self.on_leave_notify_event)
mbox.pack_end(btn,True,True,0)
self.set_action_widget(event_box, Gtk.PackType.END)
self.connect('switch-page',self.on_switch_page);
event_box.show_all()
self.action_minimum_width = event_box.get_preferred_width().minimum_width ## action_widget 最小宽度
self.action_minimum_height = event_box.get_preferred_height().minimum_height
self.old_win_width = 0
self.old_page_sum = 0
def init_drag_box(self):
mbox = Gtk.Box(spacing=0)
btn_close = Gtk.ToolButton()
btn_max = Gtk.ToolButton()
btn_min = Gtk.ToolButton()
btn_new = Gtk.ToolButton()
mbox.pack_end(btn_close,False,False,0)
mbox.pack_end(btn_max,False,False,0)
mbox.pack_end(btn_min,False,False,0)
mbox.pack_end(btn_new,False,False,0)
icon_close = Gtk.Image()
icon_close.set_from_file("images/win_close.svg")
icon_max = Gtk.Image()
icon_max.set_from_file("images/win_max.svg")
icon_min = Gtk.Image()
icon_min.set_from_file("images/win_min.svg")
icon_new = Gtk.Image()
icon_new.set_from_file("images/add.svg")
btn_close.set_icon_widget(icon_close)
btn_max.set_icon_widget(icon_max)
btn_min.set_icon_widget(icon_min)
btn_new.set_icon_widget(icon_new)
btn_close.connect("clicked", self.window.quitApp)
btn_max.connect("clicked", self.window.do_max)
btn_min.connect("clicked", self.window.do_min)
btn_new.connect("clicked", self.on_add_term)
# for btn in [btn_close,btn_max,btn_min,btn_new]:
# btn.connect("button_press_event",self.on_drag_label)
return mbox
def on_enter_notify_event(self,widget, event):
self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND1))
return True
def on_leave_notify_event(self,widget, event):
self.get_window().set_cursor(None)
return True
def on_add_term(self,widget):
self.new_term()
def on_drag_label(self, widget, event):
if event.button==Gdk.BUTTON_PRIMARY :
# print('start drag')
self.window.begin_move_drag(event.button,event.x_root, event.y_root, event.time)
return True
def init_focus(self, widget):
# 还不行,不能在界面启动后,自动聚焦到第一个终端
print('init focus')
self.grab_focus()
def new_term(self, label=None, callback=None):
n = self.get_n_pages()
title = "term#{}".format(n+1)
if label:
title = label
cur_term = self.current_term()
cwd = None
if cur_term:
cwd = cur_term.get_cwd()
t = term.Term(title, self, init_dir=cwd, callback=callback)
t.set_scrollback_lines(30000) # 设置最大滚动3000行
self.counter += 1
t.counter = self.counter
# t.feed_child("ll\r".encode("utf-8"))
self.insert_page(t, tab.ClosableTab(title, self,t), n)
self.child_set_property(t, 'tab-expand', True)
self.set_menu_label_text(t, "{}: {}".format(t.counter,title)) # 顶部右键菜单都带顺序编号
self.set_tab_reorderable(t,True)
self.show_all()
self.set_current_page(n)
t.grab_focus()
t.connect("contents-changed",self.on_contents_changed) # 如果终端里面内容发生变化了,通知一下(实际会修改tab的颜色)
t.connect("focus-out-event",self.on_focus_out) # 如果终端里面内容发生变化了,通知一下(实际会修改tab的颜色)
return t
def on_switch_page(self, notebook, term, page_num):
closable_tab = self.get_tab_label(term)
closable_tab.clear_changed()
def on_contents_changed(self,term):
if self.current_term()==term :
return
closable_tab = self.get_tab_label(term)
closable_tab.set_changed()
def on_focus_out(self,term,event):
closable_tab = self.get_tab_label(term)
closable_tab.clear_changed()
# 更新窗口透明度,但是最低不得低于0.2,否则就看不清了
def update_opacity(self,opacity):
# print('new opacity: ', opacity) #打开这里,方便调试合适的透明度
if opacity<0.2:
opacity=0.2
self.set_opacity(opacity)
self.opacity = opacity
#增加透明度
def increase_opacity(self):
self.update_opacity(self.opacity-0.1)
#降低透明度
def decrease_opacity(self):
self.update_opacity(self.opacity+0.1)
def batch_new_term(self, commands):
# print('batch_new_term:', commands)
for c in commands:
self.new_tab(None,c[1:])
def new_tab(self, label, commands):
def callback(term):
term.start_commands_thread(commands)
self.new_term(label=label, callback=callback)
def next_term(self):
self.next_page()
def previous_term(self):
self.prev_page()
def move_to_next(self):
n = self.get_current_page()
if n < self.get_n_pages()-1:
widget = self.get_nth_page(n)
self.reorder_child(widget,n+1)
def move_to_previous(self):
n = self.get_current_page()
if n>=1 :
widget = self.get_nth_page(n)
self.reorder_child(widget,n-1)
def close_term(self, term):
# 如果只有一个Tab了,直接提示关闭App
if self.get_n_pages()==1:
self.window.quitApp()
return True
if not confirm(self.window, "确认要关闭该标签页吗?"):
return False
#因为有关闭按钮以及Vte本身的退出事件,可能会导致触发close_term两次,所以判断是否已经在退出中
if hasattr(term,'closing') and term.closing==True:
return True
#如果不是在退出中,则设置'退出中'标记(第一次进入设置,第二次进入的会执行函数入口的检查)
term.closing = True
n = self.page_num(term)
#如果找不到了page_num,也视作已退出
if n==-1:
return True
self.remove_page(n)
term.destroy()
if self.get_n_pages()==0:
self.window.quitApp()
return True
def current_term(self):
n = self.get_current_page()
widget = self.get_nth_page(n)
return widget
def focus_term(self):
widget = self.current_term()
widget.grab_focus()
def rename_term(self):
widget = self.current_term()
closable_tab = self.get_tab_label(widget)
label_text = closable_tab.label_text
dialog = RenameDialog(self.window, label_text)
response = dialog.run()
if response == Gtk.ResponseType.OK:
# print("The OK button was clicked", dialog.get_text())
self.rename(widget,dialog.get_text(),True) #强制更新标题
# elif response == Gtk.ResponseType.CANCEL:
# print("The Cancel button was clicked")
dialog.destroy()
# force: 是否强制更新标题,如果设置了,那么以后就固定为本标题,除非通过对话框重新设置
# 目前只有通过对话框或者通过title:指令来进行设置
def rename(self,term, text, force=None):
# 已经强制设置过名称的,不再自动跟随终端标题变化,只能再次强制设置
if force==None and hasattr(term,'title_changed_by_force') :
return
if force:
term.title_changed_by_force = True
closable_tab = self.get_tab_label(term)
closable_tab.set_text(text)
self.set_menu_label_text(term,"{}: {}".format( term.counter , text) ) # 顶部右键菜单都带顺序编号
'''
设置action_widget的宽度
'''
def set_action_widget_width(self):
(new_win_width,new_win_height) = self.window.cur_size
page_sum = self.get_n_pages()
if (self.old_win_width == new_win_width and self.old_page_sum == page_sum):
return;
self.old_win_width = new_win_width
self.old_page_sum = page_sum
action_widget = self.get_action_widget(Gtk.PackType.END)
## 调整action_widget的宽度,达到类似浏览器标签页的效果
action_w_new = self.calculate_action_widget_width(new_win_width,page_sum)
action_widget.set_size_request(action_w_new,self.action_minimum_height)
self.window.resize(new_win_width,new_win_height)
return
def calculate_action_widget_width(self,win_width,page_sum):
# 因为size_request为widget的最小尺寸,所以,为了可以让window更好的缩小,设置为稍小一些的尺寸
# 这里将宽度设置为计算的80%
action_widget_width = int(0.8*(win_width-page_sum*200))
return min(max(action_widget_width,self.action_minimum_width),int(0.8*(win_width -200)))
from keymap import *
class RenameDialog(Gtk.Dialog):
def __init__(self, parent, text):
Gtk.Dialog.__init__(self, title="重命名", transient_for=parent, flags=0)
self.add_buttons(
Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK
)
self.set_default_size(300, 100)
entry = Gtk.Entry()
entry.props.text=text
# 回车直接关闭窗口
entry.connect("key-press-event", self.on_key_press_event)
box = self.get_content_area()
box.add(entry)
self.entry = entry
self.show_all()
def get_text(self):
return self.entry.props.text
def on_key_press_event(self, widget, key_event):
keyevent_name = get_keyevent_name(key_event)
if keyevent_name == "Enter":
self.emit('response',Gtk.ResponseType.OK)
return True
Python
1
https://gitee.com/outersky/JingTerm.git
git@gitee.com:outersky/JingTerm.git
outersky
JingTerm
JingTerm
master

搜索帮助