Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,123 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "Color.h"
#include "Serialization/IArchive.h"
#include <math.h>
#include "MathUtils.h"
// HSV
// h=0..360, s=0..1, v=0..1
inline void HSVtoRGB(float h,float s,float v,
float& r,float& g,float& b)
{
const float min=1e-5f;
int i;
float f,m,n,k;
if(s<min){
r=g=b=v;
}
else {
if(h>=360.0f)
h=0;
else
h=h/60.0f;
i=xround(floor(h));
f=h-i;
m=v*(1-s);
n=v*(1-s*f);
k=v*(1-s*(1-f));
switch(i){
case 0:
r=v; g=k; b=m;
break;
case 1:
r=n; g=v; b=m;
break;
case 2:
r=m; g=v; b=k;
break;
case 3:
r=m; g=n; b=v;
break;
case 4:
r=k; g=m; b=v;
break;
case 5:
r=v; g=m; b=n;
break;
default:
YASLI_ASSERT(0);
}
}
YASLI_ASSERT(r>=0 && r<=1);
YASLI_ASSERT(g>=0 && g<=1);
YASLI_ASSERT(b>=0 && b<=1);
}
void Color::setHSV(float h,float s,float v, unsigned char alpha)
{
float rf,gf,bf;
HSVtoRGB(h,s,v, rf,gf,bf);
r = xround(rf*255);
g = xround(gf*255);
b = xround(bf*255);
a = alpha;
}
void Color::toHSV(float& h,float& s,float& v)
{
float rf = r/255.f;
float gf = g/255.f;
float bf = b/255.f;
v = max(max(rf,gf),bf);
float temp=min(min(rf,gf),bf);
if(v==0)
s=0;
else
s=(v-temp)/v;
if(s==0)
h=0;
else {
float Cr=(v-rf)/(v-temp);
float Cg=(v-gf)/(v-temp);
float Cb=(v-bf)/(v-temp);
if(rf==v) {
h=Cb-Cg;
}
else if(gf==v) {
h=2+Cr-Cb;
}
else if(bf==v) {
h=4+Cg-Cr;
}
h=60*h;
if(h<0)h+=360;
}
}
void Color::Serialize(Serialization::IArchive& ar)
{
ar(r, "", "^R");
ar(g, "", "^G");
ar(b, "", "^B");
ar(a, "", "^A");
}
@@ -0,0 +1,66 @@
// Modifications copyright Amazon.com, Inc. or its affiliates.
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_COLOR_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_COLOR_H
#pragma once
namespace Serialization {
class IArchive;
}
struct Color
{
unsigned char b, g, r, a;
Color() : r(255), g(255), b(255), a(255) { }
Color(unsigned char _r, unsigned char _g, unsigned char _b, unsigned char _a = 255) { r=_r; g=_g; b=_b; a=_a; }
explicit Color(unsigned long _argb) { argb() = _argb; }
void set(int rc,int gc,int bc,int ac = 255) { r=rc; g=gc; b=bc; a=ac; }
Color& setGDI(unsigned long color) {
b = (unsigned char)(color >> 16);
g = (unsigned char)(color >> 8);
r = (unsigned char)(color);
a = 255;
return *this;
}
void setHSV(float h,float s,float v, unsigned char alpha = 255);
void toHSV(float& h,float& s, float& v);
Color& operator*= (float f) { r=int(r*f); g=int(g*f); b=int(b*f); a=int(a*f); return *this; }
Color& operator+= (Color &p) { r+=p.r; g+=p.g; b+=p.b; a+=p.a; return *this; }
Color& operator-= (Color &p) { r-=p.r; g-=p.g; b-=p.b; a-=p.a; return *this; }
Color operator+ (Color &p) { return Color(r+p.r,g+p.g,b+p.b,a+p.a); }
Color operator- (Color &p) { return Color(r-p.r,g-p.g,b-p.b,a-p.a); }
Color operator* (float f) const { return Color(int(r*f), int(g*f), int(b*f), int(a*f)); }
Color operator* (int f) const { return Color(r*f,g*f,b*f,a*f); }
Color operator/ (int f) const { if(f!=0) f=(1<<16)/f; else f=1<<16; return Color((r*f)>>16,(g*f)>>16,(b*f)>>16,(a*f)>>16); }
bool operator==(const Color& rhs) const { return argb() == rhs.argb(); }
bool operator!=(const Color& rhs) const { return argb() != rhs.argb(); }
unsigned long argb() const { return *reinterpret_cast<const unsigned long*>(this); }
unsigned long& argb() { return *reinterpret_cast<unsigned long*>(this); }
unsigned long rgb() const { return r | g << 8 | b << 16; }
unsigned long rgba() const { return r | g << 8 | b << 16 | a << 24; }
unsigned char& operator[](int i) { return ((unsigned char*)this)[i];}
Color interpolate(const Color &v, float f) const
{
return Color(int(r+int(v.r-r)*f),
int(g+int(v.g-g)*f),
int(b+int(v.b-b)*f),
int(a+(v.a-a)*f));
}
void Serialize(Serialization::IArchive& ar);
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_COLOR_H
@@ -0,0 +1,58 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "ConstStringList.h"
#include <algorithm>
#include "Serialization/STL.h"
#include "Serialization/IArchive.h"
#include "Serialization/STLImpl.h"
ConstStringList globalConstStringList;
const char* ConstStringList::findOrAdd(const char* string)
{
// TODO: try sorted vector of const char*
Strings::iterator it = std::find(strings_.begin(), strings_.end(), string);
if (it == strings_.end()) {
strings_.push_back(string);
return strings_.back().c_str();
}
else {
return it->c_str();
}
}
ConstStringWrapper::ConstStringWrapper(ConstStringList* list, const char*& string)
: list_(list ? list : &globalConstStringList)
, string_(string)
{
YASLI_ASSERT(string_);
}
using Serialization::string;
bool Serialize(Serialization::IArchive& ar, ConstStringWrapper& val, const char* name, const char* label)
{
if (ar.IsOutput()) {
YASLI_ASSERT(val.string_);
string out = val.string_;
return ar(out, name, label);
}
else {
string in;
bool result = ar(in, name, label);
val.string_ = val.list_->findOrAdd(in.c_str());
return result;
}
}
@@ -0,0 +1,46 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_CONSTSTRINGLIST_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_CONSTSTRINGLIST_H
#pragma once
#include <list>
#include <string>
#include "EditorCommonAPI.h"
class ConstStringWrapper;
namespace Serialization { class IArchive; }
bool Serialize(Serialization::IArchive& ar, ConstStringWrapper &wrapper, const char* name, const char* label);
class ConstStringList{
public:
const char* findOrAdd(const char* string);
protected:
typedef std::list<std::string> Strings;
Strings strings_;
};
class ConstStringWrapper {
public:
ConstStringWrapper(ConstStringList* list, const char*& string);
protected:
ConstStringList* list_;
const char*& string_;
friend bool ::Serialize(Serialization::IArchive& ar, ConstStringWrapper &wrapper, const char* name, const char* label);
};
extern ConstStringList globalConstStringList;
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_CONSTSTRINGLIST_H
@@ -0,0 +1,76 @@
/*
* 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_CONTEXTLIST_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_CONTEXTLIST_H
#pragma once
#include <Serialization/IArchive.h>
namespace Serialization
{
class CContextList
{
public:
template<class T>
void Update(T* contextObject)
{
for (size_t i = 0; i < links_.size(); ++i)
{
if (links_[i]->type == TypeID::get<T>())
{
links_[i]->contextObject = (void*)contextObject;
return;
}
}
SContextLink* newLink = new SContextLink;
newLink->type = TypeID::get<T>();
newLink->outer = links_.empty() ? connectedList_ : links_.back();
newLink->contextObject = (void*)contextObject;
tail_.outer = newLink;
links_.push_back(newLink);
}
CContextList()
{
tail_.outer = 0;
tail_.contextObject = 0;
connectedList_ = 0;
}
explicit CContextList(SContextLink* connectedList)
{
tail_.outer = 0;
tail_.contextObject = 0;
connectedList_ = connectedList;
}
~CContextList()
{
for (size_t i = 0; i < links_.size(); ++i)
{
delete links_[i];
}
links_.clear();
}
SContextLink* Tail() { return &tail_; }
private:
SContextLink tail_;
std::vector<SContextLink*> links_;
SContextLink* connectedList_;
};
}
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_CONTEXTLIST_H
@@ -0,0 +1,156 @@
/**
* yasli - Serialization Library.
* Copyright (C) 2007-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_FACTORY_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_FACTORY_H
#pragma once
#include <AzCore/std/containers/map.h>
#include <AzCore/std/functional.h>
#include "Serialization/Assert.h"
template<class _Key, class _Product, class _KeyPred = std::less<_Key>>
class Factory {
public:
typedef AZStd::map<_Key, AZStd::function<_Product *()>, _KeyPred, AZ::StdLegacyAllocator> Creators;
typedef _Product* (*ProductConstructionFunction)(void);
Factory() {}
struct Creator
{
Creator()
{
if (s_creatorsHead)
{
m_next = s_creatorsHead;
}
s_creatorsHead = this;
}
Creator(Factory& factory, _Key key, ProductConstructionFunction construction_function_)
: Creator()
{
// capture key and construction_function_ by value so the lazy load won't try to access possibly deleted data
Register = [&, key, construction_function_]()
{
factory.add(key, construction_function_);
};
}
Creator(_Key key, ProductConstructionFunction construction_function_)
: Creator()
{
// capture key and construction_function_ by value so the lazy load won't try to access possibly deleted data
Register = [&, key, construction_function_]()
{
Factory::the().add(key, construction_function_);
};
}
AZStd::function<void()> Register;
Creator* m_next = nullptr;
};
void add(const _Key& key, AZStd::function<_Product *()> creator) {
YASLI_ASSERT(creators_.find(key) == creators_.end());
YASLI_ASSERT(creator);
creators_[key] = creator;
}
void remove(const _Key& key) {
auto& entry = creators_.find(key);
if (entry != creators_.end()) {
creators_.erase(entry);
}
}
_Product* create(const _Key& key) const
{
lazyRegisterCreators();
typename Creators::const_iterator it = creators_.find(key);
if (it != creators_.end()) {
return it->second();
}
else
return 0;
}
std::size_t size() const
{
lazyRegisterCreators();
return creators_.size();
}
_Product* createByIndex(int index) const
{
lazyRegisterCreators();
YASLI_ASSERT(index >= 0 && index < creators_.size());
typename Creators::const_iterator it = creators_.begin();
std::advance(it, index);
return it->second();
}
const Creators& creators() const
{
lazyRegisterCreators();
return creators_;
}
static Factory& the()
{
static Factory* genericFactory = nullptr;
static AZStd::aligned_storage_for_t<Factory> s_storage;
if (!genericFactory)
{
genericFactory = new(&s_storage) Factory();
}
return *genericFactory;
}
private:
void lazyRegisterCreators() const
{
if (s_creatorsHead)
{
Creator* creator = s_creatorsHead;
while (creator)
{
creator->Register();
creator = creator->m_next;
}
s_creatorsHead = nullptr;
}
}
protected:
Creators creators_;
static Creator* s_creatorsHead;
};
template <class _Key, class _Product, class _KeyPred>
typename Factory<_Key, _Product, _KeyPred>::Creator* Factory<_Key, _Product, _KeyPred>::s_creatorsHead = nullptr;
#define REGISTER_IN_FACTORY(factory, key, product, construction_function) \
static factory::Creator factory##product##Creator(key, construction_function);
#define REGISTER_IN_FACTORY_INSTANCE(factory, factoryType, key, product) \
static factoryType::Creator<product> factoryType##product##Creator(factory, key);
#define DECLARE_SEGMENT(fileName) int dataSegment##fileName;
#define FORCE_SEGMENT(fileName) \
extern int dataSegment##fileName; \
int* dataSegmentPtr##fileName = &dataSegment##fileName;
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_FACTORY_H
@@ -0,0 +1,54 @@
/*
* 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_MATHUTILS_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_MATHUTILS_H
#pragma once
inline int xround(float v)
{
return int(v + 0.5f);
}
inline int min(int a, int b)
{
return a < b ? a : b;
}
inline int max(int a, int b)
{
return a > b ? a : b;
}
inline float min(float a, float b)
{
return a < b ? a : b;
}
inline float max(float a, float b)
{
return a > b ? a : b;
}
inline float clamp(float value, float min, float max)
{
return ::min(::max(min, value), max);
}
inline int clamp(int value, int min, int max)
{
return ::min(::max(min, value), max);
}
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_MATHUTILS_H
@@ -0,0 +1,466 @@
/*
* 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.
*
*/
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "PropertyDrawContext.h"
#include <memory>
#include "QPropertyTree.h"
#include "Serialization/Decorators/IconXPM.h"
#include "Unicode.h"
#include <QApplication>
#include <QStyleOption>
#include <QPainter>
#include <QBitmap>
// required to create context for the draw calls
#include <QPushButton>
#include <QCheckBox>
#include <QLineEdit>
#include <AzQtComponents/Components/StyleManager.h>
#ifndef _MSC_VER
# define _stricmp strcasecmp
#endif
// ---------------------------------------------------------------------------
QColor interpolateColor(const QColor& a, const QColor& b, float k);
IconXPMCache::~IconXPMCache()
{
flush();
}
void IconXPMCache::flush()
{
IconToBitmap::iterator it;
for (it = iconToImageMap_.begin(); it != iconToImageMap_.end(); ++it)
delete it->second.bitmap;
iconToImageMap_.clear();
}
struct RGBAImage
{
int width_;
int height_;
std::vector<Color> pixels_;
RGBAImage() : width_(0), height_(0) {}
};
bool IconXPMCache::parseXPM(RGBAImage* out, const Serialization::IconXPM& icon)
{
if (icon.lineCount < 3) {
return false;
}
// parse values
std::vector<Color> pixels;
int width = 0;
int height = 0;
int charsPerPixel = 0;
int colorCount = 0;
int hotSpotX = -1;
int hotSpotY = -1;
int scanResult = azsscanf(icon.source[0], "%d %d %d %d %d %d", &width, &height, &colorCount, &charsPerPixel, &hotSpotX, &hotSpotY);
if (scanResult != 4 && scanResult != 6)
return false;
if (charsPerPixel > 4)
return false;
if (icon.lineCount != 1 + colorCount + height) {
YASLI_ASSERT(0 && "Wrong line count");
return false;
}
// parse colors
std::vector<std::pair<int, Color> > colors;
colors.resize(colorCount);
for (int colorIndex = 0; colorIndex < colorCount; ++colorIndex) {
const char* p = icon.source[colorIndex + 1];
int code = 0;
for (int charIndex = 0; charIndex < charsPerPixel; ++charIndex) {
if (*p == '\0')
return false;
code = (code << 8) | *p;
++p;
}
colors[colorIndex].first = code;
while (*p == '\t' || *p == ' ')
++p;
if (*p == '\0')
return false;
if (*p != 'c' && *p != 'g')
return false;
++p;
while (*p == '\t' || *p == ' ')
++p;
if (*p == '\0')
return false;
if (*p == '#') {
++p;
if (strlen(p) == 6) {
int colorCode;
if (azsscanf(p, "%x", &colorCode) != 1)
return false;
Color color((colorCode & 0xff0000) >> 16,
(colorCode & 0xff00) >> 8,
(colorCode & 0xff),
255);
colors[colorIndex].second = color;
}
}
else {
if (_stricmp(p, "None") == 0)
colors[colorIndex].second = Color(0, 0, 0, 0);
else if (_stricmp(p, "Black") == 0)
colors[colorIndex].second = Color(0, 0, 0, 255);
else {
// unknown color
colors[colorIndex].second = Color(255, 0, 0, 255);
}
}
}
// parse pixels
pixels.resize(width * height);
int pi = 0;
for (int y = 0; y < height; ++y) {
const char* p = icon.source[1 + colorCount + y];
if (strlen(p) != width * charsPerPixel)
return false;
for (int x = 0; x < width; ++x) {
int code = 0;
for (int i = 0; i < charsPerPixel; ++i) {
code = (code << 8) | *p;
++p;
}
for (size_t i = 0; i < size_t(colorCount); ++i)
if (colors[i].first == code)
pixels[pi] = colors[i].second;
++pi;
}
}
out->pixels_.swap(pixels);
out->width_ = width;
out->height_ = height;
return true;
}
QImage* IconXPMCache::getImageForIcon(const Serialization::IconXPM& icon)
{
IconToBitmap::iterator it = iconToImageMap_.find(icon.source);
if (it != iconToImageMap_.end())
return it->second.bitmap;
RGBAImage image;
if (!parseXPM(&image, icon))
return 0;
BitmapCache& cache = iconToImageMap_[icon.source];
cache.pixels.swap(image.pixels_);
cache.bitmap = new QImage((unsigned char*)&cache.pixels[0], image.width_, image.height_, QImage::Format_ARGB32);
return cache.bitmap;
}
// ---------------------------------------------------------------------------
void drawRoundRectangle(QPainter& p, const QRect &_r, unsigned int color, int radius, [[maybe_unused]] int width)
{
QRect r = _r;
int dia = 2 * radius;
p.setPen(QColor(color));
p.drawRoundedRect(r, dia, dia);
}
void fillRoundRectangle(QPainter& p, const QBrush& brush, const QRect& _r, const QColor& border, int radius)
{
bool wasAntialisingSet = p.renderHints().testFlag(QPainter::Antialiasing);
p.setRenderHints(QPainter::Antialiasing, true);
p.setBrush(brush);
QPen pen(QBrush(border), 1.0, Qt::SolidLine);
p.setPen(pen);
QRectF adjustedRect = _r;
adjustedRect.adjust(0.5f, 0.5f, -0.5f, -0.5f);
p.drawRoundedRect(adjustedRect, radius, radius);
p.setRenderHints(QPainter::Antialiasing, wasAntialisingSet);
}
// ---------------------------------------------------------------------------
void PropertyDrawContext::drawIcon(const QRect& rect, const Serialization::IconXPM& icon) const
{
QImage* image = tree->_iconCache()->getImageForIcon(icon);
if (!image)
return;
int x = rect.left() + (rect.width() - image->width()) / 2;
int y = rect.top() + (rect.height() - image->height()) / 2;
painter->drawImage(x, y, *image);
}
void PropertyDrawContext::drawCheck(const QRect& rect, bool disabled, CheckState checked) const
{
QStyleOptionButton option;
if (!disabled)
option.state |= QStyle::State_Enabled;
else {
option.state |= QStyle::State_ReadOnly;
option.palette.setCurrentColorGroup(QPalette::Disabled);
}
if (checked == CHECK_SET)
option.state |= QStyle::State_On;
else if (checked == CHECK_IN_BETWEEN)
option.state |= QStyle::State_NoChange;
else
option.state |= QStyle::State_Off;
// create a widget so that the style sheet has context for its draw calls
QCheckBox forContext;
QSize checkboxSize = tree->style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option, &forContext).size();
option.rect = QRect(rect.left(), rect.center().y() - checkboxSize.height() / 2, checkboxSize.width(), checkboxSize.height());
tree->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter, &forContext);
if (disabled) {
// With Fusion theme difference between disabled and enabled checkbox is very subtle, let's amplify it
QColor readOnlyOverlay = tree->backgroundColor();
readOnlyOverlay.setAlpha(128);
painter->fillRect(option.rect, QBrush(readOnlyOverlay));
}
}
void PropertyDrawContext::drawButton(const QRect& rect, const wchar_t* text, int buttonFlags, const QFont* font, const Color* colorOverride) const
{
QPushButton button;
button.ensurePolished();
QStyleOptionButton option;
option.initFrom(&button);
if (buttonFlags & BUTTON_DISABLED) {
option.state |= QStyle::State_ReadOnly;
option.palette.setCurrentColorGroup(QPalette::Disabled);
}
else
option.state |= QStyle::State_Enabled;
if (buttonFlags & BUTTON_PRESSED) {
option.state |= QStyle::State_On;
option.state |= QStyle::State_Sunken;
}
else
option.state |= QStyle::State_Raised;
if (buttonFlags & BUTTON_FOCUSED)
option.state |= QStyle::State_HasFocus;
option.rect = rect.adjusted(0, 0, -1, -1);
QWidget* pseudoDrawWidget = &button;
if (colorOverride) {
QPalette& palette = option.palette;
palette.setCurrentColorGroup(QPalette::Normal);
QColor tintTarget(colorOverride->r, colorOverride->g, colorOverride->b, colorOverride->a);
QPalette::ColorRole groups[] = { QPalette::Button, QPalette::Light, QPalette::Dark, QPalette::Midlight, QPalette::Mid, QPalette::Shadow };
for (int i = 0; i < sizeof(groups) / sizeof(groups[0]); ++i)
palette.setColor(groups[i], interpolateColor(palette.color(groups[i]), tintTarget, 0.11f));
tree->style()->drawControl(QStyle::CE_PushButtonBevel, &option, painter, pseudoDrawWidget);
}
else
{
// Previously, a temporary QPushButton widget was used as the drawing aid
// for this control. However, our stylesheets didn't seem to affect the
// QPushButton as intended, which left some of them with incorrect background
// colors. It seemed to work to let the tree be the drawing aid, but we should
// probably revisit this in the future.
tree->style()->drawControl(QStyle::CE_PushButtonBevel, &option, painter, pseudoDrawWidget);
}
QRect textRect;
if ((buttonFlags & BUTTON_DISABLED) == 0 && buttonFlags & BUTTON_POPUP_ARROW)
{
QStyleOption arrowOption;
arrowOption.rect = QRect(rect.right() - 11, rect.top(), 8, rect.height());
arrowOption.state |= QStyle::State_Enabled;
// part of the above context change
tree->style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOption, painter, tree);
textRect = rect.adjusted(0, 0, -8, 0);
}
else
{
textRect = rect;
}
if (buttonFlags & BUTTON_PRESSED)
{
textRect = textRect.adjusted(1, 0, 1, 0);
}
if ((buttonFlags & BUTTON_CENTER) == 0)
{
textRect.adjust(4, 0, -5, 0);
}
QColor textColor;
if (colorOverride && !(buttonFlags & BUTTON_DISABLED))
{
textColor = interpolateColor(tree->palette().color(QPalette::Normal, QPalette::ButtonText),
QColor(colorOverride->r, colorOverride->g, colorOverride->b, colorOverride->a), 0.4f);
}
else
{
textColor = tree->palette().color((buttonFlags & BUTTON_DISABLED) ? QPalette::Disabled : QPalette::Normal, QPalette::ButtonText);
}
tree->_drawRowValue(*painter, text, font, textRect, textColor, false, (buttonFlags & BUTTON_CENTER) != 0);
}
void PropertyDrawContext::drawButtonWithIcon(const QIcon& icon, const QRect& rect, const wchar_t* text, bool selected, bool pressed, bool focused, bool enabled, bool showButtonFrame, const QFont* font) const
{
QStyleOptionButton option;
if (enabled)
option.state |= QStyle::State_Enabled;
else
option.state |= QStyle::State_ReadOnly;
if (pressed) {
option.state |= QStyle::State_On;
option.state |= QStyle::State_Sunken;
}
else
option.state |= QStyle::State_Raised;
if (focused)
option.state |= QStyle::State_HasFocus;
option.rect = rect.adjusted(0, 0, -1, -1);
// See the comment in the drawButton method above for why we don't use the
// QPushButton as the drawing aid for this control
if (showButtonFrame)
tree->style()->drawControl(QStyle::CE_PushButton, &option, painter, tree);
int iconSize = 16;
QRect iconRect(rect.topLeft(), QPoint(rect.left() + iconSize, rect.bottom()));
QRect textRect;
if (enabled)
textRect = rect.adjusted(iconSize, 0, -8, 0);
else
textRect = rect.adjusted(iconSize, 0, 0, 0);
if (pressed)
{
textRect.adjust(5, 0, 1, 0);
iconRect.adjust(4, 0, 4, 0);
}
else
{
textRect.adjust(4, 0, 0, 0);
iconRect.adjust(3, 0, 3, 0);
}
icon.paint(painter, iconRect);
QColor textColor = tree->palette().color(enabled ? QPalette::Active : QPalette::Disabled, selected && !showButtonFrame ? QPalette::HighlightedText : QPalette::ButtonText);
tree->_drawRowValue(*painter, text, font, textRect, textColor, false, false);
}
void PropertyDrawContext::drawValueText(bool highlighted, const wchar_t* text) const
{
QColor textColor = highlighted ? tree->palette().highlight().color() : tree->palette().buttonText().color();
QRect textRect(widgetRect.left() + 3, widgetRect.top() + 2, widgetRect.width() - 6, widgetRect.height() - 4);
tree->_drawRowValue(*painter, text, &tree->font(), textRect, textColor, false, false);
}
void PropertyDrawContext::drawEntry(const wchar_t* text, bool pathEllipsis, bool grayBackground, int trailingOffset) const
{
QRect rt = widgetRect;
rt.adjust(0, 0, -trailingOffset, 0);
// the drawing context requires context so that the style sheet can be used:
QFrame frameForContext;
QLineEdit forContext;
#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))
QStyleOptionFrameV2 option;
option.features = QStyleOptionFrameV2::None;
#else
QStyleOptionFrame option;
option.features = QStyleOptionFrame::None;
#endif
option.state = QStyle::State_Sunken;
option.lineWidth = tree->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, &frameForContext);
option.midLineWidth = 0;
if (!grayBackground)
option.state |= QStyle::State_Enabled;
else {
option.palette.setCurrentColorGroup(QPalette::Disabled);
}
if (captured)
option.state |= QStyle::State_HasFocus;
option.rect = rt; // option.rect is the rectangle to be drawn on.
QRect textRect = tree->style()->subElementRect(QStyle::SE_LineEditContents, &option, &forContext);
if (!textRect.isValid())
{
textRect = rt;
textRect.adjust(3, 1, -3, -2);
}
else {
textRect.adjust(2, 1, -2, -1);
}
// make sure the context control is polished (ie, ready for rendering) since we need to use its color palette:
forContext.ensurePolished();
// some styles rely on default pens
painter->setPen(QPen(forContext.palette().color(QPalette::Text)));
painter->setBrush(QBrush(forContext.palette().color(QPalette::Base)));
tree->style()->drawPrimitive(QStyle::PE_PanelLineEdit, &option, painter, &forContext);
tree->_drawRowValue(*painter, text, &tree->font(), textRect, forContext.palette().color(QPalette::Text), pathEllipsis, false);
// end amazno changes
}
QFont* propertyTreeDefaultFont()
{
static QFont font;
return &font;
}
QFont* propertyTreeDefaultBoldFont()
{
static QFont font;
font.setBold(true);
return &font;
}
@@ -0,0 +1,98 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYDRAWCONTEXT_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYDRAWCONTEXT_H
#pragma once
#include <map>
#include <vector>
#include <QRect>
#include "Color.h"
#include "EditorCommonAPI.h"
class QPainter;
class QImage;
class QBrush;
class QRect;
class QIcon;
class QColor;
class QFont;
struct RGBAImage;
namespace Serialization { struct IconXPM; }
struct Color;
struct IconXPMCache
{
void initialize();
void finalize();
void flush();
~IconXPMCache();
QImage* getImageForIcon(const Serialization::IconXPM& icon);
private:
struct BitmapCache {
std::vector<Color> pixels;
QImage* bitmap;
};
static bool parseXPM(RGBAImage* out, const Serialization::IconXPM& xpm);
typedef std::map<const char* const*, BitmapCache> IconToBitmap;
IconToBitmap iconToImageMap_;
};
void fillRoundRectangle(QPainter& p, const QBrush& brush, const QRect& r, const QColor& borderColor, int radius);
void drawRoundRectangle(QPainter& p, const QRect &_r, unsigned int color, int radius, int width);
enum CheckState {
CHECK_SET,
CHECK_NOT_SET,
CHECK_IN_BETWEEN
};
enum {
BUTTON_POPUP_ARROW = 1 << 0,
BUTTON_DISABLED = 1 << 1,
BUTTON_FOCUSED = 1 << 2,
BUTTON_PRESSED = 1 << 3,
BUTTON_CENTER = 1 << 4
};
class QPropertyTree;
struct EDITOR_COMMON_API PropertyDrawContext {
const QPropertyTree* tree;
QPainter* painter;
QRect widgetRect;
QRect lineRect;
bool captured;
bool m_pressed;
void drawIcon(const QRect& rect, const Serialization::IconXPM& icon) const;
void drawCheck(const QRect& rect, bool disabled, CheckState checked) const;
void drawButton(const QRect& rect, const wchar_t* text, int buttonFlags, const QFont* font, const Color* optionalColorOverride = 0) const;
void drawButtonWithIcon(const QIcon& icon, const QRect& rect, const wchar_t* text, bool selected, bool pressed, bool focused, bool enabled, bool showButtonFrame, const QFont* font) const;
void drawValueText(bool highlighted, const wchar_t* text) const;
void drawEntry(const wchar_t* text, bool pathEllipsis, bool grayBackground, int trailingOffset) const;
PropertyDrawContext()
: tree(0)
, painter(0)
, captured(false)
, m_pressed(false)
{
}
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYDRAWCONTEXT_H
@@ -0,0 +1,377 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "Serialization.h"
#include "Serialization/Enum.h"
#include "Serialization/Callback.h"
#include "PropertyTreeModel.h"
#include "PropertyIArchive.h"
#include "PropertyRowBool.h"
#include "PropertyRowString.h"
#include "PropertyRowNumber.h"
#include "PropertyRowPointer.h"
#include "PropertyRowObject.h"
#include "Unicode.h"
using Serialization::TypeID;
PropertyIArchive::PropertyIArchive(PropertyTreeModel* model, PropertyRow* root)
: IArchive(INPUT | EDIT)
, model_(model)
, currentNode_(0)
, lastNode_(0)
, root_(root)
{
stack_.push_back(Level());
if (!root_)
root_ = model_->root();
else
currentNode_ = root;
}
bool PropertyIArchive::operator()(Serialization::IString& value, const char* name, const char* label)
{
if(openRow(name, label, "string")){
if(PropertyRowString* row = static_cast<PropertyRowString*>(currentNode_))
value.set(fromWideChar(row->value().c_str()).c_str());
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(Serialization::IWString& value, const char* name, const char* label)
{
if(openRow(name, label, "string")){
if(PropertyRowString* row = static_cast<PropertyRowString*>(currentNode_)) {
value.set(row->value().c_str());
}
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(bool& value, const char* name, const char* label)
{
if(openRow(name, label, "bool")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(char& value, const char* name, const char* label)
{
if(openRow(name, label, "char")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
// Signed types
bool PropertyIArchive::operator()(int8& value, const char* name, const char* label)
{
if(openRow(name, label, "int8")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(int16& value, const char* name, const char* label)
{
if(openRow(name, label, "int16")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(int32& value, const char* name, const char* label)
{
if(openRow(name, label, "int32")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(int64& value, const char* name, const char* label)
{
if(openRow(name, label, "int64")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
// Unsigned types
bool PropertyIArchive::operator()(uint8& value, const char* name, const char* label)
{
if(openRow(name, label, "uint8")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(uint16& value, const char* name, const char* label)
{
if(openRow(name, label, "uint16")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(uint32& value, const char* name, const char* label)
{
if(openRow(name, label, "uint32")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(uint64& value, const char* name, const char* label)
{
if(openRow(name, label, "uint64")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(float& value, const char* name, const char* label)
{
if(openRow(name, label, "float")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(double& value, const char* name, const char* label)
{
if(openRow(name, label, "double")){
currentNode_->assignToPrimitive(&value, sizeof(value));
closeRow(name);
return true;
}
else
return false;
}
bool PropertyIArchive::operator()(Serialization::IContainer& ser, const char* name, const char* label)
{
const char* typeName = ser.containerType().name();
if(!openRow(name, label, typeName))
return false;
size_t size = 0;
if(currentNode_->multiValue())
size = ser.size();
else{
size = currentNode_->count();
size = ser.resize(size);
}
stack_.push_back(Level());
size_t index = 0;
if(ser.size() > 0)
while(index < size)
{
ser(*this, "", "<");
ser.next();
++index;
}
stack_.pop_back();
closeRow(name);
return true;
}
bool PropertyIArchive::operator()(const Serialization::SStruct& ser, const char* name, const char* label)
{
PropertyRow* nonLeafNode = 0;
if(openRow(name, label, ser.type().name())){
if (currentNode_->isLeaf()) {
if(!currentNode_->isRoot()){
currentNode_->assignTo(ser);
closeRow(name);
return true;
}
}
else
nonLeafNode = currentNode_;
}
else
return false;
stack_.push_back(Level());
ser(*this);
stack_.pop_back();
if (nonLeafNode)
nonLeafNode->closeNonLeaf(ser, *this);
closeRow(name);
return true;
}
bool PropertyIArchive::operator()(Serialization::IPointer& ser, const char* name, const char* label)
{
const char* baseName = ser.baseType().name();
if(openRow(name, label, baseName)){
if (!currentNode_->isPointer()) {
closeRow(name);
return false;
}
YASLI_ASSERT(currentNode_);
PropertyRowPointer* row = static_cast<PropertyRowPointer*>(currentNode_);
if(!row){
closeRow(name);
return false;
}
row->assignTo(ser);
}
else
return false;
stack_.push_back(Level());
if(ser.get() != 0)
ser.serializer()( *this );
stack_.pop_back();
closeRow(name);
return true;
}
bool PropertyIArchive::operator()(Serialization::ICallback& callback, const char* name, const char* label)
{
return callback.SerializeValue(*this, name, label);
}
bool PropertyIArchive::operator()(Serialization::Object& obj, const char* name, const char* label)
{
if(openRow(name, label, obj.type().name())){
bool result = false;
if (currentNode_->isObject()) {
PropertyRowObject* rowObj = static_cast<PropertyRowObject*>(currentNode_);
result = rowObj->assignTo(&obj);
}
closeRow(name);
return result;
}
else
return false;
}
bool PropertyIArchive::OpenBlock(const char* name, const char* label)
{
if(openRow(name, label, "block")){
stack_.push_back(Level());
return true;
}
else
return false;
}
void PropertyIArchive::CloseBlock()
{
closeRow("block");
stack_.pop_back();
}
bool PropertyIArchive::openRow(const char* name, [[maybe_unused]] const char* label, const char* typeName)
{
if(!name)
return false;
if(!currentNode_){
lastNode_ = currentNode_ = model_->root();
YASLI_ASSERT(currentNode_);
if (currentNode_ && strcmp(currentNode_->typeName(), typeName) != 0)
return false;
return true;
}
YASLI_ESCAPE(currentNode_, return false);
if(currentNode_->empty())
return false;
Level& level = stack_.back();
PropertyRow* node = 0;
if(currentNode_->isContainer()){
if (level.rowIndex < int(currentNode_->children_.size()))
node = currentNode_->children_[level.rowIndex];
++level.rowIndex;
}
else {
node = currentNode_->findFromIndex(&level.rowIndex, name, typeName, level.rowIndex);
++level.rowIndex;
}
if(node){
lastNode_ = node;
if(node->isContainer() || !node->multiValue()){
currentNode_ = node;
if (currentNode_ && strcmp(currentNode_->typeName(), typeName) != 0)
return false;
return true;
}
}
return false;
}
void PropertyIArchive::closeRow([[maybe_unused]] const char* name)
{
YASLI_ESCAPE(currentNode_, return);
currentNode_ = currentNode_->parent();
}
@@ -0,0 +1,80 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYIARCHIVE_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYIARCHIVE_H
#pragma once
#include "Serialization/IArchive.h"
namespace Serialization{
class CEnumDescription;
class Object;
}
class PropertyRow;
class PropertyTreeModel;
class PropertyIArchive : public Serialization::IArchive{
public:
PropertyIArchive(PropertyTreeModel* model, PropertyRow* root);
protected:
bool operator()(Serialization::IString& value, const char* name, const char* label);
bool operator()(Serialization::IWString& value, const char* name, const char* label);
bool operator()(bool& value, const char* name, const char* label);
bool operator()(char& value, const char* name, const char* label);
// Signed types
bool operator()(int8& value, const char* name, const char* label);
bool operator()(int16& value, const char* name, const char* label);
bool operator()(int32& value, const char* name, const char* label);
bool operator()(int64& value, const char* name, const char* label);
// Unsigned types
bool operator()(uint8& value, const char* name, const char* label);
bool operator()(uint16& value, const char* name, const char* label);
bool operator()(uint32& value, const char* name, const char* label);
bool operator()(uint64& value, const char* name, const char* label);
bool operator()(float& value, const char* name, const char* label);
bool operator()(double& value, const char* name, const char* label);
bool operator()(const Serialization::SStruct& ser, const char* name, const char* label);
bool operator()(Serialization::IPointer& ser, const char* name, const char* label);
bool operator()(Serialization::IContainer& ser, const char* name, const char* label);
bool operator()(Serialization::Object& obj, const char* name, const char* label);
bool operator()(Serialization::ICallback& callback, const char* name, const char* label);
using Serialization::IArchive::operator();
bool OpenBlock(const char* name, const char* label);
void CloseBlock();
protected:
bool needDefaultArchive([[maybe_unused]] const char* baseName) const { return false; }
private:
bool openRow(const char* name, const char* label, const char* typeName);
void closeRow(const char* name);
struct Level {
int rowIndex;
Level() : rowIndex(0) {}
};
vector<Level> stack_;
PropertyTreeModel* model_;
PropertyRow* currentNode_;
PropertyRow* lastNode_;
PropertyRow* root_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYIARCHIVE_H
@@ -0,0 +1,494 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include <math.h>
#include <memory>
#include "PropertyTreeModel.h"
#include "QPropertyTree.h"
#include "PropertyRowContainer.h"
#include "PropertyRowBool.h"
#include "PropertyRowString.h"
#include "PropertyRowNumber.h"
#include "PropertyRowPointer.h"
#include "PropertyRowObject.h"
#include "ConstStringList.h"
#include "Unicode.h"
#include "Serialization.h"
#include "PropertyOArchive.h"
#include "Serialization/Callback.h"
using Serialization::TypeID;
PropertyOArchive::PropertyOArchive(PropertyTreeModel* model, PropertyRow* root, ValidatorBlock* validator)
: IArchive(OUTPUT | EDIT | VALIDATION | DOCUMENTATION)
, model_(model)
, currentNode_(root)
, lastNode_(0)
, updateMode_(false)
, defaultValueCreationMode_(false)
, rootNode_(root)
, outlineMode_(false)
, validator_(validator)
{
stack_.push_back(Level());
YASLI_ASSERT(model != 0);
if(!rootNode_->empty()){
updateMode_ = true;
stack_.back().oldRows.swap(rootNode_->children_);
}
}
PropertyOArchive::PropertyOArchive(PropertyTreeModel* model, bool forDefaultType)
: IArchive(OUTPUT | EDIT | VALIDATION | DOCUMENTATION)
, model_(model)
, currentNode_(0)
, lastNode_(0)
, updateMode_(false)
, defaultValueCreationMode_(forDefaultType)
, rootNode_(0)
, outlineMode_(false)
, validator_(0)
{
rootNode_ = new PropertyRow();
rootNode_->setName("root");
currentNode_ = rootNode_.get();
stack_.push_back(Level());
}
PropertyOArchive::~PropertyOArchive()
{
}
PropertyRow* PropertyOArchive::defaultValueRootNode()
{
if (!rootNode_)
return 0;
return rootNode_->childByIndex(0);
}
void PropertyOArchive::enterNode(PropertyRow* row)
{
currentNode_ = row;
stack_.push_back(Level());
Level& level = stack_.back();
level.oldRows.swap(row->children_);
row->children_.reserve(level.oldRows.size());
}
void PropertyOArchive::closeStruct([[maybe_unused]] const char* name)
{
stack_.pop_back();
if(currentNode_){
lastNode_ = currentNode_;
currentNode_ = currentNode_->parent();
}
}
static PropertyRow* findRow(int* index, PropertyRows& rows, const char* name, const char* typeName, int startIndex)
{
int count = int(rows.size());
for(int i = startIndex; i < count; ++i){
PropertyRow* row = rows[i];
if (!row)
continue;
if(((row->name() == name) || strcmp(row->name(), name) == 0) &&
(row->typeName() == typeName || strcmp(row->typeName(), typeName) == 0)) {
*index = (int)i;
return row;
}
}
for(int i = 0; i < startIndex; ++i){
PropertyRow* row = rows[i];
if (!row)
continue;
if(((row->name() == name) || strcmp(row->name(), name) == 0) &&
(row->typeName() == typeName || strcmp(row->typeName(), typeName) == 0)) {
*index = (int)i;
return row;
}
}
return 0;
}
template<class RowType, class ValueType>
RowType* PropertyOArchive::updateRow(const char* name, const char* label, const char* typeName, const ValueType& value)
{
SharedPtr<RowType> newRow;
if(currentNode_ == 0){
if (rootNode_)
newRow = static_cast<RowType*>(rootNode_.get());
else
newRow.reset(new RowType());
newRow->setNames(name, label, typeName);
if(updateMode_){
model_->setRoot(newRow);
return newRow;
}
else{
if(defaultValueCreationMode_)
rootNode_ = newRow;
else
model_->setRoot(newRow);
newRow->setValueAndContext(value, *this);
return newRow;
}
}
else{
Level& level = stack_.back();
int rowIndex;
PropertyRow* oldRow = findRow(&rowIndex, level.oldRows, name, typeName, level.rowIndex);
const char* oldLabel = 0;
if(oldRow){
oldRow->setMultiValue(false);
newRow = static_cast<RowType*>(oldRow);
level.oldRows[rowIndex] = 0;
level.rowIndex = rowIndex + 1;
oldLabel = oldRow->label();
newRow->setNames(name, label, typeName);
}
else{
PropertyRowFactory& factory = PropertyRowFactory::the();
newRow = static_cast<RowType*>(factory.create(typeName));
if(!newRow)
newRow.reset(new RowType());
newRow->setNames(name, label, typeName);
if(model_->expandLevels() != 0 && (model_->expandLevels() == -1 || model_->expandLevels() >= currentNode_->level()))
newRow->_setExpanded(true);
}
currentNode_->add(newRow);
if (!oldRow || oldLabel != label) {
// for new rows we should mark all parents with labelChanged_
newRow->setLabelChanged();
newRow->setLabelChangedToChildren();
}
newRow->setValueAndContext(value, *this);
return newRow;
}
}
template<class RowType, class ValueType>
PropertyRow* PropertyOArchive::updateRowPrimitive(const char* name, const char* label, const char* typeName, const ValueType& value, const void* handle, const Serialization::TypeID& typeId)
{
SharedPtr<RowType> newRow;
if(currentNode_ == 0)
return 0;
int rowIndex;
Level& level = stack_.back();
PropertyRow* oldRow = findRow(&rowIndex, level.oldRows, name, typeName, level.rowIndex);
const char* oldLabel = 0;
if(oldRow){
oldRow->setMultiValue(false);
newRow.reset(static_cast<RowType*>(oldRow));
level.oldRows[rowIndex] = 0;
level.rowIndex = rowIndex + 1;
oldLabel = oldRow->label();
oldRow->setNames(name, label, typeName);
}
else{
newRow = new RowType();
newRow->setNames(name, label, typeName);
if(model_->expandLevels() != 0){
if(model_->expandLevels() == -1 || model_->expandLevels() >= currentNode_->level())
newRow->_setExpanded(true);
}
}
currentNode_->add(newRow);
if (!oldRow || oldLabel != label)
{
// for new rows we should mark all parents with labelChanged_
newRow->setLabelChanged();
}
newRow->setValue(value, handle, typeId);
return newRow;
}
bool PropertyOArchive::operator()(const Serialization::SStruct& ser, const char* name, const char* label)
{
const char* typeName = ser.type().name();
size_t size = ser.size();
lastNode_ = currentNode_;
bool hideChildren = outlineMode_ && currentNode_ && currentNode_->isContainer();
PropertyRow* row = updateRow<PropertyRow>(name, label, typeName, ser);
row->setHideChildren(hideChildren);
PropertyRow* nonLeaf = 0;
if(!row->isLeaf() || currentNode_ == 0){
enterNode(row);
if(currentNode_->isLeaf())
return false;
else
nonLeaf = currentNode_;
}
else{
lastNode_ = row;
return true;
}
if (ser)
ser(*this);
if (nonLeaf)
nonLeaf->closeNonLeaf(ser, *this);
closeStruct(name);
return true;
}
bool PropertyOArchive::operator()(Serialization::IString& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowString>(name, label, "string", value.get(), value.handle(), value.type());
return true;
}
bool PropertyOArchive::operator()(Serialization::IWString& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowString>(name, label, "string", value.get(), value.handle(), value.type());
return true;
}
bool PropertyOArchive::operator()(bool& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowBool>(name, label, "bool", value, &value, Serialization::TypeID::get<bool>());
return true;
}
bool PropertyOArchive::operator()(char& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<char> >(name, label, "char", value, &value, Serialization::TypeID::get<char>());
return true;
}
// ---
bool PropertyOArchive::operator()(int8& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<int8> >(name, label, "int8", value, &value, Serialization::TypeID::get<int8>());
return true;
}
bool PropertyOArchive::operator()(int16& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<int16> >(name, label, "int16", value, &value, Serialization::TypeID::get<int16>());
return true;
}
bool PropertyOArchive::operator()(int32& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<int32> >(name, label, "int32", value, &value, Serialization::TypeID::get<int32>());
return true;
}
bool PropertyOArchive::operator()(int64& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<int64> >(name, label, "int64", value, &value, Serialization::TypeID::get<int64>());
return true;
}
// ---
bool PropertyOArchive::operator()(uint8& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<uint8> >(name, label, "uint8", value, &value, Serialization::TypeID::get<uint8>());
return true;
}
bool PropertyOArchive::operator()(uint16& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<uint16> >(name, label, "uint16", value, &value, Serialization::TypeID::get<uint16>());
return true;
}
bool PropertyOArchive::operator()(uint32& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<uint32> >(name, label, "uint32", value, &value, Serialization::TypeID::get<uint32>());
return true;
}
bool PropertyOArchive::operator()(uint64& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<uint64> >(name, label, "uint64", value, &value, Serialization::TypeID::get<uint64>());
return true;
}
// ---
bool PropertyOArchive::operator()(float& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<float> >(name, label, "float", value, &value, Serialization::TypeID::get<float>());
return true;
}
bool PropertyOArchive::operator()(double& value, const char* name, const char* label)
{
lastNode_ = updateRowPrimitive<PropertyRowNumber<double> >(name, label, "double", value, &value, Serialization::TypeID::get<double>());
return true;
}
bool PropertyOArchive::operator()(Serialization::IContainer& ser, const char *name, const char *label)
{
const char* elementTypeName = ser.elementType().name();
bool fixedSizeContainer = ser.isFixedSize();
lastNode_ = currentNode_;
enterNode(updateRow<PropertyRowContainer>(name, label, ser.containerType().name(), ser));
if (!model_->defaultTypeRegistered(elementTypeName)) {
PropertyOArchive ar(model_, true);
ar.SetOutlineMode(outlineMode_);
ar.SetFilter(GetFilter());
ar.SetInnerContext(GetInnerContext());
model_->addDefaultType(0, elementTypeName); // add empty default to prevent recursion
ser.serializeNewElement(ar, "", (label&&*label=='!')?"!<":"<");
if (ar.defaultValueRootNode() != 0)
model_->addDefaultType(ar.defaultValueRootNode(), elementTypeName);
}
if ( ser.size() > 0 )
while( true ) {
ser(*this, "", (label&&*label=='!')?"!<":"<");
if ( !ser.next() )
break;
}
currentNode_->labelChanged();
closeStruct(name);
return true;
}
bool PropertyOArchive::operator()(Serialization::IPointer& ptr, const char *name, const char *label)
{
lastNode_ = currentNode_;
bool hideChildren = outlineMode_ && currentNode_ && currentNode_->isContainer();
PropertyRow* row = updateRow<PropertyRowPointer>(name, label, ptr.baseType().name(), ptr);
row->setHideChildren(hideChildren);
enterNode(row);
{
TypeID baseType = ptr.baseType();
Serialization::IClassFactory* factory = ptr.factory();
size_t count = factory->size();
const char* nullLabel = factory->nullLabel();
if (!(nullLabel && nullLabel[0] == '\0'))
{
PropertyDefaultDerivedTypeValue nullValue;
nullValue.factory = factory;
nullValue.factoryIndex = -1;
nullValue.label = nullLabel ? nullLabel : "[ null ]";
model_->addDefaultType(baseType, nullValue);
}
for(size_t i = 0; i < count; ++i) {
const Serialization::TypeDescription *desc = factory->descriptionByIndex((int)i);
if (!model_->defaultTypeRegistered(baseType, desc->name())){
PropertyOArchive ar(model_, true);
ar.SetOutlineMode(outlineMode_);
ar.SetInnerContext(GetInnerContext());
ar.SetFilter(GetFilter());
PropertyDefaultDerivedTypeValue defaultValue;
defaultValue.registeredName = desc->name();
defaultValue.factory = factory;
defaultValue.factoryIndex = int(i);
defaultValue.label = desc->label();
model_->addDefaultType(baseType, defaultValue);
factory->serializeNewByIndex(ar, (int)i, "name", "label");
if (ar.defaultValueRootNode() != 0) {
ar.defaultValueRootNode()->setTypeName(desc->name());
defaultValue.root = ar.defaultValueRootNode();
model_->addDefaultType(baseType, defaultValue);
}
}
}
}
if(Serialization::SStruct ser = ptr.serializer())
ser(*this);
closeStruct(name);
return true;
}
bool PropertyOArchive::operator()(Serialization::ICallback& callback, const char* name, const char* label)
{
if (!callback.SerializeValue(*this, name, label))
return false;
lastNode_->setCallback(callback.Clone());
return true;
}
bool PropertyOArchive::operator()(Serialization::Object& obj, const char *name, const char *label)
{
const char* typeName = obj.type().name();
PropertyRowObject* row = 0;
if (typeName_.empty())
row = updateRow<PropertyRowObject>(name, label, obj.type().name(), obj);
else
row = updateRow<PropertyRowObject>(name, label, obj.type().name(), obj);
lastNode_ = row;
return true;
}
bool PropertyOArchive::OpenBlock(const char* name, const char* label)
{
PropertyRow* row = updateRow<PropertyRow>(name, label, "block", Serialization::SStruct());
lastNode_ = currentNode_;
enterNode(row);
return true;
}
void PropertyOArchive::ValidatorMessage(bool error, const void* handle, const Serialization::TypeID& type, const char* message)
{
if (validator_)
{
ValidatorEntry entry(error ? VALIDATOR_ENTRY_ERROR : VALIDATOR_ENTRY_WARNING,
handle,
type,
message);
validator_->AddEntry(entry);
}
}
void PropertyOArchive::DocumentLastField(const char* message)
{
if (lastNode_ && (!currentNode_ || lastNode_->parent() == currentNode_))
lastNode_->setTooltip(message ? message : "");
else if (currentNode_)
currentNode_->setTooltip(message ? message : "");
}
void PropertyOArchive::CloseBlock()
{
closeStruct("block");
}
void PropertyOArchive::SetOutlineMode(bool outlineMode)
{
outlineMode_ = outlineMode;
}
// vim:ts=4 sw=4:
@@ -0,0 +1,112 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYOARCHIVE_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYOARCHIVE_H
#pragma once
#include "Serialization/IArchive.h"
#include "Serialization/Pointers.h"
namespace Serialization
{
class CEnumDescription;
class Object;
struct ICallback;
}
class PropertyRow;
class PropertyTreeModel;
class ValidatorBlock;
using Serialization::SharedPtr;
class PropertyOArchive : public Serialization::IArchive{
public:
PropertyOArchive(PropertyTreeModel* model, PropertyRow* root, ValidatorBlock* validator);
~PropertyOArchive();
void SetOutlineMode(bool outlineMode);
inline const SharedPtr<PropertyRow>& currentNode() const {
return currentNode_;
}
protected:
bool operator()(Serialization::IString& value, const char* name, const char* label);
bool operator()(Serialization::IWString& value, const char* name, const char* label);
bool operator()(bool& value, const char* name, const char* label);
bool operator()(char& value, const char* name, const char* label);
bool operator()(int8& value, const char* name, const char* label);
bool operator()(int16& value, const char* name, const char* label);
bool operator()(int32& value, const char* name, const char* label);
bool operator()(int64& value, const char* name, const char* label);
bool operator()(uint8& value, const char* name, const char* label);
bool operator()(uint16& value, const char* name, const char* label);
bool operator()(uint32& value, const char* name, const char* label);
bool operator()(uint64& value, const char* name, const char* label);
bool operator()(float& value, const char* name, const char* label);
bool operator()(double& value, const char* name, const char* label);
bool operator()(const Serialization::SStruct& ser, const char* name, const char* label);
bool operator()(Serialization::IPointer& ptr, const char *name, const char *label);
bool operator()(Serialization::IContainer& ser, const char *name, const char *label);
bool operator()(Serialization::Object& obj, const char *name, const char *label);
bool operator()(Serialization::ICallback& ser, const char *name, const char *label);
using Serialization::IArchive::operator();
bool OpenBlock(const char* name, const char* label);
void CloseBlock();
void ValidatorMessage(bool error, const void* handle, const Serialization::TypeID& type, const char* message);
void DocumentLastField(const char* docString);
protected:
PropertyOArchive(PropertyTreeModel* model, bool forDefaultType);
private:
struct Level {
std::vector<SharedPtr<PropertyRow> > oldRows;
int rowIndex;
Level() : rowIndex(0) {}
};
std::vector<Level> stack_;
template<class RowType, class ValueType>
PropertyRow* updateRowPrimitive(const char* name, const char* label, const char* typeName, const ValueType& value, const void* handle, const Serialization::TypeID& typeId);
template<class RowType, class ValueType>
RowType* updateRow(const char* name, const char* label, const char* typeName, const ValueType& value);
void enterNode(PropertyRow* row); // sets currentNode
void closeStruct(const char* name);
PropertyRow* defaultValueRootNode();
bool updateMode_;
bool defaultValueCreationMode_;
PropertyTreeModel* model_;
ValidatorBlock* validator_;
SharedPtr<PropertyRow> currentNode_;
SharedPtr<PropertyRow> lastNode_;
// for defaultArchive
SharedPtr<PropertyRow> rootNode_;
std::string typeName_;
const char* derivedTypeName_;
std::string derivedTypeNameAlt_;
bool outlineMode_;
};
// vim:ts=4 sw=4:
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYOARCHIVE_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,575 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#pragma once
#if !defined(Q_MOC_RUN)
#include <typeinfo>
#include <algorithm>
#include "Serialization/Serializer.h"
#include "Serialization/StringList.h"
#include <Serialization/Pointers.h>
#include "Factory.h"
#include "ConstStringList.h"
#include "Strings.h"
#include "../EditorCommonAPI.h"
#include "Serialization/ClassFactory.h"
#include <QObject>
#include <QPoint>
#include <QRect>
#include <QCursor>
#endif
namespace Serialization { struct ICallback; }
class QWidget;
class QFont;
class QPainter;
class QMenu;
class QKeyEvent;
using std::vector;
class QPropertyTree;
class PropertyRow;
class PropertyTreeModel;
class PopupMenuItem;
struct PropertyDrawContext;
struct EDITOR_COMMON_API ContainerMenuHandler;
class PropertyRowContainer;
enum ScanResult {
SCAN_FINISHED,
SCAN_CHILDREN,
SCAN_SIBLINGS,
SCAN_CHILDREN_SIBLINGS,
};
struct EDITOR_COMMON_API PropertyRowMenuHandler : QObject
{
public:
virtual ~PropertyRowMenuHandler() {}
};
struct PropertyActivationEvent
{
enum Reason
{
REASON_PRESS,
REASON_RELEASE,
REASON_DOUBLECLICK,
REASON_KEYBOARD,
REASON_NEW_ELEMENT
};
QPropertyTree* tree;
Reason reason;
bool force;
QPoint clickPoint;
PropertyActivationEvent()
: force(false)
, clickPoint(0, 0)
, tree(0)
, reason(REASON_PRESS)
{
}
};
struct PropertyDragEvent
{
QPropertyTree* tree;
QPoint pos;
QPoint start;
QPoint lastDelta;
QPoint totalDelta;
};
struct PropertyHoverInfo
{
QCursor cursor;
QString toolTip;
PropertyHoverInfo()
: cursor()
{
}
};
enum DragCheckBegin {
DRAG_CHECK_IGNORE,
DRAG_CHECK_SET,
DRAG_CHECK_UNSET
};
class PropertyRowWidget : public QObject
{
Q_OBJECT
public:
PropertyRowWidget(PropertyRow* row, QPropertyTree* tree);
virtual ~PropertyRowWidget();
virtual QWidget* actualWidget() { return 0; }
virtual void showPopup() {}
virtual void commit() = 0;
PropertyRow* row() { return row_; }
PropertyTreeModel* model() { return model_; }
protected:
PropertyRow* row_;
QPropertyTree* tree_;
PropertyTreeModel* model_;
};
class PropertyTreeTransaction;
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
class EDITOR_COMMON_API PropertyRow : public Serialization::RefCounter
{
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
public:
enum WidgetPlacement {
WIDGET_NONE,
WIDGET_ICON,
WIDGET_AFTER_NAME,
WIDGET_VALUE,
WIDGET_AFTER_PULLED,
WIDGET_INSTEAD_OF_TEXT
};
typedef std::vector< Serialization::SharedPtr<PropertyRow> > Rows;
typedef Rows::iterator iterator;
typedef Rows::const_iterator const_iterator;
PropertyRow();
virtual ~PropertyRow();
void setNames(const char* name, const char* label, const char* typeName);
bool selected() const{ return selected_; }
void setSelected(bool selected) { selected_ = selected; }
bool expanded() const{ return expanded_; }
void _setExpanded(bool expanded); // use QPropertyTree::expandRow
void setExpandedRecursive(QPropertyTree* tree, bool expanded);
void setMatchFilter(bool matchFilter) { matchFilter_ = matchFilter; }
bool matchFilter() const { return matchFilter_; }
void setBelongsToFilteredRow(bool belongs) { belongsToFilteredRow_ = belongs; }
bool belongsToFilteredRow() const { return belongsToFilteredRow_; }
bool visible(const QPropertyTree* tree) const;
bool hasVisibleChildren(const QPropertyTree* tree, bool internalCall = false) const;
const PropertyRow* hit(const QPropertyTree* tree, QPoint point) const;
PropertyRow* hit(const QPropertyTree* tree, QPoint point);
PropertyRow* parent() { return parent_; }
const PropertyRow* parent() const{ return parent_; }
void setParent(PropertyRow* row) { parent_ = row; }
bool isRoot() const { return !parent_; }
int level() const;
void add(PropertyRow* row);
void addAfter(PropertyRow* row, PropertyRow* after);
void addBefore(PropertyRow* row, PropertyRow* before);
template<class Op> bool scanChildren(Op& op);
template<class Op> bool scanChildren(Op& op, QPropertyTree* tree);
template<class Op> bool scanChildrenReverse(Op& op, QPropertyTree* tree);
template<class Op> bool scanChildrenBottomUp(Op& op, QPropertyTree* tree);
PropertyRow* childByIndex(int index);
const PropertyRow* childByIndex(int index) const;
int childIndex(const PropertyRow* row) const;
bool isChildOf(const PropertyRow* row) const;
bool empty() const{ return children_.empty(); }
iterator find(PropertyRow* row) { return std::find(children_.begin(), children_.end(), row); }
PropertyRow* findFromIndex(int* outIndex, const char* name, const char* typeName, int startIndex) const;
PropertyRow* findByAddress(const void* handle);
virtual const void* searchHandle() const;
iterator begin() { return children_.begin(); }
iterator end() { return children_.end(); }
const_iterator begin() const{ return children_.begin(); }
const_iterator end() const{ return children_.end(); }
std::size_t count() const{ return children_.size(); }
iterator erase(iterator it){ return children_.erase(it); }
void clear(){ children_.clear(); }
void erase(PropertyRow* row);
void swapChildren(PropertyRow* row, PropertyTreeModel* model);
void assignRowState(const PropertyRow& row, bool recurse);
void assignRowProperties(PropertyRow* row);
void replaceAndPreserveState(PropertyRow* oldRow, PropertyRow* newRow, PropertyTreeModel* model);
const char* name() const{ return name_; }
void setName(const char* name) { name_ = name; }
const char* label() const { return label_; }
const char* labelUndecorated() const { return labelUndecorated_; }
void setLabel(const char* label);
void setLabelChanged();
void setTooltip(const char* tooltip);
bool setValidatorEntry(int index, int count);
int validatorCount() const{ return validatorCount_; }
int validatorIndex() const{ return validatorIndex_; }
void resetValidatorIcons();
void addValidatorIcons(bool hasWarnings, bool hasErrors);
const char* tooltip() const { return tooltip_; }
void setLayoutChanged();
void setLabelChangedToChildren();
void setLayoutChangedToChildren();
void setHideChildren(bool hideChildren) { hideChildren_ = hideChildren; }
bool hideChildren() const { return hideChildren_; }
void updateLabel(const QPropertyTree* tree, int index, bool parentHidesNonInlineChildren);
void updateTextSizeInitial(const QPropertyTree* tree, int index, bool force);
virtual void labelChanged() {}
void parseControlCodes(const QPropertyTree* tree, const char* label, bool changeLabel);
const char* typeName() const{ return typeName_; }
virtual const char* typeNameForFilter(QPropertyTree* tree) const;
void setTypeName(const char* typeName) { typeName_ = typeName; }
const char* rowText(char* containerLabelBuffer, size_t bufsiz, const QPropertyTree* tree, int rowIndex) const;
PropertyRow* findSelected();
PropertyRow* find(const char* name, const char* nameAlt, const char* typeName);
const PropertyRow* find(const char* name, const char* nameAlt, const char* typeName) const;
void intersect(const PropertyRow* row);
int verticalIndex(QPropertyTree* tree, PropertyRow* row);
PropertyRow* rowByVerticalIndex(QPropertyTree* tree, int index);
int horizontalIndex(QPropertyTree* tree, PropertyRow* row);
PropertyRow* rowByHorizontalIndex(QPropertyTree* tree, int index);
virtual bool assignToPrimitive([[maybe_unused]] void* object, [[maybe_unused]] size_t size) const{ return false; }
virtual bool assignTo([[maybe_unused]] const Serialization::SStruct& ser) const{ return false; }
virtual bool assignToByPointer(void* instance, const Serialization::TypeID& type) const{ return assignTo(Serialization::SStruct(type, instance, type.sizeOf(), 0)); }
virtual void setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) { serializer_ = ser; }
virtual void handleChildrenChange() {}
virtual string valueAsString() const;
virtual wstring valueAsWString() const;
int height() const{ return size_.y(); }
virtual int widgetSizeMin(const QPropertyTree*) const { return userWidgetSize() >= 0 ? userWidgetSize() : 0; }
virtual int floorHeight() const{ return 0; }
void calcPulledRows(int* minTextSize, int* freePulledChildren, int* minimalWidth, const QPropertyTree* tree, int index);
void calculateMinimalSize(const QPropertyTree* tree, int posX, int availableWidth, bool force, int* extraSizeRemainder, int* _extraSize, int index);
void setTextSize(const QPropertyTree* tree, int rowIndex, float multiplier);
void calculateTotalSizes(int* minTextSize);
void adjustVerticalPosition(const QPropertyTree* tree, int& totalHeight);
virtual bool isWidgetFixed() const{ return userFixedWidget_ || (widgetPlacement() != WIDGET_VALUE && widgetPlacement() != WIDGET_INSTEAD_OF_TEXT); }
virtual WidgetPlacement widgetPlacement() const{ return WIDGET_NONE; }
QRect rect() const{ return QRect(pos_.x(), pos_.y(), size_.x(), size_.y()); }
QRect rectIncludingChildren(const QPropertyTree* tree) const;
QRect textRect(const QPropertyTree* tree) const;
QRect widgetRect(const QPropertyTree* tree) const;
QRect plusRect(const QPropertyTree* tree) const;
QRect floorRect(const QPropertyTree* tree) const;
QRect validatorRect(const QPropertyTree* tree) const;
QRect validatorWarningIconRect(const QPropertyTree* tree) const;
QRect validatorErrorIconRect(const QPropertyTree* tree) const;
void adjustHoveredRect(QRect& hoveredRect);
int heightIncludingChildren() const{ return heightIncludingChildren_; }
const QFont* rowFont(const QPropertyTree* tree) const;
void drawRow(QPainter& painter, const QPropertyTree* tree, int rowIndex, bool selectionPass);
void drawPlus(QPainter& p, const QPropertyTree* tree, const QRect& rect, bool expanded, bool selected, bool grayed) const;
void drawStaticText(QPainter& p, const QRect& widgetRect);
virtual void redraw(const PropertyDrawContext& context);
virtual PropertyRowWidget* createWidget([[maybe_unused]] QPropertyTree* tree) { return 0; }
virtual bool isContainer() const{ return false; }
virtual bool isPointer() const{ return false; }
virtual bool isObject() const{ return false; }
virtual bool isLeaf() const{ return false; }
virtual void closeNonLeaf([[maybe_unused]] const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) {}
virtual bool isStatic() const{ return pulledContainer_ == 0; }
virtual bool isSelectable() const{ return (!userReadOnly() && !userReadOnlyRecurse()) || (!pulledUp() && !pulledBefore()); }
virtual bool activateOnAdd() const{ return false; }
virtual bool inlineInShortArrays() const{ return false; }
bool canBeToggled(const QPropertyTree* tree) const;
bool canBeDragged() const;
bool canBeDroppedOn(const PropertyRow* parentRow, const PropertyRow* beforeChild, const QPropertyTree* tree) const;
void dropInto(PropertyRow* parentRow, PropertyRow* cursorRow, QPropertyTree* tree, bool before);
virtual bool getHoverInfo(PropertyHoverInfo* hit, [[maybe_unused]] const QPoint& cursorPos, [[maybe_unused]] const QPropertyTree* tree) const {
hit->toolTip = QString::fromUtf8(tooltip_);
return true;
}
virtual bool onActivate(const PropertyActivationEvent& e);
virtual bool processesKey(QPropertyTree* tree, const QKeyEvent* ev); // returns true if it wants to process key events; otherwise, they will get processed by shortcuts in some cases, like delete
virtual bool onKeyDown(QPropertyTree* tree, const QKeyEvent* ev);
virtual bool onMouseDown([[maybe_unused]] QPropertyTree* tree, [[maybe_unused]] QPoint point, [[maybe_unused]] bool& changed) { return false; }
virtual void onMouseDrag([[maybe_unused]] const PropertyDragEvent& e) {}
virtual void onMouseStill([[maybe_unused]] const PropertyDragEvent& e) {}
virtual void onMouseUp([[maybe_unused]] QPropertyTree* tree, [[maybe_unused]] QPoint point) {}
// "drag check" allows you to "paint" with the mouse through checkboxes to set all values at once
virtual DragCheckBegin onMouseDragCheckBegin() { return DRAG_CHECK_IGNORE; }
virtual bool onMouseDragCheck([[maybe_unused]] QPropertyTree* tree, [[maybe_unused]] bool value) { return false; }
virtual bool onContextMenu(QMenu &menu, QPropertyTree* tree);
virtual ContainerMenuHandler* createMenuHandler(QPropertyTree* tree, PropertyRowContainer* container);
virtual bool isFullRow(const QPropertyTree* tree) const;
// User states.
// Assigned using control codes (characters in the beginning of label)
// fixed widget doesn't expand automatically to occupy all available place
bool userFixedWidget() const{ return userFixedWidget_; }
bool userFullRow() const { return userFullRow_; }
void setUserReadOnly(bool userReadOnly) { userReadOnly_ = userReadOnly; }
virtual bool userReadOnly() const { return userReadOnly_; }
void propagateFlagsTopToBottom();
virtual bool userReadOnlyRecurse() const { return userReadOnlyRecurse_; }
bool userWidgetToContent() const { return userWidgetToContent_; }
int userWidgetSize() const{ return userWidgetSize_; }
bool userNonCopyable() const { return userNonCopyable_; }
// multiValue is used to edit properties of multiple objects simulateneously
bool multiValue() const { return multiValue_; }
void setMultiValue(bool multiValue) { multiValue_ = multiValue; }
// pulledRow - is the one that is pulled up to the parents row
// (created with ^ in the beginning of label)
bool pulledUp() const { return pulledUp_; }
bool pulledBefore() const { return pulledBefore_; }
bool hasPulled() const { return hasPulled_; }
bool packedAfterPreviousRow() const { return packedAfterPreviousRow_; }
bool pulledSelected() const;
PropertyRow* nonPulledParent();
void setPulledContainer(PropertyRow* container){ pulledContainer_ = container; }
PropertyRow* pulledContainer() { return pulledContainer_; }
const PropertyRow* pulledContainer() const{ return pulledContainer_; }
Serialization::SharedPtr<PropertyRow> clone(ConstStringList* constStrings) const;
Serialization::SStruct serializer() const{ return serializer_; }
virtual Serialization::TypeID typeId() const{ return serializer_.type(); }
void setSerializer(const Serialization::SStruct& ser) { serializer_ = ser; }
virtual void serializeValue([[maybe_unused]] Serialization::IArchive& ar) {}
void setCallback(Serialization::ICallback* callback);
Serialization::ICallback* callback() { return callback_; }
virtual void Serialize(Serialization::IArchive& ar);
static void setConstStrings(ConstStringList* constStrings){ constStrings_ = constStrings; }
protected:
void init(const char* name, const char* nameAlt, const char* typeName);
PropertyRow* findChildFromDescendant(PropertyRow* row) const;
virtual void overrideTextColor([[maybe_unused]] QColor& textColor) {}
const char* name_;
const char* label_;
const char* labelUndecorated_;
const char* typeName_;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
Serialization::SStruct serializer_;
PropertyRow* parent_;
Serialization::ICallback* callback_;
const char* tooltip_;
Rows children_;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
unsigned int textHash_;
// do we really need QPoint here?
QPoint pos_;
QPoint size_;
short int textPos_;
short int textSizeInitial_;
short int textSize_;
short int widgetPos_; // widget == icon!
short int widgetSize_;
short int userWidgetSize_;
unsigned short heightIncludingChildren_;
unsigned short validatorIndex_;
unsigned short validatorsHeight_;
unsigned char validatorCount_;
unsigned char plusSize_;
bool visible_ : 1;
bool matchFilter_ : 1;
bool belongsToFilteredRow_ : 1;
bool expanded_ : 1;
bool selected_ : 1;
bool labelChanged_ : 1;
bool layoutChanged_ : 1;
bool userReadOnly_ : 1;
bool userReadOnlyRecurse_ : 1;
bool userFixedWidget_ : 1;
bool userFullRow_ : 1;
bool userPackCheckboxes_ : 1;
bool userWidgetToContent_ : 1;
bool pulledUp_ : 1;
bool pulledBefore_ : 1;
bool packedAfterPreviousRow_ : 1;
bool hasPulled_ : 1;
bool multiValue_ : 1;
bool hideChildren_ : 1;
bool validatorHasErrors_ : 1;
bool validatorHasWarnings_ : 1;
bool userNonCopyable_ : 1;
enum class FontWeight
{
Undefined,
Bold,
Regular
};
FontWeight fontWeight_;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
Serialization::SharedPtr<PropertyRow> pulledContainer_;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
static ConstStringList* constStrings_;
friend class PropertyOArchive;
friend class PropertyIArchive;
};
inline unsigned int calculateHash(const char* str, unsigned hash = 5381)
{
while(*str)
hash = hash * 33 + (unsigned char)*str++;
return hash;
}
template<class T>
inline unsigned int calculateHash(const T& t, unsigned hash = 5381)
{
for (int i = 0; i < sizeof(T); i++)
hash = hash * 33 + ((unsigned char*)&t)[i];
return hash;
}
struct RowWidthCache
{
unsigned int valueHash;
int width;
RowWidthCache() : valueHash(0), width(-1) {}
int getOrUpdate(const QPropertyTree* tree, const PropertyRow* rowForValue, int extraSpace);
};
typedef vector<Serialization::SharedPtr<PropertyRow> > PropertyRows;
template<bool value>
struct StaticBool{
enum { Value = value };
};
struct LessStrCmp
{
bool operator()(const char* a, const char* b) const {
return strcmp(a, b) < 0;
}
};
typedef Factory<const char*, PropertyRow, LessStrCmp> PropertyRowFactory;
template<class Op>
bool PropertyRow::scanChildren(Op& op)
{
Rows::iterator it;
for(it = children_.begin(); it != children_.end(); ++it){
ScanResult result = op(*it);
if(result == SCAN_FINISHED)
return false;
if(result == SCAN_CHILDREN || result == SCAN_CHILDREN_SIBLINGS){
if(!(*it)->scanChildren(op))
return false;
if(result == SCAN_CHILDREN)
return false;
}
}
return true;
}
template<class Op>
bool PropertyRow::scanChildren(Op& op, QPropertyTree* tree)
{
int numChildren = int(children_.size());
for(int index = 0; index < numChildren; ++index){
PropertyRow* child = children_[index];
ScanResult result = op(child, tree, index);
if(result == SCAN_FINISHED)
return false;
if(result == SCAN_CHILDREN || result == SCAN_CHILDREN_SIBLINGS){
if(!child->scanChildren(op, tree))
return false;
if(result == SCAN_CHILDREN)
return false;
}
}
return true;
}
template<class Op>
bool PropertyRow::scanChildrenReverse(Op& op, QPropertyTree* tree)
{
int numChildren = (int)children_.size();
for(int index = numChildren - 1; index >= 0; --index){
PropertyRow* child = children_[index];
ScanResult result = op(child, tree, index);
if(result == SCAN_FINISHED)
return false;
if(result == SCAN_CHILDREN || result == SCAN_CHILDREN_SIBLINGS){
if(!child->scanChildrenReverse(op, tree))
return false;
if(result == SCAN_CHILDREN)
return false;
}
}
return true;
}
template<class Op>
bool PropertyRow::scanChildrenBottomUp(Op& op, QPropertyTree* tree)
{
size_t numChildren = children_.size();
for(size_t i = 0; i < numChildren; ++i)
{
PropertyRow* child = children_[i];
if(!child->scanChildrenBottomUp(op, tree))
return false;
ScanResult result = op(child, tree);
if(result == SCAN_FINISHED)
return false;
}
return true;
}
EDITOR_COMMON_API PropertyRowFactory& GlobalPropertyRowFactory();
EDITOR_COMMON_API Serialization::ClassFactory<PropertyRow>& GlobalPropertyRowClassFactory();
struct PropertyRowPtrSerializer : Serialization::SharedPtrSerializer<PropertyRow>
{
PropertyRowPtrSerializer(Serialization::SharedPtr<PropertyRow>& ptr) : SharedPtrSerializer(ptr) {}
Serialization::ClassFactory<PropertyRow>* factory() const override { return &GlobalPropertyRowClassFactory(); }
};
inline bool Serialize(Serialization::IArchive& ar, Serialization::SharedPtr<PropertyRow>& ptr, const char* name, const char* label)
{
PropertyRowPtrSerializer serializer(ptr);
return ar(static_cast<Serialization::IPointer&>(serializer), name, label);
}
#define REGISTER_PROPERTY_ROW(DataType, RowType) \
PropertyRow* _Factory_For_##RowType() {return new RowType; }; \
REGISTER_IN_FACTORY(PropertyRowFactory, Serialization::TypeID::get<DataType>().name(), RowType, _Factory_For_##RowType); \
SERIALIZATION_CLASS_NAME_FOR_FACTORY(GlobalPropertyRowClassFactory(), PropertyRow, RowType, #DataType, #DataType);
// Exposes the necessary class factories to extend the property tree
// Exposes the necessary class factories to extend the property tree
EDITOR_COMMON_API Serialization::ClassFactory<PropertyRow>& GetPropertyRowClassFactory();
EDITOR_COMMON_API PropertyRowFactory& GetPropertyRowFactory();
@@ -0,0 +1,168 @@
/*
* 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.
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "platform.h"
#include <QIcon>
#include "Serialization/ClassFactory.h"
#include "PropertyDrawContext.h"
#include "PropertyRowImpl.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "Serialization.h"
#include "Color.h"
#include "Unicode.h"
#include "Serialization/Decorators/ActionButton.h"
using Serialization::IActionButton;
using Serialization::IActionButtonPtr;
class PropertyRowActionButton
: public PropertyRow
{
public:
PropertyRowActionButton()
: underMouse_()
, pressed_()
, minimalWidth_() {}
bool isLeaf() const override { return true; }
bool isStatic() const override { return false; }
bool isSelectable() const override { return true; }
bool onActivate(const PropertyActivationEvent& e) override
{
if (e.reason == PropertyActivationEvent::REASON_KEYBOARD)
{
if (value_)
{
value_->Callback();
}
}
return true;
}
bool onMouseDown(QPropertyTree* tree, QPoint point, [[maybe_unused]] bool& changed) override
{
if (userReadOnly())
{
return false;
}
if (widgetRect(tree).contains(point))
{
underMouse_ = true;
pressed_ = true;
tree->update();
return true;
}
return false;
}
void onMouseDrag(const PropertyDragEvent& e) override
{
if (userReadOnly())
{
return;
}
bool underMouse = widgetRect(e.tree).contains(e.pos);
if (underMouse != underMouse_)
{
underMouse_ = underMouse;
e.tree->update();
}
}
void onMouseUp(QPropertyTree* tree, QPoint point) override
{
if (userReadOnly())
{
return;
}
if (widgetRect(tree).contains(point))
{
pressed_ = false;
if (value_)
{
value_->Callback();
}
tree->update();
}
}
void setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) override
{
value_ = static_cast<IActionButton*>(ser.pointer())->Clone();
const char* icon = value_->Icon();
icon_ = icon && icon[0] ? QIcon() : QIcon(QString::fromLocal8Bit(icon));
}
bool assignTo([[maybe_unused]] const Serialization::SStruct& ser) const override { return true; }
wstring valueAsWString() const override { return L""; }
WidgetPlacement widgetPlacement() const override { return WIDGET_INSTEAD_OF_TEXT; }
void serializeValue([[maybe_unused]] Serialization::IArchive& ar) override { }
int widgetSizeMin(const QPropertyTree* tree) const override
{
if (minimalWidth_ == 0)
{
QFontMetrics fm(tree->font());
minimalWidth_ = (int)fm.horizontalAdvance(QString::fromLocal8Bit(labelUndecorated())) + 6 + (icon_.isNull() ? 0 : 18);
}
return minimalWidth_;
}
void redraw(const PropertyDrawContext& context)
{
QRect rect = context.widgetRect.adjusted(-1, -1, 1, 1);
bool pressed = pressed_ && underMouse_;
wstring text = toWideChar(labelUndecorated());
if (icon_.isNull())
{
int buttonFlags = BUTTON_CENTER;
if (pressed)
{
buttonFlags |= BUTTON_PRESSED;
}
if (selected())
{
buttonFlags |= BUTTON_FOCUSED;
}
if (userReadOnly())
{
buttonFlags |= BUTTON_DISABLED;
}
context.drawButton(rect, text.c_str(), buttonFlags, &context.tree->font());
}
else
{
context.drawButtonWithIcon(icon_, rect, text.c_str(), selected(), pressed, selected(), !userReadOnly(), true, &context.tree->font());
}
}
bool isFullRow(const QPropertyTree* tree) const override
{
if (PropertyRow::isFullRow(tree))
{
return true;
}
return !userFixedWidget();
}
protected:
mutable int minimalWidth_;
bool underMouse_;
bool pressed_;
QIcon icon_;
IActionButtonPtr value_;
};
REGISTER_PROPERTY_ROW(IActionButton, PropertyRowActionButton);
@@ -0,0 +1,116 @@
/*
* 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.
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "PropertyRowBool.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "PropertyDrawContext.h"
#include "Serialization/ClassFactory.h"
#include "Serialization.h"
#include <QKeyEvent>
SERIALIZATION_CLASS_NAME(PropertyRow, PropertyRowBool, "PropertyRowBool", "bool");
PropertyRowBool::PropertyRowBool()
: value_(false)
{
}
bool PropertyRowBool::assignToPrimitive(void* object, [[maybe_unused]] size_t size) const
{
YASLI_ASSERT(size == sizeof(bool));
*reinterpret_cast<bool*>(object) = value_;
return true;
}
bool PropertyRowBool::assignToByPointer(void* instance, const Serialization::TypeID& type) const
{
return assignToPrimitive(instance, type.sizeOf());
}
void PropertyRowBool::redraw(const PropertyDrawContext& context)
{
context.drawCheck(widgetRect(context.tree), userReadOnly(), multiValue() ? CHECK_IN_BETWEEN : (value_ ? CHECK_SET : CHECK_NOT_SET));
}
bool PropertyRowBool::processesKey(QPropertyTree* tree, const QKeyEvent* ev)
{
if (QKeySequence(ev->key()) == QKeySequence(Qt::Key_Space))
{
return true;
}
return PropertyRow::processesKey(tree, ev);
}
bool PropertyRowBool::onKeyDown(QPropertyTree* tree, const QKeyEvent* ev)
{
if (QKeySequence(ev->key()) == QKeySequence(Qt::Key_Space))
{
PropertyActivationEvent e;
e.tree = tree;
e.reason = e.REASON_KEYBOARD;
onActivate(e);
return true;
}
return PropertyRow::onKeyDown(tree, ev);
}
bool PropertyRowBool::onActivate(const PropertyActivationEvent& e)
{
if (e.reason != e.REASON_RELEASE)
{
if (!this->userReadOnly())
{
e.tree->model()->rowAboutToBeChanged(this);
value_ = !value_;
e.tree->model()->rowChanged(this);
return true;
}
}
return false;
}
DragCheckBegin PropertyRowBool::onMouseDragCheckBegin()
{
if (userReadOnly())
{
return DRAG_CHECK_IGNORE;
}
return value_ ? DRAG_CHECK_UNSET : DRAG_CHECK_SET;
}
bool PropertyRowBool::onMouseDragCheck(QPropertyTree* tree, bool value)
{
if (value_ != value)
{
tree->model()->rowAboutToBeChanged(this);
value_ = value;
tree->model()->rowChanged(this);
return true;
}
return false;
}
void PropertyRowBool::serializeValue(Serialization::IArchive& ar)
{
ar(value_, "value", "Value");
}
int PropertyRowBool::widgetSizeMin(const QPropertyTree* tree) const
{
return aznumeric_cast<int>(tree->_defaultRowHeight() * 0.9f);
}
@@ -0,0 +1,50 @@
/*
* 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.
// Modifications copyright Amazon.com, Inc. or its affiliates.
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWBOOL_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWBOOL_H
#pragma once
#include "PropertyRow.h"
#include "Unicode.h"
class PropertyRowBool
: public PropertyRow
{
public:
PropertyRowBool();
bool assignToPrimitive(void* val, size_t size) const override;
bool assignToByPointer(void* instance, const Serialization::TypeID& type) const;
void setValue(bool value, const void* handle, [[maybe_unused]] const Serialization::TypeID& typeId) { value_ = value; serializer_.setPointer((void*)handle); serializer_.setType(Serialization::TypeID::get<bool>()); }
void redraw(const PropertyDrawContext& context);
bool isLeaf() const{ return true; }
bool isStatic() const{ return false; }
bool onActivate(const PropertyActivationEvent& e);
DragCheckBegin onMouseDragCheckBegin() override;
bool onMouseDragCheck(QPropertyTree* tree, bool value) override;
wstring valueAsWString() const{ return value_ ? L"true" : L"false"; }
string valueAsString() const{ return value_ ? "true" : "false"; }
WidgetPlacement widgetPlacement() const{ return WIDGET_ICON; }
void serializeValue(Serialization::IArchive& ar);
int widgetSizeMin(const QPropertyTree* tree) const override;
bool processesKey(QPropertyTree* tree, const QKeyEvent* ev) override;
bool onKeyDown(QPropertyTree* tree, const QKeyEvent* ev) override;
protected:
bool value_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWBOOL_H
@@ -0,0 +1,241 @@
/*
* 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.
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "PropertyRowColor.h"
#include "Serialization/ClassFactory.h"
#include <Cry_Color.h>
#include <QMenu>
#include <QFileDialog>
#include <QPainter>
#include <AzQtComponents/Components/Widgets/ColorPicker.h>
#include <AzQtComponents/Utilities/Conversions.h>
using Serialization::Vec3AsColor;
typedef SerializableColor_tpl<unsigned char> SerializableColorB;
typedef SerializableColor_tpl<float> SerializableColorF;
QColor ToQColor(const ColorB& v)
{
return QColor(v.r, v.g, v.b, v.a);
}
void FromQColor(SerializableColorB& vColor, QColor color)
{
vColor.r = color.red();
vColor.g = color.green();
vColor.b = color.blue();
vColor.a = color.alpha();
}
QColor ToQColor(const Vec3AsColor& v)
{
return QColor(int(v.v.x * 255.0f), int(v.v.y * 255.0f), int(v.v.z * 255.0f));
}
void FromQColor(Vec3AsColor& vColor, QColor color)
{
vColor.v.x = color.red() / 255.0f;
vColor.v.y = color.green() / 255.0f;
vColor.v.z = color.blue() / 255.0f;
}
QColor ToQColor(const SerializableColorF& v)
{
return QColor::fromRgbF(v.r, v.g, v.b, v.a);
}
void FromQColor(SerializableColorF& vColor, QColor color)
{
vColor.r = aznumeric_cast<float>(color.redF());
vColor.g = aznumeric_cast<float>(color.greenF());
vColor.b = aznumeric_cast<float>(color.blueF());
vColor.a = aznumeric_cast<float>(color.alphaF());
}
template <class ColorClass>
bool PropertyRowColor<ColorClass>::pickColor(QPropertyTree* tree)
{
const AZ::Color initialColor = AzQtComponents::fromQColor(color_);
const AZ::Color color = AzQtComponents::ColorPicker::getColor(AzQtComponents::ColorPicker::Configuration::RGB, initialColor, QObject::tr("Select Color"));
if (color != initialColor)
{
tree->model()->rowAboutToBeChanged(this);
color_.setRed(color.GetR8());
color_.setGreen(color.GetG8());
color_.setBlue(color.GetB8());
colorChanged_ = true;
tree->model()->rowChanged(this);
return true;
}
return false;
}
template <class ColorClass>
bool PropertyRowColor<ColorClass>::onActivate(const PropertyActivationEvent& e)
{
return pickColor(e.tree);
}
template <class ColorClass>
void PropertyRowColor<ColorClass>::setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] IArchive& ar)
{
color_ = ToQColor(*(ColorClass*)ser.pointer());
colorChanged_ = false;
}
template <class ColorClass>
bool PropertyRowColor<ColorClass>::assignTo(const Serialization::SStruct& ser) const
{
FromQColor(*((ColorClass*)ser.pointer()), color_);
return true;
}
template<class ColorClass>
string PropertyRowColor<ColorClass>::valueAsString() const
{
char buf[64];
sprintf_s(buf, "%d %d %d", (int)color_.red(), (int)color_.green(), (int)color_.blue());
return string(buf);
}
template <class ColorClass>
bool PropertyRowColor<ColorClass>::onContextMenu(QMenu& menu, QPropertyTree* tree)
{
Serialization::SharedPtr<PropertyRowColor> selfPointer(this);
ColorMenuHandler* handler = new ColorMenuHandler(tree, this);
menu.addAction("Pick Color", handler, SLOT(onMenuPickColor()));
tree->addMenuHandler(handler);
return true;
}
template <class ColorClass>
void PropertyRowColor<ColorClass>::redraw(const PropertyDrawContext& context)
{
static QImage checkboardPattern;
if (checkboardPattern.isNull())
{
int size = 12;
static vector<int> pixels(size * size);
for (int i = 0; i < pixels.size(); ++i)
{
pixels[i] = ((i / size) / (size / 2) + (i % size) / (size / 2)) % 2 ? 0xffffffff : 0x000000ff;
}
checkboardPattern = QImage((unsigned char*)pixels.data(), size, size, size * 4, QImage::Format_RGBA8888);
}
QRect r = context.widgetRect.adjusted(0, 0, 0, -1);
context.painter->save();
context.painter->setPen(QPen(Qt::NoPen));
context.painter->setRenderHint(QPainter::Antialiasing, true);
context.painter->setBrush(context.tree->palette().color(QPalette::Dark));
context.painter->setPen(Qt::NoPen);
context.painter->drawRoundedRect(r, 2, 2);
r = r.adjusted(1, 1, -1, -1);
QRect cr = r.adjusted(0, 0, -r.width() / 2, 0);
context.painter->setBrushOrigin(cr.topRight() + QPoint(1, 0));
context.painter->setBrush(QBrush(checkboardPattern));
context.painter->setRenderHint(QPainter::Antialiasing, false);
context.painter->drawRoundedRect(r, 2, 2);
context.painter->setPen(QPen(Qt::NoPen));
context.painter->setClipRect(cr);
context.painter->setBrush(QBrush(color_));
context.painter->drawRoundedRect(r, 2, 2);
cr = r.adjusted(r.width() / 2, 0, 0, 0);
context.painter->setClipRect(cr);
context.painter->setBrush(QBrush(QColor(color_.red(), color_.green(), color_.blue(), 255)));
context.painter->drawRoundedRect(r, 2, 2);
context.painter->restore();
}
template <class ColorClass>
void PropertyRowColor<ColorClass>::closeNonLeaf(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar)
{
color_ = ToQColor(*(ColorClass*)ser.pointer());
}
static int componentFromRowValue(const char* str, ColorB*)
{
return clamp_tpl(atoi(str), 0, 255);
}
static int componentFromRowValue(const char* str, ColorF*)
{
return clamp_tpl(int(atof(str) * 255.0f + 0.5f), 0, 255);
}
static int componentFromRowValue(const char* str, Vec3AsColor*)
{
return clamp_tpl(int(atof(str) * 255.0f + 0.5f), 0, 255);
}
template<class ColorClass>
void PropertyRowColor<ColorClass>::handleChildrenChange()
{
// generally is not needed unless we are using callbacks
PropertyRow* rows[4] = {
childByIndex(0),
childByIndex(1),
childByIndex(2),
childByIndex(3)
};
if (rows[0])
{
color_.setRed(componentFromRowValue(rows[0]->valueAsString().c_str(), (ColorClass*)0));
}
if (rows[1])
{
color_.setGreen(componentFromRowValue(rows[1]->valueAsString().c_str(), (ColorClass*)0));
}
if (rows[2])
{
color_.setBlue(componentFromRowValue(rows[2]->valueAsString().c_str(), (ColorClass*)0));
}
if (rows[3])
{
color_.setAlpha(componentFromRowValue(rows[3]->valueAsString().c_str(), (ColorClass*)0));
}
}
ColorMenuHandler::ColorMenuHandler(QPropertyTree* tree, IPropertyRowColor* propertyRowColor)
: propertyRowColor(propertyRowColor)
, tree(tree)
{
}
void ColorMenuHandler::onMenuPickColor()
{
propertyRowColor->pickColor(tree);
}
typedef PropertyRowColor<SerializableColorB> PropertyRowColorB;
typedef PropertyRowColor<Vec3AsColor> PropertyRowVec3AsColor;
typedef PropertyRowColor<SerializableColorF> PropertyRowColorF;
REGISTER_PROPERTY_ROW(SerializableColorB, PropertyRowColorB);
REGISTER_PROPERTY_ROW(Vec3AsColor, PropertyRowVec3AsColor);
REGISTER_PROPERTY_ROW(SerializableColorF, PropertyRowColorF);
#include <QPropertyTree/moc_PropertyRowColor.cpp>
@@ -0,0 +1,75 @@
/*
* 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.
// Modifications copyright Amazon.com, Inc. or its affiliates.
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyDrawContext.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include <Serialization.h>
#endif
struct IPropertyRowColor
{
virtual bool pickColor(QPropertyTree* tree) = 0;
};
template <class ColorClass>
class PropertyRowColor
: public PropertyRow
, public IPropertyRowColor
{
public:
PropertyRowColor()
: colorChanged_(false) {}
bool isLeaf() const override { return colorChanged_; }
bool isStatic() const override { return false; }
WidgetPlacement widgetPlacement() const{ return WIDGET_AFTER_PULLED; }
int widgetSizeMin(const QPropertyTree* tree) const { return userWidgetSize() >= 0 ? userWidgetSize() : tree->_defaultRowHeight()* 2 - 4; }
void handleChildrenChange() override;
void setValueAndContext(const Serialization::SStruct& ser, Serialization::IArchive& ar) override;
bool assignTo(const Serialization::SStruct& ser) const override;
void closeNonLeaf(const Serialization::SStruct& ser, Serialization::IArchive& ar);
bool onActivate(const PropertyActivationEvent& ev) override;
string valueAsString() const;
void redraw(const PropertyDrawContext& context);
bool onContextMenu(QMenu& menu, QPropertyTree* tree);
bool pickColor(QPropertyTree* tree) override;
private:
QColor color_;
bool colorChanged_;
};
struct ColorMenuHandler
: PropertyRowMenuHandler
{
Q_OBJECT
public:
QPropertyTree * tree;
IPropertyRowColor* propertyRowColor;
ColorMenuHandler(QPropertyTree* tree, IPropertyRowColor* propertyRowColor);
~ColorMenuHandler(){};
public slots:
void onMenuPickColor();
};
@@ -0,0 +1,158 @@
/*
* 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.
*
*/
#include "EditorCommon_precompiled.h"
#include "PropertyRowColorPicker.h"
#include "Serialization/ClassFactory.h"
#include <IEditor.h>
#include <QMenu>
#include <QPainter>
#include <QIcon>
#include <QKeyEvent>
#include <AzQtComponents/Components/Widgets/ColorPicker.h>
#include <AzQtComponents/Utilities/Conversions.h>
bool PropertyRowColorPicker::onActivate(const PropertyActivationEvent& e)
{
if (e.reason == e.REASON_RELEASE)
{
return false;
}
// ColorF -> QColor.
AZ::Color initialColor;
initialColor.SetR(color_.r);
initialColor.SetG(color_.g);
initialColor.SetB(color_.b);
initialColor.SetA(color_.a);
const AZ::Color colorFromDialog = AzQtComponents::ColorPicker::getColor(AzQtComponents::ColorPicker::Configuration::RGBA,
initialColor,
QObject::tr("Select Color"));
if (initialColor == colorFromDialog)
{
// The user cancelled the dialog box.
// Nothing more to do.
return false;
}
// QColor -> ColorF.
ColorF color(colorFromDialog.GetR(),
colorFromDialog.GetG(),
colorFromDialog.GetB(),
colorFromDialog.GetA());
e.tree->model()->rowAboutToBeChanged(this);
color_ = color;
e.tree->model()->rowChanged(this);
return true;
}
void PropertyRowColorPicker::setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar)
{
ColorPicker* value = (ColorPicker*)ser.pointer();
color_ = *value->color;
}
bool PropertyRowColorPicker::assignTo(const Serialization::SStruct& ser) const
{
((ColorPicker*)ser.pointer())->SetColor(&color_);
return true;
}
void PropertyRowColorPicker::serializeValue(Serialization::IArchive& ar)
{
ar(color_, "color");
}
const QIcon& PropertyRowColorPicker::buttonIcon([[maybe_unused]] const QPropertyTree* tree, [[maybe_unused]] int index) const
{
// Color-chip.
QColor color((int)(color_.r * 255.0f),
(int)(color_.g * 255.0f),
(int)(color_.b * 255.0f));
QPen pen(color);
QBrush brush(color);
QPixmap pixmap(16, 16);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setBrush(brush);
painter.setPen(pen);
painter.drawEllipse(0, 0, 15, 15);
static QIcon icon;
icon.addPixmap(pixmap);
return icon;
}
string PropertyRowColorPicker::valueAsString() const
{
int r = (int)(255.0f * color_.r);
int g = (int)(255.0f * color_.g);
int b = (int)(255.0f * color_.b);
int a = (int)(255.0f * color_.a);
string value;
value.Format("#%02x%02x%02x%02x", r, g, b, a);
return value;
}
void PropertyRowColorPicker::clear()
{
color_ = Col_White;
}
bool PropertyRowColorPicker::onContextMenu(QMenu& menu, QPropertyTree* tree)
{
QAction* action = menu.addAction("Clear");
QObject::connect(action,
&QAction::triggered,
tree,
[ this, tree ]
{
tree->model()->rowAboutToBeChanged(this);
clear();
tree->model()->rowChanged(this);
});
return true;
}
bool PropertyRowColorPicker::processesKey(QPropertyTree* tree, const QKeyEvent* ev)
{
if (QKeySequence(ev->key()) == QKeySequence(Qt::Key_Delete))
{
return true;
}
return PropertyRowField::processesKey(tree, ev);
}
bool PropertyRowColorPicker::onKeyDown(QPropertyTree* tree, const QKeyEvent* ev)
{
if (ev->key() == Qt::Key_Delete)
{
tree->model()->rowAboutToBeChanged(this);
clear();
tree->model()->rowChanged(this);
return true;
}
return PropertyRowField::onKeyDown(tree, ev);
}
REGISTER_PROPERTY_ROW(ColorPicker, PropertyRowColorPicker);
DECLARE_SEGMENT(PropertyRowColorPicker)
@@ -0,0 +1,56 @@
/*
* 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.
*
*/
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWCOLORPICKER_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWCOLORPICKER_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyDrawContext.h"
#include "PropertyRowField.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "Serialization.h"
#include <Serialization/Decorators/ColorPicker.h>
#include <Serialization/Decorators/ColorPickerImpl.h>
#include <Serialization/Decorators/IconXPM.h>
#endif
using Serialization::ColorPicker;
class PropertyRowColorPicker
: public PropertyRowField
{
public:
void clear();
bool isLeaf() const override { return true; }
bool isStatic() const override { return false; }
void setValueAndContext(const Serialization::SStruct& ser, Serialization::IArchive& ar) override;
bool assignTo(const Serialization::SStruct& ser) const override;
bool onActivate(const PropertyActivationEvent& e) override;
int buttonCount() const override { return 1; }
virtual const QIcon& buttonIcon(const QPropertyTree* tree, int index) const override;
string valueAsString() const override;
void serializeValue(Serialization::IArchive& ar);
bool onContextMenu(QMenu& menu, QPropertyTree* tree);
bool processesKey(QPropertyTree* tree, const QKeyEvent* ev) override;
bool onKeyDown(QPropertyTree* tree, const QKeyEvent* ev) override;
private:
ColorF color_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWCOLORPICKER_H
@@ -0,0 +1,439 @@
/*
* 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>
@@ -0,0 +1,96 @@
/*
* 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_PROPERTYROWCONTAINER_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWCONTAINER_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyRow.h"
#endif
class EDITOR_COMMON_API PropertyRowContainer;
struct EDITOR_COMMON_API ContainerMenuHandler
: PropertyRowMenuHandler
{
Q_OBJECT
public:
QPropertyTree * tree;
PropertyRowContainer* container;
PropertyRow* element;
int pointerIndex;
ContainerMenuHandler(QPropertyTree* tree, PropertyRowContainer* container);
public slots:
virtual void onMenuAddElement();
virtual void onMenuAppendElement();
virtual void onMenuAppendPointerByIndex();
virtual void onMenuRemoveAll();
virtual void onMenuChildInsertBefore();
virtual void onMenuChildRemove();
};
class EDITOR_COMMON_API PropertyRowContainer
: public PropertyRow
{
public:
PropertyRowContainer();
bool isContainer() const{ return true; }
bool onActivate(const PropertyActivationEvent& e);
bool onContextMenu(QMenu& item, QPropertyTree* tree);
virtual ContainerMenuHandler* createMenuHandler(QPropertyTree* tree, PropertyRowContainer* container) override;
void redraw(const PropertyDrawContext& context);
bool processesKeyContainer(QPropertyTree* tree, const QKeyEvent* ev);
bool processesKey(QPropertyTree* tree, const QKeyEvent* ev) override;
bool onKeyDownContainer(QPropertyTree* tree, const QKeyEvent* key);
bool onKeyDown(QPropertyTree* tree, const QKeyEvent* key) override;
void labelChanged() override;
bool isStatic() const{ return false; }
bool isSelectable() const{ return userWidgetSize() == 0 ? false : true; }
PropertyRow* addElement(QPropertyTree* tree, bool append);
void setInlined(bool inlined) { inlined_ = inlined; }
bool isInlined() const{ return inlined_; }
PropertyRow* defaultRow(PropertyTreeModel* model);
const PropertyRow* defaultRow(const PropertyTreeModel* model) const;
void serializeValue(Serialization::IArchive& ar);
const char* elementTypeName() const{ return elementTypeName_; }
using PropertyRow::setValueAndContext;
virtual void setValueAndContext(const Serialization::IContainer& value, [[maybe_unused]] Serialization::IArchive& ar)
{
fixedSize_ = value.isFixedSize();
elementTypeName_ = value.elementType().name();
serializer_.setPointer(value.pointer());
serializer_.setType(value.containerType());
}
const char* typeNameForFilter(QPropertyTree* tree) const override;
string valueAsString() const;
// C-array is an example of fixed size container
bool isFixedSize() const{ return fixedSize_; }
WidgetPlacement widgetPlacement() const override { return inlined_ ? WIDGET_NONE : WIDGET_AFTER_NAME; }
int widgetSizeMin(const QPropertyTree* tree) const override;
protected:
virtual void generateMenu(QMenu& menu, QPropertyTree* tree, bool addActions);
const char* elementTypeName_;
wchar_t buttonLabel_[8];
bool fixedSize_;
bool inlined_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWCONTAINER_H
@@ -0,0 +1,84 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "PropertyRowField.h"
#include "PropertyDrawContext.h"
#include "QPropertyTree.h"
#include "QPropertyTreeStyle.h"
#include <QtGui/QIcon>
enum { BUTTON_SIZE = 16 };
QRect PropertyRowField::fieldRect(const QPropertyTree* tree) const
{
QRect fieldRect = widgetRect(tree);
fieldRect.setRight(fieldRect.right() - buttonCount() * BUTTON_SIZE);
return fieldRect;
}
bool PropertyRowField::onActivate(const PropertyActivationEvent& e)
{
if (e.reason == e.REASON_PRESS) {
int buttonCount = this->buttonCount();
QRect buttonsRect = widgetRect(e.tree);
buttonsRect.setLeft(buttonsRect.right() - buttonCount * BUTTON_SIZE);
if (buttonsRect.contains(e.clickPoint)) {
int buttonIndex = buttonCount - (e.clickPoint.x() - buttonsRect.x()) / BUTTON_SIZE - 1;
if (buttonIndex >= 0 && buttonIndex < buttonCount)
{
if (onActivateButton(buttonIndex, e))
return true;
}
}
}
return PropertyRow::onActivate(e);
}
void PropertyRowField::redraw(const PropertyDrawContext& context)
{
int buttonCount = this->buttonCount();
int offset = 0;
for (int i = 0; i < buttonCount; ++i) {
const QIcon& icon = buttonIcon(context.tree, i);
QRect iconRect(context.widgetRect.right() - offset - BUTTON_SIZE, context.widgetRect.top(), BUTTON_SIZE, context.widgetRect.height());
icon.paint(context.painter, iconRect, Qt::AlignCenter, userReadOnly() ? QIcon::Disabled : QIcon::Normal);
offset += BUTTON_SIZE;
}
int iconSpace = offset ? offset + 2 : 0;
if(multiValue())
context.drawEntry(L" ... ", false, true, iconSpace);
else if(userReadOnly())
context.drawValueText(pulledSelected(), valueAsWString().c_str());
else
context.drawEntry(valueAsWString().c_str(), usePathEllipsis(), false, iconSpace);
}
const QIcon& PropertyRowField::buttonIcon([[maybe_unused]] const QPropertyTree* tree, [[maybe_unused]] int index) const
{
static QIcon defaultIcon;
return defaultIcon;
}
int PropertyRowField::widgetSizeMin(const QPropertyTree* tree) const
{
if (userWidgetSize() >= 0)
return userWidgetSize();
if (userWidgetToContent_)
return widthCache_.getOrUpdate(tree, this, 0);
else
return 40;
}
@@ -0,0 +1,39 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWFIELD_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWFIELD_H
#pragma once
#include "PropertyRow.h"
class QIcon;
class PropertyRowField : public PropertyRow
{
public:
WidgetPlacement widgetPlacement() const override{ return WIDGET_VALUE; }
int widgetSizeMin(const QPropertyTree* tree) const override;
virtual int buttonCount() const{ return 0; }
virtual const QIcon& buttonIcon(const QPropertyTree* tree, int index) const;
virtual bool usePathEllipsis() const { return false; }
virtual bool onActivateButton([[maybe_unused]] int buttonIndex, [[maybe_unused]] const PropertyActivationEvent& e) { return false; }
void redraw(const PropertyDrawContext& context) override;
bool onActivate(const PropertyActivationEvent& e) override;
protected:
QRect fieldRect(const QPropertyTree* tree) const;
void drawButtons(int* offset);
mutable RowWidthCache widthCache_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWFIELD_H
@@ -0,0 +1,119 @@
/**
* yasli - Serialization Library.
* Copyright (C) 2007-2013 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "Serialization/ClassFactory.h"
#include "PropertyDrawContext.h"
#include "PropertyRowImpl.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "Serialization.h"
#include "Color.h"
#include "Serialization/Decorators/IconXPM.h"
using Serialization::IconXPM;
using Serialization::IconXPMToggle;
class PropertyRowIconXPM : public PropertyRow{
public:
void redraw(const PropertyDrawContext& context)
{
QRect rect = context.widgetRect;
context.drawIcon(rect, icon_);
}
bool isLeaf() const{ return true; }
bool isStatic() const{ return false; }
bool isSelectable() const{ return false; }
bool onActivate([[maybe_unused]] const PropertyActivationEvent& e)
{
return false;
}
void setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) override {
YASLI_ESCAPE(ser.size() == sizeof(IconXPM), return);
icon_ = *(IconXPM*)(ser.pointer());
}
wstring valueAsWString() const{ return L""; }
WidgetPlacement widgetPlacement() const{ return WIDGET_ICON; }
void serializeValue([[maybe_unused]] Serialization::IArchive& ar) {}
int widgetSizeMin(const QPropertyTree* tree) const override{ return tree->_defaultRowHeight(); }
int height() const{ return 16; }
protected:
IconXPM icon_;
};
class PropertyRowIconToggle : public PropertyRow{
public:
void redraw(const PropertyDrawContext& context) override
{
IconXPM& icon = value_ ? iconTrue_ : iconFalse_;
context.drawIcon(context.widgetRect, icon);
}
void setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) override {
YASLI_ESCAPE(ser.size() == sizeof(IconXPMToggle), return);
const IconXPMToggle* icon = (IconXPMToggle*)(ser.pointer());
iconTrue_ = icon->iconTrue_;
iconFalse_ = icon->iconFalse_;
value_ = icon->value_;
}
bool assignTo(const Serialization::SStruct& ser) const override
{
IconXPMToggle* toggle = (IconXPMToggle*)ser.pointer();
toggle->value_ = value_;
return true;
}
bool isLeaf() const override{ return true; }
bool isStatic() const override{ return false; }
bool isSelectable() const override{ return true; }
bool onActivate(const PropertyActivationEvent& e)
{
if (e.reason != e.REASON_RELEASE)
{
e.tree->model()->rowAboutToBeChanged(this);
value_ = !value_;
e.tree->model()->rowChanged(this);
return true;
}
return false;
}
DragCheckBegin onMouseDragCheckBegin() override
{
if (userReadOnly())
return DRAG_CHECK_IGNORE;
return value_ ? DRAG_CHECK_UNSET : DRAG_CHECK_SET;
}
bool onMouseDragCheck(QPropertyTree* tree, bool value) override
{
if (value_ != value) {
tree->model()->rowAboutToBeChanged(this);
value_ = value;
tree->model()->rowChanged(this);
return true;
}
return false;
}
wstring valueAsWString() const{ return value_ ? L"true" : L"false"; }
WidgetPlacement widgetPlacement() const{ return WIDGET_ICON; }
int widgetSizeMin(const QPropertyTree* tree) const{ return tree->_defaultRowHeight(); }
int height() const{ return 16; }
IconXPM iconTrue_;
IconXPM iconFalse_;
bool value_;
};
REGISTER_PROPERTY_ROW(IconXPM, PropertyRowIconXPM);
REGISTER_PROPERTY_ROW(IconXPMToggle, PropertyRowIconToggle);
DECLARE_SEGMENT(PropertyRowIconXPM)
@@ -0,0 +1,48 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWIMPL_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWIMPL_H
#pragma once
#include "Serialization/STL.h"
#include "PropertyRowField.h"
#include "Serialization.h"
template<class Type>
class PropertyRowImpl;
template<class Type>
class PropertyRowImpl : public PropertyRowField{
public:
bool assignTo(const Serialization::SStruct& ser) const override {
*reinterpret_cast<Type*>(ser.pointer()) = value();
return true;
}
bool isLeaf() const override{ return true; }
bool isStatic() const override{ return false; }
void setValue(const Type& value) { value_ = value; }
Type& value() { return value_; }
const Type& value() const{ return value_; }
void setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) override {
YASLI_ESCAPE(ser.size() == sizeof(Type), return);
value_ = *(Type*)(ser.pointer());
}
void serializeValue(Serialization::IArchive& ar) override{
ar(value_, "value", "Value");
}
protected:
Type value_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWIMPL_H
@@ -0,0 +1,152 @@
/*
* 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 "PropertyRowLocalFrame.h"
#include <QIcon>
#include <QAction>
#include <QMenu>
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include <Serialization/Decorators/IGizmoSink.h>
#include <Serialization/Decorators/LocalFrame.h>
#include "Serialization/ClassFactory.h"
#include "PropertyDrawContext.h"
#include "Serialization.h"
#include <Serialization/Decorators/LocalFrameImpl.h>
using Serialization::LocalPosition;
void LocalFrameMenuHandler::onMenuReset()
{
self->reset(tree);
}
PropertyRowLocalFrameBase::PropertyRowLocalFrameBase()
: m_sink(0)
, m_gizmoIndex(-1)
, m_handle(0)
, m_reset(false)
{
}
PropertyRowLocalFrameBase::~PropertyRowLocalFrameBase()
{
m_sink = 0;
}
bool PropertyRowLocalFrameBase::onActivate(const PropertyActivationEvent& e)
{
if (e.reason == e.REASON_RELEASE)
{
return false;
}
return false;
}
string PropertyRowLocalFrameBase::valueAsString() const
{
return string();
}
bool PropertyRowLocalFrameBase::onContextMenu(QMenu& menu, QPropertyTree* tree)
{
Serialization::SharedPtr<PropertyRow> selfPointer(this);
LocalFrameMenuHandler* handler = new LocalFrameMenuHandler(tree, this);
QAction* action = menu.addAction("Reset", handler, SLOT(onMenuReset()));
tree->addMenuHandler(handler);
return true;
}
void PropertyRowLocalFrameBase::reset(QPropertyTree* tree)
{
tree->model()->rowAboutToBeChanged(this);
m_reset = true;
tree->model()->rowChanged(this);
}
void PropertyRowLocalFrameBase::redraw(const PropertyDrawContext& context)
{
static QIcon gizmo("Editor/Icons/animation/gizmo_location.png");
gizmo.paint(context.painter, context.widgetRect.adjusted(1, 1, 1, 1), Qt::AlignRight);
}
static void ResetTransform(Serialization::LocalPosition* l) { *l->value = ZERO; }
static void ResetTransform(Serialization::LocalOrientation* l) { *l->value = IDENTITY; }
static void ResetTransform(Serialization::LocalFrame* l) { *l->position = ZERO; *l->rotation = IDENTITY; }
template<class TLocal>
class PropertyRowLocalFrameImpl
: public PropertyRowLocalFrameBase
{
public:
void setValueAndContext(const Serialization::SStruct& ser, Serialization::IArchive& ar) override
{
serializer_ = ser;
TLocal* value = (TLocal*)ser.pointer();
m_handle = value->handle;
m_reset = false;
if (label() && label()[0])
{
m_sink = ar.FindContext<Serialization::IGizmoSink>();
if (m_sink)
{
m_gizmoIndex = m_sink->Write(*value, m_gizmoFlags, m_handle);
}
}
}
void closeNonLeaf(const Serialization::SStruct& ser, Serialization::IArchive& ar) override
{
if (label() && label()[0] && ar.IsInput())
{
TLocal& value = *((TLocal*)ser.pointer());
if (m_sink)
{
if (m_sink->CurrentGizmoIndex() == m_gizmoIndex)
{
m_sink->Read(&value, &m_gizmoFlags, m_handle);
}
else
{
m_sink->SkipRead();
}
}
}
}
bool assignTo(const Serialization::SStruct& ser) const
{
if (m_reset)
{
TLocal& value = *((TLocal*)ser.pointer());
ResetTransform(&value);
}
return false;
}
};
typedef PropertyRowLocalFrameImpl<Serialization::LocalPosition> PropertyRowLocalPosition;
typedef PropertyRowLocalFrameImpl<Serialization::LocalOrientation> PropertyRowLocalOrientation;
typedef PropertyRowLocalFrameImpl<Serialization::LocalFrame> PropertyRowLocalFrame;
REGISTER_PROPERTY_ROW(Serialization::LocalPosition, PropertyRowLocalPosition);
REGISTER_PROPERTY_ROW(Serialization::LocalOrientation, PropertyRowLocalOrientation);
REGISTER_PROPERTY_ROW(Serialization::LocalFrame, PropertyRowLocalFrame);
#include <QPropertyTree/moc_PropertyRowLocalFrame.cpp>
@@ -0,0 +1,70 @@
/*
* 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_PROPERTYROWLOCALFRAME_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWLOCALFRAME_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "Serialization/Decorators/IGizmoSink.h"
#include "PropertyRowField.h"
#include "QPropertyTree.h"
#endif
struct IGizmoSink;
class PropertyRowLocalFrameBase
: public PropertyRow
{
public:
PropertyRowLocalFrameBase();
~PropertyRowLocalFrameBase();
bool isLeaf() const override { return m_reset; }
bool isStatic() const override { return false; }
bool onActivate(const PropertyActivationEvent& e) override;
WidgetPlacement widgetPlacement() const override { return WIDGET_AFTER_PULLED; }
int widgetSizeMin(const QPropertyTree* tree) const override { return tree->_defaultRowHeight(); }
string valueAsString() const override;
bool onContextMenu(QMenu& menu, QPropertyTree* tree) override;
const void* searchHandle() const override { return m_handle; }
void redraw(const PropertyDrawContext& context) override;
void reset(QPropertyTree* tree);
protected:
Serialization::IGizmoSink* m_sink;
const void* m_handle;
int m_gizmoIndex;
mutable Serialization::GizmoFlags m_gizmoFlags;
bool m_reset;
};
struct LocalFrameMenuHandler
: PropertyRowMenuHandler
{
Q_OBJECT
public:
QPropertyTree * tree;
PropertyRowLocalFrameBase* self;
LocalFrameMenuHandler(QPropertyTree* tree, PropertyRowLocalFrameBase* self)
: tree(tree)
, self(self) {}
public slots:
void onMenuReset();
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWLOCALFRAME_H
@@ -0,0 +1,43 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "Serialization.h"
#include "PropertyRowNumber.h"
#define REGISTER_NUMBER_ROW(TypeName, postfix) \
typedef PropertyRowNumber<TypeName> PropertyRow##postfix; \
typedef Serialization::RangeDecorator<TypeName> RangeDecorator##postfix; \
PropertyRow* TypeName##postfixFactory() { return new PropertyRow##postfix; }; \
REGISTER_IN_FACTORY(PropertyRowFactory, Serialization::TypeID::get<RangeDecorator##postfix>().name(), PropertyRow##postfix, TypeName##postfixFactory); \
SERIALIZATION_CLASS_NAME(PropertyRow, PropertyRow##postfix, "PropertyRow" #postfix, #TypeName);
REGISTER_NUMBER_ROW(float, Float)
REGISTER_NUMBER_ROW(double , Double)
REGISTER_NUMBER_ROW(char, Char)
REGISTER_NUMBER_ROW(int8, Int8)
REGISTER_NUMBER_ROW(uint8, Uint8)
REGISTER_NUMBER_ROW(int16, Int16)
REGISTER_NUMBER_ROW(int32, Int32)
REGISTER_NUMBER_ROW(int64, Int64)
REGISTER_NUMBER_ROW(uint16, Uint16)
REGISTER_NUMBER_ROW(uint32, Uint32)
REGISTER_NUMBER_ROW(uint64, Uint64)
#undef REGISTER_NUMBER_ROW
DECLARE_SEGMENT(PropertyRowNumber)
// ---------------------------------------------------------------------------
@@ -0,0 +1,237 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWNUMBER_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWNUMBER_H
#pragma once
#include "QPropertyTree.h"
#include "Serialization/MemoryWriter.h"
#include "Serialization/Decorators/Range.h"
#include "PropertyRowNumberField.h"
#include <limits.h>
#include <float.h>
#include <math.h>
template<class T>
string numberAsString(T value)
{
Serialization::MemoryWriter buf;
buf << value;
return buf.c_str();
}
inline long long stringToSignedInteger(const char* str)
{
long long value;
#ifdef _MSC_VER
value = _atoi64(str);
#else
char* endptr = (char*)str;
value = strtoll(str, &endptr, 10);
#endif
return value;
}
inline unsigned long long stringToUnsignedInteger(const char* str)
{
unsigned long long value;
if (*str == '-') {
value = 0;
}
else {
#ifdef _MSC_VER
char* endptr = (char*)str;
value = _strtoui64(str, &endptr, 10);
#else
char* endptr = (char*)str;
value = strtoull(str, &endptr, 10);
#endif
}
return value;
}
template<class Output, class Input>
Output clamp(Input value, Output min, Output max)
{
if (value < Input(min))
return min;
if (value > Input(max))
return max;
return Output(value);
}
template<class Out, class In> void clampToType(Out* out, In value) { *out = clamp(value, std::numeric_limits<Out>::lowest(), std::numeric_limits<Out>::max()); }
inline void clampedNumberFromString(char* value, const char* str) { clampToType(value, stringToSignedInteger(str)); }
inline void clampedNumberFromString(signed char* value, const char* str) { clampToType(value, stringToSignedInteger(str)); }
inline void clampedNumberFromString(short* value, const char* str) { clampToType(value, stringToSignedInteger(str)); }
inline void clampedNumberFromString(int* value, const char* str) { clampToType(value, stringToSignedInteger(str)); }
inline void clampedNumberFromString(long* value, const char* str) { clampToType(value, stringToSignedInteger(str)); }
inline void clampedNumberFromString(long long* value, const char* str) { clampToType(value, stringToSignedInteger(str)); }
inline void clampedNumberFromString(unsigned char* value, const char* str) { clampToType(value, stringToUnsignedInteger(str)); }
inline void clampedNumberFromString(unsigned short* value, const char* str) { clampToType(value, stringToUnsignedInteger(str)); }
inline void clampedNumberFromString(unsigned int* value, const char* str) { clampToType(value, stringToUnsignedInteger(str)); }
inline void clampedNumberFromString(unsigned long* value, const char* str) { clampToType(value, stringToUnsignedInteger(str)); }
inline void clampedNumberFromString(unsigned long long* value, const char* str) { clampToType(value, stringToUnsignedInteger(str)); }
inline void clampedNumberFromString(float* value, const char* str)
{
double v = atof(str);
if (v > FLT_MAX)
v = FLT_MAX;
if (v < -FLT_MAX)
v = -FLT_MAX;
*value = float(v);
}
inline void clampedNumberFromString(double* value, const char* str)
{
*value = atof(str);
}
template<class Type>
class PropertyRowNumber : public PropertyRowNumberField{
public:
PropertyRowNumber()
{
softMin_ = std::numeric_limits<Type>::lowest();
softMax_ = std::numeric_limits<Type>::max();
hardMin_ = std::numeric_limits<Type>::lowest();
hardMax_ = std::numeric_limits<Type>::max();
}
void setValue(Type value, const void* handle, const Serialization::TypeID& type)
{
value_ = value;
serializer_.setPointer((void*)handle);
serializer_.setType(type);
}
bool setValueFromString(const char* str) override{
Type value = value_;
clampedNumberFromString(&value_, str);
return value_ != value;
}
string valueAsString() const override
{
return numberAsString(Type(value_));
}
bool assignToPrimitive(void* object, [[maybe_unused]] size_t size) const override
{
*reinterpret_cast<Type*>(object) = value_;
return true;
}
void setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) override
{
Serialization::RangeDecorator<Type>* range = (Serialization::RangeDecorator<Type>*)ser.pointer();
serializer_.setPointer((void*)range->value);
serializer_.setType(Serialization::TypeID::get<Type>());
value_ = *range->value;
softMin_ = range->softMin;
softMax_ = range->softMax;
hardMin_ = range->hardMin;
hardMax_ = range->hardMax;
}
bool assignTo(const Serialization::SStruct& ser) const override
{
if (ser.type() == Serialization::TypeID::get<Serialization::RangeDecorator<Type>>()) {
Serialization::RangeDecorator<Type>* range = (Serialization::RangeDecorator<Type>*)ser.pointer();
*range->value = value_;
}
else if (ser.type() == Serialization::TypeID::get<Type>()) {
*(Type*)ser.pointer() = value_;
}
return true;
}
void serializeValue(Serialization::IArchive& ar)
{
ar(value_, "value", "Value");
ar(softMin_, "softMin", "SoftMin");
ar(softMax_, "softMax", "SoftMax");
ar(hardMin_, "hardMin", "HardMin");
ar(hardMax_, "hardMax", "HardMax");
}
void startIncrement() override
{
incrementStartValue_ = value_;
}
void endIncrement(QPropertyTree* tree) override
{
if (value_ != incrementStartValue_) {
Type value = value_;
value_ = incrementStartValue_;
value_ = value;
tree->model()->rowChanged(this, true);
}
}
void incrementLog(float screenFraction, float valueFieldFraction)
{
bool bothSoftLimitsSet = (std::numeric_limits<Type>::lowest() == 0 || softMin_ != std::numeric_limits<Type>::lowest()) && softMax_ != std::numeric_limits<Type>::max();
if (bothSoftLimitsSet)
{
Type softRange = softMax_ - softMin_;
double newValue = incrementStartValue_ + softRange * valueFieldFraction;
value_ = clamp(newValue, hardMin_, hardMax_);
}
else
{
double screenFractionMultiplier = 1000.0;
if (Serialization::TypeID::get<Type>() == Serialization::TypeID::get<float>() ||
Serialization::TypeID::get<Type>() == Serialization::TypeID::get<double>())
screenFractionMultiplier = 10.0;
double startPower = log10(fabs(double(incrementStartValue_)) + 1.0) - 3.0;
double power = startPower + fabs(screenFraction) * 10.0f;
double delta = pow(10.0, power) - pow(10.0, startPower) + screenFractionMultiplier * fabs(screenFraction);
double newValue;
if (screenFraction > 0.0f)
newValue = double(incrementStartValue_) + delta;
else
newValue = double(incrementStartValue_) - delta;
#ifdef _MSC_VER
if (_isnan(newValue)) {
#else
if (isnan(newValue)) {
#endif
if (screenFraction > 0.0f)
newValue = DBL_MAX;
else
newValue = -DBL_MAX;
}
value_ = clamp(newValue, hardMin_, hardMax_);
}
}
double sliderPosition() const override
{
if ((softMin_ == std::numeric_limits<Type>::lowest() && softMax_ == std::numeric_limits<Type>::max() && softMax_ != Type(255)) || (softMin_ >= softMax_))
return 0.0;
return clamp(double(value_ - softMin_) / (softMax_ - softMin_), 0.0, 1.0);
}
protected:
Type incrementStartValue_;
Type value_;
Type softMin_;
Type softMax_;
Type hardMin_;
Type hardMax_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWNUMBER_H
@@ -0,0 +1,287 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "QPropertyTree.h"
#include "QPropertyTreeStyle.h"
#include "PropertyTreeModel.h"
#include "PropertyRowNumberField.h"
#include "PropertyDrawContext.h"
#include "MathUtils.h"
#include <QStyleOption>
#include <QDesktopWidget>
#include <QApplication>
#include <QPainter>
#include <QBitmap>
PropertyRowNumberField::PropertyRowNumberField()
: pressed_(false)
, dragStarted_(false)
{
}
PropertyRowWidget* PropertyRowNumberField::createWidget(QPropertyTree* tree)
{
return new PropertyRowWidgetNumber(tree->model(), this, tree);
}
QColor interpolateColor(const QColor& a, const QColor& b, float k);
void PropertyRowNumberField::redraw(const PropertyDrawContext& context)
{
if (multiValue())
context.drawEntry(L" ... ", false, true, 0);
else if (userReadOnly())
context.drawValueText(pulledSelected(), valueAsWString().c_str());
else
{
QPainter* painter = context.painter;
const QPropertyTree* tree = context.tree;
QRect rt = context.widgetRect;
rt.adjust(0, 0, 0, -1);
#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))
QStyleOptionFrameV2 option;
option.features = QStyleOptionFrameV2::None;
#else
QStyleOptionFrame option;
option.features = QStyleOptionFrame::None;
#endif
option.state = QStyle::State_Sunken;
// We require a widget to use as context, so that the style sheet can work.
QLineEdit widgetForContext;
option.lineWidth = tree->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, &widgetForContext);
option.midLineWidth = 0;
if (context.captured) {
option.state |= QStyle::State_HasFocus;
option.state |= QStyle::State_Active;
option.state |= QStyle::State_MouseOver;
}
else if (!userReadOnly()) {
option.state |= QStyle::State_Enabled;
}
option.rect = rt; // option.rect is the rectangle to be drawn on.
option.palette = tree->palette();
option.fontMetrics = tree->fontMetrics();
QRect textRect = tree->style()->subElementRect(QStyle::SE_LineEditContents, &option, &widgetForContext);
if (!textRect.isValid()) {
textRect = rt;
textRect.adjust(3, 1, -3, -2);
}
else {
textRect.adjust(2, 1, -2, -1);
}
widgetForContext.ensurePolished();
option.palette = widgetForContext.palette();
painter->setPen(QPen(widgetForContext.palette().color(QPalette::WindowText)));
painter->setBrush(QBrush(widgetForContext.palette().color(QPalette::Base)));
tree->style()->drawPrimitive(QStyle::PE_PanelLineEdit, &option, painter, &widgetForContext);
double sliderPos = sliderPosition();
if (sliderPos != 0.0)
{
QRect r = textRect.adjusted(-2, -1, 2, 1);
QRect sliderOverlayRect(r.left(), r.top(), int(r.width() * sliderPos), r.height());
QColor sliderOverlayColor = interpolateColor(tree->palette().color(QPalette::Window), tree->palette().color(QPalette::Highlight), tree->treeStyle().sliderSaturation);
sliderOverlayColor.setAlpha(192);
painter->setBrush(QBrush(sliderOverlayColor));
painter->setPen(Qt::NoPen);
painter->drawRoundedRect(sliderOverlayRect, 1, 1);
if (pressed_) {
painter->setPen(QColor(255, 255, 255));
painter->setBrush(QBrush(QColor(255, 255, 255)));
painter->drawLine(sliderOverlayRect.right(), sliderOverlayRect.top(), sliderOverlayRect.right(), sliderOverlayRect.bottom());
painter->setRenderHint(QPainter::Antialiasing, true);
painter->translate(0.5f, 0.5f);
int r2 = sliderOverlayRect.right();
int t = sliderOverlayRect.top();
int h = sliderOverlayRect.height();
QPoint points[3] = {
QPoint(r2 - 1 - h / 8 - h / 3, t + h / 2),
QPoint(r2 - 1 - h / 8, t + h * 1 / 4),
QPoint(r2 - 1 - h / 8, t + h * 3 / 4)
};
QPoint pointsR[3] = {
QPoint(r2 + 1 + h / 8 + h / 3, t + h / 2),
QPoint(r2 + 1 + h / 8, t + h * 1 / 4),
QPoint(r2 + 1 + h / 8, t + h * 3 / 4)
};
painter->drawPolygon(points, 3);
painter->drawPolygon(pointsR, 3);
painter->setRenderHint(QPainter::Antialiasing, false);
painter->translate(-0.5f, -0.5f);
}
}
painter->setPen(QPen(widgetForContext.palette().color(QPalette::WindowText)));
painter->setBrush(QBrush(widgetForContext.palette().color(QPalette::Base)));
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, QString(valueAsString().c_str()));
}
}
QCursor createSliderHoverCursor()
{
QCursor arrow(Qt::ArrowCursor);
QPoint hotSpot = arrow.hotSpot();
static QImage image = arrow.pixmap().toImage();
if (image.isNull())
return QCursor(Qt::SizeHorCursor);
int w = image.width();
int h = image.height();
QImage empty(w * 2, h, QImage::Format_ARGB32);
empty.fill(Qt::transparent);
QPixmap pixmap = QPixmap::fromImage(empty);
if (pixmap.isNull())
return QCursor(Qt::SizeHorCursor);
QPainter p(&pixmap);
p.drawImage(image.width() / 2, 0, image);
p.setRenderHint(QPainter::Antialiasing, true);
QPoint points[3] = {
QPoint(w / 2 - w * 2 / 8, h / 2),
QPoint(w / 2 - w / 8, h * 3 / 8),
QPoint(w / 2 - w / 8, h * 5 / 8)
};
QPoint pointsR[3] = {
QPoint(w, h * 3 / 8),
QPoint(w, h * 5 / 8),
QPoint(w + w / 8, h / 2),
};
p.setBrush(QBrush(QColor(255, 255, 255)));
p.setPen(QPen(QColor(0, 0, 0)));
p.drawPolygon(points, 3);
p.drawPolygon(pointsR, 3);
return QCursor(pixmap, image.width() / 2 + hotSpot.x(), hotSpot.y());
}
void PropertyRowNumberField::onMouseDrag(const PropertyDragEvent& e)
{
if (!dragStarted_) {
e.tree->model()->rowAboutToBeChanged(this);
dragStarted_ = true;
}
QSize screenSize = QApplication::desktop()->screenGeometry(e.tree).size();
float relativeDelta = float(e.totalDelta.x()) / screenSize.width();
int fieldRectWidth = widgetRect(e.tree).width();
if (fieldRectWidth < 16)
fieldRectWidth = aznumeric_cast<int>(e.tree->treeSize().x() * e.tree->valueColumnWidth());
float valueFieldFraction = fieldRectWidth < FLT_EPSILON ? 0 : float(e.totalDelta.x()) / fieldRectWidth;
incrementLog(relativeDelta, valueFieldFraction);
setMultiValue(false);
}
bool PropertyRowNumberField::getHoverInfo(PropertyHoverInfo* hit, const QPoint& cursorPos, const QPropertyTree* tree) const
{
if (pressed_ && !userReadOnly())
hit->cursor = QCursor(Qt::BlankCursor);
else if (widgetRect(tree).contains(cursorPos) && !userReadOnly())
hit->cursor = QCursor(createSliderHoverCursor());
hit->toolTip = tooltip_;
return true;
}
void PropertyRowNumberField::onMouseStill(const PropertyDragEvent& e)
{
e.tree->model()->callRowCallback(this);
e.tree->apply(true);
}
bool PropertyRowNumberField::onMouseDown(QPropertyTree* tree, QPoint point, bool& changed)
{
changed = false;
if (widgetRect(tree).contains(point) && !userReadOnly()) {
startIncrement();
pressed_ = true;
return true;
}
return false;
}
void PropertyRowNumberField::onMouseUp(QPropertyTree* tree, [[maybe_unused]] QPoint point)
{
tree->unsetCursor();
pressed_ = false;
dragStarted_ = false;
// endIncrement() can cause PropertyRow to be destroy,
// so no "this" members should be accessed after the call.
endIncrement(tree);
}
bool PropertyRowNumberField::onActivate(const PropertyActivationEvent& e)
{
if (e.reason == e.REASON_RELEASE || e.reason == e.REASON_DOUBLECLICK)
return e.tree->spawnWidget(this, false);
return false;
}
int PropertyRowNumberField::widgetSizeMin(const QPropertyTree* tree) const
{
if (userWidgetSize() >= 0)
return userWidgetSize();
if (userWidgetToContent())
return widthCache_.getOrUpdate(tree, this, 0);
else
return 40;
}
// ---------------------------------------------------------------------------
PropertyRowWidgetNumber::PropertyRowWidgetNumber([[maybe_unused]] PropertyTreeModel* model, PropertyRowNumberField* row, QPropertyTree* tree)
: PropertyRowWidget(row, tree)
, row_(row)
, entry_(new QLineEdit())
, tree_(tree)
{
entry_->setText(row_->valueAsString().c_str());
connect(entry_, SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
connect(entry_, &QLineEdit::textChanged, this, [this, tree] {
QFontMetrics fm(entry_->font());
int contentWidth = min((int)fm.horizontalAdvance(entry_->text()) + 8, tree->width() - entry_->x());
if (contentWidth > entry_->width())
entry_->resize(contentWidth, entry_->height());
});
entry_->selectAll();
}
void PropertyRowWidgetNumber::onEditingFinished()
{
tree_->model()->rowAboutToBeChanged(row());
string str = entry_->text().toLocal8Bit().data();
if (row_->setValueFromString(str.c_str()) || row_->multiValue())
tree_->model()->rowChanged(row());
else
tree_->_cancelWidget();
}
void PropertyRowWidgetNumber::commit()
{
if (entry_)
onEditingFinished();
}
#include <QPropertyTree/moc_PropertyRowNumberField.cpp>
@@ -0,0 +1,75 @@
// Modifications copyright Amazon.com, Inc. or its affiliates.
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWNUMBERFIELD_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWNUMBERFIELD_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyRow.h"
#include <QLineEdit>
#endif
class PropertyRowNumberField;
class PropertyRowWidgetNumber : public PropertyRowWidget
{
Q_OBJECT
public:
PropertyRowWidgetNumber(PropertyTreeModel* mode, PropertyRowNumberField* numberField, QPropertyTree* tree);
~PropertyRowWidgetNumber(){
if (entry_)
entry_->setParent(0);
entry_->deleteLater();
entry_ = 0;
}
void commit();
QWidget* actualWidget() { return entry_; }
public slots:
void onEditingFinished();
protected:
QLineEdit* entry_;
PropertyRowNumberField* row_;
QPropertyTree* tree_;
};
// ---------------------------------------------------------------------------
class PropertyRowNumberField : public PropertyRow
{
public:
PropertyRowNumberField();
WidgetPlacement widgetPlacement() const override{ return WIDGET_VALUE; }
int widgetSizeMin(const QPropertyTree* tree) const override;
PropertyRowWidget* createWidget(QPropertyTree* tree) override;
bool isLeaf() const override{ return true; }
bool isStatic() const override{ return false; }
bool inlineInShortArrays() const override{ return true; }
void redraw(const PropertyDrawContext& context) override;
bool onActivate(const PropertyActivationEvent& e) override;
bool onMouseDown(QPropertyTree* tree, QPoint point, bool& changed) override;
void onMouseUp(QPropertyTree* tree, QPoint point) override;
void onMouseDrag(const PropertyDragEvent& e) override;
void onMouseStill(const PropertyDragEvent& e) override;
bool getHoverInfo(PropertyHoverInfo* hit, const QPoint& cursorPos, const QPropertyTree* tree) const;
virtual void startIncrement() = 0;
virtual void endIncrement(QPropertyTree* tree) = 0;
virtual void incrementLog(float screenFraction, float valueFieldFraction) = 0;
virtual bool setValueFromString(const char* str) = 0;
virtual double sliderPosition() const = 0;
mutable RowWidthCache widthCache_;
bool pressed_ : 1;
bool dragStarted_ : 1;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWNUMBERFIELD_H
@@ -0,0 +1,42 @@
/*
* 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 "PropertyRowObject.h"
#include "PropertyTreeModel.h"
PropertyRowObject::PropertyRowObject()
: model_(0)
{
}
bool PropertyRowObject::assignTo(Serialization::Object* obj)
{
if (object_.type() == obj->type())
{
*obj = object_;
return true;
}
return false;
}
PropertyRowObject::~PropertyRowObject()
{
object_ = Serialization::Object();
}
void PropertyRowObject::Serialize(Serialization::IArchive& ar)
{
PropertyRow::Serialize(ar);
}
@@ -0,0 +1,51 @@
/*
* 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_PROPERTYROWOBJECT_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWOBJECT_H
#pragma once
#include "PropertyRow.h"
#include "Serialization/MemoryWriter.h"
#include "Serialization/Pointers.h"
#include "Serialization/Object.h"
namespace Serialization {
class IArchive;
struct SStruct;
class MemoryWriter;
};
class PropertyRowObject
: public PropertyRow
{
public:
PropertyRowObject();
~PropertyRowObject();
using PropertyRow::setValueAndContext;
using PropertyRow::assignTo;
void setValueAndContext(const Serialization::Object& obj, [[maybe_unused]] Serialization::IArchive& ar) { object_ = obj; }
void setModel(PropertyTreeModel* model) { model_ = model; }
bool isObject() const override { return true; }
bool assignTo(Serialization::Object* obj);
void Serialize(Serialization::IArchive& ar);
const Serialization::Object& object() const{ return object_; }
protected:
Serialization::Object object_;
PropertyTreeModel* model_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWOBJECT_H
@@ -0,0 +1,205 @@
/*
* 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 "PropertyRowOutputFilePath.h"
#include "Serialization/ClassFactory.h"
#include <Serialization/Decorators/IconXPM.h>
#ifndef SERIALIZATION_STANDALONE
#include <Include/EditorCoreAPI.h>
#include <Util/PathUtil.h> // for Getting game folder
#endif
#include <QFileDialog>
#include <QIcon>
#include <QMenu>
#include <QKeyEvent>
OutputFilePathMenuHandler::OutputFilePathMenuHandler(QPropertyTree* tree, PropertyRowOutputFilePath* self)
: self(self)
, tree(tree)
{
}
void OutputFilePathMenuHandler::onMenuClear()
{
tree->model()->rowAboutToBeChanged(self);
self->clear();
tree->model()->rowChanged(self);
}
QString convertMFCToQtFileFilter(QString* defaultSuffix, const char* mfcFilter)
{
// convert filter from "All Files|*.*|Text files|*.txt||"
// format into "All files (*.*);;Text Files (*.txt)"
QString filterMFC = QString::fromLocal8Bit(mfcFilter);
QStringList filterItems = filterMFC.split("|");
if (defaultSuffix && filterItems.size() > 1)
{
QString extensions = filterItems[1];
QRegExp re("\\*\\.(\\w*)");
if (extensions.indexOf(re) >= 0)
{
*defaultSuffix = re.cap(1);
}
}
QString filter;
for (int i = 0; i < int(filterItems.size()) / 2; ++i)
{
int bracketPos = filterItems[i].indexOf('(');
QString desc = bracketPos >= 0 ? filterItems[i].left(bracketPos) : filterItems[i];
int extIndex = i * 2 + 1;
if (extIndex >= filterItems.size())
{
break;
}
if (!filter.isEmpty())
{
filter += ";;";
}
filter += desc;
filter += " (";
filter += filterItems[extIndex];
filter += ")";
}
return filter;
}
bool PropertyRowOutputFilePath::onActivate(const PropertyActivationEvent& e)
{
if (e.reason == e.REASON_RELEASE)
{
return false;
}
#ifndef SERIALIZATION_STANDALONE
if (!GetIEditor())
{
return true;
}
#endif
QString title;
if (labelUndecorated())
{
title = QString("Choose file for '") + labelUndecorated() + "'";
}
else
{
title = "Choose file";
}
#ifdef SERIALIZATION_STANDALONE
QString gameFolder;
#else
QString gameFolder = QString::fromLocal8Bit(Path::GetEditingGameDataFolder().c_str());
#endif
QDir gameFolderDir(QDir::fromNativeSeparators(gameFolder));
QString defaultSuffix;
QString filter = convertMFCToQtFileFilter(&defaultSuffix, filter_.c_str());
QString existingFile = QString::fromLocal8Bit(path_.c_str());
QString existingFilePath = (existingFile.isEmpty() || QDir::isAbsolutePath(existingFile)) ? existingFile : gameFolderDir.absoluteFilePath(existingFile);
QString startFolder = QString::fromLocal8Bit(startFolder_.c_str());
// Not using QFileDialog().exec() as it implements custom file dialog that
// freezes for couple of seconds when being open. Scannign network drives?
QString result = QFileDialog::getSaveFileName(e.tree, title, existingFilePath.isEmpty() ? (gameFolder + "/" + startFolder) : existingFilePath, filter);
if (!result.isEmpty())
{
e.tree->model()->rowAboutToBeChanged(this);
QString relativeFilename = gameFolderDir.relativeFilePath(result);
path_ = relativeFilename.toLocal8Bit().data();
e.tree->model()->rowChanged(this);
}
return true;
}
void PropertyRowOutputFilePath::setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar)
{
OutputFilePath* value = (OutputFilePath*)ser.pointer();
path_ = value->m_path->c_str();
filter_ = value->filter.c_str();
startFolder_ = value->startFolder.c_str();
handle_ = value->m_path;
}
bool PropertyRowOutputFilePath::assignTo(const Serialization::SStruct& ser) const
{
((OutputFilePath*)ser.pointer())->SetPath(path_.c_str());
return true;
}
const QIcon& PropertyRowOutputFilePath::buttonIcon(const QPropertyTree* tree, [[maybe_unused]] int index) const
{
#include "file_save.xpm"
static QIcon fileOpenIcon = QIcon(QPixmap::fromImage(*tree->_iconCache()->getImageForIcon(Serialization::IconXPM(file_save_xpm))));
return fileOpenIcon;
}
string PropertyRowOutputFilePath::valueAsString() const
{
return path_;
}
void PropertyRowOutputFilePath::clear()
{
path_.clear();
}
bool PropertyRowOutputFilePath::onContextMenu(QMenu& menu, QPropertyTree* tree)
{
QAction* action = menu.addAction("Clear");
Serialization::SharedPtr<PropertyRow> selfPointer(this);
OutputFilePathMenuHandler* handler = new OutputFilePathMenuHandler(tree, this);
QObject::connect(action, SIGNAL(triggered()), handler, SLOT(onMenuClear()));
tree->addMenuHandler(handler);
return true;
}
void PropertyRowOutputFilePath::serializeValue(Serialization::IArchive& ar)
{
ar(path_, "path");
ar(filter_, "filter");
ar(startFolder_, "startFolder");
}
bool PropertyRowOutputFilePath::processesKey(QPropertyTree* tree, const QKeyEvent* ev)
{
if (ev->key() == Qt::Key_Delete)
{
return true;
}
return PropertyRowField::processesKey(tree, ev);
}
bool PropertyRowOutputFilePath::onKeyDown(QPropertyTree* tree, const QKeyEvent* ev)
{
if (ev->key() == Qt::Key_Delete)
{
tree->model()->rowAboutToBeChanged(this);
clear();
tree->model()->rowChanged(this);
return true;
}
return PropertyRowField::onKeyDown(tree, ev);
}
REGISTER_PROPERTY_ROW(OutputFilePath, PropertyRowOutputFilePath);
DECLARE_SEGMENT(PropertyRowOutputFilePath)
#include <QPropertyTree/moc_PropertyRowOutputFilePath.cpp>
@@ -0,0 +1,74 @@
/*
* 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_PROPERTYROWOUTPUTFILEPATH_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWOUTPUTFILEPATH_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyDrawContext.h"
#include "PropertyRowField.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "Serialization.h"
#include <Serialization/Decorators/OutputFilePath.h>
#include <Serialization/Decorators/OutputFilePathImpl.h>
#endif
using Serialization::OutputFilePath;
class PropertyRowOutputFilePath
: public PropertyRowField
{
public:
void clear();
bool isLeaf() const override { return true; }
bool isStatic() const override { return false; }
bool onActivate(const PropertyActivationEvent& e) override;
void setValueAndContext(const Serialization::SStruct& ser, Serialization::IArchive& ar) override;
bool assignTo(const Serialization::SStruct& ser) const override;
string valueAsString() const;
void serializeValue(Serialization::IArchive& ar);
bool onContextMenu(QMenu& menu, QPropertyTree* tree);
const void* searchHandle() const { return handle_; }
int buttonCount() const override { return 1; }
virtual const QIcon& buttonIcon(const QPropertyTree* tree, int index) const override;
virtual bool usePathEllipsis() const override { return true; }
bool processesKey(QPropertyTree* tree, const QKeyEvent* ev) override;
bool onKeyDown(QPropertyTree* tree, const QKeyEvent* ev) override;
private:
string path_;
string filter_;
string startFolder_;
const void* handle_;
};
struct OutputFilePathMenuHandler
: PropertyRowMenuHandler
{
Q_OBJECT
public:
QPropertyTree * tree;
PropertyRowOutputFilePath* self;
OutputFilePathMenuHandler(QPropertyTree* tree, PropertyRowOutputFilePath* container);
public slots:
void onMenuClear();
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWOUTPUTFILEPATH_H
@@ -0,0 +1,347 @@
/*
* 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 "PropertyRowPointer.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "PropertyDrawContext.h"
#include "Serialization.h"
#include "Unicode.h"
#include <QMenu>
// ---------------------------------------------------------------------------
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 level2 = 0; level2 < int(path.size()); ++level2)
{
const char* leaf = path[level2].c_str();
if (level2 == 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, [[maybe_unused]] 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.m_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, [[maybe_unused]] 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, [[maybe_unused]] 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/moc_PropertyRowPointer.cpp>
// vim:ts=4 sw=4:
@@ -0,0 +1,95 @@
/*
* 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_PROPERTYROWPOINTER_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWPOINTER_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "Color.h"
#include "Serialization/StringList.h"
using Serialization::StringList;
#include "PropertyRow.h"
#endif
class QPropertyTree;
class PropertyRowPointer;
struct CreatePointerMenuHandler
: PropertyRowMenuHandler
{
Q_OBJECT
public:
QPropertyTree * tree;
PropertyRowPointer* row;
int index;
bool useDefaultValue;
public slots:
void onMenuCreateByIndex();
};
class QMenu;
struct ClassMenuItemAdder
{
virtual void addAction(QMenu& menu, const char* text, int index);
virtual QMenu* addMenu(QMenu& menu, const char* text);
void generateMenu(QMenu& createItem, const StringList& comboStrings);
};
class PropertyRowPointer
: public PropertyRow
{
public:
PropertyRowPointer();
bool assignTo(Serialization::IPointer& ptr);
void setValueAndContext(const Serialization::IPointer& ptr, Serialization::IArchive& ar);
using PropertyRow::assignTo;
using PropertyRow::setValueAndContext;
using PropertyRow::onActivate;
Serialization::TypeID baseType() const{ return baseType_; }
void setBaseType(const Serialization::TypeID& baseType) { baseType_ = baseType; }
const char* derivedTypeName() const{ return derivedTypeName_.c_str(); }
void setDerivedType(const char* typeName, Serialization::IClassFactory* factory);
void setFactory(Serialization::IClassFactory* factory) { factory_ = factory; }
Serialization::IClassFactory* factory() const{ return factory_; }
bool onActivate(QPropertyTree* tree, bool force);
bool onMouseDown(QPropertyTree* tree, QPoint point, bool& changed);
bool onContextMenu(QMenu& root, QPropertyTree* tree);
bool isStatic() const{ return false; }
bool isPointer() const{ return true; }
int widgetSizeMin(const QPropertyTree* tree) const override;
wstring generateLabel() const;
string valueAsString() const;
const char* typeNameForFilter([[maybe_unused]] QPropertyTree* tree) const override { return baseType_.name(); }
void redraw(const PropertyDrawContext& context);
WidgetPlacement widgetPlacement() const{ return WIDGET_VALUE; }
void serializeValue(Serialization::IArchive& ar);
const void* searchHandle() const override { return searchHandle_; }
Serialization::TypeID typeId() const override { return pointerType_; }
protected:
Serialization::TypeID baseType_;
string derivedTypeName_;
string derivedLabel_;
// this member is available for instances deserialized from clipboard:
Serialization::IClassFactory* factory_;
const void* searchHandle_;
Serialization::TypeID pointerType_;
Color colorOverride_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWPOINTER_H
@@ -0,0 +1,177 @@
/*
* 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 <AzCore/IO/FileIO.h>
#include "PropertyRowResourceFilePath.h"
#include "Serialization/ClassFactory.h"
#include <Include/EditorCoreAPI.h>
#include <QMenu>
#include <QFileDialog>
#include <QIcon>
#include <QKeyEvent>
#include <Util/PathUtil.h> // for getting game folder.
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
ResourceFilePathMenuHandler::ResourceFilePathMenuHandler(QPropertyTree* tree, PropertyRowResourceFilePath* self)
: self(self)
, tree(tree)
{
}
void ResourceFilePathMenuHandler::onMenuClear()
{
tree->model()->rowAboutToBeChanged(self);
self->clear();
tree->model()->rowChanged(self);
}
// Get filename relative to the asset folder,
// whether it came from the project or from a gem
QString AssetRelativePathFromAbsolutePath(const QString& absPath)
{
return Path::FullPathToGamePath(absPath);
}
bool PropertyRowResourceFilePath::onActivate(const PropertyActivationEvent& e)
{
using namespace AzToolsFramework::AssetBrowser;
if (e.reason == e.REASON_RELEASE)
{
return false;
}
AssetSelectionModel selection;
if (m_group)
{
selection = AssetSelectionModel::AssetGroupSelection(filter_);
}
else
{
selection = AssetSelectionModel::AssetTypeSelection(filter_);
}
AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection);
if (!selection.IsValid())
{
return true;
}
auto product = azrtti_cast<const ProductAssetBrowserEntry*>(selection.GetResult());
if (!product)
{
return true;
}
AZStd::string relativeFilename = product->GetRelativePath();
if (flags_ & ResourceFilePath::STRIP_EXTENSION)
{
size_t ext = relativeFilename.rfind('.');
if (ext != relativeFilename.npos)
{
relativeFilename.erase(ext, relativeFilename.length() - ext);
}
}
e.tree->model()->rowAboutToBeChanged(this);
path_ = relativeFilename.c_str();
e.tree->model()->rowChanged(this);
return true;
}
void PropertyRowResourceFilePath::setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar)
{
ResourceFilePath* value = (ResourceFilePath*)ser.pointer();
filter_ = value->filter.c_str();
path_ = value->m_path->c_str();
flags_ = value->flags;
handle_ = value->m_path;
m_group = value->group;
}
bool PropertyRowResourceFilePath::assignTo(const Serialization::SStruct& ser) const
{
((ResourceFilePath*)ser.pointer())->SetPath(path_.c_str());
return true;
}
void PropertyRowResourceFilePath::serializeValue(Serialization::IArchive& ar)
{
ar(filter_, "filter");
ar(path_, "path");
ar(startFolder_, "startFolder");
ar(m_group, "group");
}
const QIcon& PropertyRowResourceFilePath::buttonIcon(const QPropertyTree* tree, [[maybe_unused]] int index) const
{
#include "file_open.xpm"
static QIcon fileOpenIcon = QIcon(QPixmap::fromImage(*tree->_iconCache()->getImageForIcon(Serialization::IconXPM(file_open_xpm))));
return fileOpenIcon;
}
string PropertyRowResourceFilePath::valueAsString() const
{
return path_;
}
void PropertyRowResourceFilePath::clear()
{
path_.clear();
}
bool PropertyRowResourceFilePath::onContextMenu(QMenu& menu, QPropertyTree* tree)
{
QAction* action = menu.addAction("Clear");
Serialization::SharedPtr<PropertyRow> selfPointer(this);
ResourceFilePathMenuHandler* handler = new ResourceFilePathMenuHandler(tree, this);
QObject::connect(action, SIGNAL(triggered()), handler, SLOT(onMenuClear()));
tree->addMenuHandler(handler);
return true;
}
bool PropertyRowResourceFilePath::processesKey(QPropertyTree* tree, const QKeyEvent* ev)
{
if (ev->key() == Qt::Key_Delete)
{
return true;
}
return PropertyRowField::processesKey(tree, ev);
}
bool PropertyRowResourceFilePath::onKeyDown(QPropertyTree* tree, const QKeyEvent* ev)
{
if (ev->key() == Qt::Key_Delete)
{
tree->model()->rowAboutToBeChanged(this);
clear();
tree->model()->rowChanged(this);
return true;
}
return PropertyRowField::onKeyDown(tree, ev);
}
REGISTER_PROPERTY_ROW(ResourceFilePath, PropertyRowResourceFilePath);
DECLARE_SEGMENT(PropertyRowResourceFilePath)
#include <QPropertyTree/moc_PropertyRowResourceFilePath.cpp>
@@ -0,0 +1,79 @@
/*
* 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_PROPERTYROWRESOURCEFILEPATH_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWRESOURCEFILEPATH_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyDrawContext.h"
#include "PropertyRowField.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "Serialization.h"
#include <Serialization/Decorators/ResourceFilePath.h>
#include <Serialization/Decorators/ResourceFilePathImpl.h>
#include <Serialization/Decorators/IconXPM.h>
#endif
using Serialization::ResourceFilePath;
class PropertyRowResourceFilePath
: public PropertyRowField
{
public:
void clear();
bool isLeaf() const override { return true; }
bool isStatic() const override { return false; }
void setValueAndContext(const Serialization::SStruct& ser, Serialization::IArchive& ar) override;
bool assignTo(const Serialization::SStruct& ser) const override;
bool onActivate(const PropertyActivationEvent& e) override;
int buttonCount() const override { return 1; }
virtual const QIcon& buttonIcon(const QPropertyTree* tree, int index) const override;
virtual bool usePathEllipsis() const override { return true; }
string valueAsString() const;
void serializeValue(Serialization::IArchive& ar);
const void* searchHandle() const override { return handle_; }
Serialization::TypeID typeId() const override { return Serialization::TypeID::get<string>(); }
bool onContextMenu(QMenu& menu, QPropertyTree* tree);
bool processesKey(QPropertyTree* tree, const QKeyEvent* ev) override;
bool onKeyDown(QPropertyTree* tree, const QKeyEvent* ev) override;
private:
string filter_;
string path_;
string startFolder_;
bool m_group;
int flags_;
const void* handle_;
};
struct ResourceFilePathMenuHandler
: PropertyRowMenuHandler
{
Q_OBJECT
public:
QPropertyTree * tree;
PropertyRowResourceFilePath* self;
ResourceFilePathMenuHandler(QPropertyTree* tree, PropertyRowResourceFilePath* container);
public slots:
void onMenuClear();
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWRESOURCEFILEPATH_H
@@ -0,0 +1,159 @@
/*
* 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 <Serialization/Decorators/IconXPM.h>
#include "PropertyRowResourceFolderPath.h"
#include "Serialization/ClassFactory.h"
#include <Include/EditorCoreAPI.h>
#include <QMenu>
#include <QKeyEvent>
#include <Util/PathUtil.h>
ResourceFolderPathMenuHandler::ResourceFolderPathMenuHandler(QPropertyTree* tree, PropertyRowResourceFolderPath* self)
: self(self)
, tree(tree)
{
}
void ResourceFolderPathMenuHandler::onMenuClear()
{
tree->model()->rowAboutToBeChanged(self);
self->clear();
tree->model()->rowChanged(self);
}
bool PropertyRowResourceFolderPath::onActivate(const PropertyActivationEvent& e)
{
if (e.reason == e.REASON_RELEASE)
{
return false;
}
if (!GetIEditor())
{
return true;
}
if (userReadOnly())
{
return false;
}
QString title;
if (labelUndecorated() && labelUndecorated()[0] != '\0')
{
title = QString("Choose folder for '") + QString::fromLocal8Bit(labelUndecorated()) + "'";
}
else
{
title = "Choose folder";
}
QString gameFolder = QString::fromLocal8Bit(Path::GetEditingGameDataFolder().c_str());
QString startFolder = gameFolder + QDir::separator();
if (path_.empty() || !QDir().exists(startFolder))
{
startFolder += QString::fromLocal8Bit(startFolder_.c_str());
}
else
{
startFolder += QString::fromLocal8Bit(path_.c_str());
}
QString filename = QFileDialog::getExistingDirectory(e.tree, title, startFolder, QFileDialog::ShowDirsOnly);
if (filename.isEmpty())
{
return true;
}
e.tree->model()->rowAboutToBeChanged(this);
QString result = QDir(gameFolder).relativeFilePath(filename);
path_ = result.toLocal8Bit().data();
e.tree->model()->rowChanged(this);
return true;
}
void PropertyRowResourceFolderPath::setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar)
{
ResourceFolderPath* value = (ResourceFolderPath*)(ser.pointer());
path_ = value->m_path->c_str();
startFolder_ = value->startFolder.c_str();
handle_ = value->m_path;
}
bool PropertyRowResourceFolderPath::assignTo(const Serialization::SStruct& ser) const
{
((ResourceFolderPath*)ser.pointer())->SetPath(path_.c_str());
return true;
}
const QIcon& PropertyRowResourceFolderPath::buttonIcon(const QPropertyTree* tree, [[maybe_unused]] int index) const
{
#include "file_open.xpm"
static QIcon fileOpenIcon = QIcon(QPixmap::fromImage(*tree->_iconCache()->getImageForIcon(Serialization::IconXPM(file_open_xpm))));
return fileOpenIcon;
}
string PropertyRowResourceFolderPath::valueAsString() const
{
return path_;
}
void PropertyRowResourceFolderPath::clear()
{
path_.clear();
}
void PropertyRowResourceFolderPath::serializeValue(Serialization::IArchive& ar)
{
ar(path_, "path");
ar(startFolder_, "startFolder");
}
bool PropertyRowResourceFolderPath::onContextMenu(QMenu& menu, QPropertyTree* tree)
{
ResourceFolderPathMenuHandler* handler = new ResourceFolderPathMenuHandler(tree, this);
QAction* action = menu.addAction("Clear", handler, SLOT(onMenuClear()));
action->setEnabled(!userReadOnly());
SharedPtr<PropertyRow> selfPointer(this);
tree->addMenuHandler(handler);
return true;
}
bool PropertyRowResourceFolderPath::processesKey(QPropertyTree* tree, const QKeyEvent* ev)
{
if (ev->key() == Qt::Key_Delete)
{
return true;
}
return PropertyRowField::processesKey(tree, ev);
}
bool PropertyRowResourceFolderPath::onKeyDown(QPropertyTree* tree, const QKeyEvent* ev)
{
if (ev->key() == Qt::Key_Delete)
{
tree->model()->rowAboutToBeChanged(this);
clear();
tree->model()->rowChanged(this);
return true;
}
return PropertyRowField::onKeyDown(tree, ev);
}
REGISTER_PROPERTY_ROW(ResourceFolderPath, PropertyRowResourceFolderPath);
DECLARE_SEGMENT(PropertyRowResourceFolderPath)
#include <QPropertyTree/moc_PropertyRowResourceFolderPath.cpp>
@@ -0,0 +1,76 @@
/*
* 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_PROPERTYROWRESOURCEFOLDERPATH_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWRESOURCEFOLDERPATH_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyDrawContext.h"
#include "PropertyRowImpl.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "Serialization.h"
#include <Serialization/Decorators/ResourceFolderPath.h>
#include <Serialization/Decorators/ResourceFolderPathImpl.h>
#include <QFileDialog>
#include <QtGui/QIcon>
#endif
using Serialization::ResourceFolderPath;
class PropertyRowResourceFolderPath
: public PropertyRowField
{
public:
PropertyRowResourceFolderPath()
: handle_() {}
bool isLeaf() const override { return true; }
bool isStatic() const override { return false; }
bool onActivate(const PropertyActivationEvent& e) override;
void setValueAndContext(const Serialization::SStruct& ser, Serialization::IArchive& ar) override;
bool assignTo(const Serialization::SStruct& ser) const override;
string valueAsString() const;
bool onContextMenu(QMenu& menu, QPropertyTree* tree);
int buttonCount() const override { return 1; }
virtual const QIcon& buttonIcon(const QPropertyTree* tree, int index) const override;
virtual bool usePathEllipsis() const override { return true; }
void serializeValue(Serialization::IArchive& ar) override;
const void* searchHandle() const override { return handle_; }
Serialization::TypeID typeId() const override { return Serialization::TypeID::get<string>(); }
void clear();
bool processesKey(QPropertyTree* tree, const QKeyEvent* ev) override;
bool onKeyDown(QPropertyTree* tree, const QKeyEvent* ev) override;
private:
string path_;
string startFolder_;
const void* handle_;
};
struct ResourceFolderPathMenuHandler
: PropertyRowMenuHandler
{
Q_OBJECT
public:
QPropertyTree * tree;
PropertyRowResourceFolderPath* self;
ResourceFolderPathMenuHandler(QPropertyTree* tree, PropertyRowResourceFolderPath* container);
public slots:
void onMenuClear();
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWRESOURCEFOLDERPATH_H
@@ -0,0 +1,425 @@
/*
* 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 "PropertyRowResourceSelector.h"
#include "Serialization/ClassFactory.h"
#include "Serialization/Decorators/Resources.h"
#include "Serialization/Decorators/INavigationProvider.h"
#include "Serialization/Decorators/IconXPM.h"
#include <Include/EditorCoreAPI.h>
#include "IEditor.h"
#include <QMenu>
#include <QFileDialog>
#include <QIcon>
#include <QKeyEvent>
#include <Util/PathUtil.h>
enum Button
{
BUTTON_PICK,
BUTTON_CREATE
};
ResourceSelectorMenuHandler::ResourceSelectorMenuHandler(QPropertyTree* tree, PropertyRowResourceSelector* self)
: self(self)
, tree(tree)
{
}
void ResourceSelectorMenuHandler::onMenuClear()
{
tree->model()->rowAboutToBeChanged(self);
self->clear();
tree->model()->rowChanged(self);
}
void ResourceSelectorMenuHandler::onMenuPickResource()
{
self->pickResource(tree);
}
void ResourceSelectorMenuHandler::onMenuCreateFile()
{
self->createFile(tree);
}
void ResourceSelectorMenuHandler::onMenuJumpTo()
{
self->jumpTo(tree);
}
bool PropertyRowResourceSelector::onActivate(const PropertyActivationEvent& e)
{
if (PropertyRowField::onActivate(e))
{
return true;
}
bool canSelect = !userReadOnly() && !multiValue() && provider_ && provider_->CanSelect(type_.c_str(), value_.c_str(), id_);
if (!userReadOnly() && e.reason == e.REASON_DOUBLECLICK && provider_ && provider_->CanPickFile(type_.c_str(), id_))
{
return pickResource(e.tree);
}
if (canSelect)
{
jumpTo(e.tree);
return true;
}
else if (!userReadOnly())
{
if (!provider_ && !userReadOnly())
{
pickResource(e.tree);
}
}
return false;
}
int PropertyRowResourceSelector::buttonCount() const
{
if (!provider_)
{
return 1;
}
int result = 0;
if (provider_->CanPickFile(type_.c_str(), id_))
{
result = 1;
if (!multiValue() && value_.empty() && provider_->CanCreate(type_.c_str(), id_))
{
result = 2;
}
}
return result;
}
bool PropertyRowResourceSelector::onActivateButton(int button, const PropertyActivationEvent& e)
{
if (userReadOnly())
{
return false;
}
if (button == BUTTON_PICK)
{
return pickResource(e.tree);
}
else if (button == BUTTON_CREATE)
{
return createFile(e.tree);
}
return true;
}
bool PropertyRowResourceSelector::getHoverInfo(PropertyHoverInfo* hover, const QPoint& cursorPos, const QPropertyTree* tree) const
{
if (fieldRect(tree).contains(cursorPos) && provider_ && provider_->CanSelect(type_.c_str(), value_.c_str(), id_) && !provider_->IsSelected(type_.c_str(), value_.c_str(), id_))
{
hover->cursor = QCursor(Qt::PointingHandCursor);
}
else
{
hover->cursor = QCursor();
}
hover->toolTip = QString::fromLocal8Bit(value_.c_str());
return true;
}
void PropertyRowResourceSelector::jumpTo([[maybe_unused]] QPropertyTree* tree)
{
if (multiValue())
{
return;
}
if (provider_)
{
provider_->Select(type_.c_str(), value_.c_str(), id_);
}
return;
}
bool PropertyRowResourceSelector::pickResource(QPropertyTree* tree)
{
if (!GetIEditor())
{
return false;
}
context_.typeName = type_.c_str();
context_.parentWidget = tree;
QString filename = GetIEditor()->GetResourceSelectorHost()->SelectResource(context_, value_.c_str());
tree->model()->rowAboutToBeChanged(this);
value_ = filename.toUtf8().constData();
tree->model()->rowChanged(this);
return true;
}
QString convertMFCToQtFileFilter(QString* defaultSuffix, const char* mfcFilter);
bool PropertyRowResourceSelector::createFile(QPropertyTree* tree)
{
if (!provider_)
{
return false;
}
QString title;
if (labelUndecorated())
{
title = QString("Create file for '") + labelUndecorated() + "'";
}
else
{
title = "Choose file";
}
string originalFilter;
originalFilter = provider_->GetFileSelectorMaskForType(type_.c_str());
QString gameFolder = QString::fromLocal8Bit(Path::GetEditingGameDataFolder().c_str());
QDir gameFolderDir(QDir::fromNativeSeparators(gameFolder));
QString defaultSuffix;
QString filter = convertMFCToQtFileFilter(&defaultSuffix, originalFilter.c_str());
QString existingFile = QString::fromLocal8Bit(PathUtil::ReplaceExtension(defaultPath_.empty() ? value_.c_str() : defaultPath_.c_str(), defaultSuffix.toLocal8Bit().data()));
QString existingFilePath = (existingFile.isEmpty() || QDir::isAbsolutePath(existingFile)) ? existingFile : gameFolderDir.absoluteFilePath(existingFile);
// Not using QFileDialog().exec() as it implements custom file dialog that
// freezes for couple of seconds when being open. Scannign network drives?
QString result = QFileDialog::getSaveFileName(tree, title, existingFilePath.isEmpty() ? (gameFolder + "/") : existingFilePath, filter);
if (!result.isEmpty())
{
QString relativeFilename = gameFolderDir.relativeFilePath(result);
if (provider_->Create(type_.c_str(), relativeFilename.toLocal8Bit().data(), id_))
{
tree->model()->rowAboutToBeChanged(this);
value_ = relativeFilename.toLocal8Bit().data();
tree->model()->rowChanged(this);
}
}
return true;
}
void PropertyRowResourceSelector::setValueAndContext(const Serialization::SStruct& ser, IArchive& ar)
{
IResourceSelector* value = (IResourceSelector*)ser.pointer();
if (type_ != value->resourceType)
{
type_ = value->resourceType;
const char* resourceIconPath = GetIEditor()->GetResourceSelectorHost()->ResourceIconPath(type_.c_str());
icon_ = resourceIconPath[0] ? QIcon(QString::fromLocal8Bit(resourceIconPath)) : QIcon();
}
value_ = value->GetValue();
id_ = value->GetId();
searchHandle_ = value->GetHandle();
wrappedType_ = value->GetType();
provider_ = ar.FindContext<Serialization::INavigationProvider>();
if (!provider_ || !provider_->IsRegistered(type_))
{
provider_ = 0;
}
Serialization::TypeID contextObjectType = GetIEditor()->GetResourceSelectorHost()->ResourceContextType(type_.c_str());
if (contextObjectType != Serialization::TypeID())
{
context_.contextObject = ar.FindContextByType(contextObjectType);
context_.contextObjectType = contextObjectType;
}
if (Serialization::SNavigationContext* navigationContext = ar.FindContext<Serialization::SNavigationContext>())
{
defaultPath_ = navigationContext->path.c_str();
}
else
{
defaultPath_.clear();
}
}
bool PropertyRowResourceSelector::assignTo(const Serialization::SStruct& ser) const
{
((IResourceSelector*)ser.pointer())->SetValue(value_.c_str());
return true;
}
void PropertyRowResourceSelector::serializeValue(Serialization::IArchive& ar)
{
ar(type_, "type");
ar(value_, "value");
ar(id_, "index");
if (ar.IsInput())
{
const char* resourceIconPath = GetIEditor()->GetResourceSelectorHost()->ResourceIconPath(type_.c_str());
icon_ = resourceIconPath[0] ? QIcon(QString::fromLocal8Bit(resourceIconPath)) : QIcon();
}
}
const QIcon& PropertyRowResourceSelector::buttonIcon(const QPropertyTree* tree, int index) const
{
switch (index)
{
case BUTTON_PICK:
{
if (provider_ != 0 || icon_.isNull())
{
#include "file_open.xpm"
static QIcon defaultIcon(QPixmap::fromImage(*tree->_iconCache()->getImageForIcon(Serialization::IconXPM(file_open_xpm))));
return defaultIcon;
}
else
{
return icon_;
}
}
case BUTTON_CREATE:
{
static QIcon addIcon("Editor/Icons/animation/add.png");
;
return addIcon;
}
default:
{
static QIcon defaultIcon;
return defaultIcon;
}
}
}
string PropertyRowResourceSelector::valueAsString() const
{
return value_;
}
void PropertyRowResourceSelector::clear()
{
value_.clear();
}
bool PropertyRowResourceSelector::onContextMenu(QMenu& menu, QPropertyTree* tree)
{
Serialization::SharedPtr<PropertyRow> selfPointer(this);
ResourceSelectorMenuHandler* handler = new ResourceSelectorMenuHandler(tree, this);
if (!multiValue() && provider_ && provider_->CanSelect(type_.c_str(), value_.c_str(), id_))
{
QAction* jumpToAction = menu.addAction("Jump to", handler, SLOT(onMenuJumpTo()));
menu.setDefaultAction(jumpToAction);
}
if (!userReadOnly())
{
if (!provider_ || provider_->CanPickFile(type_.c_str(), id_))
{
menu.addAction(buttonIcon(tree, 0), "Pick Resource...", handler, SLOT(onMenuPickResource()))->setEnabled(!userReadOnly());
}
if (provider_ && provider_->CanCreate(type_.c_str(), id_))
{
menu.addAction(buttonIcon(tree, 1), "Create...", handler, SLOT(onMenuCreateFile()));
}
menu.addAction("Clear", handler, SLOT(onMenuClear()))->setEnabled(!userReadOnly());
}
tree->addMenuHandler(handler);
PropertyRow::onContextMenu(menu, tree);
return true;
}
static const wchar_t* getFilenameFromPath(const wchar_t* path)
{
const wchar_t* lastSep = wcsrchr(path, L'/');
if (!lastSep)
{
return path;
}
return lastSep + 1;
}
void PropertyRowResourceSelector::redraw(const PropertyDrawContext& context)
{
////! TOFIX: THIS CODE IS DUPLICATED IN PropertyRowField.cpp: PropertyRowField::redraw()!!!
//
int buttonCount = this->buttonCount();
int offset = 0;
for (int i = 0; i < buttonCount; ++i)
{
const QIcon& icon = buttonIcon(context.tree, i);
int width = 16;
QRect iconRect(context.widgetRect.right() - offset - width, context.widgetRect.top(), width, context.widgetRect.height());
icon.paint(context.painter, iconRect, Qt::AlignCenter, userReadOnly() ? QIcon::Disabled : QIcon::Normal);
offset += width;
}
int iconSpace = offset ? offset + 2 : 0;
//
////
QRect rect = context.widgetRect;
rect.setRight(rect.right() - iconSpace);
bool pressed = context.m_pressed || (provider_ ? provider_->IsSelected(type_.c_str(), value_.c_str(), id_) : false);
bool active = !provider_ || provider_->IsActive(type_.c_str(), value_.c_str(), id_);
bool modified = provider_ && provider_->IsModified(type_.c_str(), value_.c_str(), id_);
QIcon icon = icon_;
if (provider_)
{
icon = QIcon(provider_->GetIcon(type_.c_str(), value_.c_str()));
}
bool canSelect = !multiValue() && provider_ && provider_->CanSelect(type_.c_str(), value_.c_str(), id_);
wstring text = multiValue() ? L"..." : wstring(modified ? L"*" : L"") + getFilenameFromPath(valueAsWString());
if (provider_)
{
if (canSelect || !text.empty())
{
context.drawButtonWithIcon(icon, rect, text.c_str(), selected(), pressed, selected(), !userReadOnly(), canSelect, active ? &context.tree->_boldFont() : &context.tree->font());
}
}
else
{
context.drawEntry(text.c_str(), true, false, iconSpace);
}
}
bool PropertyRowResourceSelector::processesKey(QPropertyTree* tree, const QKeyEvent* ev)
{
if (ev->key() == Qt::Key_Delete)
{
return true;
}
return PropertyRowField::processesKey(tree, ev);
}
bool PropertyRowResourceSelector::onKeyDown(QPropertyTree* tree, const QKeyEvent* ev)
{
if (ev->key() == Qt::Key_Delete)
{
tree->model()->rowAboutToBeChanged(this);
clear();
tree->model()->rowChanged(this);
return true;
}
return PropertyRowField::onKeyDown(tree, ev);
}
REGISTER_PROPERTY_ROW(IResourceSelector, PropertyRowResourceSelector);
DECLARE_SEGMENT(PropertyRowResourceSelector)
#include <QPropertyTree/moc_PropertyRowResourceSelector.cpp>
@@ -0,0 +1,100 @@
/*
* 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_PROPERTYROWRESOURCESELECTOR_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWRESOURCESELECTOR_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyDrawContext.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "PropertyRowField.h"
#include <Serialization.h>
#include "Serialization/Decorators/Resources.h"
#include "IResourceSelectorHost.h"
#include <QIcon>
#endif
using Serialization::IResourceSelector;
namespace Serialization {
struct INavigationProvider;
}
class PropertyRowResourceSelector
: public PropertyRowField
{
public:
PropertyRowResourceSelector()
: provider_(0)
, id_(0)
, searchHandle_(0) {}
void clear();
bool isLeaf() const override { return true; }
bool isStatic() const override { return false; }
void jumpTo(QPropertyTree* tree);
bool createFile(QPropertyTree* tree);
void setValueAndContext(const Serialization::SStruct& ser, Serialization::IArchive& ar) override;
bool assignTo(const Serialization::SStruct& ser) const override;
bool onActivate(const PropertyActivationEvent& ev) override;
bool onActivateButton(int button, const PropertyActivationEvent& e) override;
bool getHoverInfo(PropertyHoverInfo* hover, const QPoint& cursorPos, const QPropertyTree* tree) const override;
const void* searchHandle() const override { return searchHandle_; }
Serialization::TypeID typeId() const override { return wrappedType_; }
int buttonCount() const override;
virtual const QIcon& buttonIcon(const QPropertyTree* tree, int index) const override;
virtual bool usePathEllipsis() const override { return true; }
string valueAsString() const;
void serializeValue(Serialization::IArchive& ar);
void redraw(const PropertyDrawContext& context);
bool onContextMenu(QMenu& menu, QPropertyTree* tree);
bool pickResource(QPropertyTree* tree);
const char* typeNameForFilter([[maybe_unused]] QPropertyTree* tree) const override { return !type_.empty() ? type_.c_str() : "ResourceSelector"; }
bool processesKey(QPropertyTree* tree, const QKeyEvent* ev) override;
bool onKeyDown(QPropertyTree* tree, const QKeyEvent* ev) override;
private:
SResourceSelectorContext context_;
Serialization::INavigationProvider* provider_;
const void* searchHandle_;
Serialization::TypeID wrappedType_;
QIcon icon_;
string type_;
string value_;
string defaultPath_;
int id_;
};
struct ResourceSelectorMenuHandler
: PropertyRowMenuHandler
{
Q_OBJECT
public:
QPropertyTree * tree;
PropertyRowResourceSelector* self;
ResourceSelectorMenuHandler(QPropertyTree* tree, PropertyRowResourceSelector* container);
public slots:
void onMenuCreateFile();
void onMenuJumpTo();
void onMenuClear();
void onMenuPickResource();
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWRESOURCESELECTOR_H
@@ -0,0 +1,521 @@
/*
* 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 "Serialization/ClassFactory.h"
#include "PropertyTreeModel.h"
#include "PropertyRowNumber.h"
#include "MathUtils.h"
#include <QKeyEvent>
#include <QStyleOption>
#include <QStyleOptionSlider>
#include <QPainter>
#include "QPropertyTree.h"
#include "PropertyRow.h"
#include "PropertyDrawContext.h"
#include "Serialization.h"
#include "Serialization/Decorators/Slider.h"
#include "Serialization/Decorators/SliderImpl.h"
#include <math.h>
using Serialization::SSliderF;
using Serialization::SSliderI;
class PropertyRowSliderF
: public PropertyRowNumberField
{
public:
static const bool Custom = true;
PropertyRowSliderF();
void setValueAndContext(const Serialization::SStruct& ser, Serialization::IArchive& ar) override;
int floorHeight() const override { return 18; }
void redraw(const PropertyDrawContext& context) override;
bool onKeyDown(QPropertyTree* tree, const QKeyEvent* ev) override;
bool onMouseDown(QPropertyTree* tree, QPoint point, bool& changed) override;
void onMouseDrag(const PropertyDragEvent& e) override;
void onMouseUp(QPropertyTree* tree, QPoint point) override;
bool assignTo(const Serialization::SStruct& ser) const override
{
if (ser.size() != sizeof(SSliderF))
{
return false;
}
SSliderF* slider = (SSliderF*)(ser.pointer());
*slider->valuePointer = clamp(localValue_, slider->minLimit, slider->maxLimit);
return true;
}
bool handleMouse(QPropertyTree* tree, QPoint point);
bool setValueFromString(const char* str) override
{
float newValue = aznumeric_cast<float>(atof(str));
if (localValue_ != newValue)
{
localValue_ = newValue;
return true;
}
else
{
return false;
}
}
string valueAsString() const override
{
return numberAsString(localValue_);
}
void startIncrement() override
{
incrementStartValue_ = localValue_;
}
void endIncrement(QPropertyTree* tree) override
{
if (localValue_ != incrementStartValue_)
{
float localValue = localValue_;
localValue_ = incrementStartValue_;
tree->model()->rowAboutToBeChanged(this);
localValue_ = localValue;
tree->model()->rowChanged(this);
}
}
void incrementLog(float screenFraction, [[maybe_unused]] float valueFieldFraction)
{
double startPower = log10(fabs(double(incrementStartValue_) + 1.0)) - 3.0;
double power = startPower + fabs(screenFraction) * 10.0f;
double delta = powf(10.0f, aznumeric_cast<float>(power)) - powf(10.0f, aznumeric_cast<float>(startPower)) + 10.0f * fabsf(screenFraction);
double newValue;
if (screenFraction > 0.0f)
{
newValue = double(incrementStartValue_) + delta;
}
else
{
newValue = double(incrementStartValue_) - delta;
}
if (_isnan(newValue))
{
if (screenFraction > 0.0f)
{
newValue = DBL_MAX;
}
else
{
newValue = -DBL_MAX;
}
}
clampToType(&localValue_, newValue);
}
void serializeValue(Serialization::IArchive& ar)
{
ar(value_.minLimit, "min");
ar(value_.maxLimit, "max");
ar(localValue_, "value");
}
double sliderPosition() const override { return 0.0; }
SSliderF value_;
float localValue_;
float incrementStartValue_;
bool captured_;
};
bool PropertyRowSliderF::handleMouse(QPropertyTree* tree, QPoint point)
{
QStyleOptionSlider slider;
slider.rect = floorRect(tree);
QSlider widgetForContext;
QRect sliderGroove = tree->style()->subControlRect(QStyle::CC_Slider, &slider, QStyle::SC_SliderGroove, &widgetForContext);
QRect sliderHandle = tree->style()->subControlRect(QStyle::CC_Slider, &slider, QStyle::SC_SliderHandle, &widgetForContext);
int sliderLength = sliderGroove.width() - sliderHandle.width();
float valRelative = float(point.x() - (sliderGroove.left() + sliderHandle.width() / 2)) / sliderLength;
if (valRelative < 0.0f)
{
valRelative = 0.0f;
}
if (valRelative > 1.0f)
{
valRelative = 1.0f;
}
float newValue = float(valRelative * (value_.maxLimit - value_.minLimit) + value_.minLimit);
if (newValue != localValue_)
{
localValue_ = newValue;
setMultiValue(false);
return true;
}
else
{
return false;
}
}
bool PropertyRowSliderF::onKeyDown(QPropertyTree* tree, const QKeyEvent* ev)
{
float step = (value_.maxLimit - value_.minLimit) * 0.01f;
if (ev->key() == Qt::Key_Left)
{
tree->model()->rowAboutToBeChanged(this);
localValue_ = clamp(localValue_ - step, value_.minLimit, value_.maxLimit);
tree->model()->rowChanged(this);
return true;
}
if (ev->key() == Qt::Key_Right)
{
tree->model()->rowAboutToBeChanged(this);
localValue_ = clamp(localValue_ + step, value_.minLimit, value_.maxLimit);
tree->model()->rowChanged(this);
return true;
}
return PropertyRowNumberField::onKeyDown(tree, ev);
}
bool PropertyRowSliderF::onMouseDown(QPropertyTree* tree, QPoint point, [[maybe_unused]] bool& changed)
{
if (floorRect(tree).contains(point) && !userReadOnly())
{
tree->model()->rowAboutToBeChanged(this);
if (handleMouse(tree, point))
{
tree->update();
}
captured_ = true;
return true;
}
captured_ = false;
return true;
}
void PropertyRowSliderF::onMouseDrag(const PropertyDragEvent& e)
{
if (!captured_)
{
return;
}
if (userReadOnly())
{
return;
}
if (handleMouse(e.tree, e.pos))
{
e.tree->update();
}
}
void PropertyRowSliderF::onMouseUp(QPropertyTree* tree, QPoint point)
{
if (!captured_)
{
return;
}
handleMouse(tree, point);
tree->model()->rowChanged(this);
}
void PropertyRowSliderF::setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar)
{
value_ = *(SSliderF*)ser.pointer();
localValue_ = *value_.valuePointer;
value_.valuePointer = 0;
}
static void drawSlider(const PropertyDrawContext& context, float relativeVal, bool userReadOnly, bool selected)
{
// Eliminate x-shift offset in the control rect as it triggers a bug in
// Fusion theme, that causes blue area in the slider groove to stand out to
// the right from slider.
int xOffset = context.lineRect.left();
context.painter->translate(xOffset, 0);
QStyleOptionSlider sliderOptions;
sliderOptions.rect = context.lineRect.translated(-xOffset, 0);
sliderOptions.minimum = 0;
QSlider widgetForContext;
QRect sliderGroove = context.tree->style()->subControlRect(QStyle::CC_Slider, &sliderOptions, QStyle::SC_SliderGroove, &widgetForContext);
QRect sliderHandle = context.tree->style()->subControlRect(QStyle::CC_Slider, &sliderOptions, QStyle::SC_SliderHandle, &widgetForContext);
int width = sliderGroove.width() - sliderHandle.width() + 1;
sliderOptions.maximum = width;
sliderOptions.pageStep = width / 100;
sliderOptions.sliderPosition = aznumeric_cast<int>(width * relativeVal);
sliderOptions.state = !userReadOnly ? (QStyle::State_Enabled | (selected ? QStyle::State_HasFocus : QStyle::State())) : QStyle::State();
context.tree->style()->drawComplexControl(QStyle::CC_Slider, &sliderOptions, context.painter, &widgetForContext);
context.painter->translate(-xOffset, 0);
}
void PropertyRowSliderF::redraw(const PropertyDrawContext& context)
{
PropertyRowNumberField::redraw(context);
float val = localValue_;
float valRange = value_.maxLimit - value_.minLimit;
if (valRange == 0.0f)
{
valRange = 0.00001f;
}
float relativeVal = clamp((val - value_.minLimit) / valRange, 0.0f, 1.0f);
drawSlider(context, relativeVal, userReadOnly(), selected());
}
PropertyRowSliderF::PropertyRowSliderF()
: captured_(false)
, localValue_()
, incrementStartValue_()
{
}
DECLARE_SEGMENT(PropertyRowSliderF)
REGISTER_PROPERTY_ROW(SSliderF, PropertyRowSliderF)
// ---------------------------------------------------------------------------
class PropertyRowSliderI
: public PropertyRowNumberField
{
public:
static const bool Custom = true;
PropertyRowSliderI();
void setValueAndContext(const Serialization::SStruct& ser, Serialization::IArchive& ar) override;
int floorHeight() const override { return 18; }
void redraw(const PropertyDrawContext& context) override;
bool onKeyDown(QPropertyTree* tree, const QKeyEvent* ev) override;
bool onMouseDown(QPropertyTree* tree, QPoint point, bool& changed) override;
void onMouseDrag(const PropertyDragEvent& e) override;
void onMouseUp(QPropertyTree* tree, QPoint point) override;
bool assignTo(const Serialization::SStruct& ser) const override
{
if (ser.size() != sizeof(SSliderI))
{
return false;
}
SSliderI* slider = (SSliderI*)(ser.pointer());
*slider->valuePointer = clamp(localValue_, slider->minLimit, slider->maxLimit);
return true;
}
bool handleMouse(QPropertyTree* tree, QPoint point);
bool setValueFromString(const char* str) override
{
int newValue = atoi(str);
if (localValue_ != newValue)
{
localValue_ = newValue;
return true;
}
else
{
return false;
}
}
Serialization::string valueAsString() const override
{
return numberAsString(localValue_);
}
void startIncrement() override
{
incrementStartValue_ = localValue_;
}
void endIncrement(QPropertyTree* tree) override
{
if (localValue_ != incrementStartValue_)
{
int localValue = localValue_;
localValue_ = incrementStartValue_;
tree->model()->rowAboutToBeChanged(this);
localValue_ = localValue;
tree->model()->rowChanged(this);
}
}
void incrementLog(float screenFraction, [[maybe_unused]] float valueFieldFraction)
{
double startPower = log10(fabs(double(incrementStartValue_) + 1.0)) - 3.0;
double power = startPower + fabs(screenFraction) * 10.0f;
double delta = powf(10.0f, aznumeric_cast<float>(power)) - powf(10.0f, aznumeric_cast<float>(startPower)) + 1000.0f * fabsf(screenFraction);
double newValue;
if (screenFraction > 0.0f)
{
newValue = double(incrementStartValue_) + delta;
}
else
{
newValue = double(incrementStartValue_) - delta;
}
if (_isnan(newValue))
{
if (screenFraction > 0.0f)
{
newValue = DBL_MAX;
}
else
{
newValue = -DBL_MAX;
}
}
clampToType(&localValue_, newValue);
}
void serializeValue(Serialization::IArchive& ar)
{
ar(value_.minLimit, "min");
ar(value_.maxLimit, "max");
ar(localValue_, "value");
}
double sliderPosition() const override { return 0.0; }
SSliderI value_;
int localValue_;
int incrementStartValue_;
bool captured_;
};
bool PropertyRowSliderI::handleMouse(QPropertyTree* tree, QPoint point)
{
QStyleOptionSlider slider;
slider.rect = floorRect(tree);
QSlider widgetForContext;
QRect sliderGroove = tree->style()->subControlRect(QStyle::CC_Slider, &slider, QStyle::SC_SliderGroove, &widgetForContext);
QRect sliderHandle = tree->style()->subControlRect(QStyle::CC_Slider, &slider, QStyle::SC_SliderHandle, &widgetForContext);
int sliderLength = sliderGroove.width() - sliderHandle.width();
float valRelative = float(point.x() - (sliderGroove.left() + sliderHandle.width() / 2)) / sliderLength;
if (valRelative < 0.0f)
{
valRelative = 0.0f;
}
if (valRelative > 1.0f)
{
valRelative = 1.0f;
}
int newValue = int(valRelative * (value_.maxLimit - value_.minLimit) + value_.minLimit);
if (newValue != localValue_)
{
localValue_ = newValue;
setMultiValue(false);
return true;
}
else
{
return false;
}
}
bool PropertyRowSliderI::onKeyDown(QPropertyTree* tree, const QKeyEvent* ev)
{
int step = aznumeric_cast<int>((value_.maxLimit - value_.minLimit) * 0.01f);
if (ev->key() == Qt::Key_Left)
{
tree->model()->rowAboutToBeChanged(this);
localValue_ = clamp(localValue_ - step, value_.minLimit, value_.maxLimit);
tree->model()->rowChanged(this);
return true;
}
if (ev->key() == Qt::Key_Right)
{
tree->model()->rowAboutToBeChanged(this);
localValue_ = clamp(localValue_ + step, value_.minLimit, value_.maxLimit);
tree->model()->rowChanged(this);
return true;
}
return PropertyRowNumberField::onKeyDown(tree, ev);
}
bool PropertyRowSliderI::onMouseDown(QPropertyTree* tree, QPoint point, [[maybe_unused]] bool& changed)
{
if (floorRect(tree).contains(point) && !userReadOnly())
{
tree->model()->rowAboutToBeChanged(this);
if (handleMouse(tree, point))
{
tree->update();
}
captured_ = true;
return true;
}
captured_ = false;
return true;
}
void PropertyRowSliderI::onMouseDrag(const PropertyDragEvent& e)
{
if (!captured_)
{
return;
}
if (userReadOnly())
{
return;
}
if (handleMouse(e.tree, e.pos))
{
e.tree->update();
}
}
void PropertyRowSliderI::onMouseUp(QPropertyTree* tree, QPoint point)
{
if (!captured_)
{
return;
}
handleMouse(tree, point);
tree->model()->rowChanged(this);
}
void PropertyRowSliderI::setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar)
{
value_ = *(SSliderI*)ser.pointer();
localValue_ = *value_.valuePointer;
value_.valuePointer = 0;
}
void PropertyRowSliderI::redraw(const PropertyDrawContext& context)
{
PropertyRowNumberField::redraw(context);
int val = localValue_;
int valRange = value_.maxLimit - value_.minLimit;
if (valRange == 0)
{
valRange = 1;
}
float relativeVal = clamp(float(val - value_.minLimit) / valRange, 0.0f, 1.0f);
drawSlider(context, relativeVal, userReadOnly(), selected());
}
PropertyRowSliderI::PropertyRowSliderI()
: captured_(false)
, localValue_()
, incrementStartValue_()
{
}
DECLARE_SEGMENT(PropertyRowSliderI)
REGISTER_PROPERTY_ROW(SSliderI, PropertyRowSliderI)
@@ -0,0 +1,299 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "EditorCommon_precompiled.h"
#include "SpriteBorderEditorCommon.h"
#include "QPropertyTree.h"
#include "PropertyRowField.h"
#include "PropertyRowSprite.h"
#include "PropertyDrawContext.h"
#include "PropertyTreeModel.h"
#include <Serialization/Decorators/Sprite.h>
#include <Serialization/Decorators/SpriteImpl.h>
#include <Serialization/Decorators/IconXPM.h>
#include <QFileDialog>
extern QString AssetRelativePathFromAbsolutePath(const QString& absPath);
bool PropertyRowSprite::onActivateButton(int buttonIndex, const PropertyActivationEvent& ev)
{
Show show = FromButtonIndexToShow( buttonIndex );
if( show == Show::kFilePicker )
{
return showFilePicker( ev );
}
if( show == Show::kSpriteBorderEditor )
{
return showSpriteBorderEditor( ev );
}
// This is to avoid a compiler warning.
// We should NEVER get here.
CRY_ASSERT( 0 );
return false;
}
bool PropertyRowSprite::onActivate(const PropertyActivationEvent& ev)
{
if( PropertyRowField::onActivate( ev ) )
{
// PropertyRowSprite::onActivateButton() has handled this event.
// Nothing else to do.
return true;
}
return showFilePicker( ev );
}
void PropertyRowSprite::setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar)
{
Serialization::Sprite* value = (Serialization::Sprite *)ser.pointer();
m_path = value->m_path->c_str();
}
bool PropertyRowSprite::assignTo(const Serialization::SStruct& ser) const
{
if( ser.size() != sizeof(Serialization::Sprite) )
{
return false;
}
Serialization::Sprite* s = (Serialization::Sprite *)ser.pointer();
*s->m_path = m_path.c_str();
return true;
}
void PropertyRowSprite::serializeValue(Serialization::IArchive& ar)
{
ar(m_path, "path");
ar(m_filter, "filter");
ar(m_startFolder, "startFolder");
}
int PropertyRowSprite::buttonCount() const
{
return ( CanBeEdited() ? 2 : 1 );
}
const QIcon& PropertyRowSprite::buttonIcon(const QPropertyTree* tree, int index) const
{
Show show = FromButtonIndexToShow( index );
if( show == Show::kFilePicker )
{
#include "file_open.xpm"
static QIcon icon = QIcon(QPixmap::fromImage(*tree->_iconCache()->getImageForIcon(Serialization::IconXPM(file_open_xpm))));
return icon;
}
if( show == Show::kSpriteBorderEditor )
{
#include "gear.xpm"
static QIcon icon = QIcon(QPixmap::fromImage(*tree->_iconCache()->getImageForIcon(Serialization::IconXPM(gear_xpm))));
return icon;
}
// This is to avoid a compiler warning.
// We should NEVER get here.
CRY_ASSERT( 0 );
#include "gear.xpm"
static QIcon icon;
return icon;
}
string PropertyRowSprite::valueAsString() const
{
return m_path;
}
void PropertyRowSprite::clear()
{
m_path.clear();
}
bool PropertyRowSprite::onContextMenu(QMenu &menu, QPropertyTree* tree)
{
QAction* action = nullptr;
action = menu.addAction("Clear");
QObject::connect( action,
&QAction::triggered,
tree,
[ this, tree ]
{
Clear( tree );
} );
int buttonIndex = ( buttonCount() - 1 );
action = menu.addAction(buttonIcon(tree, buttonIndex--), "Pick Resource...");
QObject::connect( action,
&QAction::triggered,
tree,
[ this, tree ]
{
PropertyActivationEvent ev;
ev.tree = tree;
showFilePicker( ev );
} );
if( buttonIndex >= 0 )
{
action = menu.addAction(buttonIcon(tree, buttonIndex), "Edit");
QObject::connect( action,
&QAction::triggered,
tree,
[ this, tree ]
{
PropertyActivationEvent ev;
ev.tree = tree;
showSpriteBorderEditor( ev );
} );
}
return true;
}
bool PropertyRowSprite::processesKey(QPropertyTree* tree, const QKeyEvent* ev)
{
if (ev->key() == Qt::Key_Delete)
{
return true;
}
return PropertyRowField::processesKey(tree, ev);
}
bool PropertyRowSprite::onKeyDown(QPropertyTree* tree, const QKeyEvent* ev)
{
if( ev->key() == Qt::Key_Delete )
{
Clear( tree );
return true;
}
return PropertyRowField::onKeyDown(tree, ev);
}
void PropertyRowSprite::Clear(QPropertyTree* tree)
{
tree->model()->rowAboutToBeChanged(this);
clear();
tree->model()->rowChanged(this);
}
bool PropertyRowSprite::showFilePicker(const PropertyActivationEvent& ev)
{
if (ev.reason == ev.REASON_RELEASE)
return false;
// Open the file picker and get the filename the user selects
// (QFileDialog can traverse symlinks and shortcuts)
QString filename = QFileDialog::getOpenFileName(ev.tree,
"Choose file",
QString(),
"*.tif;;*.sprite" );
// Early out.
{
if (filename.isEmpty())
{
// Nothing selected.
return true;
}
QFileInfo fileInfo( filename );
if( ! ( ( fileInfo.suffix() == "tif" ) ||
( fileInfo.suffix() == "sprite" ) ) )
{
// Incompatible files selected.
return true;
}
}
ev.tree->model()->rowAboutToBeChanged(this);
m_path = AssetRelativePathFromAbsolutePath(filename).toStdString().c_str();;
ev.tree->model()->rowChanged(this);
return true;
}
bool PropertyRowSprite::showSpriteBorderEditor(const PropertyActivationEvent& ev)
{
SpriteBorderEditor sbe( m_path.c_str(), ev.tree );
if (sbe.GetHasBeenInitializedProperly())
{
sbe.exec();
return true;
}
return false;
}
bool PropertyRowSprite::CanBeEdited() const
{
return ( ! m_path.empty() );
}
PropertyRowSprite::Show PropertyRowSprite::FromButtonIndexToShow(int index) const
{
bool showFile = false;
bool showGear = false;
if( index )
{
// Second icon from the right.
showFile = true;
}
else
{
// First icon from the right (right-most icon).
if( CanBeEdited() )
{
showGear = true;
}
else
{
showFile = true;
}
}
if( showFile )
{
return Show::kFilePicker;
}
if( showGear )
{
return Show::kSpriteBorderEditor;
}
// This is to avoid a compiler warning.
// We should NEVER get here.
CRY_ASSERT( 0 );
return (Show)0;
}
DECLARE_SEGMENT(PropertyRowSprite)
REGISTER_PROPERTY_ROW(Serialization::Sprite, PropertyRowSprite);
@@ -0,0 +1,70 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWSPRITE_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWSPRITE_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyRowField.h"
#endif
class PropertyRowSprite
: public PropertyRowField
{
public:
void clear();
bool isLeaf() const override{ return true; }
bool isStatic() const override{ return false; }
void setValueAndContext(const Serialization::SStruct& ser, Serialization::IArchive& ar) override;
bool assignTo(const Serialization::SStruct& ser) const override;
bool onActivateButton(int buttonIndex, const PropertyActivationEvent& ev) override;
bool onActivate(const PropertyActivationEvent& ev) override;
int buttonCount() const override;
virtual const QIcon& buttonIcon(const QPropertyTree* tree, int index) const override;
virtual bool usePathEllipsis() const override { return true; }
string valueAsString() const override;
void serializeValue(Serialization::IArchive& ar);
bool onContextMenu(QMenu& menu, QPropertyTree* tree);
bool processesKey(QPropertyTree* tree, const QKeyEvent* ev) override;
bool onKeyDown(QPropertyTree* tree, const QKeyEvent* ev) override;
private:
enum class Show
{
kFilePicker,
kSpriteBorderEditor
};
void Clear(QPropertyTree* tree);
bool showFilePicker(const PropertyActivationEvent& ev);
bool showSpriteBorderEditor(const PropertyActivationEvent& ev);
bool CanBeEdited() const;
Show FromButtonIndexToShow(int index) const;
string m_path;
string m_filter;
string m_startFolder;
int m_flags;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWSPRITE_H
@@ -0,0 +1,87 @@
/*
* 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 <math.h>
#include "PropertyRowString.h"
#include "PropertyTreeModel.h"
#include "PropertyDrawContext.h"
#include "QPropertyTree.h"
#include "Serialization/IArchive.h"
#include "Serialization/ClassFactory.h"
#include <QMenu>
#include "Unicode.h"
// ---------------------------------------------------------------------------
SERIALIZATION_CLASS_NAME(PropertyRow, PropertyRowString, "PropertyRowString", "string");
bool PropertyRowString::assignTo(string& str) const
{
str = fromWideChar(value_.c_str());
return true;
}
bool PropertyRowString::assignTo(wstring& str) const
{
str = value_;
return true;
}
PropertyRowWidget* PropertyRowString::createWidget(QPropertyTree* tree)
{
return new PropertyRowWidgetString(this, tree);
}
bool PropertyRowString::assignToByPointer(void* instance, const Serialization::TypeID& type) const
{
if (type == Serialization::TypeID::get<string>())
{
assignTo(*(string*)instance);
return true;
}
else if (type == Serialization::TypeID::get<wstring>())
{
assignTo(*(wstring*)instance);
return true;
}
return false;
}
string PropertyRowString::valueAsString() const
{
return fromWideChar(value_.c_str());
}
void PropertyRowString::setValue(const wchar_t* str, const void* handle, const Serialization::TypeID& type)
{
value_ = str;
serializer_.setPointer((void*)handle);
serializer_.setType(type);
}
void PropertyRowString::setValue(const char* str, const void* handle, const Serialization::TypeID& type)
{
value_ = toWideChar(str);
serializer_.setPointer((void*)handle);
serializer_.setType(type);
}
void PropertyRowString::serializeValue(Serialization::IArchive& ar)
{
ar(value_, "value", "Value");
}
#include <QPropertyTree/moc_PropertyRowString.cpp>
// vim:ts=4 sw=4:
@@ -0,0 +1,114 @@
/*
* 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_PROPERTYROWSTRING_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWSTRING_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyRowField.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "Unicode.h"
#include "MathUtils.h"
#include <QLineEdit>
#endif
class PropertyRowString
: public PropertyRowField
{
public:
bool isLeaf() const override { return true; }
bool isStatic() const override { return false; }
using PropertyRowField::assignTo;
bool assignTo(string& str) const;
bool assignTo(wstring& str) const;
void setValue(const char* str, const void* handle, const Serialization::TypeID& typeId);
void setValue(const wchar_t* str, const void* handle, const Serialization::TypeID& typeId);
PropertyRowWidget* createWidget(QPropertyTree* tree);
string valueAsString() const;
wstring valueAsWString() const { return value_; }
WidgetPlacement widgetPlacement() const override { return WIDGET_VALUE; }
void serializeValue(Serialization::IArchive& ar) override;
const wstring& value() const{ return value_; }
bool assignToByPointer(void* instance, const Serialization::TypeID& type) const;
protected:
wstring value_;
};
class PropertyRowWidgetString
: public PropertyRowWidget
{
Q_OBJECT
public:
PropertyRowWidgetString(PropertyRowString* row, QPropertyTree* tree)
: PropertyRowWidget(row, tree)
, entry_(new QLineEdit())
, tree_(tree)
{
initialValue_ = QString(fromWideChar(row->value().c_str()).c_str());
entry_->setText(initialValue_);
entry_->selectAll();
connect(entry_.data(), SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
connect(entry_.data(), &QLineEdit::textChanged, this, [this, tree] {
QFontMetrics fm(entry_->font());
int contentWidth = min((int)fm.horizontalAdvance(entry_->text()) + 8, tree->width() - entry_->x());
if (contentWidth > entry_->width())
{
entry_->resize(contentWidth, entry_->height());
}
});
}
~PropertyRowWidgetString()
{
entry_->hide();
entry_->setParent(0);
entry_.take()->deleteLater();
}
void commit()
{
onEditingFinished();
}
QWidget* actualWidget() { return entry_.data(); }
public slots:
void onEditingFinished()
{
PropertyRowString* row = static_cast<PropertyRowString*>(this->row());
if (initialValue_ != entry_->text() || row_->multiValue())
{
model()->rowAboutToBeChanged(row);
vector<wchar_t> str;
QString text = entry_->text();
str.resize(text.size() + 1, L'\0');
if (!text.isEmpty())
{
text.toWCharArray(&str[0]);
}
row->setValue(&str[0], row->searchHandle(), row->typeId());
model()->rowChanged(row);
}
else
{
tree_->_cancelWidget();
}
}
protected:
QPropertyTree* tree_;
QScopedPointer<QLineEdit> entry_;
QString initialValue_;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWSTRING_H
@@ -0,0 +1,42 @@
/*
* 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 "Factory.h"
#include "PropertyRowStringListValue.h"
#include "Serialization/IArchive.h"
#include "Serialization/ClassFactory.h"
using Serialization::StringList;
using Serialization::StringListValue;
REGISTER_PROPERTY_ROW(StringListValue, PropertyRowStringListValue)
PropertyRowWidget * PropertyRowStringListValue::createWidget(QPropertyTree * tree)
{
return new PropertyRowWidgetStringListValue(this, tree);
}
// ---------------------------------------------------------------------------
REGISTER_PROPERTY_ROW(StringListStaticValue, PropertyRowStringListStaticValue)
PropertyRowWidget * PropertyRowStringListStaticValue::createWidget(QPropertyTree * tree)
{
return new PropertyRowWidgetStringListValue(this, tree);
}
DECLARE_SEGMENT(PropertyRowStringList)
#include <QPropertyTree/moc_PropertyRowStringListValue.cpp>
// vim:ts=4 sw=4:
@@ -0,0 +1,303 @@
/*
* 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
@@ -0,0 +1,132 @@
/*
* 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 "PropertyRowTagList.h"
#include "PropertyRowString.h"
#include "QPropertyTree.h"
#include "Serialization/Decorators/TagList.h"
#include "Serialization/ClassFactory.h"
#include "Serialization/IArchive.h"
#include "Serialization/Decorators/TagListImpl.h"
#include <QMenu>
PropertyRowTagList::PropertyRowTagList()
: source_(0)
{
}
PropertyRowTagList::~PropertyRowTagList()
{
if (source_)
{
source_->Release();
}
}
void PropertyRowTagList::generateMenu(QMenu& item, QPropertyTree* tree, [[maybe_unused]] bool addActions)
{
if (userReadOnly() || isFixedSize())
{
return;
}
if (!source_)
{
return;
}
TagListMenuHandler* handler = new TagListMenuHandler();
handler->tree = tree;
handler->row = this;
tree->addMenuHandler(handler);
unsigned int numGroups = source_->GroupCount();
for (unsigned int group = 0; group < numGroups; ++group)
{
unsigned int tagCount = source_->TagCount(group);
if (tagCount == 0)
{
continue;
}
const char* groupName = source_->GroupName(group);
QString title = QString("From ") + groupName;
QMenu* menu = item.addMenu(title);
for (unsigned int tagIndex = 0; tagIndex < tagCount; ++tagIndex)
{
QString str;
str = source_->TagValue(group, tagIndex);
const char* desc = source_->TagDescription(group, tagIndex);
if (desc && desc[0] != '\0')
{
str += "\t";
str += desc;
}
QAction* action = menu->addAction(str);
QString tag = QString::fromLocal8Bit(source_->TagValue(group, tagIndex));
action->setData(QVariant(tag));
QObject::connect(action, SIGNAL(triggered()), handler, SLOT(onMenuAddTag()));
}
}
QAction* action = item.addAction("Add");
action->setData(QVariant(QString()));
QObject::connect(action, SIGNAL(triggered()), handler, SLOT(onMenuAddTag()));
PropertyRowContainer::generateMenu(item, tree, false);
}
void PropertyRowTagList::addTag(const char* tag, QPropertyTree* tree)
{
Serialization::SharedPtr<PropertyRowTagList> ref(this);
PropertyRow* child = addElement(tree, false);
if (child && strcmp(child->typeName(), "string") == 0)
{
PropertyRowString* stringRow = static_cast<PropertyRowString*>(child);
tree->model()->rowAboutToBeChanged(stringRow);
stringRow->setValue(tag, stringRow->searchHandle(), stringRow->typeId());
tree->model()->rowChanged(stringRow);
}
}
void TagListMenuHandler::onMenuAddTag()
{
if (QAction* action = qobject_cast<QAction*>(sender()))
{
QString str = action->data().toString();
row->addTag(str.toLocal8Bit().data(), tree);
}
}
void PropertyRowTagList::setValueAndContext(const Serialization::IContainer& value, Serialization::IArchive& ar)
{
if (source_)
{
source_->Release();
}
source_ = ar.FindContext<ITagSource>();
if (source_)
{
source_->AddRef();
}
PropertyRowContainer::setValueAndContext(value, ar);
}
REGISTER_PROPERTY_ROW(TagList, PropertyRowTagList)
DECLARE_SEGMENT(PropertyRowTagList)
#include <QPropertyTree/moc_PropertyRowTagList.cpp>
@@ -0,0 +1,51 @@
/*
* 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_PROPERTYROWTAGLIST_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWTAGLIST_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "PropertyRowContainer.h"
#endif
struct ITagSource;
class PropertyRowTagList
: public PropertyRowContainer
{
public:
PropertyRowTagList();
~PropertyRowTagList();
void setValueAndContext(const Serialization::IContainer& value, Serialization::IArchive& ar) override;
void generateMenu(QMenu& item, QPropertyTree* tree, bool addActions) override;
void addTag(const char* tag, QPropertyTree* tree);
private:
using PropertyRow::setValueAndContext;
ITagSource* source_;
};
struct TagListMenuHandler
: public PropertyRowMenuHandler
{
Q_OBJECT
public:
PropertyRowTagList * row;
QPropertyTree* tree;
public slots:
void onMenuAddTag();
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYROWTAGLIST_H
@@ -0,0 +1,205 @@
/*
* 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 <QIcon>
#include "Serialization/ClassFactory.h"
#include "PropertyDrawContext.h"
#include "PropertyRowImpl.h"
#include "QPropertyTree.h"
#include "PropertyTreeModel.h"
#include "Serialization.h"
#include "Color.h"
#include "Unicode.h"
#include "Serialization/Decorators/ToggleButton.h"
using Serialization::ToggleButton;
using Serialization::RadioButton;
class PropertyRowToggleButton
: public PropertyRow
{
public:
PropertyRowToggleButton()
: underMouse_(false)
, value_(false)
{
}
bool isLeaf() const{ return true; }
bool isStatic() const{ return false; }
bool isSelectable() const{ return true; }
void setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) override
{
ToggleButton* value = (ToggleButton*)(ser.pointer());
value_ = *value->value;
}
bool assignTo(const Serialization::SStruct& ser) const override
{
ToggleButton* value = (ToggleButton*)(ser.pointer());
*value->value = value_;
return true;
}
wstring valueAsWString() const override { return L""; }
WidgetPlacement widgetPlacement() const override { return WIDGET_INSTEAD_OF_TEXT; }
void serializeValue([[maybe_unused]] Serialization::IArchive& ar) {}
int widgetSizeMin([[maybe_unused]] const QPropertyTree* tree) const override { return 36; }
bool onActivate(const PropertyActivationEvent& e) override
{
if (e.reason == PropertyActivationEvent::REASON_KEYBOARD)
{
value_;
}
return true;
}
bool onMouseDown(QPropertyTree* tree, QPoint point, [[maybe_unused]] bool& changed) override
{
if (widgetRect(tree).contains(point))
{
underMouse_ = true;
pressed_ = true;
tree->update();
return true;
}
return false;
}
void onMouseDrag(const PropertyDragEvent& e) override
{
bool underMouse = widgetRect(e.tree).contains(e.pos);
if (underMouse != underMouse_)
{
underMouse_ = underMouse;
e.tree->update();
}
}
void onMouseUp(QPropertyTree* tree, QPoint point) override
{
if (widgetRect(tree).contains(point))
{
tree->model()->rowAboutToBeChanged(this);
pressed_ = false;
value_ = !value_;
tree->model()->rowChanged(this);
}
}
void redraw(const PropertyDrawContext& context) override
{
QRect rect = context.widgetRect;
wstring text = toWideChar(labelUndecorated());
int buttonFlags = BUTTON_CENTER;
if ((value_ || pressed_) && underMouse_)
{
buttonFlags |= BUTTON_PRESSED;
}
if (selected() || pressed_)
{
buttonFlags |= BUTTON_FOCUSED;
}
if (userReadOnly())
{
buttonFlags |= BUTTON_DISABLED;
}
context.drawButton(rect, text.c_str(), buttonFlags, &context.tree->font());
}
protected:
bool pressed_ : 1;
bool underMouse_ : 1;
bool value_ : 1;
};
class PropertyRowRadioButton
: public PropertyRow
{
public:
bool isLeaf() const override { return true; }
bool isStatic() const override { return false; }
bool isSelectable() const override { return false; }
bool onActivate(const PropertyActivationEvent& e) override
{
if (!m_justSet)
{
e.tree->model()->rowAboutToBeChanged(this);
m_justSet = true;
e.tree->model()->rowChanged(this);
}
return true;
}
void setValueAndContext(const Serialization::SStruct& ser, [[maybe_unused]] Serialization::IArchive& ar) override
{
RadioButton* value = (RadioButton*)(ser.pointer());
m_value = value->buttonValue;
m_toggled = m_value == *value->value;
m_justSet = false;
}
bool assignTo(const Serialization::SStruct& ser) const override
{
if (m_justSet)
{
*((RadioButton*)ser.pointer())->value = m_value;
}
return true;
}
wstring valueAsWString() const override { return L""; }
WidgetPlacement widgetPlacement() const override { return WIDGET_INSTEAD_OF_TEXT; }
void serializeValue(Serialization::IArchive& ar) override
{
bool oldToggled = m_toggled;
ar(m_toggled, "toggled");
if (m_toggled && !oldToggled)
{
m_justSet = true;
}
ar(m_value, "value");
}
int widgetSizeMin([[maybe_unused]] const QPropertyTree* tree) const override { return 40; }
void redraw(const PropertyDrawContext& context)
{
QRect rect = context.widgetRect;
bool pressed = context.m_pressed || m_toggled || m_justSet;
wstring text = toWideChar(labelUndecorated());
int buttonFlags = BUTTON_CENTER;
if (pressed)
{
buttonFlags |= BUTTON_PRESSED;
}
if (selected())
{
buttonFlags |= BUTTON_FOCUSED;
}
if (userReadOnly())
{
buttonFlags |= BUTTON_DISABLED;
}
context.drawButton(rect, text.c_str(), buttonFlags, &context.tree->font());
}
protected:
bool m_toggled;
bool m_justSet;
int m_value;
};
REGISTER_PROPERTY_ROW(ToggleButton, PropertyRowToggleButton);
REGISTER_PROPERTY_ROW(RadioButton, PropertyRowRadioButton);
@@ -0,0 +1,45 @@
/*
* 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_PROPERTYTREEMENUHANDLER_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYTREEMENUHANDLER_H
#pragma once
#include "PropertyRow.h"
struct PropertyTreeMenuHandler
: PropertyRowMenuHandler
{
Q_OBJECT
public:
PropertyRow * row;
QPropertyTree* tree;
string filterName;
string filterValue;
string filterType;
public slots:
void onMenuFilter();
void onMenuFilterByName();
void onMenuFilterByValue();
void onMenuFilterByType();
void onMenuUndo();
void onMenuRedo();
void onMenuCopy();
void onMenuPaste();
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYTREEMENUHANDLER_H
@@ -0,0 +1,443 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "PropertyTreeModel.h"
#include "QPropertyTree.h"
#include "Serialization.h"
#include "Serialization/ClassFactory.h"
#include "Serialization/Callback.h"
PropertyTreeModel::PropertyTreeModel()
: expandLevels_(0)
, undoEnabled_(true)
, fullUndo_(false)
{
clear();
}
PropertyTreeModel::~PropertyTreeModel()
{
root_ = 0;
defaultTypes_.clear();
defaultTypesPoly_.clear();
}
TreePath PropertyTreeModel::pathFromRow(PropertyRow* row)
{
TreePath result;
if(row)
{
while(row->parent()){
int childIndex = row->parent()->childIndex(row);
YASLI_ESCAPE(childIndex >= 0, return TreePath());
result.insert(result.begin(), childIndex);
row = row->parent();
}
}
return result;
}
void PropertyTreeModel::selectRow(PropertyRow* row, bool select, bool exclusive)
{
if(exclusive)
deselectAll();
row->setSelected(select);
Selection::iterator it = std::find(selection_.begin(), selection_.end(), pathFromRow(row));
if(select){
if(it == selection_.end())
selection_.push_back(pathFromRow(row));
setFocusedRow(row);
}
else if(it != selection_.end()){
PropertyRow* it_row = rowFromPath(*it);
YASLI_ASSERT(it_row->refCount() > 0 && it_row->refCount() < 0xFFFF);
selection_.erase(it);
}
}
void PropertyTreeModel::deselectAll()
{
Selection::iterator it;
for(it = selection_.begin(); it != selection_.end(); ++it){
PropertyRow* row = rowFromPath(*it);
row->setSelected(false);
}
selection_.clear();
}
PropertyRow* PropertyTreeModel::rowFromPath(const TreePath& path)
{
PropertyRow* row = root();
if (!root())
return 0;
TreePath::const_iterator it;
for(it = path.begin(); it != path.end(); ++it){
int index = it->index;
if(index < int(row->count()) && index >= 0){
PropertyRow* nextRow = row->childByIndex(index);
if(!nextRow)
return row;
else
row = nextRow;
}
else
return row;
}
return row;
}
void PropertyTreeModel::setSelection(const Selection& selection)
{
deselectAll();
Selection::const_iterator it;
for(it = selection.begin(); it != selection.end(); ++it){
const TreePath& path = *it;
PropertyRow* row = rowFromPath(path);
if(row)
selectRow(row, true, false);
}
}
void PropertyTreeModel::clear()
{
if(root_)
root_->clear();
root_ = 0;
setRoot(new PropertyRow());
root_->setNames("", "root", "");
selection_.clear();
}
void PropertyTreeModel::onUpdated(const PropertyRows& rows, bool needApply)
{
signalUpdated(rows, needApply);
}
void PropertyTreeModel::applyOperator(PropertyTreeOperator* op)
{
YASLI_ESCAPE(op, return);
PropertyRow *dest = rowFromPath(op->path_);
YASLI_ESCAPE(dest && "Unable to apply operator!", return);
if(op->type_ == PropertyTreeOperator::NONE)
return;
YASLI_ESCAPE(op->row_, return);
if(dest->parent())
dest->parent()->replaceAndPreserveState(dest, op->row_, 0);
else{
op->row_->assignRowProperties(root_);
root_ = op->row_;
}
PropertyRow* newRow = op->row_;
op->row_ = 0;
rowChanged(newRow);
}
void PropertyTreeModel::undo()
{
YASLI_ESCAPE(!undoOperators_.empty(), return);
auto op = &undoOperators_.back();
PropertyRow *dest = rowFromPath(op->path_);
PropertyTreeOperator redoOp = getCurrentStateTreeOperator(dest);
applyOperator(op);
undoOperators_.pop_back();
pushRedo(redoOp);
}
void PropertyTreeModel::redo()
{
YASLI_ESCAPE(!redoOperators_.empty(), return);
auto op = &redoOperators_.back();
PropertyRow *dest = rowFromPath(op->path_);
PropertyTreeOperator undoOp = getCurrentStateTreeOperator(dest);
applyOperator(op);
redoOperators_.pop_back();
pushUndo(undoOp);
}
void PropertyTreeModel::clearUndo()
{
undoOperators_.clear();
redoOperators_.clear();
Q_EMIT signalUndoRedoStackChanged(false, false);
}
PropertyTreeModel::UpdateLock PropertyTreeModel::lockUpdate()
{
if(updateLock_)
return updateLock_;
else {
UpdateLock lock = new PropertyTreeModel::LockedUpdate(this);;
updateLock_ = lock;
lock->release();
return lock;
}
}
void PropertyTreeModel::dismissUpdate()
{
if(updateLock_)
updateLock_->dismissUpdate();
}
void PropertyTreeModel::requestUpdate(const PropertyRows& rows, bool apply)
{
if(updateLock_)
updateLock_->requestUpdate(rows, apply);
else
onUpdated(rows, apply);
}
struct RowObtainer {
RowObtainer(std::vector<char>& states) : states_(states) {}
ScanResult operator()(PropertyRow* row)
{
states_.push_back(row->expanded() ? 1 : 0);
return row->expanded() ? SCAN_CHILDREN_SIBLINGS : SCAN_SIBLINGS;
}
protected:
std::vector<char>& states_;
};
struct RowExpander {
RowExpander(const std::vector<char>& states) : states_(states), index_(0) {}
ScanResult operator()(PropertyRow* row, QPropertyTree* tree, [[maybe_unused]] int index)
{
if(size_t(index_) >= states_.size())
return SCAN_FINISHED;
if(states_[index_++]){
if(row->canBeToggled(tree))
row->_setExpanded(true);
return SCAN_CHILDREN_SIBLINGS;
}
else{
row->_setExpanded(false);
return SCAN_SIBLINGS;
}
}
protected:
int index_;
const std::vector<char>& states_;
};
void PropertyTreeModel::Serialize(Serialization::IArchive& ar, QPropertyTree* tree)
{
ar(focusedRow_, "focusedRow", 0);
ar(selection_, "selection", 0);
if (root()) {
std::vector<char> expanded;
if(ar.IsOutput()) {
RowObtainer op(expanded);
root()->scanChildren(op);
}
ar(expanded, "expanded", 0);
if(ar.IsInput()){
Selection sel = selection_;
setSelection(sel);
RowExpander op(expanded);
root()->scanChildren(op, tree);
root()->setLayoutChanged();
root()->setLayoutChangedToChildren();
}
}
}
void PropertyTreeModel::pushUndo(const PropertyTreeOperator& op)
{
PropertyTreeOperator oper = op;
bool handled = false;
signalPushUndo(&oper, &handled);
if(!handled && oper.row_ != 0)
undoOperators_.push_back(oper);
Q_EMIT signalUndoRedoStackChanged(!undoOperators_.empty(), !redoOperators_.empty());
}
void PropertyTreeModel::pushRedo(const PropertyTreeOperator& op)
{
PropertyTreeOperator oper = op;
bool handled = false;
signalPushRedo(&oper, &handled);
if (!handled && oper.row_ != 0)
redoOperators_.push_back(oper);
Q_EMIT signalUndoRedoStackChanged(!undoOperators_.empty(), !redoOperators_.empty());
}
PropertyTreeOperator PropertyTreeModel::getCurrentStateTreeOperator(PropertyRow* row)
{
if (fullUndo_){
if (undoEnabled_){
SharedPtr<PropertyRow> clonedRow = root()->clone(constStrings());
clonedRow->assignRowState(*root(), true);
return PropertyTreeOperator(TreePath(), clonedRow);
}
else{
return PropertyTreeOperator(TreePath(), 0);
}
}
else{
if (undoEnabled_){
SharedPtr<PropertyRow> clonedRow = row->clone(constStrings());
clonedRow->assignRowState(*row, true);
return PropertyTreeOperator(pathFromRow(row), clonedRow);
}
else{
return PropertyTreeOperator(pathFromRow(row), 0);
}
}
}
void PropertyTreeModel::rowAboutToBeChanged(PropertyRow* row)
{
YASLI_ESCAPE(row, return);
pushUndo(getCurrentStateTreeOperator(row));
// clear the redo stack now
redoOperators_.clear();
Q_EMIT signalUndoRedoStackChanged(true, false);
}
void PropertyTreeModel::callRowCallback(PropertyRow* row)
{
PropertyRow* current = row;
while (true) {
Serialization::ICallback* callback = current->callback();
if (callback) {
auto applyFunc = [=](void* arg, [[maybe_unused]] const TypeID& type) {
current->assignToByPointer(arg, callback->Type());
};
callback->Call(applyFunc);
return;
}
current = current->parent();
if (current)
current->handleChildrenChange();
else
break;
}
}
void PropertyTreeModel::rowChanged(PropertyRow* row, bool apply)
{
callRowCallback(row);
YASLI_ESCAPE(row, return);
row->setLabelChanged();
row->setLayoutChanged();
PropertyRow* parentObj = row;
while (parentObj->parent() && !parentObj->isObject())
parentObj = parentObj->parent();
row->setMultiValue(false);
PropertyRows rows;
rows.push_back(parentObj);
requestUpdate(rows, apply);
}
bool PropertyTreeModel::defaultTypeRegistered(const char* typeName) const
{
return defaultTypes_.find(typeName) != defaultTypes_.end();
}
void PropertyTreeModel::addDefaultType(PropertyRow* row, const char* typeName)
{
YASLI_ESCAPE(typeName != 0, return);
defaultTypes_[typeName] = row;
}
PropertyRow* PropertyTreeModel::defaultType(const char* typeName) const
{
DefaultTypes::const_iterator it = defaultTypes_.find(typeName);
YASLI_ESCAPE(it != defaultTypes_.end(), return 0);
return it->second;
}
void PropertyTreeModel::addDefaultType(const TypeID& type, const PropertyDefaultDerivedTypeValue& value)
{
YASLI_ASSERT(type != TypeID());
BaseClass& base = defaultTypesPoly_[type];
for (DerivedTypes::iterator it = base.types.begin(); it != base.types.end(); ++it){
if (it->registeredName == value.registeredName) {
YASLI_ASSERT(it->root == 0);
*it = value;
return;
}
}
base.types.push_back(value);
base.strings.push_back(value.label.c_str());
}
const PropertyDefaultDerivedTypeValue* PropertyTreeModel::defaultType(const TypeID& baseType, int derivedIndex) const
{
DefaultTypesPoly::const_iterator it = defaultTypesPoly_.find(baseType);
YASLI_ESCAPE(it != defaultTypesPoly_.end(), return 0);
const BaseClass& base = it->second;
YASLI_ESCAPE(size_t(derivedIndex) < base.types.size(), return 0);
return &base.types[derivedIndex];
}
bool PropertyTreeModel::defaultTypeRegistered(const TypeID& baseType, const char* derivedRegisteredName) const
{
if (!derivedRegisteredName)
derivedRegisteredName = "";
DefaultTypesPoly::const_iterator it = defaultTypesPoly_.find(baseType);
if (it == defaultTypesPoly_.end())
return false;
const BaseClass& base = it->second;
DerivedTypes::const_iterator dit;
for (dit = base.types.begin(); dit != base.types.end(); ++dit){
if (dit->registeredName == derivedRegisteredName)
return true;
}
return false;
}
const Serialization::StringList& PropertyTreeModel::typeStringList(const TypeID& baseType) const
{
DefaultTypesPoly::const_iterator it = defaultTypesPoly_.find(baseType);
static Serialization::StringList empty;
YASLI_ESCAPE(it != defaultTypesPoly_.end(), return empty);
const BaseClass& base = it->second;
return base.strings;
}
// ----------------------------------------------------------------------------------
bool Serialize(Serialization::IArchive& ar, TreePathLeaf& value, const char* name, const char* label)
{
return ar(value.index, name, label);
}
bool Serialize(Serialization::IArchive& ar, TreeSelection& value, const char* name, const char* label)
{
return ar(static_cast<std::vector<TreePath>&>(value), name, label);
}
#include <QPropertyTree/moc_PropertyTreeModel.cpp>
@@ -0,0 +1,208 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYTREEMODEL_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYTREEMODEL_H
#pragma once
#if !defined(Q_MOC_RUN)
#include <map>
#include "PropertyRow.h"
#include "PropertyTreeOperator.h"
#include "Serialization/Pointers.h"
#endif
using std::vector;
using std::map;
struct TreeSelection : vector<TreePath>
{
bool operator==(const TreeSelection& rhs){
if(size() != rhs.size())
return false;
for(int i = 0; i < int(size()); ++i)
if((*this)[i] != rhs[i])
return false;
return true;
}
};
struct PropertyDefaultDerivedTypeValue
{
string registeredName;
Serialization::SharedPtr<PropertyRow> root;
Serialization::IClassFactory* factory;
int factoryIndex;
std::string label;
PropertyDefaultDerivedTypeValue()
: factoryIndex(-1)
, factory(0)
{
}
};
struct PropertyDefaultTypeValue
{
Serialization::TypeID type;
string registedName;
Serialization::SharedPtr<PropertyRow> root;
Serialization::IClassFactory* factory;
int factoryIndex;
std::string label;
PropertyDefaultTypeValue()
: factoryIndex(-1)
, factory(0)
{
}
};
// ---------------------------------------------------------------------------
class PropertyTreeModel : public QObject
{
Q_OBJECT
public:
class LockedUpdate : public Serialization::RefCounter{
public:
LockedUpdate(PropertyTreeModel* model)
: model_(model)
, apply_(false)
{}
void requestUpdate(const PropertyRows& rows, bool apply) {
for (size_t i = 0; i < rows.size(); ++i) {
PropertyRow* row = rows[i];
if (std::find(rows_.begin(), rows_.end(), row) == rows_.end())
rows_.push_back(row);
}
if (apply)
apply_ = true;
}
void dismissUpdate(){ rows_.clear(); }
~LockedUpdate(){
model_->updateLock_ = 0;
if(!rows_.empty())
model_->signalUpdated(rows_, apply_);
}
protected:
PropertyTreeModel* model_;
PropertyRows rows_;
bool apply_;
};
typedef Serialization::SharedPtr<LockedUpdate> UpdateLock;
typedef TreeSelection Selection;
PropertyTreeModel();
~PropertyTreeModel();
void clear();
bool canUndo() const{ return !undoOperators_.empty(); }
void undo();
bool canRedo() const{ return !redoOperators_.empty(); }
void redo();
void clearUndo();
TreePath pathFromRow(PropertyRow* node);
PropertyRow* rowFromPath(const TreePath& path);
void setFocusedRow(PropertyRow* row) { focusedRow_ = pathFromRow(row); }
PropertyRow* focusedRow() { return rowFromPath(focusedRow_); }
const Selection& selection() const{ return selection_; }
void setSelection(const Selection& selection);
void setRoot(PropertyRow* root) { root_ = root; }
PropertyRow* root() { return root_; }
const PropertyRow* root() const { return root_; }
void Serialize(Serialization::IArchive& ar, QPropertyTree* tree);
UpdateLock lockUpdate();
void requestUpdate(const PropertyRows& rows, bool needApply);
void dismissUpdate();
void selectRow(PropertyRow* row, bool selected, bool exclusive = true);
void deselectAll();
void rowAboutToBeChanged(PropertyRow* row);
void callRowCallback(PropertyRow* row);
void rowChanged(PropertyRow* row, bool apply = true); // be careful: it can destroy 'row'
void setUndoEnabled(bool enabled) { undoEnabled_ = enabled; }
void setFullUndo(bool fullUndo) { fullUndo_ = fullUndo; }
void setExpandLevels(int levels) { expandLevels_ = levels; }
int expandLevels() const{ return expandLevels_; }
void onUpdated(const PropertyRows& rows, bool needApply);
// for defaultArchive
const Serialization::StringList& typeStringList(const Serialization::TypeID& baseType) const;
bool defaultTypeRegistered(const char* typeName) const;
void addDefaultType(PropertyRow* propertyRow, const char* typeName);
PropertyRow* defaultType(const char* typeName) const;
bool defaultTypeRegistered(const Serialization::TypeID& baseType, const char* derivedRegisteredName) const;
void addDefaultType(const Serialization::TypeID& baseType, const PropertyDefaultDerivedTypeValue& value);
const PropertyDefaultDerivedTypeValue* defaultType(const Serialization::TypeID& baseType, int index) const;
ConstStringList* constStrings() { return &constStrings_; }
signals:
void signalUpdated(const PropertyRows& rows, bool needApply);
void signalPushUndo(PropertyTreeOperator* op, bool* result);
void signalPushRedo(PropertyTreeOperator* op, bool* result);
void signalUndoRedoStackChanged(bool undosAvailable, bool redosAvailable);
private:
void applyOperator(PropertyTreeOperator* op);
void pushUndo(const PropertyTreeOperator& op);
void pushRedo(const PropertyTreeOperator& op);
void clearObjectReferences();
PropertyTreeOperator getCurrentStateTreeOperator(PropertyRow* row);
TreePath focusedRow_;
Selection selection_;
Serialization::SharedPtr<PropertyRow> root_;
UpdateLock updateLock_;
typedef std::map<string, Serialization::SharedPtr<PropertyRow> > DefaultTypes;
DefaultTypes defaultTypes_;
typedef vector<PropertyDefaultDerivedTypeValue> DerivedTypes;
struct BaseClass{
Serialization::TypeID type;
std::string name;
Serialization::StringList strings;
DerivedTypes types;
};
typedef map<Serialization::TypeID, BaseClass> DefaultTypesPoly;
DefaultTypesPoly defaultTypesPoly_;
int expandLevels_;
bool undoEnabled_;
bool fullUndo_;
std::vector<PropertyTreeOperator> undoOperators_;
std::vector<PropertyTreeOperator> redoOperators_;
ConstStringList constStrings_;
friend class TreeImpl;
};
bool Serialize(Serialization::IArchive& ar, TreeSelection &selection, const char* name, const char* label);
// vim:ts=4 sw=4:
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYTREEMODEL_H
@@ -0,0 +1,53 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates.
#include "EditorCommon_precompiled.h"
#include "PropertyTreeOperator.h"
#include "PropertyRow.h"
#include "Serialization/Enum.h"
#include "Serialization/STL.h"
#include "Serialization/Pointers.h"
#include "Serialization/IArchive.h"
#include "Serialization/STLImpl.h"
#include "Serialization/PointersImpl.h"
SERIALIZATION_ENUM_BEGIN_NESTED(PropertyTreeOperator, Type, "PropertyTreeOp")
SERIALIZATION_ENUM_VALUE_NESTED(PropertyTreeOperator, REPLACE, "Replace")
SERIALIZATION_ENUM_VALUE_NESTED(PropertyTreeOperator, ADD, "Add")
SERIALIZATION_ENUM_VALUE_NESTED(PropertyTreeOperator, REMOVE, "Remove")
SERIALIZATION_ENUM_END()
PropertyTreeOperator::PropertyTreeOperator(const TreePath& path, PropertyRow* row)
: type_(REPLACE)
, path_(path)
, index_(-1)
, row_(row)
{
}
PropertyTreeOperator::PropertyTreeOperator()
: type_(NONE)
, index_(-1)
{
}
PropertyTreeOperator::~PropertyTreeOperator()
{
}
void PropertyTreeOperator::Serialize(Serialization::IArchive& ar)
{
ar(type_, "type", "Type");
ar(path_, "path", "Path");
ar(row_, "row", "Row");
ar(index_, "index", "Index");
}
@@ -0,0 +1,65 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYTREEOPERATOR_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYTREEOPERATOR_H
#pragma once
#include <vector>
#include "Serialization/Pointers.h"
namespace Serialization{ class IArchive; }
class PropertyRow;
struct TreePathLeaf
{
int index;
TreePathLeaf(int _index = -1)
: index(_index)
{
}
bool operator==(const TreePathLeaf& rhs) const{
return index == rhs.index;
}
bool operator!=(const TreePathLeaf& rhs) const{
return index != rhs.index;
}
};
bool Serialize(Serialization::IArchive& ar, TreePathLeaf& value, const char* name, const char* label);
typedef std::vector<TreePathLeaf> TreePath;
typedef std::vector<TreePath> TreePathes;
class PropertyTreeOperator
{
public:
enum Type{
NONE,
REPLACE,
ADD,
REMOVE
};
PropertyTreeOperator();
~PropertyTreeOperator();
PropertyTreeOperator(const TreePath& path, PropertyRow* row);
void Serialize(Serialization::IArchive& ar);
private:
Type type_;
TreePath path_;
Serialization::SharedPtr<PropertyRow> row_;
int index_;
friend class PropertyTreeModel;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_PROPERTYTREEOPERATOR_H
@@ -0,0 +1,227 @@
/*
* 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 "QPropertyDialog.h"
#include "QPropertyTree.h"
#include "Serialization/IArchive.h"
#include "Serialization/BinArchive.h"
#include "Serialization/JSONIArchive.h"
#include "Serialization/JSONOArchive.h"
#include <QBoxLayout>
#include <QDialogButtonBox>
#include <QDir>
#include <CryPath.h>
#ifndef SERIALIZATION_STANDALONE
#include <CryFile.h>
#include <Include/EditorCoreAPI.h>
#else
namespace PathUtil
{
string GetParentDirectory(const char* path)
{
const char* end = strrchr(path, '/');
if (!end)
{
end = strrchr(path, '\\');
}
if (end)
{
return string(path, end);
}
else
{
return string();
}
}
};
#endif
#ifndef SERIALIZATION_STANDALONE
#include <IEditor.h>
#endif
static string getFullStateFilename(const char* filename)
{
#ifdef SERIALIZATION_STANDALONE
// use current folder
return filename;
#else
string path = GetIEditor()->GetResolvedUserFolder().toUtf8().data();
if (!path.empty() && path[path.size() - 1] != '\\' && path[path.size() - 1] != '/')
{
path.push_back('\\');
}
path += filename;
return path;
#endif
}
bool QPropertyDialog::edit(Serialization::SStruct& ser, const char* title, const char* windowStateFilename, QWidget* parent)
{
QPropertyDialog dialog(parent);
dialog.setSerializer(ser);
dialog.setWindowTitle(QString::fromLocal8Bit(title));
dialog.setWindowStateFilename(windowStateFilename);
return dialog.exec() == QDialog::Accepted;
}
QPropertyDialog::QPropertyDialog(QWidget* parent)
: QDialog(parent)
, m_sizeHint(440, 500)
, m_layout(0)
, m_storeContent(false)
{
connect(this, SIGNAL(accepted()), this, SLOT(onAccepted()));
connect(this, SIGNAL(rejected()), this, SLOT(onRejected()));
setModal(true);
setWindowModality(Qt::ApplicationModal);
m_propertyTree = new QPropertyTree(this);
m_propertyTree->setExpandLevels(1);
m_layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
m_layout->addWidget(m_propertyTree, 1);
QDialogButtonBox* buttons = new QDialogButtonBox(this);
buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
m_layout->addWidget(buttons, 0);
}
QPropertyDialog::~QPropertyDialog()
{
}
void QPropertyDialog::revert()
{
if (m_propertyTree)
{
m_propertyTree->revert();
}
}
void QPropertyDialog::setSerializer(const Serialization::SStruct& ser)
{
if (!m_serializer)
{
m_serializer.reset(new Serialization::SStruct());
}
*m_serializer = ser;
}
void QPropertyDialog::setWindowStateFilename(const char* windowStateFilename)
{
m_windowStateFilename = windowStateFilename;
}
void QPropertyDialog::setSizeHint(const QSize& size)
{
m_sizeHint = size;
}
void QPropertyDialog::setStoreContent(bool storeContent)
{
m_storeContent = storeContent;
}
QSize QPropertyDialog::sizeHint() const
{
return m_sizeHint;
}
void QPropertyDialog::setVisible(bool visible)
{
QDialog::setVisible(visible);
if (visible)
{
string fullStateFilename = getFullStateFilename(m_windowStateFilename.c_str());
if (!fullStateFilename.empty())
{
Serialization::JSONIArchive ia;
if (ia.load(fullStateFilename.c_str()))
{
ia(*this);
}
}
m_backup.reset(new Serialization::BinOArchive());
if (m_serializer && *m_serializer)
{
const Serialization::SStruct& ser = *m_serializer;
(*m_backup)(ser, "backup");
m_propertyTree->attach(*m_serializer);
}
}
}
void QPropertyDialog::onAccepted()
{
string fullStateFilename = getFullStateFilename(m_windowStateFilename.c_str());
if (!fullStateFilename.empty())
{
Serialization::JSONOArchive oa;
oa(*this);
QDir().mkdir(QString::fromLocal8Bit(PathUtil::GetParentDirectory(fullStateFilename.c_str()).c_str()));
oa.save(fullStateFilename.c_str());
}
}
void QPropertyDialog::onRejected()
{
if (m_backup.get() && m_serializer.get() && *m_serializer)
{
// restore previous object state
Serialization::BinIArchive ia;
if (ia.open(m_backup->buffer(), m_backup->length()))
{
const Serialization::SStruct& ser = *m_serializer;
ia(ser, "backup");
}
}
}
void QPropertyDialog::setArchiveContext(Serialization::SContextLink* context)
{
m_propertyTree->setArchiveContext(context);
}
void QPropertyDialog::Serialize(Serialization::IArchive& ar)
{
if (m_storeContent && m_serializer.get())
{
ar(*m_serializer, "content");
}
QByteArray geometry;
if (ar.IsOutput())
{
geometry = saveGeometry();
}
std::vector<char> geometryVec(geometry.begin(), geometry.end());
ar(geometryVec, "geometry");
if (ar.IsInput() && !geometryVec.empty())
{
restoreGeometry(QByteArray(geometryVec.data(), (int)geometryVec.size()));
}
ar(*m_propertyTree, "propertyTree");
}
#include <QPropertyTree/moc_QPropertyDialog.cpp>
@@ -0,0 +1,76 @@
/*
* 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_QPROPERTYDIALOG_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_QPROPERTYDIALOG_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "../EditorCommonAPI.h"
#include "Strings.h"
#include <memory>
#include <QDialog>
#endif
namespace Serialization
{
struct SStruct;
struct SContextLink;
class BinOArchive;
class IArchive;
}
class QPropertyTree;
class QBoxLayout;
class EDITOR_COMMON_API QPropertyDialog
: public QDialog
{
Q_OBJECT
public:
static bool edit(Serialization::SStruct& ser, const char* title, const char* windowStateFilename, QWidget* parent);
QPropertyDialog(QWidget* parent);
~QPropertyDialog();
void setSerializer(const Serialization::SStruct& ser);
void setArchiveContext(Serialization::SContextLink* context);
void setWindowStateFilename(const char* windowStateFilename);
void setSizeHint(const QSize& sizeHint);
void setStoreContent(bool storeContent);
void revert();
QBoxLayout* layout() { return m_layout; }
void Serialize(Serialization::IArchive& ar);
protected slots:
void onAccepted();
void onRejected();
protected:
QSize sizeHint() const override;
void setVisible(bool visible) override;
private:
QPropertyTree* m_propertyTree;
QBoxLayout* m_layout;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
std::unique_ptr<Serialization::SStruct> m_serializer;
std::unique_ptr<Serialization::BinOArchive> m_backup;
string m_windowStateFilename;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
QSize m_sizeHint;
bool m_storeContent;
};
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_QPROPERTYDIALOG_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,528 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_QPROPERTYTREE_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_QPROPERTYTREE_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "../EditorCommonAPI.h"
#include "ConstStringList.h"
#include "ValidatorBlock.h"
#include <string>
#include "Serialization/Serializer.h"
#include "Serialization/IArchive.h"
#include "Serialization/Pointers.h"
#include "Serialization/Object.h"
#include "PropertyRow.h"
#include <QWidget>
#include <vector>
#endif
namespace Serialization
{
struct SContextLink;
class IClassFactory;
}
class QMenu;
class QLineEdit;
class QScrollBar;
struct Color;
class TreeImpl;
class PropertyTreeModel;
class PopupMenuItem;
class PropertyTreeModel;
class PropertyRow;
class PropertyRowWidget;
class PropertyTreeOperator;
class Entry;
struct IconXPMCache;
// ---------------------------------------------------------------------------
struct QPropertyTreeStyle;
struct PropertyTreeConfig
{
bool immediateUpdate;
bool hideUntranslated;
bool showContainerIndices;
bool showContainerIndexLabels;
bool containerIndicesZeroBased;
bool filterWhenType;
int filter;
int sliderUpdateDelay;
int expandLevels;
bool undoEnabled;
bool fullUndo;
bool multiSelection;
bool copyPasteEnabled;
PropertyTreeConfig()
: immediateUpdate(true)
, hideUntranslated(true)
, showContainerIndices(true)
, showContainerIndexLabels(false)
, containerIndicesZeroBased(true)
, filterWhenType(true)
, filter(0)
, sliderUpdateDelay(25)
, undoEnabled(true)
, fullUndo(true)
, multiSelection(true)
, copyPasteEnabled(true)
{
}
};
// ---------------------------------------------------------------------------
struct PropertyRowMenuHandler;
class DragWindow : public QWidget
{
Q_OBJECT
public:
DragWindow(QPropertyTree* tree);
void set(QPropertyTree* tree, PropertyRow* row, const QRect& rowRect);
void setWindowPos(bool visible);
void show();
void move(int deltaX, int deltaY);
void hide();
void drawRow(QPainter& p);
void paintEvent(QPaintEvent* ev);
protected:
bool useLayeredWindows_;
PropertyRow* row_;
QRect rect_;
QPropertyTree* tree_;
QPoint offset_;
};
class EDITOR_COMMON_API QPropertyTree : public QWidget
{
Q_OBJECT
public:
explicit QPropertyTree(QWidget* parent = nullptr);
~QPropertyTree();
// Used to attach an object to a PropertyTree widget. Attached object should implement
// Serialize method. Example of usage:
//
// struct MyType
// {
// void Serialize(Serialization::IArchive& ar);
// };
// MyType object;
//
// propertyTree->attach(Serialization::SStruct(object));
//
// Attached object will be serialized through PropertyOArchive to populate the tree. On
// every input made to the tree attached object will be deserialized through
// PropertyIArchive and serialized back again through PropertyOArchive to make sure that
// tree content is up-to-date.
// Property archives can be identified by calling ar.IsEdit().
// SStruct stores a pointer to an actual object that should either outlive property tree
// or be detached on destruction.
void attach(const Serialization::SStruct& serializer);
// This form attaches an array of SStruct-s. This is used to edit multiple objects
// simultaneously. Only shared properties will be shown (i.e. intersection of all
// properties). Properties with different values will be shown as "..." or a gray
// checkbox.
bool attach(const Serialization::SStructs& serializers);
// Used for two-trees setup. In this case leader tree acts as an outliner, that shows
// top level of the data (either by using setOutlineMode or setting different filter).
// Attached, follower tree then shows properties ot the item selected in the main tree.
// Temporary structures (e.g. created on the stack) should not be used in this mode
// (except for decorators), as this may cause access to deallocated object when
// selecting it in the tree.
void attachPropertyTree(QPropertyTree* propertyTree);
void detachPropertyTree();
void setAutoHideAttachedPropertyTree(bool autoHide);
// Effectively clears the tree.
void detach();
bool attached() const { return !attached_.empty(); }
// Forces serialization of attached object to update properties. Can be used to update
// property tree when attached object was changed for some reason.
void revert();
// Same as revert(), except that it will but interrupt editing or mouse action in
// progress.
void revertNoninterrupting();
// Forces deserialization of attached objects from property items.
void apply(bool continuousUpdate);
// Useful to apply edit boxes that are being edited at the moment.
// May be needed when click on toolbar button doesn't steal the focus, leaving input
// data effectively not saved.
void applyInplaceEditor();
// Reduces width of the tree by removing expansion arrow/plus on the first level of the
// tree (first level is always expanded).
void setCompact(bool compact);
bool compact() const;
// Puts checkboxes into two columns when possible.
void setPackCheckboxes(bool pack);
bool packCheckboxes() const;
// Changes distance between rows, multiplier of row height.
void setRowSpacing(float rowSpacing);
float rowSpacing() const;
// Sets default width of the value column, 0..1 (relative to widget width)
void setValueColumnWidth(float valueColumnWidth);
float valueColumnWidth() const;
// Allows to override background color, useful when placing on tabs or panels that have
// have different background.
void setBackgroundColor(const QColor& color);
const QColor& backgroundColor() const { return backgroundColor_; }
// Set number of levels to be expanded by default. Note that this function should be
// invoked before first call to attach attach() to have an effect.
void setExpandLevels(int levels);
// Can be used to control if container(array) elements have numbered labels.
void setShowContainerIndices(bool showContainerIndices) { config_.showContainerIndices = showContainerIndices; }
bool showContainerIndices() const{ return config_.showContainerIndices; }
// Can be used to control if container(array) elements should prepend the number to the existing label
void setShowContainerIndexLabels(bool showContainerIndexLabels) { config_.showContainerIndexLabels = showContainerIndexLabels; }
bool showContainerIndexLabels() const{ return config_.showContainerIndexLabels; }
// Can be used to control if container(array) elements should be zero- (default) or one-based
void setContainerIndicesZeroBased(bool containerIndicesZeroBased) { config_.containerIndicesZeroBased = containerIndicesZeroBased; }
bool containerIndicesZeroBased() const{ return config_.containerIndicesZeroBased; }
// Allows control of copy/paste functionality
void setCopyPasteEnabled(bool copyPasteEnabled) { config_.copyPasteEnabled = copyPasteEnabled; }
bool copyPasteEnabled() const{ return config_.copyPasteEnabled; }
// Limits the rate at which sliders emit change signal.
void setSliderUpdateDelay(int delayMS) { config_.sliderUpdateDelay = delayMS; }
// Limit number of mouse-movement updates per-frame. Used to prevent large tree updates
// from draining all the idle time.
void setAggregateMouseEvents(bool aggregate) { aggregateMouseEvents_ = aggregate; }
void flushAggregatedMouseEvents();
// Can be used to disable internal undo.
void setUndoEnabled(bool enabled, bool full = false);
// This can be used to disable automatic serialization after each deserialization call.
// May be useful to prevent double-revert when signalChange is connected to some
// external data model, which fires an event that reverts tree automatically.
void setAutoRevert(bool autoRevert) { autoRevert_ = autoRevert; }
// Default size.
void setSizeHint(const QSize& size) { sizeHint_ = size; }
// Sets minimal size of the widget to the size of the visible content of the tree.
void setSizeToContent(bool sizeToContent);
bool sizeToContent() const{ return sizeToContent_; }
// Retrieves size of the content, doesn't require sizeToContent to be set.
QSize contentSize() const{ return contentSize_; }
// When set filtering is started just by typing in the property tree
void setFilterWhenType(bool filterWhenType) { config_.filterWhenType = filterWhenType; }
// Outline mode hides content of the elements of the container (excepted for
// inlined/pulled-up properties). Can be used together with second property
// tree through attachPropertyTree.
void setOutlineMode(bool outlineMode) { outlineMode_ = outlineMode; }
bool outlineMode() const{ return outlineMode_; }
// Hide selection when widget is out of focus. Disables selection for parent of inline items.
void setHideSelection(bool hideSelection) { hideSelection_ = hideSelection; }
bool hideSelection() const{ return hideSelection_; }
// Can be used to disable selection of multiple properties at the same time.
void setMultiSelection(bool multiSelection) { config_.multiSelection = multiSelection; }
bool multiSelection() const{ return config_.multiSelection; }
// Sets head of the context-list. Can be used to pass additional data to nested decorators.
void setArchiveContext(Serialization::SContextLink* context) { archiveContext_ = context; }
// Sets archive filter. Filter is a bit mask stored within archive that can be used to
// affect behavior of serialization. For example one can have two trees that shows
// different portions of the same object.
void setFilter(int filter) { config_.filter = filter; }
// This methods returns array of SStruct-s for all selected properties.
// This is useful for manual implementation of attachPropertyTree behavior
// with type filtering or special logic.
void getSelectionSerializers(Serialization::SStructs* serializers);
// Can be used to select once serialized object(s) in the tree.
bool selectByAddress(const void*, bool keepSelectionIfChildSelected = false);
bool selectByAddresses(const void* const* addresses, size_t addressCount, bool keepSelectionIfChildSelected);
// Can be used to query information about selection in the tree.
bool setSelectedRow(PropertyRow* row);
PropertyRow* selectedRow();
int selectedRowCount() const;
PropertyRow* selectedRowByIndex(int index);
// Reports if serialized data contains errors. Errors are reported
// through IArchive::Error() method.
bool containsErrors() const;
void focusFirstError();
void ensureVisible(PropertyRow* row, bool update = true, bool considerChildren = true);
void expandRow(PropertyRow* row, bool expanded = true, bool updateHeights = true);
// PropertyTreeStyle used to customize visual appearance of the property tree
const QPropertyTreeStyle& treeStyle() const{ return *style_; }
void setTreeStyle(const QPropertyTreeStyle& style);
// Config used to store behavioral settings
const PropertyTreeConfig& config() const{ return config_; }
// Instance of PropertyTree can be serialized. In this case the expansion state
// of the rows and list of selected rows will be saved (not the property values).
void Serialize(Serialization::IArchive& ar);
// OBSOLETE: Serialization::Object will be gone
void attach(const Serialization::Object& object);
int revertObjects(vector<void*> objectAddresses);
bool revertObject(void* objectAddress);
signals:
// Emited for every finished changed of the value. E.g. when you drag a slider,
// signalChanged will be invoked when you release a mouse button.
void signalChanged();
// Used fast-pace changes, like movement of the slider before mouse gets released.
void signalContinuousChange();
// Invoked whenever selection changed.
void signalSelected();
// Invoked after each revert() call (can be caused by user intput).
void signalReverted();
// Invoked before any change is going to occur and can be used to store current version
// of data for own undo stack.
void signalPushUndo();
void signalPushRedo();
// Called before and after serialization is invoked. Can be used to update context list
// in archive.
void signalAboutToSerialize(Serialization::IArchive& ar);
void signalSerialized(Serialization::IArchive& ar);
// OBSOLETE: do not use
void signalObjectChanged(const Serialization::Object& obj);
// Called when visual size of the tree changes, i.e. when things are deserialized and
// and when rows are expanded/collapsed.
void signalSizeChanged();
// Called when undo/redo are triggered via keyboard shortcut
void signalUndo();
void signalRedo();
public slots:
void expandAll(PropertyRow* root = 0);
void collapseAll(PropertyRow* root = 0);
void onAttachedTreeChanged();
public:
// internal methods:
void setFullRowMode(bool fullRowMode);
bool fullRowMode() const;
void setHideUntranslated(bool hideUntranslated) { config_.hideUntranslated = hideUntranslated; }
bool hideUntranslated() const{ return config_.hideUntranslated; }
void setImmediateUpdate(bool immediateUpdate) { config_.immediateUpdate = immediateUpdate; }
bool immediateUpdate() const{ return config_.immediateUpdate; }
int _defaultRowHeight() const { return defaultRowHeight_; }
PropertyTreeModel* model() { return model_.data(); }
const PropertyTreeModel* model() const { return model_.data(); }
QPoint treeSize() const;
int leftBorder() const { return leftBorder_; }
int rightBorder() const { return rightBorder_; }
bool multiSelectable() const { return attachedPropertyTree_ != 0 || config_.multiSelection; }
void expandParents(PropertyRow* row);
bool spawnWidget(PropertyRow* row, bool ignoreReadOnly);
bool getSelectedObject(Serialization::Object* object);
void onSignalChanged() { signalChanged(); }
void onRowSelected(const std::vector<PropertyRow*>& row, bool addSelection, bool adjustCursorPos);
const ValidatorBlock* _validatorBlock() const { return validatorBlock_.data(); }
QPoint _toScreen(QPoint point) const;
void _cancelWidget(){ widget_.reset(); }
void _drawRowLabel(QPainter& p, const wchar_t* text, const QFont* font, const QRect& rect, const QColor& color) const;
void _drawRowValue(QPainter& p, const wchar_t* text, const QFont* font, const QRect& rect, const QColor& color, bool pathEllipsis, bool center) const;
QRect _visibleRect() const;
bool _isDragged(const PropertyRow* row) const;
bool _isCapturedRow(const PropertyRow* row) const;
PropertyRow* _pressedRow() const { return pressedRow_; }
void _setPressedRow(PropertyRow* row) { pressedRow_ = row; }
int _applyTime() const{ return applyTime_; }
int _revertTime() const{ return revertTime_; }
int _updateHeightsTime() const{ return updateHeightsTime_; }
int _paintTime() const{ return paintTime_; }
const QFont& _boldFont() const{ return boldFont_; }
bool hasFocusOrInplaceHasFocus() const;
void addMenuHandler(PropertyRowMenuHandler* handler);
IconXPMCache* _iconCache() const{ return iconCache_.data(); }
public slots:
void onFilterChanged(const QString& str);
protected slots:
void onScroll(int pos);
void onModelUpdated(const PropertyRows& rows, bool apply);
void onModelPushUndo(PropertyTreeOperator* op, bool* handled);
void onModelPushRedo(PropertyTreeOperator* op, bool* handled);
void onMouseStillTimeout();
private:
QPropertyTree(const QPropertyTree&);
QPropertyTree& operator=(const QPropertyTree&);
protected:
class DragController;
enum HitTest{
TREE_HIT_PLUS,
TREE_HIT_TEXT,
TREE_HIT_ROW,
TREE_HIT_NONE
};
PropertyRow* rowByPoint(const QPoint& point);
HitTest hitTest(PropertyRow* row, const QPoint& pointInWindowSpace, const QRect& rowRect);
void onRowMenuDecompose(PropertyRow* row);
void onMouseStill(QPoint point);
QSize sizeHint() const override;
bool event(QEvent* ev) override;
void paintEvent(QPaintEvent* ev) override;
void moveEvent(QMoveEvent* ev) override;
void resizeEvent(QResizeEvent* ev) override;
void mousePressEvent(QMouseEvent* ev) override;
void mouseReleaseEvent(QMouseEvent* ev) override;
void mouseDoubleClickEvent(QMouseEvent* ev) override;
void mouseMoveEvent(QMouseEvent* ev) override;
void wheelEvent(QWheelEvent* ev) override;
void keyPressEvent(QKeyEvent* ev) override;
void focusInEvent(QFocusEvent* ev) override;
void updateArea();
bool toggleRow(PropertyRow* row);
struct RowFilter {
enum Type {
NAME_VALUE,
NAME,
VALUE,
TYPE,
NUM_TYPES
};
string start[NUM_TYPES];
bool tillEnd[NUM_TYPES];
std::vector<string> substrings[NUM_TYPES];
void parse(const char* filter);
bool match(const char* text, Type type, size_t* matchStart, size_t* matchEnd) const;
bool typeRelevant(Type type) const{
return !start[type].empty() || !substrings[type].empty();
}
RowFilter()
{
for (int i = 0; i < NUM_TYPES; ++i)
tillEnd[i] = false;
}
};
QPoint pointToRootSpace(const QPoint& pointInWindowSpace) const;
QPoint pointFromRootSpace(const QPoint& point) const;
void interruptDrag();
void updateHeights(bool recalculateTextSize=false);
void updateValidatorIcons();
bool updateScrollBar();
void applyValidation();
void jumpToNextHiddenValidatorIssue(bool isError, PropertyRow* start);
bool onContextMenu(PropertyRow* row, QMenu& menu);
void clearMenuHandlers();
bool onRowKeyDown(PropertyRow* row, const QKeyEvent* ev);
bool rowProcessesKey(PropertyRow* row, const QKeyEvent* ev);
// points here are specified in root-row space
bool onRowLMBDown(PropertyRow* row, const QRect& rowRect, QPoint point, bool controlPressed, bool shiftPressed);
void onRowLMBUp(PropertyRow* row, const QRect& rowRect, QPoint point);
void onRowRMBDown(PropertyRow* row, const QRect& rowRect, QPoint point);
void onRowMouseMove(PropertyRow* row, const QRect& rowRect, QPoint point);
bool canBePasted(PropertyRow* destination);
bool canBePasted(const char* destinationType);
void setFilterMode(bool inFilterMode);
void startFilter(const char* filter);
void setWidget(PropertyRowWidget* widget);
void _arrangeChildren();
void updateAttachedPropertyTree(bool revert);
void drawFilteredString(QPainter& p, const wchar_t* text, RowFilter::Type type, const QFont* font, const QRect& rect, const QColor& color, bool pathEllipsis, bool center) const;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<PropertyTreeModel> model_;
int cursorX_;
QScopedPointer<PropertyRowWidget> widget_; // in-place widget
vector<PropertyRowMenuHandler*> menuHandlers_;
typedef vector<Serialization::Object> Objects;
Objects attached_;
QPropertyTree* attachedPropertyTree_;
bool autoHideAttachedPropertyTree_;
bool filterMode_;
RowFilter rowFilter_;
QScopedPointer<QLineEdit> filterEntry_;
QScopedPointer<IconXPMCache> iconCache_;
Serialization::SContextLink* archiveContext_;
QScopedPointer<ValidatorBlock> validatorBlock_;
bool outlineMode_;
bool sizeToContent_;
bool hideSelection_;
bool autoRevert_;
bool needUpdate_;
QScrollBar* scrollBar_;
QFont boldFont_;
QColor backgroundColor_;
QRect area_;
int leftBorder_;
int rightBorder_;
QPoint size_;
QPoint offset_;
QSize sizeHint_;
QSize contentSize_;
DragController* dragController_;
Serialization::SharedPtr<PropertyRow> lastSelectedRow_;
QPoint pressPoint_;
QPoint pressDelta_;
bool pointerMovedSincePress_;
QPoint lastStillPosition_;
PropertyRow* capturedRow_;
PropertyRow* pressedRow_;
QTimer* mouseStillTimer_;
bool aggregateMouseEvents_;
int aggregatedMouseEventCount_;
QScopedPointer<QMouseEvent> lastMouseMoveEvent_;
PropertyTreeConfig config_;
QScopedPointer<QPropertyTreeStyle> style_;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
int defaultRowHeight_;
int applyTime_;
int revertTime_;
int updateHeightsTime_;
int paintTime_;
int zoomLevel_;
bool dragCheckMode_;
bool dragCheckValue_;
friend class TreeImpl;
friend class FilterEntry;
friend class DragWindow;
friend struct FilterVisitor;
friend struct PropertyTreeMenuHandler;
};
wstring generateDigest(Serialization::SStruct& ser);
// vim: tw=90:
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_QPROPERTYTREE_H
@@ -0,0 +1,90 @@
/*
* 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.
#pragma once
#include "Serialization.h"
#include "Serialization/Decorators/Range.h"
struct QPropertyTreeStyle
{
bool compact;
bool packCheckboxes;
bool fullRowMode;
bool showHorizontalLines;
bool doNotIndentSecondLevel;
bool groupShadows;
bool groupRectangle;
bool alignLabelsToRight;
float valueColumnWidth;
float rowSpacing;
unsigned char levelShadowOpacity;
float levelIndent;
float firstLevelIndent;
float groupShade;
float sliderSaturation;
QPropertyTreeStyle()
: compact(false)
, packCheckboxes(true)
, fullRowMode(false)
, valueColumnWidth(.59f)
, rowSpacing(1.1f)
, showHorizontalLines(false)
, firstLevelIndent(0.75f)
, levelIndent(0.75f)
, levelShadowOpacity(36)
, doNotIndentSecondLevel(false)
, groupShadows(false)
, sliderSaturation(0.0f)
, groupShade(0.15f)
, groupRectangle(false)
, alignLabelsToRight(false)
{
}
void Serialize(Serialization::IArchive& ar)
{
ar.Doc("Here you can define appearance of QPropertyTree control.");
ar(valueColumnWidth, "valueColumnWidth", "Value Column Width");
ar.Doc("Defines a ratio of the value / name columns. Normalized.");
ar(Serialization::Range(rowSpacing, 0.5f, 3.0f), "rowSpacing", "Row Spacing");
ar.Doc("Height of one row (line) in text-height units.");
ar(alignLabelsToRight, "alignLabelsToRight", "Right Alignment");
ar(Serialization::Range(levelIndent, 0.0f, 3.0f), "levelIndent", "Level Indent");
ar.Doc("Indentation of a every next level in text-height units.");
ar(Serialization::Range(firstLevelIndent, 0.0f, 3.0f), "firstLevelIndent", "First Level Indent");
ar.Doc("Indentation of a very first level in text-height units.");
ar(Serialization::Range(sliderSaturation, 0.0f, 1.0f), "sliderSaturation", "Slider Saturation");
ar(levelShadowOpacity, "levelShadowOpacity", "Level Shadow Opacity");
ar.Doc("Amount of background darkening that gets added to each next nested level.");
ar(compact, "compact", "Compact");
ar.Doc("Compact mode removes expansion pluses from the level and reduces inner padding. Useful for narrowing the widget.");
ar(packCheckboxes, "packCheckboxes", "Pack Checkboxes");
ar.Doc("Arranges checkboxes in two columns, when possible.");
ar(showHorizontalLines, "showHorizontalLines", "Horizontal Lines");
ar.Doc("Show thin line that connects row name with its value.");
ar(doNotIndentSecondLevel, "doNotIndentSecondLevel", "Do not indent second level");
ar(groupShadows, "groupShadows", "Group Shadows");
ar(groupRectangle, "groupRectangle", "Group Rectangle");
ar(Serialization::Range(groupShade, -1.0f, 1.0f), "groupShade", "Group Shade");
ar.Doc("Shade of the group.");
}
};
@@ -0,0 +1,29 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_SERIALIZATION_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_SERIALIZATION_H
#pragma once
#include "Serialization/STL.h"
#include "Serialization/Pointers.h"
#include "Serialization/ClassFactory.h"
#include "Serialization/StringList.h"
#include "Serialization/IArchive.h"
#include "Serialization/BinArchive.h"
using Serialization::IArchive;
using Serialization::SStruct;
using Serialization::TypeID;
using Serialization::SharedPtr;
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_SERIALIZATION_H
@@ -0,0 +1,56 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "EditorCommon_precompiled.h"
#include "SpriteBorderEditorCommon.h"
SlicerEdit::SlicerEdit( SpriteBorder border,
QSize& unscaledPixmapSize,
ISprite* sprite )
: QLineEdit()
, m_manipulator( nullptr )
{
bool isVertical = IsBorderVertical( border );
float totalUnscaledSizeInPixels = aznumeric_cast<float>( isVertical ? unscaledPixmapSize.width() : unscaledPixmapSize.height() );
setPixelPosition( GetBorderValueInPixels( sprite, border, totalUnscaledSizeInPixels ) );
setValidator( new QDoubleValidator( 0.0f, totalUnscaledSizeInPixels, 1 ) );
QObject::connect( this,
&SlicerEdit::editingFinished, this,
[ this, border, sprite, totalUnscaledSizeInPixels ]()
{
float p = text().toFloat();
m_manipulator->setPixelPosition( p );
SetBorderValue( sprite, border, p, totalUnscaledSizeInPixels );
} );
}
void SlicerEdit::SetManipulator(SlicerManipulator* manipulator)
{
m_manipulator = manipulator;
}
void SlicerEdit::setPixelPosition(float p)
{
setText( QString::number( p ) );
}
#include <QPropertyTree/moc_SlicerEdit.cpp>
@@ -0,0 +1,46 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#ifndef CRYINCLUDE_EDITORCOMMON_SLICEREDIT_H
#define CRYINCLUDE_EDITORCOMMON_SLICEREDIT_H
#if !defined(Q_MOC_RUN)
#include <QLineEdit>
#include "SpriteBorderEditorCommon.h"
#endif
class SlicerEdit
: public QLineEdit
{
Q_OBJECT
public:
SlicerEdit( SpriteBorder border,
QSize& unscaledPixmapSize,
ISprite* sprite );
void SetManipulator(SlicerManipulator* manipulator);
void setPixelPosition(float p);
private:
SlicerManipulator* m_manipulator;
};
#endif // CRYINCLUDE_EDITORCOMMON_SLICEREDIT_H
@@ -0,0 +1,143 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "EditorCommon_precompiled.h"
#include "SpriteBorderEditorCommon.h"
#define CRYINCLUDE_EDITORCOMMON_DRAW_SELECTABLE_AREA_OF_SLICERMANIPULATOR ( 0 )
#define CRYINCLUDE_EDITORCOMMON_ARBITRARILY_LARGE_NUMBER ( 10000.0f )
#define CRYINCLUDE_EDITORCOMMON_SLICERMANIPULATOR_WIDTH ( 2.0f )
SlicerManipulator::SlicerManipulator( SpriteBorder border,
QSize& unscaledPixmapSize,
QSize& scaledPixmapSize,
float thicknessInPixels,
ISprite* sprite,
QGraphicsScene* scene )
: QGraphicsRectItem()
, m_border( border )
, m_isVertical( IsBorderVertical( m_border ) )
, m_unscaledPixmapSize( unscaledPixmapSize )
, m_scaledPixmapSize( scaledPixmapSize )
, m_sprite( sprite )
, m_unscaledOverScaledFactor( ( (float)m_unscaledPixmapSize.width() / (float)m_scaledPixmapSize.width() ),
( (float)m_unscaledPixmapSize.height() / (float)m_scaledPixmapSize.height() ) )
, m_scaledOverUnscaledFactor( ( 1.0f / m_unscaledOverScaledFactor.x() ),
( 1.0f / m_unscaledOverScaledFactor.y() ) )
, m_color( Qt::white )
, m_edit( nullptr )
{
setAcceptHoverEvents( true );
scene->addItem( this );
setRect( ( m_isVertical ? - ( thicknessInPixels * 0.5f ) : - CRYINCLUDE_EDITORCOMMON_ARBITRARILY_LARGE_NUMBER ),
( m_isVertical ? - CRYINCLUDE_EDITORCOMMON_ARBITRARILY_LARGE_NUMBER : - ( thicknessInPixels * 0.5f ) ),
( m_isVertical ? thicknessInPixels : ( 3.0f * CRYINCLUDE_EDITORCOMMON_ARBITRARILY_LARGE_NUMBER ) ),
( m_isVertical ? ( 3.0f * CRYINCLUDE_EDITORCOMMON_ARBITRARILY_LARGE_NUMBER ) : thicknessInPixels ) );
setPixelPosition( GetBorderValueInPixels( m_sprite, m_border, aznumeric_cast<float>( m_isVertical ? m_unscaledPixmapSize.width() : m_unscaledPixmapSize.height() ) ) );
setFlag( QGraphicsItem::ItemIsMovable, true );
setFlag( QGraphicsItem::ItemIsSelectable, true ); // This allows using the CTRL key to select multiple manipulators and move them simultaneously.
setFlag( QGraphicsItem::ItemSendsScenePositionChanges, true );
}
void SlicerManipulator::SetEdit( SlicerEdit *edit )
{
m_edit = edit;
}
void SlicerManipulator::paint(QPainter* painter, [[maybe_unused]] const QStyleOptionGraphicsItem* option, [[maybe_unused]] QWidget* widget)
{
#if CRYINCLUDE_EDITORCOMMON_DRAW_SELECTABLE_AREA_OF_SLICERMANIPULATOR
QGraphicsRectItem::paint( painter, option, widget );
#endif // CRYINCLUDE_EDITORCOMMON_DRAW_SELECTABLE_AREA_OF_SLICERMANIPULATOR
QPen pen;
pen.setStyle( isSelected() ? Qt::DashLine : Qt::DotLine );
pen.setWidthF( CRYINCLUDE_EDITORCOMMON_SLICERMANIPULATOR_WIDTH );
// Draw a thin line in the middle of the selectable area.
if( m_isVertical )
{
float x = aznumeric_cast<float>( ( ( rect().left() + rect().right() ) * 0.5f ) - CRYINCLUDE_EDITORCOMMON_SLICERMANIPULATOR_WIDTH );
pen.setColor( m_color );
painter->setPen( pen );
painter->drawLine(aznumeric_cast<int>(x), aznumeric_cast<int>(rect().top()), aznumeric_cast<int>(x), aznumeric_cast<int>(rect().bottom()) );
x += CRYINCLUDE_EDITORCOMMON_SLICERMANIPULATOR_WIDTH;
pen.setColor( Qt::black );
painter->setPen( pen );
painter->drawLine(aznumeric_cast<int>(x), aznumeric_cast<int>(rect().top()), aznumeric_cast<int>(x), aznumeric_cast<int>(rect().bottom()) );
}
else
{
float y = aznumeric_cast<float>( ( ( rect().top() + rect().bottom() ) * 0.5f ) - CRYINCLUDE_EDITORCOMMON_SLICERMANIPULATOR_WIDTH );
pen.setColor( m_color );
painter->setPen( pen );
painter->drawLine(aznumeric_cast<int>(rect().left()), aznumeric_cast<int>(y), aznumeric_cast<int>(rect().right()), aznumeric_cast<int>(y) );
y += CRYINCLUDE_EDITORCOMMON_SLICERMANIPULATOR_WIDTH;
pen.setColor( Qt::black );
painter->setPen( pen );
painter->drawLine(aznumeric_cast<int>(rect().left()), aznumeric_cast<int>(y), aznumeric_cast<int>(rect().right()), aznumeric_cast<int>(y) );
}
}
void SlicerManipulator::setPixelPosition(float p)
{
setPos( ( m_isVertical ? ( p * m_scaledOverUnscaledFactor.x() ) : 0.0f ),
( m_isVertical ? 0.0f : ( p * m_scaledOverUnscaledFactor.y() ) ) );
}
QVariant SlicerManipulator::itemChange(GraphicsItemChange change, const QVariant& value)
{
if( ( change == ItemPositionChange ) &&
scene() )
{
float totalScaledSizeInPixels = aznumeric_cast<float>( m_isVertical ? m_scaledPixmapSize.width() : m_scaledPixmapSize.height() );
float p = clamp_tpl<float>(aznumeric_cast<float>( m_isVertical ? value.toPointF().x() : value.toPointF().y() ),
0.0f,
totalScaledSizeInPixels );
m_edit->setPixelPosition( m_isVertical ? aznumeric_cast<float>( p * m_unscaledOverScaledFactor.x() ) : aznumeric_cast<float>( p * m_unscaledOverScaledFactor.y() ) );
SetBorderValue( m_sprite, m_border, p, totalScaledSizeInPixels );
return QPointF( ( m_isVertical ? p : 0.0f ),
( m_isVertical ? 0.0f : p ) );
}
return QGraphicsItem::itemChange( change, value );
}
void SlicerManipulator::hoverEnterEvent([[maybe_unused]] QGraphicsSceneHoverEvent* event)
{
setCursor( m_isVertical ? Qt::SizeHorCursor : Qt::SizeVerCursor );
m_color = Qt::yellow;
update();
}
void SlicerManipulator::hoverLeaveEvent([[maybe_unused]] QGraphicsSceneHoverEvent* event)
{
setCursor(Qt::ArrowCursor);
m_color = Qt::white;
update();
}
@@ -0,0 +1,58 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#ifndef CRYINCLUDE_EDITORCOMMON_SLICERMANIPULATOR_H
#define CRYINCLUDE_EDITORCOMMON_SLICERMANIPULATOR_H
class SlicerManipulator
: public QGraphicsRectItem
{
public:
SlicerManipulator( SpriteBorder border,
QSize& unscaledPixmapSize,
QSize& scaledPixmapSize,
float thicknessInPixels,
ISprite* sprite,
QGraphicsScene* scene );
void SetEdit(SlicerEdit* edit);
void setPixelPosition(float p);
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant& value) override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent* event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent* event) override;
private:
SpriteBorder m_border;
bool m_isVertical;
QSize m_unscaledPixmapSize;
QSize m_scaledPixmapSize;
ISprite* m_sprite;
QPointF m_unscaledOverScaledFactor;
QPointF m_scaledOverUnscaledFactor;
QColor m_color;
SlicerEdit* m_edit;
};
#endif // CRYINCLUDE_EDITORCOMMON_SLICERMANIPULATOR_H
@@ -0,0 +1,25 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "EditorCommon_precompiled.h"
#include "SpriteBorderEditorCommon.h"
SlicerView::SlicerView(QGraphicsScene* scene, QWidget* parent)
: QGraphicsView( scene, parent )
{
setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
}
@@ -0,0 +1,34 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#ifndef CRYINCLUDE_EDITORCOMMON_SLICERVIEW_H
#define CRYINCLUDE_EDITORCOMMON_SLICERVIEW_H
class SlicerView
: public QGraphicsView
{
public:
SlicerView(QGraphicsScene* scene, QWidget* parent = nullptr);
protected:
// This is intentionally empty.
void scrollContentsBy([[maybe_unused]] int dx, [[maybe_unused]] int dy) override {};
};
#endif // CRYINCLUDE_EDITORCOMMON_SLICERVIEW_H
@@ -0,0 +1,175 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "EditorCommon_precompiled.h"
#include "SpriteBorderEditorCommon.h"
#include <Util/PathUtil.h> // for Getting the game folder
//-------------------------------------------------------------------------------
#define VIEW_WIDTH ( 200 )
#define VIEW_HEIGHT ( 200 )
#define MANIPULATOR_THICKNESS_IN_PIXELS ( 24 )
//-------------------------------------------------------------------------------
SpriteBorderEditor::SpriteBorderEditor(const char* path, QWidget* parent)
: QDialog( parent )
, hasBeenInitializedProperly( true )
{
ISprite* sprite = gEnv->pLyShine->LoadSprite( path );
CRY_ASSERT( sprite );
// The layout.
QGridLayout* outerGrid = new QGridLayout(this);
QGridLayout* innerGrid = new QGridLayout();
outerGrid->addLayout( innerGrid, 0, 0, 1, 2 );
// The scene.
QGraphicsScene* scene( new QGraphicsScene( 0.0f, 0.0f, VIEW_WIDTH, VIEW_HEIGHT, this ) );
// The view.
innerGrid->addWidget( new SlicerView( scene, this ), 0, 0, 6, 1 );
// The image.
QGraphicsPixmapItem* pixmapItem = nullptr;
QSize unscaledPixmapSize;
QSize scaledPixmapSize;
{
// assets can be in gems as well as in the current project. Qpixmap requires a path to
// the asset and doesn't know about such concepts. So adjust the pathname to something
// that Qpixmap can open.
QString fullPath = Path::GamePathToFullPath(sprite->GetTexturePathname().c_str());
QPixmap unscaledPixmap(fullPath);
bool isVertical = ( unscaledPixmap.size().height() > unscaledPixmap.size().width() );
// Scale-to-fit, while preserving aspect ratio.
pixmapItem = scene->addPixmap( isVertical ? unscaledPixmap.scaledToHeight( VIEW_HEIGHT ) : unscaledPixmap.scaledToWidth( VIEW_WIDTH ) );
unscaledPixmapSize = unscaledPixmap.size();
scaledPixmapSize = pixmapItem->pixmap().size();
}
// Add text fields and manipulators.
{
int row = 0;
innerGrid->addWidget( new QLabel( QString( "Texture is %1 x %2" ).arg( QString::number( unscaledPixmapSize.width() ),
QString::number( unscaledPixmapSize.height() ) ),
this ),
row++,
1 );
for( SpriteBorder b : SpriteBorder() )
{
SlicerEdit* edit = new SlicerEdit( b,
unscaledPixmapSize,
sprite );
SlicerManipulator* manipulator = new SlicerManipulator( b,
unscaledPixmapSize,
scaledPixmapSize,
MANIPULATOR_THICKNESS_IN_PIXELS,
sprite,
scene );
edit->SetManipulator( manipulator );
manipulator->SetEdit( edit );
innerGrid->addWidget( new QLabel( SpriteBorderToString( b ), this ), row, 1 );
innerGrid->addWidget( edit, row, 2 );
innerGrid->addWidget( new QLabel( "pixels", this ), row, 3 );
++row;
}
}
// Add buttons.
{
// Save button.
QPushButton* saveButton = new QPushButton( "Save", this );
QObject::connect( saveButton,
&QPushButton::clicked, this,
[ this, sprite ]([[maybe_unused]] bool checked )
{
// Sanitize values.
//
// This is the simplest way to sanitize the
// border values. Otherwise, we need to prevent
// flipping the manipulators in the UI.
{
ISprite::Borders b = sprite->GetBorders();
if( b.m_top > b.m_bottom )
{
std::swap( b.m_top, b.m_bottom );
}
if( b.m_left > b.m_right )
{
std::swap( b.m_left, b.m_right );
}
sprite->SetBorders( b );
}
QString fullPath = Path::GamePathToFullPath(sprite->GetPathname().c_str());
bool result = sprite->SaveToXml(fullPath.toUtf8().data());
if (result)
{
close();
}
else
{
QMessageBox box(QMessageBox::Critical,
"Error",
"Unable to save file",
QMessageBox::Ok);
box.exec();
}
} );
outerGrid->addWidget( saveButton, 1, 0 );
// Cancel button.
ISprite::Borders originalBorders = sprite->GetBorders();
QPushButton* cancelButton = new QPushButton( "Cancel", this );
QObject::connect( cancelButton,
&QPushButton::clicked, this,
[ this, sprite, originalBorders ]([[maybe_unused]] bool checked )
{
// Restore original borders.
sprite->SetBorders( originalBorders );
close();
} );
outerGrid->addWidget( cancelButton, 1, 1 );
}
setWindowTitle( "SpriteBorderEditor" );
setModal( true );
setWindowModality( Qt::ApplicationModal );
layout()->setSizeConstraint( QLayout::SetFixedSize );
}
bool SpriteBorderEditor::GetHasBeenInitializedProperly()
{
return hasBeenInitializedProperly;
}
#include <QPropertyTree/moc_SpriteBorderEditor.cpp>
@@ -0,0 +1,41 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#ifndef CRYINCLUDE_EDITORCOMMON_SPRITEBORDEREDITOR_H
#define CRYINCLUDE_EDITORCOMMON_SPRITEBORDEREDITOR_H
#if !defined(Q_MOC_RUN)
#include <QDialog>
#endif
class SpriteBorderEditor
: public QDialog
{
Q_OBJECT
public:
SpriteBorderEditor(const char* path, QWidget* parent = nullptr);
bool GetHasBeenInitializedProperly();
private:
bool hasBeenInitializedProperly;
};
#endif // CRYINCLUDE_EDITORCOMMON_SPRITEBORDEREDITOR_H
@@ -0,0 +1,120 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "EditorCommon_precompiled.h"
#include "SpriteBorderEditorCommon.h"
bool IsBorderVertical(SpriteBorder border)
{
return ( ( border == SpriteBorder::Left ) ||
( border == SpriteBorder::Right ) );
}
float GetBorderValueInPixels(ISprite* sprite, SpriteBorder b, float totalSizeInPixels)
{
// IMPORTANT: We CAN'T replace totalSizeInPixels with
// sprite->GetTexture()->GetWidth()/GetHeight() because
// it DOESN'T return the original texture file's size.
ISprite::Borders sb = sprite->GetBorders();
float *f = nullptr;
if( b == SpriteBorder::Top )
{
f = &sb.m_top;
}
else if( b == SpriteBorder::Bottom )
{
f = &sb.m_bottom;
}
else if( b == SpriteBorder::Left )
{
f = &sb.m_left;
}
else if( b == SpriteBorder::Right )
{
f = &sb.m_right;
}
else
{
CRY_ASSERT( 0 );
f = nullptr;
}
return ( *f * totalSizeInPixels );
}
void SetBorderValue(ISprite* sprite, SpriteBorder b, float pixelPosition, float totalSizeInPixels)
{
// IMPORTANT: We CAN'T replace totalSizeInPixels with
// sprite->GetTexture()->GetWidth()/GetHeight() because
// it DOESN'T return the original texture file's size.
ISprite::Borders sb = sprite->GetBorders();
float *f = nullptr;
if( b == SpriteBorder::Top )
{
f = &sb.m_top;
}
else if( b == SpriteBorder::Bottom )
{
f = &sb.m_bottom;
}
else if( b == SpriteBorder::Left )
{
f = &sb.m_left;
}
else if( b == SpriteBorder::Right )
{
f = &sb.m_right;
}
else
{
CRY_ASSERT( 0 );
f = nullptr;
}
*f = ( pixelPosition / totalSizeInPixels );
sprite->SetBorders( sb );
}
const char* SpriteBorderToString(SpriteBorder b)
{
if( b == SpriteBorder::Top )
{
return "Top";
}
else if( b == SpriteBorder::Bottom )
{
return "Bottom";
}
else if( b == SpriteBorder::Left )
{
return "Left";
}
else if( b == SpriteBorder::Right )
{
return "Right";
}
else
{
CRY_ASSERT( 0 );
return "UNKNOWN";
}
}
@@ -0,0 +1,78 @@
//-------------------------------------------------------------------------------
// Copyright (C) Amazon.com, Inc. or its affiliates.
// All Rights Reserved.
//
// Licensed under the terms set out in the LICENSE.HTML file included at the
// root of the distribution; you may not use this file except in compliance
// with the License.
//
// Do not remove or modify this notice or the LICENSE.HTML file. This file
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// either express or implied. See the License for the specific language
// governing permissions and limitations under the License.
//-------------------------------------------------------------------------------
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#ifndef CRYINCLUDE_EDITORCOMMON_SPRITEBORDEREDITORCOMMON_H
#define CRYINCLUDE_EDITORCOMMON_SPRITEBORDEREDITORCOMMON_H
#include <vector> // required to be included before platform.h
#include <platform.h>
#include <ISystem.h>
#include <IRenderer.h>
#include <IEditor.h>
#include <LyShine/ILyShine.h>
#include <LyShine/ISprite.h>
#include <QDialog>
#include <QDoubleValidator>
#include <QGraphicsRectItem>
#include <QGraphicsView>
#include <QIcon>
#include <QKeyEvent>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QMenu>
#include <QPainter>
#include <QPushButton>
#include <QMessageBox>
class SlicerEdit;
class SlicerManipulator;
class SlicerView;
class SpriteBorderEditor;
enum class SpriteBorder
{
Top,
Bottom,
Left,
Right
};
// This allows iterating over an enum class.
#define ADD_ENUM_CLASS_ITERATION_OPERATORS( CLASS_NAME, FIRST_VALUE, LAST_VALUE ) \
\
inline CLASS_NAME operator++(CLASS_NAME &m){ return m = (CLASS_NAME)(std::underlying_type<CLASS_NAME>::type(m) + 1); } \
inline CLASS_NAME operator*(CLASS_NAME m){ return m; } \
inline CLASS_NAME begin([[maybe_unused]] CLASS_NAME m){ return FIRST_VALUE; } \
inline CLASS_NAME end([[maybe_unused]] CLASS_NAME m){ return (CLASS_NAME)(std::underlying_type<CLASS_NAME>::type(LAST_VALUE) + 1); }
ADD_ENUM_CLASS_ITERATION_OPERATORS( SpriteBorder,
SpriteBorder::Top,
SpriteBorder::Right );
#include "SlicerEdit.h"
#include "SlicerManipulator.h"
#include "SlicerView.h"
#include "SpriteBorderEditor.h"
bool IsBorderVertical(SpriteBorder border);
float GetBorderValueInPixels(ISprite* sprite, SpriteBorder b, float totalSizeInPixels);
void SetBorderValue(ISprite* sprite, SpriteBorder b, float pixelPosition, float totalSizeInPixels);
const char* SpriteBorderToString(SpriteBorder b);
#endif // CRYINCLUDE_EDITORCOMMON_SPRITEBORDEREDITORCOMMON_H
@@ -0,0 +1,29 @@
/*
* 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_STRINGS_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_STRINGS_H
#pragma once
#ifndef SERIALIZATION_STANDALONE
#include <platform.h>
typedef CryStringT<char> string;
typedef CryStringT<wchar_t> wstring;
#else
#include <string>
using std::string;
using std::wstring;
#endif
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_STRINGS_H
@@ -0,0 +1,24 @@
/**
* wWidgets - Lightweight UI Toolkit.
* Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
* Alexander Kotliar <alexander.kotliar@gmail.com>
*
* This code is distributed under the MIT License:
* http://www.opensource.org/licenses/MIT
*/
// Modifications copyright Amazon.com, Inc. or its affiliates
#ifndef CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_UNICODE_H
#define CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_UNICODE_H
#pragma once
#include "Strings.h"
#include <stdio.h>
string fromWideChar(const wchar_t* wideCharString);
wstring toWideChar(const char* multiByteString);
wstring fromANSIToWide(const char* ansiString);
string toANSIFromWide(const wchar_t* wstr);
#endif // CRYINCLUDE_EDITORCOMMON_QPROPERTYTREE_UNICODE_H
@@ -0,0 +1,172 @@
/*
* 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.
#pragma once
#include "Strings.h"
#include <Serialization/TypeID.h>
#include <vector>
#include <algorithm>
enum ValidatorEntryType
{
VALIDATOR_ENTRY_WARNING,
VALIDATOR_ENTRY_ERROR
};
struct ValidatorEntry
{
const void* handle;
Serialization::TypeID typeId;
ValidatorEntryType type;
string message;
bool operator<(const ValidatorEntry& rhs) const
{
if (handle != rhs.handle)
{
return handle < rhs.handle;
}
return typeId < rhs.typeId;
}
ValidatorEntry(ValidatorEntryType type, const void* handle, const Serialization::TypeID& typeId, const char* message)
: type(type)
, handle(handle)
, message(message)
, typeId(typeId)
{
}
ValidatorEntry()
: handle()
, type(VALIDATOR_ENTRY_WARNING)
{
}
};
typedef std::vector<ValidatorEntry> ValidatorEntries;
class ValidatorBlock
{
public:
ValidatorBlock()
: m_enabled(false)
{
}
void Clear()
{
m_entries.clear();
m_used.clear();
}
void AddEntry(const ValidatorEntry& entry)
{
ValidatorEntries::iterator it = std::upper_bound(m_entries.begin(), m_entries.end(), entry);
m_used.insert(m_used.begin() + (it - m_entries.begin()), false);
m_entries.insert(it, entry);
m_enabled = true;
}
bool IsEnabled() const { return m_enabled; }
const ValidatorEntry* GetEntry(int index, int count) const
{
if (size_t(index) >= m_entries.size())
{
return 0;
}
if (size_t(index + count) > m_entries.size())
{
return 0;
}
return &m_entries[index];
}
bool FindHandleEntries(int* outIndex, int* outCount, const void* handle, Serialization::TypeID& typeId)
{
if (handle == 0)
{
return false;
}
ValidatorEntry e;
e.handle = handle;
e.typeId = typeId;
ValidatorEntries::iterator begin = std::lower_bound(m_entries.begin(), m_entries.end(), e);
ValidatorEntries::iterator end = std::upper_bound(m_entries.begin(), m_entries.end(), e);
if (begin != end)
{
*outIndex = int(begin - m_entries.begin());
*outCount = int(end - begin);
return true;
}
return false;
}
void MarkAsUsed(int start, int count)
{
if (start < 0)
{
return;
}
if (start + count > m_entries.size())
{
return;
}
for (int i = start; i < start + count; ++i)
{
m_used[i] = true;
}
}
void MergeUnusedItemsWithRootItems(int* firstUnusedItem, int* count, const void* newHandle, Serialization::TypeID& typeId)
{
size_t numItems = m_used.size();
for (size_t i = 0; i < numItems; ++i)
{
if (m_entries[i].handle == newHandle)
{
m_entries.push_back(m_entries[i]);
m_used.push_back(true);
m_entries[i].typeId = Serialization::TypeID();
}
if (!m_used[i])
{
m_entries.push_back(m_entries[i]);
m_used.push_back(true);
m_entries.back().handle = newHandle;
m_entries.back().typeId = typeId;
}
}
*firstUnusedItem = (int)numItems;
*count = int(m_entries.size() - numItems);
}
bool ContainsErrors() const
{
for (size_t i = 0; i < m_entries.size(); ++i)
{
if (m_entries[i].type == VALIDATOR_ENTRY_ERROR)
{
return true;
}
}
return false;
}
private:
ValidatorEntries m_entries;
std::vector<bool> m_used;
bool m_enabled;
};
@@ -0,0 +1,126 @@
/* XPM */
static const char * error_xpm[] = {
"16 16 107 2",
" c None",
". c #F98267",
"+ c #F78065",
"@ c #F57E63",
"# c #F37C61",
"$ c #F98268",
"% c #EE836E",
"& c #F4A692",
"* c #F8B4A0",
"= c #F3A691",
"- c #E97D68",
"; c #EB7359",
"> c #F88166",
", c #F19784",
"' c #FBBDA9",
") c #F8A38A",
"! c #F6896B",
"~ c #F8A289",
"{ c #FABCA8",
"] c #EC927F",
"^ c #E46C52",
"/ c #F67F65",
"( c #F09783",
"_ c #F58263",
": c #FFFFFF",
"< c #F37E61",
"[ c #F37C60",
"} c #F9B9A6",
"| c #EA8D7B",
"1 c #DE644A",
"2 c #EC816C",
"3 c #F58162",
"4 c #F48062",
"5 c #F17A5F",
"6 c #F0785F",
"7 c #EF765D",
"8 c #F8B5A5",
"9 c #DD705D",
"0 c #F8A188",
"a c #EE735C",
"b c #EC705B",
"c c #F19382",
"d c #EC9889",
"e c #D2583E",
"f c #ED765B",
"g c #F8B6A1",
"h c #F48467",
"i c #EB6E5A",
"j c #EA6C59",
"k c #E96F5F",
"l c #F1A89B",
"m c #CE533A",
"n c #E97157",
"o c #F7B3A0",
"p c #F28065",
"q c #FAD9D3",
"r c #E86958",
"s c #E76757",
"t c #E76C5D",
"u c #F1A599",
"v c #CA4F35",
"w c #E56D52",
"x c #F09F8E",
"y c #F49984",
"z c #F19D90",
"A c #F3AFA6",
"B c #E66556",
"C c #E56255",
"D c #EB897D",
"E c #E79185",
"F c #C64A31",
"G c #E07360",
"H c #F7B3A4",
"I c #E36154",
"J c #E25F53",
"K c #F2A99F",
"L c #D16150",
"M c #DA6046",
"N c #E68878",
"O c #F5B0A3",
"P c #ED9289",
"Q c #EC9288",
"R c #E15D52",
"S c #DD7D6F",
"T c #C0442B",
"U c #D3593F",
"V c #E38475",
"W c #F4ACA1",
"X c #EC8B7F",
"Y c #E4675C",
"Z c #E3665B",
"` c #EA877D",
" . c #F1A89F",
".. c #DD7C6F",
"+. c #BF4329",
"@. c #CC5238",
"#. c #D46452",
"$. c #E79084",
"%. c #EEA095",
"&. c #ED9F95",
"*. c #E58E83",
"=. c #CE5D4C",
"-. c #BD4128",
";. c #C4482F",
">. c #C2462C",
",. c #C0442A",
"'. c #BE4228",
" ",
" . + @ # ",
" $ % & * * = - ; ",
" > , ' ) ! ! ~ { ] ^ ",
" / ( ' _ _ : : < [ } | 1 ",
" 2 ' _ 3 4 : : 5 6 7 8 9 ",
" 5 = 0 4 < [ : : 7 a b c d e ",
" f g h [ 5 6 : : b i j k l m ",
" n o p 6 7 a q : j r s t u v ",
" w x y a b i z A s B C D E F ",
" G H i j r : : C I J K L ",
" M N O s B P Q J R K S T ",
" U V W X Y Z ` ...+. ",
" @.#.$.%.&.*.=.-. ",
" ;.>.,.'. ",
" "};
@@ -0,0 +1,142 @@
/* XPM */
static const char * file_open_xpm[] = {
"16 16 123 2",
" c None",
". c #E0C259",
"+ c #E2C361",
"@ c #E3C463",
"# c #E3C462",
"$ c #E0C056",
"% c #DBB53C",
"& c #FEFEFD",
"* c #FFFFFE",
"= c #FFFEFE",
"- c #FFFEFD",
"; c #FBF7EA",
"> c #E5C86E",
", c #E4C96F",
"' c #E7CF7D",
") c #E8D084",
"! c #DCB441",
"~ c #FEFCF7",
"{ c #F8E48E",
"] c #F5DE91",
"^ c #F5E09F",
"/ c #F6E1AC",
"( c #FEFBEF",
"_ c #FEFDF4",
": c #FEFCF3",
"< c #FEFCF1",
"[ c #FEFBEE",
"} c #FFFDFA",
"| c #E0BC58",
"1 c #DCAE40",
"2 c #FDFAF1",
"3 c #F5DE94",
"4 c #F4DC93",
"5 c #F2D581",
"6 c #EDCA6A",
"7 c #EACB6C",
"8 c #EFD385",
"9 c #EFD280",
"0 c #EFD07A",
"a c #EECF76",
"b c #EECF72",
"c c #FBF7E9",
"d c #DCB23E",
"e c #DBAD39",
"f c #FBF6E8",
"g c #EFD494",
"h c #EECE88",
"i c #E9C173",
"j c #F6E9C9",
"k c #FEFCF2",
"l c #FEFCF0",
"m c #DBAE3C",
"n c #DBA83B",
"o c #FFFDF8",
"p c #FFFDF6",
"q c #FFFCF5",
"r c #FCF6D8",
"s c #F8E694",
"t c #F7E385",
"u c #F6DF76",
"v c #F5DB68",
"w c #F4D85C",
"x c #FCF4D7",
"y c #DBA73B",
"z c #DBA33B",
"A c #FEFCF6",
"B c #FCF2C8",
"C c #FBEFB9",
"D c #FAECAC",
"E c #F9E89C",
"F c #F7E38B",
"G c #F6E07C",
"H c #F6DC6C",
"I c #F5D95D",
"J c #F4D64F",
"K c #F3D344",
"L c #FCF3D0",
"M c #DBA23B",
"N c #DB9D3C",
"O c #FDFAF2",
"P c #FAEDB3",
"Q c #F9E9A4",
"R c #F8E695",
"S c #F7E285",
"T c #F6DE76",
"U c #F5DB65",
"V c #F4D757",
"W c #F3D449",
"X c #F2D13B",
"Y c #F1CE30",
"Z c #FBF2CC",
"` c #DB9B3B",
" . c #DB973B",
".. c #FEFAEF",
"+. c #F9E9A1",
"@. c #F8E591",
"#. c #F7E181",
"$. c #F6DE72",
"%. c #F5DA63",
"&. c #F4D754",
"*. c #F3D347",
"=. c #F2D039",
"-. c #F1CD2E",
";. c #F0CB26",
">. c #FBF2CA",
",. c #DD9947",
"'. c #FAF1DE",
"). c #F4DDA8",
"!. c #F4DB9E",
"~. c #F3DA96",
"{. c #F3D88E",
"]. c #F3D786",
"^. c #F2D47F",
"/. c #F2D379",
"(. c #F1D272",
"_. c #F1D06C",
":. c #F1CF69",
"<. c #F8EAC2",
"[. c #DB953F",
"}. c #DB913E",
"|. c #D98C34",
"1. c #D98B34",
"2. c #DA8F39",
" ",
" ",
" . + @ @ @ # $ ",
" % & * = - * ; > , , , ' ) ",
" ! ~ { ] ^ / ( _ : < ( [ } | ",
" 1 2 3 4 5 6 7 8 9 0 a b c d ",
" e f g h i j k : k l ( [ * m ",
" n * o p q : r s t u v w x y ",
" z A B C D E F G H I J K L M ",
" N O P Q R S T U V W X Y Z ` ",
" N O P Q R S T U V W X Y Z ` ",
" ...+.@.#.$.%.&.*.=.-.;.>. . ",
" ,.'.).!.~.{.].^./.(._.:.<.[. ",
" ,.}.|.|.|.|.|.|.|.|.1.2. ",
" ",
" "};
@@ -0,0 +1,168 @@
/* XPM */
static const char * file_save_xpm[] = {
"16 16 149 2",
" c None",
". c #8DABD9",
"+ c #5E89C9",
"@ c #4375C0",
"# c #3A6EBD",
"$ c #376CBB",
"% c #366BBB",
"& c #366ABB",
"* c #396CBC",
"= c #3B6EBD",
"- c #3A6DBB",
"; c #4474BF",
"> c #658DC9",
", c #85A5D6",
"' c #D1E0F6",
") c #D1E0F7",
"! c #F8FBFE",
"~ c #F7FBFE",
"{ c #F6F9FD",
"] c #F0F5FC",
"^ c #EDF2FB",
"/ c #F7FAFD",
"( c #EBF1FB",
"_ c #DFE9F8",
": c #BED1EC",
"< c #6A92CD",
"[ c #5582C6",
"} c #D1DFF6",
"| c #80AAE9",
"1 c #F6FAFE",
"2 c #F6FAFD",
"3 c #648CC8",
"4 c #EEF3FB",
"5 c #F2F6FC",
"6 c #F1F6FC",
"7 c #E2ECF9",
"8 c #DBE7F8",
"9 c #BAD0EE",
"0 c #BDD0EC",
"a c #4374BD",
"b c #4274C0",
"c c #D0DFF6",
"d c #7EA8E8",
"e c #E9F1FA",
"f c #E8F0FA",
"g c #DDE8F8",
"h c #DBE6F7",
"i c #7AA3E1",
"j c #C3D5EF",
"k c #366AB7",
"l c #CCDDF5",
"m c #7EA8E7",
"n c #668DC9",
"o c #E9F0FA",
"p c #F8FAFE",
"q c #EFF4FC",
"r c #DFE9F9",
"s c #DBE7F7",
"t c #D9E5F7",
"u c #78A2E0",
"v c #A9C2E7",
"w c #3568B6",
"x c #C9DCF4",
"y c #7DA7E7",
"z c #E1ECF9",
"A c #E3EDF9",
"B c #EEF4FC",
"C c #F3F7FD",
"D c #E5EDFA",
"E c #D8E5F6",
"F c #77A0DE",
"G c #A4BEE4",
"H c #3467B4",
"I c #C7D9F4",
"J c #7DA6E6",
"K c #678EC9",
"L c #6C92CB",
"M c #6990CA",
"N c #658CC8",
"O c #749CDA",
"P c #9FBAE1",
"Q c #3466B3",
"R c #C5D8F2",
"S c #7BA4E3",
"T c #7AA3E3",
"U c #7AA4E3",
"V c #7BA4E2",
"W c #7BA3E2",
"X c #79A2E1",
"Y c #77A0DF",
"Z c #769FDE",
"` c #749EDD",
" . c #729CDB",
".. c #749DDC",
"+. c #9AB5DD",
"@. c #3465B1",
"#. c #BED2F0",
"$. c #7AA3E2",
"%. c #7BA3E1",
"&. c #779FDE",
"*. c #769FDD",
"=. c #729BD9",
"-. c #7199D8",
";. c #7099D6",
">. c #8EABD5",
",. c #3363AD",
"'. c #366ABA",
"). c #BBD0EF",
"!. c #7AA2E2",
"~. c #6D96D3",
"{. c #8AA7D2",
"]. c #3262AB",
"^. c #386BBB",
"/. c #B8CEEF",
"(. c #F7FAFE",
"_. c #88C062",
":. c #6A93CF",
"<. c #84A3CE",
"[. c #3261AA",
"}. c #386CBB",
"|. c #B6CCEE",
"1. c #7AA2E1",
"2. c #C2DCBF",
"3. c #6890CD",
"4. c #819ECC",
"5. c #3261A8",
"6. c #386CBA",
"7. c #B3CAED",
"8. c #7AA2E0",
"9. c #658DCA",
"0. c #7C9BC9",
"a. c #3261A7",
"b. c #4F7DC3",
"c. c #ADC6EB",
"d. c #ADC5EA",
"e. c #7C9AC8",
"f. c #7998C7",
"g. c #406BAD",
"h. c #7095CD",
"i. c #4273BD",
"j. c #3568B7",
"k. c #3568B5",
"l. c #3466B2",
"m. c #3364AE",
"n. c #3263AC",
"o. c #3262AA",
"p. c #3261A9",
"q. c #3160A8",
"r. c #3C69AB",
" . + @ # $ % & * = - ; > ",
" , ' ) ! ~ { ] ^ { / ( _ : < ",
" [ } | 1 2 3 4 5 ! 6 7 8 9 0 a ",
" b c d 6 6 3 e / { f g h i j k ",
" # l m f f n o p q r s t u v w ",
" $ x y z z A B C D s t E F G H ",
" % I J 3 > K L M N 3 3 3 O P Q ",
" & R S T U V W X Y Z ` ...+.@.",
" & #.$.$.i W %.&.*...=.-.;.>.,.",
" '.).!.! ! ! ! ! ! ! ! ! ~.{.].",
" ^./.X (._._._._._._._.{ :.<.[.",
" }.|.1.(.2.2.2.2.2.2.2.{ 3.4.5.",
" 6.7.8.(._._._._._._._.{ 9.0.a.",
" b.c.d.! ! ! ! ! ! ! ! ! e.f.g.",
" h.i.j.k.H l.m.n.o.p.q.a.r. ",
" "};
@@ -0,0 +1,24 @@
/* XPM */
static const char * gear_xpm[] = {
/* columns rows colors chars-per-pixel */
"16 16 2 1",
" c #000000",
". c None",
/* pixels */
"....... .......",
"....... .......",
".. .. .. ..",
".. ..",
"... .... ...",
"... ...... ...",
".. ........ ..",
" ........ ",
" ........ ",
".. ........ ..",
"... ...... ...",
"... .... ...",
".. ..",
".. .. .. ..",
"....... .......",
"....... ......."
};
@@ -0,0 +1,49 @@
Portions based on WWidgets and Yasli Serialization Library
wWidgets - Lightweight UI Toolkit.
Copyright (C) 2009-2011 Evgeny Andreeshchev <eugene.andreeshchev@gmail.com>
Alexander Kotliar <alexander.kotliar@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Yasli Serialization Library
Copyright (c) 2007 Eugene Andreeshchev
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,134 @@
/* XPM */
static const char * warning_xpm[] = {
"16 16 115 2",
" c None",
". c #EBBC3C",
"+ c #EABA3A",
"@ c #F1D485",
"# c #F0D182",
"$ c #E7B537",
"% c #E9BA3A",
"& c #FDFAF1",
"* c #FAEFD5",
"= c #E6B235",
"- c #E9B93A",
"; c #F2D894",
"> c #FEFCF3",
", c #FEFAE7",
"' c #F0D38F",
") c #E3AC31",
"! c #E8B738",
"~ c #FFFDF9",
"{ c #F9E994",
"] c #FAEB9E",
"^ c #FEFAEC",
"/ c #E1A92F",
"( c #F4DFA9",
"_ c #FDF9ED",
": c #D6A33E",
"< c #FCF5D4",
"[ c #F1D7A2",
"} c #DEA32B",
"| c #E6B436",
"1 c #EDC871",
"2 c #FFFEF9",
"3 c #F4DC5E",
"4 c #D5A23E",
"5 c #F4D95C",
"6 c #FEFBED",
"7 c #E5BB68",
"8 c #D99924",
"9 c #F7EAC8",
"0 c #FDFAE6",
"a c #F4DA5D",
"b c #D5A13D",
"c c #F2D757",
"d c #FCF3C7",
"e c #F4E3C0",
"f c #E6B336",
"g c #F0D28C",
"h c #FEFBEA",
"i c #F8E694",
"j c #F4DA5C",
"k c #DDB147",
"l c #F2D756",
"m c #F5DB5C",
"n c #FDF8DE",
"o c #E7C07D",
"p c #D48E1D",
"q c #E5B134",
"r c #FEFBF3",
"s c #FBF2C3",
"t c #F6DC5C",
"u c #F6DF64",
"v c #EBCB57",
"w c #F2D655",
"x c #F5D954",
"y c #F8E794",
"z c #FBF4E3",
"A c #D08717",
"B c #E5B034",
"C c #F1D79D",
"D c #FDF9E7",
"E c #F8E58B",
"F c #F6DB5A",
"G c #F4DA5B",
"H c #F2D654",
"I c #F5D852",
"J c #F4D650",
"K c #FCF6D8",
"L c #E5BF88",
"M c #C9790E",
"N c #E3AD31",
"O c #E8BF62",
"P c #FEFCF4",
"Q c #FAEFB5",
"R c #F5DA58",
"S c #F3D857",
"T c #F2D758",
"U c #F2D658",
"V c #F4D957",
"W c #F5D851",
"X c #F4D74E",
"Y c #F6DA62",
"Z c #D29344",
"` c #C36D06",
" . c #F5E3BE",
".. c #FEFBEF",
"+. c #FEFBEE",
"@. c #FEFCEF",
"#. c #FEFBEC",
"$. c #FEFCF2",
"%. c #EBCEAB",
"&. c #C16803",
"*. c #E2AA2F",
"=. c #E0A72D",
"-. c #DFA42B",
";. c #DDA129",
">. c #DC9E27",
",. c #DA9B25",
"'. c #D99823",
"). c #D69320",
"!. c #D38C1B",
"~. c #CF8516",
"{. c #CC7E11",
"]. c #C9770D",
"^. c #C67109",
"/. c #C36C06",
"(. c #BF6400",
" ",
" . + ",
" . @ # $ ",
" % & * = ",
" - ; > , ' ) ",
" ! ~ { ] ^ / ",
" ! ( _ : : < [ } ",
" | 1 2 3 4 4 5 6 7 8 ",
" | 9 0 a b b c d e 8 ",
" f g h i j k b l m n o p ",
" q r s t j u v w x y z A ",
" B C D E F G b b H I J K L M ",
"N O P Q R R S T U V W X Y h Z ` ",
"N .P ..+.+.@.@...+.6 6 #.$.%.&.",
"*.=.-.;.>.,.'.).!.~.{.].^./.&.(.",
" "};