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.
o3de/Code/Sandbox/Plugins/EditorCommon/QPropertyTree/PropertyRowStringListValue.h

304 lines
11 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.
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWSTRINGLISTVALUE_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWSTRINGLISTVALUE_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyRowImpl.h"
#include "PropertyTreeModel.h"
#include "PropertyDrawContext.h"
#include "QPropertyTree.h"
#include <QComboBox>
#include <QMouseEvent>
#include <QApplication>
#include <QStyle>
#include <QtGui/QPainter>
#endif
using Serialization::StringListValue;
class PropertyRowStringListValue
: public PropertyRow
{
public:
PropertyRowStringListValue()
: handle_() {}
PropertyRowWidget* createWidget(QPropertyTree* tree) override;
string valueAsString() const override { return value_.c_str(); }
bool assignTo(const Serialization::SStruct& ser) const override
{
*((StringListValue*)ser.pointer()) = value_.c_str();
return true;
}
void setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) override
{
YASLI_ESCAPE(ser.size() == sizeof(StringListValue), return );
const StringListValue& stringListValue = *((StringListValue*)(ser.pointer()));
stringList_ = stringListValue.stringList();
value_ = stringListValue.c_str();
handle_ = stringListValue.handle();
type_ = stringListValue.type();
}
bool isLeaf() const override { return true; }
bool isStatic() const override { return false; }
int widgetSizeMin(const QPropertyTree* tree) const override
{
if (userWidgetToContent())
{
return widthCache_.getOrUpdate(tree, this, tree->_defaultRowHeight());
}
else
{
return 80;
}
}
WidgetPlacement widgetPlacement() const override { return WIDGET_VALUE; }
const void* searchHandle() const override { return handle_; }
Serialization::TypeID typeId() const override { return type_; }
void redraw(const PropertyDrawContext& context) override
{
if (multiValue())
{
context.drawEntry(L" ... ", false, true, 0);
}
else if (userReadOnly())
{
context.drawValueText(pulledSelected(), valueAsWString().c_str());
}
else
{
QStyleOptionComboBox option;
option.editable = false;
option.frame = true;
option.currentText = QString(valueAsString().c_str());
option.state |= QStyle::State_Enabled;
option.rect = QRect(0, 0, context.widgetRect.width(), context.widgetRect.height());
// we have to translate painter here to work around bug in some themes
context.painter->translate(context.widgetRect.left(), context.widgetRect.top());
// create a real instance of a combo so that it has the style sheet applied.
QComboBox widgetForContext;
context.tree->style()->drawComplexControl(QStyle::CC_ComboBox, &option, context.painter, &widgetForContext);
context.painter->setPen(QPen(context.tree->palette().color(QPalette::WindowText)));
QRect textRect = context.tree->style()->subControlRect(QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxEditField, &widgetForContext);
textRect.adjust(1, 0, -1, 0);
context.tree->_drawRowValue(*context.painter, valueAsWString().c_str(), &context.tree->font(), textRect, context.tree->palette().color(QPalette::WindowText), false, false);
context.painter->translate(-context.widgetRect.left(), -context.widgetRect.top());
}
}
void serializeValue(Serialization::IArchive& ar)
{
ar(value_, "value", "Value");
ar(stringList_, "stringList", "String List");
}
private:
Serialization::StringList stringList_;
string value_;
const void* handle_;
Serialization::TypeID type_;
friend class PropertyRowWidgetStringListValue;
mutable RowWidthCache widthCache_;
};
using Serialization::StringListStaticValue;
class PropertyRowStringListStaticValue
: public PropertyRowImpl<StringListStaticValue>
{
public:
PropertyRowStringListStaticValue()
: handle_() {}
PropertyRowWidget* createWidget(QPropertyTree* tree) override;
string valueAsString() const override { return value_.c_str(); }
bool assignTo(const Serialization::SStruct& ser) const override
{
*((StringListStaticValue*)ser.pointer()) = value_.c_str();
return true;
}
void setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) override
{
YASLI_ESCAPE(ser.size() == sizeof(StringListStaticValue), return );
const StringListStaticValue& stringListValue = *((StringListStaticValue*)(ser.pointer()));
stringList_.resize(stringListValue.stringList().size());
for (size_t i = 0; i < stringList_.size(); ++i)
{
stringList_[i] = stringListValue.stringList()[i];
}
value_ = stringListValue.c_str();
handle_ = stringListValue.handle();
type_ = stringListValue.type();
}
bool isLeaf() const override { return true; }
bool isStatic() const override { return false; }
int widgetSizeMin(const QPropertyTree* tree) const override
{
if (userWidgetToContent())
{
return widthCache_.getOrUpdate(tree, this, tree->_defaultRowHeight());
}
else
{
return 80;
}
}
WidgetPlacement widgetPlacement() const override { return WIDGET_VALUE; }
const void* searchHandle() const override { return handle_; }
Serialization::TypeID typeId() const override { return type_; }
void redraw(const PropertyDrawContext& context) override
{
if (multiValue())
{
context.drawEntry(L" ... ", false, true, 0);
}
else if (userReadOnly())
{
context.drawValueText(pulledSelected(), valueAsWString().c_str());
}
else
{
QStyleOptionComboBox option;
option.currentText = QString(valueAsString().c_str());
option.state |= QStyle::State_Enabled;
option.rect = context.widgetRect;
// create a real instance of a combo so that it has the style sheet applied.
QComboBox widgetForContext;
context.tree->style()->drawComplexControl(QStyle::CC_ComboBox, &option, context.painter, &widgetForContext);
context.painter->setPen(QPen(context.tree->palette().color(QPalette::WindowText)));
QRect textRect = context.tree->style()->subControlRect(QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxEditField, &widgetForContext);
textRect.adjust(1, 0, -1, 0);
context.tree->_drawRowValue(*context.painter, valueAsWString().c_str(), &context.tree->font(), textRect, context.tree->palette().color(QPalette::WindowText), false, false);
}
}
void serializeValue(Serialization::IArchive& ar)
{
ar(value_, "value", "Value");
ar(stringList_, "stringList", "String List");
}
private:
Serialization::StringList stringList_;
string value_;
const void* handle_;
Serialization::TypeID type_;
friend class PropertyRowWidgetStringListValue;
mutable RowWidthCache widthCache_;
};
// ---------------------------------------------------------------------------
class PropertyRowWidgetStringListValue
: public PropertyRowWidget
{
Q_OBJECT
public:
PropertyRowWidgetStringListValue(PropertyRowStringListValue* row, QPropertyTree* tree)
: PropertyRowWidget(row, tree)
, comboBox_(new QComboBox())
{
const Serialization::StringList& stringList = row->stringList_;
for (size_t i = 0; i < stringList.size(); ++i)
{
comboBox_->addItem(stringList[i].c_str());
}
comboBox_->setCurrentIndex(stringList.find(row->value_.c_str()));
connect(comboBox_, SIGNAL(activated(int)), this, SLOT(onChange(int)));
}
PropertyRowWidgetStringListValue(PropertyRowStringListStaticValue* row, QPropertyTree* tree)
: PropertyRowWidget(row, tree)
, comboBox_(new QComboBox())
{
const Serialization::StringList& stringList = row->stringList_;
for (size_t i = 0; i < stringList.size(); ++i)
{
comboBox_->addItem(stringList[i].c_str());
}
comboBox_->setCurrentIndex(stringList.find(row->value_.c_str()));
connect(comboBox_, SIGNAL(currentIndexChanged(int)), this, SLOT(onChange(int)));
}
void showPopup() override
{
// Here comboBox_->showPopup() should be sufficient, but sadly with Fusion
// theme ComboBox, when clicked, it fires a mouseReleseTimer, which doesn't
// happen with showPopup. It is used to distinguish click-and-hold from
// simple click. If timer is not fired following mouse release hides combo
// box. That's why the user click is emulated here.
QSize size = comboBox_->size();
QPoint localPoint = QPoint(aznumeric_cast<int>(size.width() * 0.5f), aznumeric_cast<int>(size.height() * 0.5f));
QMouseEvent ev(QMouseEvent::MouseButtonPress, localPoint, comboBox_->mapToGlobal(localPoint), Qt::LeftButton, Qt::LeftButton, Qt::KeyboardModifiers());
QApplication::sendEvent(comboBox_, &ev);
}
~PropertyRowWidgetStringListValue()
{
comboBox_->hide();
comboBox_->setParent(0);
comboBox_->deleteLater();
comboBox_ = 0;
}
void commit(){}
QWidget* actualWidget() { return comboBox_; }
public slots:
void onChange(int)
{
if (strcmp(this->row()->typeName(), Serialization::TypeID::get<StringListValue>().name()) == 0)
{
PropertyRowStringListValue* r = static_cast<PropertyRowStringListValue*>(this->row());
QByteArray newValue = comboBox_->currentText().toUtf8();
if (r->value_ != newValue.data())
{
model()->rowAboutToBeChanged(r);
r->value_ = newValue.data();
model()->rowChanged(r);
}
else
{
tree_->_cancelWidget();
}
}
else if (strcmp(this->row()->typeName(), Serialization::TypeID::get<StringListStaticValue>().name()) == 0)
{
PropertyRowStringListStaticValue* r = static_cast<PropertyRowStringListStaticValue*>(this->row());
QByteArray newValue = comboBox_->currentText().toUtf8();
if (r->value_ != newValue.data())
{
model()->rowAboutToBeChanged(r);
r->value_ = newValue.data();
model()->rowChanged(r);
}
else
{
tree_->_cancelWidget();
}
}
}
protected:
QComboBox* comboBox_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWSTRINGLISTVALUE_H