Attacher UX enhancements

- New editor for MapMode with button to open attacher dialog
- Hide attachment properties when they are not applicable
- Disable super placement ui in attacher dialog when object is not attached
- Always select used mode in mode list
This commit is contained in:
Peter Lama
2017-09-03 22:56:21 -04:00
committed by wmayer
parent 8550967f92
commit 9187919bb8
13 changed files with 255 additions and 28 deletions

View File

@@ -295,7 +295,7 @@ TYPESYSTEM_SOURCE(App::PropertyEnumeration, App::PropertyInteger);
PropertyEnumeration::PropertyEnumeration()
{
_editorTypeName = "Gui::PropertyEditor::PropertyEnumItem";
}
PropertyEnumeration::PropertyEnumeration(const App::Enumeration &e)

View File

@@ -187,7 +187,8 @@ public:
const char ** getEnums(void) const;
//@}
virtual const char * getEditorName(void) const { return "Gui::PropertyEditor::PropertyEnumItem"; }
const char* getEditorName(void) const { return _editorTypeName.c_str(); }
void setEditorName(const char* name) { _editorTypeName = name; }
virtual PyObject * getPyObject(void);
virtual void setPyObject(PyObject *);
@@ -203,6 +204,7 @@ public:
private:
Enumeration _enum;
std::string _editorTypeName;
};
/** Constraint integer properties

View File

@@ -870,6 +870,7 @@ LabelButton::LabelButton (QWidget * parent)
layout->addWidget(button);
connect(button, SIGNAL(clicked()), this, SLOT(browse()));
connect(button, SIGNAL(clicked()), this, SIGNAL(buttonClicked()));
}
LabelButton::~LabelButton()
@@ -903,6 +904,15 @@ void LabelButton::setValue(const QVariant& val)
valueChanged(_val);
}
void LabelButton::showValue(const QVariant& data)
{
label->setText(data.toString());
}
void LabelButton::browse()
{
}
// ----------------------------------------------------------------------
ToolTip* ToolTip::inst = 0;

View File

@@ -298,14 +298,15 @@ public Q_SLOTS:
void setValue(const QVariant&);
protected:
virtual void showValue(const QVariant&) = 0;
virtual void showValue(const QVariant& data);
void resizeEvent(QResizeEvent*);
protected Q_SLOTS:
virtual void browse() = 0;
virtual void browse();
Q_SIGNALS:
void valueChanged(const QVariant &);
void buttonClicked();
private:
QLabel *label;

View File

@@ -48,6 +48,7 @@ AttachExtension::AttachExtension()
EXTENSION_ADD_PROPERTY_TYPE(Support, (0,0), "Attachment",(App::PropertyType)(App::Prop_None),"Support of the 2D geometry");
EXTENSION_ADD_PROPERTY_TYPE(MapMode, (mmDeactivated), "Attachment", App::Prop_None, "Mode of attachment to other object");
MapMode.setEditorName("PartGui::PropertyEnumAttacherItem");
MapMode.setEnums(AttachEngine::eMapModeStrings);
//a rough test if mode string list in Attacher.cpp is in sync with eMapMode enum.
assert(MapMode.getEnumVector().size() == mmDummy_NumberOfModes);
@@ -58,6 +59,11 @@ AttachExtension::AttachExtension()
EXTENSION_ADD_PROPERTY_TYPE(superPlacement, (Base::Placement()), "Attachment", App::Prop_None, "Extra placement to apply in addition to attachment (in local coordinates)");
// Only show these properties when applicable. Controlled by extensionOnChanged
this->MapPathParameter.setStatus(App::Property::Status::Hidden, true);
this->MapReversed.setStatus(App::Property::Status::Hidden, true);
this->superPlacement.setStatus(App::Property::Status::Hidden, true);
setAttacher(new AttachEngine3D);//default attacher
initExtensionType(AttachExtension::getExtensionClassTypeId());
}
@@ -172,8 +178,23 @@ void AttachExtension::extensionOnChanged(const App::Property* prop)
Base::Console().Error("PositionBySupport: %s",e.GetMessageString());
}
// Hide properties when not applicable to reduce user confusion
eMapMode mmode = eMapMode(this->MapMode.getValue());
this->superPlacement.setReadOnly(!bAttached);
bool modeIsPointOnCurve = mmode == mmNormalToPath ||
mmode == mmFrenetNB || mmode == mmFrenetTN || mmode == mmFrenetTB ||
mmode == mmRevolutionSection || mmode == mmConcentric;
// MapPathParameter is only used if there is a reference to one edge and not edge + vertex
bool hasOneRef = false;
if (_attacher && _attacher->references.getSubValues().size() == 1) {
hasOneRef = true;
}
this->MapPathParameter.setStatus(App::Property::Status::Hidden, !bAttached || !(modeIsPointOnCurve && hasOneRef));
this->MapReversed.setStatus(App::Property::Status::Hidden, !bAttached);
this->superPlacement.setStatus(App::Property::Status::Hidden, !bAttached);
getPlacement().setReadOnly(bAttached && mmode != mmTranslate); //for mmTranslate, orientation should remain editable even when attached.
}

View File

@@ -472,8 +472,11 @@ class AttachmentEditorTaskPanel(FrozenClass):
list_widget = self.form.listOfModes
list_widget.clear()
sugr = self.last_sugr
# always have the option to choose Deactivated mode
valid_modes = ['Deactivated'] + sugr['allApplicableModes']
# add valid modes
for m in sugr['allApplicableModes']:
for m in valid_modes:
item = QtGui.QListWidgetItem()
txt = self.attacher.getModeInfo(m)['UserFriendlyName']
item.setText(txt)
@@ -521,8 +524,11 @@ class AttachmentEditorTaskPanel(FrozenClass):
for refstr in mi['ReferenceCombinations']:
refstr_userfriendly = [self.attacher.getRefTypeInfo(t)['UserFriendlyName'] for t in refstr]
cmb.append(u", ".join(refstr_userfriendly))
tip = _translate('AttachmentEditor',"{docu}\n\nReference combinations:\n{combinations}",None).format(docu=mi['BriefDocu'], combinations= u"\n".join(cmb) )
tip = mi['BriefDocu']
if (m != 'Deactivated'):
tip += _translate('AttachmentEditor', "\n\nReference combinations:\n", None) + u"\n".join(cmb)
item.setToolTip(tip)
finally:
@@ -587,8 +593,10 @@ class AttachmentEditorTaskPanel(FrozenClass):
if new_plm is not None:
self.form.groupBox_superplacement.setTitle(_translate('AttachmentEditor',"Extra placement:",None))
self.form.groupBox_superplacement.setEnabled(True)
else:
self.form.groupBox_superplacement.setTitle(_translate('AttachmentEditor',"Extra placement (inactive - not attached):",None))
self.form.groupBox_superplacement.setEnabled(False)
def cleanUp(self):
'''stuff that needs to be done when dialog is closed.'''

View File

@@ -29,6 +29,7 @@
#include <Mod/Part/App/PropertyTopoShape.h>
#include "AttacherTexts.h"
#include "PropertyEnumAttacherItem.h"
#include "SoBrepFaceSet.h"
#include "SoBrepEdgeSet.h"
#include "SoBrepPointSet.h"
@@ -139,6 +140,7 @@ PyMOD_INIT_FUNC(PartGui)
Py_INCREF(pAttachEngineTextsModule);
PyModule_AddObject(partGuiModule, "AttachEngineResources", pAttachEngineTextsModule);
PartGui::PropertyEnumAttacherItem ::init();
PartGui::SoBrepFaceSet ::initClass();
PartGui::SoBrepEdgeSet ::initClass();
PartGui::SoBrepPointSet ::initClass();

View File

@@ -48,7 +48,7 @@ TextSet getUIStrings(Base::Type attacherType, eMapMode mmode)
switch (mmode){
case mmDeactivated:
return TwoStrings(qApp->translate("Attacher3D", "Deactivated","Attachment3D mode caption"),
qApp->translate("Attacher3D", "Attachment is disabled. CS can be moved by editing Placement property.","Attachment3D mode tooltip"));
qApp->translate("Attacher3D", "Attachment is disabled. Object can be moved by editing Placement property.","Attachment3D mode tooltip"));
case mmTranslate:
return TwoStrings(qApp->translate("Attacher3D", "Translate origin","Attachment3D mode caption"),
qApp->translate("Attacher3D", "Origin is aligned to match Vertex. Orientation is controlled by Placement property.","Attachment3D mode tooltip"));
@@ -123,7 +123,7 @@ TextSet getUIStrings(Base::Type attacherType, eMapMode mmode)
switch (mmode){
case mmDeactivated:
return TwoStrings(qApp->translate("Attacher2D", "Deactivated","AttachmentPlane mode caption"),
qApp->translate("Attacher2D", "Attachment is disabled. Plane can be moved by editing Placement property.","AttachmentPlane mode tooltip"));
qApp->translate("Attacher2D", "Attachment is disabled. Object can be moved by editing Placement property.","AttachmentPlane mode tooltip"));
case mmTranslate:
return TwoStrings(qApp->translate("Attacher2D", "Translate origin","AttachmentPlane mode caption"),
qApp->translate("Attacher2D", "Origin is aligned to match Vertex. Orientation is controlled by Placement property.","AttachmentPlane mode tooltip"));

View File

@@ -53,6 +53,7 @@ set(PartGui_MOC_HDRS
DlgSettings3DViewPartImp.h
DlgSettingsGeneral.h
DlgSettingsObjectColor.h
PropertyEnumAttacherItem.h
TaskFaceColors.h
TaskShapeBuilder.h
TaskLoft.h
@@ -161,6 +162,8 @@ SET(PartGui_SRCS
Resources/Part.qrc
PreCompiled.cpp
PreCompiled.h
PropertyEnumAttacherItem.cpp
PropertyEnumAttacherItem.h
SoFCShapeObject.cpp
SoFCShapeObject.h
SoBrepEdgeSet.cpp

View File

@@ -0,0 +1,94 @@
/***************************************************************************
* Copyright (c) 2017 Peter Lama (peterldev94@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"
#include <Gui/Application.h>
#include <Gui/Control.h>
#include <Gui/ViewProviderDocumentObject.h>
#include "PropertyEnumAttacherItem.h"
using namespace PartGui;
PROPERTYITEM_SOURCE(PartGui::PropertyEnumAttacherItem)
PropertyEnumAttacherItem::PropertyEnumAttacherItem()
{
}
QWidget* PropertyEnumAttacherItem::createEditor(QWidget* parent, const QObject* receiver, const char* method) const
{
Gui::LabelButton* modeEditor = new Gui::LabelButton(parent);
QObject::connect(modeEditor, SIGNAL(valueChanged(const QVariant &)), receiver, method);
QObject::connect(modeEditor, SIGNAL(buttonClicked()), this, SLOT(openTask()));
modeEditor->setDisabled(isReadOnly());
return modeEditor;
}
void PropertyEnumAttacherItem::setEditorData(QWidget *editor, const QVariant& data) const
{
Gui::LabelButton* modeEditor = qobject_cast<Gui::LabelButton*>(editor);
modeEditor->setValue(data);
}
QVariant PropertyEnumAttacherItem::editorData(QWidget *editor) const
{
Gui::LabelButton* modeEditor = qobject_cast<Gui::LabelButton*>(editor);
return modeEditor->value();
}
void PropertyEnumAttacherItem::openTask()
{
Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog();
TaskDlgAttacher* task;
task = qobject_cast<TaskDlgAttacher*>(dlg);
if (dlg && !task) {
// there is already another task dialog which must be closed first
Gui::Control().showDialog(dlg);
return;
}
if (!task) {
const App::Property* prop = getFirstProperty();
if (prop) {
App::PropertyContainer* parent = prop->getContainer();
if (parent->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId())) {
App::DocumentObject* obj = static_cast<App::DocumentObject*>(parent);
Gui::ViewProvider* view = Gui::Application::Instance->getViewProvider(obj);
if (view->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId())) {
task = new TaskDlgAttacher(static_cast<Gui::ViewProviderDocumentObject*>(view));
}
}
}
if (!task) {
return;
}
}
Gui::Control().showDialog(task);
}
#include "moc_PropertyEnumAttacherItem.cpp"

View File

@@ -0,0 +1,56 @@
/***************************************************************************
* Copyright (c) 2017 Peter Lama (peterldev94@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 PART_PropertyEnumAttacherItem_H
#define PART_PropertyEnumAttacherItem_H
#include <Gui/propertyeditor/PropertyItem.h>
#include "TaskAttacher.h"
namespace PartGui
{
/**
* Custom editor item for PropertyEnumeration to open Attacher task
*/
class PartGuiExport PropertyEnumAttacherItem: public Gui::PropertyEditor::PropertyEnumItem
{
Q_OBJECT
public:
PROPERTYITEM_HEADER
virtual QWidget* createEditor(QWidget* parent, const QObject* receiver, const char* method) const;
virtual void setEditorData(QWidget* editor, const QVariant& data) const;
virtual QVariant editorData(QWidget* editor) const;
protected Q_SLOTS:
void openTask();
protected:
PropertyEnumAttacherItem();
};
} // namespace PartGui
#endif // PART_PropertyEnumAttacherItem_H

