Improves the use of the ShapeAppearance property for the Part workbench.
removes DiffuseColor property
adds Python compatibility using custom attributes
transitions DiffuseColor to ShapeAppearance on open
Improved UI elements for setting object appearance, and appearance per face
Lays the foundation for future texture support
556 lines
20 KiB
C++
556 lines
20 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2011 Juergen Riegel <FreeCAD@juergen-riegel.net> *
|
|
* *
|
|
* 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/actions/SoGetBoundingBoxAction.h>
|
|
# include <Inventor/nodes/SoSeparator.h>
|
|
# include <Precision.hxx>
|
|
# include <QMenu>
|
|
#endif
|
|
|
|
#include <App/Document.h>
|
|
#include <App/Origin.h>
|
|
#include <App/Part.h>
|
|
#include <Base/Console.h>
|
|
#include <Gui/ActionFunction.h>
|
|
#include <Gui/Application.h>
|
|
#include <Gui/Command.h>
|
|
#include <Gui/Document.h>
|
|
#include <Gui/MDIView.h>
|
|
#include <Gui/View3DInventor.h>
|
|
#include <Gui/View3DInventorViewer.h>
|
|
#include <Gui/ViewProviderOrigin.h>
|
|
#include <Gui/ViewProviderOriginFeature.h>
|
|
#include <Mod/PartDesign/App/Body.h>
|
|
#include <Mod/PartDesign/App/DatumCS.h>
|
|
#include <Mod/PartDesign/App/FeatureSketchBased.h>
|
|
#include <Mod/PartDesign/App/FeatureBase.h>
|
|
|
|
#include "ViewProviderBody.h"
|
|
#include "Utils.h"
|
|
#include "ViewProvider.h"
|
|
#include "ViewProviderDatum.h"
|
|
|
|
|
|
using namespace PartDesignGui;
|
|
namespace sp = std::placeholders;
|
|
|
|
const char* PartDesignGui::ViewProviderBody::BodyModeEnum[] = {"Through","Tip",nullptr};
|
|
|
|
PROPERTY_SOURCE_WITH_EXTENSIONS(PartDesignGui::ViewProviderBody,PartGui::ViewProviderPart)
|
|
|
|
ViewProviderBody::ViewProviderBody()
|
|
{
|
|
ADD_PROPERTY(DisplayModeBody,((long)0));
|
|
DisplayModeBody.setEnums(BodyModeEnum);
|
|
|
|
sPixmap = "PartDesign_Body.svg";
|
|
|
|
Gui::ViewProviderOriginGroupExtension::initExtension(this);
|
|
}
|
|
|
|
ViewProviderBody::~ViewProviderBody()
|
|
{
|
|
connectChangedObjectApp.disconnect();
|
|
connectChangedObjectGui.disconnect();
|
|
}
|
|
|
|
void ViewProviderBody::attach(App::DocumentObject *pcFeat)
|
|
{
|
|
// call parent attach method
|
|
ViewProviderPart::attach(pcFeat);
|
|
|
|
//set default display mode
|
|
onChanged(&DisplayModeBody);
|
|
|
|
App::Document *adoc = pcObject->getDocument ();
|
|
Gui::Document *gdoc = Gui::Application::Instance->getDocument ( adoc ) ;
|
|
|
|
assert ( adoc );
|
|
assert ( gdoc );
|
|
|
|
//NOLINTBEGIN
|
|
connectChangedObjectApp = adoc->signalChangedObject.connect (
|
|
std::bind ( &ViewProviderBody::slotChangedObjectApp, this, sp::_1, sp::_2) );
|
|
|
|
connectChangedObjectGui = gdoc->signalChangedObject.connect (
|
|
std::bind ( &ViewProviderBody::slotChangedObjectGui, this, sp::_1, sp::_2) );
|
|
//NOLINTEND
|
|
}
|
|
|
|
// TODO on activating the body switch to the "Through" mode (2015-09-05, Fat-Zer)
|
|
// TODO different icon in tree if mode is Through (2015-09-05, Fat-Zer)
|
|
// TODO drag&drop (2015-09-05, Fat-Zer)
|
|
// TODO Add activate () call (2015-09-08, Fat-Zer)
|
|
|
|
void ViewProviderBody::setDisplayMode(const char* ModeName) {
|
|
|
|
//if we show "Through" we must avoid to set the display mask modes, as this would result
|
|
//in going into "tip" mode. When through is chosen the child features are displayed, and all
|
|
//we need to ensure is that the display mode change is propagated to them from within the
|
|
//onChanged() method.
|
|
if(DisplayModeBody.getValue() == 1)
|
|
PartGui::ViewProviderPartExt::setDisplayMode(ModeName);
|
|
}
|
|
|
|
void ViewProviderBody::setOverrideMode(const std::string& mode) {
|
|
|
|
//if we are in through mode, we need to ensure that the override mode is not set for the body
|
|
//(as this would result in "tip" mode), it is enough when the children are set to the correct
|
|
//override mode.
|
|
|
|
if(DisplayModeBody.getValue() != 0)
|
|
Gui::ViewProvider::setOverrideMode(mode);
|
|
else
|
|
overrideMode = mode;
|
|
}
|
|
|
|
void ViewProviderBody::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
|
|
{
|
|
Q_UNUSED(receiver);
|
|
Q_UNUSED(member);
|
|
Gui::ActionFunction* func = new Gui::ActionFunction(menu);
|
|
|
|
QAction* act = menu->addAction(tr("Active body"));
|
|
act->setCheckable(true);
|
|
act->setChecked(isActiveBody());
|
|
func->trigger(act, [this]() {
|
|
this->toggleActiveBody();
|
|
});
|
|
|
|
Gui::ViewProviderGeometryObject::setupContextMenu(menu, receiver, member); // clazy:exclude=skipped-base-method
|
|
}
|
|
|
|
bool ViewProviderBody::isActiveBody()
|
|
{
|
|
auto activeDoc = Gui::Application::Instance->activeDocument();
|
|
if(!activeDoc)
|
|
activeDoc = getDocument();
|
|
auto activeView = activeDoc->setActiveView(this);
|
|
if(!activeView)
|
|
return false;
|
|
|
|
if (activeView->isActiveObject(getObject(),PDBODYKEY)){
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void ViewProviderBody::toggleActiveBody()
|
|
{
|
|
if (isActiveBody()) {
|
|
//active body double-clicked. Deactivate.
|
|
Gui::Command::doCommand(Gui::Command::Gui,
|
|
"Gui.ActiveDocument.ActiveView.setActiveObject('%s', None)", PDBODYKEY);
|
|
} else {
|
|
|
|
// assure the PartDesign workbench
|
|
if(App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/PartDesign")->GetBool("SwitchToWB", true))
|
|
Gui::Command::assureWorkbench("PartDesignWorkbench");
|
|
|
|
// and set correct active objects
|
|
auto* part = App::Part::getPartOfObject ( getObject() );
|
|
if ( part && !isActiveBody() ) {
|
|
Gui::Command::doCommand(Gui::Command::Gui,
|
|
"Gui.ActiveDocument.ActiveView.setActiveObject('%s',%s)",
|
|
PARTKEY, Gui::Command::getObjectCmd(part).c_str());
|
|
}
|
|
|
|
Gui::Command::doCommand(Gui::Command::Gui,
|
|
"Gui.ActiveDocument.ActiveView.setActiveObject('%s',%s)",
|
|
PDBODYKEY, Gui::Command::getObjectCmd(getObject()).c_str());
|
|
}
|
|
}
|
|
|
|
bool ViewProviderBody::doubleClicked()
|
|
{
|
|
toggleActiveBody();
|
|
return true;
|
|
}
|
|
|
|
|
|
// TODO To be deleted (2015-09-08, Fat-Zer)
|
|
//void ViewProviderBody::updateTree()
|
|
//{
|
|
// if (ActiveGuiDoc == NULL) return;
|
|
//
|
|
// // Highlight active body and all its features
|
|
// //Base::Console().Error("ViewProviderBody::updateTree()\n");
|
|
// PartDesign::Body* body = static_cast<PartDesign::Body*>(getObject());
|
|
// bool active = body->IsActive.getValue();
|
|
// //Base::Console().Error("Body is %s\n", active ? "active" : "inactive");
|
|
// ActiveGuiDoc->signalHighlightObject(*this, Gui::Blue, active);
|
|
// std::vector<App::DocumentObject*> features = body->Group.getValues();
|
|
// bool highlight = true;
|
|
// App::DocumentObject* tip = body->Tip.getValue();
|
|
// for (std::vector<App::DocumentObject*>::const_iterator f = features.begin(); f != features.end(); f++) {
|
|
// //Base::Console().Error("Highlighting %s: %s\n", (*f)->getNameInDocument(), highlight ? "true" : "false");
|
|
// Gui::ViewProviderDocumentObject* vp = dynamic_cast<Gui::ViewProviderDocumentObject*>(Gui::Application::Instance->getViewProvider(*f));
|
|
// if (vp != NULL)
|
|
// ActiveGuiDoc->signalHighlightObject(*vp, Gui::LightBlue, active ? highlight : false);
|
|
// if (highlight && (tip == *f))
|
|
// highlight = false;
|
|
// }
|
|
//}
|
|
|
|
bool ViewProviderBody::onDelete ( const std::vector<std::string> &) {
|
|
// TODO May be do it conditionally? (2015-09-05, Fat-Zer)
|
|
FCMD_OBJ_CMD(getObject(),"removeObjectsFromDocument()");
|
|
return true;
|
|
}
|
|
|
|
void ViewProviderBody::updateData(const App::Property* prop)
|
|
{
|
|
PartDesign::Body* body = static_cast<PartDesign::Body*>(getObject());
|
|
|
|
if (prop == &body->Group || prop == &body->BaseFeature) {
|
|
// update sizes of origins and datums
|
|
updateOriginDatumSize ();
|
|
//ensure all model features are in visual body mode
|
|
setVisualBodyMode(true);
|
|
}
|
|
|
|
if (prop == &body->Tip) {
|
|
// We changed Tip
|
|
App::DocumentObject* tip = body->Tip.getValue();
|
|
|
|
auto features = body->Group.getValues();
|
|
|
|
// restore icons
|
|
for (auto feature : features) {
|
|
Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(feature);
|
|
if (vp && vp->isDerivedFrom(PartDesignGui::ViewProvider::getClassTypeId())) {
|
|
static_cast<PartDesignGui::ViewProvider*>(vp)->setTipIcon(feature == tip);
|
|
}
|
|
}
|
|
|
|
if (tip)
|
|
copyColorsfromTip(tip);
|
|
}
|
|
|
|
PartGui::ViewProviderPart::updateData(prop);
|
|
}
|
|
|
|
void ViewProviderBody::copyColorsfromTip(App::DocumentObject* tip) {
|
|
// update ShapeAppearance
|
|
Gui::ViewProvider* vptip = Gui::Application::Instance->getViewProvider(tip);
|
|
if (vptip && vptip->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) {
|
|
auto materials = static_cast<PartGui::ViewProviderPartExt*>(vptip)->ShapeAppearance.getValues();
|
|
this->ShapeAppearance.setValues(materials);
|
|
}
|
|
}
|
|
|
|
void ViewProviderBody::slotChangedObjectApp ( const App::DocumentObject& obj, const App::Property& prop ) {
|
|
|
|
if(App::GetApplication().isRestoring())
|
|
return;
|
|
|
|
if (!obj.isDerivedFrom ( Part::Feature::getClassTypeId () ) ||
|
|
obj.isDerivedFrom ( Part::BodyBase::getClassTypeId () ) ) { // we are interested only in Part::Features, not in bodies
|
|
return;
|
|
}
|
|
|
|
const Part::Feature *feat = static_cast <const Part::Feature *>(&obj);
|
|
|
|
if ( &feat->Shape != &prop && &feat->Placement != &prop) { // react only on changes in shapes and placement
|
|
return;
|
|
}
|
|
|
|
PartDesign::Body *body = static_cast<PartDesign::Body*> ( getObject() );
|
|
if ( body && body->hasObject (&obj ) ) {
|
|
updateOriginDatumSize ();
|
|
}
|
|
}
|
|
|
|
void ViewProviderBody::slotChangedObjectGui (
|
|
const Gui::ViewProviderDocumentObject& vp, const App::Property& prop )
|
|
{
|
|
if (&vp.Visibility != &prop) { // react only on visibility changes
|
|
return;
|
|
}
|
|
|
|
if ( !vp.isDerivedFrom ( Gui::ViewProviderOrigin::getClassTypeId () ) &&
|
|
!vp.isDerivedFrom ( Gui::ViewProviderOriginFeature::getClassTypeId () ) ) {
|
|
// Ignore origins to avoid infinite recursion (not likely in a well-formed document,
|
|
// but may happen in documents designed in old versions of assembly branch )
|
|
return;
|
|
}
|
|
|
|
PartDesign::Body *body = static_cast<PartDesign::Body*> ( getObject() );
|
|
App::DocumentObject *obj = vp.getObject ();
|
|
|
|
if ( body && obj && body->hasObject ( obj ) ) {
|
|
updateOriginDatumSize ();
|
|
}
|
|
}
|
|
|
|
void ViewProviderBody::updateOriginDatumSize () {
|
|
PartDesign::Body *body = static_cast<PartDesign::Body *> ( getObject() );
|
|
|
|
// Use different bounding boxes for datums and for origins:
|
|
Gui::Document* gdoc = Gui::Application::Instance->getDocument(getObject()->getDocument());
|
|
if(!gdoc)
|
|
return;
|
|
|
|
Gui::MDIView* view = gdoc->getViewOfViewProvider(this);
|
|
if(!view)
|
|
return;
|
|
|
|
Gui::View3DInventorViewer* viewer = static_cast<Gui::View3DInventor*>(view)->getViewer();
|
|
SoGetBoundingBoxAction bboxAction(viewer->getSoRenderManager()->getViewportRegion());
|
|
|
|
const auto & model = body->getFullModel ();
|
|
|
|
// BBox for Datums is calculated from all visible objects but treating datums as their basepoints only
|
|
SbBox3f bboxDatums = ViewProviderDatum::getRelevantBoundBox ( bboxAction, model );
|
|
// BBox for origin should take into account datums size also
|
|
SbBox3f bboxOrigins = bboxDatums;
|
|
|
|
for(App::DocumentObject* obj : model) {
|
|
if ( obj->isDerivedFrom ( Part::Datum::getClassTypeId () ) ) {
|
|
ViewProvider *vp = Gui::Application::Instance->getViewProvider(obj);
|
|
if (!vp) { continue; }
|
|
|
|
ViewProviderDatum *vpDatum = static_cast <ViewProviderDatum *> (vp) ;
|
|
|
|
vpDatum->setExtents ( bboxDatums );
|
|
|
|
bboxAction.apply ( vp->getRoot () );
|
|
bboxOrigins.extendBy ( bboxAction.getBoundingBox () );
|
|
}
|
|
}
|
|
|
|
// get the bounding box values
|
|
SbVec3f max = bboxOrigins.getMax();
|
|
SbVec3f min = bboxOrigins.getMin();
|
|
|
|
// obtain an Origin and it's ViewProvider
|
|
App::Origin* origin = nullptr;
|
|
Gui::ViewProviderOrigin* vpOrigin = nullptr;
|
|
try {
|
|
origin = body->getOrigin ();
|
|
assert (origin);
|
|
|
|
Gui::ViewProvider *vp = Gui::Application::Instance->getViewProvider(origin);
|
|
if (!vp) {
|
|
throw Base::ValueError ("No view provider linked to the Origin");
|
|
}
|
|
assert ( vp->isDerivedFrom ( Gui::ViewProviderOrigin::getClassTypeId () ) );
|
|
vpOrigin = static_cast <Gui::ViewProviderOrigin *> ( vp );
|
|
} catch (const Base::Exception &ex) {
|
|
if(!getExtendedViewProvider()->getDocument()->getDocument()->testStatus(App::Document::Restoring))
|
|
Base::Console().Error ("%s\n", ex.what() );
|
|
return;
|
|
}
|
|
|
|
// calculate the desired origin size
|
|
Base::Vector3d size;
|
|
|
|
for (uint_fast8_t i=0; i<3; i++) {
|
|
size[i] = std::max ( fabs ( max[i] ), fabs ( min[i] ) );
|
|
if (size[i] < Precision::Confusion() ) {
|
|
size[i] = Gui::ViewProviderOrigin::defaultSize();
|
|
}
|
|
}
|
|
|
|
vpOrigin->Size.setValue ( size*1.2 );
|
|
}
|
|
|
|
void ViewProviderBody::onChanged(const App::Property* prop) {
|
|
|
|
if(prop == &DisplayModeBody) {
|
|
auto body = dynamic_cast<PartDesign::Body*>(getObject());
|
|
|
|
if ( DisplayModeBody.getValue() == 0 ) {
|
|
//if we are in an override mode we need to make sure to come out, because
|
|
//otherwise the maskmode is blocked and won't go into "through"
|
|
if(getOverrideMode() != "As Is") {
|
|
auto mode = getOverrideMode();
|
|
ViewProvider::setOverrideMode("As Is");
|
|
overrideMode = mode;
|
|
}
|
|
setDisplayMaskMode("Group");
|
|
if(body)
|
|
body->setShowTip(false);
|
|
}
|
|
else {
|
|
if(body)
|
|
body->setShowTip(true);
|
|
if(getOverrideMode() == "As Is")
|
|
setDisplayMaskMode(DisplayMode.getValueAsString());
|
|
else {
|
|
Base::Console().Message("Set override mode: %s\n", getOverrideMode().c_str());
|
|
setDisplayMaskMode(getOverrideMode().c_str());
|
|
}
|
|
}
|
|
|
|
// #0002559: Body becomes visible upon changing DisplayModeBody
|
|
Visibility.touch();
|
|
}
|
|
else
|
|
unifyVisualProperty(prop);
|
|
|
|
PartGui::ViewProviderPartExt::onChanged(prop);
|
|
}
|
|
|
|
|
|
void ViewProviderBody::unifyVisualProperty(const App::Property* prop) {
|
|
|
|
if (!pcObject || isRestoring()) {
|
|
return;
|
|
}
|
|
|
|
if (prop == &Visibility ||
|
|
prop == &Selectable ||
|
|
prop == &DisplayModeBody ||
|
|
prop == &PointColorArray ||
|
|
prop == &LineColorArray) {
|
|
return;
|
|
}
|
|
|
|
// Fixes issue 11197. In case of affected projects where the bounding box of a sub-feature
|
|
// is shown allow it to hide it
|
|
if (prop == &BoundingBox) {
|
|
if (BoundingBox.getValue()) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
Gui::Document *gdoc = Gui::Application::Instance->getDocument ( pcObject->getDocument() ) ;
|
|
|
|
PartDesign::Body *body = static_cast<PartDesign::Body *> ( getObject() );
|
|
auto features = body->Group.getValues();
|
|
for (auto feature : features) {
|
|
|
|
if (!feature->isDerivedFrom(PartDesign::Feature::getClassTypeId())) {
|
|
continue;
|
|
}
|
|
|
|
//copy over the properties data
|
|
auto fprop = gdoc->getViewProvider(feature)->getPropertyByName(prop->getName());
|
|
fprop->Paste(*prop);
|
|
}
|
|
}
|
|
|
|
void ViewProviderBody::setVisualBodyMode(bool bodymode) {
|
|
|
|
Gui::Document *gdoc = Gui::Application::Instance->getDocument ( pcObject->getDocument() ) ;
|
|
|
|
PartDesign::Body *body = static_cast<PartDesign::Body *> ( getObject() );
|
|
auto features = body->Group.getValues();
|
|
for(auto feature : features) {
|
|
|
|
if(!feature->isDerivedFrom(PartDesign::Feature::getClassTypeId()))
|
|
continue;
|
|
|
|
auto* vp = static_cast<PartDesignGui::ViewProvider*>(gdoc->getViewProvider(feature));
|
|
if (vp) vp->setBodyMode(bodymode);
|
|
}
|
|
}
|
|
|
|
std::vector< std::string > ViewProviderBody::getDisplayModes() const {
|
|
|
|
//we get all display modes and remove the "Group" mode, as this is what we use for "Through"
|
|
//body display mode
|
|
std::vector< std::string > modes = ViewProviderPart::getDisplayModes();
|
|
modes.erase(modes.begin());
|
|
return modes;
|
|
}
|
|
|
|
bool ViewProviderBody::canDropObjects() const
|
|
{
|
|
// if the BaseFeature property is marked as hidden or read-only then
|
|
// it's not allowed to modify it.
|
|
PartDesign::Body* body = static_cast<PartDesign::Body*>(getObject());
|
|
if (body->BaseFeature.testStatus(App::Property::Status::Hidden))
|
|
return false;
|
|
if (body->BaseFeature.testStatus(App::Property::Status::ReadOnly))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool ViewProviderBody::canDropObject(App::DocumentObject* obj) const
|
|
{
|
|
if (!obj->isDerivedFrom(Part::Feature::getClassTypeId())) {
|
|
return false;
|
|
}
|
|
else if (PartDesign::Body::findBodyOf(obj)) {
|
|
return false;
|
|
}
|
|
else if (obj->isDerivedFrom (Part::BodyBase::getClassTypeId())) {
|
|
return false;
|
|
}
|
|
|
|
App::Part *actPart = PartDesignGui::getActivePart();
|
|
App::Part* partOfBaseFeature = App::Part::getPartOfObject(obj);
|
|
if (partOfBaseFeature && partOfBaseFeature != actPart)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ViewProviderBody::dropObject(App::DocumentObject* obj)
|
|
{
|
|
PartDesign::Body* body = static_cast<PartDesign::Body*>(getObject());
|
|
if (obj->isDerivedFrom<Part::Part2DObject>()) {
|
|
body->addObject(obj);
|
|
}
|
|
else if (PartDesign::Body::isAllowed(obj) && PartDesignGui::isFeatureMovable(obj)) {
|
|
std::vector<App::DocumentObject*> move;
|
|
move.push_back(obj);
|
|
std::vector<App::DocumentObject*> deps = PartDesignGui::collectMovableDependencies(move);
|
|
move.insert(std::end(move), std::begin(deps), std::end(deps));
|
|
|
|
PartDesign::Body* source = PartDesign::Body::findBodyOf(obj);
|
|
if (source)
|
|
source->removeObjects(move);
|
|
try {
|
|
body->addObjects(move);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
e.ReportException();
|
|
}
|
|
}
|
|
else if (!body->BaseFeature.getValue()) {
|
|
body->BaseFeature.setValue(obj);
|
|
}
|
|
|
|
App::Document* doc = body->getDocument();
|
|
doc->recompute();
|
|
|
|
// check if a proxy object has been created for the base feature
|
|
std::vector<App::DocumentObject*> links = body->Group.getValues();
|
|
for (auto it : links) {
|
|
if (it->isDerivedFrom<PartDesign::FeatureBase>()) {
|
|
PartDesign::FeatureBase* base = static_cast<PartDesign::FeatureBase*>(it);
|
|
if (base && base->BaseFeature.getValue() == obj) {
|
|
Gui::Application::Instance->hideViewProvider(obj);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|