Signed-off-by: Daniel Francis <fran...@sugarlabs.org> Signed-off-by: Agustin Zubiaga <a...@sugarlabs.org> --- icons/close-tab.svg | 27 ++++++++++ terminal.py | 42 ++++++++++----- widgets.py | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 13 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 0ba2871..6918e3f 100644 --- a/terminal.py +++ b/terminal.py @@ -32,7 +32,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 @@ -40,6 +39,9 @@ from sugar3.activity.widgets import StopButton from sugar3.activity import activity from sugar3 import env +from widgets import BrowserNotebook +from widgets import TabLabel + MASKED_ENVIRONMENT = [ 'DBUS_SESSION_BUS_ADDRESS', 'PPID'] @@ -118,7 +120,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() @@ -248,17 +251,24 @@ class TerminalActivity(activity.Activity): index = self._create_tab(None) self._notebook.page = index if self._notebook.get_n_pages() == 2: + self._notebook.get_tab_label(self._notebook.get_nth_page(0 + )).show_close_button() self._delete_tab_button.props.sensitive = True self._previous_tab_button.props.sensitive = True self._next_tab_button.props.sensitive = True - def __close_tab_cb(self, btn): - self._close_tab(self._notebook.props.page) + def __close_tab_cb(self, btn, child): + index = self._notebook.page_num(child) + self._close_tab(index) if self._notebook.get_n_pages() == 1: + self._notebook.get_tab_label(self._notebook.get_nth_page(0 + )).hide_close_button() 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 @@ -305,9 +315,8 @@ 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) - #FIXME Drag and drop not working SL#3655 #vt.drag_dest_set(Gtk.DestDefaults.MOTION | Gtk.DestDefaults.DROP, # [('text/plain', 0, 0), ('STRING', 0, 1)], # Gdk.DragAction.DEFAULT | @@ -318,25 +327,32 @@ class TerminalActivity(activity.Activity): vt.show() - label = Gtk.Label() - scrollbar = Gtk.VScrollbar.new(vt.get_vadjustment()) - scrollbar.show() box = Gtk.HBox() box.pack_start(vt, True, True, 0) box.pack_start(scrollbar, False, True, 0) box.vt = vt - box.label = label + box.show() + + tablabel = TabLabel(box) + tablabel.connect('tab-close', self.__close_tab_cb) + tablabel.update_size(200) + 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 # one tab. I think it's useful to always see it, since it displays # the 'window title'. # self._notebook.props.show_tabs = self._notebook.get_n_pages() > 1 + tablabel.hide_close_button() if self._notebook.get_n_pages() == 1\ + else None # Launch the default shell in the HOME directory. os.chdir(os.environ["HOME"]) @@ -380,8 +396,8 @@ class TerminalActivity(activity.Activity): 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 diff --git a/widgets.py b/widgets.py new file mode 100644 index 0000000..94eff64 --- /dev/null +++ b/widgets.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# 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.first_expose = True + self.connect("draw", self._draw_cb) + 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 _draw_cb(self, widget, event): + if self.first_expose: + self.update_tab_sizes() + self.first_expose = False + + 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, + ([GObject.TYPE_PYOBJECT])), + } + + def __init__(self, child): + GObject.GObject.__init__(self) + + self.child = child + 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', self.child) -- 1.7.10.2 _______________________________________________ Sugar-devel mailing list Sugar-devel@lists.sugarlabs.org http://lists.sugarlabs.org/listinfo/sugar-devel