GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
QtHandlesUtils.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 <list>
31
32#include <QApplication>
33#include <QKeyEvent>
34#include <QMouseEvent>
35
36#include "Container.h"
37#include "KeyMap.h"
38#include "Object.h"
39#include "QtHandlesUtils.h"
40#include "qt-graphics-toolkit.h"
41
42#include "oct-string.h"
43
44#include "graphics.h"
45#include "ov.h"
46
47namespace octave
48{
49
50 namespace Utils
51 {
52
53 QString
54 fromStdString (const std::string& s)
55 {
56 return QString::fromUtf8 (s.c_str ());
57 }
58
59 std::string
60 toStdString (const QString& s)
61 {
62 return std::string (s.toUtf8 ().data ());
63 }
64
65 QStringList
67 {
68 QStringList l;
69 octave_idx_type n = v.numel ();
70
71 for (octave_idx_type i = 0; i < n; i++)
72 l << fromStdString (v[i]);
73
74 return l;
75 }
76
78 toStringVector (const QStringList& l)
79 {
80 string_vector v (l.length ());
81 int i = 0;
82
83 for (const auto& s : l)
84 v[i++] = toStdString (s);
85
86 return v;
87 }
88
89 Cell toCellString (const QStringList& l)
90 {
91 QStringList tmp = l;
92
93 // don't get any empty lines from end of the list
94 while ((tmp.length () > 0) && tmp.last ().isEmpty ())
95 {
96 tmp.removeLast ();
97 }
98 // no strings converts to a 1x1 cell with empty string
99 if (tmp.isEmpty ())
100 tmp += "";
101
102 Cell v (toStringVector (tmp));
103 return v;
104 }
105
106 template <typename T>
107 QFont
108 computeFont (const typename T::properties& props, int height)
109 {
110 QFont f (fromStdString (props.get_fontname ()));
111
112 static std::map<std::string, QFont::Weight> weightMap;
113 static std::map<std::string, QFont::Style> angleMap;
114 static bool mapsInitialized = false;
115
116 if (! mapsInitialized)
117 {
118 weightMap["normal"] = QFont::Normal;
119 weightMap["bold"] = QFont::Bold;
120
121 angleMap["normal"] = QFont::StyleNormal;
122 angleMap["italic"] = QFont::StyleItalic;
123 angleMap["oblique"] = QFont::StyleOblique;
124
125 mapsInitialized = true;
126 }
127
128 f.setPointSizeF (props.get___fontsize_points__ (height));
129 f.setWeight (weightMap[props.get_fontweight ()]);
130 f.setStyle (angleMap[props.get_fontangle ()]);
131
132 return f;
133 }
134
135 template QFont computeFont<uicontrol> (const uicontrol::properties& props,
136 int height);
137
138 template QFont computeFont<uipanel> (const uipanel::properties& props,
139 int height);
140
142 props,
143 int height);
144
145 template QFont computeFont<uitable> (const uitable::properties& props,
146 int height);
147
148 QColor
149 fromRgb (const Matrix& rgb)
150 {
151 QColor c;
152
153 if (rgb.numel () == 3)
154 c.setRgbF (rgb(0), rgb(1), rgb(2));
155
156 return c;
157 }
158
159 Matrix
160 toRgb (const QColor& c)
161 {
162 Matrix rgb (1, 3);
163 double *rgbData = rgb.fortran_vec ();
164
165 // qreal is a typedef for double except for ARM CPU architectures
166 // where it is a typedef for float (Bug #44970).
167 qreal tmp[3];
168 c.getRgbF (tmp, tmp+1, tmp+2);
169 rgbData[0] = tmp[0]; rgbData[1] = tmp[1]; rgbData[2] = tmp[2];
170
171 return rgb;
172 }
173
174 std::string
175 figureSelectionType (QMouseEvent *event, bool isDoubleClick)
176 {
177 if (isDoubleClick)
178 return "open";
179 else
180 {
181 Qt::MouseButtons buttons = event->buttons ();
182 Qt::KeyboardModifiers mods = event->modifiers ();
183
184 if (mods == Qt::NoModifier)
185 {
186 if (buttons == Qt::LeftButton)
187 return "normal";
188 else if (buttons == Qt::RightButton)
189 return "alt";
190 else if (buttons == Qt::MiddleButton
191 || buttons == (Qt::LeftButton | Qt::RightButton))
192 return "extend";
193 }
194 else if (buttons == Qt::LeftButton)
195 {
196 if (mods == Qt::ShiftModifier)
197 return "extend";
198 else if (mods == Qt::ControlModifier)
199 return "alt";
200 }
201 }
202
203 return "normal";
204 }
205
206 /*
207 Two figureCurrentPoint() routines are required:
208 1) Used for QMouseEvents where cursor position data is in callback from Qt.
209 2) Used for QKeyEvents where cursor position must be determined.
210 */
211 Matrix
212 figureCurrentPoint (const graphics_object& fig, QMouseEvent *event)
213 {
215
216 if (tkFig)
217 {
218 Container *c = tkFig->innerContainer ();
219
220 if (c)
221 {
222 QPoint qp = c->mapFromGlobal (event->globalPos ());
223
224 return tkFig->properties<figure> ().map_from_boundingbox (qp.x (),
225 qp.y ());
226 }
227 }
228
229 return Matrix (1, 2, 0.0);
230 }
231
232 Matrix
233 figureCurrentPoint (const graphics_object& fig)
234 {
236
237 if (tkFig)
238 {
239 Container *c = tkFig->innerContainer ();
240
241 if (c)
242 {
243 // FIXME: QCursor::pos() may give inaccurate results with
244 // asynchronous window systems like X11 over ssh.
245 QPoint qp = c->mapFromGlobal (QCursor::pos ());
246
247 return tkFig->properties<figure> ().map_from_boundingbox (qp.x (),
248 qp.y ());
249 }
250 }
251
252 return Matrix (1, 2, 0.0);
253 }
254
255 Qt::Alignment
256 fromHVAlign (const std::string& halign, const std::string& valign)
257 {
258 Qt::Alignment flags;
259
260 if (octave::string::strcmpi (halign, "left"))
261 flags |= Qt::AlignLeft;
262 else if (octave::string::strcmpi (halign, "center"))
263 flags |= Qt::AlignHCenter;
264 else if (octave::string::strcmpi (halign, "right"))
265 flags |= Qt::AlignRight;
266 else
267 flags |= Qt::AlignLeft;
268
269 if (octave::string::strcmpi (valign, "middle"))
270 flags |= Qt::AlignVCenter;
271 else if (octave::string::strcmpi (valign, "top"))
272 flags |= Qt::AlignTop;
273 else if (octave::string::strcmpi (valign, "bottom"))
274 flags |= Qt::AlignBottom;
275 else
276 flags |= Qt::AlignVCenter;
277
278 return flags;
279 }
280
281 QImage
282 makeImageFromCData (const octave_value& v, int width, int height)
283 {
284 dim_vector dv (v.dims ());
285
286 if (dv.ndims () == 3 && dv(2) == 3)
287 {
288 int w = qMin (dv(1), static_cast<octave_idx_type> (width));
289 int h = qMin (dv(0), static_cast<octave_idx_type> (height));
290
291 // If size mismatch, take data from center of CDATA and
292 // place in in center of QImage.
293 int x_img_off = (w < width ? (width - w) / 2 : 0);
294 int y_img_off = (h < height ? (height - h) / 2 : 0);
295 int x_cdat_off = (dv(1) > w ? (dv(1) - w) / 2 : 0);
296 int y_cdat_off = (dv(0) > h ? (dv(0) - h) / 2 : 0);
297
298 QImage img (width, height, QImage::Format_ARGB32);
299 img.fill (qRgba (0, 0, 0, 0));
300
301 if (v.is_uint8_type ())
302 {
304
305 for (int i = x_cdat_off; i < w + x_cdat_off; i++)
306 for (int j = y_cdat_off; j < h + y_cdat_off; j++)
307 {
308 int r = d(j, i, 0);
309 int g = d(j, i, 1);
310 int b = d(j, i, 2);
311 int a = 255;
312
313 img.setPixel (x_img_off + i - x_cdat_off,
314 y_img_off + j - y_cdat_off,
315 qRgba (r, g, b, a));
316 }
317 }
318 else if (v.is_single_type ())
319 {
321
322 for (int i = x_cdat_off; i < w + x_cdat_off; i++)
323 for (int j = y_cdat_off; j < h + y_cdat_off; j++)
324 {
325 float r = f(j, i, 0);
326 float g = f(j, i, 1);
327 float b = f(j, i, 2);
328 int a = (octave::math::isnan (r) || octave::math::isnan (g)
329 || octave::math::isnan (b) ? 0 : 255);
330
331 img.setPixel (x_img_off + i - x_cdat_off,
332 y_img_off + j - y_cdat_off,
333 qRgba (octave::math::round (r * 255),
334 octave::math::round (g * 255),
335 octave::math::round (b * 255),
336 a));
337 }
338 }
339 else if (v.isreal ())
340 {
341 NDArray d = v.array_value ();
342
343 for (int i = x_cdat_off; i < w + x_cdat_off; i++)
344 for (int j = y_cdat_off; j < h + y_cdat_off; j++)
345 {
346 double r = d(j, i, 0);
347 double g = d(j, i, 1);
348 double b = d(j, i, 2);
349 int a = (octave::math::isnan (r) || octave::math::isnan (g)
350 || octave::math::isnan (b) ? 0 : 255);
351
352 img.setPixel (x_img_off + i - x_cdat_off,
353 y_img_off + j - y_cdat_off,
354 qRgba (octave::math::round (r * 255),
355 octave::math::round (g * 255),
356 octave::math::round (b * 255),
357 a));
358 }
359 }
360
361 return img;
362 }
363
364 return QImage ();
365 }
366
368 makeKeyEventStruct (QKeyEvent *event)
369 {
370 octave_scalar_map retval;
371
372 retval.setfield ("Key", KeyMap::qKeyToKeyString (event->key ()));
373 retval.setfield ("Character", toStdString (event->text ()));
374
375 std::list<std::string> modList;
376 Qt::KeyboardModifiers mods = event->modifiers ();
377
378 if (mods & Qt::ShiftModifier)
379 modList.push_back ("shift");
380 if (mods & Qt::ControlModifier)
381#if defined (Q_OS_MAC)
382 modList.push_back ("command");
383#else
384 modList.push_back ("control");
385#endif
386 if (mods & Qt::AltModifier)
387 modList.push_back ("alt");
388#if defined (Q_OS_MAC)
389 if (mods & Qt::MetaModifier)
390 modList.push_back ("control");
391#endif
392
393 retval.setfield ("Modifier", Cell (modList));
394
395 return retval;
396 }
397
399 makeScrollEventStruct (QWheelEvent *event)
400 {
401 octave_scalar_map retval;
402
403 // We assume a standard mouse with 15 degree steps and Qt returns
404 // 1/8 of a degree.
405#if defined (HAVE_QWHEELEVENT_ANGLEDELTA)
406 int ydelta = -(event->angleDelta().y ());
407#else
408 int ydelta = -(event->delta ());
409#endif
410 retval.setfield ("VerticalScrollCount", octave_value (ydelta / 120));
411
412 // FIXME: Is there any way to access the number of lines a scroll step
413 // should correspond to?
414 retval.setfield ("VerticalScrollAmount", octave_value (3));
415 retval.setfield ("EventName", octave_value ("WindowScrollWheel"));
416
417 return retval;
418 }
419
420 }
421
422}
static int qp(const Matrix &H, const ColumnVector &q, const Matrix &Aeq, const ColumnVector &beq, const Matrix &Ain, const ColumnVector &bin, int maxit, double rtol, ColumnVector &x, ColumnVector &lambda, int &iter)
Definition: __qp__.cc:106
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:411
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array.cc:1744
Definition: Cell.h:43
Definition: dMatrix.h:42
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:257
virtual Container * innerContainer(void)=0
base_properties & properties(void)
Definition: Object.h:60
static Object * toolkitObject(const graphics_object &go)
void setfield(const std::string &key, const octave_value &val)
Definition: oct-map.cc:190
bool isreal(void) const
Definition: ov.h:783
uint8NDArray uint8_array_value(void) const
Definition: ov.h:1007
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:904
bool is_single_type(void) const
Definition: ov.h:743
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:907
bool is_uint8_type(void) const
Definition: ov.h:763
dim_vector dims(void) const
Definition: ov.h:586
octave_idx_type numel(void) const
Definition: str-vec.h:100
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
class OCTAVE_API Matrix
Definition: mx-fwd.h:31
std::complex< double > w(std::complex< double > z, double relerr=0)
std::string qKeyToKeyString(int key)
Definition: KeyMap.cc:253
octave_scalar_map makeScrollEventStruct(QWheelEvent *event)
QImage makeImageFromCData(const octave_value &v, int width, int height)
QStringList fromStringVector(const string_vector &v)
QColor fromRgb(const Matrix &rgb)
QString fromStdString(const std::string &s)
template QFont computeFont< uitable >(const uitable::properties &props, int height)
std::string figureSelectionType(QMouseEvent *event, bool isDoubleClick)
QFont computeFont(const typename T::properties &props, int height)
Qt::Alignment fromHVAlign(const std::string &halign, const std::string &valign)
T::properties & properties(graphics_object obj)
Matrix toRgb(const QColor &c)
octave_scalar_map makeKeyEventStruct(QKeyEvent *event)
Cell toCellString(const QStringList &l)
template QFont computeFont< uipanel >(const uipanel::properties &props, int height)
std::string toStdString(const QString &s)
template QFont computeFont< uicontrol >(const uicontrol::properties &props, int height)
template QFont computeFont< uibuttongroup >(const uibuttongroup::properties &props, int height)
string_vector toStringVector(const QStringList &l)
Matrix figureCurrentPoint(const graphics_object &fig, QMouseEvent *event)
bool isnan(bool)
Definition: lo-mappers.h:178
double round(double x)
Definition: lo-mappers.h:136
OCTAVE_API bool strcmpi(const T &str_a, const T &str_b)
True if strings are the same, ignoring case.
static double f(double k, double l_nu, double c_pm)
Definition: randpoisson.cc:118