Mercurial > octave
view libgui/src/tab-bar.cc @ 30564:796f54d4ddbf stable
update Octave Project Developers copyright for the new year
In files that have the "Octave Project Developers" copyright notice,
update for 2021.
In all .txi and .texi files except gpl.txi and gpl.texi in the
doc/liboctave and doc/interpreter directories, change the copyright
to "Octave Project Developers", the same as used for other source
files. Update copyright notices for 2022 (not done since 2019). For
gpl.txi and gpl.texi, change the copyright notice to be "Free Software
Foundation, Inc." and leave the date at 2007 only because this file
only contains the text of the GPL, not anything created by the Octave
Project Developers.
Add Paul Thomas to contributors.in.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 28 Dec 2021 18:22:40 -0500 |
parents | d4d83344d653 |
children | c6d54dd31a7e |
line wrap: on
line source
//////////////////////////////////////////////////////////////////////// // // Copyright (C) 2018-2022 The Octave Project Developers // // See the file COPYRIGHT.md in the top-level directory of this // distribution or <https://octave.org/copyright/>. // // This file is part of Octave. // // Octave 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 3 of the License, or // (at your option) any later version. // // Octave 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 Octave; see the file COPYING. If not, see // <https://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////// // This file implements a tab bar derived from QTabBar with a contextmenu // and possibility to close a tab via double-left or middle mouse click. #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include "tab-bar.h" namespace octave { // // Reimplemented QTabbar // tab_bar::tab_bar (QWidget *p) : QTabBar (p), m_context_menu (new QMenu (this)) { } void tab_bar::set_rotated (int rotated) { m_rotated = rotated; } // slots for tab navigation void tab_bar::switch_left_tab (void) { switch_tab (-1); } void tab_bar::switch_right_tab (void) { switch_tab (1); } void tab_bar::move_tab_left (void) { switch_tab (-1, true); } void tab_bar::move_tab_right (void) { switch_tab (1, true); } void tab_bar::switch_tab (int direction, bool movetab) { int tabs = count (); if (tabs < 2) return; int old_pos = currentIndex (); int new_pos = currentIndex () + direction; if (new_pos < 0 || new_pos >= tabs) new_pos = new_pos - direction*tabs; if (movetab) { moveTab (old_pos, new_pos); setCurrentIndex (old_pos); setCurrentIndex (new_pos); } else setCurrentIndex (new_pos); } void tab_bar::sort_tabs_alph (void) { QString current_title = tabText (currentIndex ()); int tab_with_focus = 0; // Get all tab title and sort QStringList tab_texts; for (int i = 0; i < count (); i++) tab_texts.append (tabText (i)); tab_texts.sort (); // Move tab into the order of the generated string list for (int title = 0; title < tab_texts.count (); title++) { // Target tab is same as place of title in QStringList. // Find index of next title in string list, leaving out the // tabs (or titles) that were already moved. for (int tab = title; tab < count (); tab++) { if (tabText (tab) == tab_texts.at (title)) { // Index of next tile found, so move tab into next position moveTab (tab, title); if (tab_texts.at (title) == current_title) tab_with_focus = title; break; } } } setCurrentIndex (tab_with_focus); } // The following two functions are reimplemented for allowing rotated // tabs and are based on this answer on stack overflow: // https://stackoverflow.com/a/50579369 // Reimplemented size hint allowing rotated tabs QSize tab_bar::tabSizeHint (int idx) const { QSize s = QTabBar::tabSizeHint (idx); if (m_rotated) s.transpose(); return s; } // Reimplemented paint event allowing rotated tabs void tab_bar::paintEvent(QPaintEvent *e) { // Just process the original event if not rotated if (! m_rotated) return QTabBar::paintEvent (e); // Process the event for rotated tabs QStylePainter painter (this); QStyleOptionTab opt; for (int idx = 0; idx < count(); idx++) { initStyleOption (&opt, idx); painter.drawControl (QStyle::CE_TabBarTabShape, opt); painter.save (); QSize s = opt.rect.size(); s.transpose(); QRect rect (QPoint (), s); rect.moveCenter (opt.rect.center ()); opt.rect = rect; QPoint p = tabRect (idx).center (); painter.translate (p); painter.rotate (-m_rotated*90); painter.translate (-p); painter.drawControl (QStyle::CE_TabBarTabLabel, opt); painter.restore (); } } // Reimplement mouse event for filtering out the desired mouse clicks void tab_bar::mousePressEvent (QMouseEvent *me) { QPoint click_pos; int clicked_idx = -1; // detect the tab where the click occurred for (int i = 0; i < count (); i++) { click_pos = mapToGlobal (me->pos ()); if (tabRect (i).contains (mapFromGlobal (click_pos))) { clicked_idx = i; break; } } // If a tab was clicked if (clicked_idx >= 0) { int current_idx = currentIndex (); int current_count = count (); // detect the mouse click if ((me->type () == QEvent::MouseButtonDblClick && me->button() == Qt::LeftButton) || (me->type () != QEvent::MouseButtonDblClick && me->button() == Qt::MiddleButton)) { // Middle click or double click -> close the tab // Make the clicked tab the current one and close it setCurrentIndex (clicked_idx); emit close_current_tab_signal (true); // Was the closed tab before or after the previously current tab? // According to the result, use previous index or reduce it by one if (current_idx - clicked_idx > 0) setCurrentIndex (current_idx - 1); else if (current_idx - clicked_idx < 0) setCurrentIndex (current_idx); } else if (me->type () != QEvent::MouseButtonDblClick && me->button() == Qt::RightButton) { // Right click, show context menu setCurrentIndex (clicked_idx); // Fill context menu with actions for selecting current tabs m_ctx_actions = m_context_menu->actions (); // Copy of basic actions QMenu ctx_menu; // The menu actually used connect (&ctx_menu, &QMenu::triggered, this, &tab_bar::ctx_menu_activated); for (int i = count () - 1; i >= 0; i--) { // Prepend an action for each tab QAction *a = new QAction (tabIcon (i), tabText (i), &ctx_menu); m_ctx_actions.prepend (a); } // Add all actions to our menu ctx_menu.insertActions (nullptr, m_ctx_actions); if (! ctx_menu.exec (click_pos)) { // No action selected, back to previous tab setCurrentIndex (current_idx); } else if (count () < current_count) { // A tab was closed: // Was the possibly only closed tab before or after the // previously current tab? According to the result, use previous // index or reduce it by one. Also prevent using a too large // index if other or all files were closed. int new_idx = count () - 1; if (new_idx > 0) { if (current_idx - clicked_idx > 0) new_idx = current_idx - 1; else if (current_idx - clicked_idx < 0) new_idx = current_idx; } if (new_idx >= 0) setCurrentIndex (new_idx); } } else { // regular handling of the mouse event QTabBar::mousePressEvent (me); } } else { // regular handling of the mouse event QTabBar::mousePressEvent (me); } } // Slot if a menu entry in the context menu is activated void tab_bar::ctx_menu_activated (QAction *a) { // If the index of the activated action is in the range of // the current tabs, set the related current tab. The basic actions // are handled by the editor int i = m_ctx_actions.indexOf (a); if ((i > -1) && (i < count ())) setCurrentIndex (i); } }