GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
BaseControl.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 <QEvent>
31 #include <QKeyEvent>
32 #include <QMouseEvent>
33 #include <QWidget>
34 
35 #include "BaseControl.h"
36 #include "ContextMenu.h"
37 #include "QtHandlesUtils.h"
38 
39 #include "graphics.h"
40 #include "interpreter.h"
41 
43 
44 static void
46 {
47  QPalette p = w->palette ();
48 
49  if (props.style_is ("edit")
50  || props.style_is ("listbox"))
51  {
52  Matrix bg_color = props.get_backgroundcolor_rgb ();
53  // Matlab compatibility: Default color is ignored, and rendered as
54  // white ([1.0, 1.0, 1.0]). See bug #58261.
55  if (bg_color(0) == bg_color(1) && bg_color(0) == bg_color(2)
56  && (std::abs (bg_color(1) - 0.94) < .005))
57  bg_color.fill (1.0);
58 
59  p.setColor (QPalette::Active, QPalette::Base,
60  Utils::fromRgb (bg_color));
61  p.setColor (QPalette::Inactive, QPalette::Base,
62  Utils::fromRgb (bg_color));
63  p.setColor (QPalette::Active, QPalette::Text,
64  Utils::fromRgb (props.get_foregroundcolor_rgb ()));
65  p.setColor (QPalette::Inactive, QPalette::Text,
66  Utils::fromRgb (props.get_foregroundcolor_rgb ()));
67  }
68  else if (props.style_is ("popupmenu"))
69  {
70  // popupmenu (QComboBox) is a listbox with a button.
71  // This requires setting colors for both.
72  QColor bcol = Utils::fromRgb (props.get_backgroundcolor_rgb ());
73  QColor fcol = Utils::fromRgb (props.get_foregroundcolor_rgb ());
74  QString qss = QString (":enabled { background: %1 none;\n"
75  "color: %2; }")
76  .arg(bcol.name ()).arg (fcol.name ());
77  w->setStyleSheet(qss);
78  return;
79  }
80  else if (props.style_is ("radiobutton")
81  || props.style_is ("checkbox"))
82  {
83  p.setColor (QPalette::Active, QPalette::Button,
84  Utils::fromRgb (props.get_backgroundcolor_rgb ()));
85  p.setColor (QPalette::Inactive, QPalette::Button,
86  Utils::fromRgb (props.get_backgroundcolor_rgb ()));
87  p.setColor (QPalette::Active, QPalette::WindowText,
88  Utils::fromRgb (props.get_foregroundcolor_rgb ()));
89  p.setColor (QPalette::Inactive, QPalette::WindowText,
90  Utils::fromRgb (props.get_foregroundcolor_rgb ()));
91  }
92  else if (props.style_is ("pushbutton")
93  || props.style_is ("togglebutton"))
94  {
95  QColor bcol = Utils::fromRgb (props.get_backgroundcolor_rgb ());
96  QColor fcol = Utils::fromRgb (props.get_foregroundcolor_rgb ());
97  QString qss = QString (":enabled { background: %1 none;\n"
98  "color: %2; }")
99  .arg(bcol.name ()).arg (fcol.name ());
100  w->setStyleSheet(qss);
101  return;
102  }
103  else
104  {
105  p.setColor (QPalette::Active, QPalette::Window,
106  Utils::fromRgb (props.get_backgroundcolor_rgb ()));
107  p.setColor (QPalette::Inactive, QPalette::Window,
108  Utils::fromRgb (props.get_backgroundcolor_rgb ()));
109  p.setColor (QPalette::Active, QPalette::WindowText,
110  Utils::fromRgb (props.get_foregroundcolor_rgb ()));
111  p.setColor (QPalette::Inactive, QPalette::WindowText,
112  Utils::fromRgb (props.get_foregroundcolor_rgb ()));
113  }
114 
115  w->setPalette (p);
116 }
117 
118 BaseControl::BaseControl (octave::base_qobject& oct_qobj,
119  octave::interpreter& interp,
120  const graphics_object& go, QWidget *w)
121  : Object (oct_qobj, interp, go, w), m_normalizedFont (false),
122  m_keyPressHandlerDefined (false)
123 {
124  qObject ()->setObjectName ("UIControl");
125  init (w);
126 }
127 
128 void
129 BaseControl::init (QWidget *w, bool callBase)
130 {
131  if (callBase)
132  Object::init (w, callBase);
133 
134  uicontrol::properties& up = properties<uicontrol> ();
135 
136  Matrix bb = up.get_boundingbox (false);
137  w->setGeometry (octave::math::round (bb(0)), octave::math::round (bb(1)),
138  octave::math::round (bb(2)), octave::math::round (bb(3)));
139  w->setFont (Utils::computeFont<uicontrol> (up, bb(3)));
140  updatePalette (up, w);
141  if (up.enable_is ("inactive"))
142  w->blockSignals (true);
143  else
144  w->setEnabled (up.enable_is ("on"));
145  w->setToolTip (Utils::fromStdString (up.get_tooltipstring ()));
146  w->setVisible (up.is_visible ());
147  m_keyPressHandlerDefined = ! up.get_keypressfcn ().isempty ();
148 
149  w->installEventFilter (this);
150 
151  m_normalizedFont = up.fontunits_is ("normalized");
152 }
153 
155 { }
156 
157 void
159 {
160  update (uicontrol::properties::ID_POSITION);
161 }
162 
163 void
165 {
166  uicontrol::properties& up = properties<uicontrol> ();
167  QWidget *w = qWidget<QWidget> ();
168 
169  switch (pId)
170  {
171  case uicontrol::properties::ID_POSITION:
172  {
173  Matrix bb = up.get_boundingbox (false);
174  w->setGeometry (octave::math::round (bb(0)), octave::math::round (bb(1)),
175  octave::math::round (bb(2)), octave::math::round (bb(3)));
176  }
177  break;
178 
179  case uicontrol::properties::ID_FONTNAME:
180  case uicontrol::properties::ID_FONTSIZE:
181  case uicontrol::properties::ID_FONTWEIGHT:
182  case uicontrol::properties::ID_FONTANGLE:
183  w->setFont (Utils::computeFont<uicontrol> (up));
184  break;
185 
186  case uicontrol::properties::ID_FONTUNITS:
187  // FIXME: We shouldn't have to do anything, octave should update
188  // the "fontsize" property automatically to the new units.
189  // Hence the actual font used shouldn't change.
190  m_normalizedFont = up.fontunits_is ("normalized");
191  break;
192 
193  case uicontrol::properties::ID_BACKGROUNDCOLOR:
194  case uicontrol::properties::ID_FOREGROUNDCOLOR:
195  updatePalette (up, w);
196  break;
197 
198  case uicontrol::properties::ID_ENABLE:
199  if (up.enable_is ("inactive"))
200  {
201  w->blockSignals (true);
202  w->setEnabled (true);
203  }
204  else
205  {
206  w->blockSignals (false);
207  w->setEnabled (up.enable_is ("on"));
208  }
209  break;
210 
211  case uicontrol::properties::ID_TOOLTIPSTRING:
212  w->setToolTip (Utils::fromStdString (up.get_tooltipstring ()));
213  break;
214 
215  case base_properties::ID_VISIBLE:
216  w->setVisible (up.is_visible ());
217  break;
218 
219  case uicontrol::properties::ID_KEYPRESSFCN:
220  m_keyPressHandlerDefined = ! up.get_keypressfcn ().isempty ();
221  break;
222 
223  case uicontrol::properties::ID___FOCUS__:
224  if (up.is___focus__ ())
225  w->setFocus ();
226  else
227  w->clearFocus ();
228  break;
229 
230  default:
231  break;
232  }
233 }
234 
235 bool
236 BaseControl::eventFilter (QObject *watched, QEvent *xevent)
237 {
238  gh_manager& gh_mgr = m_interpreter.get_gh_manager ();
239 
240  switch (xevent->type ())
241  {
242  case QEvent::Resize:
243  if (m_normalizedFont)
244  {
245  octave::autolock guard (gh_mgr.graphics_lock ());
246 
247  qWidget<QWidget> ()->setFont (Utils::computeFont<uicontrol>
248  (properties<uicontrol> ()));
249  }
250  break;
251 
252  case QEvent::MouseButtonPress:
253  {
254  octave::autolock guard (gh_mgr.graphics_lock ());
255 
256  QMouseEvent *m = dynamic_cast<QMouseEvent *> (xevent);
257  graphics_object go = object ();
258  uicontrol::properties& up = Utils::properties<uicontrol> (go);
259  graphics_object fig = go.get_ancestor ("figure");
260  if (fig)
261  {
262  emit gh_set_event (fig.get_handle (), "currentobject",
263  m_handle.value (), false);
264 
265  if (m->button () != Qt::LeftButton || ! up.enable_is ("on"))
266  {
267  emit gh_set_event (fig.get_handle (), "selectiontype",
268  Utils::figureSelectionType (m), false);
269  emit gh_set_event (fig.get_handle (), "currentpoint",
271  false);
272  emit gh_callback_event (fig.get_handle (),
273  "windowbuttondownfcn");
274  emit gh_callback_event (m_handle, "buttondownfcn");
275 
276  if (m->button () == Qt::RightButton)
277  ContextMenu::executeAt (m_interpreter, up, m->globalPos ());
278  }
279  else
280  {
281  if (up.style_is ("listbox"))
282  emit gh_set_event (fig.get_handle (), "selectiontype",
284  false);
285  else
286  emit gh_set_event (fig.get_handle (), "selectiontype",
287  octave_value ("normal"), false);
288  }
289  }
290  }
291  break;
292 
293  case QEvent::MouseMove:
294  if (qWidget<QWidget> ()->hasMouseTracking ())
295  {
296  octave::autolock guard (gh_mgr.graphics_lock ());
297 
298  QMouseEvent *m = dynamic_cast<QMouseEvent *> (xevent);
299  graphics_object go = object ();
300  graphics_object fig = go.get_ancestor ("figure");
301 
302  if (fig)
303  {
304  emit gh_set_event (fig.get_handle (), "currentpoint",
305  Utils::figureCurrentPoint (fig, m), false);
306  emit gh_callback_event (fig.get_handle (),
307  "windowbuttonmotionfcn");
308  }
309  }
310  break;
311 
312  case QEvent::KeyPress:
314  {
315  octave::autolock guard (gh_mgr.graphics_lock ());
316 
317  octave_scalar_map keyData =
318  Utils::makeKeyEventStruct (dynamic_cast<QKeyEvent *> (xevent));
319  graphics_object fig = object ().get_ancestor ("figure");
320 
321  emit gh_set_event (fig.get_handle (), "currentcharacter",
322  keyData.getfield ("Character"), false);
323  emit gh_callback_event (m_handle, "keypressfcn", keyData);
324  }
325  break;
326 
327  case QEvent::FocusIn:
328  emit gh_set_event (m_handle, "__focus__", "on", false);
329  break;
330 
331  case QEvent::FocusOut:
332  emit gh_set_event (m_handle, "__focus__", "off", false);
333  break;
334 
335  default:
336  break;
337  }
338 
339  return Object::eventFilter (watched, xevent);
340 }
341 
static void updatePalette(const uicontrol::properties &props, QWidget *w)
Definition: BaseControl.cc:45
OCTAVE_END_NAMESPACE(octave)
void redraw(void)
Definition: BaseControl.cc:158
~BaseControl(void)
Definition: BaseControl.cc:154
bool eventFilter(QObject *watched, QEvent *e)
Definition: BaseControl.cc:236
bool m_keyPressHandlerDefined
Definition: BaseControl.h:57
BaseControl(octave::base_qobject &oct_qobj, octave::interpreter &interp, const graphics_object &go, QWidget *w)
Definition: BaseControl.cc:118
void init(QWidget *w, bool callBase=false)
Definition: BaseControl.cc:129
void update(int pId)
Definition: BaseControl.cc:164
bool m_normalizedFont
Definition: BaseControl.h:56
static void executeAt(octave::interpreter &interp, const base_properties &props, const QPoint &pt)
Definition: ContextMenu.cc:122
Definition: dMatrix.h:42
OCTAVE_API Matrix & fill(double val)
Definition: dMatrix.cc:221
Definition: Object.h:47
void gh_callback_event(const graphics_handle &h, const std::string &name)
graphics_handle m_handle
Definition: Object.h:153
void gh_set_event(const graphics_handle &h, const std::string &name, const octave_value &value)
graphics_object object(void) const
Definition: Object.cc:82
virtual QObject * qObject(void)
Definition: Object.h:78
octave::interpreter & m_interpreter
Definition: Object.h:136
void init(QObject *obj, bool callBase=false)
Definition: Object.cc:61
double value(void) const
Definition: oct-handle.h:78
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:183
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
double round(double x)
Definition: lo-mappers.h:136
T octave_idx_type m
Definition: mx-inlines.cc:773
std::complex< double > w(std::complex< double > z, double relerr=0)
Matrix figureCurrentPoint(const graphics_object &fig, QMouseEvent *event)
QString fromStdString(const std::string &s)
octave_scalar_map makeKeyEventStruct(QKeyEvent *event)
template QFont computeFont< uicontrol >(const uicontrol::properties &props, int height)
std::string figureSelectionType(QMouseEvent *event, bool isDoubleClick)
QColor fromRgb(const Matrix &rgb)
T::properties & properties(graphics_object obj)
static T abs(T x)
Definition: pr-output.cc:1678