Sketcher: New flexible DSH Architecture

=======================================

Rewrite of the architecture to accomodate on-view parameters and to enable code reuse
between the default widget and custom widgets.
This commit is contained in:
Abdullah Tahiri
2023-10-20 20:29:05 +02:00
committed by abdullahtahiriyo
parent a5b5d01c22
commit 82fed5bbfc
10 changed files with 1392 additions and 1414 deletions

View File

@@ -133,7 +133,11 @@ SET(SketcherGui_SRCS
DrawSketchHandler.cpp
DrawSketchHandler.h
DrawSketchDefaultHandler.h
DrawSketchDefaultWidgetHandler.h
DrawSketchController.h
DrawSketchDefaultWidgetController.h
DrawSketchControllableHandler.h
DrawSketchKeyboardManager.h
DrawSketchKeyboardManager.cpp
Workbench.cpp
Workbench.h
EditDatumDialog.cpp

View File

@@ -0,0 +1,198 @@
/***************************************************************************
* Copyright (c) 2023 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef SKETCHERGUI_DrawSketchControllableHandler_H
#define SKETCHERGUI_DrawSketchControllableHandler_H
#include <type_traits>
#include "DrawSketchDefaultHandler.h"
namespace SketcherGui
{
/** @brief Template class intended for handlers controllable by a DrawSketchController
*
* @details
* The template encapsulates a minimal interaction between a DrawSketchDefaultHandler and a
* a DrawSketchController, and it is intended to facilitate the creation of enhanced DSHs having
* controlling entities such as widgets and on-screen controls.
*/
template<typename ControllerT>
class DrawSketchControllableHandler
: public DrawSketchDefaultHandler<typename ControllerT::HandlerType,
typename ControllerT::SelectModeType,
ControllerT::AutoConstraintInitialSize,
typename ControllerT::ContructionMethodType>
{
/** @name Meta-programming definitions and members */
//@{
using HandlerType = typename ControllerT::HandlerType;
using SelectModeType = typename ControllerT::SelectModeType;
using ConstructionMethodType = typename ControllerT::ContructionMethodType;
//@}
/** @name Convenience definitions */
//@{
using DSDefaultHandler = DrawSketchDefaultHandler<HandlerType,
SelectModeType,
ControllerT::AutoConstraintInitialSize,
ConstructionMethodType>;
using ConstructionMachine = ConstructionMethodMachine<ConstructionMethodType>;
//@}
// Enable access to the actual controller provided
friend ControllerT;
// Enable access to the parent controller (if any).
// Non-derived controllers shall define ControllerBase as void to interoperate with this class.
friend typename ControllerT::ControllerBase;
public:
DrawSketchControllableHandler(
ConstructionMethodType constructionmethod = static_cast<ConstructionMethodType>(0))
: DSDefaultHandler(constructionmethod)
, toolWidgetManager(static_cast<HandlerType*>(this))
{}
~DrawSketchControllableHandler() override = default;
/** @name functions NOT intended for specialisation or further overriding */
//@{
void mouseMove(Base::Vector2d onSketchPos) override
{
toolWidgetManager.mouseMoved(onSketchPos);
toolWidgetManager.enforceControlParameters(onSketchPos);
updateDataAndDrawToPosition(onSketchPos);
toolWidgetManager.adaptParameters(onSketchPos);
}
bool pressButton(Base::Vector2d onSketchPos) override
{
toolWidgetManager.enforceControlParameters(onSketchPos);
onButtonPressed(onSketchPos);
return true;
}
bool releaseButton(Base::Vector2d onSketchPos) override
{
Q_UNUSED(onSketchPos);
DSDefaultHandler::finish();
return true;
}
//@}
protected:
/** @name functions requiring specialisation */
//@{
std::string getToolName() const override
{
return DrawSketchHandler::getToolName();
}
QString getCrosshairCursorSVGName() const override
{
return DrawSketchHandler::getCrosshairCursorSVGName();
}
//@}
private:
/** @name functions requiring specialisation */
//@{
// For every machine state, it updates the EditData temporary
// curve, and draws the temporary curve during edit mode.
void updateDataAndDrawToPosition(Base::Vector2d onSketchPos) override
{
Q_UNUSED(onSketchPos)
};
void executeCommands() override {};
void createAutoConstraints() override {};
//@}
/** @name functions which MAY require specialisation*/
//@{
/** Default implementation is that on every mouse click the mode is changed to the next seek
On the last seek, it changes to SelectMode::End
If this behaviour is not acceptable, then the function must be specialised.*/
void onButtonPressed(Base::Vector2d onSketchPos) override
{
DSDefaultHandler::onButtonPressed(onSketchPos);
}
void beforeCreateAutoConstraints() override
{
toolWidgetManager.addConstraints();
}
void onWidgetChanged() override
{
toolWidgetManager.initControls(DSDefaultHandler::toolwidget);
}
void onReset() override
{
toolWidgetManager.resetControls();
}
void onModeChanged() override
{
toolWidgetManager.onHandlerModeChanged();
DSDefaultHandler::onModeChanged();
toolWidgetManager.afterHandlerModeChanged();
}
void onConstructionMethodChanged() override
{
toolWidgetManager.onConstructionMethodChanged();
}
void registerPressedKey(bool pressed, int key) override
{
DSDefaultHandler::registerPressedKey(pressed, key);
if (key == SoKeyboardEvent::U && !pressed && !this->isLastState()) {
toolWidgetManager.firstKeyShortcut();
}
if (key == SoKeyboardEvent::J && !pressed && !this->isLastState()) {
toolWidgetManager.secondKeyShortcut();
}
if (key == SoKeyboardEvent::TAB && !pressed) {
toolWidgetManager.tabShortcut();
}
}
//@}
protected:
ControllerT toolWidgetManager;
};
} // namespace SketcherGui
#endif // SKETCHERGUI_DrawSketchControllableHandler_H

