You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
440 lines
12 KiB
C++
440 lines
12 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
#include "EditorCommon_precompiled.h"
|
|
#include "PropertyRowContainer.h"
|
|
#include "PropertyRowPointer.h"
|
|
#include "QPropertyTree.h"
|
|
#include "PropertyTreeModel.h"
|
|
#include "PropertyDrawContext.h"
|
|
#include "Serialization.h"
|
|
#include "PropertyRowPointer.h"
|
|
|
|
#include <QMenu>
|
|
#include <QKeyEvent>
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
ContainerMenuHandler::ContainerMenuHandler(QPropertyTree* tree, PropertyRowContainer* container)
|
|
: element()
|
|
, container(container)
|
|
, tree(tree)
|
|
, pointerIndex(-1)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
SERIALIZATION_CLASS_NAME(PropertyRow, PropertyRowContainer, "PropertyRowContainer", "Container");
|
|
|
|
PropertyRowContainer::PropertyRowContainer()
|
|
: fixedSize_(false)
|
|
, elementTypeName_("")
|
|
, inlined_(false)
|
|
{
|
|
buttonLabel_[0] = '\0';
|
|
}
|
|
|
|
struct ClassMenuItemAdderRowContainer
|
|
: ClassMenuItemAdder
|
|
{
|
|
ClassMenuItemAdderRowContainer(PropertyRowContainer* row, QPropertyTree* tree, bool insert = false)
|
|
: row_(row)
|
|
, tree_(tree)
|
|
, insert_(insert) {}
|
|
|
|
void addAction(QMenu& menu, const char* text, int index) override
|
|
{
|
|
ContainerMenuHandler* handler = row_->createMenuHandler(tree_, row_);
|
|
tree_->addMenuHandler(handler);
|
|
handler->pointerIndex = index;
|
|
|
|
QAction* action = menu.addAction(text);
|
|
QObject::connect(action, SIGNAL(triggered()), handler, SLOT(onMenuAppendPointerByIndex()));
|
|
}
|
|
protected:
|
|
PropertyRowContainer* row_;
|
|
QPropertyTree* tree_;
|
|
bool insert_;
|
|
};
|
|
|
|
void PropertyRowContainer::redraw(const PropertyDrawContext& context)
|
|
{
|
|
QRect widgetRect = context.widgetRect;
|
|
if (widgetRect.width() == 0 || inlined_)
|
|
{
|
|
return;
|
|
}
|
|
QRect rt = widgetRect;
|
|
rt.adjust(0, 1, -1, -1);
|
|
QColor brushColor = context.tree->palette().button().color();
|
|
QLinearGradient gradient(rt.left(), rt.top(), rt.left(), rt.bottom());
|
|
gradient.setColorAt(0.0f, brushColor);
|
|
gradient.setColorAt(0.6f, brushColor);
|
|
gradient.setColorAt(1.0f, context.tree->palette().color(QPalette::Shadow));
|
|
QBrush brush(gradient);
|
|
|
|
const wchar_t* text = multiValue() ? L"..." : buttonLabel_;
|
|
int buttonFlags = BUTTON_CENTER | BUTTON_POPUP_ARROW;
|
|
if (userReadOnly())
|
|
{
|
|
buttonFlags |= BUTTON_DISABLED;
|
|
}
|
|
if (context.m_pressed)
|
|
{
|
|
buttonFlags |= BUTTON_PRESSED;
|
|
}
|
|
context.drawButton(rt, text, buttonFlags, &context.tree->font());
|
|
}
|
|
|
|
|
|
bool PropertyRowContainer::onActivate(const PropertyActivationEvent& e)
|
|
{
|
|
if (e.reason == e.REASON_RELEASE)
|
|
{
|
|
return false;
|
|
}
|
|
if (userReadOnly())
|
|
{
|
|
return false;
|
|
}
|
|
if (inlined_)
|
|
{
|
|
return false;
|
|
}
|
|
QMenu menu;
|
|
generateMenu(menu, e.tree, true);
|
|
e.tree->_setPressedRow(this);
|
|
menu.exec(e.tree->_toScreen(QPoint(widgetPos_, pos_.y() + e.tree->_defaultRowHeight())));
|
|
e.tree->_setPressedRow(0);
|
|
return true;
|
|
}
|
|
|
|
ContainerMenuHandler* PropertyRowContainer::createMenuHandler(QPropertyTree* tree, PropertyRowContainer* container)
|
|
{
|
|
return new ContainerMenuHandler(tree, container);
|
|
}
|
|
|
|
void PropertyRowContainer::generateMenu(QMenu& menu, QPropertyTree* tree, bool addActions)
|
|
{
|
|
ContainerMenuHandler* handler = createMenuHandler(tree, this);
|
|
tree->addMenuHandler(handler);
|
|
|
|
if (fixedSize_)
|
|
{
|
|
if (!inlined_)
|
|
{
|
|
menu.addAction("[ Fixed Size Container ]")->setEnabled(false);
|
|
}
|
|
}
|
|
else if (userReadOnly())
|
|
{
|
|
menu.addAction("[ Read Only Container ]")->setEnabled(false);
|
|
}
|
|
else
|
|
{
|
|
if (addActions)
|
|
{
|
|
PropertyRow* row = defaultRow(tree->model());
|
|
if (row && row->isPointer())
|
|
{
|
|
QMenu* createItem = menu.addMenu("Add");
|
|
menu.addSeparator();
|
|
|
|
PropertyRowPointer* pointerRow = static_cast<PropertyRowPointer*>(row);
|
|
ClassMenuItemAdderRowContainer(this, tree).generateMenu(*createItem, tree->model()->typeStringList(pointerRow->baseType()));
|
|
}
|
|
else
|
|
{
|
|
menu.addAction("Insert", handler, SLOT(onMenuAddElement()));
|
|
menu.addAction("Add", handler, SLOT(onMenuAppendElement()), Qt::Key_Insert);
|
|
}
|
|
}
|
|
|
|
if (!menu.isEmpty())
|
|
{
|
|
menu.addSeparator();
|
|
}
|
|
|
|
QAction* removeAll = menu.addAction(pulledUp() ? "Remove Children" : "Remove All");
|
|
removeAll->setShortcut(QKeySequence("Shift+Delete"));
|
|
removeAll->setEnabled(!userReadOnly());
|
|
QObject::connect(removeAll, SIGNAL(triggered()), handler, SLOT(onMenuRemoveAll()));
|
|
}
|
|
}
|
|
|
|
bool PropertyRowContainer::onContextMenu(QMenu& menu, QPropertyTree* tree)
|
|
{
|
|
if (!menu.isEmpty())
|
|
{
|
|
menu.addSeparator();
|
|
}
|
|
|
|
generateMenu(menu, tree, true);
|
|
|
|
if (pulledUp())
|
|
{
|
|
return !menu.isEmpty();
|
|
}
|
|
|
|
return PropertyRow::onContextMenu(menu, tree);
|
|
}
|
|
|
|
|
|
void ContainerMenuHandler::onMenuRemoveAll()
|
|
{
|
|
tree->model()->rowAboutToBeChanged(container);
|
|
container->clear();
|
|
tree->model()->rowChanged(container);
|
|
}
|
|
|
|
PropertyRow* PropertyRowContainer::defaultRow(PropertyTreeModel* model)
|
|
{
|
|
PropertyRow* defaultType = model->defaultType(elementTypeName_);
|
|
//YASLI_ASSERT(defaultType);
|
|
//YASLI_ASSERT(defaultType->numRef() == 1);
|
|
return defaultType;
|
|
}
|
|
|
|
const PropertyRow* PropertyRowContainer::defaultRow(const PropertyTreeModel* model) const
|
|
{
|
|
const PropertyRow* defaultType = model->defaultType(elementTypeName_);
|
|
return defaultType;
|
|
}
|
|
|
|
void ContainerMenuHandler::onMenuAddElement()
|
|
{
|
|
container->addElement(tree, false);
|
|
}
|
|
|
|
void ContainerMenuHandler::onMenuAppendElement()
|
|
{
|
|
container->addElement(tree, true);
|
|
}
|
|
|
|
PropertyRow* PropertyRowContainer::addElement(QPropertyTree* tree, bool append)
|
|
{
|
|
tree->model()->rowAboutToBeChanged(this);
|
|
PropertyRow* defaultType = defaultRow(tree->model());
|
|
YASLI_ESCAPE(defaultType != 0, return 0);
|
|
SharedPtr<PropertyRow> clonedRow = defaultType->clone(tree->model()->constStrings());
|
|
if (count() == 0)
|
|
{
|
|
tree->expandRow(this);
|
|
}
|
|
if (append)
|
|
{
|
|
add(clonedRow);
|
|
}
|
|
else
|
|
{
|
|
addBefore(clonedRow, 0);
|
|
}
|
|
clonedRow->setHideChildren(tree->outlineMode());
|
|
clonedRow->setLabelChanged();
|
|
clonedRow->setLabelChangedToChildren();
|
|
setMultiValue(false);
|
|
if (expanded())
|
|
{
|
|
tree->model()->selectRow(clonedRow, true);
|
|
}
|
|
tree->expandRow(clonedRow);
|
|
TreePath path = tree->model()->pathFromRow(clonedRow);
|
|
tree->model()->rowChanged(clonedRow);
|
|
clonedRow = tree->model()->rowFromPath(path);
|
|
tree->update();
|
|
clonedRow = tree->model()->rowFromPath(path);
|
|
if (clonedRow)
|
|
{
|
|
PropertyTreeModel::Selection sel;
|
|
sel.push_back(path);
|
|
tree->model()->setSelection(sel);
|
|
if (clonedRow->activateOnAdd())
|
|
{
|
|
PropertyActivationEvent e;
|
|
e.tree = tree;
|
|
e.reason = e.REASON_NEW_ELEMENT;
|
|
clonedRow->onActivate(e);
|
|
}
|
|
}
|
|
return clonedRow;
|
|
}
|
|
|
|
|
|
void ContainerMenuHandler::onMenuAppendPointerByIndex()
|
|
{
|
|
PropertyRow* defaultType = container->defaultRow(tree->model());
|
|
PropertyRowPointer* defaultTypePointer = static_cast<PropertyRowPointer*>(defaultType);
|
|
SharedPtr<PropertyRow> clonedRow = defaultType->clone(tree->model()->constStrings());
|
|
if (container->count() == 0)
|
|
{
|
|
tree->expandRow(container);
|
|
}
|
|
container->add(clonedRow);
|
|
clonedRow->setLabelChanged();
|
|
clonedRow->setLabelChangedToChildren();
|
|
clonedRow->setHideChildren(tree->outlineMode());
|
|
container->setMultiValue(false);
|
|
PropertyRowPointer* clonedRowPointer = static_cast<PropertyRowPointer*>(clonedRow.get());
|
|
clonedRowPointer->setDerivedType(defaultTypePointer->derivedTypeName(), defaultTypePointer->factory());
|
|
clonedRowPointer->setBaseType(defaultTypePointer->baseType());
|
|
clonedRowPointer->setFactory(defaultTypePointer->factory());
|
|
if (container->expanded())
|
|
{
|
|
tree->model()->selectRow(clonedRow, true);
|
|
}
|
|
tree->expandRow(clonedRowPointer);
|
|
PropertyTreeModel::Selection sel = tree->model()->selection();
|
|
|
|
CreatePointerMenuHandler handler;
|
|
handler.tree = tree;
|
|
handler.row = clonedRowPointer;
|
|
handler.index = pointerIndex;
|
|
handler.onMenuCreateByIndex();
|
|
tree->model()->setSelection(sel);
|
|
tree->update();
|
|
}
|
|
|
|
void ContainerMenuHandler::onMenuChildInsertBefore()
|
|
{
|
|
tree->model()->rowAboutToBeChanged(container);
|
|
PropertyRow* defaultType = tree->model()->defaultType(container->elementTypeName());
|
|
if (!defaultType)
|
|
{
|
|
return;
|
|
}
|
|
SharedPtr<PropertyRow> clonedRow = defaultType->clone(tree->model()->constStrings());
|
|
clonedRow->setHideChildren(tree->outlineMode());
|
|
element->setSelected(false);
|
|
container->addBefore(clonedRow, element);
|
|
container->setMultiValue(false);
|
|
tree->model()->selectRow(clonedRow, true);
|
|
PropertyTreeModel::Selection sel = tree->model()->selection();
|
|
tree->model()->rowChanged(clonedRow);
|
|
tree->model()->setSelection(sel);
|
|
tree->update();
|
|
clonedRow = tree->selectedRow();
|
|
if (clonedRow->activateOnAdd())
|
|
{
|
|
PropertyActivationEvent e;
|
|
e.tree = tree;
|
|
e.reason = PropertyActivationEvent::REASON_NEW_ELEMENT;
|
|
clonedRow->onActivate(e);
|
|
}
|
|
}
|
|
|
|
void ContainerMenuHandler::onMenuChildRemove()
|
|
{
|
|
tree->model()->rowAboutToBeChanged(container);
|
|
container->erase(element);
|
|
container->setMultiValue(false);
|
|
tree->model()->rowChanged(container);
|
|
}
|
|
|
|
|
|
void PropertyRowContainer::labelChanged()
|
|
{
|
|
swprintf(buttonLabel_, sizeof(buttonLabel_) / sizeof(buttonLabel_[0]), L"%zi", count());
|
|
}
|
|
|
|
void PropertyRowContainer::serializeValue(IArchive& ar)
|
|
{
|
|
ar(ConstStringWrapper(constStrings_, elementTypeName_), "elementTypeName", "ElementTypeName");
|
|
ar(fixedSize_, "fixedSize", "fixedSize");
|
|
}
|
|
|
|
string PropertyRowContainer::valueAsString() const
|
|
{
|
|
char buf[32] = { 0 };
|
|
sprintf_s(buf, "%d", (int)children_.size());
|
|
return string(buf);
|
|
}
|
|
|
|
const char* PropertyRowContainer::typeNameForFilter(QPropertyTree* tree) const
|
|
{
|
|
const PropertyRow* defaultType = defaultRow(tree->model());
|
|
if (defaultType)
|
|
{
|
|
return defaultType->typeNameForFilter(tree);
|
|
}
|
|
else
|
|
{
|
|
return elementTypeName_;
|
|
}
|
|
}
|
|
|
|
bool PropertyRowContainer::processesKeyContainer([[maybe_unused]] QPropertyTree* tree, const QKeyEvent* ev)
|
|
{
|
|
if (ev->key() == Qt::Key_Delete && ev->modifiers() == Qt::SHIFT)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (ev->key() == Qt::Key_Insert && ev->modifiers() == Qt::NoModifier)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool PropertyRowContainer::processesKey(QPropertyTree* tree, const QKeyEvent* ev)
|
|
{
|
|
if (processesKeyContainer(tree, ev))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return PropertyRow::processesKey(tree, ev);
|
|
}
|
|
|
|
bool PropertyRowContainer::onKeyDownContainer(QPropertyTree* tree, const QKeyEvent* ev)
|
|
{
|
|
if (userReadOnly())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::unique_ptr<ContainerMenuHandler> handler(createMenuHandler(tree, this));
|
|
if (ev->key() == Qt::Key_Delete && ev->modifiers() == Qt::SHIFT)
|
|
{
|
|
handler->onMenuRemoveAll();
|
|
return true;
|
|
}
|
|
|
|
if (ev->key() == Qt::Key_Insert && ev->modifiers() == Qt::NoModifier)
|
|
{
|
|
handler->onMenuAppendElement();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool PropertyRowContainer::onKeyDown(QPropertyTree* tree, const QKeyEvent* ev)
|
|
{
|
|
if (onKeyDownContainer(tree, ev))
|
|
{
|
|
return true;
|
|
}
|
|
return PropertyRow::onKeyDown(tree, ev);
|
|
}
|
|
|
|
int PropertyRowContainer::widgetSizeMin(const QPropertyTree* tree) const
|
|
{
|
|
return inlined_ ? 0 : (userWidgetSize() >= 0 ? userWidgetSize() : aznumeric_cast<int>(tree->_defaultRowHeight() * 1.7f));
|
|
}
|
|
|
|
#include <QPropertyTree/moc_PropertyRowContainer.cpp>
|