From 6b2c5dbe17dafca6fd970bf859c95489df90aecf Mon Sep 17 00:00:00 2001 From: astaric Date: Mon, 21 May 2018 13:33:19 +0200 Subject: [PATCH 1/6] canvas: Float Widgets on Top option --- Orange/canvas/application/canvasmain.py | 20 +++++++++++++++ Orange/canvas/config.py | 3 +++ Orange/canvas/scheme/widgetsscheme.py | 33 ++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/Orange/canvas/application/canvasmain.py b/Orange/canvas/application/canvasmain.py index 4c2f7a69247..5469a24b9c5 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("Float 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): @@ -1655,6 +1667,14 @@ 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): + wm = self.current_document().scheme().widget_manager + + settings = QSettings() + settings.setValue("mainwindow/widgets-float-on-top", bool(enabled)) + wm.show_widgets_on_top_changed() + + def show_report_view(self): from Orange.canvas.report.owreport import OWReport doc = self.current_document() 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..cfb9e63da6d 100644 --- a/Orange/canvas/scheme/widgetsscheme.py +++ b/Orange/canvas/scheme/widgetsscheme.py @@ -28,7 +28,7 @@ from AnyQt.QtWidgets import QWidget, QShortcut, QLabel, QSizePolicy, QAction from AnyQt.QtGui import QKeySequence, QWhatsThisClickedEvent -from AnyQt.QtCore import Qt, QObject, QCoreApplication, QTimer, QEvent +from AnyQt.QtCore import Qt, QObject, QCoreApplication, QTimer, QEvent, QSettings from AnyQt.QtCore import pyqtSignal as Signal from .signalmanager import SignalManager, compress_signals, can_enable_dynamic @@ -597,6 +597,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(widget) + # Schedule an update with the signal manager, due to the cleared # implicit Initializing flag self.signal_manager()._update() @@ -627,6 +630,15 @@ def widget_processing_state(self, widget): """ return self.__widget_processing_state[widget] + def show_widgets_on_top_changed(self): + """ + `Float Widgets on Top` menu option has changed. + + Update the flag on existing widgets. + """ + for widget in self.__widget_for_node.values(): + self.__set_float_on_top(widget) + def __create_delayed(self): if self.__init_queue: state = self.__init_queue.popleft() @@ -790,6 +802,25 @@ 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(self, widget): + """Set or unset widget's float on top flag""" + settings = QSettings() + should_float_on_top = settings.value("mainwindow/widgets-float-on-top", False, type=bool) + 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( From a53a12675ddcf447057f1152f8118d4cf98346c1 Mon Sep 17 00:00:00 2001 From: astaric Date: Mon, 21 May 2018 22:51:48 +0200 Subject: [PATCH 2/6] only float on top when application is active --- Orange/canvas/scheme/widgetsscheme.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Orange/canvas/scheme/widgetsscheme.py b/Orange/canvas/scheme/widgetsscheme.py index cfb9e63da6d..283ebe08362 100644 --- a/Orange/canvas/scheme/widgetsscheme.py +++ b/Orange/canvas/scheme/widgetsscheme.py @@ -25,7 +25,7 @@ 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, QSettings @@ -258,6 +258,9 @@ def __init__(self, parent=None): # Tracks the widget in the update loop by the SignalManager self.__updating_widget = None + # disables/enables widget floating when app (de)activates + qApp.applicationStateChanged.connect(self.show_widgets_on_top_changed) + def set_scheme(self, scheme): """ Set the :class:`WidgetsScheme` instance to manage. @@ -806,6 +809,7 @@ def __set_float_on_top(self, widget): """Set or unset widget's float on top flag""" settings = QSettings() should_float_on_top = settings.value("mainwindow/widgets-float-on-top", False, type=bool) + should_float_on_top &= qApp.applicationState() == Qt.ApplicationActive float_on_top = widget.windowFlags() & Qt.WindowStaysOnTopHint if float_on_top == should_float_on_top: From 39a23f825ae7c8da1a9c6833c768339a287808c8 Mon Sep 17 00:00:00 2001 From: astaric Date: Tue, 22 May 2018 07:02:50 +0200 Subject: [PATCH 3/6] Qt <5.2 compatibility --- Orange/canvas/scheme/widgetsscheme.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Orange/canvas/scheme/widgetsscheme.py b/Orange/canvas/scheme/widgetsscheme.py index 283ebe08362..26865462bc0 100644 --- a/Orange/canvas/scheme/widgetsscheme.py +++ b/Orange/canvas/scheme/widgetsscheme.py @@ -258,8 +258,10 @@ def __init__(self, parent=None): # Tracks the widget in the update loop by the SignalManager self.__updating_widget = None - # disables/enables widget floating when app (de)activates - qApp.applicationStateChanged.connect(self.show_widgets_on_top_changed) + if hasattr(qApp, "applicationStateChanged"): + # disables/enables widget floating when app (de)activates + # available in Qt >= 5.2 + qApp.applicationStateChanged.connect(self.show_widgets_on_top_changed) def set_scheme(self, scheme): """ @@ -809,7 +811,10 @@ def __set_float_on_top(self, widget): """Set or unset widget's float on top flag""" settings = QSettings() should_float_on_top = settings.value("mainwindow/widgets-float-on-top", False, type=bool) - should_float_on_top &= qApp.applicationState() == Qt.ApplicationActive + 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: From 9e64bb28dd64b1a3a3de9efbfee20e16907f9e88 Mon Sep 17 00:00:00 2001 From: astaric Date: Thu, 24 May 2018 15:16:45 +0200 Subject: [PATCH 4/6] store float_on_top as WidgetManager's attribute Serialize to QSettings on close, like other canvas settings --- Orange/canvas/application/canvasmain.py | 13 +++++++----- Orange/canvas/scheme/widgetsscheme.py | 27 ++++++++++++++----------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Orange/canvas/application/canvasmain.py b/Orange/canvas/application/canvasmain.py index 5469a24b9c5..ce73c4799f5 100644 --- a/Orange/canvas/application/canvasmain.py +++ b/Orange/canvas/application/canvasmain.py @@ -1669,11 +1669,7 @@ def reset_widget_settings(self): def set_float_widgets_on_top_enabled(self, enabled): wm = self.current_document().scheme().widget_manager - - settings = QSettings() - settings.setValue("mainwindow/widgets-float-on-top", bool(enabled)) - wm.show_widgets_on_top_changed() - + wm.set_float_widgets_on_top(enabled) def show_report_view(self): from Orange.canvas.report.owreport import OWReport @@ -1842,6 +1838,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() @@ -1994,6 +1992,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/scheme/widgetsscheme.py b/Orange/canvas/scheme/widgetsscheme.py index 26865462bc0..f4031e547d6 100644 --- a/Orange/canvas/scheme/widgetsscheme.py +++ b/Orange/canvas/scheme/widgetsscheme.py @@ -28,11 +28,11 @@ 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, QSettings +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,10 +258,14 @@ 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 - qApp.applicationStateChanged.connect(self.show_widgets_on_top_changed) + 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): """ @@ -603,7 +607,7 @@ def create_widget_instance(self, node): # befriend class Report widget._Report__report_view = self.scheme().report_view - self.__set_float_on_top(widget) + self.__set_float_on_top_flag(widget) # Schedule an update with the signal manager, due to the cleared # implicit Initializing flag @@ -635,14 +639,14 @@ def widget_processing_state(self, widget): """ return self.__widget_processing_state[widget] - def show_widgets_on_top_changed(self): + def set_float_widgets_on_top(self, float_on_top): """ - `Float Widgets on Top` menu option has changed. - - Update the flag on existing widgets. + 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(widget) + self.__set_float_on_top_flag(widget) def __create_delayed(self): if self.__init_queue: @@ -807,10 +811,9 @@ 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(self, widget): + def __set_float_on_top_flag(self, widget): """Set or unset widget's float on top flag""" - settings = QSettings() - should_float_on_top = settings.value("mainwindow/widgets-float-on-top", False, type=bool) + 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 From 5d9589509d23dcb1ff829e95d4b2725a82dc3762 Mon Sep 17 00:00:00 2001 From: astaric Date: Fri, 25 May 2018 12:08:19 +0200 Subject: [PATCH 5/6] apply current float_on_top to new workflows --- Orange/canvas/application/canvasmain.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Orange/canvas/application/canvasmain.py b/Orange/canvas/application/canvasmain.py index ce73c4799f5..e298b3ecab5 100644 --- a/Orange/canvas/application/canvasmain.py +++ b/Orange/canvas/application/canvasmain.py @@ -937,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) @@ -1668,6 +1669,9 @@ def reset_widget_settings(self): 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) From 4e8f814d2bc316a434ac9f42cb6bd4d8fcf9114e Mon Sep 17 00:00:00 2001 From: astaric Date: Fri, 25 May 2018 12:09:00 +0200 Subject: [PATCH 6/6] rename menu option --- Orange/canvas/application/canvasmain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orange/canvas/application/canvasmain.py b/Orange/canvas/application/canvasmain.py index e298b3ecab5..6b64f5df6ce 100644 --- a/Orange/canvas/application/canvasmain.py +++ b/Orange/canvas/application/canvasmain.py @@ -617,7 +617,7 @@ def setup_actions(self): triggered=self.reset_widget_settings) self.float_widgets_on_top_action = \ - QAction(self.tr("Float Widgets on Top"), self, + 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(