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