/* * 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. */ /* Proplist table view */ #ifndef INC_C4ConsoleQtPropListViewer #define INC_C4ConsoleQtPropListViewer #ifdef WITH_QT_EDITOR #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 { // TODO: For now just storing the path. May want to keep the path info later to allow validation/updating of values StdCopyStrBuf get_path, argument, set_path; StdCopyStrBuf root; public: enum PathType { PPT_Root = 0, PPT_Property = 1, PPT_Index = 2, PPT_SetFunction = 3, PPT_GlobalSetFunction = 4, PPT_RootSetFunction = 5, } get_path_type, set_path_type; public: C4PropertyPath() {} C4PropertyPath(C4PropList *target); C4PropertyPath(C4Effect *fx, C4Object *target_obj); C4PropertyPath(const char *path) : get_path(path), root(path), get_path_type(PPT_Root), set_path_type(PPT_Root) {} C4PropertyPath(const C4PropertyPath &parent, int32_t elem_index); C4PropertyPath(const C4PropertyPath &parent, const char *child_property); void SetSetPath(const C4PropertyPath &parent, const char *child_property, PathType path_type); void Clear() { get_path.Clear(); set_path.Clear(); } const char *GetGetPath() const { return get_path.getData(); } const char *GetSetPath() const { return set_path ? set_path.getData() : get_path.getData(); } const char *GetRoot() const { return root.getData(); } // Parent-most path (usually the object) bool IsEmpty() const { return get_path.getLength() <= 0; } C4Value ResolveValue() const; void SetProperty(const char *set_string) const; void SetProperty(const C4Value &to_val) const; void DoCall(const char *call_string) const; // Perform a script call where %s is replaced by the current path bool operator ==(const C4PropertyPath &v) const { return get_path == v.get_path; } }; class C4PropertyDelegate : public QObject { Q_OBJECT protected: const class C4PropertyDelegateFactory *factory; C4Value creation_props; C4RefCntPointer set_function, async_get_function, name; C4PropertyPath::PathType set_function_type; public: C4PropertyDelegate(const class C4PropertyDelegateFactory *factory, C4PropList *props); virtual ~C4PropertyDelegate() { } virtual void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const {}; virtual void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const {}; virtual QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection) const = 0; virtual void UpdateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option) const; virtual bool GetPropertyValue(const C4Value &container, C4String *key, int32_t index, C4Value *out_val) const; virtual bool GetPropertyValueBase(const C4Value &container, C4String *key, int32_t index, 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() : nullptr; } // get name of setter function for this property virtual const class C4PropertyDelegateShape *GetShapeDelegate(C4Value &val, C4PropertyPath *shape_path) const { return nullptr; } virtual const class C4PropertyDelegateShape *GetDirectShapeDelegate() const { return nullptr; } virtual bool HasCustomPaint() const { return false; } virtual bool Paint(QPainter *painter, const QStyleOptionViewItem &option, const C4Value &val) const { return false; } C4PropertyPath GetPathForProperty(struct C4ConsoleQtPropListModelProperty *editor_prop) const; C4PropertyPath GetPathForProperty(const C4PropertyPath &parent_path, const char *default_subpath) const; C4String *GetNameStr() const { return name.Get(); } const C4Value &GetCreationProps() const { return creation_props; } signals: void EditorValueChangedSignal(QWidget *editor) const; void EditingDoneSignal(QWidget *editor) const; }; class C4PropertyDelegateInt : public C4PropertyDelegate { private: int32_t min, max, step; public: C4PropertyDelegateInt(const class C4PropertyDelegateFactory *factory, C4PropList *props); void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const override; void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const override; QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection) const override; }; class C4PropertyDelegateStringEditor : public QLineEdit { public: C4PropertyDelegateStringEditor(QWidget *parent) : QLineEdit(parent), commit_pending(false) {} bool commit_pending; }; class C4PropertyDelegateString : public C4PropertyDelegate { public: typedef C4PropertyDelegateStringEditor Editor; C4PropertyDelegateString(const class C4PropertyDelegateFactory *factory, C4PropList *props); void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const override; void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const override; QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection) const override; QString GetDisplayString(const C4Value &v, C4Object *obj) const override; }; // Editor: Text displaying value plus a button that opens an extended editor class C4PropertyDelegateLabelAndButtonWidget : public QWidget { Q_OBJECT public: QHBoxLayout *layout; QLabel *label; QPushButton *button; C4Value last_value; C4PropertyPath property_path; bool button_pending; C4PropertyDelegateLabelAndButtonWidget(QWidget *parent); }; class C4PropertyDelegateDescendPath : public C4PropertyDelegate { protected: C4Value info_proplist; bool edit_on_selection; C4RefCntPointer descend_path; public: typedef C4PropertyDelegateLabelAndButtonWidget Editor; C4PropertyDelegateDescendPath(const class C4PropertyDelegateFactory *factory, C4PropList *props); void SetEditorData(QWidget *aeditor, const C4Value &val, const C4PropertyPath &property_path) const override; QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection) const override; }; class C4PropertyDelegateArray : public C4PropertyDelegateDescendPath { private: int32_t max_array_display; mutable C4PropertyDelegate *element_delegate; // lazy eval public: C4PropertyDelegateArray(const class C4PropertyDelegateFactory *factory, C4PropList *props); QString GetDisplayString(const C4Value &v, C4Object *obj) const override; }; class C4PropertyDelegatePropList : public C4PropertyDelegateDescendPath { private: C4RefCntPointer display_string; public: C4PropertyDelegatePropList(const class C4PropertyDelegateFactory *factory, C4PropList *props); QString GetDisplayString(const C4Value &v, C4Object *obj) const override; }; class C4PropertyDelegateColor : public C4PropertyDelegate { public: typedef C4PropertyDelegateLabelAndButtonWidget Editor; C4PropertyDelegateColor(const class C4PropertyDelegateFactory *factory, C4PropList *props); void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const override; void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const override; QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection) const override; QString GetDisplayString(const C4Value &v, C4Object *obj) const override; QColor GetDisplayTextColor(const C4Value &val, class C4Object *obj) const override; QColor GetDisplayBackgroundColor(const C4Value &val, class C4Object *obj) const override; }; // Display delegate for deep combo box. Handles the help tooltip showing. class C4StyledItemDelegateWithButton : public QStyledItemDelegate { Q_OBJECT public: enum ButtonType { BT_Help, BT_PlaySound, } button_type; C4StyledItemDelegateWithButton(ButtonType bt) : button_type(bt) { } public: bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; protected: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; // A combo box that can select from a model with nested elements // On click, descend into child elements class C4DeepQComboBox : public QComboBox { Q_OBJECT bool is_next_close_blocked; int last_popup_height; std::unique_ptr item_delegate; QSize default_icon_size; public: enum { OptionIndexRole = Qt::UserRole + 1, ObjectHighlightRole = Qt::UserRole + 2, }; C4DeepQComboBox(QWidget *parent, C4StyledItemDelegateWithButton::ButtonType button_type); void showPopup() override; void hidePopup() override; void setCurrentModelIndex(QModelIndex new_index); int32_t GetCurrentSelectionIndex(); void BlockNextCloseEvent() { is_next_close_blocked = true; }; // after item selection on a "play" button, the combo dropdown should stay open signals: void NewItemSelected(int32_t new_item); protected: // event filter for view: Catch mouse clicks to descend into children bool eventFilter(QObject *obj, QEvent *event) override; }; // Widget holder class class C4PropertyDelegateEnumEditor : public QWidget { Q_OBJECT public: C4Value last_val; C4Value last_parameter_val; // Resolved parameter of last_val - assigned for shape parameters only int32_t last_selection_index; C4PropertyPath last_get_path; C4DeepQComboBox *option_box; QHBoxLayout *layout; QWidget *parameter_widget; bool updating, option_changed; const C4PropertyDelegate *paint_parameter_delegate; // Delegate to draw over the parameter_widget if it's an empty transparent QWidget (for shape delegates) C4PropertyDelegateEnumEditor(QWidget *parent) : QWidget(parent), last_selection_index(-1), option_box(NULL), layout(NULL), parameter_widget(NULL), updating(false), option_changed(false), paint_parameter_delegate(nullptr) { } void paintEvent(QPaintEvent *) override; }; class C4PropertyDelegateEnum : public C4PropertyDelegate { Q_OBJECT public: typedef C4PropertyDelegateEnumEditor Editor; // qmake doesn't like nested classes class Option { public: C4RefCntPointer name; // Display name in Editor enum dropdown box C4RefCntPointer help; // Tooltip text C4RefCntPointer group; // Grouping in enum dropdown box; nested groups separated by '/' C4RefCntPointer option_key; C4RefCntPointer value_key; C4RefCntPointer sound_name; // Assigned for options that have a play button C4V_Type type; // Assume this option is set when value is of given type C4Value value; // Value to set if this entry is selected C4Value value_function; // Function to be called to set value mutable C4PropertyDelegate *adelegate; // Delegate to display if this entry is selected (pointer owned by C4PropertyDelegateFactory) C4Value adelegate_val; // Value to resolve adelegate from // How the currently selected option is identified from the value enum StorageType { StorageNone=0, // Invalid option StorageByType=1, // Use type to identify this enum StorageByValue=2, // This option sets a constant value StorageByKey=3, // Assume value is a proplist; identify option by field option_key } storage_type; Option() : type(C4V_Any), adelegate(NULL), storage_type(StorageNone) {} }; protected: virtual C4StyledItemDelegateWithButton::ButtonType GetOptionComboBoxButtonType() const { return C4StyledItemDelegateWithButton::BT_Help; } private: std::vector