GNU Octave  8.1.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-2023 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 
42 
43 static QKeySequence
45 {
46  std::string s (up.get_accelerator ());
47 
48  if (! s.empty ())
49  {
50  char c = s[0];
51  int keyMod = Qt::CTRL;
52 
53  if (c >= 'A' && c <= 'Z')
54  keyMod |= Qt::SHIFT;
55  if (c >= 'a' && c <= 'z')
56  c -= ('a' - 'A');
57  if (c >= 'A' && c <= 'Z')
58  return QKeySequence (keyMod | static_cast<int> (c));
59  }
60 
61  return QKeySequence ();
62 }
63 
64 Menu *
65 Menu::create (octave::base_qobject& oct_qobj, octave::interpreter& interp,
66  const graphics_object& go)
67 {
68  Object *parent_obj = parentObject (interp, go);
69 
70  if (parent_obj)
71  {
72  QObject *qObj = parent_obj->qObject ();
73 
74  if (qObj)
75  return new Menu (oct_qobj, interp, go, new QAction (qObj),
76  parent_obj);
77  }
78 
79  return nullptr;
80 }
81 
82 Menu::Menu (octave::base_qobject& oct_qobj, octave::interpreter& interp,
83  const graphics_object& go, QAction *action, Object *xparent)
84  : Object (oct_qobj, interp, go, action), m_parent (nullptr),
85  m_separator (nullptr)
86 {
87  uimenu::properties& up = properties<uimenu> ();
88 
89  action->setText (Utils::fromStdString (up.get_text ()));
90 
91  if (up.is_checked ())
92  {
93  action->setCheckable (true);
94  action->setChecked (up.is_checked ());
95  }
96 
97  action->setEnabled (up.is_enable ());
98  action->setShortcut (accelSequence (up));
99  action->setVisible (up.is_visible ());
100 
101  if (up.is_separator ())
102  {
103  m_separator = new QAction (action);
104  m_separator->setSeparator (true);
105  m_separator->setVisible (up.is_visible ());
106  }
107 
108  MenuContainer *menuContainer = dynamic_cast<MenuContainer *> (xparent);
109 
110  if (menuContainer)
111  m_parent = menuContainer->menu ();
112 
113  if (m_parent)
114  {
115  int pos = static_cast<int> (up.get_position ());
116 
117  if (pos <= 0)
118  {
119  if (m_separator)
120  m_parent->insertAction (nullptr, m_separator);
121  m_parent->insertAction (nullptr, action);
122 
123  int count = 0;
124 
125  for (auto *a : m_parent->actions ())
126  if (! a->isSeparator ())
127  count++;
128 
129  up.get_property ("position").set
130  (octave_value (static_cast<double> (count)), true, false);
131  }
132  else
133  {
134 
135  int count = 0;
136  QAction *before = nullptr;
137 
138  for (auto *a : m_parent->actions ())
139  {
140  if (! a->isSeparator ())
141  {
142  count++;
143  if (pos <= count)
144  {
145  before = a;
146  break;
147  }
148  }
149  }
150 
151  if (m_separator)
152  m_parent->insertAction (before, m_separator);
153  m_parent->insertAction (before, action);
154 
155  if (before)
157  else
158  up.get_property ("position").set
159  (octave_value (static_cast<double> (count+1)), true, false);
160  }
161  }
162 
163  connect (action, &QAction::triggered, this, &Menu::actionTriggered);
164 }
165 
167 { }
168 
169 void
170 Menu::update (int pId)
171 {
172  uimenu::properties& up = properties<uimenu> ();
173  QAction *action = qWidget<QAction> ();
174 
175  switch (pId)
176  {
177  case uimenu::properties::ID_TEXT:
178  action->setText (Utils::fromStdString (up.get_text ()));
179  break;
180 
181  case uimenu::properties::ID_CHECKED:
182  if (up.is_checked ())
183  {
184  action->setCheckable (true);
185  action->setChecked (up.is_checked ());
186  }
187  else
188  {
189  action->setChecked (false);
190  action->setCheckable (false);
191  }
192  break;
193 
194  case uimenu::properties::ID_ENABLE:
195  action->setEnabled (up.is_enable ());
196  break;
197 
198  case uimenu::properties::ID_ACCELERATOR:
199  if (! action->menu ())
200  action->setShortcut (accelSequence (up));
201  break;
202 
203  case uimenu::properties::ID_SEPARATOR:
204  if (up.is_separator ())
205  {
206  if (! m_separator)
207  {
208  m_separator = new QAction (action);
209  m_separator->setSeparator (true);
210  m_separator->setVisible (up.is_visible ());
211  if (m_parent)
212  m_parent->insertAction (action, m_separator);
213  }
214  }
215  else
216  {
217  if (m_separator)
218  delete m_separator;
219  m_separator = nullptr;
220  }
221  break;
222 
223  case uimenu::properties::ID_VISIBLE:
224  action->setVisible (up.is_visible ());
225  if (m_separator)
226  m_separator->setVisible (up.is_visible ());
227  break;
228 
229  case uimenu::properties::ID_POSITION:
230  {
231  if (m_separator)
232  m_parent->removeAction (m_separator);
233 
234  m_parent->removeAction (action);
235 
236  int pos = static_cast<int> (up.get_position ());
237  QAction *before = nullptr;
238 
239  if (pos > 0)
240  {
241  int count = 0;
242 
243  for (auto *a : m_parent->actions ())
244  {
245  if (! a->isSeparator ())
246  {
247  count++;
248  if (pos <= count)
249  {
250  before = a;
251  break;
252  }
253  }
254  }
255  }
256 
257  if (m_separator)
258  m_parent->insertAction (before, m_separator);
259 
260  m_parent->insertAction (before, action);
261 
263  }
264  break;
265 
266  default:
267  Object::update (pId);
268  break;
269  }
270 }
271 
272 QWidget *
274 {
275  QAction *action = qWidget<QAction> ();
276  QMenu *action_menu = action->menu ();
277 
278  if (! action_menu)
279  {
280  action_menu = new QMenu (action->parentWidget ());
281  action->setMenu (action_menu);
282  action->setShortcut (QKeySequence ());
283  connect (action_menu, &QMenu::aboutToShow, this, &Menu::actionHovered);
284  }
285 
286  return action_menu;
287 }
288 
289 void
291 {
292  QAction *action = qWidget<QAction> ();
293 
294  if (action->isCheckable ())
295  action->setChecked (! action->isChecked ());
296  emit gh_callback_event (m_handle, "menuselectedfcn");
297 }
298 
299 void
301 {
302  emit gh_callback_event (m_handle, "menuselectedfcn");
303 }
304 
305 void
307 {
308  if (m_parent)
309  {
310  double count = 1.0;
311 
312  for (auto *a : m_parent->actions ())
313  {
314  if (! a->isSeparator ())
315  {
316  Object *aObj = Object::fromQObject (a);
317 
318  if (aObj)
319  {
320  graphics_object go = aObj->object ();
321 
322  // Probably overkill as a uimenu child can only be another
323  // uimenu object.
324  if (go.isa ("uimenu"))
325  {
326  uimenu::properties& up = Utils::properties<uimenu> (go);
327 
328  up.get_property ("position").set
329  (octave_value (count), true, false);
330  }
331  }
332 
333  count++;
334  }
335  }
336  }
337 }
338 
OCTAVE_END_NAMESPACE(octave)
static QKeySequence accelSequence(const uimenu::properties &up)
Definition: Menu.cc:44
virtual QWidget * menu(void)=0
Definition: Menu.h:42
QWidget * m_parent
Definition: Menu.h:69
Menu(octave::base_qobject &oct_qobj, octave::interpreter &interp, const graphics_object &go, QAction *action, Object *parent)
Definition: Menu.cc:82
void actionTriggered(void)
Definition: Menu.cc:290
QWidget * menu(void)
Definition: Menu.cc:273
~Menu(void)
Definition: Menu.cc:166
void actionHovered(void)
Definition: Menu.cc:300
static Menu * create(octave::base_qobject &oct_qobj, octave::interpreter &interp, const graphics_object &go)
Definition: Menu.cc:65
void update(int pId)
Definition: Menu.cc:170
QAction * m_separator
Definition: Menu.h:70
void updateSiblingPositions(void)
Definition: Menu.cc:306
Definition: Object.h:47
void gh_callback_event(const graphics_handle &h, const std::string &name)
static Object * parentObject(octave::interpreter &interp, const graphics_object &go)
Definition: Object.cc:200
graphics_handle m_handle
Definition: Object.h:153
static Object * fromQObject(QObject *obj)
Definition: Object.cc:213
graphics_object object(void) const
Definition: Object.cc:82
virtual QObject * qObject(void)
Definition: Object.h:78
virtual void update(int pId)
Definition: Object.cc:163
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
const Qt::KeyboardModifier CTRL
QString fromStdString(const std::string &s)
T::properties & properties(graphics_object obj)