forked from Mirrors/openclonk
Qt Editor: Add effects to object list view + fixes
Also remove cache of C4Values and use callbacks on object and effect deletion instead.qteditor
parent
a4d28c383b
commit
771a333e21
|
@ -36,6 +36,7 @@
|
|||
// * mattex pictures in dropdown
|
||||
// * mat drawing cursor size preview in active viewports
|
||||
// * proper viewport focus when clicked
|
||||
// * crash when viewport closes on player elimination
|
||||
// -----------------------------------------------
|
||||
|
||||
void C4ConsoleGUI::Execute() { state->Execute(); }
|
||||
|
@ -184,7 +185,7 @@ bool C4ConsoleGUI::FileSelect(StdStrBuf *sFilename, const char * szFilter, DWORD
|
|||
if (!filenames.length()) return false;
|
||||
for (auto fn : filenames)
|
||||
{
|
||||
sFilename->Append(fn.toStdString().c_str());
|
||||
sFilename->Append(fn.toUtf8());
|
||||
sFilename->AppendChar('\0');
|
||||
}
|
||||
return true;
|
||||
|
@ -192,7 +193,7 @@ bool C4ConsoleGUI::FileSelect(StdStrBuf *sFilename, const char * szFilter, DWORD
|
|||
// Cancelled?
|
||||
if (filename.length() <= 0) return false;
|
||||
// File selected!
|
||||
sFilename->Copy(filename.toStdString().c_str());
|
||||
sFilename->Copy(filename.toUtf8());
|
||||
sFilename->AppendChar('\0');
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
// Avoid some name conflicts
|
||||
#undef LineFeed
|
||||
#undef new
|
||||
#undef delete
|
||||
// disable OPENGL_ES
|
||||
// (not necessery if Qt is compiled with -opengl desktop)
|
||||
//#define QT_OPENGL_ES_2
|
||||
|
@ -31,6 +32,8 @@
|
|||
//#define QT_OPENGL_ES
|
||||
//#define QT_NO_OPENGL_ES
|
||||
#include <QtWidgets>
|
||||
#include <qabstractitemmodel.h>
|
||||
#include <QAbstractTableModel>
|
||||
#include <memory>
|
||||
|
||||
// TODO: If we remove the other editors, state and consolegui can be merged and the relevant header go into this file
|
||||
|
|
|
@ -29,71 +29,12 @@
|
|||
|
||||
/* Object list information cache */
|
||||
|
||||
// Cached copy of displayed tree
|
||||
// (Leaf nodes only validated on demand)
|
||||
class C4ConsoleQtObjectListModel::Node
|
||||
{
|
||||
Node *parent;
|
||||
C4Value data; // root data
|
||||
std::vector<class Node> children; // child vector - is kept around and usually only increased on query because most updates will just re-set the same object
|
||||
int32_t num_children; // children valid until this point
|
||||
bool valid; // if false, re-fill node (and all children) on next data query
|
||||
|
||||
public:
|
||||
Node(Node *parent) : parent(parent), valid(false), num_children(0) {}
|
||||
|
||||
void Validate();
|
||||
void Invalidate() { valid = false; }
|
||||
bool IsValid() const { return valid; }
|
||||
|
||||
void SetData(class C4PropList *to_data) { data.SetPropList(to_data); Invalidate(); }
|
||||
C4PropList *GetData() const { return data.getPropList(); }
|
||||
Node *_GetChild(int32_t idx) { return &children[idx]; } // unchecked child access
|
||||
Node *GetParent() const { return parent; }
|
||||
int32_t GetNumChildren() const { return num_children; }
|
||||
void EnsureValid() { if (!valid) Validate(); }
|
||||
|
||||
void AddChild(C4PropList *p)
|
||||
{
|
||||
if (num_children >= children.size()) children.resize(num_children + 1, Node(this));
|
||||
children[num_children++].SetData(p);
|
||||
}
|
||||
|
||||
int32_t GetChildIndex(class C4PropList *data)
|
||||
{
|
||||
for (int32_t idx = 0; idx < num_children; ++idx)
|
||||
if (_GetChild(idx)->GetData() == data)
|
||||
return idx;
|
||||
return -1; // not found
|
||||
}
|
||||
};
|
||||
|
||||
void C4ConsoleQtObjectListModel::Node::Validate()
|
||||
{
|
||||
num_children = 0;
|
||||
// Fill from object list (either main list or contents)
|
||||
C4Object *obj = data.getObj();
|
||||
C4ObjectList *list = NULL;
|
||||
if (!parent)
|
||||
list = &::Objects;
|
||||
else if (obj)
|
||||
list = &obj->Contents;
|
||||
if (list)
|
||||
for (auto cobj : *list)
|
||||
if (cobj && cobj->Contained == obj)
|
||||
AddChild(cobj);
|
||||
// Add object effects
|
||||
if (obj)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
valid = true;
|
||||
}
|
||||
|
||||
C4ConsoleQtObjectListModel::C4ConsoleQtObjectListModel(class QTreeView *view)
|
||||
: selection_model(NULL), view(view), is_updating(0)
|
||||
: selection_model(NULL), view(view), is_updating(0), last_row_count(0)
|
||||
{
|
||||
root.reset(new Node(NULL));
|
||||
// default font colors
|
||||
clr_deleted.setColor(QApplication::palette(view).color(QPalette::Mid));
|
||||
clr_effect.setColor(QApplication::palette(view).color(QPalette::Dark));
|
||||
// install the item model
|
||||
view->setModel(this);
|
||||
// get the selection model to control it
|
||||
|
@ -110,12 +51,9 @@ C4ConsoleQtObjectListModel::~C4ConsoleQtObjectListModel()
|
|||
|
||||
void C4ConsoleQtObjectListModel::Invalidate()
|
||||
{
|
||||
// Invalidate everything
|
||||
int32_t num_invalid = root->GetNumChildren();
|
||||
root->Invalidate();
|
||||
// Force redraw
|
||||
QModelIndex topLeft = index(0, 0, QModelIndex());
|
||||
QModelIndex bottomRight = index(num_invalid, columnCount() - 1, QModelIndex());
|
||||
QModelIndex bottomRight = index(last_row_count, columnCount() - 1, QModelIndex());
|
||||
emit dataChanged(topLeft, bottomRight);
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
@ -141,10 +79,32 @@ void C4ConsoleQtObjectListModel::SetSelection(class C4EditCursorSelection &rSele
|
|||
|
||||
int C4ConsoleQtObjectListModel::rowCount(const QModelIndex & parent) const
|
||||
{
|
||||
Node *parent_node = this->GetNodeByIndex(parent);
|
||||
if (!parent_node) return 0;
|
||||
parent_node->Validate();
|
||||
return parent_node->GetNumChildren();
|
||||
int result = 0;
|
||||
if (parent.isValid())
|
||||
{
|
||||
// Child row count of object
|
||||
C4PropList *parent_item = static_cast<C4PropList *>(parent.internalPointer());
|
||||
if (!parent_item) return result;
|
||||
C4Object *obj = parent_item->GetObject();
|
||||
if (!obj) return result;
|
||||
// Contained objects plus effects
|
||||
for (C4Object *contents : obj->Contents)
|
||||
if (contents && contents->Status)
|
||||
++result;
|
||||
for (C4Effect *fx = obj->pEffects; fx; fx = fx->pNext) if (fx->IsActive())
|
||||
++result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Main object + effect count
|
||||
for (C4Object *obj : ::Objects)
|
||||
if (obj && obj->Status && !obj->Contained)
|
||||
++result;
|
||||
for (C4Effect *fx = ::Game.pGlobalEffects; fx; fx = fx->pNext) if (fx->IsActive())
|
||||
++result;
|
||||
last_row_count = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int C4ConsoleQtObjectListModel::columnCount(const QModelIndex & parent) const
|
||||
|
@ -155,12 +115,10 @@ int C4ConsoleQtObjectListModel::columnCount(const QModelIndex & parent) const
|
|||
QVariant C4ConsoleQtObjectListModel::data(const QModelIndex & index, int role) const
|
||||
{
|
||||
// Object list lookup is done in index(). Here we just use the pointer.
|
||||
Node *node = static_cast<Node *>(index.internalPointer());
|
||||
if (!node) return QVariant();
|
||||
C4PropList *data = static_cast<C4PropList *>(index.internalPointer());
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
// Deleted proplist?
|
||||
C4PropList *data = node->GetData();
|
||||
if (!data) return QString("<deleted>");
|
||||
// Prefer own name
|
||||
const char *name = data->GetName();
|
||||
|
@ -171,51 +129,76 @@ QVariant C4ConsoleQtObjectListModel::data(const QModelIndex & index, int role) c
|
|||
// Fallback to effect names for effects
|
||||
return QString("Fx???");
|
||||
}
|
||||
else if (role == Qt::ForegroundRole)
|
||||
{
|
||||
// Deleted proplist?
|
||||
if (!data) return clr_deleted;
|
||||
// Object?
|
||||
C4Object *obj = data->GetObject();
|
||||
if (obj) return QVariant(); // default
|
||||
// Effect
|
||||
return clr_effect;
|
||||
}
|
||||
// Nothing to show
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
C4ConsoleQtObjectListModel::Node *C4ConsoleQtObjectListModel::GetNodeByIndex(const QModelIndex &index) const
|
||||
{
|
||||
// Find node recursively
|
||||
if (!index.isValid()) return root.get();
|
||||
Node *parent = GetNodeByIndex(index.parent());
|
||||
// Out of range
|
||||
if (index.row() < 0 || index.column() != 0) return NULL;
|
||||
// Get indexed child node
|
||||
parent->EnsureValid();
|
||||
if (index.row() >= parent->GetNumChildren()) return NULL;
|
||||
return parent->_GetChild(index.row());
|
||||
}
|
||||
|
||||
QModelIndex C4ConsoleQtObjectListModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
Node *parent_node = GetNodeByIndex(parent);
|
||||
// Parent out of range?
|
||||
if (!parent_node) return QModelIndex();
|
||||
// Make sure it's updated
|
||||
parent_node->EnsureValid();
|
||||
// Current index out of range?
|
||||
if (row < 0 || column != 0 || row >= parent_node->GetNumChildren()) return QModelIndex();
|
||||
// This item is OK. Create an index!
|
||||
return createIndex(row, column, parent_node->_GetChild(row));
|
||||
if (row < 0 || column != 0) return QModelIndex();
|
||||
int index = row;
|
||||
// Child element or main list?
|
||||
if (parent.isValid())
|
||||
{
|
||||
// Child of valid object?
|
||||
C4PropList *parent_item = static_cast<C4PropList *>(parent.internalPointer());
|
||||
if (!parent_item) return QModelIndex();
|
||||
C4Object *obj = parent_item->GetObject();
|
||||
if (!obj) return QModelIndex();
|
||||
// Contained objects plus effects
|
||||
for (C4Object *contents : obj->Contents)
|
||||
if (contents && contents->Status)
|
||||
if (!index--)
|
||||
return createIndex(row, column, contents);
|
||||
for (C4Effect *fx = obj->pEffects; fx; fx = fx->pNext) if (fx->IsActive())
|
||||
if (!index--)
|
||||
return createIndex(row, column, fx);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Main object list
|
||||
for (C4Object *obj : ::Objects)
|
||||
if (obj && obj->Status && !obj->Contained)
|
||||
if (!index--)
|
||||
return createIndex(row, column, obj);
|
||||
}
|
||||
return QModelIndex(); // out of range
|
||||
}
|
||||
|
||||
QModelIndex C4ConsoleQtObjectListModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
// Look up parent through node structure
|
||||
// Find parent of object or effect
|
||||
if (!index.isValid()) return QModelIndex();
|
||||
Node *node = static_cast<Node *>(index.internalPointer());
|
||||
if (!node) return QModelIndex();
|
||||
Node *parent = node->GetParent();
|
||||
if (!parent) return QModelIndex();
|
||||
// Parent must not be the root
|
||||
Node *grandparent = parent->GetParent();
|
||||
if (!grandparent) return QModelIndex();
|
||||
// Find index of parent
|
||||
for (int idx = 0; idx < grandparent->GetNumChildren(); ++idx)
|
||||
if (grandparent->_GetChild(idx) == parent)
|
||||
return createIndex(idx, 0, parent);
|
||||
C4PropList *data = static_cast<C4PropList *>(index.internalPointer());
|
||||
if (!data) return QModelIndex();
|
||||
C4Object *obj = data->GetObject();
|
||||
if (obj) return GetModelIndexByItem(obj->Contained);
|
||||
// Parent object of effect
|
||||
// TODO: Effects currently don't keep track of their owners.
|
||||
// If this ever changes, lookup can be much more efficient...
|
||||
C4Effect *fx = data->GetEffect();
|
||||
if (fx)
|
||||
{
|
||||
for (C4Object *cobj : ::Objects) if (cobj && cobj->Status)
|
||||
{
|
||||
for (C4Effect *cfx = cobj->pEffects; cfx; cfx = cfx->pNext)
|
||||
if (cfx == fx) { obj = cobj; break; }
|
||||
if (obj) break;
|
||||
}
|
||||
return GetModelIndexByItem(obj); // returns root index for obj==NULL, i.e. global effects
|
||||
}
|
||||
// Can't happen
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
|
@ -223,72 +206,58 @@ void C4ConsoleQtObjectListModel::OnSelectionChanged(const QItemSelection & selec
|
|||
{
|
||||
if (is_updating) return;
|
||||
// Forward to EditCursor
|
||||
Node *node; C4PropList *p;
|
||||
for (const QItemSelectionRange &item_range : deselected)
|
||||
if (item_range.isValid())
|
||||
for (const QModelIndex &item : item_range.indexes())
|
||||
if ((node = static_cast<Node *>(item.internalPointer())))
|
||||
if ((p = node->GetData()))
|
||||
::Console.EditCursor.RemoveFromSelection(p);
|
||||
for (const QItemSelectionRange &item_range : selected)
|
||||
if (item_range.isValid())
|
||||
for (const QModelIndex &item : item_range.indexes())
|
||||
if ((node = static_cast<Node *>(item.internalPointer())))
|
||||
if ((p = node->GetData()))
|
||||
::Console.EditCursor.AddToSelection(p);
|
||||
C4PropList *p;
|
||||
for (const QModelIndex &item : deselected.indexes())
|
||||
if ((p = static_cast<C4PropList *>(item.internalPointer())))
|
||||
::Console.EditCursor.RemoveFromSelection(p);
|
||||
for (const QModelIndex &item : selected.indexes())
|
||||
if ((p = static_cast<C4PropList *>(item.internalPointer())))
|
||||
::Console.EditCursor.AddToSelection(p);
|
||||
::Console.EditCursor.OnSelectionChanged(true);
|
||||
}
|
||||
|
||||
bool C4ConsoleQtObjectListModel::GetNodeByItem(class C4PropList *item, C4ConsoleQtObjectListModel::Node **out_parent_node, int32_t *out_index) const
|
||||
{
|
||||
// Deduce node and parent index from item pointer
|
||||
if (!item) return false;
|
||||
Node *parent_node;
|
||||
int32_t idx;
|
||||
C4Object *obj = item->GetObject();
|
||||
if (obj)
|
||||
{
|
||||
if (!obj->Contained)
|
||||
{
|
||||
// Uncontained object
|
||||
parent_node = root.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Contained object
|
||||
if (!GetNodeByItem(obj->Contained, &parent_node, &idx)) return false;
|
||||
parent_node = parent_node->_GetChild(idx);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Effect
|
||||
C4Effect *fx = item->GetEffect();
|
||||
if (!fx) return false;
|
||||
// Parent object of effect
|
||||
// TODO: Effects currently don't keep track of their owners.
|
||||
// If this ever changes, lookup can be much faster
|
||||
for (C4Object *cobj : ::Objects)
|
||||
{
|
||||
for (C4Effect *cfx = obj->pEffects; cfx; cfx = cfx->pNext)
|
||||
if (cfx == fx) { obj = cobj; break; }
|
||||
if (obj) break;
|
||||
}
|
||||
if (!GetNodeByItem(obj, &parent_node, &idx)) return false;
|
||||
parent_node = parent_node->_GetChild(idx);
|
||||
}
|
||||
parent_node->EnsureValid();
|
||||
idx = parent_node->GetChildIndex(obj);
|
||||
if (idx < 0) return false;
|
||||
*out_index = idx;
|
||||
*out_parent_node = parent_node;
|
||||
return true;
|
||||
}
|
||||
|
||||
QModelIndex C4ConsoleQtObjectListModel::GetModelIndexByItem(C4PropList *item) const
|
||||
{
|
||||
// Deduce position in model list from item pointer
|
||||
Node *parent_node=NULL; int32_t row=0;
|
||||
if (!GetNodeByItem(item, &parent_node, &row)) return QModelIndex();
|
||||
return createIndex(row, 0, parent_node->_GetChild(row));
|
||||
if (!item) return QModelIndex();
|
||||
C4Object *obj; C4Effect *fx;
|
||||
int row=0;
|
||||
if ((obj = item->GetObject()))
|
||||
{
|
||||
const C4ObjectList *list = &::Objects;
|
||||
if (obj->Contained) list = &(obj->Contained->Contents);
|
||||
for (C4Object *cobj : *list)
|
||||
{
|
||||
if (cobj == obj) break;
|
||||
if (cobj && cobj->Status) ++row;
|
||||
}
|
||||
}
|
||||
else if ((fx = item->GetEffect()))
|
||||
{
|
||||
// TODO: Effects currently don't keep track of their owners.
|
||||
// If this ever changes, lookup can be much more efficient...
|
||||
bool found = false;
|
||||
for (C4Object *cobj : ::Objects) if (cobj && cobj->Status)
|
||||
{
|
||||
row = 0;
|
||||
for (C4Effect *cfx = cobj->pEffects; cfx; cfx = cfx->pNext)
|
||||
if (cfx == fx) { obj = cobj; found = true; break; } else ++row;
|
||||
if (obj) break;
|
||||
}
|
||||
// Also search global effect list
|
||||
if (!found)
|
||||
{
|
||||
row = 0;
|
||||
for (C4Effect *cfx = ::Game.pGlobalEffects; cfx; cfx = cfx->pNext) if (cfx->IsActive())
|
||||
if (cfx == fx) { found = true; break; } else ++row;
|
||||
if (!found) return QModelIndex();
|
||||
}
|
||||
// Add other objects on top of this index
|
||||
const C4ObjectList *list = &::Objects;
|
||||
if (obj) list = &obj->Contents;
|
||||
for (C4Object *cobj : *list)
|
||||
if (cobj && cobj->Status)
|
||||
++row;
|
||||
}
|
||||
return createIndex(row, 0, item);
|
||||
}
|
||||
|
|
|
@ -24,18 +24,17 @@
|
|||
#include <C4ConsoleGUI.h> // for glew.h
|
||||
#include <C4Value.h>
|
||||
#include <C4ConsoleQt.h>
|
||||
#include <qabstractitemmodel.h>
|
||||
|
||||
// Prop list view implemented as a model view
|
||||
class C4ConsoleQtObjectListModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
class Node;
|
||||
std::unique_ptr<Node> root;
|
||||
class QItemSelectionModel *selection_model;
|
||||
QTreeView *view;
|
||||
int32_t is_updating;
|
||||
mutable int32_t last_row_count;
|
||||
QBrush clr_deleted, clr_effect;
|
||||
|
||||
public:
|
||||
C4ConsoleQtObjectListModel(class QTreeView *view);
|
||||
|
@ -48,8 +47,6 @@ public:
|
|||
void SetSelection(class C4EditCursorSelection &rSelection);
|
||||
|
||||
private:
|
||||
Node *GetNodeByIndex(const QModelIndex &index) const;
|
||||
bool GetNodeByItem(class C4PropList *item, Node **out_parent_node, int32_t *out_index) const;
|
||||
QModelIndex GetModelIndexByItem(class C4PropList *item) const;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <C4Include.h> // needed for automoc
|
||||
#include <C4ConsoleGUI.h> // for glew.h
|
||||
#include <C4ConsoleQt.h>
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
// Prop list view implemented as a model view
|
||||
class C4ConsoleQtPropListModel : public QAbstractTableModel
|
||||
|
|
|
@ -114,9 +114,9 @@ void C4ConsoleViewportWidget::OnActiveChanged(bool active)
|
|||
QColor bgclr = QApplication::palette(this).color(QPalette::Highlight);
|
||||
QColor fontclr = QApplication::palette(this).color(QPalette::HighlightedText);
|
||||
if (active)
|
||||
setStyleSheet(FormatString("QDockWidget::title { background: %s; padding: 5px; } QDockWidget { color: %s; font-weight: bold; }",
|
||||
bgclr.name().toStdString().c_str(),
|
||||
fontclr.name().toStdString().c_str()).getData());
|
||||
setStyleSheet(QString(
|
||||
"QDockWidget::title { background: %1; padding: 5px; } QDockWidget { color: %2; font-weight: bold; }")
|
||||
.arg(bgclr.name(), fontclr.name()));
|
||||
else
|
||||
setStyleSheet("");
|
||||
}
|
||||
|
@ -306,17 +306,14 @@ void C4ConsoleQtMainWindow::HelpAbout() { ::Console.HelpAbout(); }
|
|||
void C4ConsoleQtMainWindow::MainConsoleEditEnter()
|
||||
{
|
||||
QLineEdit *main_console_edit = state->ui.consoleInputBox->lineEdit();
|
||||
std::string script = main_console_edit->text().toStdString();
|
||||
::Console.RegisterRecentInput(script.c_str(), C4Console::MRU_Scenario);
|
||||
::Console.In(script.c_str());
|
||||
::Console.RegisterRecentInput(main_console_edit->text().toUtf8(), C4Console::MRU_Scenario);
|
||||
::Console.In(main_console_edit->text().toUtf8());
|
||||
}
|
||||
|
||||
void C4ConsoleQtMainWindow::PropertyConsoleEditEnter()
|
||||
{
|
||||
QLineEdit *property_console_edit = state->ui.propertyInputBox->lineEdit();
|
||||
std::string script = property_console_edit->text().toStdString();
|
||||
//::Console.RegisterRecentInput(script.c_str(), C4Console::MRU_Object); - done by EditCursor
|
||||
::Console.EditCursor.In(script.c_str());
|
||||
::Console.EditCursor.In(property_console_edit->text().toUtf8());
|
||||
}
|
||||
|
||||
|
||||
|
@ -570,13 +567,10 @@ void C4ConsoleGUIState::PropertyDlgUpdate(C4EditCursorSelection &rSelection, boo
|
|||
{
|
||||
// Single object selection: Show property view + Object info in label
|
||||
property_model->SetPropList(rSelection.front().getPropList());
|
||||
ui.selectionInfoLabel->setText(rSelection.front().GetDataString().getData());
|
||||
ui.selectionInfoLabel->setText(rSelection.front().GetDataString(0).getData());
|
||||
ui.propertyTable->setVisible(true);
|
||||
}
|
||||
// Function update in script combo box
|
||||
if (force_function_update)
|
||||
SetComboItems(ui.propertyInputBox, ::Console.GetScriptSuggestions(::Console.PropertyDlgObject, C4Console::MRU_Object));
|
||||
// Update object list on timer update
|
||||
if (!force_function_update)
|
||||
object_list_model->Invalidate();
|
||||
}
|
||||
|
|
|
@ -44,8 +44,7 @@ StdStrBuf C4EditCursorSelection::GetDataString() const
|
|||
{
|
||||
StdStrBuf Output;
|
||||
// Compose info text by selected object(s)
|
||||
// Only care for objects, not other proplists, because the function is relevant for the non-qt-editor only anyway
|
||||
int32_t obj_count = ObjectCount();
|
||||
int32_t obj_count = size();
|
||||
switch (obj_count)
|
||||
{
|
||||
// No selection
|
||||
|
@ -54,8 +53,14 @@ StdStrBuf C4EditCursorSelection::GetDataString() const
|
|||
break;
|
||||
// One selected object
|
||||
case 1:
|
||||
Output.Take(GetObject()->GetDataString());
|
||||
{
|
||||
C4Object *obj = GetObject();
|
||||
if (obj)
|
||||
Output.Take(obj->GetDataString());
|
||||
else
|
||||
Output.Take(front().GetDataString());
|
||||
break;
|
||||
}
|
||||
// Multiple selected objects
|
||||
default:
|
||||
Output.Format(LoadResStr("IDS_CNS_MULTIPLEOBJECTS"), obj_count);
|
||||
|
@ -105,7 +110,7 @@ bool C4EditCursorSelection::ClearPointers(C4Object *obj)
|
|||
|
||||
bool C4EditCursorSelection::IsContained(C4PropList *obj) const
|
||||
{
|
||||
for (const C4Value &v : (*this)) if (obj == v.getObj()) return true;
|
||||
for (const C4Value &v : (*this)) if (obj == v.getPropList()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -822,6 +822,19 @@ void C4ObjectListDlg::Open()
|
|||
}
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnObjectContainerChanged(C4Object *obj, C4Object *old_container, C4Object *new_container)
|
||||
{
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnEffectAdded(C4Effect *fx)
|
||||
{
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnEffectRemoved(C4Effect *fx)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
C4ObjectListDlg::C4ObjectListDlg()
|
||||
|
@ -849,6 +862,7 @@ void C4ObjectListDlg::Update(C4EditCursorSelection &rSelection)
|
|||
if (view_model) view_model->SetSelection(rSelection);
|
||||
}
|
||||
|
||||
// Could do some crazy fine-grained updates. But updating is cheap enough...
|
||||
void C4ObjectListDlg::OnObjectRemove(C4ObjectList * pList, C4ObjectLink * pLnk)
|
||||
{
|
||||
if (view_model) view_model->Invalidate();
|
||||
|
@ -864,6 +878,21 @@ void C4ObjectListDlg::OnObjectRename(C4ObjectList * pList, C4ObjectLink * pLnk)
|
|||
if (view_model) view_model->Invalidate();
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnObjectContainerChanged(C4Object *obj, C4Object *old_container, C4Object *new_container)
|
||||
{
|
||||
if (view_model) view_model->Invalidate();
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnEffectAdded(C4Effect *fx)
|
||||
{
|
||||
if (view_model) view_model->Invalidate();
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnEffectRemoved(C4Effect *fx)
|
||||
{
|
||||
if (view_model) view_model->Invalidate();
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
@ -883,6 +912,19 @@ void C4ObjectListDlg::OnObjectRename(C4ObjectList * pList, C4ObjectLink * pLnk)
|
|||
{
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnObjectContainerChanged(C4Object *obj, C4Object *old_container, C4Object *new_container)
|
||||
{
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnEffectAdded(C4Effect *fx)
|
||||
{
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnEffectRemoved(C4Effect *fx)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#endif WITH_QT_EDITOR
|
||||
|
||||
#endif
|
||||
|
|
|
@ -44,6 +44,9 @@ public:
|
|||
virtual void OnObjectRemove(C4ObjectList * pList, C4ObjectLink * pLnk) override;
|
||||
virtual void OnObjectAdded(C4ObjectList * pList, C4ObjectLink * pLnk) override;
|
||||
virtual void OnObjectRename(C4ObjectList * pList, C4ObjectLink * pLnk) override;
|
||||
virtual void OnObjectContainerChanged(C4Object *obj, C4Object *old_container, C4Object *new_container) override;
|
||||
virtual void OnEffectAdded(class C4Effect *fx) override;
|
||||
virtual void OnEffectRemoved(class C4Effect *fx) override;
|
||||
|
||||
#ifdef USE_GTK
|
||||
private:
|
||||
|
|
|
@ -129,6 +129,8 @@ C4Effect * C4Effect::New(C4Object * pForObj, C4String * szName, int32_t iPrio, i
|
|||
// Update OnFire cache
|
||||
if (!pEffect->IsDead() && pForObj && WildcardMatch(C4Fx_AnyFire, szName->GetCStr()))
|
||||
pForObj->SetOnFire(true);
|
||||
// Creation callback
|
||||
if (!pEffect->IsDead()) ObjectListChangeListener.OnEffectAdded(pEffect);
|
||||
return pEffect;
|
||||
}
|
||||
|
||||
|
@ -181,6 +183,12 @@ void C4Effect::ClearPointers(C4Object *pObj)
|
|||
while ((pEff=pEff->pNext));
|
||||
}
|
||||
|
||||
void C4Effect::SetDead()
|
||||
{
|
||||
iPriority = 0;
|
||||
ObjectListChangeListener.OnEffectRemoved(this);
|
||||
}
|
||||
|
||||
C4Effect *C4Effect::Get(const char *szName, int32_t iIndex, int32_t iMaxPriority)
|
||||
{
|
||||
// safety
|
||||
|
|
|
@ -99,7 +99,7 @@ public:
|
|||
void Denumerate(C4ValueNumbers *); // numbers to object pointers
|
||||
void ClearPointers(C4Object *pObj); // clear all pointers to object - may kill some effects w/o callback, because the callback target is lost
|
||||
|
||||
void SetDead() { iPriority=0; } // mark effect to be removed in next execution cycle
|
||||
void SetDead(); // mark effect to be removed in next execution cycle
|
||||
bool IsDead() { return !iPriority; } // return whether effect is to be removed
|
||||
void FlipActive() { iPriority*=-1; } // alters activation status
|
||||
bool IsActive() { return iPriority>0; } // returns whether effect is active
|
||||
|
|
|
@ -1366,6 +1366,8 @@ bool C4Object::Exit(int32_t iX, int32_t iY, int32_t iR, C4Real iXDir, C4Real iYD
|
|||
CloseMenu(true);
|
||||
UpdateFace(true);
|
||||
SetOCF();
|
||||
// Object list callback (before script callbacks, because script callbacks may enter again)
|
||||
ObjectListChangeListener.OnObjectContainerChanged(this, pContainer, NULL);
|
||||
// Engine calls
|
||||
if (fCalls) pContainer->Call(PSF_Ejection,&C4AulParSet(this));
|
||||
if (fCalls) Call(PSF_Departure,&C4AulParSet(pContainer));
|
||||
|
@ -1437,6 +1439,8 @@ bool C4Object::Enter(C4Object *pTarget, bool fCalls, bool fCopyMotion, bool *pfR
|
|||
// Update container
|
||||
Contained->UpdateMass();
|
||||
Contained->SetOCF();
|
||||
// Object list callback (before script callbacks, because script callbacks may exit again)
|
||||
ObjectListChangeListener.OnObjectContainerChanged(this, NULL, Contained);
|
||||
// Collection call
|
||||
if (fCalls) pTarget->Call(PSF_Collection2,&C4AulParSet(this));
|
||||
if (!Contained || !Contained->Status || !pTarget->Status) return true;
|
||||
|
|
|
@ -35,6 +35,9 @@ public:
|
|||
virtual void OnObjectRemove(C4ObjectList * pList, C4ObjectLink * pLnk) = 0;
|
||||
virtual void OnObjectAdded(C4ObjectList * pList, C4ObjectLink * pLnk) = 0;
|
||||
virtual void OnObjectRename(C4ObjectList * pList, C4ObjectLink * pLnk) = 0;
|
||||
virtual void OnObjectContainerChanged(C4Object *obj, C4Object *old_container, C4Object *new_container) = 0;
|
||||
virtual void OnEffectAdded(class C4Effect *fx) = 0;
|
||||
virtual void OnEffectRemoved(class C4Effect *fx) = 0;
|
||||
virtual ~C4ObjectListChangeListener() { }
|
||||
};
|
||||
|
||||
|
|
|
@ -147,8 +147,9 @@ StdStrBuf C4Value::GetDataString(int depth) const
|
|||
const C4PropListStatic * Def = Data.PropList->IsStatic();
|
||||
if (Def)
|
||||
return Def->GetDataString();
|
||||
C4Effect * fx = Data.PropList->GetEffect();
|
||||
StdStrBuf DataString;
|
||||
DataString = "{";
|
||||
DataString = (fx ? "effect {" : "{");
|
||||
Data.PropList->AppendDataString(&DataString, ", ", depth);
|
||||
DataString.AppendChar('}');
|
||||
return DataString;
|
||||
|
|
Loading…
Reference in New Issue