Mercurial > octave
view libgui/graphics/Backend.cc @ 27303:07b330708e3c
use Qt signals for interpreter callbacks in Qt graphics toolkit
* Backend.h, Backend.cc (Backend::m_interpreter): New data member.
(Backend::createObject): Pass pointer to invoking Backend object in
signal argument list.
(Backend::interpreter_event): New slots. Access interpreter
event_manager to post interpreter callbacks events here.
* ObjectFactory.h, ObjectFactory.cc (ObjectFactory::createObject): New
arg, backend. Connect interpreter_event signal from newly created
object to interpreter_event slot in backend object.
* __init_qt__.cc (__init__): Pass interpreter to Backend constructor.
* module.mk (OCTAVE_GUI_GRAPHICS_MOC): New files, moc-Canvas.cc and
moc-Container.cc.
* Object.h (Object::interpreter_event): New signals.
* Canvas.h, Canvas.cc (Canvas::interprter_event): New signals.
(Canvas::canvasMouseReleaseEvent): Emit interpreter_event signal
instead of accessing interpreter event_manager object directly here.
* GLCanvas.cc (GLCanvas::do_print): Emit interpreter_event signal
instead of accessing interpreter event_manager object directly here.
* Container.h, Container.cc (Container::interpreter_event):
New signals.
(Container::canvas): Forward Canvas interpreter_event signals to
Container interpreter_event signals.
* ButtonGroup.cc (ButtonGroup::ButtonGroup) Forward Container
interpreter_event signals to the ButtonGroup interpreter_event
signal. Since ButtonGroup is derived from Object, this connection and
the one made by ObjectFactory::createObject has the effect of passing
the interpreter_event signal up to the Backend interpreter_event slot.
* Figure.cc (Figure::Figure): Likewise, for Figure.
* Panel.cc (Panel::Panel): Likewise, for Panel.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Mon, 29 Jul 2019 10:43:20 -0400 |
parents | e3d886685813 |
children | 22265a75be74 |
line wrap: on
line source
/* Copyright (C) 2011-2019 Michael Goffioul This file is part of Octave. Octave is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Octave; see the file COPYING. If not, see <https://www.gnu.org/licenses/>. */ #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include <cstdint> #include <QApplication> #include <QFontMetrics> #include <QThread> #include "Backend.h" #include "Logger.h" #include "Object.h" #include "ObjectFactory.h" #include "ObjectProxy.h" #include "QtHandlesUtils.h" #include "event-manager.h" #include "interpreter.h" //#if INTPTR_MAX == INT32_MAX //# define OCTAVE_PTR_TYPE octave_uint32 //# define OCTAVE_INTPTR_TYPE uint32_t //# define OCTAVE_PTR_SCALAR uint32_scalar_value //#else # define OCTAVE_PTR_TYPE octave_uint64 # define OCTAVE_INTPTR_TYPE uint64_t # define OCTAVE_PTR_SCALAR uint64_scalar_value //#endif namespace QtHandles { static std::string toolkitObjectProperty (const graphics_object& go) { if (go.isa ("figure")) return "__plot_stream__"; else if (go.isa ("uicontrol") || go.isa ("uipanel") || go.isa ("uibuttongroup") || go.isa ("uimenu") || go.isa ("uicontextmenu") || go.isa ("uitable") || go.isa ("uitoolbar") || go.isa ("uipushtool") || go.isa ("uitoggletool")) return "__object__"; else qCritical ("QtHandles::Backend: no __object__ property known for object " "of type %s", go.type ().c_str ()); return ""; } Backend::Backend (octave::interpreter& interp) : QObject (), base_graphics_toolkit ("qt"), m_interpreter (interp) { ObjectFactory *factory = ObjectFactory::instance (); connect (this, SIGNAL (createObject (Backend *, double)), factory, SLOT (createObject (Backend *, double)), Qt::BlockingQueuedConnection); } Backend::~Backend (void) { } bool Backend::initialize (const graphics_object& go) { if (go.isa ("figure") || go.isa ("uicontrol") || go.isa ("uipanel") || go.isa ("uibuttongroup") || go.isa ("uimenu") || go.isa ("uicontextmenu") || go.isa ("uitable") || go.isa ("uitoolbar") || go.isa ("uipushtool") || go.isa ("uitoggletool")) { // FIXME: We need to unlock the mutex here but we have no way to know if // if it was previously locked by this thread, and thus if we should // re-lock it. gh_manager::unlock (); Logger::debug ("Backend::initialize %s from thread %08x", go.type ().c_str (), QThread::currentThreadId ()); ObjectProxy *proxy = new ObjectProxy (); graphics_object gObj (go); OCTAVE_PTR_TYPE tmp (reinterpret_cast<OCTAVE_INTPTR_TYPE> (proxy)); gObj.get_properties ().set (toolkitObjectProperty (go), tmp); emit createObject (this, go.get_handle ().value ()); return true; } return false; } void Backend::update (const graphics_object& go, int pId) { // Rule out obvious properties we want to ignore. if (pId == figure::properties::ID___PLOT_STREAM__ || pId == uicontrol::properties::ID___OBJECT__ || pId == uipanel::properties::ID___OBJECT__ || pId == uibuttongroup::properties::ID___OBJECT__ || pId == uimenu::properties::ID___OBJECT__ || pId == uicontextmenu::properties::ID___OBJECT__ || pId == uitable::properties::ID___OBJECT__ || pId == uitoolbar::properties::ID___OBJECT__ || pId == uipushtool::properties::ID___OBJECT__ || pId == uitoggletool::properties::ID___OBJECT__ || pId == base_properties::ID___MODIFIED__) return; Logger::debug ("Backend::update %s(%d) from thread %08x", go.type ().c_str (), pId, QThread::currentThreadId ()); ObjectProxy *proxy = toolkitObjectProxy (go); if (proxy) { if (go.isa ("uicontrol") && pId == uicontrol::properties::ID_STYLE) { // Special case: we need to recreate the control widget // associated with the octave graphics_object finalize (go); initialize (go); } else proxy->update (pId); } } void Backend::finalize (const graphics_object& go) { // FIXME: We need to unlock the mutex here but we have no way to know if // if it was previously locked by this thread, and thus if we should // re-lock it. gh_manager::unlock (); Logger::debug ("Backend::finalize %s from thread %08x", go.type ().c_str (), QThread::currentThreadId ()); ObjectProxy *proxy = toolkitObjectProxy (go); if (proxy) { proxy->finalize (); delete proxy; graphics_object gObj (go); gObj.get_properties ().set (toolkitObjectProperty (go), Matrix ()); } } void Backend::redraw_figure (const graphics_object& go) const { if (go.get_properties ().is_visible ()) { ObjectProxy *proxy = toolkitObjectProxy (go); if (proxy) proxy->redraw (); } } void Backend::show_figure (const graphics_object& go) const { if (go.get_properties ().is_visible ()) { ObjectProxy *proxy = toolkitObjectProxy (go); if (proxy) proxy->show (); } } void Backend::print_figure (const graphics_object& go, const std::string& term, const std::string& file_cmd, const std::string& /*debug_file*/) const { ObjectProxy *proxy = toolkitObjectProxy (go); if (proxy) proxy->print (QString::fromStdString (file_cmd), QString::fromStdString (term)); } uint8NDArray Backend::get_pixels (const graphics_object& go) const { uint8NDArray retval; if (go.isa ("figure")) { ObjectProxy *proxy = toolkitObjectProxy (go); if (proxy) retval = proxy->get_pixels (); } return retval; } Matrix Backend::get_text_extent (const graphics_object& go) const { Matrix ext (1, 4, 0.0); if (go.isa ("uicontrol")) { octave_value str = go.get ("string"); if (! str.isempty ()) { const uicontrol::properties& up = dynamic_cast<const uicontrol::properties&> (go.get_properties ()); Matrix bb = up.get_boundingbox (false); QFont font = Utils::computeFont<uicontrol> (up, bb(3)); QFontMetrics fm (font); QString s; QSize sz; if (str.is_string ()) { s = QString::fromStdString (str.string_value ()); sz = fm.size (Qt::TextSingleLine, s); ext(2) = sz.width (); ext(3) = sz.height (); } else if (str.iscellstr ()) { string_vector sv = str.string_vector_value (); double wd = 0.0; double hg = 0.0; for (octave_idx_type ii = 0; ii < sv.numel (); ii++) { s = QString::fromStdString (sv(ii)); sz = fm.size (Qt::TextSingleLine, s); wd = std::max (wd, static_cast<double> (sz.width ())); hg = std::max (hg, static_cast<double> (sz.height ())); } ext(2) = wd; // FIXME: Find a better way to determine the height of e.g. // listbox uicontrol objects ext(3) = hg * sv.numel (); } } } return ext; } Object* Backend::toolkitObject (const graphics_object& go) { ObjectProxy *proxy = toolkitObjectProxy (go); if (proxy) return proxy->object (); return nullptr; } ObjectProxy* Backend::toolkitObjectProxy (const graphics_object& go) { if (go) { octave_value ov = go.get (toolkitObjectProperty (go)); if (ov.is_defined () && ! ov.isempty ()) { OCTAVE_INTPTR_TYPE ptr = ov.OCTAVE_PTR_SCALAR ().value (); return reinterpret_cast<ObjectProxy *> (ptr); } } return nullptr; } void Backend::interpreter_event (const octave::fcn_callback& fcn) { octave::event_manager& evmgr = m_interpreter.get_event_manager (); evmgr.post_event (fcn); } void Backend::interpreter_event (const octave::meth_callback& meth) { octave::event_manager& evmgr = m_interpreter.get_event_manager (); evmgr.post_event (meth); } };