View File

@@ -0,0 +1,573 @@
/***************************************************************************
* Copyright (c) 2023 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef SKETCHERGUI_DrawSketchController_H
#define SKETCHERGUI_DrawSketchController_H
#include <Base/Tools2D.h>
#include <Gui/EditableDatumLabel.h>
#include "DrawSketchDefaultHandler.h"
#include "SketcherToolDefaultWidget.h"
#include "DrawSketchKeyboardManager.h"
namespace SketcherGui
{
/** @brief template class for creating a type encapsulating an int value associated to each of
the possible construction modes supported by the tool.
@details Different construction modes of a DSH may use different types of controls. This class
allows to instantiate a handler template class to provide such construction mode specific
controls.
Each different type of control is a template class deriving from this.
*/
template<int... sizes> // Initial sizes for each mode
class ControlAmount
{
public:
template<typename constructionT>
static constexpr int size(constructionT constructionmethod)
{
auto modeint = static_cast<int>(constructionmethod);
return constructionMethodParameters[modeint];
}
static constexpr int defaultMethodSize()
{
return size(0);
}
private:
static constexpr std::array<int, sizeof...(sizes)> constructionMethodParameters = {{sizes...}};
};
/** @brief Type encapsulating the number of On view parameters*/
template<int... sizes> // Initial sizes for each mode
class OnViewParameters: public ControlAmount<sizes...>
{
};
namespace sp = std::placeholders;
/** @brief Class defining a generic handler controller operable with a DrawSketchControllableHandler
*
* @details
* This class is intended as a parent for controller classes. This controller class provides the
* essential controller functionalities, including on-view parameters. This controller class does
* NOT control based on (taskbox) widgets.
*
* For an example of a tool using directly this class see DrawSketchHandlerPoint.
*
* Controls based on taskbox widgets may derive from this class and add on top any widget mandated
* functionality. For the default widget (SketcherToolDefaultWidget), see
* DrawSketchDefaultWidgetController. For custom widgets, an appropriate class, preferably deriving
* from this controller needs to be provided.
*/
template<typename HandlerT, // The name of the actual handler of the tool
typename SelectModeT, // The state machine defining the working of the tool
int PAutoConstraintSize, // The initial size of the AutoConstraint vector
typename OnViewParametersT, // The number of parameter spinboxes in the 3D view (one
// value per construction mode)
typename ConstructionMethodT =
ConstructionMethods::DefaultConstructionMethod> // The enum comprising all the
// supported construction methods
class DrawSketchController
{
public:
/** @name Meta-programming definitions and members */
//@{
using ControllerBase = void; // No base controller for parent class.
using HandlerType = HandlerT;
using SelectModeType = SelectModeT;
using ContructionMethodType = ConstructionMethodT;
static constexpr const int AutoConstraintInitialSize = PAutoConstraintSize;
//@}
/** @name Convenience definitions */
//@{
using DSDefaultHandler =
DrawSketchDefaultHandler<HandlerT, SelectModeT, PAutoConstraintSize, ConstructionMethodT>;
using ConstructionMachine = ConstructionMethodMachine<ConstructionMethodT>;
using ConstructionMethod = ConstructionMethodT;
using SelectMode = SelectModeT;
//@}
protected:
HandlerT* handler; // real derived type
bool init = false; // true if the controls have been initialised.
bool firstMoveInit = false; // true if first mouse movement not yet performed (resets)
Base::Vector2d prevCursorPosition;
Base::Vector2d lastControlEnforcedPosition;
int onViewIndexWithFocus = 0; // track the index of the on-view parameter having the focus
int nOnViewParameter = OnViewParametersT::defaultMethodSize();
/** @name Named indices for controlling on-view controls */
//@{
enum OnViewParameter
{
First,
Second,
Third,
Fourth,
Fifth,
Sixth,
Seventh,
Eighth,
Ninth,
Tenth,
nOnViewParameters // Must Always be the last one
};
//@}
std::vector<std::unique_ptr<Gui::EditableDatumLabel>> onViewParameters;
/// Class to keep track of colors used by the on-view parameters
class ColorManager
{
public:
SbColor dimConstrColor, dimConstrDeactivatedColor;
ColorManager()
{
init();
}
private:
void init()
{
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/View");
dimConstrColor = SbColor(1.0f, 0.149f, 0.0f);
dimConstrDeactivatedColor = SbColor(0.8f, 0.8f, 0.8f);
float transparency = 0.f;
unsigned long color = (unsigned long)(dimConstrColor.getPackedValue());
color = hGrp->GetUnsigned("ConstrainedDimColor", color);
dimConstrColor.setPackedValue((uint32_t)color, transparency);
color = (unsigned long)(dimConstrDeactivatedColor.getPackedValue());
color = hGrp->GetUnsigned("DeactivatedConstrDimColor", color);
dimConstrDeactivatedColor.setPackedValue((uint32_t)color, transparency);
}
};
public:
/** Creates the controller.
* @param dshandler a controllable DSH handler
*/
DrawSketchController(HandlerT* dshandler)
: handler(dshandler)
, keymanager(std::make_unique<DrawSketchKeyboardManager>())
{}
~DrawSketchController()
{}
/** @name functions NOT intended for specialisation offering a NVI for extension */
/** These functions offer a NVI to ensure the order on initialisation. It is heavily encouraged
* to extend functionality using the NVI interface (by overriding the NVI functions).
*/
//@{
/** @brief Initialises controls, such as the widget and the on-view parameters via NVI.*/
void initControls(QWidget* widget)
{
doInitControls(widget); // NVI
resetControls();
init = true;
}
/** @brief Resets the controls, such as the widget and the on-view parameters */
void resetControls()
{
doResetControls(); // NVI
firstMoveInit = false;
}
/** @brief function triggered by the handler when the mouse has been moved */
void mouseMoved(Base::Vector2d originalSketchPosition)
{
onMouseMoved(originalSketchPosition); // NVI
if (!firstMoveInit) {
firstMoveInit = true;
}
}
/** @brief function triggered by the handler to ensure its operating position takes into
* account widget mandated parameters */
void enforceControlParameters(Base::Vector2d& onSketchPos)
{
prevCursorPosition = onSketchPos;
doEnforceControlParameters(onSketchPos); // specialisation interface
lastControlEnforcedPosition = onSketchPos; // store enforced cursor position.
afterEnforceControlParameters(); // NVI
}
/** function that is called by the handler when the construction mode changed */
void onConstructionMethodChanged()
{
nOnViewParameter = OnViewParametersT::size(handler->constructionMethod());
doConstructionMethodChanged(); // NVI
handler->updateCursor();
handler->reset(); // reset of handler to restart.
}
//@}
/** @name functions NOT intended for specialisation offering specialisation interface for
* extension */
/** These functions offer a specialisation interface to ensure the order on initialisation. It
* is heavily encouraged to extend functionality using the specialisation interface (by
* specialising the NVI functions).
*/
//@{
/** slot triggering when a on view parameter has changed
* It is intended to remote control the DrawSketchDefaultWidgetHandler
*/
void onViewValueChanged(int onviewparameterindex, double value)
{
if (isOnViewParameterOfCurrentMode(onviewparameterindex + 1)) {
setFocusToOnViewParameter(onviewparameterindex + 1);
}
/* That is not supported with on-view parameters.
// -> A machine does not forward to a next state when adapting the parameter (though it
// may forward to
// a next state if all the parameters are fulfilled, see
// doChangeDrawSketchHandlerMode). This ensures that the geometry has been defined
// (either by mouse clicking or by widget). Autoconstraints on point should be picked
// when the state is reached upon machine state advancement.
//
// -> A machine goes back to a previous state if a parameter of a previous state is
// modified. This ensures
// that appropriate autoconstraints are picked.
if (isOnViewParameterOfPreviousMode(onviewparameterindex)) {
// change to previous state
handler->setState(getState(onviewparameterindex));
}*/
adaptDrawingToOnViewParameterChange(onviewparameterindex,
value); // specialisation interface
finishControlsChanged();
}
void adaptParameters()
{
adaptParameters(lastControlEnforcedPosition); // specialisation interface
}
//@}
/** @name Specialisation Interface */
/** These functions offer a specialisation interface. Non-virtual functions are specific to
* this controller. Virtual functions may depend on input from a derived controller, and thus
* the specialisation needs to be of an overriden version (so as to be able to access members
* of the derived controller).
*/
//@{
/// Change DSH to reflect a value entered in the view
void adaptDrawingToOnViewParameterChange(int onviewparameterindex, double value)
{
Q_UNUSED(onviewparameterindex);
Q_UNUSED(value);
}
/** Returns the state to which the on-view parameter corresponds in the current construction
* method. */
auto getState(int parameterindex) const
{
Q_UNUSED(parameterindex);
return handler->getFirstState();
}
/// function to create constraints based on control information.
virtual void addConstraints()
{}
/// Configures on-view parameters
void configureOnViewParameters()
{}
/** Change DSH to reflect the SelectMode it should be in based on values entered in the
* controls
*/
virtual void doChangeDrawSketchHandlerMode()
{}
/** function that is called by the handler when the selection mode changed */
void onHandlerModeChanged()
{
setModeOnViewParameters();
}
/** function that is called by the handler with a Vector2d position to update the widget
*
* It MUST be specialised if you want the parameters to update on mouseMove
*/
virtual void adaptParameters(Base::Vector2d onSketchPos)
{
Q_UNUSED(onSketchPos)
}
/** function that is called by the handler with a mouse position, enabling the
* widget to override it having regard to the widget information.
*
* It MUST be specialised if you want to override mouse position based on parameters.
*/
void doEnforceControlParameters(Base::Vector2d& onSketchPos)
{
Q_UNUSED(onSketchPos)
}
/** on first shortcut, it toggles the first checkbox if there is go. Must be specialised if
* this is not intended */
virtual void firstKeyShortcut()
{}
virtual void secondKeyShortcut()
{}
virtual void tabShortcut()
{
passFocusToNextOnViewParameter();
}
//@}
/// triggered by the controllable DSH after a mode change has been effected
virtual void afterHandlerModeChanged()
{
if (!handler->isState(SelectModeT::End) || handler->continuousMode) {
handler->mouseMove(prevCursorPosition);
}
}
protected:
/** @name NVI for extension of controller functionality in derived classes */
//@{
virtual void doInitControls(QWidget* widget)
{
Q_UNUSED(widget)
}
virtual void doResetControls()
{
resetOnViewParameters();
}
virtual void onMouseMoved(Base::Vector2d originalSketchPosition)
{
Q_UNUSED(originalSketchPosition)
if (!firstMoveInit) {
setModeOnViewParameters();
}
}
virtual void afterEnforceControlParameters()
{
// Give focus to current on-view parameter. In case user interacted outside of 3dview.
setFocusToOnViewParameter(onViewIndexWithFocus);
}
virtual void doConstructionMethodChanged()
{}
//@}
protected:
/** @name helper functions */
//@{
/// function to assist in adaptDrawingToComboboxChange specialisation
/// assigns the modevalue to the modeenum
/// it also triggers an update of the cursor
template<typename T>
void setMode(T& modeenum, int modevalue)
{
auto mode = static_cast<T>(modevalue);
modeenum = mode;
handler->updateCursor();
handler->resetControls(); // resetControls of handler to restart.
}
/// function to redraw before and after any eventual mode change in reaction to a control
/// change
void finishControlsChanged()
{
handler->mouseMove(prevCursorPosition);
auto currentstate = handler->state();
// ensure that object at point is preselected, so that autoconstraints are generated
handler->preselectAtPoint(lastControlEnforcedPosition);
doChangeDrawSketchHandlerMode();
// if the state changed and is not the last state (End). And is init (ie tool has not
// reset)
if (!handler->isLastState() && handler->state() != currentstate && firstMoveInit) {
// mode has changed, so reprocess the previous position to the new widget state
handler->mouseMove(prevCursorPosition);
}
}
/** @brief Initialises on-screen parameters */
void initNOnViewParameters(int n)
{
Gui::View3DInventorViewer* viewer = handler->getViewer();
Base::Placement placement = handler->sketchgui->getSketchObject()->Placement.getValue();
onViewParameters.clear();
for (int i = 0; i < n; i++) {
// the returned is a naked pointer
auto parameter = onViewParameters
.emplace_back(std::make_unique<Gui::EditableDatumLabel>(
viewer,
placement,
colorManager.dimConstrDeactivatedColor,
/*autoDistance = */ true))
.get();
QObject::connect(parameter, &Gui::EditableDatumLabel::valueChanged, [=](double value) {
parameter->setColor(colorManager.dimConstrColor);
onViewValueChanged(i, value);
});
}
}
/// Allows a on-view parameter to take any mouse mandated value (as opposed to enforce one)
void unsetOnViewParameter(Gui::EditableDatumLabel* onViewParameter)
{
onViewParameter->isSet = false;
onViewParameter->setColor(colorManager.dimConstrDeactivatedColor);
}
/** Activates the correct set of on-view parameters corresponding to current
* mode. It may be specialized if necessary.*/
void setModeOnViewParameters()
{
bool firstOfMode = true;
for (size_t i = 0; i < onViewParameters.size(); i++) {
if (!isOnViewParameterOfCurrentMode(i)) {
onViewParameters[i]->stopEdit();
if (!onViewParameters[i]->isSet || handler->state() == SelectMode::End) {
onViewParameters[i]->deactivate();
}
}
else {
if (firstOfMode) {
onViewIndexWithFocus = i;
firstOfMode = false;
}
onViewParameters[i]->activate();
// points/value will be overridden by the mouseMove triggered by the mode change.
onViewParameters[i]->setPoints(Base::Vector3d(), Base::Vector3d());
onViewParameters[i]->startEdit(0.0, keymanager.get());
}
}
}
/// This function gives the focus to a spinbox and tracks the focus.
void setFocusToOnViewParameter(unsigned int onviewparameterindex)
{
if (onviewparameterindex < onViewParameters.size()) {
onViewParameters[onviewparameterindex]->setFocusToSpinbox();
onViewIndexWithFocus = onviewparameterindex;
}
}
/// Switches focus to the next parameter in the current state machine.
void passFocusToNextOnViewParameter()
{
unsigned int index = onViewIndexWithFocus + 1;
if (index >= onViewParameters.size()) {
index = 0;
}
while (index < onViewParameters.size()) {
if (isOnViewParameterOfCurrentMode(index)) {
setFocusToOnViewParameter(index);
break;
}
index++;
}
}
/** Returns whether the provided on-view parameter index belongs to the current state of the
* state machine */
bool isOnViewParameterOfCurrentMode(unsigned int onviewparameterindex) const
{
return onviewparameterindex < onViewParameters.size()
&& getState(onviewparameterindex) == handler->state();
}
/** Returns whether the provided on-view parameter index belongs to the previous state of the
* state machine */
bool isOnViewParameterOfPreviousMode(unsigned int onviewparameterindex) const
{
return onviewparameterindex < onViewParameters.size()
&& getState(onviewparameterindex) < handler->state();
}
/** Resets the on-view parameter controls */
void resetOnViewParameters()
{
initNOnViewParameters(nOnViewParameter);
onViewIndexWithFocus = 0;
configureOnViewParameters();
}
//@}
private:
ColorManager colorManager;
std::unique_ptr<DrawSketchKeyboardManager> keymanager;
};
} // namespace SketcherGui
#endif // SKETCHERGUI_DrawSketchController_H

