Signed-off-by: Agustin Zubiaga <a...@sugarlabs.org> Signed-off-by: Daniel Francis <fran...@sugarlabs.org> --- icons/close-tab.svg | 27 ++++++++++ terminal.py | 42 +++++++++++----- widgets.py | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+), 12 deletions(-) create mode 100644 icons/close-tab.svg create mode 100644 widgets.py
diff --git a/icons/close-tab.svg b/icons/close-tab.svg new file mode 100644 index 0000000..782ad24 --- /dev/null +++ b/icons/close-tab.svg @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY fill_color "#FFFFFF"> + <!ENTITY stroke_color "#010101"> +]> +<svg + xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="22.16" + height="22.16" + viewBox="0 0 22.16 22.16" + id="browse-close-tab" + xml:space="preserve"> + <g + transform="matrix(1.3,0,0,1.3,-3.2682282,-3.3351543)" + id="browse-dialog-cancel" + style="stroke:&fill_color;;stroke-width:2.69230771;stroke-miterlimit:4;stroke-dasharray:none"> + <path + d="M 14.798121,7.2131543 6.9900671,15.021208" + id="path2986" + style="fill:none;stroke:&fill_color;;stroke-width:2.69230771;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="M 6.9900671,7.2131543 14.798121,15.021208" + id="path3756" + style="fill:none;stroke:&fill_color;;stroke-width:2.69230771;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + </g> +</svg> diff --git a/terminal.py b/terminal.py index 160b35d..59b4940 100644 --- a/terminal.py +++ b/terminal.py @@ -31,7 +31,6 @@ from gi.repository import Pango from sugar3.graphics.toolbutton import ToolButton from sugar3.graphics.toolbarbox import ToolbarBox from sugar3.graphics.toolbarbox import ToolbarButton -from sugar3.graphics.notebook import Notebook from sugar3.activity.widgets import EditToolbar from sugar3.activity.widgets import ActivityToolbarButton @@ -39,6 +38,8 @@ from sugar3.activity.widgets import StopButton from sugar3.activity import activity from sugar3 import env +from widgets import BrowserNotebook, TabLabel + MASKED_ENVIRONMENT = [ 'DBUS_SESSION_BUS_ADDRESS', 'PPID'] @@ -117,7 +118,8 @@ class TerminalActivity(activity.Activity): toolbar_box.show() self._update_accelerators(toolbar_box) - self._notebook = Notebook() + self._notebook = BrowserNotebook() + self._notebook.connect("tab-added", self.__open_tab_cb) self._notebook.set_property("tab-pos", Gtk.PositionType.TOP) self._notebook.set_scrollable(True) self._notebook.show() @@ -254,10 +256,13 @@ class TerminalActivity(activity.Activity): def __close_tab_cb(self, btn): self._close_tab(self._notebook.props.page) if self._notebook.get_n_pages() == 1: + self._notebook.get_tab_label(0).button.hide_all() self._delete_tab_button.props.sensitive = False self._previous_tab_button.props.sensitive = False self._next_tab_button.props.sensitive = False + self._notebook.update_tab_sizes() + def __prev_tab_cb(self, btn): if self._notebook.props.page == 0: self._notebook.props.page = self._notebook.get_n_pages() - 1 @@ -304,7 +309,7 @@ class TerminalActivity(activity.Activity): vt.connect("window-title-changed", self.__tab_title_changed_cb) # FIXME have to resend motion events to parent, see #1402 - vt.connect('motion-notify-event', self.__motion_notify_cb) + #vt.connect('motion-notify-event', self.__motion_notify_cb) #vt.drag_dest_set(Gtk.DestDefaults.MOTION | Gtk.DestDefaults.DROP, # [('text/plain', 0, 0), ('STRING', 0, 1)], @@ -316,19 +321,24 @@ class TerminalActivity(activity.Activity): vt.show() - label = Gtk.Label() - scrollbar = Gtk.VScrollbar(vt.get_vadjustment()) - scrollbar.show() box = Gtk.HBox() + box.pack_start(vt, True, True, 0) box.pack_start(scrollbar, True, True, 0) box.vt = vt - box.label = label + box.show() + + tablabel = TabLabel() + tablabel.connect('tab-close', self.__close_tab_cb) + box.label = tablabel + + index = self._notebook.append_page(box, tablabel) + tablabel.show_all() - index = self._notebook.append_page(box, label) + self._notebook.update_tab_sizes() self._notebook.show_all() # Uncomment this to only show the tab bar when there is at least @@ -366,20 +376,28 @@ class TerminalActivity(activity.Activity): for l in tab_state['scrollback']: vt.feed(l + '\r\n') - box.pid = vt.fork_command_full(Vte.PtyFlags.DEFAULT, os.environ["HOME"], ["/bin/bash"], [], GLib.SpawnFlags.DO_NOT_REAP_CHILD, None, None) + box.pid = vt.fork_command_full(Vte.PtyFlags.DEFAULT, + os.environ["HOME"], + ["/bin/bash"], [], + GLib.SpawnFlags.DO_NOT_REAP_CHILD, + None, None) self._notebook.props.page = index vt.grab_focus() return index - def __motion_notify_cb(self, widget, event): - self.emit('motion-notify-event', event) +# def __motion_notify_cb(self, widget, event): +# self.emit('motion-notify-event', event) def __become_root_cb(self, button): vt = self._notebook.get_nth_page(self._notebook.get_current_page()).vt vt.feed('\r\n') - vt.fork_command_full(Vte.PtyFlags.DEFAULT, os.environ["HOME"], ["/bin/su"], [], GLib.SpawnFlags.DO_NOT_REAP_CHILD, None, None) + vt.fork_command_full(Vte.PtyFlags.DEFAULT, + os.environ["HOME"], + ["/bin/su"], [], + GLib.SpawnFlags.DO_NOT_REAP_CHILD, + None, None) def __key_press_cb(self, window, event): """Route some keypresses directly to the vte and then drop them. diff --git a/widgets.py b/widgets.py new file mode 100644 index 0000000..93d7dc0 --- /dev/null +++ b/widgets.py @@ -0,0 +1,140 @@ +# Copyright (C) 2006, Red Hat, Inc. +# Copyright (C) 2011, One Laptop Per Child +# Copyright (C) 2009, Tomeu Vizoso, Simon Schampijer +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +#, +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from gi.repository import GObject +from gi.repository import Gtk +from gi.repository import Pango + +from sugar3.graphics.icon import Icon + + +class TabAdd(Gtk.Button): + __gtype_name__ = 'BrowseTabAdd' + + __gsignals__ = { + 'tab-added': (GObject.SignalFlags.RUN_FIRST, + None, + ([])), + } + + def __init__(self): + GObject.GObject.__init__(self) + + add_tab_icon = Icon(icon_name='add') + self.props.relief = Gtk.ReliefStyle.NONE + self.props.focus_on_click = False + icon_box = Gtk.HBox() + icon_box.pack_start(add_tab_icon, True, False, 0) + self.add(icon_box) + self.connect('clicked', self.__button_clicked_cb) + self.set_name('browse-tab-add') + add_tab_icon.show() + icon_box.show() + self.show() + + def __button_clicked_cb(self, button): + self.emit('tab-added') + + +class BrowserNotebook(Gtk.Notebook): + __gtype_name__ = 'BrowseNotebook' + + __gsignals__ = { + 'tab-added': (GObject.SignalFlags.RUN_FIRST, + None, + ([])), + } + + """Handle an extra tab at the end with an Add Tab button.""" + + def __init__(self): + GObject.GObject.__init__(self) + + self._tab_add = TabAdd() + self._tab_add.connect('tab-added', self.on_add_tab) + self.set_action_widget(self._tab_add, Gtk.PackType.END) + self._tab_add.show() + + def on_add_tab(self, obj): + self.emit('tab-added') + + def update_tab_sizes(self): + n_pages = self.get_n_pages() + canvas_size = self.get_allocation() + + # FIXME + # overlap_size = self.style_get_property('tab-overlap') * n_pages - 1 + overlap_size = 0 + allowed_size = canvas_size.width - overlap_size + + tab_new_size = int(float(allowed_size) / (n_pages) -\ + self._tab_add.get_allocation().width - 5) + + for page_idx in range(n_pages): + page = self.get_nth_page(page_idx) + label = self.get_tab_label(page) + label.update_size(tab_new_size) + + +class TabLabel(Gtk.HBox): + __gtype_name__ = 'BrowseTabLabel' + + __gsignals__ = { + 'tab-close': (GObject.SignalFlags.RUN_FIRST, + None, + ([])), + } + + def __init__(self): + GObject.GObject.__init__(self) + + self._label = Gtk.Label(label="") + self._label.set_ellipsize(Pango.EllipsizeMode.END) + self._label.set_alignment(0, 0.5) + self.pack_start(self._label, True, True, 0) + self._label.show() + + close_tab_icon = Icon(icon_name='close-tab') + button = Gtk.Button() + button.props.relief = Gtk.ReliefStyle.NONE + button.props.focus_on_click = False + icon_box = Gtk.HBox() + icon_box.pack_start(close_tab_icon, True, False, 0) + button.add(icon_box) + button.connect('clicked', self.__button_clicked_cb) + button.set_name('browse-tab-close') + self.pack_start(button, False, True, 0) + close_tab_icon.show() + icon_box.show() + button.show() + self._close_button = button + + def set_text(self, title): + self._label.set_text(title) + + def update_size(self, size): + self.set_size_request(size, -1) + + def hide_close_button(self): + self._close_button.hide() + + def show_close_button(self): + self._close_button.show() + + def __button_clicked_cb(self, button): + self.emit('tab-close') -- 1.7.9.5 _______________________________________________ Sugar-devel mailing list Sugar-devel@lists.sugarlabs.org http://lists.sugarlabs.org/listinfo/sugar-devel