GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
octave-dock-widget.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2012-2018 Richard Crozier
4 Copyright (C) 2013-2018 Torsten <ttl@justmail.de>
5 
6 This file is part of Octave.
7 
8 Octave is free software: you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include <QApplication>
29 #include <QToolBar>
30 #include <QAction>
31 #include <QHBoxLayout>
32 #include <QLabel>
33 #include <QSettings>
34 #include <QStyle>
35 
36 #include "resource-manager.h"
37 #include "octave-dock-widget.h"
38 
39 namespace octave
40 {
42  : QDockWidget (p)
43  {
44  QStyle *st = style ();
45  m_icon_size = 0.75*st->pixelMetric (QStyle::PM_SmallIconSize);
46 
47  // the custom (extra) title bar of the widget
48  m_title_widget = new QWidget ();
49 
50  m_dock_action = new QAction
51  (QIcon (":/actions/icons/widget-undock.png"), "", this);
52  m_dock_action->setToolTip (tr ("Undock widget"));
54  m_dock_button->setDefaultAction (m_dock_action);
55  m_dock_button->setFocusPolicy (Qt::NoFocus);
56  m_dock_button->setIconSize (QSize (m_icon_size,m_icon_size));
57 
58  m_close_action = new QAction
59  (QIcon (":/actions/icons/widget-close.png"), "", this);
60  m_close_action->setToolTip (tr ("Close widget"));
62  m_close_button->setDefaultAction (m_close_action);
63  m_close_button->setFocusPolicy (Qt::NoFocus);
64  m_close_button->setIconSize (QSize (m_icon_size,m_icon_size));
65 
66  QString css_button = QString ("QToolButton {background: transparent; border: 0px;}");
67  m_dock_button->setStyleSheet (css_button);
68  m_close_button->setStyleSheet (css_button);
69 
70  QHBoxLayout *h_layout = new QHBoxLayout ();
71  h_layout->addStretch (100);
72  h_layout->addWidget (m_dock_button);
73  h_layout->addWidget (m_close_button);
74  h_layout->setSpacing (0);
75  h_layout->setContentsMargins (5,2,2,2);
76 
77  m_title_widget->setLayout (h_layout);
78  setTitleBarWidget (m_title_widget);
79 
80  // copy & paste handling
81  connect (p, SIGNAL (copyClipboard_signal ()),
82  this, SLOT (copyClipboard ()));
83  connect (p, SIGNAL (pasteClipboard_signal ()),
84  this, SLOT (pasteClipboard ()));
85  connect (p, SIGNAL (selectAll_signal ()),
86  this, SLOT (selectAll ()));
87  // undo handling
88  connect (p, SIGNAL (undo_signal ()), this, SLOT (do_undo ()));
89  }
90 
91  // set the title in the dockwidgets title bar
92  void
93  label_dock_widget::set_title (const QString& title)
94  {
95  QHBoxLayout *h_layout
96  = static_cast<QHBoxLayout *> (titleBarWidget ()->layout ());
97  QLabel *label = new QLabel (title, titleBarWidget ());
98  label->setStyleSheet ("background: transparent;");
99  h_layout->insertWidget (0,label);
100  setWindowTitle (title);
101  }
102 
103 
105  : label_dock_widget (p)
106  {
107  m_parent = static_cast<QMainWindow *> (p); // store main window
108  m_floating = false;
109  m_predecessor_widget = nullptr;
110 
111  connect (this, SIGNAL (visibilityChanged (bool)),
112  this, SLOT (handle_visibility_changed (bool)));
113 
114  connect (p, SIGNAL (settings_changed (const QSettings*)),
115  this, SLOT (handle_settings (const QSettings*)));
116 
117  connect (p, SIGNAL (active_dock_changed (octave_dock_widget*,
120  octave_dock_widget*)));
121 
122  setFeatures (QDockWidget::DockWidgetMovable); // not floatable or closeable
123 
124  connect (m_dock_action, SIGNAL (triggered (bool)),
125  this, SLOT (change_floating (bool)));
126  connect (m_close_action, SIGNAL (triggered (bool)),
127  this, SLOT (change_visibility (bool)));
128 
129  m_close_action->setToolTip (tr ("Hide widget"));
130 
131  m_icon_color = "";
132  m_title_3d = 50;
133 
134  installEventFilter (this);
135 
136  setFocusPolicy (Qt::StrongFocus);
137  }
138 
139  // connect signal visibility changed to related slot (called from main-window)
140  void
142  {
143  connect (this, SIGNAL (visibilityChanged (bool)),
144  this, SLOT (handle_visibility (bool)));
145  emit active_changed (isVisible ()); // emit once for init of window menu
146  }
147 
148  // make the widget floating
149  void
151  {
152  // the widget has to be reparented (parent = 0)
153 
154  QSettings *settings = resource_manager::get_settings ();
155 
156  // save the docking area and geometry for later redocking
157  settings->setValue ("DockWidgets/" + objectName () + "_dock_area",
158  m_parent->dockWidgetArea (this));
159  settings->setValue ("DockWidgets/" + objectName (), saveGeometry ());
160  settings->sync ();
161 
162  // remove parent and adjust the (un)dock icon
163  setTitleBarWidget (0);
164  setParent (0, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
165  Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
166  setTitleBarWidget (m_title_widget);
167  setParent (0, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
168  Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
169 
170 #if defined (Q_OS_UNIX)
171  m_title_widget->setToolTip (
172  tr ("Use <Alt> + <Left Mouse Button> for moving the window"));
173 #endif
174 
175  m_dock_action->setIcon (QIcon (":/actions/icons/widget-dock"
176  + m_icon_color + ".png"));
177  m_dock_action->setToolTip (tr ("Dock widget"));
178 
179  // restore the last geometry when floating
180  setGeometry (settings->value ("DockWidgets/" + objectName ()
181  + "_floating_geometry",
182  QRect (50,100,480,480)).toRect ());
183 
184  m_floating = true;
185 
186  set_focus_predecessor (); // set focus previously active widget if tabbed
187  }
188 
189  // dock the widget
190  void
192  {
193  // Since floating widget has no parent, we have to read it
194 
195  QSettings *settings = resource_manager::get_settings ();
196 
197  // save last floating geometry if widget really was floating
198  if (m_floating)
199  settings->setValue ("DockWidgets/" + objectName () + "_floating_geometry",
200  geometry ());
201  settings->sync ();
202 
203  if (dock)
204  {
205  settings->setValue ("MainWindow/windowState", m_parent->saveState ());
206  // Stay window, otherwise will bounce back to window by default because
207  // there is no layout information for this widget in the saved settings.
208  setParent (m_parent, Qt::Window);
209  m_parent->addDockWidget (Qt::TopDockWidgetArea, this);
210  // recover old window states, hide and re-show new added widget
211  m_parent->restoreState (settings->value ("MainWindow/windowState").toByteArray ());
212  setFloating (false);
213  focus ();
214  QApplication::setActiveWindow (this);
215  m_title_widget->setToolTip ("");
216  }
217  else // only reparent, no docking
218  setParent (m_parent);
219 
220  // adjust the (un)dock icon
221  m_dock_action->setIcon (QIcon (":/actions/icons/widget-undock"
222  + m_icon_color + ".png"));
223  m_dock_action->setToolTip (tr ("Undock widget"));
224 
225  m_floating = false;
226  }
227 
228  // set the widget which previously had focus when tabified
229  void
231  {
232  m_predecessor_widget = prev_widget;
233  }
234 
235  // close event
236  void
238  {
239  emit active_changed (false);
241  QDockWidget::closeEvent (e);
242  }
243 
244  // get focus widget
245  QWidget *
247  {
248  QWidget *w = QApplication::focusWidget ();
249  if (w && w->focusProxy ()) w = w->focusProxy ();
250  return w;
251  }
252 
253  void
254  octave_dock_widget::handle_settings (const QSettings *settings)
255  {
257  = settings->value ("DockWidgets/widget_title_custom_style",false).toBool ();
258 
259  m_title_3d
260  = settings->value ("DockWidgets/widget_title_3d",50).toInt ();
261 
262  QColor default_var = QColor (0,0,0);
263  m_fg_color = settings->value ("DockWidgets/title_fg_color",
264  default_var).value<QColor> ();
265  default_var = QColor (0,0,0);
266  m_fg_color_active = settings->value ("DockWidgets/title_fg_color_active",
267  default_var).value<QColor> ();
268 
269  default_var = QColor (255,255,255);
270  m_bg_color = settings->value ("DockWidgets/title_bg_color",
271  default_var).value<QColor> ();
272  default_var = QColor (192,192,192);
273  m_bg_color_active = settings->value ("DockWidgets/title_bg_color_active",
274  default_var).value<QColor> ();
275 
276  QColor bcol (m_bg_color);
277  QColor bcola (m_bg_color_active);
278 
279  if (! m_custom_style)
280  {
281  bcol = QWidget::palette ().color (m_title_widget->backgroundRole());
282  bcola = bcol;
283  }
284 
285  int r, g, b;
286  bcol.getRgb (&r, &g, &b);
287  if (r+g+b < 400)
288  m_icon_color = "-light";
289  else
290  m_icon_color = "";
291 
292  bcola.getRgb (&r, &g, &b);
293  if (r+g+b < 400)
294  m_icon_color_active = "-light";
295  else
296  m_icon_color_active = "";
297 
298  notice_settings (settings); // call individual handler
299 
300  set_style (false);
301  }
302 
303  void
305  octave_dock_widget *w_new)
306  {
307  if (m_custom_style && this == w_old)
308  {
309  set_style (false);
310  update ();
311  }
312 
313  if (m_custom_style && this == w_new)
314  {
315  set_style (true);
316  update ();
317  }
318  }
319 
320  void
322  {
323  // save state of this dock-widget
324  QString name = objectName ();
325  QSettings *settings = resource_manager::get_settings ();
326 
327  if (! settings)
328  return;
329 
330  settings->beginGroup ("DockWidgets");
331 
332  if (m_floating) // widget is floating (windows), save actual floating geometry
333  settings->setValue (name+"_floating_geometry", geometry ());
334  else // not floating save docked (normal) geometry
335  settings->setValue (name, saveGeometry ());
336 
337  settings->setValue (name+"Visible", isVisible ()); // store visibility
338  settings->setValue (name+"Floating", m_floating); // store visibility
339  settings->setValue (name+"_minimized", isMinimized ()); // store minimized
340 
341  settings->endGroup ();
342  settings->sync ();
343  }
344 
346  {
347  if (e->type () == QEvent::NonClientAreaMouseButtonDblClick)
348  {
349  e->ignore (); // ignore double clicks into window decoration elements
350  return true;
351  }
352 
353  return QDockWidget::eventFilter (obj,e);
354  }
355 
356  // slot for (un)dock action
357  void
359  {
360  if (m_floating)
361  make_widget ();
362  else
363  {
364  make_window ();
365  focus ();
366  }
367  }
368 
369  // slot for hiding the widget
370  void
372  {
373  setVisible (false);
374  emit active_changed (false);
375  }
376 
377  void
379  {
380  QString css;
381  QString css_button;
382  QString dock_icon;
383 
384  QString icon_col = m_icon_color;
385 
386  if (m_floating)
387  dock_icon = "widget-dock";
388  else
389  dock_icon = "widget-undock";
390 
391 #if defined (Q_OS_MAC)
392  QString alignment = "center";
393 #else
394  QString alignment = "center left";
395 #endif
396  if (m_custom_style)
397  {
398 
399  QColor bg_col, fg_col;
400 
401  if (active)
402  {
403  bg_col = m_bg_color_active;
404  fg_col = m_fg_color_active;
405  icon_col = m_icon_color_active;
406  }
407  else
408  {
409  bg_col = m_bg_color;
410  fg_col = m_fg_color;
411  icon_col = m_icon_color;
412  }
413 
414  QColor bg_col_top, bg_col_bottom;
415  if (m_title_3d > 0)
416  {
417  bg_col_top = bg_col.lighter (100 + m_title_3d);
418  bg_col_bottom = bg_col.darker (100 + m_title_3d);
419  }
420  else
421  {
422  bg_col_top = bg_col.darker (100 - m_title_3d);
423  bg_col_bottom = bg_col.lighter (100 - m_title_3d);
424  }
425 
426  QString background =
427  QString ("background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
428  " stop: 0 %1, stop: 0.60 %2, stop: 0.95 %2 stop: 1.0 %3);").
429  arg (bg_col_top.name ()).
430  arg (bg_col.name ()).
431  arg (bg_col_bottom.name ());
432 
433  css = background + QString (" color: %1 ;").arg (fg_col.name ());
434  }
435  else
436  {
437  css = QString ("");
438  }
439 
440  m_title_widget->setStyleSheet (css);
441  css_button = QString ("QToolButton {background: transparent; border: 0px;}");
442  m_dock_button->setStyleSheet (css_button);
443  m_close_button->setStyleSheet (css_button);
444  m_dock_action->setIcon (QIcon (":/actions/icons/" + dock_icon + icon_col +
445  ".png"));
446  m_close_action->setIcon (QIcon (":/actions/icons/widget-close" + icon_col +
447  ".png"));
448  }
449 
450  // set focus to previously active widget in tabbed widget stack
451  void
453  {
454  if (m_predecessor_widget) // only != 0 if widget was tabbed
456 
457  m_predecessor_widget = nullptr;
458  // FIXME: Until cset bda0c5b38bda, the wrong keys "Dockwidget/..." were used
459  // here. This had no effect in Qt4, but does in Qt5. In the following, the
460  // four incorrect keys are updated if still present in the settings files.
461  // The keys are also used in the settings dialog, but
462  // octave_dock_widget::handle_settings is already called at program start.
463  // These tests can be removed in a future version of Octave (version 6).
464  resource_manager::update_settings_key ("Dockwidgets/title_bg_color",
465  "DockWidgets/title_bg_color");
466  resource_manager::update_settings_key ("Dockwidgets/title_bg_color_active",
467  "DockWidgets/title_bg_color_active");
468  resource_manager::update_settings_key ("Dockwidgets/title_fg_color",
469  "DockWidgets/title_fg_color");
470  resource_manager::update_settings_key ("Dockwidgets/title_fg_color_active",
471  "DockWidgets/title_fg_color_active");
472  }
473 }
virtual void notice_settings(const QSettings *)
void set_predecessor_widget(octave_dock_widget *prev_widget)
virtual void handle_visibility_changed(bool visible)
Slot to steer changing visibility from outside.
virtual void selectAll(void)
Slots to handle copy & paste.
void active_changed(bool active)
Custom signal that tells whether a user has clicked away that dock widget, i.e the active dock widget...
virtual void copyClipboard(void)
Slots to handle copy & paste.
label_dock_widget(QWidget *p=nullptr)
QMainWindow * m_parent
Stores the parent, since we are reparenting to 0.
i e
Definition: data.cc:2591
virtual void handle_visibility(bool visible)
octave_value arg
Definition: pr-output.cc:3244
octave_dock_widget(QWidget *p=nullptr)
nd deftypefn *std::string name
Definition: sysdep.cc:647
virtual void pasteClipboard(void)
Slots to handle copy & paste.
std::complex< double > w(std::complex< double > z, double relerr=0)
octave_value arg(void) const
Definition: ov.h:1411
void handle_settings(const QSettings *)
void set_title(const QString &)
void handle_active_dock_changed(octave_dock_widget *, octave_dock_widget *)
octave_dock_widget * m_predecessor_widget
virtual void do_undo(void)
Slot to handle undo.
virtual void connect_visibility_changed(void)
void make_widget(bool dock=true)
virtual void closeEvent(QCloseEvent *e)
bool eventFilter(QObject *obj, QEvent *e)
Event filter for double clicks into the window decoration elements.
p
Definition: lu.cc:138
b
Definition: cellfun.cc:400
static QSettings * get_settings(void)
static bool update_settings_key(const QString &new_key, const QString &old_key)