Qt Editor: Shape properties

qteditor
Sven Eberhardt 2016-04-25 16:17:10 -04:00
parent f594737d7e
commit 881534bee0
24 changed files with 816 additions and 80 deletions

View File

@ -811,6 +811,8 @@ if(WITH_QT_EDITOR)
src/editor/C4ConsoleQt.h
src/editor/C4ConsoleQtState.cpp
src/editor/C4ConsoleQtState.h
src/editor/C4ConsoleQtShapes.cpp
src/editor/C4ConsoleQtShapes.h
src/editor/C4ConsoleQtPropListViewer.cpp
src/editor/C4ConsoleQtPropListViewer.h
src/editor/C4ConsoleQtObjectListViewer.cpp

View File

@ -87,6 +87,10 @@ public:
void OnStartGame();
void ClearGamePointers();
// TODO some qt editor stuff is in state and needs to be public
// Once other editors are removed, C4ConsoleGUI, C4ConsoleQt and C4ConsoleQtState should be reorganized
State *GetState() const { return state; }
friend class C4ConsoleQtMainWindow;
friend class C4ToolsDlg;
#else

View File

@ -353,10 +353,10 @@ bool C4ConsoleGUI::CreateNewScenario(StdStrBuf *out_filename)
state->SetObjectSelection(selection);
}
void C4ConsoleGUI::ClearGamePointers()
{
void C4ConsoleGUI::ClearGamePointers()
{
state->ClearGamePointers();
}
}
void C4ToolsDlg::UpdateToolCtrls()
{

View File

@ -17,6 +17,7 @@
#include "C4Include.h"
#include "script/C4Value.h"
#include "editor/C4ConsoleQtPropListViewer.h"
#include "editor/C4ConsoleQtState.h"
#include "editor/C4Console.h"
#include "object/C4Object.h"
#include "object/C4DefList.h"
@ -127,7 +128,7 @@ void C4PropertyDelegateInt::SetEditorData(QWidget *editor, const C4Value &val) c
spinBox->setValue(val.getInt());
}
void C4PropertyDelegateInt::SetModelData(QWidget *editor, const C4PropertyPath &property_path) const
void C4PropertyDelegateInt::SetModelData(QObject *editor, const C4PropertyPath &property_path) const
{
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText();
@ -188,7 +189,7 @@ void C4PropertyDelegateColor::SetEditorData(QWidget *aeditor, const C4Value &val
editor->last_value = val;
}
void C4PropertyDelegateColor::SetModelData(QWidget *aeditor, const C4PropertyPath &property_path) const
void C4PropertyDelegateColor::SetModelData(QObject *aeditor, const C4PropertyPath &property_path) const
{
Editor *editor = static_cast<Editor *>(aeditor);
property_path.SetProperty(editor->last_value);
@ -199,7 +200,7 @@ QWidget *C4PropertyDelegateColor::CreateEditor(const class C4PropertyDelegateFac
Editor *editor;
std::unique_ptr<Editor> peditor((editor = new Editor(parent)));
connect(editor->button, &QPushButton::pressed, this, [editor, this]() {
QColor clr = QColorDialog::getColor(QColor(editor->last_value.getInt()));
QColor clr = QColorDialog::getColor(QColor(editor->last_value.getInt()), editor, QString(), QColorDialog::ShowAlphaChannel);
editor->last_value.SetInt(clr.rgba());
this->SetEditorData(editor, editor->last_value); // force update on display
emit EditingDoneSignal(editor);
@ -209,7 +210,7 @@ QWidget *C4PropertyDelegateColor::CreateEditor(const class C4PropertyDelegateFac
QString C4PropertyDelegateColor::GetDisplayString(const C4Value &v, C4Object *obj) const
{
return QString("#%1").arg(v.getInt(), 8, 16, QChar('0'));
return QString("#%1").arg(uint32_t(v.getInt()), 8, 16, QChar('0'));
}
QColor C4PropertyDelegateColor::GetDisplayTextColor(const C4Value &val, class C4Object *obj) const
@ -329,8 +330,7 @@ void C4PropertyDelegateEnum::UpdateEditorParameter(C4PropertyDelegateEnum::Edito
if (idx < 0 || idx >= options.size()) return;
const Option &option = options[idx];
// Lazy-resolve parameter delegate
if (!option.adelegate && option.adelegate_val.GetType() != C4V_Nil)
option.adelegate = factory->GetDelegateByValue(option.adelegate_val);
EnsureOptionDelegateResolved(option);
// Create editor if needed
if (option.adelegate)
{
@ -375,7 +375,7 @@ void C4PropertyDelegateEnum::SetEditorData(QWidget *aeditor, const C4Value &val)
editor->updating = false;
}
void C4PropertyDelegateEnum::SetModelData(QWidget *aeditor, const C4PropertyPath &property_path) const
void C4PropertyDelegateEnum::SetModelData(QObject *aeditor, const C4PropertyPath &property_path) const
{
// Fetch value from editor
Editor *editor = static_cast<Editor*>(aeditor);
@ -428,6 +428,13 @@ void C4PropertyDelegateEnum::UpdateOptionIndex(C4PropertyDelegateEnum::Editor *e
emit EditorValueChangedSignal(editor);
}
void C4PropertyDelegateEnum::EnsureOptionDelegateResolved(const Option &option) const
{
// Lazy-resolve parameter delegate
if (!option.adelegate && option.adelegate_val.GetType() != C4V_Nil)
option.adelegate = factory->GetDelegateByValue(option.adelegate_val);
}
QString C4PropertyDelegateEnum::GetDisplayString(const C4Value &v, class C4Object *obj) const
{
// Display string from value
@ -440,11 +447,10 @@ QString C4PropertyDelegateEnum::GetDisplayString(const C4Value &v, class C4Objec
else
{
// Value found: Display option string plus parameter
Option option = options[idx];
const Option &option = options[idx];
QString result = option.name->GetCStr();
// Lazy-resolve parameter delegate
if (!option.adelegate && option.adelegate_val.GetType() != C4V_Nil)
option.adelegate = factory->GetDelegateByValue(option.adelegate_val);
EnsureOptionDelegateResolved(option);
if (option.adelegate)
{
C4Value param_val = v;
@ -460,6 +466,23 @@ QString C4PropertyDelegateEnum::GetDisplayString(const C4Value &v, class C4Objec
}
}
const C4PropertyDelegateShape *C4PropertyDelegateEnum::GetShapeDelegate(const C4Value &val) const
{
// Does this delegate own a shape? Forward decision into selected option.
int32_t option_idx = GetOptionByValue(val);
if (option_idx < 0) return nullptr;
const Option &option = options[option_idx];
EnsureOptionDelegateResolved(option);
if (!option.adelegate) return nullptr;
C4Value param_val = val;
if (option.value_key.Get())
{
C4PropList *vp = val.getPropList();
if (vp) vp->GetPropertyByS(option.value_key, &param_val);
}
return option.adelegate->GetShapeDelegate(param_val);
}
C4PropertyDelegateDef::C4PropertyDelegateDef(const C4PropertyDelegateFactory *factory, C4PropList *props)
: C4PropertyDelegateEnum(factory, props)
{
@ -544,7 +567,7 @@ void C4PropertyDelegateC4ValueInput::SetEditorData(QWidget *aeditor, const C4Val
editor->edit->setText(val.GetDataString().getData());
}
void C4PropertyDelegateC4ValueInput::SetModelData(QWidget *aeditor, const C4PropertyPath &property_path) const
void C4PropertyDelegateC4ValueInput::SetModelData(QObject *aeditor, const C4PropertyPath &property_path) const
{
// Only set model data when pressing Enter explicitely; not just when leaving
Editor *editor = static_cast<Editor *>(aeditor);
@ -578,6 +601,50 @@ QWidget *C4PropertyDelegateC4ValueInput::CreateEditor(const class C4PropertyDele
}
/* Areas shown in viewport */
C4PropertyDelegateShape::C4PropertyDelegateShape(const class C4PropertyDelegateFactory *factory, C4PropList *props)
: C4PropertyDelegate(factory, props), clr(0xffff0000), can_move_center(false)
{
if (props)
{
shape_type = props->GetPropertyStr(P_Type);
clr = props->GetPropertyInt(P_Color) | 0xff000000;
can_move_center = props->GetPropertyBool(P_CanMoveCenter);
}
}
void C4PropertyDelegateShape::SetModelData(QObject *editor, const C4PropertyPath &property_path) const
{
C4ConsoleQtShape *shape = static_cast<C4ConsoleQtShape *>(editor);
property_path.SetProperty(shape->GetValue());
}
void C4PropertyDelegateShape::Paint(QPainter *painter, const QStyleOptionViewItem &option, const C4Value &val) const
{
// Background color
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
else
painter->fillRect(option.rect, option.palette.base());
// Draw a frame in shape color
painter->save();
QColor frame_color = QColor(QRgb(clr & 0xffffff));
int32_t width = Clamp<int32_t>(option.rect.height() / 8, 2, 6) &~1;
QPen rect_pen(QBrush(frame_color), width, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin);
painter->setPen(rect_pen);
QRect inner_rect = option.rect.adjusted(width / 2, width / 2, -width / 2, -width / 2);
if (shape_type && shape_type->GetData() == "circle")
{
painter->drawEllipse(inner_rect);
if (can_move_center) painter->drawPoint(inner_rect.center());
}
else
{
painter->drawRect(inner_rect);
}
painter->restore();
}
/* Delegate factory: Create delegates based on the C4Value type */
@ -594,6 +661,7 @@ C4PropertyDelegate *C4PropertyDelegateFactory::CreateDelegateByString(const C4St
if (str->GetData() == "bool") return new C4PropertyDelegateBool(this, props);
if (str->GetData() == "has_effect") return new C4PropertyDelegateHasEffect(this, props);
if (str->GetData() == "c4valueenum") return new C4PropertyDelegateC4ValueEnum(this, props);
if (str->GetData() == "rect" || str->GetData() == "circle") return new C4PropertyDelegateShape(this, props);
if (str->GetData() == "any") return new C4PropertyDelegateC4ValueInput(this, props);
// unknown type
return NULL;
@ -679,18 +747,23 @@ void C4PropertyDelegateFactory::setModelData(QWidget *editor, QAbstractItemModel
C4PropertyDelegate *d = GetDelegateByIndex(index);
if (!d) return;
C4ConsoleQtPropListModel::Property *prop = static_cast<C4ConsoleQtPropListModel::Property *>(index.internalPointer());
C4PropList *props = prop->parent_proplist.getPropList();
if (props)
{
// Compose set command
C4PropertyPath path(prop->parent_proplist.GetDataString().getData());
C4PropertyPath subpath;
if (d->GetSetFunction())
subpath = C4PropertyPath(path, d->GetSetFunction(), C4PropertyPath::PPT_SetFunction);
else
subpath = C4PropertyPath(path, prop->key->GetCStr());
d->SetModelData(editor, subpath);
}
SetPropertyData(d, editor, prop);
}
void C4PropertyDelegateFactory::SetPropertyData(const C4PropertyDelegate *d, QObject *editor, C4ConsoleQtPropListModel::Property *editor_prop) const
{
// Safety: Ensure target properties still exist
C4PropList *target_props = editor_prop->parent_proplist.getPropList();
if (!target_props) return;
// Compose set command
C4PropertyPath path(editor_prop->parent_proplist.GetDataString().getData());
C4PropertyPath subpath;
if (d->GetSetFunction())
subpath = C4PropertyPath(path, d->GetSetFunction(), C4PropertyPath::PPT_SetFunction);
else
subpath = C4PropertyPath(path, editor_prop->key->GetCStr());
// Set according to delegate
d->SetModelData(editor, subpath);
}
QWidget *C4PropertyDelegateFactory::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
@ -700,14 +773,17 @@ QWidget *C4PropertyDelegateFactory::createEditor(QWidget *parent, const QStyleOp
C4ConsoleQtPropListModel::Property *prop = static_cast<C4ConsoleQtPropListModel::Property *>(index.internalPointer());
prop->about_to_edit = true;
QWidget *editor = d->CreateEditor(this, parent, option);
// Connect value change signals
// Connect value change signals (if editing is possible for this property)
// For some reason, commitData needs a non-const pointer
connect(d, &C4PropertyDelegate::EditorValueChangedSignal, editor, [editor, this](QWidget *signal_editor) {
if (signal_editor == editor) const_cast<C4PropertyDelegateFactory *>(this)->EditorValueChanged(editor);
});
connect(d, &C4PropertyDelegate::EditingDoneSignal, editor, [editor, this](QWidget *signal_editor) {
if (signal_editor == editor) const_cast<C4PropertyDelegateFactory *>(this)->EditingDone(editor);
});
if (editor)
{
connect(d, &C4PropertyDelegate::EditorValueChangedSignal, editor, [editor, this](QWidget *signal_editor) {
if (signal_editor == editor) const_cast<C4PropertyDelegateFactory *>(this)->EditorValueChanged(editor);
});
connect(d, &C4PropertyDelegate::EditingDoneSignal, editor, [editor, this](QWidget *signal_editor) {
if (signal_editor == editor) const_cast<C4PropertyDelegateFactory *>(this)->EditingDone(editor);
});
}
return editor;
}
@ -724,6 +800,26 @@ QSize C4PropertyDelegateFactory::sizeHint(const QStyleOptionViewItem &option, co
return QSize(100, height);
}
void C4PropertyDelegateFactory::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
// Delegate has custom painting?
C4ConsoleQtPropListModel::Property *prop = static_cast<C4ConsoleQtPropListModel::Property *>(index.internalPointer());
C4PropertyDelegate *d = GetDelegateByIndex(index);
if (d && prop && d->HasCustomPaint())
{
C4Value val;
C4PropList *props = prop->parent_proplist.getPropList();
if (props)
{
d->GetPropertyValue(props, prop->key, &val);
d->Paint(painter, option, val);
return;
}
}
// Otherwise use default paint implementation
QStyledItemDelegate::paint(painter, option, index);
}
/* Proplist table view */
@ -749,23 +845,41 @@ bool C4ConsoleQtPropListModel::AddPropertyGroup(C4PropList *add_proplist, int32_
properties.props.resize(new_properties.size());
for (int32_t i = 0; i < new_properties.size(); ++i)
{
properties.props[i].parent_proplist.SetPropList(target_proplist);
properties.props[i].key = NULL;
properties.props[i].display_name = NULL;
properties.props[i].delegate_info.Set0(); // default C4Value delegate
properties.props[i].delegate = NULL; // init when needed
properties.props[i].group_idx = group_index;
Property *prop = &properties.props[i];
prop->parent_proplist.SetPropList(target_proplist);
prop->key = NULL;
prop->display_name = NULL;
prop->delegate_info.Set0(); // default C4Value delegate
prop->group_idx = group_index;
C4Value published_prop_val;
add_proplist->GetPropertyByS(new_properties[i], &published_prop_val);
C4PropList *published_prop = published_prop_val.getPropList();
if (published_prop)
{
properties.props[i].key = published_prop->GetPropertyStr(P_Key);
properties.props[i].display_name = published_prop->GetPropertyStr(P_Name);
properties.props[i].delegate_info.SetPropList(published_prop);
prop->key = published_prop->GetPropertyStr(P_Key);
prop->display_name = published_prop->GetPropertyStr(P_Name);
prop->delegate_info.SetPropList(published_prop);
}
if (!prop->key) properties.props[i].key = ::Strings.RegString(new_properties[i]->GetCStr() + strlen(editor_prop_prefix));
if (!prop->display_name) properties.props[i].display_name = ::Strings.RegString(new_properties[i]->GetCStr() + strlen(editor_prop_prefix));
prop->delegate = delegate_factory->GetDelegateByValue(prop->delegate_info);
C4Value v;
prop->delegate->GetPropertyValue(target_proplist, prop->key, &v);
// Connect editable shape to property
const C4PropertyDelegateShape *new_shape_delegate = prop->delegate->GetShapeDelegate(v);
if (new_shape_delegate != prop->shape_delegate)
{
prop->shape_delegate = new_shape_delegate;
if (new_shape_delegate)
{
C4ConsoleQtShape *shape = ::Console.EditCursor.GetShapes()->CreateShape(target_proplist->GetObject(), published_prop, v);
C4PropertyDelegateFactory *factory = this->delegate_factory;
connect(shape, &C4ConsoleQtShape::ShapeDragged, new_shape_delegate, [factory, new_shape_delegate, shape, prop]() {
factory->SetPropertyData(new_shape_delegate, shape, prop);
});
prop->shape.Set(shape);
}
}
if (!properties.props[i].key) properties.props[i].key = ::Strings.RegString(new_properties[i]->GetCStr() + strlen(editor_prop_prefix));
if (!properties.props[i].display_name) properties.props[i].display_name = ::Strings.RegString(new_properties[i]->GetCStr() + strlen(editor_prop_prefix));
}
return true;
}
@ -821,6 +935,8 @@ void C4ConsoleQtPropListModel::SetPropList(class C4PropList *new_proplist)
internal_properties.props[i].delegate_info.Set0(); // default C4Value delegate
internal_properties.props[i].delegate = NULL; // init when needed
internal_properties.props[i].group_idx = num_groups;
internal_properties.props[i].shape.Clear();
internal_properties.props[i].shape_delegate = nullptr;
}
++num_groups;
}

View File

@ -23,8 +23,12 @@
#include "C4Include.h" // needed for automoc
#include "editor/C4ConsoleGUI.h" // for glew.h
#include "editor/C4ConsoleQt.h"
#include "editor/C4ConsoleQtShapes.h"
#include "script/C4Value.h"
class C4ConsoleQtPropListModel;
struct C4ConsoleQtPropListModelProperty;
// Path to a property, like e.g. Object(123).foo.bar[456].baz
// Used to allow proper synchronization of property setting
class C4PropertyPath
@ -64,15 +68,17 @@ public:
virtual ~C4PropertyDelegate() { }
virtual void SetEditorData(QWidget *editor, const C4Value &val) const = 0;
virtual void SetModelData(QWidget *editor, const C4PropertyPath &property_path) const = 0;
virtual void SetModelData(QObject *editor, const C4PropertyPath &property_path) const = 0;
virtual QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option) const = 0;
virtual void UpdateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option) const;
virtual bool GetPropertyValue(C4PropList *props, C4String *key, C4Value *out_val) const;
virtual QString GetDisplayString(const C4Value &val, class C4Object *obj) const;
virtual QColor GetDisplayTextColor(const C4Value &val, class C4Object *obj) const;
virtual QColor GetDisplayBackgroundColor(const C4Value &val, class C4Object *obj) const;
const char *GetSetFunction() const { return set_function.Get() ? set_function->GetCStr() : NULL; } // get name of setter function for this property
const char *GetSetFunction() const { return set_function.Get() ? set_function->GetCStr() : nullptr; } // get name of setter function for this property
virtual const class C4PropertyDelegateShape *GetShapeDelegate(const C4Value &val) const { return nullptr; }
virtual bool HasCustomPaint() const { return false; }
virtual void Paint(QPainter *painter, const QStyleOptionViewItem &option, const C4Value &val) const { }
signals:
void EditorValueChangedSignal(QWidget *editor) const;
@ -87,7 +93,7 @@ public:
C4PropertyDelegateInt(const class C4PropertyDelegateFactory *factory, C4PropList *props);
void SetEditorData(QWidget *editor, const C4Value &val) const override;
void SetModelData(QWidget *editor, const C4PropertyPath &property_path) const override;
void SetModelData(QObject *editor, const C4PropertyPath &property_path) const override;
QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option) const override;
};
@ -113,7 +119,7 @@ public:
C4PropertyDelegateColor(const class C4PropertyDelegateFactory *factory, C4PropList *props);
void SetEditorData(QWidget *editor, const C4Value &val) const override;
void SetModelData(QWidget *editor, const C4PropertyPath &property_path) const override;
void SetModelData(QObject *editor, const C4PropertyPath &property_path) const override;
QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option) const override;
QString GetDisplayString(const C4Value &v, C4Object *obj) const override;
QColor GetDisplayTextColor(const C4Value &val, class C4Object *obj) const override;
@ -175,13 +181,15 @@ public:
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;
void SetModelData(QObject *editor, const C4PropertyPath &property_path) const override;
QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option) const override;
QString GetDisplayString(const C4Value &val, class C4Object *obj) const override;
const class C4PropertyDelegateShape *GetShapeDelegate(const C4Value &val) const override; // Forward to parameter of selected option
private:
int32_t GetOptionByValue(const C4Value &val) const;
void UpdateEditorParameter(C4PropertyDelegateEnum::Editor *editor) const;
void EnsureOptionDelegateResolved(const Option &option) const;
public slots:
void UpdateOptionIndex(Editor *editor, int idx) const;
@ -244,10 +252,27 @@ public:
C4PropertyDelegateC4ValueInput(const C4PropertyDelegateFactory *factory, C4PropList *props) : C4PropertyDelegate(factory, props) { }
void SetEditorData(QWidget *editor, const C4Value &val) const override;
void SetModelData(QWidget *editor, const C4PropertyPath &property_path) const override;
void SetModelData(QObject *editor, const C4PropertyPath &property_path) const override;
QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option) const override;
};
// areas shown in viewport
class C4PropertyDelegateShape : public C4PropertyDelegate
{
C4RefCntPointer<C4String> shape_type;
uint32_t clr;
bool can_move_center;
public:
C4PropertyDelegateShape(const class C4PropertyDelegateFactory *factory, C4PropList *props);
void SetEditorData(QWidget *editor, const C4Value &val) const override { } // TODO maybe implement update?
void SetModelData(QObject *editor, const C4PropertyPath &property_path) const override;
QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option) const override { return NULL; }
const C4PropertyDelegateShape *GetShapeDelegate(const C4Value &val) const override { return this; }
bool HasCustomPaint() const override { return true; }
void Paint(QPainter *painter, const QStyleOptionViewItem &option, const C4Value &val) const override;
};
class C4PropertyDelegateFactory : public QStyledItemDelegate
{
Q_OBJECT
@ -264,17 +289,41 @@ public:
C4PropertyDelegate *GetDelegateByValue(const C4Value &val) const;
void ClearDelegates();
void SetPropertyData(const C4PropertyDelegate *d, QObject *editor, C4ConsoleQtPropListModelProperty *editor_prop) const;
private:
void EditorValueChanged(QWidget *editor);
void EditingDone(QWidget *editor);
protected:
// Model callbacks forwarded to actual delegates
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
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;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
// One property in the prop list model view
struct C4ConsoleQtPropListModelProperty
{
C4PropertyPath property_path;
C4Value parent_proplist;
C4RefCntPointer<C4String> display_name;
C4RefCntPointer<C4String> key;
C4Value delegate_info;
C4PropertyDelegate *delegate;
bool about_to_edit;
// Parent group index
int32_t group_idx;
// Each property may be connected to one shape shown in the viewport for editing
C4ConsoleQtShapeHolder shape;
const C4PropertyDelegate *shape_delegate;
C4ConsoleQtPropListModelProperty() : delegate(nullptr), about_to_edit(false), group_idx(-1), shape_delegate(nullptr) {}
};
// Prop list view implemented as a model view
@ -283,19 +332,7 @@ class C4ConsoleQtPropListModel : public QAbstractItemModel
Q_OBJECT
public:
struct Property
{
C4PropertyPath property_path;
C4Value parent_proplist;
C4RefCntPointer<C4String> display_name;
C4RefCntPointer<C4String> key;
C4Value delegate_info;
C4PropertyDelegate *delegate;
bool about_to_edit;
int32_t group_idx;
Property() : delegate(NULL), about_to_edit(false), group_idx(-1) {}
};
typedef C4ConsoleQtPropListModelProperty Property;
struct PropertyGroup
{
QString name;

View File

@ -0,0 +1,369 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2013, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
/* Editable shapes in the viewports (like e.g. AI guard range rectangles) */
#include "C4Include.h"
#include "editor/C4Console.h"
#include "editor/C4ConsoleQtState.h"
#include "editor/C4ConsoleQtShapes.h"
#include "graphics/C4FacetEx.h"
#include "object/C4Object.h"
/* Generic shape */
C4ConsoleQtShape::C4ConsoleQtShape(C4Object *for_obj, C4PropList *props)
: is_relative(false), dragging_border(-1), border_color(0xffff0000)
{
rel_obj.SetPropList(for_obj);
if (props)
{
is_relative = props->GetPropertyBool(P_Relative);
border_color = props->GetPropertyInt(P_Color) | 0xff000000;
}
}
uint32_t C4ConsoleQtShape::GetBorderColor(int32_t border_index, bool dragging_border_is_bitmask) const
{
// Return shape color, or dragged border color if index is the border currently being dragged
if (IsDragging())
if ((dragging_border == border_index) || (dragging_border_is_bitmask && (dragging_border & border_index)))
return 0xffffffff;
return border_color;
}
int32_t C4ConsoleQtShape::AbsX(int32_t rel_x) const
{
if (is_relative)
{
C4Object *obj = rel_obj.getObj();
if (obj) rel_x += obj->GetX();
}
return rel_x;
}
int32_t C4ConsoleQtShape::AbsY(int32_t rel_y) const
{
if (is_relative)
{
C4Object *obj = rel_obj.getObj();
if (obj) rel_y += obj->GetY();
}
return rel_y;
}
/* Rectangular shape*/
C4ConsoleQtRect::C4ConsoleQtRect(C4Object *for_obj, C4PropList *props, const C4Value &val)
: C4ConsoleQtShape(for_obj, props), left(0), top(0), right(10), bottom(10)
{
// Expect rect to be given as [left,top,width,height]
C4ValueArray *varr = val.getArray();
if (varr && varr->GetSize() >= 4)
{
left = varr->GetItem(0).getInt();
top = varr->GetItem(1).getInt();
right = left + varr->GetItem(2).getInt()-1; // right/bottom borders are drawn inclusively
bottom = top + varr->GetItem(3).getInt()-1;
}
}
bool C4ConsoleQtRect::IsHit(int32_t x, int32_t y, int32_t hit_range, Qt::CursorShape *drag_cursor, int32_t *drag_border)
{
// Current border pos
int32_t left = AbsX(this->left), top = AbsY(this->top);
int32_t right = AbsX(this->right), bottom = AbsY(this->bottom);
// Distance to each border
int32_t dleft = Abs<int32_t>(left - x);
int32_t dtop = Abs<int32_t>(top - y);
int32_t dright = Abs<int32_t>(right - x);
int32_t dbottom = Abs<int32_t>(bottom - y);
// In box at all?
if (x < left - hit_range || y < top - hit_range || x > right + hit_range || y > bottom + hit_range)
return false;
// Border hit?
bool hit_left = (dleft <= hit_range && dleft < dright);
bool hit_top = (dtop <= hit_range && dtop < dbottom);
bool hit_right = (!hit_left && dright <= hit_range);
bool hit_bottom = (!hit_top && dbottom <= hit_range);
// Compose cursor and drag border
int32_t idrag_border = (hit_left * CNAT_Left) + (hit_top * CNAT_Top) + (hit_right * CNAT_Right) + (hit_bottom * CNAT_Bottom);
if (idrag_border) *drag_border = idrag_border;
if (hit_left || hit_right)
if (hit_top || hit_bottom)
*drag_cursor = (hit_left == hit_top) ? Qt::SizeFDiagCursor : Qt::SizeBDiagCursor;
else
*drag_cursor = Qt::SizeHorCursor;
else if (hit_top || hit_bottom)
*drag_cursor = Qt::SizeVerCursor;
return !!idrag_border;
}
void C4ConsoleQtRect::Draw(class C4TargetFacet &cgo, float line_width)
{
float left = float(AbsX(this->left)) + cgo.X - cgo.TargetX;
float top = float(AbsY(this->top)) + cgo.Y - cgo.TargetY;
float right = float(AbsX(this->right)) + cgo.X - cgo.TargetX;
float bottom = float(AbsY(this->bottom)) + cgo.Y - cgo.TargetY;
pDraw->DrawLineDw(cgo.Surface, left, top, right, top, GetBorderColor(CNAT_Top, true), line_width);
pDraw->DrawLineDw(cgo.Surface, right, top, right, bottom, GetBorderColor(CNAT_Right, true), line_width);
pDraw->DrawLineDw(cgo.Surface, right, bottom, left, bottom, GetBorderColor(CNAT_Bottom, true), line_width);
pDraw->DrawLineDw(cgo.Surface, left, bottom, left, top, GetBorderColor(CNAT_Left, true), line_width);
}
void C4ConsoleQtRect::Drag(int32_t x, int32_t y, int32_t dx, int32_t dy)
{
if (dragging_border & CNAT_Left) left += dx;
if (dragging_border & CNAT_Top) top += dy;
if (dragging_border & CNAT_Right) right += dx;
if (dragging_border & CNAT_Bottom) bottom += dy;
if (left > right) std::swap(left, right);
if (top > bottom) std::swap(top, bottom);
}
C4Value C4ConsoleQtRect::GetValue() const
{
// Return array: Convert left/top/right/bottom (inclusive) to left/top/width/height
C4ValueArray *pos_array = new C4ValueArray(4);
pos_array->SetItem(0, C4VInt(left));
pos_array->SetItem(1, C4VInt(top));
pos_array->SetItem(2, C4VInt(right - left + 1));
pos_array->SetItem(3, C4VInt(bottom - top + 1));
return C4VArray(pos_array);
}
/* Circle shape */
C4ConsoleQtCircle::C4ConsoleQtCircle(class C4Object *for_obj, C4PropList *props, const C4Value &val)
: C4ConsoleQtShape(for_obj, props), radius(10), cx(0), cy(0), can_move_center(false)
{
if (props)
{
can_move_center = props->GetPropertyBool(P_CanMoveCenter);
}
// If center is moveable, expect value as [radius, center_x, center_y]
// Otherwise just radius
if (can_move_center)
{
C4ValueArray *aval = val.getArray();
if (aval && aval->GetSize() == 3)
{
radius = aval->GetItem(0).getInt();
cx = aval->GetItem(1).getInt();
cy = aval->GetItem(2).getInt();
}
}
else
{
radius = val.getInt();
}
}
bool C4ConsoleQtCircle::IsHit(int32_t x, int32_t y, int32_t hit_range, Qt::CursorShape *drag_cursor, int32_t *drag_border)
{
// Get relative circle center pos
x -= AbsX(cx);
y -= AbsY(cy);
int32_t r = x*x + y*y;
// Is on circle border? (Higher priority than center to allow resizing circle from 0 radius)
if (Inside<int32_t>(r, (radius - hit_range)*(radius - hit_range), (radius + hit_range)*(radius + hit_range)))
{
// Cursor by position on 60 deg circle segments
if (x * 58 / 100 / (y+!y)) // tan(30) ~= 0.58
*drag_cursor = Qt::CursorShape::SizeHorCursor;
else if (y * 58 / 100 / (x+!x))
*drag_cursor = Qt::CursorShape::SizeVerCursor;
else if (x*y > 0)
*drag_cursor = Qt::CursorShape::SizeFDiagCursor;
else
*drag_cursor = Qt::CursorShape::SizeBDiagCursor;
*drag_border = 0;
return true;
}
// Circle center?
if (can_move_center && r <= hit_range*hit_range)
{
*drag_cursor = Qt::CursorShape::SizeAllCursor;
*drag_border = 1;
return true;
}
return false;
}
void C4ConsoleQtCircle::Draw(class C4TargetFacet &cgo, float line_width)
{
// Circle
pDraw->DrawCircleDw(cgo.Surface, AbsX(cx) + cgo.X - cgo.TargetX, AbsY(cy) + cgo.Y - cgo.TargetY, radius, GetBorderColor(0, false), line_width);
// Center if moveable
if (can_move_center)
pDraw->DrawCircleDw(cgo.Surface, AbsX(cx) + cgo.X - cgo.TargetX, AbsY(cy) + cgo.Y - cgo.TargetY, line_width*3, GetBorderColor(1, false), line_width);
}
void C4ConsoleQtCircle::C4ConsoleQtCircle::Drag(int32_t x, int32_t y, int32_t dx, int32_t dy)
{
if (dragging_border == 0)
{
x -= AbsX(cx);
y -= AbsY(cy);
radius = int32_t(sqrt(double(x*x + y*y)));
}
else if (dragging_border == 1)
{
cx += dx;
cy += dy;
}
}
C4Value C4ConsoleQtCircle::GetValue() const
{
// Return single value for non-center-adjustable circles; return [radius, cx, cy] otherwise
if (can_move_center)
{
C4ValueArray *pos_array = new C4ValueArray(3);
pos_array->SetItem(0, C4VInt(radius));
pos_array->SetItem(1, C4VInt(cx));
pos_array->SetItem(2, C4VInt(cy));
return C4VArray(pos_array);
}
else
{
return C4VInt(radius);
}
}
/* Shape list */
C4ConsoleQtShape *C4ConsoleQtShapes::CreateShape(class C4Object *for_obj, C4PropList *props, const C4Value &val)
{
C4String *type = props->GetPropertyStr(P_Type);
if (!type) return nullptr;
C4ConsoleQtShape *shape = nullptr;
if (type->GetData() == "rect") shape = new C4ConsoleQtRect(for_obj, props, val);
else if (type->GetData() == "circle") shape = new C4ConsoleQtCircle(for_obj, props, val);
return shape;
}
void C4ConsoleQtShapes::AddShape(C4ConsoleQtShape *shape)
{
if (shape) shapes.emplace_back(shape);
}
void C4ConsoleQtShapes::RemoveShape(C4ConsoleQtShape *shape)
{
// Remove from list and currently moving shape
shapes.remove_if([shape](auto &it) { return it.get() == shape; });
if (dragging_shape == shape) dragging_shape = NULL;
}
void C4ConsoleQtShapes::ClearShapes()
{
shapes.clear();
dragging_shape = NULL;
drag_cursor = Qt::CursorShape::ArrowCursor;
}
void C4ConsoleQtShapes::Draw(C4TargetFacet &cgo)
{
// Draw all shapes with at least 1px line width
ZoomDataStackItem zdsi(cgo.X, cgo.Y, cgo.Zoom);
float line_width = std::max<float>(1.0f, 1.0f / cgo.Zoom);
for (auto &shape : shapes) shape->Draw(cgo, line_width);
}
bool C4ConsoleQtShapes::MouseDown(float x, float y, float hit_range)
{
// Check for shape hit and start dragging if a shape is in hit range
int32_t hit_range_int = std::max(int32_t(hit_range + 0.5f), 1); // Using integer hit ranges for now
// Ensure no leftover other shape
if (dragging_shape) MouseUp(x, y);
int32_t drag_border=-1;
for (auto &shape : shapes)
{
if (shape->IsHit(x, y, hit_range_int, &drag_cursor, &drag_border))
{
dragging_shape = shape.get();
dragging_shape->StartDragging(drag_border);
drag_x = x;
drag_y = y;
return true;
}
}
return false;
}
void C4ConsoleQtShapes::MouseMove(float x, float y, bool left_down, float hit_range)
{
// Check for shape hit and start dragging if a shape is in hit range
int32_t hit_range_int = std::max(int32_t(hit_range + 0.5f), 1); // Using integer hit ranges for now
// move down move: Execute shape dragging (full pixels only)
if (dragging_shape && left_down)
{
int32_t dx = int32_t(round(x - drag_x)),
dy = int32_t(round(y - drag_y));
if (dx || dy)
{
drag_x += dx;
drag_y += dy;
dragging_shape->Drag(drag_x, drag_y, dx, dy);
}
}
else if (!left_down)
{
// Just moving around: Update cursor
drag_cursor = Qt::CursorShape::ArrowCursor;
int32_t ignored;
for (auto &shape : shapes) if (shape->IsHit(x, y, hit_range_int, &drag_cursor, &ignored)) break;
}
else
{
// Regular move: Reset drag cursor
drag_cursor = Qt::CursorShape::ArrowCursor;
}
}
void C4ConsoleQtShapes::MouseUp(float x, float y)
{
// Stop dragging
if (dragging_shape)
{
dragging_shape->emit ShapeDragged();
dragging_shape->StopDragging();
dragging_shape = NULL;
drag_cursor = Qt::CursorShape::ArrowCursor;
}
}
/* Shape pointer holder class */
void C4ConsoleQtShapeHolder::Clear()
{
if (shape)
{
::Console.EditCursor.GetShapes()->RemoveShape(shape);
shape = nullptr;
}
}
void C4ConsoleQtShapeHolder::Set(C4ConsoleQtShape *new_shape)
{
Clear();
shape = new_shape;
if (shape) ::Console.EditCursor.GetShapes()->AddShape(shape);
}

View File

@ -0,0 +1,139 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2013, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
/* Editable shapes in the viewports (like e.g. AI guard range rectangles) */
#ifndef INC_C4ConsoleQtShapes
#define INC_C4ConsoleQtShapes
#ifdef WITH_QT_EDITOR
#include "editor/C4ConsoleGUI.h" // for glew.h
#include "editor/C4ConsoleQt.h"
#include "script/C4Value.h"
// Shape base class
class C4ConsoleQtShape : public QObject
{
Q_OBJECT
protected:
C4Value rel_obj; // Object relative to which shape is defined
bool is_relative;
int32_t dragging_border;
uint32_t border_color;
protected:
// Return shape color, or dragged border color if index is the border currently being dragged
uint32_t GetBorderColor(int32_t border_index, bool dragging_border_is_bitmask) const;
public:
C4ConsoleQtShape(class C4Object *for_obj, C4PropList *props);
virtual bool IsHit(int32_t x, int32_t y, int32_t hit_range, Qt::CursorShape *drag_cursor, int32_t *drag_border) = 0;
virtual void Draw(class C4TargetFacet &cgo, float line_width) = 0;
// Coordinate transform: Add object
int32_t AbsX(int32_t rel_x) const;
int32_t AbsY(int32_t rel_x) const;
// Start/stop dragging
void StartDragging(int32_t border) { dragging_border = border; }
void StopDragging() { dragging_border = -1; }
virtual void Drag(int32_t x, int32_t y, int32_t dx, int32_t dy) = 0;
bool IsDragging() const { return dragging_border != -1; }
// Return current shape as C4Value to be stored back to property
virtual C4Value GetValue() const = 0;
signals:
void ShapeDragged();
};
// Rectangular shape
class C4ConsoleQtRect : public C4ConsoleQtShape
{
private:
int32_t left, top, right, bottom;
public:
C4ConsoleQtRect(class C4Object *for_obj, C4PropList *props, const C4Value &val);
bool IsHit(int32_t x, int32_t y, int32_t hit_range, Qt::CursorShape *drag_cursor, int32_t *drag_border) override;
void Draw(class C4TargetFacet &cgo, float line_width) override;
void Drag(int32_t x, int32_t y, int32_t dx, int32_t dy) override;
C4Value GetValue() const override;
};
// Circular shape
class C4ConsoleQtCircle : public C4ConsoleQtShape
{
private:
int32_t radius;
int32_t cx, cy;
bool can_move_center;
public:
C4ConsoleQtCircle(class C4Object *for_obj, C4PropList *props, const C4Value &val);
bool IsHit(int32_t x, int32_t y, int32_t hit_range, Qt::CursorShape *drag_cursor, int32_t *drag_border) override;
void Draw(class C4TargetFacet &cgo, float line_width) override;
void Drag(int32_t x, int32_t y, int32_t dx, int32_t dy) override;
C4Value GetValue() const override;
};
/* List of all current editable Qt shapes */
class C4ConsoleQtShapes
{
typedef std::list<std::unique_ptr<C4ConsoleQtShape> > ShapeList;
ShapeList shapes;
C4ConsoleQtShape *dragging_shape;
Qt::CursorShape drag_cursor;
float drag_x, drag_y;
public:
C4ConsoleQtShapes() : dragging_shape(nullptr), drag_x(0), drag_y(0), drag_cursor(Qt::CursorShape::ArrowCursor) { }
C4ConsoleQtShape *CreateShape(class C4Object *for_obj, C4PropList *props, const C4Value &val);
void AddShape(C4ConsoleQtShape *shape);
void RemoveShape(C4ConsoleQtShape *shape);
void ClearShapes();
// Mouse callbacks from viewports to execute shape dragging
bool MouseDown(float x, float y, float hit_range); // return true if a shape was hit
void MouseMove(float x, float y, bool left_down, float hit_range); // move move: Execute shape dragging
void MouseUp(float x, float y);
void Draw(C4TargetFacet &cgo);
// Dragging info
bool HasDragCursor() const { return drag_cursor != Qt::CursorShape::ArrowCursor; }
Qt::CursorShape GetDragCursor() const { return drag_cursor; }
};
/* Shape holder class: Handles adding/removal of shape to shapes list */
class C4ConsoleQtShapeHolder
{
C4ConsoleQtShape *shape;
public:
C4ConsoleQtShapeHolder() : shape(nullptr) {}
~C4ConsoleQtShapeHolder() { Clear(); }
void Clear();
void Set(C4ConsoleQtShape *new_shape);
C4ConsoleQtShape *Get() const { return shape; }
};
#endif // WITH_QT_EDITOR
#endif // INC_C4ConsoleQtShapes

View File

@ -23,6 +23,7 @@
#include "editor/C4ConsoleQtDefinitionListViewer.h"
#include "editor/C4ConsoleQtNewScenario.h"
#include "editor/C4ConsoleQtViewport.h"
#include "editor/C4ConsoleQtShapes.h"
#include "editor/C4Console.h"
#include "platform/StdRegistry.h"
#include "landscape/C4Landscape.h"

View File

@ -88,6 +88,7 @@ public:
C4ConsoleQtMainWindow(class C4AbstractApp *app, class C4ConsoleGUIState *state);
void closeEvent(class QCloseEvent *event) override;
class C4ConsoleGUIState *GetConsoleState() const { return state; }
public slots:
// Toolbar items
@ -220,6 +221,8 @@ public:
void HideWelcomeScreen();
void ClearGamePointers();
void Draw(C4TargetFacet &cgo);
};
class C4ConsoleGUI::State : public C4ConsoleGUIState

View File

@ -20,6 +20,8 @@
#include "script/C4Value.h"
#include "editor/C4ConsoleQtViewport.h"
#include "editor/C4ConsoleQtState.h"
#include "editor/C4Console.h"
#include "editor/C4ConsoleQtShapes.h"
#include "game/C4Viewport.h"
#include "editor/C4ViewportWindow.h"
#include "editor/C4Console.h"
@ -67,8 +69,8 @@ void C4ConsoleQtViewportView::mouseMoveEvent(QMouseEvent *eventMove)
}
else
{
this->setCursor(Qt::CrossCursor);
cvp->pWindow->EditCursorMove(eventMove->x(), eventMove->y(), GetShiftWParam());
this->setCursor(::Console.EditCursor.GetShapes()->HasDragCursor() ? ::Console.EditCursor.GetShapes()->GetDragCursor() : Qt::CrossCursor);
}
}

View File

@ -32,6 +32,9 @@
#include "game/C4Game.h"
#include "object/C4GameObjects.h"
#include "control/C4GameControl.h"
#ifdef WITH_QT_EDITOR
#include "editor/C4ConsoleQtShapes.h"
#endif
#ifdef _WIN32
#include "res/resource.h"
@ -124,7 +127,7 @@ int32_t C4EditCursorSelection::ObjectCount() const
}
C4EditCursor::C4EditCursor()
C4EditCursor::C4EditCursor() : shapes(new C4ConsoleQtShapes())
{
Default();
}
@ -223,8 +226,11 @@ bool C4EditCursor::Move(float iX, float iY, DWORD dwKeyState)
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case C4CNS_ModeEdit:
#ifdef WITH_QT_EDITOR
shapes->MouseMove(X, Y, Hold, 3.0f /* TODO: Depend on zoom */);
#endif
// Hold
if (!DragFrame && Hold)
if (!DragFrame && Hold && !DragShape)
{
MoveSelection(ftofix(xoff),ftofix(yoff));
UpdateDropTarget(dwKeyState);
@ -361,6 +367,14 @@ bool C4EditCursor::LeftButtonDown(DWORD dwKeyState)
}
else
{
// Click on shape?
#ifdef WITH_QT_EDITOR
if (shapes->MouseDown(X, Y, 3.0f /* TODO: Depend on zoom */))
{
DragShape = true;
break;
}
#endif
// Click on unselected: select single
if (Target)
{
@ -475,9 +489,13 @@ bool C4EditCursor::LeftButtonUp(DWORD dwKeyState)
}
// Release
#ifdef WITH_QT_EDITOR
shapes->MouseUp(X, Y);
#endif
Hold=false;
DragFrame=false;
DragLine=false;
DragShape = false;
DropTarget=NULL;
// Update
UpdateStatusBar();
@ -596,6 +614,10 @@ void C4EditCursor::Draw(C4TargetFacet &cgo)
{
ZoomDataStackItem zdsi(cgo.X, cgo.Y, cgo.Zoom);
float line_width = std::max<float>(1.0f, 1.0f / cgo.Zoom);
#ifdef WITH_QT_EDITOR
// Draw shapes of selection
shapes->Draw(cgo);
#endif
// Draw selection marks
for (C4Value &obj : selection)
{
@ -747,7 +769,7 @@ void C4EditCursor::Default()
#ifdef USE_WIN32_WINDOWS
hMenu=NULL;
#endif
Hold=DragFrame=DragLine=false;
Hold=DragFrame=DragLine=DragShape=false;
selection.clear();
creator_def = NULL;
creator_overlay = NULL;
@ -765,6 +787,9 @@ void C4EditCursor::Clear()
selection.clear();
Console.PropertyDlgUpdate(selection, false);
creator_overlay.reset(NULL);
#ifdef WITH_QT_EDITOR
shapes->ClearShapes(); // Should really be empty already
#endif
}
bool C4EditCursor::SetMode(int32_t iMode)

View File

@ -56,7 +56,7 @@ protected:
bool has_mouse_hover;
int32_t Mode;
float X,Y,X2,Y2;
bool Hold,DragFrame,DragLine;
bool Hold,DragFrame,DragLine,DragShape;
C4Object *Target,*DropTarget;
class C4Def *creator_def;
std::unique_ptr<C4GraphicsOverlay> creator_overlay;
@ -82,6 +82,9 @@ protected:
#endif
// Selection may either be any number of objects or a single non-object prop list
C4EditCursorSelection selection;
#ifdef WITH_QT_EDITOR
std::unique_ptr<class C4ConsoleQtShapes> shapes;
#endif
public:
void Default();
void Clear();
@ -112,6 +115,7 @@ public:
bool AltDown();
bool AltUp();
void SetMouseHover(bool h) { has_mouse_hover = h; }
class C4ConsoleQtShapes *GetShapes() const { return shapes.get(); }
protected:
void UpdateStatusBar();
void ApplyCreateObject(bool contained);

View File

@ -219,5 +219,5 @@ void C4ViewportWindow::Close()
}
void C4ViewportWindow::EditCursorMove(int X, int Y, uint32_t state)
{
Console.EditCursor.Move(cvp->GetViewX() + X / cvp->Zoom, cvp->GetViewY() + Y / cvp->Zoom, state);
Console.EditCursor.Move(cvp->WindowToGameX(X), cvp->WindowToGameY(Y), state);
}

View File

@ -347,7 +347,7 @@ void C4Viewport::Draw(C4TargetFacet &cgo0, bool fDrawGame, bool fDrawOverlay)
// Draw overlay
C4ST_STARTNEW(OvrStat, "C4Viewport::Draw: Overlay")
if (Application.isEditor) Console.EditCursor.Draw(cgo);
if (Application.isEditor) ::Console.EditCursor.Draw(cgo);
// Game messages
C4ST_STARTNEW(MsgStat, "C4Viewport::DrawOverlay: Messages")

View File

@ -77,6 +77,10 @@ public:
/** Return y-position of the center of viewport in landscape coordinates */
float GetViewCenterY() { return viewY + ViewHgt/Zoom/2; }
// Convert window coordinates to game coordinates
float WindowToGameX(int32_t win_x) { return GetViewX() + float(win_x) / Zoom; }
float WindowToGameY(int32_t win_y) { return GetViewY() + float(win_y) / Zoom; }
/** Scroll the viewport by x,y */
void ScrollView(float byX, float byY);
/** Set the view position. */

View File

@ -606,7 +606,7 @@ C4CustomKey::C4CustomKey(const CodeList &rDefCodes, const char *szName, C4KeySco
}
C4CustomKey::C4CustomKey(const C4CustomKey &rCpy, bool fCopyCallbacks)
: Codes(rCpy.Codes), DefaultCodes(rCpy.DefaultCodes), Scope(rCpy.Scope), Name(), uiPriority(rCpy.uiPriority), iRef(0)
: Codes(rCpy.Codes), DefaultCodes(rCpy.DefaultCodes), Scope(rCpy.Scope), Name(), uiPriority(rCpy.uiPriority), iRef(0), is_down(false)
{
Name.Copy(rCpy.GetName());
if (fCopyCallbacks)

View File

@ -5061,7 +5061,7 @@ void C4Object::ResetProperty(C4String * k)
return C4PropListNumbered::ResetProperty(k);
}
bool C4Object::GetPropertyByS(C4String *k, C4Value *pResult) const
bool C4Object::GetPropertyByS(const C4String *k, C4Value *pResult) const
{
if (k >= &Strings.P[0] && k < &Strings.P[P_LAST])
{

View File

@ -398,7 +398,7 @@ public:
virtual C4Object const * GetObject() const { return this; }
virtual void SetPropertyByS(C4String * k, const C4Value & to);
virtual void ResetProperty(C4String * k);
virtual bool GetPropertyByS(C4String *k, C4Value *pResult) const;
virtual bool GetPropertyByS(const C4String *k, C4Value *pResult) const;
virtual C4ValueArray * GetProperties() const;
};

View File

@ -535,7 +535,7 @@ void C4Effect::ResetProperty(C4String * k)
C4PropListNumbered::ResetProperty(k);
}
bool C4Effect::GetPropertyByS(C4String *k, C4Value *pResult) const
bool C4Effect::GetPropertyByS(const C4String *k, C4Value *pResult) const
{
if (k >= &Strings.P[0] && k < &Strings.P[P_LAST])
{

View File

@ -130,7 +130,7 @@ public:
virtual C4Effect * GetEffect() { return this; }
virtual void SetPropertyByS(C4String * k, const C4Value & to);
virtual void ResetProperty(C4String * k);
virtual bool GetPropertyByS(C4String *k, C4Value *pResult) const;
virtual bool GetPropertyByS(const C4String *k, C4Value *pResult) const;
virtual C4ValueArray * GetProperties() const;
protected:

View File

@ -587,9 +587,8 @@ C4Effect * C4PropList::GetEffect()
return 0;
}
template<> template<>
unsigned int C4Set<C4Property>::Hash<C4String *>(C4String * const & e)
unsigned int C4Set<C4Property>::Hash<const C4String *>(C4String const * const & e)
{
assert(e);
unsigned int hash = 4, tmp;
@ -606,6 +605,18 @@ unsigned int C4Set<C4Property>::Hash<C4String *>(C4String * const & e)
return hash;
}
template<> template<>
unsigned int C4Set<C4Property>::Hash<C4String *>(C4String * const & e)
{
return Hash<const C4String *>(e);
}
template<> template<>
bool C4Set<C4Property>::Equals<const C4String *>(C4Property const & a, C4String const * const & b)
{
return a.Key == b;
}
template<> template<>
bool C4Set<C4Property>::Equals<C4String *>(C4Property const & a, C4String * const & b)
{
@ -618,7 +629,7 @@ unsigned int C4Set<C4Property>::Hash<C4Property>(C4Property const & p)
return C4Set<C4Property>::Hash(p.Key);
}
bool C4PropList::GetPropertyByS(C4String * k, C4Value *pResult) const
bool C4PropList::GetPropertyByS(const C4String * k, C4Value *pResult) const
{
if (Properties.Has(k))
{
@ -723,6 +734,20 @@ C4PropertyName C4PropList::GetPropertyP(C4PropertyName n) const
return P_LAST;
}
int32_t C4PropList::GetPropertyBool(C4PropertyName n) const
{
C4String * k = &Strings.P[n];
if (Properties.Has(k))
{
return Properties.Get(k).Value.getBool();
}
if (GetPrototype())
{
return GetPrototype()->GetPropertyBool(n);
}
return false;
}
int32_t C4PropList::GetPropertyInt(C4PropertyName n, int32_t default_val) const
{
C4String * k = &Strings.P[n];

View File

@ -92,7 +92,7 @@ public:
// These four operate on properties as seen by script, which can be dynamic
// or reflect C++ variables
virtual bool GetPropertyByS(C4String *k, C4Value *pResult) const;
virtual bool GetPropertyByS(const C4String *k, C4Value *pResult) const;
virtual C4ValueArray * GetProperties() const;
// not allowed on frozen proplists
virtual void SetPropertyByS(C4String * k, const C4Value & to);
@ -113,6 +113,7 @@ public:
C4Value Call(C4String * k, C4AulParSet *pPars=0, bool fPassErrors=false);
C4Value Call(const char * k, C4AulParSet *pPars=0, bool fPassErrors=false);
C4PropertyName GetPropertyP(C4PropertyName k) const;
int32_t GetPropertyBool(C4PropertyName n) const;
int32_t GetPropertyInt(C4PropertyName k, int32_t default_val = 0) const;
C4PropList *GetPropertyPropList(C4PropertyName k) const;
bool HasProperty(C4String * k) const { return Properties.Has(k); }

View File

@ -257,6 +257,8 @@ C4StringTable::C4StringTable()
P[P_Key] = "Key";
P[P_Effect] = "Effect";
P[P_AsyncGet] = "AsyncGet";
P[P_Relative] = "Relative";
P[P_CanMoveCenter] = "CanMoveCenter";
P[DFA_WALK] = "WALK";
P[DFA_FLIGHT] = "FLIGHT";
P[DFA_KNEEL] = "KNEEL";

View File

@ -481,6 +481,8 @@ enum C4PropertyName
P_Key,
P_Effect,
P_AsyncGet,
P_Relative,
P_CanMoveCenter,
// Default Action Procedures
DFA_WALK,
DFA_FLIGHT,