GNU Octave  4.0.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
octave-dock-widget.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2012-2015 Richard Crozier
4 Copyright (C) 2013-2015 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 the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 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 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef 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 
41  : QDockWidget (p)
42 {
43 
44  _parent = static_cast<QMainWindow *> (p); // store main window
45  _floating = false;
47 
48  connect (this, SIGNAL (visibilityChanged (bool)),
49  this, SLOT (handle_visibility_changed (bool)));
50 
51  connect (p, SIGNAL (settings_changed (const QSettings*)),
52  this, SLOT (handle_settings (const QSettings*)));
53 
54  connect (p, SIGNAL (active_dock_changed (octave_dock_widget*, octave_dock_widget*)),
56 
57  QStyle *st = style ();
58  _icon_size = 0.75*st->pixelMetric (QStyle::PM_SmallIconSize);
59 
60 #if defined (Q_OS_WIN32)
61  // windows: add an extra title bar that persists when floating
62 
63  setFeatures (QDockWidget::DockWidgetMovable); // not floatable or closeable
64 
65  // the custom (extra) title bar of the widget
66  _dock_action = new QAction
67  (QIcon (":/actions/icons/widget-undock.png"), "", this);
68  _dock_action-> setToolTip (tr ("Undock widget"));
69  connect (_dock_action, SIGNAL (triggered (bool)),
70  this, SLOT (change_floating (bool)));
71  _dock_button = new QToolButton (this);
72  _dock_button->setDefaultAction (_dock_action);
73  _dock_button->setFocusPolicy (Qt::NoFocus);
74  _dock_button->setIconSize (QSize (_icon_size,_icon_size));
75 
76  _close_action = new QAction
77  (QIcon (":/actions/icons/widget-close.png"), "", this);
78  _close_action-> setToolTip (tr ("Hide widget"));
79  connect (_close_action, SIGNAL (triggered (bool)),
80  this, SLOT (change_visibility (bool)));
81  _close_button = new QToolButton (this);
82  _close_button->setDefaultAction (_close_action);
83  _close_button->setFocusPolicy (Qt::NoFocus);
84  _close_button->setIconSize (QSize (_icon_size,_icon_size));
85 
86  _icon_color = "";
87  _title_3d = 50;
88 
89  QHBoxLayout *h_layout = new QHBoxLayout ();
90  h_layout->addStretch (100);
91  h_layout->addWidget (_dock_button);
92  h_layout->addWidget (_close_button);
93  h_layout->setSpacing (0);
94  h_layout->setContentsMargins (5,2,2,2);
95 
96  _title_widget = new QWidget ();
97  _title_widget->setLayout (h_layout);
98  setTitleBarWidget (_title_widget);
99 
100 #else
101 
102  // non windows: qt takes control of floating widgets
103  setFeatures (QDockWidget::DockWidgetMovable |
104  QDockWidget::DockWidgetClosable |
105  QDockWidget::DockWidgetFloatable); // floatable and closeable
106 
107  connect (this, SIGNAL (topLevelChanged (bool)),
108  this, SLOT (change_floating (bool)));
109 
110 #endif
111 
112  // adding actions of the main window
113  connect (p, SIGNAL (add_actions_signal (QList<QAction *>)),
114  this, SLOT (add_actions (QList<QAction *>)));
115  // copy & paste handling
116  connect (p, SIGNAL (copyClipboard_signal ()),
117  this, SLOT (copyClipboard ()));
118  connect (p, SIGNAL (pasteClipboard_signal ()),
119  this, SLOT (pasteClipboard ()));
120  connect (p, SIGNAL (selectAll_signal ()),
121  this, SLOT (selectAll ()));
122  // undo handling
123  connect (p, SIGNAL (undo_signal ()), this, SLOT (do_undo ()));
124 
125  installEventFilter (this);
126 
127 }
128 
130 {
131  // save state of this dock-widget
132  QString name = objectName ();
133  QSettings *settings = resource_manager::get_settings ();
134 
135  settings->beginGroup ("DockWidgets");
136 
137 #if defined (Q_OS_WIN32)
138  if (_floating) // widget is floating (windows), save actual floating geometry
139  settings->setValue (name+"_floating_geometry", geometry ());
140  else // not floating save docked (normal) geometry
141 #endif
142  settings->setValue (name, saveGeometry ());
143 
144  settings->setValue (name+"Visible", isVisible ()); // store visibility
145  settings->setValue (name+"Floating", _floating); // store visibility
146  settings->setValue (name+"_minimized", isMinimized ()); // store minimized
147 
148  settings->endGroup ();
149  settings->sync ();
150 }
151 
152 // connect signal visibility changed to related slot (called from main-window)
153 void
155 {
156  connect (this, SIGNAL (visibilityChanged (bool)),
157  this, SLOT (handle_visibility (bool)));
158  emit active_changed (isVisible ()); // emit once for init of window menu
159 }
160 
161 
162 // set the widget which previously had focus when tabified
163 void
165 {
166  _predecessor_widget = prev_widget;
167 }
168 
169 // set the title in the dockwidgets title bar
170 void
171 octave_dock_widget::set_title (const QString& title)
172 {
173 #if defined (Q_OS_WIN32)
174  QHBoxLayout* h_layout =
175  static_cast<QHBoxLayout *> (titleBarWidget ()->layout ());
176  QLabel *label = new QLabel (title);
177  label->setStyleSheet ("background: transparent;");
178  h_layout->insertWidget (0,label);
179 #endif
180  setWindowTitle (title);
181 }
182 
183 // set focus to previously active widget in tabbed widget stack
184 void
186 {
187  if (_predecessor_widget) // only != 0 if widget was tabbed
189 
191 }
192 
193 // make the widget floating
194 void
196 {
197 #if defined (Q_OS_WIN32)
198 
199  // windows: the widget has to be reparented (parent = 0)
200 
201  QSettings *settings = resource_manager::get_settings ();
202 
203  // save the docking area and geometry for later redocking
204  // FIXME: dockWidgetArea always returns 2
205  settings->setValue ("DockWidgets/" + objectName () + "_dock_area",
206  _parent->dockWidgetArea (this));
207  settings->setValue ("DockWidgets/" + objectName (), saveGeometry ());
208  settings->sync ();
209 
210  // remove parent and adjust the (un)dock icon
211  setParent (0, Qt::Window);
212  _dock_action->setIcon (QIcon (":/actions/icons/widget-dock"+_icon_color+".png"));
213  _dock_action->setToolTip (tr ("Dock widget"));
214 
215  // restore the last geometry when floating
216  setGeometry (settings->value ("DockWidgets/" + objectName ()
217  + "_floating_geometry",QRect(50,100,480,480)).toRect ());
218 
219 #else
220 
221  // non windows: Just set the appripriate window flag
222  setWindowFlags (Qt::Window);
223 
224  QString css = styleSheet ();
225  css.replace ("widget-undock","widget-dock");
226  setStyleSheet (css);
227 
228 #endif
229 
230  _floating = true;
231 
232  set_focus_predecessor (); // set focus previously active widget if tabbed
233 }
234 
235 
236 // dock the widget
237 void
239 {
240 #if defined (Q_OS_WIN32)
241 
242  // windows: Since floating widget has no parent, we have to read it
243 
244  QSettings *settings = resource_manager::get_settings ();
245 
246  // save last floating geometry if widget really was floating
247  if (_floating)
248  settings->setValue ("DockWidgets/" + objectName () + "_floating_geometry",
249  geometry ());
250  settings->sync ();
251 
252  if (dock)
253  {
254  // add widget to last saved docking area (dock=true is default)
255  int area = settings->value ("DockWidgets/" + objectName () + "_dock_area",
256  Qt::TopDockWidgetArea).toInt ();
257  _parent->addDockWidget (static_cast<Qt::DockWidgetArea> (area), this);
258 
259  // FIXME: restoreGeometry is ignored for docked widgets
260  // and its child widget
261  restoreGeometry (settings->value
262  ("DockWidgets/" + objectName ()).toByteArray ());
263  }
264  else // only reparent, no docking
265  setParent (_parent);
266 
267  // adjust the (un)dock icon
268  _dock_action->setIcon (QIcon (":/actions/icons/widget-undock"+_icon_color+".png"));
269  _dock_action->setToolTip (tr ("Undock widget"));
270 
271 #else
272 
273  // non windows: just say we are a docked widget again
274 
275  Q_UNUSED (dock);
276 
277  setWindowFlags (Qt::Widget);
278 
279  QString css = styleSheet ();
280  css.replace ("widget-dock","widget-undock");
281  setStyleSheet (css);
282 
283 #endif
284 
285  _floating = false;
286 }
287 
288 // slot for (un)dock action
289 void
291 {
292  if (_floating)
293  make_widget ();
294  else
295  {
296  make_window ();
297  focus ();
298  }
299 }
300 
301 // slot for hiding the widget
302 void
304 {
305  setVisible (false);
306  emit active_changed (false);
307 }
308 
309 // get focus widget
310 QWidget *
312 {
313  QWidget * w = QApplication::focusWidget ();
314  if (w && w->focusProxy ()) w = w->focusProxy ();
315  return w;
316 }
317 
318 void
320 {
321  QString css;
322  QString css_button;
323  QString dock_icon;
324 
325  QString icon_col = _icon_color;
326 
327  if (_floating)
328  dock_icon = "widget-dock";
329  else
330  dock_icon = "widget-undock";
331 
332  if (_custom_style)
333  {
334 
335  QColor bg_col, fg_col;
336 
337  if (active)
338  {
339  bg_col = _bg_color_active;
340  fg_col = _fg_color_active;
341  icon_col = _icon_color_active;
342  }
343  else
344  {
345  bg_col = _bg_color;
346  fg_col = _fg_color;
347  icon_col = _icon_color;
348  }
349 
350  QColor bg_col_top, bg_col_bottom;
351  if (_title_3d > 0)
352  {
353  bg_col_top = bg_col.lighter (100 + _title_3d);
354  bg_col_bottom = bg_col.darker (100 + _title_3d);
355  }
356  else
357  {
358  bg_col_top = bg_col.darker (100 - _title_3d);
359  bg_col_bottom = bg_col.lighter (100 - _title_3d);
360  }
361 
362  QString background =
363  QString ("background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
364  " stop: 0 %1, stop: 0.60 %2, stop: 0.95 %2 stop: 1.0 %3);").
365  arg (bg_col_top.name ()).
366  arg (bg_col.name ()).
367  arg (bg_col_bottom.name ());
368 
369 #if defined (Q_OS_WIN32)
370  css = background + QString (" color: %1 ;").arg (fg_col.name ());
371 #else
372  css = QString ("QDockWidget::title { " + background +
373  " text-align: center left;"
374  " padding: 0px 0px 0px 4px;}\n"
375  "QDockWidget { color: %1 ; "
376  " titlebar-close-icon: url(:/actions/icons/widget-close%2.png);"
377  " titlebar-normal-icon: url(:/actions/icons/"+dock_icon+"%2); }"
378  "QDockWidget::close-button,"
379  "QDockWidget::float-button { border: 0px; icon-size: %3px; width: %3px}"
380  ).
381  arg (fg_col.name ()).arg (icon_col).arg (_icon_size);
382 #endif
383  }
384  else
385  {
386 #if defined (Q_OS_WIN32)
387  css = QString ("");
388 #else
389  css = QString ("QDockWidget::title { text-align: center left;"
390  " padding: 0px 0px 0px 4px;}"
391  "QDockWidget {"
392  " titlebar-close-icon: url(:/actions/icons/widget-close.png);"
393  " titlebar-normal-icon: url(:/actions/icons/"+dock_icon+"); }"
394  "QDockWidget::close-button,"
395  "QDockWidget::float-button { border: 0px; icon-size: %1px; width: %1px}"
396  ).arg (_icon_size);
397 #endif
398  }
399 
400 #if defined (Q_OS_WIN32)
401  _title_widget->setStyleSheet (css);
402  css_button = QString ("background: transparent; border: 0px;");
403  _dock_button->setStyleSheet (css_button);
404  _close_button->setStyleSheet (css_button);
405  _dock_action->setIcon (QIcon (":/actions/icons/" + dock_icon + icon_col +
406  ".png"));
407  _close_action->setIcon (QIcon (":/actions/icons/widget-close" + icon_col +
408  ".png"));
409 #else
410  setStyleSheet (css);
411 #endif
412 }
413 
414 void
415 octave_dock_widget::handle_settings (const QSettings *settings)
416 {
417  _custom_style =
418  settings->value ("DockWidgets/widget_title_custom_style",false).toBool ();
419 
420  _title_3d =
421  settings->value ("DockWidgets/widget_title_3d",50).toInt ();
422 
423  QColor default_var = QColor (0,0,0);
424  _fg_color = settings->value ("Dockwidgets/title_fg_color",
425  default_var).value<QColor> ();
426  default_var = QColor (0,0,0);
427  _fg_color_active = settings->value ("Dockwidgets/title_fg_color_active",
428  default_var).value<QColor> ();
429 
430  default_var = QColor (255,255,255);
431  _bg_color = settings->value ("Dockwidgets/title_bg_color",
432  default_var).value<QColor> ();
433  default_var = QColor (192,192,192);
434  _bg_color_active = settings->value ("Dockwidgets/title_bg_color_active",
435  default_var).value<QColor> ();
436 
437  int r, g, b;
438  _bg_color.getRgb (&r, &g, &b);
439  if (r+g+b < 400)
440  _icon_color = "-light";
441  else
442  _icon_color = "";
443 
444  _bg_color_active.getRgb (&r, &g, &b);
445  if (r+g+b < 400)
446  _icon_color_active = "-light";
447  else
448  _icon_color_active = "";
449 
450  notice_settings (settings); // call individual handler
451 
452  set_style (false);
453 }
454 
456 {
457  if (e->type () == QEvent::NonClientAreaMouseButtonDblClick)
458  {
459  e->ignore (); // ignore double clicks into window decoration elements
460  return true;
461  }
462 
463  return QDockWidget::eventFilter (obj,e);
464 }
465 
466 void
468  octave_dock_widget *w_new)
469 {
470  if (_custom_style && this == w_old)
471  {
472  set_style (false);
473  update ();
474  }
475 
476  if (_custom_style && this == w_new)
477  {
478  set_style (true);
479  update ();
480  }
481 }
482 
483 // slot for adding actions from the main window
484 void
486 {
487  if (objectName () != "FileEditor")
488  addActions (action_list);
489 }
490 
491 // close event
492 void
494 {
495  emit active_changed (false);
497  QDockWidget::closeEvent (e);
498 }
virtual void handle_visibility_changed(bool visible)
Slot to steer changing visibility from outside.
octave_dock_widget * _predecessor_widget
void handle_settings(const QSettings *)
bool eventFilter(QObject *obj, QEvent *e)
void set_title(const QString &)
void make_widget(bool dock=true)
octave_dock_widget(QWidget *p=0)
virtual void pasteClipboard()
std::complex< double > w(std::complex< double > z, double relerr=0)
virtual void add_actions(QList< QAction * > action_list)
void handle_active_dock_changed(octave_dock_widget *, octave_dock_widget *)
void set_predecessor_widget(octave_dock_widget *prev_widget)
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 selectAll()
static QSettings * get_settings(void)
double arg(double x)
Definition: lo-mappers.h:37
virtual void notice_settings(const QSettings *)
virtual void copyClipboard()
slots to handle copy & paste
virtual void closeEvent(QCloseEvent *e)
void set_style(bool active)
virtual void handle_visibility(bool visible)
virtual void do_undo()
slots to handle undo
virtual void focus(void)
virtual void connect_visibility_changed(void)