forked from Mirrors/openclonk
Qt Editor: Add user properties
parent
de98bbef46
commit
2a2fc68e3f
|
@ -449,6 +449,12 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="selectionInfoLabel">
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SELECTION</string>
|
||||
</property>
|
||||
|
@ -458,16 +464,16 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="propertyTable">
|
||||
<widget class="QTreeView" name="propertyTable">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::AnyKeyPressed|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<property name="indentation">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -53,7 +53,8 @@ void C4ConsoleQtObjectListModel::Invalidate()
|
|||
|
||||
void C4ConsoleQtObjectListModel::OnItemRemoved(C4PropList *p)
|
||||
{
|
||||
for (auto idx : this->persistentIndexList())
|
||||
QModelIndexList list = this->persistentIndexList();
|
||||
for (auto idx : list)
|
||||
if (idx.internalPointer() == p)
|
||||
this->changePersistentIndex(idx, QModelIndex());
|
||||
Invalidate();
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "editor/C4ConsoleQtPropListViewer.h"
|
||||
#include "editor/C4Console.h"
|
||||
#include "object/C4Object.h"
|
||||
#include "object/C4DefList.h"
|
||||
#include "object/C4Def.h"
|
||||
|
||||
/* Property path for property setting synchronization */
|
||||
|
||||
|
@ -62,15 +64,28 @@ void C4PropertyPath::SetProperty(const C4Value &to_val) const
|
|||
|
||||
/* Property editing */
|
||||
|
||||
C4PropertyDelegate::C4PropertyDelegate(const C4PropertyDelegateFactory *factory, const C4PropList *props)
|
||||
: QObject(), factory(factory)
|
||||
{
|
||||
// Resolve setter callback name
|
||||
if (props) set_function = props->GetPropertyStr(P_Set);
|
||||
}
|
||||
|
||||
void C4PropertyDelegate::UpdateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option) const
|
||||
{
|
||||
editor->setGeometry(option.rect);
|
||||
}
|
||||
|
||||
C4PropertyDelegateInt::C4PropertyDelegateInt(const C4PropertyDelegateFactory *factory, const C4PropList *props)
|
||||
: C4PropertyDelegate(factory)
|
||||
: C4PropertyDelegate(factory, props), min(std::numeric_limits<int32_t>::min()), max(std::numeric_limits<int32_t>::max()), step(1)
|
||||
{
|
||||
// TODO min/max/step
|
||||
if (props)
|
||||
{
|
||||
min = props->GetPropertyInt(P_Min, min);
|
||||
max = props->GetPropertyInt(P_Max, max);
|
||||
step = props->GetPropertyInt(P_Step, step);
|
||||
}
|
||||
}
|
||||
|
||||
void C4PropertyDelegateInt::SetEditorData(QWidget *editor, const C4Value &val) const
|
||||
|
@ -89,48 +104,54 @@ void C4PropertyDelegateInt::SetModelData(QWidget *editor, const C4PropertyPath &
|
|||
QWidget *C4PropertyDelegateInt::CreateEditor(const C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option) const
|
||||
{
|
||||
QSpinBox *editor = new QSpinBox(parent);
|
||||
editor->setMinimum(min);
|
||||
editor->setMaximum(max);
|
||||
editor->setSingleStep(step);
|
||||
connect(editor, &QSpinBox::editingFinished, this, [editor, this]() {
|
||||
emit EditingDoneSignal(editor);
|
||||
});
|
||||
return editor;
|
||||
}
|
||||
|
||||
C4PropertyDelegateEnum::C4PropertyDelegateEnum(const C4PropertyDelegateFactory *factory, int reserve_count)
|
||||
: C4PropertyDelegate(factory)
|
||||
{
|
||||
options.reserve(reserve_count);
|
||||
}
|
||||
|
||||
C4PropertyDelegateEnum::C4PropertyDelegateEnum(const C4PropertyDelegateFactory *factory, const C4ValueArray &props)
|
||||
: C4PropertyDelegate(factory)
|
||||
C4PropertyDelegateEnum::C4PropertyDelegateEnum(const C4PropertyDelegateFactory *factory, const C4PropList *props, const C4ValueArray *poptions)
|
||||
: C4PropertyDelegate(factory, props)
|
||||
{
|
||||
// Build enum options from C4Value definitions in script
|
||||
options.reserve(props.GetSize());
|
||||
for (int32_t i = 0; i < props.GetSize(); ++i)
|
||||
if (!poptions && props) poptions = props->GetPropertyArray(P_Options);
|
||||
if (poptions)
|
||||
{
|
||||
const C4Value &v = props.GetItem(i);
|
||||
const C4PropList *props = v.getPropList();
|
||||
if (!props) continue;
|
||||
Option option;
|
||||
option.name = props->GetPropertyStr(P_Name);
|
||||
if (!option.name.Get()) option.name = ::Strings.RegString("???");
|
||||
option.value_key = props->GetPropertyStr(P_ValueKey);
|
||||
props->GetProperty(P_Value, &option.value);
|
||||
option.type = C4V_Type(props->GetPropertyInt(P_Type, C4V_Any));
|
||||
option.option_key = props->GetPropertyStr(P_OptionKey);
|
||||
// Derive storage type from given elements in delegate definition
|
||||
if (option.type != C4V_Any)
|
||||
option.storage_type = Option::StorageByType;
|
||||
else if (option.option_key.Get())
|
||||
option.storage_type = Option::StorageByKey;
|
||||
else
|
||||
option.storage_type = Option::StorageByValue;
|
||||
// Child delegate for value (resolved at runtime because there may be circular references)
|
||||
props->GetProperty(P_Delegate, &option.adelegate_val);
|
||||
options.push_back(option);
|
||||
options.reserve(poptions->GetSize());
|
||||
for (int32_t i = 0; i < poptions->GetSize(); ++i)
|
||||
{
|
||||
const C4Value &v = poptions->GetItem(i);
|
||||
const C4PropList *props = v.getPropList();
|
||||
if (!props) continue;
|
||||
Option option;
|
||||
option.name = props->GetPropertyStr(P_Name);
|
||||
if (!option.name.Get()) option.name = ::Strings.RegString("???");
|
||||
option.value_key = props->GetPropertyStr(P_ValueKey);
|
||||
props->GetProperty(P_Value, &option.value);
|
||||
option.type = C4V_Type(props->GetPropertyInt(P_Type, C4V_Any));
|
||||
option.option_key = props->GetPropertyStr(P_OptionKey);
|
||||
// Derive storage type from given elements in delegate definition
|
||||
if (option.type != C4V_Any)
|
||||
option.storage_type = Option::StorageByType;
|
||||
else if (option.option_key.Get())
|
||||
option.storage_type = Option::StorageByKey;
|
||||
else
|
||||
option.storage_type = Option::StorageByValue;
|
||||
// Child delegate for value (resolved at runtime because there may be circular references)
|
||||
props->GetProperty(P_Delegate, &option.adelegate_val);
|
||||
options.push_back(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C4PropertyDelegateEnum::ReserveOptions(int32_t num)
|
||||
{
|
||||
options.reserve(num);
|
||||
}
|
||||
|
||||
void C4PropertyDelegateEnum::AddTypeOption(C4String *name, C4V_Type type, const C4Value &val, C4PropertyDelegate *adelegate)
|
||||
{
|
||||
Option option;
|
||||
|
@ -142,6 +163,15 @@ void C4PropertyDelegateEnum::AddTypeOption(C4String *name, C4V_Type type, const
|
|||
options.push_back(option);
|
||||
}
|
||||
|
||||
void C4PropertyDelegateEnum::AddConstOption(C4String *name, const C4Value &val)
|
||||
{
|
||||
Option option;
|
||||
option.name = name;
|
||||
option.value = val;
|
||||
option.storage_type = Option::StorageByValue;
|
||||
options.push_back(option);
|
||||
}
|
||||
|
||||
int32_t C4PropertyDelegateEnum::GetOptionByValue(const C4Value &val) const
|
||||
{
|
||||
int32_t iopt = 0;
|
||||
|
@ -249,7 +279,10 @@ void C4PropertyDelegateEnum::SetModelData(QWidget *aeditor, const C4PropertyPath
|
|||
// Value from a parameter or directly from the enum?
|
||||
if (option.adelegate)
|
||||
{
|
||||
// Value from a parameter?
|
||||
// Value from a parameter.
|
||||
// Using a setter function?
|
||||
if (option.adelegate->GetSetFunction())
|
||||
use_path = C4PropertyPath(use_path, option.adelegate->GetSetFunction(), C4PropertyPath::PPT_SetFunction);
|
||||
option.adelegate->SetModelData(editor->parameter_widget, use_path);
|
||||
}
|
||||
else
|
||||
|
@ -283,10 +316,29 @@ void C4PropertyDelegateEnum::UpdateOptionIndex(C4PropertyDelegateEnum::Editor *e
|
|||
emit EditorValueChangedSignal(editor);
|
||||
}
|
||||
|
||||
C4PropertyDelegateC4ValueEnum::C4PropertyDelegateC4ValueEnum(const C4PropertyDelegateFactory *factory)
|
||||
: C4PropertyDelegateEnum(factory, 10)
|
||||
C4PropertyDelegateDef::C4PropertyDelegateDef(const C4PropertyDelegateFactory *factory, const C4PropList *props)
|
||||
: C4PropertyDelegateEnum(factory, props)
|
||||
{
|
||||
// Collect sorted definitions
|
||||
std::vector<C4Def *> defs = ::Definitions.GetAllDefs(props ? props->GetPropertyStr(P_Filter) : NULL);
|
||||
std::sort(defs.begin(), defs.end(), [](C4Def *a, C4Def *b) -> bool {
|
||||
return strcmp(a->GetName(), b->GetName()) < 0;
|
||||
});
|
||||
// Add them
|
||||
ReserveOptions(defs.size() + 1);
|
||||
AddConstOption(::Strings.RegString("nil"), C4VNull); // nil is always an option
|
||||
for (C4Def *def : defs)
|
||||
{
|
||||
C4RefCntPointer<C4String> option_name = ::Strings.RegString(FormatString("%s (%s)", def->id.ToString(), def->GetName()));
|
||||
AddConstOption(option_name, C4Value(def));
|
||||
}
|
||||
}
|
||||
|
||||
C4PropertyDelegateC4ValueEnum::C4PropertyDelegateC4ValueEnum(const C4PropertyDelegateFactory *factory, const C4PropList *props)
|
||||
: C4PropertyDelegateEnum(factory, props)
|
||||
{
|
||||
// Add default C4Value selections
|
||||
ReserveOptions(10);
|
||||
AddTypeOption(::Strings.RegString("nil"), C4V_Nil, C4VNull);
|
||||
AddTypeOption(::Strings.RegString("bool"), C4V_Bool, C4VNull, factory->GetDelegateByValue(C4VString("bool")));
|
||||
AddTypeOption(::Strings.RegString("int"), C4V_Int, C4VNull, factory->GetDelegateByValue(C4VString("int")));
|
||||
|
@ -349,8 +401,9 @@ C4PropertyDelegate *C4PropertyDelegateFactory::CreateDelegateByString(const C4St
|
|||
if (!str) return NULL;
|
||||
// create default base types
|
||||
if (str->GetData() == "int") return new C4PropertyDelegateInt(this, props);
|
||||
if (str->GetData() == "c4valueenum") return new C4PropertyDelegateC4ValueEnum(this);
|
||||
if (str->GetData() == "any") return new C4PropertyDelegateC4ValueInput(this);
|
||||
if (str->GetData() == "def") return new C4PropertyDelegateDef(this, props);
|
||||
if (str->GetData() == "c4valueenum") return new C4PropertyDelegateC4ValueEnum(this, props);
|
||||
if (str->GetData() == "any") return new C4PropertyDelegateC4ValueInput(this, props);
|
||||
// unknown type
|
||||
return NULL;
|
||||
}
|
||||
|
@ -360,9 +413,9 @@ C4PropertyDelegate *C4PropertyDelegateFactory::CreateDelegateByValue(const C4Val
|
|||
switch (val.GetType())
|
||||
{
|
||||
case C4V_Nil:
|
||||
return new C4PropertyDelegateC4ValueInput(this);
|
||||
return new C4PropertyDelegateC4ValueInput(this, NULL);
|
||||
case C4V_Array:
|
||||
return new C4PropertyDelegateEnum(this, *val.getArray());
|
||||
return new C4PropertyDelegateEnum(this, NULL, val.getArray());
|
||||
case C4V_PropList:
|
||||
{
|
||||
C4PropList *props = val._getPropList();
|
||||
|
@ -438,9 +491,13 @@ void C4PropertyDelegateFactory::setModelData(QWidget *editor, QAbstractItemModel
|
|||
C4PropList *props = prop->parent_proplist->getPropList();
|
||||
if (props)
|
||||
{
|
||||
// Set value view path
|
||||
// Compose set command
|
||||
C4PropertyPath path(prop->parent_proplist->GetDataString().getData());
|
||||
C4PropertyPath subpath(path, prop->name->GetCStr());
|
||||
C4PropertyPath subpath;
|
||||
if (d->GetSetFunction())
|
||||
subpath = C4PropertyPath(path, d->GetSetFunction(), C4PropertyPath::PPT_SetFunction);
|
||||
else
|
||||
subpath = C4PropertyPath(path, prop->name->GetCStr());
|
||||
d->SetModelData(editor, subpath);
|
||||
}
|
||||
}
|
||||
|
@ -470,11 +527,18 @@ void C4PropertyDelegateFactory::updateEditorGeometry(QWidget *editor, const QSty
|
|||
return d->UpdateEditorGeometry(editor, option);
|
||||
}
|
||||
|
||||
QSize C4PropertyDelegateFactory::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
int height = QApplication::fontMetrics().height() + 4;
|
||||
return QSize(100, height);
|
||||
}
|
||||
|
||||
|
||||
/* Proplist table view */
|
||||
|
||||
C4ConsoleQtPropListModel::C4ConsoleQtPropListModel()
|
||||
{
|
||||
header_font.setBold(true);
|
||||
}
|
||||
|
||||
C4ConsoleQtPropListModel::~C4ConsoleQtPropListModel()
|
||||
|
@ -487,19 +551,50 @@ void C4ConsoleQtPropListModel::SetPropList(class C4PropList *new_proplist)
|
|||
proplist.SetPropList(new_proplist);
|
||||
if (new_proplist)
|
||||
{
|
||||
// Always: Internal properties
|
||||
auto new_properties = new_proplist->GetSortedLocalProperties();
|
||||
properties.resize(new_properties.size());
|
||||
internal_properties.resize(new_properties.size());
|
||||
for (int32_t i = 0; i < new_properties.size(); ++i)
|
||||
{
|
||||
properties[i].parent_proplist = &proplist;
|
||||
properties[i].name = new_properties[i];
|
||||
properties[i].delegate_info.Set0();
|
||||
properties[i].delegate = NULL; // init when needed
|
||||
internal_properties[i].parent_proplist = &proplist;
|
||||
internal_properties[i].name = new_properties[i];
|
||||
internal_properties[i].delegate_info.Set0(); // default C4Value delegate
|
||||
internal_properties[i].delegate = NULL; // init when needed
|
||||
internal_properties[i].is_internal = true;
|
||||
}
|
||||
// Objects only: Published properties
|
||||
if (new_proplist->GetObject())
|
||||
{
|
||||
const char *editor_prop_prefix = "EditorProp_";
|
||||
auto new_properties = new_proplist->GetSortedProperties(editor_prop_prefix);
|
||||
published_properties.resize(new_properties.size());
|
||||
for (int32_t i = 0; i < new_properties.size(); ++i)
|
||||
{
|
||||
published_properties[i].parent_proplist = &proplist;
|
||||
published_properties[i].name = NULL;
|
||||
published_properties[i].delegate_info.Set0(); // default C4Value delegate
|
||||
published_properties[i].delegate = NULL; // init when needed
|
||||
published_properties[i].is_internal = false;
|
||||
C4Value published_prop_val;
|
||||
new_proplist->GetPropertyByS(new_properties[i], &published_prop_val);
|
||||
C4PropList *published_prop = published_prop_val.getPropList();
|
||||
if (published_prop)
|
||||
{
|
||||
published_properties[i].name = published_prop->GetPropertyStr(P_Name);
|
||||
published_properties[i].delegate_info.SetPropList(published_prop);
|
||||
}
|
||||
if (!published_properties[i].name) published_properties[i].name = ::Strings.RegString(new_properties[i]->GetCStr() + strlen(editor_prop_prefix));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
published_properties.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
properties.clear();
|
||||
internal_properties.clear();
|
||||
published_properties.clear();
|
||||
}
|
||||
QModelIndex topLeft = index(0, 0, QModelIndex());
|
||||
QModelIndex bottomRight = index(rowCount() - 1, columnCount() - 1, QModelIndex());
|
||||
|
@ -509,13 +604,22 @@ void C4ConsoleQtPropListModel::SetPropList(class C4PropList *new_proplist)
|
|||
|
||||
int C4ConsoleQtPropListModel::rowCount(const QModelIndex & parent) const
|
||||
{
|
||||
if (parent.isValid()) return 0;
|
||||
return properties.size();
|
||||
// Nothing loaded?
|
||||
if (!proplist.getPropList()) return 0;
|
||||
// Top level: Published and internal properties
|
||||
if (!parent.isValid()) return 2;
|
||||
// Mid level: Descend into property lists
|
||||
QModelIndex grandparent = parent.parent();
|
||||
if (!grandparent.isValid())
|
||||
{
|
||||
if (parent.row() == 0) return published_properties.size();
|
||||
if (parent.row() == 1) return internal_properties.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int C4ConsoleQtPropListModel::columnCount(const QModelIndex & parent) const
|
||||
{
|
||||
if (parent.isValid()) return 0;
|
||||
return 2; // Name + Data
|
||||
}
|
||||
|
||||
|
@ -525,16 +629,36 @@ QVariant C4ConsoleQtPropListModel::headerData(int section, Qt::Orientation orien
|
|||
if (role == Qt::DisplayRole && orientation == Qt::Orientation::Horizontal)
|
||||
{
|
||||
if (section == 0) return QVariant(LoadResStr("IDS_CTL_NAME"));
|
||||
if (section == 1) return QVariant(LoadResStr("IDS_CTL_VALUE"));
|
||||
if (section == 1) return QVariant(LoadResStr("IDS_CNS_VALUE"));
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant C4ConsoleQtPropListModel::data(const QModelIndex & index, int role) const
|
||||
{
|
||||
// Query latest data from prop list
|
||||
// Anything loaded?
|
||||
C4PropList *props = proplist.getPropList();
|
||||
if (role == Qt::DisplayRole && props)
|
||||
if (!props) return QVariant();
|
||||
// Headers
|
||||
QModelIndex parent = index.parent();
|
||||
if (!parent.isValid())
|
||||
{
|
||||
if (!index.column())
|
||||
{
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
if (index.row() == 0) return QVariant(LoadResStr("IDS_CNS_PROPERTIES"));
|
||||
if (index.row() == 1) return QVariant(LoadResStr("IDS_CNS_INTERNAL"));
|
||||
}
|
||||
else if (role == Qt::FontRole)
|
||||
{
|
||||
return header_font;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
// Query latest data from prop list
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
Property *prop = static_cast<Property *>(index.internalPointer());
|
||||
if (!prop) return QVariant();
|
||||
|
@ -545,7 +669,7 @@ QVariant C4ConsoleQtPropListModel::data(const QModelIndex & index, int role) con
|
|||
case 1: // Second col: Property value
|
||||
{
|
||||
C4Value v;
|
||||
if (!props->GetPropertyByS(prop->name, &v)) return QVariant("???"); /* Property got removed between update calls */
|
||||
props->GetPropertyByS(prop->name, &v); // Just display nil if property is not set
|
||||
return QVariant(v.GetDataString().getData());
|
||||
}
|
||||
}
|
||||
|
@ -556,18 +680,37 @@ QVariant C4ConsoleQtPropListModel::data(const QModelIndex & index, int role) con
|
|||
|
||||
QModelIndex C4ConsoleQtPropListModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
// Flat model
|
||||
if (parent.isValid()) return QModelIndex();
|
||||
// In range?
|
||||
if (column < 0 || column > 1) return QModelIndex();
|
||||
if (row < 0 || row >= properties.size()) return QModelIndex();
|
||||
const Property * prop = &properties[row];
|
||||
return createIndex(row, column, const_cast<Property *>(prop));
|
||||
// Top level index?
|
||||
if (!parent.isValid())
|
||||
{
|
||||
// Top level has headers only
|
||||
if (row == 0 || row == 1) return createIndex(row, column, NULL);
|
||||
return QModelIndex();
|
||||
}
|
||||
// Property?
|
||||
QModelIndex grandparent = parent.parent();
|
||||
if (!grandparent.isValid())
|
||||
{
|
||||
const std::vector< Property > *property_list = NULL;
|
||||
if (parent.row() == 0) property_list = &published_properties;
|
||||
if (parent.row() == 1) property_list = &internal_properties;
|
||||
if (property_list)
|
||||
{
|
||||
if (row < 0 || row >= property_list->size()) return QModelIndex();
|
||||
const Property * prop = &(*property_list)[row];
|
||||
return createIndex(row, column, const_cast<Property *>(prop));
|
||||
}
|
||||
}
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex C4ConsoleQtPropListModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
return QModelIndex();
|
||||
Property *prop = static_cast<Property *>(index.internalPointer());
|
||||
if (!prop) return QModelIndex();
|
||||
// Find list to use
|
||||
return createIndex(prop->is_internal ? 1 : 0, 0, NULL);
|
||||
}
|
||||
|
||||
Qt::ItemFlags C4ConsoleQtPropListModel::flags(const QModelIndex &index) const
|
||||
|
|
|
@ -32,6 +32,7 @@ class C4PropertyPath
|
|||
// TODO: For now just storing the path. May want to keep the path info later to allow validation/updating of values
|
||||
StdCopyStrBuf path;
|
||||
|
||||
public:
|
||||
enum PathType
|
||||
{
|
||||
PPT_Root = 0,
|
||||
|
@ -56,10 +57,10 @@ class C4PropertyDelegate : public QObject
|
|||
|
||||
protected:
|
||||
const class C4PropertyDelegateFactory *factory;
|
||||
C4RefCntPointer<C4String> set_function;
|
||||
|
||||
public:
|
||||
C4PropertyDelegate(const class C4PropertyDelegateFactory *factory)
|
||||
: factory(factory) { }
|
||||
C4PropertyDelegate(const class C4PropertyDelegateFactory *factory, const C4PropList *props);
|
||||
virtual ~C4PropertyDelegate() { }
|
||||
|
||||
virtual void SetEditorData(QWidget *editor, const C4Value &val) const = 0;
|
||||
|
@ -67,6 +68,8 @@ public:
|
|||
virtual QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option) const = 0;
|
||||
virtual void UpdateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option) const;
|
||||
|
||||
const char *GetSetFunction() const { return set_function.Get() ? set_function->GetCStr() : NULL; } // get name of setter function for this property
|
||||
|
||||
signals:
|
||||
void EditorValueChangedSignal(QWidget *editor) const;
|
||||
void EditingDoneSignal(QWidget *editor) const;
|
||||
|
@ -74,8 +77,10 @@ signals:
|
|||
|
||||
class C4PropertyDelegateInt : public C4PropertyDelegate
|
||||
{
|
||||
private:
|
||||
int32_t min, max, step;
|
||||
public:
|
||||
C4PropertyDelegateInt(const class C4PropertyDelegateFactory *factory, const C4PropList *props=NULL);
|
||||
C4PropertyDelegateInt(const class C4PropertyDelegateFactory *factory, const C4PropList *props);
|
||||
|
||||
void SetEditorData(QWidget *editor, const C4Value &val) const override;
|
||||
void SetModelData(QWidget *editor, const C4PropertyPath &property_path) const override;
|
||||
|
@ -105,8 +110,9 @@ class C4PropertyDelegateEnum : public C4PropertyDelegate
|
|||
public:
|
||||
typedef C4PropertyDelegateEnumEditor Editor; // qmake doesn't like nested classes
|
||||
|
||||
struct Option
|
||||
class Option
|
||||
{
|
||||
public:
|
||||
C4RefCntPointer<C4String> name; // Display name in Editor enum dropdown box
|
||||
C4RefCntPointer<C4String> option_key;
|
||||
C4RefCntPointer<C4String> value_key;
|
||||
|
@ -126,11 +132,14 @@ public:
|
|||
};
|
||||
private:
|
||||
std::vector<Option> options;
|
||||
|
||||
protected:
|
||||
void ReserveOptions(int32_t num);
|
||||
public:
|
||||
C4PropertyDelegateEnum(const class C4PropertyDelegateFactory *factory, int reserve_count = 0);
|
||||
C4PropertyDelegateEnum(const class C4PropertyDelegateFactory *factory, const C4ValueArray &props);
|
||||
C4PropertyDelegateEnum(const class C4PropertyDelegateFactory *factory, const C4PropList *props, const C4ValueArray *poptions=NULL);
|
||||
|
||||
void AddTypeOption(C4String *name, C4V_Type type, const C4Value &val, C4PropertyDelegate *adelegate=NULL);
|
||||
void AddConstOption(C4String *name, const C4Value &val);
|
||||
|
||||
void SetEditorData(QWidget *editor, const C4Value &val) const override;
|
||||
void SetModelData(QWidget *editor, const C4PropertyPath &property_path) const override;
|
||||
|
@ -144,11 +153,18 @@ public slots:
|
|||
void UpdateOptionIndex(Editor *editor, int idx) const;
|
||||
};
|
||||
|
||||
// Select a definition
|
||||
class C4PropertyDelegateDef : public C4PropertyDelegateEnum
|
||||
{
|
||||
public:
|
||||
C4PropertyDelegateDef(const C4PropertyDelegateFactory *factory, const C4PropList *props);
|
||||
};
|
||||
|
||||
// C4Value setting using an enum
|
||||
class C4PropertyDelegateC4ValueEnum : public C4PropertyDelegateEnum
|
||||
{
|
||||
public:
|
||||
C4PropertyDelegateC4ValueEnum(const C4PropertyDelegateFactory *factory);
|
||||
C4PropertyDelegateC4ValueEnum(const C4PropertyDelegateFactory *factory, const C4PropList *props);
|
||||
};
|
||||
|
||||
class C4PropertyDelegateC4ValueInputEditor : public QWidget
|
||||
|
@ -171,7 +187,7 @@ class C4PropertyDelegateC4ValueInput : public C4PropertyDelegate
|
|||
public:
|
||||
typedef C4PropertyDelegateC4ValueInputEditor Editor;
|
||||
|
||||
C4PropertyDelegateC4ValueInput(const C4PropertyDelegateFactory *factory) : C4PropertyDelegate(factory) { }
|
||||
C4PropertyDelegateC4ValueInput(const C4PropertyDelegateFactory *factory, const C4PropList *props) : C4PropertyDelegate(factory, props) { }
|
||||
|
||||
void SetEditorData(QWidget *editor, const C4Value &val) const override;
|
||||
void SetModelData(QWidget *editor, const C4PropertyPath &property_path) const override;
|
||||
|
@ -204,6 +220,7 @@ protected:
|
|||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
// Prop list view implemented as a model view
|
||||
|
@ -220,19 +237,23 @@ public:
|
|||
C4Value delegate_info;
|
||||
C4PropertyDelegate *delegate;
|
||||
bool about_to_edit;
|
||||
bool is_internal;
|
||||
|
||||
Property() : parent_proplist(NULL), delegate(NULL), about_to_edit(false) {}
|
||||
Property() : parent_proplist(NULL), delegate(NULL), about_to_edit(false), is_internal(false) {}
|
||||
};
|
||||
private:
|
||||
C4Value proplist;
|
||||
std::vector< Property > properties;
|
||||
std::vector< Property > published_properties; // custom properties defined by definitions
|
||||
std::vector< Property > internal_properties; // proplist-properties
|
||||
QFont header_font;
|
||||
public:
|
||||
C4ConsoleQtPropListModel();
|
||||
~C4ConsoleQtPropListModel();
|
||||
|
||||
void SetPropList(class C4PropList *new_proplist);
|
||||
class C4PropList *GetPropList() const { return proplist.getPropList(); }
|
||||
|
||||
protected:
|
||||
public:
|
||||
virtual int rowCount(const QModelIndex & parent = QModelIndex()) const;
|
||||
virtual int columnCount(const QModelIndex & parent = QModelIndex()) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
|
|
|
@ -496,7 +496,7 @@ bool C4ConsoleGUIState::CreateConsoleWindow(C4AbstractApp *app)
|
|||
// Property editor
|
||||
property_delegate_factory.reset(new C4PropertyDelegateFactory());
|
||||
ui.propertyTable->setItemDelegateForColumn(1, property_delegate_factory.get());
|
||||
ui.propertyTable->verticalHeader()->setDefaultSectionSize(ui.propertyTable->fontMetrics().height()+4);
|
||||
//ui.propertyTable->verticalHeader()->setDefaultSectionSize(ui.propertyTable->fontMetrics().height()+4);
|
||||
|
||||
// Welcome page
|
||||
InitWelcomeScreen();
|
||||
|
@ -526,7 +526,9 @@ void C4ConsoleGUIState::Execute(bool redraw_only)
|
|||
if (redraw_only)
|
||||
{
|
||||
// process only non-critical events
|
||||
application->processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
// redrawing only allowed during GameTick; prevent callbacks within a Qt event triggered by windows messaging
|
||||
if (::Application.IsInGameTick())
|
||||
application->processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -679,15 +681,22 @@ void C4ConsoleGUIState::PropertyDlgUpdate(C4EditCursorSelection &rSelection, boo
|
|||
{
|
||||
// Multi object selection: Hide property view; show info label
|
||||
property_model->SetPropList(NULL);
|
||||
ui.propertyTable->setVisible(false);
|
||||
ui.propertyTable->setEnabled(false);
|
||||
ui.selectionInfoLabel->setText(rSelection.GetDataString().getData());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Single object selection: Show property view + Object info in label
|
||||
property_model->SetPropList(rSelection.front().getPropList());
|
||||
C4PropList *prev_list = property_model->GetPropList(), *new_list = rSelection.front().getPropList();
|
||||
if (prev_list != new_list)
|
||||
{
|
||||
property_model->SetPropList(new_list);
|
||||
ui.propertyTable->setFirstColumnSpanned(0, QModelIndex(), true);
|
||||
ui.propertyTable->setFirstColumnSpanned(1, QModelIndex(), true);
|
||||
ui.propertyTable->expand(property_model->index(0, 0, QModelIndex()));
|
||||
}
|
||||
ui.selectionInfoLabel->setText(rSelection.front().GetDataString(0).getData());
|
||||
ui.propertyTable->setVisible(true);
|
||||
ui.propertyTable->setEnabled(true);
|
||||
}
|
||||
// Function update in script combo box
|
||||
if (force_function_update)
|
||||
|
@ -707,10 +716,12 @@ void C4ConsoleGUIState::OnCreatorSelectionChanged(const QItemSelection & selecte
|
|||
if (is_object_selection_updating || !definition_list_model) return; // only process callbacks from users interacting with widget
|
||||
// Forward to EditCursor
|
||||
C4Def *def;
|
||||
for (const QModelIndex &item : deselected.indexes())
|
||||
auto deselected_indexes = deselected.indexes();
|
||||
for (const QModelIndex &item : deselected_indexes)
|
||||
if ((def = definition_list_model->GetDefByModelIndex(item)))
|
||||
::Console.EditCursor.RemoveFromSelection(def);
|
||||
for (const QModelIndex &item : selected.indexes())
|
||||
auto selected_indexes = deselected.indexes();
|
||||
for (const QModelIndex &item : selected_indexes)
|
||||
if ((def = definition_list_model->GetDefByModelIndex(item)))
|
||||
::Console.EditCursor.AddToSelection(def);
|
||||
::Console.EditCursor.OnSelectionChanged(true);
|
||||
|
|
|
@ -51,6 +51,7 @@ C4Application::C4Application():
|
|||
QuitAfterGame(false),
|
||||
CheckForUpdates(false),
|
||||
restartAtEnd(false),
|
||||
is_in_game_tick(false),
|
||||
pGamePadControl(NULL),
|
||||
AppState(C4AS_None),
|
||||
pGameTimer(NULL)
|
||||
|
@ -664,6 +665,7 @@ void C4Application::QuitGame()
|
|||
|
||||
void C4Application::GameTick()
|
||||
{
|
||||
is_in_game_tick = true;
|
||||
// Exec depending on game state
|
||||
switch (AppState)
|
||||
{
|
||||
|
@ -737,6 +739,7 @@ void C4Application::GameTick()
|
|||
if (pGamePadControl) pGamePadControl->Execute();
|
||||
break;
|
||||
}
|
||||
is_in_game_tick = false;
|
||||
}
|
||||
|
||||
void C4Application::Draw()
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
~C4Application();
|
||||
// Flag for restarting the engine at the end
|
||||
bool restartAtEnd;
|
||||
// Flag set during game tick
|
||||
bool is_in_game_tick;
|
||||
// main System.ocg in working folder
|
||||
C4Group SystemGroup;
|
||||
C4MusicSystem MusicSystem;
|
||||
|
@ -50,6 +52,7 @@ public:
|
|||
void ClearCommandLine();
|
||||
// Tick timing
|
||||
void GameTick();
|
||||
bool IsInGameTick() const { return is_in_game_tick; }
|
||||
void Draw();
|
||||
// System.ocg helper funcs
|
||||
bool OpenSystemGroup() { return SystemGroup.IsOpen() || SystemGroup.Open(C4CFN_System); }
|
||||
|
|
|
@ -287,6 +287,25 @@ C4Def* C4DefList::GetDef(int32_t iIndex)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
std::vector<C4Def*> C4DefList::GetAllDefs(C4String *filter_property) const
|
||||
{
|
||||
// Collect vector of all definitions
|
||||
// Filter for those where property evaluates to true if filter_property!=NULL
|
||||
std::vector<C4Def*> result;
|
||||
result.reserve(filter_property ? 32 : table.size());
|
||||
C4Value prop_val;
|
||||
for (C4Def *def = FirstDef; def; def = def->Next)
|
||||
{
|
||||
if (filter_property)
|
||||
{
|
||||
if (!def->GetPropertyByS(filter_property, &prop_val)) continue;
|
||||
if (!prop_val) continue;
|
||||
}
|
||||
result.push_back(def);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
C4Def *C4DefList::GetByPath(const char *szPath)
|
||||
{
|
||||
// search defs
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
bool fOverload = false, int32_t iMinProgress=0, int32_t iMaxProgress=0);
|
||||
C4Def *ID2Def(C4ID id);
|
||||
C4Def *GetDef(int32_t Index);
|
||||
std::vector<C4Def*> GetAllDefs(C4String *filter_property=NULL) const;
|
||||
C4Def *GetByPath(const char *szPath);
|
||||
C4Def *GetByName(const StdStrBuf &);
|
||||
int32_t GetDefCount();
|
||||
|
|
|
@ -472,6 +472,28 @@ std::vector< C4String * > C4PropList::GetSortedLocalProperties() const
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector< C4String * > C4PropList::GetSortedProperties(const char *prefix) const
|
||||
{
|
||||
// Return property list with descending into prototype
|
||||
// But do not include Prototype property
|
||||
std::vector< C4String * > result;
|
||||
const C4PropList *p = this;
|
||||
do
|
||||
{
|
||||
for (const C4Property *pp = p->Properties.First(); pp; pp = p->Properties.Next(pp))
|
||||
if (pp->Key != &::Strings.P[P_Prototype])
|
||||
if (!prefix || !pp->Key->GetData().Compare_(prefix))
|
||||
result.push_back(pp->Key);
|
||||
p = p->GetPrototype();
|
||||
} while (p);
|
||||
// Sort
|
||||
std::sort(result.begin(), result.end(), [](const C4String *a, const C4String *b) -> bool
|
||||
{
|
||||
return strcmp(a->GetCStr(), b->GetCStr()) < 0;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
const char * C4PropList::GetName() const
|
||||
{
|
||||
C4String * s = GetPropertyStr(P_Name);
|
||||
|
|
|
@ -134,6 +134,7 @@ public:
|
|||
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *);
|
||||
void AppendDataString(StdStrBuf * out, const char * delim, int depth = 3) const;
|
||||
std::vector< C4String * > GetSortedLocalProperties() const;
|
||||
std::vector< C4String * > GetSortedProperties(const char *prefix) const;
|
||||
|
||||
bool operator==(const C4PropList &b) const;
|
||||
#ifdef _DEBUG
|
||||
|
|
|
@ -250,6 +250,10 @@ C4StringTable::C4StringTable()
|
|||
P[P_ValueKey] = "ValueKey";
|
||||
P[P_Value] = "Value";
|
||||
P[P_Delegate] = "Delegate";
|
||||
P[P_Min] = "Min";
|
||||
P[P_Max] = "Max";
|
||||
P[P_Set] = "Set";
|
||||
P[P_Options] = "Options";
|
||||
P[DFA_WALK] = "WALK";
|
||||
P[DFA_FLIGHT] = "FLIGHT";
|
||||
P[DFA_KNEEL] = "KNEEL";
|
||||
|
@ -266,7 +270,11 @@ C4StringTable::C4StringTable()
|
|||
P[DFA_CONNECT] = "CONNECT";
|
||||
P[DFA_PULL] = "PULL";
|
||||
// Prevent the individual strings from being deleted, they are not created with new
|
||||
for (unsigned int i = 0; i < P_LAST; ++i) P[i].IncRef();
|
||||
for (unsigned int i = 0; i < P_LAST; ++i)
|
||||
{
|
||||
assert(P[i].GetCStr()); // all strings should be assigned
|
||||
P[i].IncRef();
|
||||
}
|
||||
}
|
||||
|
||||
C4StringTable::~C4StringTable()
|
||||
|
|
|
@ -57,10 +57,22 @@ class C4RefCntPointer
|
|||
public:
|
||||
C4RefCntPointer(T* p): p(p) { IncRef(); }
|
||||
C4RefCntPointer(): p(0) { }
|
||||
C4RefCntPointer(const C4RefCntPointer<T> & r) : p(r.p) { IncRef(); }
|
||||
template <class U> C4RefCntPointer(const C4RefCntPointer<U> & r): p(r.p) { IncRef(); }
|
||||
// Move constructor
|
||||
C4RefCntPointer(C4RefCntPointer<T> &&r) : p(r.p) { r.p = 0; }
|
||||
template <class U> C4RefCntPointer(C4RefCntPointer<U> &&r): p(r.p) { r.p = 0; }
|
||||
// Move assignment
|
||||
C4RefCntPointer& operator = (C4RefCntPointer<T> &&r)
|
||||
{
|
||||
if (p != r.p)
|
||||
{
|
||||
DecRef();
|
||||
p = r.p;
|
||||
r.p = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <class U> C4RefCntPointer& operator = (C4RefCntPointer<U> &&r)
|
||||
{
|
||||
if (p != r.p)
|
||||
|
@ -69,7 +81,6 @@ public:
|
|||
p = r.p;
|
||||
r.p = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
~C4RefCntPointer() { DecRef(); }
|
||||
|
@ -83,6 +94,10 @@ public:
|
|||
}
|
||||
return *this;
|
||||
}
|
||||
C4RefCntPointer& operator = (const C4RefCntPointer<T>& r)
|
||||
{
|
||||
return *this = r.p;
|
||||
}
|
||||
template <class U> C4RefCntPointer& operator = (const C4RefCntPointer<U>& r)
|
||||
{
|
||||
return *this = r.p;
|
||||
|
@ -459,6 +474,10 @@ enum C4PropertyName
|
|||
P_ValueKey,
|
||||
P_Value,
|
||||
P_Delegate,
|
||||
P_Min,
|
||||
P_Max,
|
||||
P_Set,
|
||||
P_Options,
|
||||
// Default Action Procedures
|
||||
DFA_WALK,
|
||||
DFA_FLIGHT,
|
||||
|
|
Loading…
Reference in New Issue