GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ButtonGroup.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2016-2018 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
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License 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 <https://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,
71  Utils::fromRgb (pp.get_backgroundcolor_rgb ()));
72  p.setColor (QPalette::WindowText,
73  Utils::fromRgb (pp.get_foregroundcolor_rgb ()));
74  p.setColor (QPalette::Light,
75  Utils::fromRgb (pp.get_highlightcolor_rgb ()));
76  p.setColor (QPalette::Dark,
77  Utils::fromRgb (pp.get_shadowcolor_rgb ()));
78  }
79 
80  static int
82  {
83  int bw = 0;
84 
85  if (! pp.bordertype_is ("none"))
86  {
87  bw = octave::math::round (pp.get_borderwidth ());
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 nullptr;
112  }
113 
114  ButtonGroup::ButtonGroup (const graphics_object& go, QButtonGroup *buttongroup,
115  QFrame *frame)
116  : Object (go, frame), m_hiddenbutton(nullptr), m_container (nullptr),
117  m_title (nullptr), 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  {
259  case uibuttongroup::properties::ID_POSITION:
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 
269  case uibuttongroup::properties::ID_BORDERWIDTH:
270  frame->setLineWidth (octave::math::round (pp.get_borderwidth ()));
271  updateLayout ();
272  break;
273 
274  case uibuttongroup::properties::ID_BACKGROUNDCOLOR:
275  case uibuttongroup::properties::ID_FOREGROUNDCOLOR:
276  case uibuttongroup::properties::ID_HIGHLIGHTCOLOR:
277  case uibuttongroup::properties::ID_SHADOWCOLOR:
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 
288  case uibuttongroup::properties::ID_TITLE:
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 = nullptr;
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 
321  case uibuttongroup::properties::ID_TITLEPOSITION:
322  updateLayout ();
323  break;
324 
325  case uibuttongroup::properties::ID_BORDERTYPE:
326  frame->setFrameStyle (frameStyleFromProperties (pp));
327  updateLayout ();
328  break;
329 
330  case uibuttongroup::properties::ID_FONTNAME:
331  case uibuttongroup::properties::ID_FONTSIZE:
332  case uibuttongroup::properties::ID_FONTWEIGHT:
333  case uibuttongroup::properties::ID_FONTANGLE:
334  if (m_title)
335  {
337  m_title->resize (m_title->sizeHint ());
338  updateLayout ();
339  }
340  break;
341 
342  case uibuttongroup::properties::ID_VISIBLE:
343  frame->setVisible (pp.is_visible ());
344  updateLayout ();
345  break;
346 
347  case uibuttongroup::properties::ID_SELECTEDOBJECT:
348  {
349  graphics_handle h = pp.get_selectedobject ();
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
static void post_callback(const graphics_handle &h, const std::string &name, const octave_value &data=Matrix())
Definition: graphics.in.h:6214
virtual void set(const caseless_str &, const octave_value &)
Matrix get_boundingbox(bool internal=false, const Matrix &parent_pix_size=Matrix()) const
Definition: graphics.cc:9592
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:191
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:53
void addButton(QAbstractButton *btn)
Definition: ButtonGroup.cc:436
virtual void update_boundingbox(void)
Definition: graphics.cc:3285
static void executeAt(const base_properties &props, const QPoint &pt)
Definition: ContextMenu.cc:113
QColor fromRgb(const Matrix &rgb)
bool valid_object(void) const
Definition: graphics.in.h:2806
void buttonClicked(QAbstractButton *btn)
Definition: ButtonGroup.cc:469
double h
Definition: graphics.cc:11808
void update(int pId)
Definition: ButtonGroup.cc:250
template QFont computeFont< uibuttongroup >(const uibuttongroup::properties &props, int height)
std::complex< double > w(std::complex< double > z, double relerr=0)
octave_value as_octave_value(void) const
Definition: oct-handle.h:76
graphics_handle m_handle
Definition: Object.h:115
static Object * fromQObject(QObject *obj)
Definition: Object.cc:176
QRadioButton * m_hiddenbutton
Definition: ButtonGroup.h:71
is false
Definition: cellfun.cc:400
base_properties & get_properties(void)
Definition: graphics.in.h:2788
Definition: dMatrix.h:36
sz
Definition: data.cc:5264
octave_handle graphics_handle
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:12190
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
static Object * toolkitObject(const graphics_object &go)
Definition: Backend.cc:212
p
Definition: lu.cc:138
void buttonToggled(bool toggled)
Definition: ButtonGroup.cc:443
static graphics_object get_object(double val)
Definition: graphics.in.h:6098
ButtonGroup(const graphics_object &go, QButtonGroup *buttongroup, QFrame *frame)
Definition: ButtonGroup.cc:114
double round(double x)
Definition: lo-mappers.h:145
Canvas * canvas(const graphics_handle &handle, bool create=true)
Definition: Container.cc:50
Container * m_container
Definition: ButtonGroup.h:72
base_properties & properties(void)
Definition: Object.h:49
QButtonGroup * m_buttongroup
Definition: ButtonGroup.h:70
static void post_set(const graphics_handle &h, const std::string &name, const octave_value &value, bool notify_toolkit=true)
Definition: graphics.in.h:6228