Files
create/src/Gui/ParamHandler.h

232 lines
8.1 KiB
C++

/****************************************************************************
* Copyright (c) 2023 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef GUI_PARAM_HANDLER_H
#define GUI_PARAM_HANDLER_H
#include <map>
#include <memory>
#include <boost_signals2.hpp>
#include <QTimer>
#include <FCGlobal.h>
#include <App/Application.h>
#include <Base/Parameter.h>
namespace Gui {
/// Structure for storing a parameter key and its path to be used in std::map
struct GuiExport ParamKey {
ParameterGrp::handle hGrp;
const char *key;
ParamKey(const char *path, const char *key)
:hGrp(App::GetApplication().GetUserParameter().GetGroup(path))
,key(key)
{}
ParamKey(ParameterGrp *h, const char *key)
:hGrp(h), key(key)
{}
bool operator < (const ParamKey &other) const {
if (hGrp < other.hGrp)
return true;
if (hGrp > other.hGrp)
return false;
return strcmp(key, other.key) < 0;
}
};
/// Helper class to handle parameter change
class GuiExport ParamHandler {
public:
virtual ~ParamHandler() {}
/** Called when the corresponding parameter key changes
* @param key: the parameter key
* @return Returns true if the handler needs to be delay triggered by a timer
*/
virtual bool onChange(const ParamKey *key) = 0;
/// Called in delay triggered
virtual void onTimer() {}
};
/// Template class for a non-delayed parameter handler
template<class Func>
class ParamHandlerT : public ParamHandler
{
public:
ParamHandlerT(Func f)
:func(f)
{}
bool onChange(const ParamKey *key) override {
func(key);
return false;
}
private:
Func func;
};
/// Template class for a delayed parameter handler
template<class Func>
class ParamDelayedHandlerT : public ParamHandler
{
public:
ParamDelayedHandlerT(Func f)
:func(f)
{}
bool onChange(const ParamKey *) override {
return true;
}
void onTimer() override {
func();
}
private:
Func func;
};
// Helper class to manage handlers of a list of parameters.
//
// The handlers are stored in a map from ParamKey to shared pointer to a
// ParamHandler. The same handler can be registered with multiple keys. When
// the registered parameter key is changed, the manager will call the
// registered handler function ParamHandler::onChange(). If it returns True,
// then the handler will be appended to a queue to be invoked later by a timer
// to avoid repeatitive processing on change of multiple keys.
//
// The handler manager is meant to be initiated by some static function, e.g.
// DlgSettingsGeneral::attachObserver(). It is intended to be one and only
// place of handling changes of the given set of parameters, regardless of
// whether the changes are coming from direct editing through parameter editor,
// user code changing of parameters, changing preference dialog, or loading a
// preference pack.
//
class GuiExport ParamHandlers {
public:
ParamHandlers();
virtual ~ParamHandlers();
void addHandler(const ParamKey &key, const std::shared_ptr<ParamHandler> &handler);
void addHandler(const char *path, const char *key, const std::shared_ptr<ParamHandler> &handler) {
addHandler(ParamKey(path, key), handler);
}
void addHandler(ParameterGrp *hGrp, const char *key, const std::shared_ptr<ParamHandler> &handler) {
addHandler(ParamKey(hGrp, key), handler);
}
void addHandler(const std::vector<ParamKey> &keys, const std::shared_ptr<ParamHandler> &handler) {
for (const auto &key : keys)
addHandler(key, handler);
}
void addHandler(const char *path, const std::vector<const char*> &keys, const std::shared_ptr<ParamHandler> &handler) {
for (const auto &key : keys)
addHandler(path, key, handler);
}
void addHandler(ParameterGrp *hGrp, const std::vector<const char*> &keys, const std::shared_ptr<ParamHandler> &handler) {
for (const auto &key : keys)
addHandler(hGrp, key, handler);
}
template<class Func>
std::shared_ptr<ParamHandler> addHandler(const char *path, const char *key, Func func) {
std::shared_ptr<ParamHandler> handler(new ParamHandlerT<Func>(func));
addHandler(path, key, handler);
return handler;
}
template<class Func>
std::shared_ptr<ParamHandler> addHandler(ParameterGrp *hGrp, const char *key, Func func) {
std::shared_ptr<ParamHandler> handler(new ParamHandlerT<Func>(func));
addHandler(hGrp, key, handler);
return handler;
}
template<class Func>
std::shared_ptr<ParamHandler> addDelayedHandler(const char *path, const char *key, Func func) {
auto hGrp = App::GetApplication().GetUserParameter().GetGroup(path);
auto wrap = [hGrp, func]() {
func(hGrp);
};
std::shared_ptr<ParamHandler> handler(new ParamDelayedHandlerT<decltype(wrap)>(wrap));
addHandler(hGrp, key, handler);
return handler;
}
template<class Func>
std::shared_ptr<ParamHandler> addDelayedHandler(ParameterGrp *hGrp, const char *key, Func func) {
auto wrap = [hGrp, func]() {
func(hGrp);
};
std::shared_ptr<ParamHandler> handler(new ParamDelayedHandlerT<decltype(wrap)>(wrap));
addHandler(hGrp, key, handler);
return handler;
}
template<class Func>
std::shared_ptr<ParamHandler> addDelayedHandler(const char *path,
const std::vector<const char *> &keys,
Func func)
{
auto hGrp = App::GetApplication().GetUserParameter().GetGroup(path);
auto wrap = [hGrp, func]() {
func(hGrp);
};
std::shared_ptr<ParamHandler> handler(new ParamDelayedHandlerT<decltype(wrap)>(wrap));
for (const auto &key : keys)
addHandler(ParamKey(hGrp, key), handler);
return handler;
}
template<class Func>
std::shared_ptr<ParamHandler> addDelayedHandler(ParameterGrp::handle hGrp,
const std::vector<const char *> &keys,
Func func)
{
auto wrap = [hGrp, func]() {
func(hGrp);
};
std::shared_ptr<ParamHandler> handler(new ParamDelayedHandlerT<decltype(wrap)>(wrap));
for (const auto &key : keys)
addHandler(ParamKey(hGrp, key), handler);
return handler;
}
protected:
std::map<ParamKey, std::shared_ptr<ParamHandler>> handlers;
std::set<std::shared_ptr<ParamHandler>> pendings;
boost::signals2::scoped_connection conn;
QTimer timer;
};
} // namespace Gui
#endif // GUI_PARAM_HANDLER_H