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