GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
Menu.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2011-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <QAction>
31 #include <QMainWindow>
32 #include <QMenu>
33 #include <QMenuBar>
34 
35 #include "Figure.h"
36 #include "Menu.h"
37 #include "QtHandlesUtils.h"
38 
39 #include "octave-qobject.h"
40 
41 namespace QtHandles
42 {
43 
44  static QKeySequence
46  {
47  std::string s (up.get_accelerator ());
48 
49  if (! s.empty ())
50  {
51  char c = s[0];
52  int keyMod = Qt::CTRL;
53 
54  if (c >= 'A' && c <= 'Z')
55  keyMod |= Qt::SHIFT;
56  if (c >= 'a' && c <= 'z')
57  c -= ('a' - 'A');
58  if (c >= 'A' && c <= 'Z')
59  return QKeySequence (keyMod | static_cast<int> (c));
60  }
61 
62  return QKeySequence ();
63  }
64 
65  Menu*
67  const graphics_object& go)
68  {
69  Object *parent_obj = parentObject (interp, go);
70 
71  if (parent_obj)
72  {
73  QObject *qObj = parent_obj->qObject ();
74 
75  if (qObj)
76  return new Menu (oct_qobj, interp, go, new QAction (qObj),
77  parent_obj);
78  }
79 
80  return nullptr;
81  }
82 
84  const graphics_object& go, QAction *action, Object *xparent)
85  : Object (oct_qobj, interp, go, action), m_parent (nullptr),
86  m_separator (nullptr)
87  {
88  uimenu::properties& up = properties<uimenu> ();
89 
90  action->setText (Utils::fromStdString (up.get_label ()));
91 
92  if (up.is_checked ())
93  {
94  action->setCheckable (true);
95  action->setChecked (up.is_checked ());
96  }
97 
98  action->setEnabled (up.is_enable ());
99  action->setShortcut (accelSequence (up));
100  action->setVisible (up.is_visible ());
101 
102  if (up.is_separator ())
103  {
104  m_separator = new QAction (action);
105  m_separator->setSeparator (true);
106  m_separator->setVisible (up.is_visible ());
107  }
108 
109  MenuContainer *menuContainer = dynamic_cast<MenuContainer *> (xparent);
110 
111  if (menuContainer)
112  m_parent = menuContainer->menu ();
113 
114  if (m_parent)
115  {
116  int pos = static_cast<int> (up.get_position ());
117 
118  if (pos <= 0)
119  {
120  if (m_separator)
121  m_parent->insertAction (nullptr, m_separator);
122  m_parent->insertAction (nullptr, action);
123 
124  int count = 0;
125 
126  for (auto *a : m_parent->actions ())
127  if (! a->isSeparator ())
128  count++;
129 
130  up.get_property ("position").set
131  (octave_value (static_cast<double> (count)), true, false);
132  }
133  else
134  {
135 
136  int count = 0;
137  QAction *before = nullptr;
138 
139  for (auto *a : m_parent->actions ())
140  {
141  if (! a->isSeparator ())
142  {
143  count++;
144  if (pos <= count)
145  {
146  before = a;
147  break;
148  }
149  }
150  }
151 
152  if (m_separator)
153  m_parent->insertAction (before, m_separator);
154  m_parent->insertAction (before, action);
155 
156  if (before)
158  else
159  up.get_property ("position").set
160  (octave_value (static_cast<double> (count+1)), true, false);
161  }
162  }
163 
164  connect (action, SIGNAL (triggered (bool)), SLOT (actionTriggered (void)));
165  }
166 
167  Menu::~Menu (void)
168  { }
169 
170  void
171  Menu::update (int pId)
172  {
173  uimenu::properties& up = properties<uimenu> ();
174  QAction *action = qWidget<QAction> ();
175 
176  switch (pId)
177  {
178  case uimenu::properties::ID_LABEL:
179  action->setText (Utils::fromStdString (up.get_label ()));
180  break;
181 
182  case uimenu::properties::ID_CHECKED:
183  if (up.is_checked ())
184  {
185  action->setCheckable (true);
186  action->setChecked (up.is_checked ());
187  }
188  else
189  {
190  action->setChecked (false);
191  action->setCheckable (false);
192  }
193  break;
194 
195  case uimenu::properties::ID_ENABLE:
196  action->setEnabled (up.is_enable ());
197  break;
198 
199  case uimenu::properties::ID_ACCELERATOR:
200  if (! action->menu ())
201  action->setShortcut (accelSequence (up));
202  break;
203 
204  case uimenu::properties::ID_SEPARATOR:
205  if (up.is_separator ())
206  {
207  if (! m_separator)
208  {
209  m_separator = new QAction (action);
210  m_separator->setSeparator (true);
211  m_separator->setVisible (up.is_visible ());
212  if (m_parent)
213  m_parent->insertAction (action, m_separator);
214  }
215  }
216  else
217  {
218  if (m_separator)
219  delete m_separator;
220  m_separator = nullptr;
221  }
222  break;
223 
224  case uimenu::properties::ID_VISIBLE:
225  action->setVisible (up.is_visible ());
226  if (m_separator)
227  m_separator->setVisible (up.is_visible ());
228  break;
229 
230  case uimenu::properties::ID_POSITION:
231  {
232  if (m_separator)
233  m_parent->removeAction (m_separator);
234 
235  m_parent->removeAction (action);
236 
237  int pos = static_cast<int> (up.get_position ());
238  QAction *before = nullptr;
239 
240  if (pos > 0)
241  {
242  int count = 0;
243 
244  for (auto *a : m_parent->actions ())
245  {
246  if (! a->isSeparator ())
247  {
248  count++;
249  if (pos <= count)
250  {
251  before = a;
252  break;
253  }
254  }
255  }
256  }
257 
258  if (m_separator)
259  m_parent->insertAction (before, m_separator);
260 
261  m_parent->insertAction (before, action);
262 
264  }
265  break;
266 
267  default:
268  Object::update (pId);
269  break;
270  }
271  }
272 
273  QWidget*
274  Menu::menu (void)
275  {
276  QAction *action = qWidget<QAction> ();
277  QMenu *_menu = action->menu ();
278 
279  if (! _menu)
280  {
281  _menu = new QMenu (action->parentWidget ());
282  action->setMenu (_menu);
283  action->setShortcut (QKeySequence ());
284  connect (_menu, SIGNAL (aboutToShow (void)),
285  this, SLOT (actionHovered (void)));
286  }
287 
288  return _menu;
289  }
290 
291  void
293  {
294  QAction *action = qWidget<QAction> ();
295 
296  if (action->isCheckable ())
297  action->setChecked (! action->isChecked ());
298  emit gh_callback_event (m_handle, "callback");
299  }
300 
301  void
303  {
304  emit gh_callback_event (m_handle, "callback");
305  }
306 
307  void
309  {
310  if (m_parent)
311  {
312  double count = 1.0;
313 
314  for (auto *a : m_parent->actions ())
315  {
316  if (! a->isSeparator ())
317  {
318  Object *aObj = Object::fromQObject (a);
319 
320  if (aObj)
321  {
322  graphics_object go = aObj->object ();
323 
324  // Probably overkill as a uimenu child can only be another
325  // uimenu object.
326  if (go.isa ("uimenu"))
327  {
328  uimenu::properties& up = Utils::properties<uimenu> (go);
329 
330  up.get_property ("position").set
331  (octave_value (count), true, false);
332  }
333  }
334 
335  count++;
336  }
337  }
338  }
339  }
340 
341 }
virtual QWidget * menu(void)=0
void updateSiblingPositions(void)
Definition: Menu.cc:308
~Menu(void)
Definition: Menu.cc:167
void actionHovered(void)
Definition: Menu.cc:302
Menu(octave::base_qobject &oct_qobj, octave::interpreter &interp, const graphics_object &go, QAction *action, Object *parent)
Definition: Menu.cc:83
static Menu * create(octave::base_qobject &oct_qobj, octave::interpreter &interp, const graphics_object &go)
Definition: Menu.cc:66
QWidget * menu(void)
Definition: Menu.cc:274
QWidget * m_parent
Definition: Menu.h:73
void update(int pId)
Definition: Menu.cc:171
void actionTriggered(void)
Definition: Menu.cc:292
QAction * m_separator
Definition: Menu.h:74
graphics_object object(void) const
Definition: Object.cc:83
static Object * parentObject(octave::interpreter &interp, const graphics_object &go)
Definition: Object.cc:201
void gh_callback_event(const graphics_handle &h, const std::string &name)
static Object * fromQObject(QObject *obj)
Definition: Object.cc:214
virtual void update(int pId)
Definition: Object.cc:164
graphics_handle m_handle
Definition: Object.h:157
virtual QObject * qObject(void)
Definition: Object.h:82
virtual property get_property(const caseless_str &pname)
bool isa(const std::string &go_name) const
Definition: graphics.in.h:2827
Base class for Octave interfaces that use Qt.
bool set(const octave_value &val, bool do_run=true, bool do_notify_toolkit=true)
Definition: graphics.in.h:2003
const Qt::KeyboardModifier CTRL
QString fromStdString(const std::string &s)
static QKeySequence accelSequence(const uimenu::properties &up)
Definition: Menu.cc:45