GNU Octave  4.2.1
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
ButtonGroup.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2016-2017 Andrew Thornton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <QAbstractButton>
28 #include <QButtonGroup>
29 #include <QEvent>
30 #include <QFrame>
31 #include <QLabel>
32 #include <QMouseEvent>
33 #include <QRadioButton>
34 #include <QTimer>
35 
36 #include "Canvas.h"
37 #include "Container.h"
38 #include "ContextMenu.h"
39 #include "ButtonGroup.h"
40 #include "ToggleButtonControl.h"
41 #include "RadioButtonControl.h"
42 #include "Backend.h"
43 #include "QtHandlesUtils.h"
44 
45 #include "ov-struct.h"
46 
47 namespace QtHandles
48 {
49 
50  static int
52  {
53  if (pp.bordertype_is ("none"))
54  return QFrame::NoFrame;
55  else if (pp.bordertype_is ("etchedin"))
56  return (QFrame::Box | QFrame::Sunken);
57  else if (pp.bordertype_is ("etchedout"))
58  return (QFrame::Box | QFrame::Raised);
59  else if (pp.bordertype_is ("beveledin"))
60  return (QFrame::Panel | QFrame::Sunken);
61  else if (pp.bordertype_is ("beveledout"))
62  return (QFrame::Panel | QFrame::Raised);
63  else
64  return (QFrame::Panel | QFrame::Plain);
65  }
66 
67  static void
68  setupPalette (const uibuttongroup::properties& pp, QPalette &p)
69  {
70  p.setColor (QPalette::Window,
72  p.setColor (QPalette::WindowText,
74  p.setColor (QPalette::Light,
76  p.setColor (QPalette::Dark,
78  }
79 
80  static int
82  {
83  int bw = 0;
84 
85  if (! pp.bordertype_is ("none"))
86  {
88  if (pp.bordertype_is ("etchedin") || pp.bordertype_is ("etchedout"))
89  bw *= 2;
90  }
91 
92  return bw;
93  }
94 
95  ButtonGroup*
97  {
98  Object* parent = Object::parentObject (go);
99 
100  if (parent)
101  {
102  Container* container = parent->innerContainer ();
103 
104  if (container)
105  {
106  QFrame* frame = new QFrame(container);
107  return new ButtonGroup (go, new QButtonGroup (frame), frame);
108  }
109  }
110 
111  return 0;
112  }
113 
114  ButtonGroup::ButtonGroup (const graphics_object& go, QButtonGroup* buttongroup,
115  QFrame* frame)
116  : Object (go, frame), m_hiddenbutton(0), m_container (0), m_title (0),
117  m_blockUpdates (false)
118  {
119  uibuttongroup::properties& pp = properties<uibuttongroup> ();
120 
121  frame->setObjectName ("UIButtonGroup");
122  frame->setAutoFillBackground (true);
123  Matrix bb = pp.get_boundingbox (false);
124  frame->setGeometry (octave::math::round (bb(0)), octave::math::round (bb(1)),
125  octave::math::round (bb(2)), octave::math::round (bb(3)));
126  frame->setFrameStyle (frameStyleFromProperties (pp));
127  frame->setLineWidth (octave::math::round (pp.get_borderwidth ()));
128  QPalette pal = frame->palette ();
129  setupPalette (pp, pal);
130  frame->setPalette (pal);
131  m_buttongroup = buttongroup;
132  m_hiddenbutton = new QRadioButton (frame);
133  m_hiddenbutton->hide ();
134  m_buttongroup->addButton (m_hiddenbutton);
135 
136  m_container = new Container (frame);
138 
139  if (frame->hasMouseTracking ())
140  {
141  foreach (QWidget* w, frame->findChildren<QWidget*> ())
142  { w->setMouseTracking (true); }
143  foreach (QWidget* w, buttongroup->findChildren<QWidget*> ())
144  { w->setMouseTracking (true); }
145  }
146 
147  QString title = Utils::fromStdString (pp.get_title ());
148  if (! title.isEmpty ())
149  {
150  m_title = new QLabel (title, frame);
151  m_title->setAutoFillBackground (true);
152  m_title->setContentsMargins (4, 0, 4, 0);
153  m_title->setPalette (pal);
154  m_title->setFont (Utils::computeFont<uibuttongroup> (pp, bb(3)));
155  }
156 
157  frame->installEventFilter (this);
158  m_container->installEventFilter (this);
159 
160  if (pp.is_visible ())
161  {
162  QTimer::singleShot (0, frame, SLOT (show (void)));
163  QTimer::singleShot (0, buttongroup, SLOT (show (void)));
164  }
165  else
166  frame->hide ();
167 
168  connect (m_buttongroup, SIGNAL (buttonClicked (QAbstractButton*)),
169  SLOT (buttonClicked (QAbstractButton*)));
170  }
171 
173  { }
174 
175  bool
176  ButtonGroup::eventFilter (QObject* watched, QEvent* xevent)
177  {
178  if (! m_blockUpdates)
179  {
180  if (watched == qObject ())
181  {
182  switch (xevent->type ())
183  {
184  case QEvent::Resize:
185  {
187  graphics_object go = object ();
188 
189  if (go.valid_object ())
190  {
191  if (m_title)
192  {
193  const uibuttongroup::properties& pp =
194  Utils::properties<uibuttongroup> (go);
195 
196  if (pp.fontunits_is ("normalized"))
197  {
198  QFrame* frame = qWidget<QFrame> ();
199 
201  (pp, frame->height ()));
202  m_title->resize (m_title->sizeHint ());
203  }
204  }
205  updateLayout ();
206  }
207  }
208  break;
209 
210  case QEvent::MouseButtonPress:
211  {
212  QMouseEvent* m = dynamic_cast<QMouseEvent*> (xevent);
213 
214  if (m->button () == Qt::RightButton)
215  {
217 
218  ContextMenu::executeAt (properties (), m->globalPos ());
219  }
220  }
221  break;
222 
223  default:
224  break;
225  }
226  }
227  else if (watched == m_container)
228  {
229  switch (xevent->type ())
230  {
231  case QEvent::Resize:
232  if (qWidget<QWidget> ()->isVisible ())
233  {
235 
237  }
238  break;
239 
240  default:
241  break;
242  }
243  }
244  }
245 
246  return false;
247  }
248 
249  void
251  {
252  uibuttongroup::properties& pp = properties<uibuttongroup> ();
253  QFrame* frame = qWidget<QFrame> ();
254 
255  m_blockUpdates = true;
256 
257  switch (pId)
258  {
260  {
261  Matrix bb = pp.get_boundingbox (false);
262 
263  frame->setGeometry (octave::math::round (bb(0)), octave::math::round (bb(1)),
264  octave::math::round (bb(2)), octave::math::round (bb(3)));
265  updateLayout ();
266  }
267  break;
268 
270  frame->setLineWidth (octave::math::round (pp.get_borderwidth ()));
271  updateLayout ();
272  break;
273 
278  {
279  QPalette pal = frame->palette ();
280 
281  setupPalette (pp, pal);
282  frame->setPalette (pal);
283  if (m_title)
284  m_title->setPalette (pal);
285  }
286  break;
287 
289  {
290  QString title = Utils::fromStdString (pp.get_title ());
291 
292  if (title.isEmpty ())
293  {
294  if (m_title)
295  delete m_title;
296  m_title = 0;
297  }
298  else
299  {
300  if (! m_title)
301  {
302  QPalette pal = frame->palette ();
303 
304  m_title = new QLabel (title, frame);
305  m_title->setAutoFillBackground (true);
306  m_title->setContentsMargins (4, 0, 4, 0);
307  m_title->setPalette (pal);
309  m_title->show ();
310  }
311  else
312  {
313  m_title->setText (title);
314  m_title->resize (m_title->sizeHint ());
315  }
316  }
317  updateLayout ();
318  }
319  break;
320 
322  updateLayout ();
323  break;
324 
326  frame->setFrameStyle (frameStyleFromProperties (pp));
327  updateLayout ();
328  break;
329 
334  if (m_title)
335  {
337  m_title->resize (m_title->sizeHint ());
338  updateLayout ();
339  }
340  break;
341 
343  frame->setVisible (pp.is_visible ());
344  updateLayout ();
345  break;
346 
348  {
352  Object* selectedObject = Backend::toolkitObject (go);
353  ToggleButtonControl* toggle = static_cast<ToggleButtonControl*>
354  (selectedObject);
355  RadioButtonControl* radio = static_cast<RadioButtonControl*>(selectedObject);
356  if (toggle)
357  {
358  go.get_properties ().set ("value", 1);
359  }
360  else if (radio)
361  {
362  go.get_properties ().set ("value", 1);
363  }
364  else
365  {
366  m_hiddenbutton->setChecked (true);
367  }
368  }
369  break;
370 
371  default:
372  break;
373  }
374 
375  m_blockUpdates = false;
376  }
377 
378  void
380  {
381  Canvas* canvas = m_container->canvas (m_handle);
382 
383  if (canvas)
384  canvas->redraw ();
385  }
386 
387  void
389  {
390  uibuttongroup::properties& pp = properties<uibuttongroup> ();
391  QFrame* frame = qWidget<QFrame> ();
392 
393  Matrix bb = pp.get_boundingbox (true);
394  int bw = borderWidthFromProperties (pp);
395 
396  frame->setFrameRect (QRect (octave::math::round (bb(0)) - bw,
397  octave::math::round (bb(1)) - bw,
398  octave::math::round (bb(2)) + 2*bw, octave::math::round (bb(3)) + 2*bw));
399  m_container->setGeometry (octave::math::round (bb(0)),
400  octave::math::round (bb(1)),
401  octave::math::round (bb(2)), octave::math::round (bb(3)));
402 
403  if (m_blockUpdates)
404  pp.update_boundingbox ();
405 
406  if (m_title)
407  {
408  QSize sz = m_title->sizeHint ();
409  int offset = 5;
410 
411  if (pp.titleposition_is ("lefttop"))
412  m_title->move (bw+offset, 0);
413  else if (pp.titleposition_is ("righttop"))
414  m_title->move (frame->width () - bw - offset - sz.width (), 0);
415  else if (pp.titleposition_is ("leftbottom"))
416  m_title->move (bw+offset, frame->height () - sz.height ());
417  else if (pp.titleposition_is ("rightbottom"))
418  m_title->move (frame->width () - bw - offset - sz.width (),
419  frame->height () - sz.height ());
420  else if (pp.titleposition_is ("centertop"))
421  m_title->move (frame->width () / 2 - sz.width () / 2, 0);
422  else if (pp.titleposition_is ("centerbottom"))
423  m_title->move (frame->width () / 2 - sz.width () / 2,
424  frame->height () - sz.height ());
425  }
426  }
427 
428  void
430  {
431  m_hiddenbutton->setChecked (true);
432  }
433 
434 
435  void
436  ButtonGroup::addButton (QAbstractButton* btn)
437  {
438  m_buttongroup->addButton(btn);
439  connect (btn, SIGNAL (toggled (bool)), SLOT (buttonToggled (bool)));
440  }
441 
442  void
444  {
445  Q_UNUSED (toggled);
446  if (!m_blockUpdates)
447  {
449  uibuttongroup::properties& bp = properties<uibuttongroup> ();
450 
451  graphics_handle oldValue = bp.get_selectedobject();
452 
453  QAbstractButton* checkedBtn = m_buttongroup->checkedButton();
454 
455  graphics_handle newValue = graphics_handle ();
456  if (checkedBtn != m_hiddenbutton)
457  {
458  Object* checkedObj = Object::fromQObject(checkedBtn);
459  newValue = checkedObj->properties ().get___myhandle__ ();
460  }
461 
462  if (oldValue != newValue)
463  gh_manager::post_set (m_handle, "selectedobject", newValue.as_octave_value (),
464  false);
465  }
466  }
467 
468  void
469  ButtonGroup::buttonClicked (QAbstractButton* btn)
470  {
471  Q_UNUSED(btn);
472 
474  uibuttongroup::properties& bp = properties<uibuttongroup> ();
475 
476  graphics_handle oldValue = bp.get_selectedobject();
477 
478  QAbstractButton* checkedBtn = m_buttongroup->checkedButton();
479  Object* checkedObj = Object::fromQObject(checkedBtn);
480  graphics_handle newValue = checkedObj->properties ().get___myhandle__ ();
481 
482  if (oldValue != newValue)
483  {
484  octave_scalar_map eventData;
485  eventData.setfield ("OldValue", oldValue.as_octave_value ());
486  eventData.setfield ("NewValue", newValue.as_octave_value ());
487  eventData.setfield ("Source", bp.get___myhandle__ ().as_octave_value ());
488  eventData.setfield ("EventName", "SelectionChanged");
489  octave_value selectionChangedEventObject = octave_value (new octave_struct (
490  eventData));
491  gh_manager::post_callback(m_handle, "selectionchangedfcn",
492  selectionChangedEventObject);
493  }
494  }
495 
496 };
static void setupPalette(const uibuttongroup::properties &pp, QPalette &p)
Definition: ButtonGroup.cc:68
bool bordertype_is(const std::string &v) const
Definition: graphics.h:12418
static void post_callback(const graphics_handle &h, const std::string &name, const octave_value &data=Matrix())
Definition: graphics.h:13910
bool is_visible(void) const
Definition: graphics.h:2704
static int frameStyleFromProperties(const uibuttongroup::properties &pp)
Definition: ButtonGroup.cc:51
QString fromStdString(const std::string &s)
void setfield(const std::string &key, const octave_value &val)
Definition: oct-map.cc:178
static Object * parentObject(const graphics_object &go)
Definition: Object.cc:165
virtual Container * innerContainer(void)=0
static ButtonGroup * create(const graphics_object &go)
Definition: ButtonGroup.cc:96
static int borderWidthFromProperties(const uibuttongroup::properties &pp)
Definition: ButtonGroup.cc:81
void redraw(bool sync=false)
Definition: Canvas.cc:54
Matrix get_boundingbox(bool internal=false, const Matrix &parent_pix_size=Matrix()) const
Definition: graphics.cc:8896
double round(double x)
Definition: lo-mappers.cc:333
void addButton(QAbstractButton *btn)
Definition: ButtonGroup.cc:436
virtual void update_boundingbox(void)
Definition: graphics.cc:3139
std::string get_title(void) const
Definition: graphics.h:12470
static void executeAt(const base_properties &props, const QPoint &pt)
Definition: ContextMenu.cc:113
QColor fromRgb(const Matrix &rgb)
bool fontunits_is(const std::string &v) const
Definition: graphics.h:12433
void buttonClicked(QAbstractButton *btn)
Definition: ButtonGroup.cc:469
double h
Definition: graphics.cc:11205
void update(int pId)
Definition: ButtonGroup.cc:250
template QFont computeFont< uibuttongroup >(const uibuttongroup::properties &props, int height)
nd deftypefn *octave_map m
Definition: ov-struct.cc:2058
std::complex< double > w(std::complex< double > z, double relerr=0)
graphics_handle m_handle
Definition: Object.h:100
bool titleposition_is(const std::string &v) const
Definition: graphics.h:12472
static Object * fromQObject(QObject *obj)
Definition: Object.cc:176
QRadioButton * m_hiddenbutton
Definition: ButtonGroup.h:71
is false
Definition: cellfun.cc:398
Matrix get_backgroundcolor_rgb(void) const
Definition: graphics.h:12415
base_properties & get_properties(void)
Definition: graphics.h:3288
Definition: dMatrix.h:37
sz
Definition: data.cc:5342
virtual QObject * qObject(void)
Definition: Object.h:71
graphics_object object(void) const
Definition: Object.cc:72
bool eventFilter(QObject *watched, QEvent *event)
Definition: ButtonGroup.cc:176
octave::unwind_protect frame
Definition: graphics.cc:11584
bool valid_object(void) const
Definition: graphics.h:3306
Matrix get_shadowcolor_rgb(void) const
Definition: graphics.h:12461
static Object * toolkitObject(const graphics_object &go)
Definition: Backend.cc:199
graphics_handle get_selectedobject(void) const
Definition: graphics.h:12454
p
Definition: lu.cc:138
octave_handle graphics_handle
Definition: graphics.h:56
void buttonToggled(bool toggled)
Definition: ButtonGroup.cc:443
static graphics_object get_object(double val)
Definition: graphics.h:13794
ButtonGroup(const graphics_object &go, QButtonGroup *buttongroup, QFrame *frame)
Definition: ButtonGroup.cc:114
double get_borderwidth(void) const
Definition: graphics.h:12421
Canvas * canvas(const graphics_handle &handle, bool create=true)
Definition: Container.cc:50
Matrix get_foregroundcolor_rgb(void) const
Definition: graphics.h:12441
virtual void set(const caseless_str &, const octave_value &)
graphics_handle get___myhandle__(void) const
Definition: graphics.h:2710
octave_value as_octave_value(void) const
Definition: oct-handle.h:76
Container * m_container
Definition: ButtonGroup.h:72
base_properties & properties(void)
Definition: Object.h:49
QButtonGroup * m_buttongroup
Definition: ButtonGroup.h:70
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))
static void post_set(const graphics_handle &h, const std::string &name, const octave_value &value, bool notify_toolkit=true)
Definition: graphics.h:13924
Matrix get_highlightcolor_rgb(void) const
Definition: graphics.h:12446