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