diff --git a/Orange/canvas/application/canvasmain.py b/Orange/canvas/application/canvasmain.py index 4c2f7a69247..6b64f5df6ce 100644 --- a/Orange/canvas/application/canvasmain.py +++ b/Orange/canvas/application/canvasmain.py @@ -616,6 +616,13 @@ def setup_actions(self): QAction(self.tr("Reset Widget Settings..."), self, triggered=self.reset_widget_settings) + self.float_widgets_on_top_action = \ + QAction(self.tr("Display Widgets on Top"), self, + checkable=True, + toolTip=self.tr("Widgets are always displayed above other windows.")) + self.float_widgets_on_top_action.toggled.connect( + self.set_float_widgets_on_top_enabled) + def setup_menu(self): if sys.platform == "darwin" and QT_VERSION >= 0x50000: self.__menu_glob = QMenuBar(None) @@ -694,6 +701,7 @@ def setup_menu(self): self.view_menu.addSeparator() self.view_menu.addAction(self.toogle_margins_action) + self.view_menu.addAction(self.float_widgets_on_top_action) menu_bar.addMenu(self.view_menu) # Options menu @@ -760,6 +768,10 @@ def restore(self): settings.value("quick-help/visible", True, type=bool) ) + self.float_widgets_on_top_action.setChecked( + settings.value("widgets-float-on-top", False, type=bool) + ) + self.__update_from_settings() def set_document_title(self, title): @@ -925,6 +937,7 @@ def create_new_window(self): window.restoreState(self.saveState(self.SETTINGS_VERSION), self.SETTINGS_VERSION) window.set_tool_dock_expanded(self.dock_widget.expanded()) + window.set_float_widgets_on_top_enabled(self.float_widgets_on_top_action.isChecked()) logview = window.log_view() # type: OutputView te = logview.findChild(QPlainTextEdit) @@ -1655,6 +1668,13 @@ def reset_widget_settings(self): "Settings will still be reset at next application start", parent=self) + def set_float_widgets_on_top_enabled(self, enabled): + if self.float_widgets_on_top_action.isChecked() != enabled: + self.float_widgets_on_top_action.setChecked(enabled) + + wm = self.current_document().scheme().widget_manager + wm.set_float_widgets_on_top(enabled) + def show_report_view(self): from Orange.canvas.report.owreport import OWReport doc = self.current_document() @@ -1822,6 +1842,8 @@ def closeEvent(self, event): settings.setValue("quick-help/visible", self.canvas_tool_dock.quickHelpVisible()) + settings.setValue("widgets-float-on-top", + self.float_widgets_on_top_action.isChecked()) settings.endGroup() self.help_dock.close() @@ -1974,6 +1996,11 @@ def __update_from_settings(self): defaultValue=15, type=int) + float_widgets_on_top = settings.value("widgets-float-on-top", + defaultValue=False, + type=bool) + self.set_float_widgets_on_top_enabled(float_widgets_on_top) + settings.endGroup() settings.beginGroup("quickmenu") diff --git a/Orange/canvas/config.py b/Orange/canvas/config.py index 7c341ac0b71..2b01c7d9341 100644 --- a/Orange/canvas/config.py +++ b/Orange/canvas/config.py @@ -85,6 +85,9 @@ def init(): "Use a popover menu to select a widget when clicking on a category " "button"), + ("mainwindow/widgets-float-on-top", bool, False, + "Float widgets on top of other windows"), + ("mainwindow/number-of-recent-schemes", int, 15, "Number of recent workflows to keep in history"), diff --git a/Orange/canvas/scheme/widgetsscheme.py b/Orange/canvas/scheme/widgetsscheme.py index 162b002a0d3..f4031e547d6 100644 --- a/Orange/canvas/scheme/widgetsscheme.py +++ b/Orange/canvas/scheme/widgetsscheme.py @@ -25,14 +25,14 @@ import sip -from AnyQt.QtWidgets import QWidget, QShortcut, QLabel, QSizePolicy, QAction +from AnyQt.QtWidgets import QWidget, QShortcut, QLabel, QSizePolicy, QAction, qApp from AnyQt.QtGui import QKeySequence, QWhatsThisClickedEvent from AnyQt.QtCore import Qt, QObject, QCoreApplication, QTimer, QEvent from AnyQt.QtCore import pyqtSignal as Signal from .signalmanager import SignalManager, compress_signals, can_enable_dynamic -from .scheme import Scheme, SchemeNode, SchemeLink +from .scheme import Scheme, SchemeNode from .node import UserMessage from ..utils import name_lookup from ..resources import icon_loader @@ -258,6 +258,15 @@ def __init__(self, parent=None): # Tracks the widget in the update loop by the SignalManager self.__updating_widget = None + # Widgets float above other windows + self.__float_widgets_on_top = False + if hasattr(qApp, "applicationStateChanged"): + # disables/enables widget floating when app (de)activates + # available in Qt >= 5.2 + def reapply_float_on_top(): + self.set_float_widgets_on_top(self.__float_widgets_on_top) + qApp.applicationStateChanged.connect(reapply_float_on_top) + def set_scheme(self, scheme): """ Set the :class:`WidgetsScheme` instance to manage. @@ -597,6 +606,9 @@ def create_widget_instance(self, node): widget.setCaption(node.title) # befriend class Report widget._Report__report_view = self.scheme().report_view + + self.__set_float_on_top_flag(widget) + # Schedule an update with the signal manager, due to the cleared # implicit Initializing flag self.signal_manager()._update() @@ -627,6 +639,15 @@ def widget_processing_state(self, widget): """ return self.__widget_processing_state[widget] + def set_float_widgets_on_top(self, float_on_top): + """ + Set `Float Widgets on Top` flag on all widgets. + """ + self.__float_widgets_on_top = float_on_top + + for widget in self.__widget_for_node.values(): + self.__set_float_on_top_flag(widget) + def __create_delayed(self): if self.__init_queue: state = self.__init_queue.popleft() @@ -790,6 +811,28 @@ def __on_env_changed(self, key, newvalue, oldvalue): for widget in self.__widget_for_node.values(): widget.workflowEnvChanged(key, newvalue, oldvalue) + def __set_float_on_top_flag(self, widget): + """Set or unset widget's float on top flag""" + should_float_on_top = self.__float_widgets_on_top + if hasattr(qApp, "applicationState"): + # only float on top when the application is active + # available in Qt >= 5.2 + should_float_on_top &= qApp.applicationState() == Qt.ApplicationActive + float_on_top = widget.windowFlags() & Qt.WindowStaysOnTopHint + + if float_on_top == should_float_on_top: + return + + widget_was_visible = widget.isVisible() + if should_float_on_top: + widget.setWindowFlags(Qt.WindowStaysOnTopHint) + else: + widget.setWindowFlags(widget.windowFlags() & ~Qt.WindowStaysOnTopHint) + + # Changing window flags hid the widget + if widget_was_visible: + widget.show() + def user_message_from_state(message_group): return UserMessage(