/* * 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 "stdafx.h" #include "PropertyRowPointer.h" #include "QPropertyTree.h" #include "PropertyTreeModel.h" #include "PropertyDrawContext.h" #include "Serialization.h" #include "Unicode.h" #include <QMenu> // --------------------------------------------------------------------------- static QAction* findAction(const QList<QAction*>& actions, const char* withText) { for (int i = 0; i < int(actions.size()); ++i) { if (actions[i]->text() == withText) { return actions[i]; } } return 0; } void ClassMenuItemAdder::generateMenu(QMenu& createItem, const StringList& comboStrings) { StringList::const_iterator it; int index = 0; for (it = comboStrings.begin(); it != comboStrings.end(); ++it) { StringList path; splitStringList(&path, it->c_str(), '\\'); int level = 0; QMenu* item = &createItem; //createItem.addMenu( for (int level = 0; level < int(path.size()); ++level) { const char* leaf = path[level].c_str(); if (level == path.size() - 1) { addAction(*item, leaf, index++); } else { if (QMenu* menu = item->findChild<QMenu*>(leaf)) { item = menu; } else { item = addMenu(*item, leaf); //&item->add(leaf); } } } } } void ClassMenuItemAdder::addAction(QMenu& menu, const char* text, int index) { menu.addAction(text)->setEnabled(false); } QMenu* ClassMenuItemAdder::addMenu(QMenu& menu, const char* text) { QMenu* result = menu.addMenu(text); result->setObjectName(text); return result; } // --------------------------------------------------------------------------- SERIALIZATION_CLASS_NAME(PropertyRow, PropertyRowPointer, "PropertyRowPointer", "SharedPtr"); PropertyRowPointer::PropertyRowPointer() : factory_(0) , searchHandle_(0) , colorOverride_(0, 0, 0, 0) { } void PropertyRowPointer::setDerivedType(const char* typeName, Serialization::IClassFactory* factory) { if (!factory) { derivedTypeName_.clear(); return; } derivedTypeName_ = typeName; } bool PropertyRowPointer::assignTo(Serialization::IPointer& ptr) { if (derivedTypeName_ != ptr.registeredTypeName()) { ptr.create(derivedTypeName_.c_str()); } return true; } void CreatePointerMenuHandler::onMenuCreateByIndex() { tree->model()->rowAboutToBeChanged(row); if (index < 0) // NULL value { row->setDerivedType("", 0); row->clear(); } else { const PropertyDefaultDerivedTypeValue* defaultValue = tree->model()->defaultType(row->baseType(), index); SharedPtr<PropertyRow> clonedDefault = defaultValue->root->clone(tree->model()->constStrings()); if (defaultValue && defaultValue->root) { YASLI_ASSERT(defaultValue->root->refCount() == 1); if (useDefaultValue) { row->clear(); row->swapChildren(clonedDefault, 0); } row->setDerivedType(defaultValue->registeredName.c_str(), row->factory()); row->setLabelChanged(); row->setLabelChangedToChildren(); tree->expandRow(row); } else { row->setDerivedType("", 0); row->clear(); } } tree->model()->rowChanged(row); } string PropertyRowPointer::valueAsString() const { string result; const Serialization::TypeDescription* desc = 0; if (factory_) { desc = factory_->descriptionByRegisteredName(derivedTypeName_.c_str()); } if (desc) { result = desc->label(); } else { result = derivedTypeName_; } return result; } wstring PropertyRowPointer::generateLabel() const { if (multiValue()) { return L"..."; } wstring str; if (!derivedTypeName_.empty()) { const char* textStart = derivedTypeName_.c_str(); if (factory_) { const Serialization::TypeDescription* desc = factory_->descriptionByRegisteredName(derivedTypeName_.c_str()); if (desc) { textStart = desc->label(); } } const char* p = textStart + strlen(textStart); while (p > textStart) { if (*(p - 1) == '\\') { break; } --p; } str = toWideChar(p); if (p != textStart) { str += L" ("; str += toWideChar(string(textStart, p - 1).c_str()); str += L")"; } } else { if (factory_) { str = toWideChar(factory_->nullLabel() ? factory_->nullLabel() : "[ null ]"); } else { str = L"[ null ]"; } } return str; } void PropertyRowPointer::redraw(const PropertyDrawContext& context) { QRect widgetRect = context.widgetRect; QRect rt = widgetRect; rt.adjust(-1, 0, 0, 1); wstring str = generateLabel(); const QFont* font = derivedTypeName_.empty() ? &context.tree->font() : &context.tree->_boldFont(); int buttonFlags = BUTTON_POPUP_ARROW; if (userReadOnly()) { buttonFlags |= BUTTON_DISABLED; } if (context.pressed) { buttonFlags |= BUTTON_PRESSED; } context.drawButton(rt, str.c_str(), buttonFlags, font, colorOverride_.a != 0 ? &colorOverride_ : 0); } struct ClassMenuItemAdderRowPointer : ClassMenuItemAdder { ClassMenuItemAdderRowPointer(PropertyRowPointer* row, QPropertyTree* tree) : row_(row) , tree_(tree) {} void addAction(QMenu& menu, const char* text, int index) { CreatePointerMenuHandler* handler = new CreatePointerMenuHandler; tree_->addMenuHandler(handler); handler->row = row_; handler->tree = tree_; handler->index = index; handler->useDefaultValue = !tree_->immediateUpdate(); QAction* action = menu.addAction(text); QObject::connect(action, SIGNAL(triggered()), handler, SLOT(onMenuCreateByIndex())); } protected: PropertyRowPointer* row_; QPropertyTree* tree_; }; bool PropertyRowPointer::onActivate(QPropertyTree* tree, bool force) { if (userReadOnly()) { return false; } QMenu menu; ClassMenuItemAdderRowPointer(this, tree).generateMenu(menu, tree->model()->typeStringList(baseType())); tree->_setPressedRow(this); menu.exec(tree->_toScreen(QPoint(widgetPos_, pos_.y() + tree->_defaultRowHeight()))); tree->_setPressedRow(0); return true; } bool PropertyRowPointer::onMouseDown(QPropertyTree* tree, QPoint point, bool& changed) { if (widgetRect(tree).contains(point)) { if (onActivate(tree, false)) { changed = true; } } return false; } bool PropertyRowPointer::onContextMenu(QMenu& menu, QPropertyTree* tree) { if (!menu.isEmpty()) { menu.addSeparator(); } if (!userReadOnly()) { QMenu* createItem = menu.addMenu("Set"); ClassMenuItemAdderRowPointer(this, tree).generateMenu(*createItem, tree->model()->typeStringList(baseType())); } return PropertyRow::onContextMenu(menu, tree); } void PropertyRowPointer::serializeValue(IArchive& ar) { ar(derivedTypeName_, "derivedTypeName", "Derived Type Name"); } int PropertyRowPointer::widgetSizeMin(const QPropertyTree* tree) const { QFontMetrics fm(tree->_boldFont()); QString str(fromWideChar(generateLabel().c_str()).c_str()); return fm.horizontalAdvance(str) + 24; } static Color parseColorString(const char* str) { unsigned int color = 0; if (azsscanf(str, "%x", &color) != 1) { return Color(0, 0, 0, 0); } Color result((color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff, 255); return result; } void PropertyRowPointer::setValueAndContext(const Serialization::IPointer& ptr, Serialization::IArchive& ar) { baseType_ = ptr.baseType(); factory_ = ptr.factory(); serializer_ = ptr.serializer(); pointerType_ = ptr.pointerType(); searchHandle_ = ptr.handle(); const char* colorString = factory_->findAnnotation(ptr.registeredTypeName(), "color"); if (colorString[0] != '\0') { colorOverride_ = parseColorString(colorString); } else { colorOverride_ = Color(0, 0, 0, 0); } const Serialization::TypeDescription* desc = factory_->descriptionByRegisteredName(ptr.registeredTypeName()); if (desc) { derivedTypeName_ = desc->name(); } else { derivedTypeName_.clear(); } } #include <QPropertyTree/PropertyRowPointer.moc> // vim:ts=4 sw=4: