GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
Panel.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 <QFrame>
32 #include <QLabel>
33 #include <QMouseEvent>
34 #include <QTimer>
35 
36 #include "Canvas.h"
37 #include "Container.h"
38 #include "ContextMenu.h"
39 #include "Panel.h"
40 #include "QtHandlesUtils.h"
41 
42 #include "octave-qobject.h"
43 
44 #include "graphics.h"
45 #include "interpreter.h"
46 
48 
49 static int
51 {
52  if (pp.bordertype_is ("none"))
53  return QFrame::NoFrame;
54  else if (pp.bordertype_is ("etchedin"))
55  return (QFrame::Box | QFrame::Sunken);
56  else if (pp.bordertype_is ("etchedout"))
57  return (QFrame::Box | QFrame::Raised);
58  else if (pp.bordertype_is ("beveledin"))
59  return (QFrame::Panel | QFrame::Sunken);
60  else if (pp.bordertype_is ("beveledout"))
61  return (QFrame::Panel | QFrame::Raised);
62  else
63  return (QFrame::Panel | QFrame::Plain);
64 }
65 
66 static void
67 setupPalette (const uipanel::properties& pp, QPalette& p)
68 {
69  p.setColor (QPalette::Window,
70  Utils::fromRgb (pp.get_backgroundcolor_rgb ()));
71  p.setColor (QPalette::WindowText,
72  Utils::fromRgb (pp.get_foregroundcolor_rgb ()));
73  p.setColor (QPalette::Light,
74  Utils::fromRgb (pp.get_highlightcolor_rgb ()));
75  p.setColor (QPalette::Dark,
76  Utils::fromRgb (pp.get_shadowcolor_rgb ()));
77 }
78 
79 static int
81 {
82  int bw = 0;
83 
84  if (! pp.bordertype_is ("none"))
85  {
86  bw = octave::math::round (pp.get_borderwidth ());
87  if (pp.bordertype_is ("etchedin") || pp.bordertype_is ("etchedout"))
88  bw *= 2;
89  }
90 
91  return bw;
92 }
93 
94 Panel *
95 Panel::create (octave::base_qobject& oct_qobj, octave::interpreter& interp,
96  const graphics_object& go)
97 {
98  Object *parent = parentObject (interp, go);
99 
100  if (parent)
101  {
102  Container *container = parent->innerContainer ();
103 
104  if (container)
105  return new Panel (oct_qobj, interp, go, new QFrame (container));
106  }
107 
108  return nullptr;
109 }
110 
111 Panel::Panel (octave::base_qobject& oct_qobj, octave::interpreter& interp,
112  const graphics_object& go, QFrame *frame)
113  : Object (oct_qobj, interp, go, frame), m_container (nullptr),
114  m_title (nullptr), m_blockUpdates (false),
115  m_previous_bbox (Matrix (1, 4, 0))
116 {
117  uipanel::properties& pp = properties<uipanel> ();
118 
119  frame->setObjectName ("UIPanel");
120  frame->setAutoFillBackground (true);
121  Matrix bb = pp.get_boundingbox (false);
122  frame->setGeometry (octave::math::round (bb(0)), octave::math::round (bb(1)),
123  octave::math::round (bb(2)), octave::math::round (bb(3)));
124  frame->setFrameStyle (frameStyleFromProperties (pp));
125  frame->setLineWidth (octave::math::round (pp.get_borderwidth ()));
126  QPalette pal = frame->palette ();
127  setupPalette (pp, pal);
128  frame->setPalette (pal);
129 
130  m_container = new Container (frame, oct_qobj, interp);
132 
133  connect (m_container, SIGNAL (interpeter_event (const fcn_callback&)),
134  this, SIGNAL (interpeter_event (const fcn_callback&)));
135 
136  connect (m_container, SIGNAL (interpeter_event (const meth_callback&)),
137  this, SIGNAL (interpeter_event (const meth_callback&)));
138 
139  if (frame->hasMouseTracking ())
140  {
141  for (auto *w : frame->findChildren<QWidget *> ())
142  w->setMouseTracking (true);
143  }
144 
145  QString title = Utils::fromStdString (pp.get_title ());
146  if (! title.isEmpty ())
147  {
148  m_title = new QLabel (title, frame);
149  m_title->setAutoFillBackground (true);
150  m_title->setContentsMargins (4, 0, 4, 0);
151  m_title->setPalette (pal);
152  m_title->setFont (Utils::computeFont<uipanel> (pp, bb(3)));
153  }
154 
155  frame->installEventFilter (this);
156  m_container->installEventFilter (this);
157 
158  graphics_object fig (go.get_ancestor ("figure"));
159  if (! fig.get ("keypressfcn").isempty ())
161 
162  if (! fig.get ("keyreleasefcn").isempty ())
164 
165  if (pp.is_visible ())
166  QTimer::singleShot (0, frame, &QFrame::show);
167  else
168  frame->hide ();
169 }
170 
172 { }
173 
174 bool
175 Panel::eventFilter (QObject *watched, QEvent *xevent)
176 {
177  if (! m_blockUpdates)
178  {
179  gh_manager& gh_mgr = m_interpreter.get_gh_manager ();
180 
181  if (watched == qObject ())
182  {
183  switch (xevent->type ())
184  {
185  case QEvent::Resize:
186  {
187  octave::autolock guard (gh_mgr.graphics_lock ());
188 
189  graphics_object go = object ();
190 
191  if (go.valid_object ())
192  {
193  if (m_title)
194  {
195  const uipanel::properties& pp =
196  Utils::properties<uipanel> (go);
197 
198  if (pp.fontunits_is ("normalized"))
199  {
200  QFrame *frame = qWidget<QFrame> ();
201 
203  (pp, frame->height ()));
204  m_title->resize (m_title->sizeHint ());
205  }
206  }
207  updateLayout ();
208  }
209  }
210  break;
211 
212  case QEvent::MouseButtonPress:
213  {
214  QMouseEvent *m = dynamic_cast<QMouseEvent *> (xevent);
215 
216  if (m->button () == Qt::RightButton)
217  {
218  octave::autolock guard (gh_mgr.graphics_lock ());
219 
220  graphics_object go = object ();
221 
222  if (go.valid_object ())
224  go.get_properties (),
225  m->globalPos ());
226  }
227  }
228  break;
229 
230  default:
231  break;
232  }
233  }
234  else if (watched == m_container)
235  {
236  switch (xevent->type ())
237  {
238  case QEvent::Resize:
239  if (qWidget<QWidget> ()->isVisible ())
240  {
241  octave::autolock guard (gh_mgr.graphics_lock ());
242 
243  graphics_object go = object ();
244 
245  if (go.valid_object ())
246  go.get_properties ().update_boundingbox ();
247  }
248  break;
249 
250  default:
251  break;
252  }
253  }
254  }
255 
256  return false;
257 }
258 
259 void
260 Panel::update (int pId)
261 {
262  uipanel::properties& pp = properties<uipanel> ();
263  QFrame *frame = qWidget<QFrame> ();
264 
265  m_blockUpdates = true;
266 
267  switch (pId)
268  {
269  case uipanel::properties::ID_POSITION:
270  {
271  Matrix bb = pp.get_boundingbox (false);
272  if (m_previous_bbox(0) != bb(0) || m_previous_bbox(1) != bb(1)
273  || m_previous_bbox(2) != bb(2) || m_previous_bbox(3) != bb(3))
274  {
275  frame->setGeometry (octave::math::round (bb(0)),
276  octave::math::round (bb(1)),
277  octave::math::round (bb(2)),
278  octave::math::round (bb(3)));
279  updateLayout ();
280  }
281  m_previous_bbox = bb;
282  }
283  break;
284 
285  case uipanel::properties::ID_BORDERWIDTH:
286  frame->setLineWidth (octave::math::round (pp.get_borderwidth ()));
287  updateLayout ();
288  break;
289 
290  case uipanel::properties::ID_BACKGROUNDCOLOR:
291  case uipanel::properties::ID_FOREGROUNDCOLOR:
292  case uipanel::properties::ID_HIGHLIGHTCOLOR:
293  case uipanel::properties::ID_SHADOWCOLOR:
294  {
295  QPalette pal = frame->palette ();
296 
297  setupPalette (pp, pal);
298  frame->setPalette (pal);
299  if (m_title)
300  m_title->setPalette (pal);
301  }
302  break;
303 
304  case uipanel::properties::ID_TITLE:
305  {
306  QString title = Utils::fromStdString (pp.get_title ());
307 
308  if (title.isEmpty ())
309  {
310  if (m_title)
311  delete m_title;
312  m_title = nullptr;
313  }
314  else
315  {
316  if (! m_title)
317  {
318  QPalette pal = frame->palette ();
319 
320  m_title = new QLabel (title, frame);
321  m_title->setAutoFillBackground (true);
322  m_title->setContentsMargins (4, 0, 4, 0);
323  m_title->setPalette (pal);
324  m_title->setFont (Utils::computeFont<uipanel> (pp));
325  m_title->show ();
326  }
327  else
328  {
329  m_title->setText (title);
330  m_title->resize (m_title->sizeHint ());
331  }
332  }
333  updateLayout ();
334  }
335  break;
336 
337  case uipanel::properties::ID_TITLEPOSITION:
338  updateLayout ();
339  break;
340 
341  case uipanel::properties::ID_BORDERTYPE:
342  frame->setFrameStyle (frameStyleFromProperties (pp));
343  updateLayout ();
344  break;
345 
346  case uipanel::properties::ID_FONTNAME:
347  case uipanel::properties::ID_FONTSIZE:
348  case uipanel::properties::ID_FONTWEIGHT:
349  case uipanel::properties::ID_FONTANGLE:
350  if (m_title)
351  {
352  m_title->setFont (Utils::computeFont<uipanel> (pp));
353  m_title->resize (m_title->sizeHint ());
354  updateLayout ();
355  }
356  break;
357 
358  case uipanel::properties::ID_VISIBLE:
359  frame->setVisible (pp.is_visible ());
360  updateLayout ();
361  break;
362 
363  default:
364  break;
365  }
366 
367  m_blockUpdates = false;
368 }
369 
370 void
372 {
373  update (uipanel::properties::ID_POSITION);
374 
375  Canvas *canvas = m_container->canvas (m_handle);
376 
377  if (canvas)
378  canvas->redraw ();
379 }
380 
381 void
383 {
384  uipanel::properties& pp = properties<uipanel> ();
385  QFrame *frame = qWidget<QFrame> ();
386 
387  Matrix bb = pp.get_boundingbox (true);
388  int bw = borderWidthFromProperties (pp);
389 
390  frame->setFrameRect (QRect (octave::math::round (bb(0)) - bw,
391  octave::math::round (bb(1)) - bw,
392  octave::math::round (bb(2)) + 2*bw, octave::math::round (bb(3)) + 2*bw));
393  m_container->setGeometry (octave::math::round (bb(0)),
394  octave::math::round (bb(1)),
395  octave::math::round (bb(2)), octave::math::round (bb(3)));
396 
397  if (m_blockUpdates)
398  pp.update_boundingbox ();
399 
400  if (m_title)
401  {
402  QSize sz = m_title->sizeHint ();
403  int offset = 5;
404 
405  if (pp.titleposition_is ("lefttop"))
406  m_title->move (bw+offset, 0);
407  else if (pp.titleposition_is ("righttop"))
408  m_title->move (frame->width () - bw - offset - sz.width (), 0);
409  else if (pp.titleposition_is ("leftbottom"))
410  m_title->move (bw+offset, frame->height () - sz.height ());
411  else if (pp.titleposition_is ("rightbottom"))
412  m_title->move (frame->width () - bw - offset - sz.width (),
413  frame->height () - sz.height ());
414  else if (pp.titleposition_is ("centertop"))
415  m_title->move (frame->width () / 2 - sz.width () / 2, 0);
416  else if (pp.titleposition_is ("centerbottom"))
417  m_title->move (frame->width () / 2 - sz.width () / 2,
418  frame->height () - sz.height ());
419  }
420 }
421 
422 void
423 Panel::do_connections (const QObject *receiver, const QObject * /* emitter */)
424 {
425  Object::do_connections (receiver);
427 }
428 
OCTAVE_END_NAMESPACE(octave)
static int frameStyleFromProperties(const uipanel::properties &pp)
Definition: Panel.cc:50
static int borderWidthFromProperties(const uipanel::properties &pp)
Definition: Panel.cc:80
static void setupPalette(const uipanel::properties &pp, QPalette &p)
Definition: Panel.cc:67
Definition: Canvas.h:50
void addEventMask(int m)
Definition: Canvas.h:71
void redraw(bool sync=false)
Definition: Canvas.cc:57
@ KeyRelease
Definition: Canvas.h:57
@ KeyPress
Definition: Canvas.h:56
Canvas * canvas(const graphics_handle &handle, bool create=true)
Definition: Container.cc:55
static void executeAt(octave::interpreter &interp, const base_properties &props, const QPoint &pt)
Definition: ContextMenu.cc:122
Definition: dMatrix.h:42
Definition: Object.h:47
static Object * parentObject(octave::interpreter &interp, const graphics_object &go)
Definition: Object.cc:200
virtual void do_connections(const QObject *receiver, const QObject *emitter=nullptr)
Definition: Object.cc:224
graphics_handle m_handle
Definition: Object.h:153
graphics_object object(void) const
Definition: Object.cc:82
virtual QObject * qObject(void)
Definition: Object.h:78
virtual Container * innerContainer(void)=0
octave::interpreter & m_interpreter
Definition: Object.h:136
Definition: Panel.h:42
void update(int pId)
Definition: Panel.cc:260
void do_connections(const QObject *receiver, const QObject *emitter=nullptr)
Definition: Panel.cc:423
static Panel * create(octave::base_qobject &oct_qobj, octave::interpreter &interp, const graphics_object &go)
Definition: Panel.cc:95
void redraw(void)
Definition: Panel.cc:371
bool eventFilter(QObject *watched, QEvent *event)
Definition: Panel.cc:175
QLabel * m_title
Definition: Panel.h:68
Container * m_container
Definition: Panel.h:67
bool m_blockUpdates
Definition: Panel.h:69
Panel(octave::base_qobject &oct_qobj, octave::interpreter &interp, const graphics_object &go, QFrame *frame)
Definition: Panel.cc:111
~Panel(void)
Definition: Panel.cc:171
void updateLayout(void)
Definition: Panel.cc:382
Matrix m_previous_bbox
Definition: Panel.h:70
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
std::function< void(void)> fcn_callback
Definition: event-manager.h:43
std::function< void(interpreter &)> meth_callback
Definition: event-manager.h:48
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)
template QFont computeFont< uipanel >(const uipanel::properties &props, int height)
QString fromStdString(const std::string &s)
QColor fromRgb(const Matrix &rgb)
T::properties & properties(graphics_object obj)