Merge pull request #23620 from hyarion/fix/qm
Gui: Toggle quick measure and input hints from status bar context menu
This commit is contained in:
@@ -1382,6 +1382,7 @@ SET(FreeCADGui_CPP_SRCS
|
||||
resource.cpp
|
||||
Control.cpp
|
||||
SpaceballEvent.cpp
|
||||
StatusBarLabel.cpp
|
||||
PreferencePackManager.cpp
|
||||
Thumbnail.cpp
|
||||
Utilities.cpp
|
||||
@@ -1431,6 +1432,7 @@ SET(FreeCADGui_SRCS
|
||||
WaitCursor.h
|
||||
ManualAlignment.h
|
||||
StartupProcess.h
|
||||
StatusBarLabel.h
|
||||
TransactionObject.h
|
||||
ToolHandler.h
|
||||
StyleParameters/Parser.h
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "InputHint.h"
|
||||
#include "InputHintWidget.h"
|
||||
|
||||
Gui::InputHintWidget::InputHintWidget(QWidget* parent) : QLabel(parent)
|
||||
Gui::InputHintWidget::InputHintWidget(QWidget* parent) : StatusBarLabel(parent, "InputHintEnabled")
|
||||
{}
|
||||
|
||||
void Gui::InputHintWidget::showHints(const std::list<InputHint>& hints)
|
||||
|
||||
@@ -24,16 +24,16 @@
|
||||
#ifndef INPUTHINTWIDGET_H
|
||||
#define INPUTHINTWIDGET_H
|
||||
|
||||
#include <QLabel>
|
||||
#include <optional>
|
||||
|
||||
#include <FCGlobal.h>
|
||||
|
||||
#include "StatusBarLabel.h"
|
||||
#include "InputHint.h"
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
class GuiExport InputHintWidget : public QLabel
|
||||
class GuiExport InputHintWidget : public StatusBarLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
#include "ReportView.h"
|
||||
#include "SelectionView.h"
|
||||
#include "SplashScreen.h"
|
||||
#include "StatusBarLabel.h"
|
||||
#include "ToolBarManager.h"
|
||||
#include "ToolBoxManager.h"
|
||||
#include "Tree.h"
|
||||
@@ -390,7 +391,7 @@ MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags f)
|
||||
|
||||
// labels and progressbar
|
||||
d->status = new StatusBarObserver();
|
||||
d->actionLabel = new QLabel(statusBar());
|
||||
d->actionLabel = new StatusBarLabel(statusBar());
|
||||
d->actionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
d->sizeLabel = new DimensionWidget(statusBar());
|
||||
|
||||
@@ -401,12 +402,19 @@ MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags f)
|
||||
|
||||
// hint label
|
||||
d->hintLabel = new InputHintWidget(statusBar());
|
||||
d->hintLabel->setObjectName(QStringLiteral("hintLabel"));
|
||||
//: A context menu action used to show or hide the input hints in the status bar
|
||||
d->hintLabel->setWindowTitle(tr("Input hints"));
|
||||
|
||||
statusBar()->addWidget(d->hintLabel);
|
||||
|
||||
// right side label
|
||||
d->rightSideLabel = new QLabel(statusBar());
|
||||
d->rightSideLabel = new StatusBarLabel(statusBar(), "QuickMeasureEnabled");
|
||||
d->rightSideLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
statusBar()->addPermanentWidget(d->rightSideLabel);
|
||||
d->rightSideLabel->setObjectName(QStringLiteral("rightSideLabel"));
|
||||
//: A context menu action used to enable or disable quick measure in the status bar
|
||||
d->rightSideLabel->setWindowTitle(tr("Quick measure"));
|
||||
|
||||
auto hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/NotificationArea");
|
||||
|
||||
@@ -2252,6 +2260,11 @@ void MainWindow::setRightSideMessage(const QString& message)
|
||||
d->rightSideLabel->setText(message.simplified());
|
||||
}
|
||||
|
||||
bool MainWindow::isRightSideMessageVisible() const
|
||||
{
|
||||
return d->rightSideLabel->isVisible();
|
||||
}
|
||||
|
||||
void MainWindow::showStatus(int type, const QString& message)
|
||||
{
|
||||
if(QApplication::instance()->thread() != QThread::currentThread()) {
|
||||
|
||||
@@ -266,6 +266,7 @@ public Q_SLOTS:
|
||||
|
||||
void showMessage (const QString & message, int timeout = 0);
|
||||
void setRightSideMessage(const QString & message);
|
||||
bool isRightSideMessageVisible() const;
|
||||
|
||||
// Set main window title
|
||||
void setWindowTitle(const QString& string);
|
||||
|
||||
101
src/Gui/StatusBarLabel.cpp
Normal file
101
src/Gui/StatusBarLabel.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2025 Benjamin Nauck <benjamin@nauck.se> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QMenu>
|
||||
#include <QClipboard>
|
||||
#include <QApplication>
|
||||
#include <QStatusBar>
|
||||
#include <QAction>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QHideEvent>
|
||||
|
||||
#include "StatusBarLabel.h"
|
||||
#include <App/Application.h>
|
||||
|
||||
namespace Gui {
|
||||
|
||||
StatusBarLabel::StatusBarLabel(QWidget *parent, const std::string& parameterName)
|
||||
: QLabel(parent)
|
||||
{
|
||||
if (!parameterName.empty()) {
|
||||
hGrp = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/MainWindow");
|
||||
|
||||
// set visibility before storing parameterName to avoid saving it immediately
|
||||
setVisible(hGrp->GetBool(parameterName.c_str(), false));
|
||||
|
||||
// now we can store parameterName
|
||||
this->parameterName = parameterName;
|
||||
}
|
||||
}
|
||||
|
||||
void StatusBarLabel::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
QMenu menu(this);
|
||||
|
||||
// Reproduce standard status bar widget menu
|
||||
if (auto *statusBar = qobject_cast<QStatusBar*>(parentWidget())) {
|
||||
for (QObject *child : statusBar->children()) {
|
||||
QWidget *widget = qobject_cast<QWidget*>(child);
|
||||
if (!widget) {
|
||||
continue;
|
||||
}
|
||||
auto title = widget->windowTitle();
|
||||
if (title.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QAction *action = menu.addAction(title);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(widget->isVisible());
|
||||
QObject::connect(action, &QAction::toggled, widget, &QWidget::setVisible);
|
||||
}
|
||||
}
|
||||
|
||||
if (textInteractionFlags() & Qt::TextSelectableByMouse) {
|
||||
menu.addSeparator(); // ----------
|
||||
|
||||
// Copy + Select All
|
||||
menu.addAction(tr("Copy"), [this]() {
|
||||
QApplication::clipboard()->setText(this->selectedText());
|
||||
});
|
||||
menu.addAction(tr("Select All"), [this]() {
|
||||
this->setSelection(0, this->text().length());
|
||||
});
|
||||
}
|
||||
|
||||
menu.exec(event->globalPos());
|
||||
}
|
||||
|
||||
void StatusBarLabel::setVisible(bool visible)
|
||||
{
|
||||
if (!parameterName.empty() && hGrp) {
|
||||
hGrp->SetBool(parameterName.c_str(), visible);
|
||||
}
|
||||
if (!visible) {
|
||||
clear(); // Clear text
|
||||
}
|
||||
QLabel::setVisible(visible);
|
||||
}
|
||||
|
||||
} // namespace Gui
|
||||
63
src/Gui/StatusBarLabel.h
Normal file
63
src/Gui/StatusBarLabel.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2025 Benjamin Nauck <benjamin@nauck.se> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef STATUSBARLABEL_H
|
||||
#define STATUSBARLABEL_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QLabel>
|
||||
#include <QStatusBar>
|
||||
#include <QMenu>
|
||||
|
||||
#include <FCGlobal.h>
|
||||
|
||||
#include <Base/Parameter.h>
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
/**
|
||||
* @brief Label for displaying information in the status bar
|
||||
*
|
||||
* A QLabel subclass that provides a context menu with additional actions
|
||||
* similar to the standard status bar widgets.
|
||||
*/
|
||||
class GuiExport StatusBarLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit StatusBarLabel(QWidget *parent, const std::string& parameterName = {});
|
||||
protected:
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
void setVisible(bool visible) override;
|
||||
private:
|
||||
ParameterGrp::handle hGrp;
|
||||
std::string parameterName;
|
||||
};
|
||||
|
||||
} // Namespace Gui
|
||||
#endif //STATUSBARLABEL_H
|
||||
@@ -725,7 +725,6 @@ MenuItem* StdWorkbench::setupMenuBar() const
|
||||
#endif
|
||||
*tool << "Std_Measure"
|
||||
<< "Std_ClarifySelection"
|
||||
<< "Std_QuickMeasure"
|
||||
<< "Std_UnitsCalculator"
|
||||
<< "Separator"
|
||||
<< "Std_ViewLoadImage"
|
||||
|
||||
@@ -110,5 +110,8 @@ PyMOD_INIT_FUNC(MeasureGui)
|
||||
|
||||
Base::Interpreter().addType(&MeasureGui::QuickMeasurePy::Type, mod, "QuickMeasure");
|
||||
|
||||
// Create a QuickMeasure instance
|
||||
new MeasureGui::QuickMeasure(QApplication::instance());
|
||||
|
||||
PyMOD_Return(mod);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <Gui/Action.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/Control.h>
|
||||
@@ -32,7 +31,6 @@
|
||||
#include <Gui/View3DInventor.h>
|
||||
#include <Gui/View3DInventorViewer.h>
|
||||
|
||||
#include "QuickMeasure.h"
|
||||
#include "TaskMeasure.h"
|
||||
|
||||
|
||||
@@ -79,68 +77,6 @@ bool StdCmdMeasure::isActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
class StdCmdQuickMeasure: public Gui::Command
|
||||
{
|
||||
public:
|
||||
StdCmdQuickMeasure()
|
||||
: Command("Std_QuickMeasure")
|
||||
{
|
||||
sGroup = "Measure";
|
||||
sMenuText = QT_TR_NOOP("&Quick measure");
|
||||
sToolTipText = QT_TR_NOOP("Toggle quick measure");
|
||||
sWhatsThis = "Std_QuickMeasure";
|
||||
sStatusTip = QT_TR_NOOP("Toggle quick measure");
|
||||
accessParameter();
|
||||
}
|
||||
~StdCmdQuickMeasure() override = default;
|
||||
StdCmdQuickMeasure(const StdCmdQuickMeasure&) = delete;
|
||||
StdCmdQuickMeasure(StdCmdQuickMeasure&&) = delete;
|
||||
StdCmdQuickMeasure& operator=(const StdCmdQuickMeasure&) = delete;
|
||||
StdCmdQuickMeasure& operator=(StdCmdQuickMeasure&&) = delete;
|
||||
|
||||
const char* className() const override
|
||||
{
|
||||
return "StdCmdQuickMeasure";
|
||||
}
|
||||
|
||||
protected:
|
||||
void activated(int iMsg) override
|
||||
{
|
||||
if (parameter.isValid()) {
|
||||
parameter->SetBool("EnableQuickMeasure", iMsg > 0);
|
||||
}
|
||||
|
||||
if (iMsg == 0) {
|
||||
if (quickMeasure) {
|
||||
quickMeasure->print(QString());
|
||||
}
|
||||
quickMeasure.reset();
|
||||
}
|
||||
else {
|
||||
quickMeasure = std::make_unique<MeasureGui::QuickMeasure>(QApplication::instance());
|
||||
}
|
||||
}
|
||||
Gui::Action* createAction() override
|
||||
{
|
||||
Gui::Action* action = Gui::Command::createAction();
|
||||
action->setCheckable(true);
|
||||
action->setChecked(parameter->GetBool("EnableQuickMeasure", true));
|
||||
return action;
|
||||
}
|
||||
void accessParameter()
|
||||
{
|
||||
// clang-format off
|
||||
parameter = App::GetApplication().GetUserParameter().
|
||||
GetGroup("BaseApp/Preferences/Mod/Measure");
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<MeasureGui::QuickMeasure> quickMeasure;
|
||||
ParameterGrp::handle parameter;
|
||||
};
|
||||
|
||||
void CreateMeasureCommands()
|
||||
{
|
||||
Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager();
|
||||
@@ -148,5 +84,4 @@ void CreateMeasureCommands()
|
||||
auto cmd = new StdCmdMeasure();
|
||||
cmd->initAction();
|
||||
rcCmdMgr.addCommand(cmd);
|
||||
rcCmdMgr.addCommand(new StdCmdQuickMeasure);
|
||||
}
|
||||
|
||||
@@ -114,18 +114,23 @@ void QuickMeasure::tryMeasureSelection()
|
||||
|
||||
bool QuickMeasure::shouldMeasure(const Gui::SelectionChanges& msg) const
|
||||
{
|
||||
if (!Gui::getMainWindow()->isRightSideMessageVisible()) {
|
||||
// don't measure if there's no where to show the result
|
||||
return false;
|
||||
}
|
||||
|
||||
// measure only IF
|
||||
Gui::Document* doc = Gui::Application::Instance->activeDocument();
|
||||
if (doc) {
|
||||
// we have a document
|
||||
if (msg.Type == Gui::SelectionChanges::AddSelection
|
||||
|| msg.Type == Gui::SelectionChanges::RmvSelection
|
||||
|| msg.Type == Gui::SelectionChanges::SetSelection
|
||||
|| msg.Type == Gui::SelectionChanges::ClrSelection) {
|
||||
// the event is about a change in selected objects
|
||||
return true;
|
||||
}
|
||||
if (!doc) {
|
||||
// no active document
|
||||
return false;
|
||||
}
|
||||
|
||||
if (msg.Type == Gui::SelectionChanges::AddSelection
|
||||
|| msg.Type == Gui::SelectionChanges::RmvSelection
|
||||
|| msg.Type == Gui::SelectionChanges::SetSelection
|
||||
|| msg.Type == Gui::SelectionChanges::ClrSelection) {
|
||||
// the event is about a change in selected objects
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user