View File

@@ -202,7 +202,8 @@ TaskAttacher::TaskAttacher(Gui::ViewProviderDocumentObject *ViewProvider,QWidget
visibilityAutomation(true);
updateSuperplacementUI();
updateReferencesUI();
updateListOfModes(eMapMode(pcAttach->MapMode.getValue()));
updateListOfModes();
selectMapMode(eMapMode(pcAttach->MapMode.getValue()));
updatePreview();
// connect object deletion with slot
@@ -296,6 +297,8 @@ bool TaskAttacher::updatePreview()
}
QString splmLabelText = attached ? tr("Extra placement:") : tr("Extra placement (inactive - not attached):");
ui->groupBox_superplacement->setTitle(splmLabelText);
ui->groupBox_superplacement->setEnabled(attached);
return attached;
}
@@ -357,7 +360,7 @@ void TaskAttacher::onSelectionChanged(const Gui::SelectionChanges& msg)
try {
pcAttach->Support.setValues(refs, refnames);
updateListOfModes();
eMapMode mmode = getActiveMapMode();//will be mmDeactivated, if no modes are available
eMapMode mmode = getActiveMapMode();//will be mmDeactivated, if selected or if no modes are available
if(mmode == mmDeactivated){
//error = true;
this->completed = false;
@@ -365,6 +368,7 @@ void TaskAttacher::onSelectionChanged(const Gui::SelectionChanges& msg)
this->completed = true;
}
pcAttach->MapMode.setValue(mmode);
selectMapMode(mmode);
updatePreview();
}
catch(Base::Exception& e) {
@@ -524,6 +528,7 @@ void TaskAttacher::onRefName(const QString& text, unsigned idx)
pcAttach->Support.setValues(newrefs, newrefnames);
updateListOfModes();
pcAttach->MapMode.setValue(getActiveMapMode());
selectMapMode(getActiveMapMode());
updatePreview();
@@ -605,6 +610,7 @@ void TaskAttacher::onRefName(const QString& text, unsigned idx)
pcAttach->Support.setValues(refs, refnames);
updateListOfModes();
pcAttach->MapMode.setValue(getActiveMapMode());
selectMapMode(getActiveMapMode());
updateReferencesUI();
}
@@ -695,22 +701,24 @@ void TaskAttacher::updateSuperplacementUI()
ui->superplacementRoll->blockSignals(bBlock);
}
void TaskAttacher::updateListOfModes(eMapMode curMode)
void TaskAttacher::updateListOfModes()
{
//first up, remember currently selected mode.
if (curMode == mmDeactivated){
auto sel = ui->listOfModes->selectedItems();
if (sel.count() > 0)
curMode = modesInList[ui->listOfModes->row(sel[0])];
}
eMapMode curMode = mmDeactivated;
auto sel = ui->listOfModes->selectedItems();
if (sel.count() > 0)
curMode = modesInList[ui->listOfModes->row(sel[0])];
//obtain list of available modes:
Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType<Part::AttachExtension>();
this->lastSuggestResult.bestFitMode = mmDeactivated;
size_t lastValidModeItemIndex = mmDummy_NumberOfModes;
if (pcAttach->Support.getSize() > 0){
pcAttach->attacher().suggestMapModes(this->lastSuggestResult);
modesInList = this->lastSuggestResult.allApplicableModes;
modesInList.insert(modesInList.begin(), mmDeactivated); // always have the option to choose Deactivated mode
//add reachable modes to the list, too, but gray them out (using lastValidModeItemIndex, later)
lastValidModeItemIndex = modesInList.size()-1;
for(std::pair<const eMapMode, refTypeStringList> &rm: this->lastSuggestResult.reachableModes){
@@ -719,6 +727,8 @@ void TaskAttacher::updateListOfModes(eMapMode curMode)
} else {
//no references - display all modes
modesInList.clear();
modesInList.push_back(mmDeactivated);
for( int mmode = 0 ; mmode < mmDummy_NumberOfModes ; mmode++){
if (pcAttach->attacher().modeEnabled[mmode])
modesInList.push_back(eMapMode(mmode));
@@ -735,10 +745,15 @@ void TaskAttacher::updateListOfModes(eMapMode curMode)
std::vector<QString> mstr = AttacherGui::getUIStrings(pcAttach->attacher().getTypeId(),mmode);
ui->listOfModes->addItem(mstr[0]);
QListWidgetItem* item = ui->listOfModes->item(i);
item->setToolTip(mstr[1] + QString::fromLatin1("\n\n") +
tr("Reference combinations:\n") +
AttacherGui::getRefListForMode(pcAttach->attacher(),mmode).join(QString::fromLatin1("\n")));
if (mmode == curMode)
QString tooltip = mstr[1];
if (mmode != mmDeactivated) {
tooltip += tr("\n\nReference combinations:\n") +
AttacherGui::getRefListForMode(pcAttach->attacher(),mmode).join(QString::fromLatin1("\n"));
}
item->setToolTip(tooltip);
if (mmode == curMode && curMode != mmDeactivated)
iSelect = ui->listOfModes->item(i);
if (i > lastValidModeItemIndex){
//potential mode - can be reached by selecting more stuff
@@ -767,10 +782,23 @@ void TaskAttacher::updateListOfModes(eMapMode curMode)
}
}
//restore selection
ui->listOfModes->selectedItems().clear();
if (iSelect)
iSelect->setSelected(true);
ui->listOfModes->blockSignals(false);
}
void TaskAttacher::selectMapMode(eMapMode mmode) {
ui->listOfModes->blockSignals(true);
for (size_t i = 0; i < modesInList.size(); ++i) {
if (modesInList[i] == mmode) {
ui->listOfModes->item(i)->setSelected(true);
}
}
ui->listOfModes->blockSignals(false);
}

View File

@@ -108,12 +108,14 @@ private:
/**
* @brief updateListOfModes Fills the mode list with modes that apply to
* current set of references.
* @param curMode the mode to select in the list. If the mode isn't
* contained in the list, nothing is selected. If mmDeactivated is passed,
* currently selected mode is kept.
* current set of references. Maintains selection when possible.
*/
void updateListOfModes(Attacher::eMapMode curMode = Attacher::mmDeactivated);
void updateListOfModes();
/**
* @brief selectMapMode Select the given mode in the list widget
*/
void selectMapMode(Attacher::eMapMode mmode);
protected:
Gui::ViewProviderDocumentObject *ViewProvider;