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:
committed by
abdullahtahiriyo
parent
a5b5d01c22
commit
82fed5bbfc
@@ -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
|
||||
|
||||
198
src/Mod/Sketcher/Gui/DrawSketchControllableHandler.h
Normal file
198
src/Mod/Sketcher/Gui/DrawSketchControllableHandler.h
Normal 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
|
||||
573
src/Mod/Sketcher/Gui/DrawSketchController.h
Normal file
573
src/Mod/Sketcher/Gui/DrawSketchController.h
Normal 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
|
||||
@@ -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(
|
||||
|
||||
371
src/Mod/Sketcher/Gui/DrawSketchDefaultWidgetController.h
Normal file
371
src/Mod/Sketcher/Gui/DrawSketchDefaultWidgetController.h
Normal 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
129
src/Mod/Sketcher/Gui/DrawSketchKeyboardManager.cpp
Normal file
129
src/Mod/Sketcher/Gui/DrawSketchKeyboardManager.cpp
Normal 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"
|
||||
104
src/Mod/Sketcher/Gui/DrawSketchKeyboardManager.h
Normal file
104
src/Mod/Sketcher/Gui/DrawSketchKeyboardManager.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user