View File

@@ -28,8 +28,10 @@
#include <Base/Exception.h>
#include <Base/Console.h>
#include <Gui/Command.h>
#include <Mod/Sketcher/App/GeoEnum.h>
#include <Mod/Sketcher/App/GeometryFacade.h>
#include <Mod/Sketcher/App/PythonConverter.h>
#include <Mod/Sketcher/App/SolverGeometryExtension.h>
@@ -389,7 +391,7 @@ public:
applyCursor();
}
virtual ~DrawSketchDefaultHandler()
~DrawSketchDefaultHandler() override
{}
/** @name public DrawSketchHandler interface
@@ -397,26 +399,26 @@ public:
* overridden/specialised instead.
*/
//@{
virtual void mouseMove(Base::Vector2d onSketchPos) override
void mouseMove(Base::Vector2d onSketchPos) override
{
updateDataAndDrawToPosition(onSketchPos);
}
virtual bool pressButton(Base::Vector2d onSketchPos) override
bool pressButton(Base::Vector2d onSketchPos) override
{
onButtonPressed(onSketchPos);
return true;
}
virtual bool releaseButton(Base::Vector2d onSketchPos) override
bool releaseButton(Base::Vector2d onSketchPos) override
{
Q_UNUSED(onSketchPos);
finish();
return true;
}
virtual void registerPressedKey(bool pressed, int key) override
void registerPressedKey(bool pressed, int key) override
{
if (key == SoKeyboardEvent::M && pressed && !this->isLastState()) {
this->iterateToNextConstructionMethod();
@@ -548,7 +550,7 @@ private:
virtual void createAutoConstraints()
{}
virtual void onConstructionMethodChanged() override {};
void onConstructionMethodChanged() override {};
virtual void updateDataAndDrawToPosition(Base::Vector2d onSketchPos)
{
@@ -569,7 +571,7 @@ protected:
See documentation of the functions above*/
//@{
/** @brief Minimal handle activation respecting avoid redundants and continuous mode.*/
virtual void activated() override
void activated() override
{
avoidRedundants =
sketchgui->AvoidRedundant.getValue() && sketchgui->Autoconstraints.getValue();
@@ -592,10 +594,10 @@ protected:
/** @brief Default behaviour that upon arriving to the End state of the state machine, the
* command is finished. */
virtual void onModeChanged() override
void onModeChanged() override
{
finish(); // internally checks that state is SelectMode::End, and only finishes then.
angleSnappingControl();
finish(); // internally checks that state is SelectMode::End, and only finishes then.
};
//@}
@@ -885,7 +887,7 @@ protected:
}
// This is an awful situation. It should not be possible if the DSH works properly. It is
// just a saveguard.
// just a safeguard.
if (sketchobject->getLastHasConflicts()) {
THROWM(Base::RuntimeError,
QT_TRANSLATE_NOOP(

View File

@@ -0,0 +1,371 @@
/***************************************************************************
* Copyright (c) 2023 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef SKETCHERGUI_DrawSketchDefaultWidgetController_H
#define SKETCHERGUI_DrawSketchDefaultWidgetController_H
#include <Base/Tools.h>
#include <Gui/EditableDatumLabel.h>
#include "DrawSketchController.h"
namespace SketcherGui
{
/** @brief Type encapsulating the number of parameters in the widget*/
template<int... sizes> // Initial sizes for each mode
class WidgetParameters: public ControlAmount<sizes...>
{
};
/** @brief Type encapsulating the number of checkboxes in the widget*/
template<int... sizes> // Initial sizes for each mode
class WidgetCheckboxes: public ControlAmount<sizes...>
{
};
/** @brief Type encapsulating the number of comboboxes in the widget*/
template<int... sizes> // Initial sizes for each mode
class WidgetComboboxes: public ControlAmount<sizes...>
{
};
namespace sp = std::placeholders;
/** @brief Class defining a handler controller making use of parameters provided by a widget of type
* SketcherToolDefaultWidget.
*
* @details
* This class derives from DrawSketchController and thus provides on-view parameters too. In
* addition it manages a SketcherToolDefaultWidget in which a number of spinboxes, checkboxes and
* comboboxes are provided.
*
* It also provides automatic handling of change of creation method.
*
* This class is not intended to control based on a custom widget.
*/
template<typename HandlerT, // The name of the actual handler of the tool
typename SelectModeT, // The state machine defining the working of the tool
int PAutoConstraintSize, // The initial size of the AutoConstraint vector
typename OnViewParametersT, // The number of parameter spinboxes in the 3D view
typename WidgetParametersT, // The number of parameter spinboxes in the default widget
typename WidgetCheckboxesT, // The number of checkboxes in the default widget
typename WidgetComboboxesT, // The number of comboboxes in the default widget
typename ConstructionMethodT = ConstructionMethods::DefaultConstructionMethod,
bool PFirstComboboxIsConstructionMethod =
false> // The handler template or class having this as inner class
class DrawSketchDefaultWidgetController: public DrawSketchController<HandlerT,
SelectModeT,
PAutoConstraintSize,
OnViewParametersT,
ConstructionMethodT>
{
public:
/** @name Meta-programming definitions and members */
//@{
using ControllerBase = DrawSketchController<HandlerT,
SelectModeT,
PAutoConstraintSize,
OnViewParametersT,
ConstructionMethodT>;
//@}
protected:
int nParameter = WidgetParametersT::defaultMethodSize();
int nCheckbox = WidgetCheckboxesT::defaultMethodSize();
int nCombobox = WidgetComboboxesT::defaultMethodSize();
SketcherToolDefaultWidget* toolWidget;
using Connection = boost::signals2::connection;
Connection connectionParameterValueChanged;
Connection connectionCheckboxCheckedChanged;
Connection connectionComboboxSelectionChanged;
/** @name Named indices for controls of the default widget (SketcherToolDefaultWidget) */
//@{
using WParameter = SketcherToolDefaultWidget::Parameter;
using WCheckbox = SketcherToolDefaultWidget::Checkbox;
using WCombobox = SketcherToolDefaultWidget::Combobox;
//@}
using SelectMode = SelectModeT;
using ControllerBase::handler;
public:
DrawSketchDefaultWidgetController(HandlerT* dshandler)
: ControllerBase(dshandler)
{}
~DrawSketchDefaultWidgetController()
{
connectionParameterValueChanged.disconnect();
connectionCheckboxCheckedChanged.disconnect();
connectionComboboxSelectionChanged.disconnect();
}
/** @name functions NOT intended for specialisation offering specialisation interface for
* extension */
/** These functions offer a specialisation interface to ensure the order on initialisation. It
* is heavily encouraged to extend functionality using the specialisation interface.
*/
//@{
/** boost slot triggering when a parameter has changed in the widget
* It is intended to remote control the DrawSketchDefaultWidgetHandler
*/
void parameterValueChanged(int parameterindex, double value)
{
adaptDrawingToParameterChange(parameterindex, value); // specialisation interface
ControllerBase::finishControlsChanged();
}
/** boost slot triggering when a checkbox has changed in the widget
* It is intended to remote control the DrawSketchDefaultWidgetHandler
*/
void checkboxCheckedChanged(int checkboxindex, bool value)
{
adaptDrawingToCheckboxChange(checkboxindex, value); // specialisation interface
ControllerBase::finishControlsChanged();
}
/** boost slot triggering when a combobox has changed in the widget
* It is intended to remote control the DrawSketchDefaultWidgetHandler
*/
void comboboxSelectionChanged(int comboboxindex, int value)
{
adaptDrawingToComboboxChange(comboboxindex, value); // specialisation interface
ControllerBase::finishControlsChanged();
}
//@}
/** @name Specialisation Interface */
/** These functions offer a specialisation interface. Non-virtual functions are specific to
* this controller. Virtual functions may depend on input from a derived controller, and thus
* the specialisation needs to be of an overriden version (so as to be able to access members
* of the derived controller).
*/
/// Change DSH to reflect a value entered in the widget
void adaptDrawingToParameterChange(int parameterindex, double value)
{
Q_UNUSED(parameterindex);
Q_UNUSED(value);
}
/// Change DSH to reflect a checkbox changed in the widget
void adaptDrawingToCheckboxChange(int checkboxindex, bool value)
{
Q_UNUSED(checkboxindex);
Q_UNUSED(value);
}
/// Change DSH to reflect a comboBox changed in the widget
void adaptDrawingToComboboxChange(int comboboxindex, int value)
{
Q_UNUSED(comboboxindex);
if constexpr (PFirstComboboxIsConstructionMethod == true) {
if (comboboxindex == WCombobox::FirstCombo && handler->ConstructionMethodsCount() > 1) {
handler->setConstructionMethod(static_cast<ConstructionMethodT>(value));
}
}
}
/// function to create constraints based on widget information.
void addConstraints() override
{}
/// function to configure the default widget.
void configureToolWidget()
{}
/** function that is called by the handler with a Vector2d position to update the widget*/
void doChangeDrawSketchHandlerMode() override
{}
/** function that is called by the handler with a Vector2d position to update the widget */
void adaptParameters(Base::Vector2d onSketchPos) override
{
Q_UNUSED(onSketchPos)
}
/** on first shortcut, it toggles the first checkbox if there is go. Must be specialised if
* this is not intended */
void firstKeyShortcut() override
{
if (nCheckbox >= 1) {
auto firstchecked = toolWidget->getCheckboxChecked(WCheckbox::FirstBox);
toolWidget->setCheckboxChecked(WCheckbox::FirstBox, !firstchecked);
}
}
/** on second shortcut, it toggles the first checkbox if there is go. Must be specialised if
* this is not intended */
void secondKeyShortcut() override
{
if (nCheckbox >= 2) {
auto secondchecked = toolWidget->getCheckboxChecked(WCheckbox::SecondBox);
toolWidget->setCheckboxChecked(WCheckbox::SecondBox, !secondchecked);
}
}
//@}
protected:
/** @name DrawSketchController NVI */
//@{
/// Initialises widget control
void doInitControls(QWidget* widget) override
{
initDefaultWidget(widget);
ControllerBase::doInitControls(widget);
}
/// Resets widget controls
void doResetControls() override
{
ControllerBase::doResetControls();
resetDefaultWidget();
}
/// Automatic default method update in combobox
void doConstructionMethodChanged() override
{
nParameter = WidgetParametersT::size(handler->constructionMethod());
nCheckbox = WidgetCheckboxesT::size(handler->constructionMethod());
nCombobox = WidgetComboboxesT::size(handler->constructionMethod());
// update the combobox only if necessary (if the change was not triggered by the
// combobox)
if constexpr (PFirstComboboxIsConstructionMethod == true) {
auto currentindex = toolWidget->getComboboxIndex(WCombobox::FirstCombo);
auto methodint = static_cast<int>(handler->constructionMethod());
if (currentindex != methodint) {
// avoid triggering of method change
boost::signals2::shared_connection_block combobox_block(
connectionComboboxSelectionChanged);
toolWidget->setComboboxIndex(WCombobox::FirstCombo, methodint);
}
}
}
//@}
private:
/// Initialisation of the widget
void initDefaultWidget(QWidget* widget)
{
toolWidget = static_cast<SketcherToolDefaultWidget*>(widget);
connectionParameterValueChanged = toolWidget->registerParameterValueChanged(
std::bind(&DrawSketchDefaultWidgetController::parameterValueChanged,
this,
sp::_1,
sp::_2));
connectionCheckboxCheckedChanged = toolWidget->registerCheckboxCheckedChanged(
std::bind(&DrawSketchDefaultWidgetController::checkboxCheckedChanged,
this,
sp::_1,
sp::_2));
connectionComboboxSelectionChanged = toolWidget->registerComboboxSelectionChanged(
std::bind(&DrawSketchDefaultWidgetController::comboboxSelectionChanged,
this,
sp::_1,
sp::_2));
}
/// Resets the widget
void resetDefaultWidget()
{
boost::signals2::shared_connection_block parameter_block(connectionParameterValueChanged);
boost::signals2::shared_connection_block checkbox_block(connectionCheckboxCheckedChanged);
boost::signals2::shared_connection_block combobox_block(connectionComboboxSelectionChanged);
toolWidget->initNParameters(nParameter);
toolWidget->initNCheckboxes(nCheckbox);
toolWidget->initNComboboxes(nCombobox);
configureToolWidget();
}
private:
/** @name helper functions */
//@{
/// returns the status to which the handler was updated
bool syncHandlerToCheckbox(int checkboxindex, bool& handlerboolean)
{
bool status = toolWidget->getCheckboxChecked(checkboxindex);
handlerboolean = status;
return status;
}
/// returns true if checkbox was changed, and false if no sync was necessary
bool syncCheckboxToHandler(int checkboxindex, bool handlerboolean)
{
bool status = toolWidget->getCheckboxChecked(checkboxindex);
if (handlerboolean != status) {
toolWidget->setCheckboxChecked(checkboxindex, handlerboolean);
return true;
}
return false;
}
/// Syncs the handler to the construction method selection in the combobox
void syncHandlerToConstructionMethodCombobox()
{
if constexpr (PFirstComboboxIsConstructionMethod == true) {
auto constructionmethod = toolWidget->getComboboxIndex(WCombobox::FirstCombo);
handler->initConstructionMethod(static_cast<ConstructionMethodT>(constructionmethod));
}
}
/// Syncs the construction method selection in the combobox to the handler selection
void syncConstructionMethodComboboxToHandler()
{
if constexpr (PFirstComboboxIsConstructionMethod == true) {
auto constructionmethod = toolWidget->getComboboxIndex(WCombobox::FirstCombo);
auto actualconstructionmethod = static_cast<int>(handler->constructionMethod());
if (constructionmethod != actualconstructionmethod) {
toolWidget->setComboboxIndex(WCombobox::FirstCombo, actualconstructionmethod);
}
}
}
//@}
};
} // namespace SketcherGui
#endif // SKETCHERGUI_DrawSketchDefaultWidgetController_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
/***************************************************************************
* Copyright (c) 2023 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <Inventor/events/SoKeyboardEvent.h>
#include <QApplication>
#include <QEvent>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#endif
#include "ViewProviderSketch.h"
#include "DrawSketchKeyboardManager.h"
using namespace SketcherGui;
DrawSketchKeyboardManager::DrawSketchKeyboardManager()
: QObject(nullptr)
, keyMode(KeyboardEventHandlingMode::DSHControl)
{
// get the active viewer, so that we can send it key events
auto doc = Gui::Application::Instance->activeDocument();
if (doc) {
auto temp = dynamic_cast<Gui::View3DInventor*>(doc->getActiveView());
if (temp) {
vpViewer = temp->getViewer();
keyMode = KeyboardEventHandlingMode::ViewProvider;
}
}
timer.setSingleShot(true);
QObject::connect(&timer, &QTimer::timeout, [this]() {
onTimeOut();
});
}
bool DrawSketchKeyboardManager::isMode(KeyboardEventHandlingMode mode)
{
return mode == keyMode;
}
DrawSketchKeyboardManager::KeyboardEventHandlingMode DrawSketchKeyboardManager::getMode()
{
return keyMode;
}
bool DrawSketchKeyboardManager::eventFilter(QObject* object, QEvent* event)
{
Q_UNUSED(object);
if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
/*If a key shortcut is required to work on sketcher when a tool using ui controls is being
* used, then you have to add this key to the below section such that the spinbox doesn't
* keep the keypress event for itself. Note if you want the event to be handled by the
* spinbox too, you can return false.*/
auto keyEvent = static_cast<QKeyEvent*>(event);
detectKeyboardEventHandlingMode(keyEvent); // determine the handler
if (vpViewer && isMode(KeyboardEventHandlingMode::ViewProvider)) {
return QApplication::sendEvent(vpViewer, keyEvent);
}
return false; // do not intercept the event and feed it to the widget
}
return false;
}
void DrawSketchKeyboardManager::detectKeyboardEventHandlingMode(QKeyEvent* keyEvent)
{
QRegularExpression rx(QStringLiteral("^[0-9]$"));
auto match = rx.match(keyEvent->text());
if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return
|| keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Backtab
|| keyEvent->key() == Qt::Key_Backspace || keyEvent->key() == Qt::Key_Delete
|| keyEvent->key() == Qt::Key_Minus || keyEvent->key() == Qt::Key_Period
|| keyEvent->key() == Qt::Key_Comma || match.hasMatch()) {
keyMode = KeyboardEventHandlingMode::DSHControl;
timer.start(timeOutValue);
}
}
void DrawSketchKeyboardManager::onTimeOut()
{
keyMode = KeyboardEventHandlingMode::ViewProvider;
}
/// sets the timeout to the amount of milliseconds.
void DrawSketchKeyboardManager::setTimeOut(int milliseconds)
{
timeOutValue = milliseconds;
}
// returns the current timeout amount
int DrawSketchKeyboardManager::timeOut()
{
return timeOutValue;
}
#include "moc_DrawSketchKeyboardManager.cpp"

View File

@@ -0,0 +1,104 @@
/***************************************************************************
* Copyright (c) 2023 Abdullah Tahiri <abdullah.tahiri.yo@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef SketcherGui_DrawSketchKeyboardManager_H
#define SketcherGui_DrawSketchKeyboardManager_H
#include <QEvent>
#include <QKeyEvent>
#include <QTimer>
#include <Gui/Application.h>
#include <Gui/Document.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
namespace Gui
{
class ViewProvider;
} // namespace Gui
namespace SketcherGui
{
class ViewProviderSketch;
/** Class implementing an event filter for DrawSketchHandler tools, enabling seamless introduction
* of values to parameters, including units, while still allowing operation of shortcuts.
*
* The basic mechanism to decide which control should respond is based on using timers, type of
* entered event.
*/
class DrawSketchKeyboardManager: public QObject
{
Q_OBJECT
public:
DrawSketchKeyboardManager();
/** Indicates whether the DSH control (e.g. on-view parameter or widget) should handle keyboard
* input or should signal it via boost */
enum class KeyboardEventHandlingMode
{
DSHControl,
ViewProvider
};
/// returns whether the provided entity will currently receive the event.
bool isMode(KeyboardEventHandlingMode mode);
/// returns which entity will currently receive the event.
KeyboardEventHandlingMode getMode();
bool eventFilter(QObject* object, QEvent* event);
/// sets the timeout to the amount of milliseconds.
void setTimeOut(int milliseconds);
// returns the current timeout amount
int timeOut();
private:
/// This function decides whether events should be send to the ViewProvider
/// or to the UI control of DSH.
void detectKeyboardEventHandlingMode(QKeyEvent* keyEvent);
void onTimeOut();
private:
/// Viewer responsible for the active document
Gui::View3DInventorViewer* vpViewer = nullptr;
KeyboardEventHandlingMode keyMode;
QTimer timer;
int timeOutValue = 2000;
};
} // namespace SketcherGui
#endif // SketcherGui_DrawSketchKeyboardManager_H

View File

@@ -27,8 +27,6 @@
#include <Inventor/events/SoKeyboardEvent.h>
#include <QApplication>
#include <QEvent>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#endif
#include "ui_SketcherToolDefaultWidget.h"
@@ -37,8 +35,6 @@
#include <Gui/BitmapFactory.h>
#include <Gui/ViewProvider.h>
#include <Gui/WaitCursor.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Gui/PrefWidgets.h>
#include <Base/Tools.h>
#include <Base/UnitsApi.h>
@@ -53,70 +49,6 @@ using namespace SketcherGui;
using namespace Gui::TaskView;
SketcherToolDefaultWidget::KeyboardManager::KeyboardManager()
: keyMode(SketcherToolDefaultWidget::KeyboardManager::KeyboardEventHandlingMode::Widget)
{
// get the active viewer, so that we can send it key events
auto doc = Gui::Application::Instance->activeDocument();
if (doc) {
auto temp = dynamic_cast<Gui::View3DInventor*>(doc->getActiveView());
if (temp) {
vpViewer = temp->getViewer();
keyMode = KeyboardEventHandlingMode::ViewProvider;
}
}
timer.setSingleShot(true);
QObject::connect(&timer, &QTimer::timeout, [this]() {
onTimeOut();
});
}
bool SketcherToolDefaultWidget::KeyboardManager::isMode(
SketcherToolDefaultWidget::KeyboardManager::KeyboardEventHandlingMode mode)
{
return mode == keyMode;
}
SketcherToolDefaultWidget::KeyboardManager::KeyboardEventHandlingMode
SketcherToolDefaultWidget::KeyboardManager::getMode()
{
return keyMode;
}
bool SketcherToolDefaultWidget::KeyboardManager::handleKeyEvent(QKeyEvent* keyEvent)
{
detectKeyboardEventHandlingMode(keyEvent); // determine the handler
if (vpViewer && isMode(KeyboardEventHandlingMode::ViewProvider)) {
return QApplication::sendEvent(vpViewer, keyEvent);
}
return false; // do not intercept the event and feed it to the widget
}
void SketcherToolDefaultWidget::KeyboardManager::detectKeyboardEventHandlingMode(
QKeyEvent* keyEvent)
{
QRegularExpression rx(QStringLiteral("^[0-9]$"));
auto match = rx.match(keyEvent->text());
if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return
|| keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Backtab
|| keyEvent->key() == Qt::Key_Backspace || keyEvent->key() == Qt::Key_Delete
|| keyEvent->key() == Qt::Key_Minus || keyEvent->key() == Qt::Key_Period
|| keyEvent->key() == Qt::Key_Comma || match.hasMatch()) {
keyMode = KeyboardEventHandlingMode::Widget;
timer.start(timeOut);
}
}
void SketcherToolDefaultWidget::KeyboardManager::onTimeOut()
{
keyMode = KeyboardEventHandlingMode::ViewProvider;
}
SketcherToolDefaultWidget::SketcherToolDefaultWidget(QWidget* parent)
: QWidget(parent)
, ui(new Ui_SketcherToolDefaultWidget)
@@ -224,16 +156,6 @@ bool SketcherToolDefaultWidget::eventFilter(QObject* object, QEvent* event)
}
}
}
else if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
/*If a key shortcut is required to work on sketcher when a tool using Tool Setting widget
is being used, then you have to add this key to the below section such that the spinbox
doesn't keep the keypress event for itself. Note if you want the event to be handled by
the spinbox too, you can return false.*/
auto keyEvent = static_cast<QKeyEvent*>(event);
return keymanager.handleKeyEvent(keyEvent);
}
return false;
}

View File

@@ -65,42 +65,6 @@ class SketcherToolDefaultWidget: public QWidget
Italic,
};
/** Class to decide which control is responsible of handling an key event
*using timers, type of entered event, ...
*/
class KeyboardManager
{
public:
KeyboardManager();
/// Indicates whether the widget should handle keyboard input or should signal it via boost
enum class KeyboardEventHandlingMode
{
Widget,
ViewProvider
};
bool isMode(KeyboardEventHandlingMode mode);
KeyboardEventHandlingMode getMode();
bool handleKeyEvent(QKeyEvent* keyEvent);
private:
/// This function decides whether events should be send to the ViewProvider
/// or to the UI control of the Default widget.
void detectKeyboardEventHandlingMode(QKeyEvent* keyEvent);
void onTimeOut();
private:
/// Viewer responsible for the active document
Gui::View3DInventorViewer* vpViewer = nullptr;
KeyboardEventHandlingMode keyMode;
QTimer timer;
const int timeOut = 1000;
};
public:
/// Parameter spinbox number/label
enum Parameter
@@ -255,8 +219,6 @@ private:
/// vector using parameter as index indicating whether the value of a parameter was set by the
/// widget
std::vector<bool> isSet;
KeyboardManager keymanager;
};