OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4ConsoleQtPropListViewer.h
Go to the documentation of this file.
1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5 * Copyright (c) 2013, The OpenClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16 
17 /* Proplist table view */
18 
19 #ifndef INC_C4ConsoleQtPropListViewer
20 #define INC_C4ConsoleQtPropListViewer
21 #ifdef WITH_QT_EDITOR
22 
23 #include "C4Include.h" // needed for automoc
24 #include "editor/C4ConsoleGUI.h" // for glew.h
25 #include "editor/C4ConsoleQt.h"
27 #include "script/C4Value.h"
28 
29 class C4ConsoleQtPropListModel;
30 struct C4ConsoleQtPropListModelProperty;
31 
32 // Path to a property, like e.g. Object(123).foo.bar[456].baz
33 // Used to allow proper synchronization of property setting
34 class C4PropertyPath
35 {
36  // TODO: For now just storing the path. May want to keep the path info later to allow validation/updating of values
37  StdCopyStrBuf get_path, argument, set_path;
38  StdCopyStrBuf root;
39 
40 public:
41  enum PathType
42  {
43  PPT_Root = 0,
44  PPT_Property = 1,
45  PPT_Index = 2,
46  PPT_SetFunction = 3,
47  PPT_GlobalSetFunction = 4,
48  PPT_RootSetFunction = 5,
49  } get_path_type, set_path_type;
50 
51 public:
52  C4PropertyPath() {}
53  C4PropertyPath(C4PropList *target);
54  C4PropertyPath(C4Effect *fx, C4Object *target_obj);
55  C4PropertyPath(const char *path) : get_path(path), root(path), get_path_type(PPT_Root), set_path_type(PPT_Root) {}
56  C4PropertyPath(const C4PropertyPath &parent, int32_t elem_index);
57  C4PropertyPath(const C4PropertyPath &parent, const char *child_property);
58  void SetSetPath(const C4PropertyPath &parent, const char *child_property, PathType path_type);
59  void Clear() { get_path.Clear(); set_path.Clear(); }
60  const char *GetGetPath() const { return get_path.getData(); }
61  const char *GetSetPath() const { return set_path ? set_path.getData() : get_path.getData(); }
62  const char *GetRoot() const { return root.getData(); } // Parent-most path (usually the object)
63  bool IsEmpty() const { return get_path.getLength() <= 0; }
64 
65  C4Value ResolveValue() const;
66  C4Value ResolveRoot() const;
67  void SetProperty(const char *set_string) const;
68  void SetProperty(const C4Value &to_val, const C4PropListStatic *ignore_reference_parent = nullptr) const;
69  void DoCall(const char *call_string) const; // Perform a script call where %s is replaced by the current path
70 
71  bool operator ==(const C4PropertyPath &v) const { return get_path == v.get_path; }
72 };
73 
74 class C4PropertyDelegate : public QObject
75 {
76  Q_OBJECT
77 
78 protected:
79  const class C4PropertyDelegateFactory *factory;
80  C4Value creation_props;
81  C4RefCntPointer<C4String> set_function, async_get_function, name;
82  C4PropertyPath::PathType set_function_type;
83  C4RefCntPointer<C4String> update_callback;
84 
85 public:
86  C4PropertyDelegate(const class C4PropertyDelegateFactory *factory, C4PropList *props);
87  virtual ~C4PropertyDelegate() { }
88 
89  virtual void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const {};
90  virtual void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const {};
91  virtual QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection, bool is_child) const = 0;
92  virtual void UpdateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option) const;
93  virtual bool GetPropertyValue(const C4Value &container, C4String *key, int32_t index, C4Value *out_val) const;
94  virtual bool GetPropertyValueBase(const C4Value &container, C4String *key, int32_t index, C4Value *out_val) const;
95  virtual QString GetDisplayString(const C4Value &val, class C4Object *obj, bool short_names) const;
96  virtual QColor GetDisplayTextColor(const C4Value &val, class C4Object *obj) const;
97  virtual QColor GetDisplayBackgroundColor(const C4Value &val, class C4Object *obj) const;
98  const char *GetSetFunction() const { return set_function.Get() ? set_function->GetCStr() : nullptr; } // get name of setter function for this property
99  virtual const class C4PropertyDelegateShape *GetShapeDelegate(C4Value &val, C4PropertyPath *shape_path) const { return nullptr; }
100  virtual const class C4PropertyDelegateShape *GetDirectShapeDelegate() const { return nullptr; }
101  const char *GetUpdateCallback() const { return update_callback ? update_callback->GetCStr() : nullptr; }
102  virtual bool HasCustomPaint() const { return false; }
103  virtual bool Paint(QPainter *painter, const QStyleOptionViewItem &option, const C4Value &val) const { return false; }
104  virtual C4PropertyPath GetPathForProperty(struct C4ConsoleQtPropListModelProperty *editor_prop) const;
105  C4PropertyPath GetPathForProperty(const C4PropertyPath &parent_path, const char *default_subpath) const;
106  C4String *GetNameStr() const { return name.Get(); }
107  const C4Value &GetCreationProps() const { return creation_props; }
108  virtual bool IsPasteValid(const C4Value &val) const = 0;
109 
110 signals:
111  void EditorValueChangedSignal(QWidget *editor) const;
112  void EditingDoneSignal(QWidget *editor) const;
113 };
114 
115 class C4PropertyDelegateInt : public C4PropertyDelegate
116 {
117 private:
118  int32_t min, max, step;
119 public:
120  C4PropertyDelegateInt(const class C4PropertyDelegateFactory *factory, C4PropList *props);
121 
122  void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const override;
123  void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const override;
124  QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection, bool is_child) const override;
125  bool IsPasteValid(const C4Value &val) const override;
126 };
127 
128 class C4PropertyDelegateStringEditor : public QLineEdit
129 {
130 public:
131  C4PropertyDelegateStringEditor(QWidget *parent) : QLineEdit(parent), commit_pending(false) {}
132  bool commit_pending;
133 };
134 
135 class C4PropertyDelegateString : public C4PropertyDelegate
136 {
137 public:
138  typedef C4PropertyDelegateStringEditor Editor;
139 
140  C4PropertyDelegateString(const class C4PropertyDelegateFactory *factory, C4PropList *props);
141 
142  void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const override;
143  void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const override;
144  QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection, bool is_child) const override;
145  QString GetDisplayString(const C4Value &v, C4Object *obj, bool short_names) const override;
146  bool IsPasteValid(const C4Value &val) const override;
147 };
148 
149 // Editor: Text displaying value plus a button that opens an extended editor
150 class C4PropertyDelegateLabelAndButtonWidget : public QWidget
151 {
152  Q_OBJECT
153 
154 public:
155  QHBoxLayout *layout;
156  QLabel *label;
157  QPushButton *button;
158  C4Value last_value;
159  C4PropertyPath property_path;
160  bool button_pending;
161 
162  C4PropertyDelegateLabelAndButtonWidget(QWidget *parent);
163 };
164 
165 class C4PropertyDelegateDescendPath : public C4PropertyDelegate
166 {
167 protected:
168  C4Value info_proplist;
169  bool edit_on_selection;
170  C4RefCntPointer<C4String> descend_path;
171 public:
172  typedef C4PropertyDelegateLabelAndButtonWidget Editor;
173 
174  C4PropertyDelegateDescendPath(const class C4PropertyDelegateFactory *factory, C4PropList *props);
175 
176  void SetEditorData(QWidget *aeditor, const C4Value &val, const C4PropertyPath &property_path) const override;
177  QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection, bool is_child) const override;
178 };
179 
180 class C4PropertyDelegateArray : public C4PropertyDelegateDescendPath
181 {
182 private:
183  int32_t max_array_display;
184  mutable C4PropertyDelegate *element_delegate; // lazy eval
185 
186  void ResolveElementDelegate() const;
187 public:
188  C4PropertyDelegateArray(const class C4PropertyDelegateFactory *factory, C4PropList *props);
189 
190  QString GetDisplayString(const C4Value &v, C4Object *obj, bool short_names) const override;
191  bool IsPasteValid(const C4Value &val) const override;
192 };
193 
194 class C4PropertyDelegatePropList : public C4PropertyDelegateDescendPath
195 {
196 private:
197  C4RefCntPointer<C4String> display_string;
198 public:
199  C4PropertyDelegatePropList(const class C4PropertyDelegateFactory *factory, C4PropList *props);
200 
201  QString GetDisplayString(const C4Value &v, C4Object *obj, bool short_names) const override;
202  bool IsPasteValid(const C4Value &val) const override;
203 };
204 
205 class C4PropertyDelegateEffectEditor : public QWidget
206 {
207  Q_OBJECT
208 
209 public:
210  QHBoxLayout *layout;
211  QPushButton *remove_button, *edit_button;
212  C4PropertyPath property_path;
213 
214  C4PropertyDelegateEffectEditor(QWidget *parent);
215 };
216 
217 class C4PropertyDelegateEffect : public C4PropertyDelegate
218 {
219 public:
220  typedef C4PropertyDelegateEffectEditor Editor;
221 
222  C4PropertyDelegateEffect(const class C4PropertyDelegateFactory *factory, C4PropList *props);
223 
224  void SetEditorData(QWidget *aeditor, const C4Value &val, const C4PropertyPath &property_path) const override;
225  QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection, bool is_child) const override;
226  QString GetDisplayString(const C4Value &v, C4Object *obj, bool short_names) const override;
227  bool IsPasteValid(const C4Value &val) const override { return false; }
228  bool GetPropertyValue(const C4Value &container, C4String *key, int32_t index, C4Value *out_val) const override;
229  C4PropertyPath GetPathForProperty(C4ConsoleQtPropListModelProperty *editor_prop) const override;
230 };
231 
232 class C4PropertyDelegateColor : public C4PropertyDelegate
233 {
234 private:
235  uint32_t alpha_mask;
236 
237 public:
238  typedef C4PropertyDelegateLabelAndButtonWidget Editor;
239 
240  C4PropertyDelegateColor(const class C4PropertyDelegateFactory *factory, C4PropList *props);
241 
242  void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const override;
243  void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const override;
244  QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection, bool is_child) const override;
245  QString GetDisplayString(const C4Value &v, C4Object *obj, bool short_names) const override;
246  QColor GetDisplayTextColor(const C4Value &val, class C4Object *obj) const override;
247  QColor GetDisplayBackgroundColor(const C4Value &val, class C4Object *obj) const override;
248  bool IsPasteValid(const C4Value &val) const override;
249 
250 private:
251  void OpenColorDialogue(Editor *editor) const;
252 };
253 
254 // Display delegate for deep combo box. Handles the help tooltip showing.
255 class C4StyledItemDelegateWithButton : public QStyledItemDelegate
256 {
257  Q_OBJECT
258 
259 public:
260  enum ButtonType
261  {
262  BT_Help,
263  BT_PlaySound,
264  } button_type;
265 
266  C4StyledItemDelegateWithButton(ButtonType bt) : button_type(bt) { }
267 
268 public:
269  bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;
270 protected:
271  void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
272 };
273 
274 // A combo box that can select from a model with nested elements
275 // On click, descend into child elements
276 class C4DeepQComboBox : public QComboBox
277 {
278  Q_OBJECT
279 
280  bool editable, manual_text_edited;
281  QString last_edited_text;
282  bool is_next_close_blocked;
283  int last_popup_height;
284  std::unique_ptr<C4StyledItemDelegateWithButton> item_delegate;
285  QSize default_icon_size;
286 
287 public:
288  enum
289  {
290  OptionIndexRole = Qt::UserRole + 1,
291  ObjectHighlightRole = Qt::UserRole + 2,
292  ValueStringRole = Qt::UserRole + 3,
293  PriorityNameSortRole = Qt::UserRole + 4,
294  };
295 
296  C4DeepQComboBox(QWidget *parent, C4StyledItemDelegateWithButton::ButtonType button_type, bool editable);
297 
298  void showPopup() override;
299  void hidePopup() override;
300 
301  void setCurrentModelIndex(QModelIndex new_index);
302  int32_t GetCurrentSelectionIndex();
303  void BlockNextCloseEvent() { is_next_close_blocked = true; }; // after item selection on a "play" button, the combo dropdown should stay open
304 
305 public slots:
306  void doShowPopup() { showPopup(); }
307 
308 signals:
309  void NewItemSelected(int32_t new_item);
310  void TextChanged(const QString &new_text);
311 
312 protected:
313  // event filter for view: Catch mouse clicks to descend into children
314  bool eventFilter(QObject *obj, QEvent *event) override;
315 };
316 
317 // Widget holder class
318 class C4PropertyDelegateEnumEditor : public QWidget
319 {
320  Q_OBJECT
321 
322 public:
323  enum { INDEX_Custom_Value = -1 };
324  C4Value last_val;
325  C4Value last_parameter_val; // Resolved parameter of last_val - assigned for shape parameters only
326  int32_t last_selection_index; // Index of selection in model or INDEX_Custom_Value for custom value that does not resolve to an existing entry in editable enum
327  C4PropertyPath last_get_path;
328  C4DeepQComboBox *option_box;
329  QHBoxLayout *layout;
330  QWidget *parameter_widget;
331  bool updating, option_changed, dropdown_pending;
332  const C4PropertyDelegate *paint_parameter_delegate; // Delegate to draw over the parameter_widget if it's an empty transparent QWidget (for shape delegates)
333 
334  C4PropertyDelegateEnumEditor(QWidget *parent)
335  : QWidget(parent), last_selection_index(-1), option_box(nullptr), layout(nullptr), parameter_widget(nullptr),
336  updating(false), option_changed(false), dropdown_pending(false), paint_parameter_delegate(nullptr) { }
337 
338  void paintEvent(QPaintEvent *) override;
339 };
340 
341 class C4PropertyDelegateEnum : public C4PropertyDelegate
342 {
343  Q_OBJECT
344 
345 public:
346  typedef C4PropertyDelegateEnumEditor Editor; // qmake doesn't like nested classes
347 
348  class Option
349  {
350  public:
351  C4RefCntPointer<C4String> name; // Display name in Editor enum dropdown box
352  C4RefCntPointer<C4String> short_name; // Shortened name displayed as sub-delegate
353  C4RefCntPointer<C4String> help; // Tooltip text
354  C4RefCntPointer<C4String> group; // Grouping in enum dropdown box; nested groups separated by '/'
355  C4RefCntPointer<C4String> option_key;
356  C4RefCntPointer<C4String> value_key;
357  C4RefCntPointer<C4String> sound_name; // Assigned for options that have a play button
358  C4V_Type type; // Assume this option is set when value is of given type
359  C4Value props; // Stored pointer to proplist defining this option
360  C4Value value; // Value to set if this entry is selected
361  bool force_serialization; // If serialization should be forced on value
362  C4Value value_function; // Function to be called to set value
363  mutable C4PropertyDelegate *adelegate; // Delegate to display if this entry is selected (pointer owned by C4PropertyDelegateFactory)
364  C4Value adelegate_val; // Value to resolve adelegate from
365  // How the currently selected option is identified from the value
366  enum StorageType {
367  StorageNone=0, // Invalid option
368  StorageByType=1, // Use type to identify this enum
369  StorageByValue=2, // This option sets a constant value
370  StorageByKey=3, // Assume value is a proplist; identify option by field option_key
371  } storage_type;
372  int32_t priority; // Custom sort order
373 
374  Option() : type(C4V_Any), adelegate(nullptr), storage_type(StorageNone), priority(0), force_serialization(false) {}
375  };
376 
377 protected:
378  virtual C4StyledItemDelegateWithButton::ButtonType GetOptionComboBoxButtonType() const { return C4StyledItemDelegateWithButton::BT_Help; }
379 
380 private:
381  std::vector<Option> options;
382  Option default_option;
383  bool allow_editing;
384  bool sorted;
385 
386 protected:
387  C4RefCntPointer<C4String> empty_name; // Override for name of empty option
388 
389 protected:
390  void ClearOptions();
391  void ReserveOptions(int32_t num);
392  QStandardItemModel *CreateOptionModel() const;
393 public:
394  C4PropertyDelegateEnum(const class C4PropertyDelegateFactory *factory, C4PropList *props, const C4ValueArray *poptions=nullptr);
395 
396  void AddTypeOption(C4String *name, C4V_Type type, const C4Value &val, C4PropertyDelegate *adelegate=nullptr);
397  void AddConstOption(C4String *name, const C4Value &val, C4String *group=nullptr, C4String *sound_name=nullptr);
398 
399  void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const override;
400  void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const override;
401  QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection, bool is_child) const override;
402  QString GetDisplayString(const C4Value &val, class C4Object *obj, bool short_names) const override;
403  const class C4PropertyDelegateShape *GetShapeDelegate(C4Value &val, C4PropertyPath *shape_path) const override; // Forward to parameter of selected option
404  bool HasCustomPaint() const override { return true; }
405  bool Paint(QPainter *painter, const QStyleOptionViewItem &option, const C4Value &val) const override;
406  bool IsPasteValid(const C4Value &val) const override;
407 
408 private:
409  QModelIndex GetModelIndexByID(QStandardItemModel *model, QStandardItem *parent_item, int32_t id, const QModelIndex &parent) const;
410  int32_t GetOptionByValue(const C4Value &val) const;
411  void UpdateEditorParameter(C4PropertyDelegateEnum::Editor *editor, bool by_selection) const;
412  void EnsureOptionDelegateResolved(const Option &option) const;
413  void SetOptionValue(const C4PropertyPath &use_path, const C4PropertyDelegateEnum::Option &option, const C4Value &option_value) const;
414  void UpdateOptionIndex(Editor *editor, int idx, const QString *custom_text) const;
415 };
416 
417 // Select a definition
418 class C4PropertyDelegateDef : public C4PropertyDelegateEnum
419 {
420 private:
421  C4RefCntPointer<C4String> filter_property;
422 public:
423  C4PropertyDelegateDef(const C4PropertyDelegateFactory *factory, C4PropList *props);
424  bool IsPasteValid(const C4Value &val) const override;
425 
426 private:
427  void AddDefinitions(class C4ConsoleQtDefinitionListModel *def_list_model, QModelIndex parent, C4String *group);
428 };
429 
430 // Select an object
431 class C4PropertyDelegateObject : public C4PropertyDelegateEnum
432 {
433 private:
435  size_t max_nearby_objects; // maximum number of objects shown in "nearby" list
436 
437  C4RefCntPointer<C4String> GetObjectEntryString(C4Object *obj) const;
438  void UpdateObjectList();
439 public:
440  C4PropertyDelegateObject(const C4PropertyDelegateFactory *factory, C4PropList *props);
441 
442  QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection, bool is_child) const override;
443  QString GetDisplayString(const C4Value &v, class C4Object *obj, bool short_names) const override;
444  bool IsPasteValid(const C4Value &val) const override;
445 };
446 
447 // Select a sound
448 class C4PropertyDelegateSound : public C4PropertyDelegateEnum
449 {
450 public:
451  C4PropertyDelegateSound(const C4PropertyDelegateFactory *factory, C4PropList *props);
452  QString GetDisplayString(const C4Value &v, class C4Object *obj, bool short_names) const override;
453  bool IsPasteValid(const C4Value &val) const override;
454 protected:
455  C4StyledItemDelegateWithButton::ButtonType GetOptionComboBoxButtonType() const override { return C4StyledItemDelegateWithButton::BT_PlaySound; }
456 };
457 
458 // true or false
459 class C4PropertyDelegateBool : public C4PropertyDelegateEnum
460 {
461 public:
462  C4PropertyDelegateBool(const class C4PropertyDelegateFactory *factory, C4PropList *props);
463 
464  bool GetPropertyValue(const C4Value &container, C4String *key, int32_t index, C4Value *out_val) const override;
465  bool IsPasteValid(const C4Value &val) const override;
466 };
467 
468 // true or false depending on whether effect is present
469 class C4PropertyDelegateHasEffect : public C4PropertyDelegateBool
470 {
471 private:
473 public:
474  C4PropertyDelegateHasEffect(const class C4PropertyDelegateFactory *factory, C4PropList *props);
475 
476  bool GetPropertyValue(const C4Value &container, C4String *key, int32_t index, C4Value *out_val) const override;
477 };
478 
479 // C4Value setting using an enum
480 class C4PropertyDelegateC4ValueEnum : public C4PropertyDelegateEnum
481 {
482 public:
483  C4PropertyDelegateC4ValueEnum(const C4PropertyDelegateFactory *factory, C4PropList *props);
484  bool IsPasteValid(const C4Value &val) const override { return true; }
485 };
486 
487 class C4PropertyDelegateC4ValueInputEditor : public QWidget // TODO: Merge with C4PropertyDelegateLabelAndButtonWidget
488 {
489  Q_OBJECT
490 
491 public:
492  QHBoxLayout *layout;
493  QLineEdit *edit;
494  QPushButton *extended_button;
495  bool commit_pending;
496  C4PropertyPath property_path;
497 
498  C4PropertyDelegateC4ValueInputEditor(QWidget *parent);
499 };
500 
501 // C4Value setting using an input box
502 class C4PropertyDelegateC4ValueInput : public C4PropertyDelegate
503 {
504 public:
505  typedef C4PropertyDelegateC4ValueInputEditor Editor;
506 
507  C4PropertyDelegateC4ValueInput(const C4PropertyDelegateFactory *factory, C4PropList *props) : C4PropertyDelegate(factory, props) { }
508 
509  void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const override;
510  void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const override;
511  QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection, bool is_child) const override;
512  bool IsPasteValid(const C4Value &val) const override { return true; }
513 };
514 
515 // areas shown in viewport
516 class C4PropertyDelegateShape : public C4PropertyDelegate
517 {
518  uint32_t clr;
519 
520  virtual void DoPaint(QPainter *painter, const QRect &inner_rect) const = 0;
521 public:
522  C4PropertyDelegateShape(const class C4PropertyDelegateFactory *factory, C4PropList *props);
523  void SetEditorData(QWidget *editor, const C4Value &val, const C4PropertyPath &property_path) const override { } // TODO maybe implement update?
524  void SetModelData(QObject *editor, const C4PropertyPath &property_path, class C4ConsoleQtShape *prop_shape) const override;
525  QWidget *CreateEditor(const class C4PropertyDelegateFactory *parent_delegate, QWidget *parent, const QStyleOptionViewItem &option, bool by_selection, bool is_child) const override { return nullptr; }
526  const C4PropertyDelegateShape *GetShapeDelegate(C4Value &val, C4PropertyPath *shape_path) const override { return this; }
527  const C4PropertyDelegateShape *GetDirectShapeDelegate() const override { return this; }
528  bool HasCustomPaint() const override { return true; }
529  bool Paint(QPainter *painter, const QStyleOptionViewItem &option, const C4Value &val) const override;
530  QString GetDisplayString(const C4Value &v, class C4Object *obj, bool short_names) const override { return QString(); }
531 
532  virtual void ConnectSignals(C4ConsoleQtShape *shape, const C4PropertyPath &property_path) const;
533 };
534 
535 class C4PropertyDelegateRect : public C4PropertyDelegateShape
536 {
538 
539  void DoPaint(QPainter *painter, const QRect &inner_rect) const override;
540 public:
541  C4PropertyDelegateRect(const class C4PropertyDelegateFactory *factory, C4PropList *props);
542  bool IsPasteValid(const C4Value &val) const override;
543 };
544 
545 class C4PropertyDelegateCircle : public C4PropertyDelegateShape
546 {
547  bool can_move_center;
548 
549  void DoPaint(QPainter *painter, const QRect &inner_rect) const override;
550 public:
551  C4PropertyDelegateCircle(const class C4PropertyDelegateFactory *factory, C4PropList *props);
552  bool IsPasteValid(const C4Value &val) const override;
553 };
554 
555 class C4PropertyDelegatePoint : public C4PropertyDelegateShape
556 {
557  void DoPaint(QPainter *painter, const QRect &inner_rect) const override;
558 public:
559  C4PropertyDelegatePoint(const class C4PropertyDelegateFactory *factory, C4PropList *props);
560  bool IsPasteValid(const C4Value &val) const override;
561 };
562 
563 class C4PropertyDelegateGraph : public C4PropertyDelegateShape
564 {
565  bool horizontal_fix = false;
566  bool vertical_fix = false;
567  bool structure_fix = false;
568 
569  void DoPaint(QPainter *painter, const QRect &inner_rect) const override;
570 protected:
571  bool IsVertexPasteValid(const C4Value &val) const;
572  bool IsEdgePasteValid(const C4Value &val) const;
573 public:
574  C4PropertyDelegateGraph(const class C4PropertyDelegateFactory *factory, C4PropList *props);
575  bool IsPasteValid(const C4Value &val) const override;
576 
577  void ConnectSignals(C4ConsoleQtShape *shape, const C4PropertyPath &property_path) const override;
578 };
579 
580 class C4PropertyDelegatePolyline : public C4PropertyDelegateGraph
581 {
582  void DoPaint(QPainter *painter, const QRect &inner_rect) const override;
583 public:
584  C4PropertyDelegatePolyline(const class C4PropertyDelegateFactory *factory, C4PropList *props);
585  bool IsPasteValid(const C4Value &val) const override;
586 };
587 
588 class C4PropertyDelegatePolygon : public C4PropertyDelegateGraph
589 {
590  void DoPaint(QPainter *painter, const QRect &inner_rect) const override;
591 public:
592  C4PropertyDelegatePolygon(const class C4PropertyDelegateFactory *factory, C4PropList *props);
593  bool IsPasteValid(const C4Value &val) const override;
594 };
595 
596 class C4PropertyDelegateFactory : public QStyledItemDelegate
597 {
598  Q_OBJECT
599 
600  mutable std::map<C4PropList *, std::unique_ptr<C4PropertyDelegate> > delegates;
601  mutable C4PropertyDelegateEffect effect_delegate;
602  mutable QWidget *current_editor;
603  mutable C4PropertyDelegate *current_editor_delegate;
604  mutable C4Value last_edited_value;
605  class C4ConsoleQtPropListModel *property_model;
606  class C4ConsoleQtDefinitionListModel *def_list_model;
607 
608  C4PropertyDelegate *CreateDelegateByPropList(C4PropList *props) const;
609  C4PropertyDelegate *GetDelegateByIndex(const QModelIndex &index) const;
610 public:
611  C4PropertyDelegateFactory();
612  ~C4PropertyDelegateFactory() { }
613 
614  C4PropertyDelegate *GetDelegateByValue(const C4Value &val) const;
615  C4PropertyDelegateEffect *GetEffectDelegate() const { return &effect_delegate; }
616 
617  void ClearDelegates();
618  void SetPropertyData(const C4PropertyDelegate *d, QObject *editor, C4ConsoleQtPropListModelProperty *editor_prop) const;
619  void SetPropertyModel(class C4ConsoleQtPropListModel *new_property_model) { property_model = new_property_model; }
620  void SetDefinitionListModel(class C4ConsoleQtDefinitionListModel *new_def_list_model) { def_list_model = new_def_list_model; }
621  class C4ConsoleQtDefinitionListModel *GetDefinitionListModel() const { return def_list_model; }
622  class C4ConsoleQtPropListModel *GetPropertyModel() const { return property_model; }
623  void OnPropListChanged();
624  bool CheckCurrentEditor(C4PropertyDelegate *d, QWidget *editor) const;
625 
626 private:
627  void EditorValueChanged(QWidget *editor);
628  void EditingDone(QWidget *editor);
629  void CopyToClipboard(const QModelIndex &index);
630  bool PasteFromClipboard(const QModelIndex &index, bool check_only);
631 
632 protected:
633  // Model callbacks forwarded to actual delegates
634  void setEditorData(QWidget *editor, const QModelIndex &index) const override;
635  void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
636  QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
637  void destroyEditor(QWidget *editor, const QModelIndex &index) const override;
638  void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
639  QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
640  void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
641  bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
642 };
643 
644 // Delegate for the name column of the property window
645 // For now, just use the default + help button
646 class C4PropertyNameDelegate : public C4StyledItemDelegateWithButton
647 {
648  Q_OBJECT
649 
650  class C4ConsoleQtPropListModel *property_model;
651 
652 public:
653  C4PropertyNameDelegate() : C4StyledItemDelegateWithButton(C4StyledItemDelegateWithButton::BT_Help), property_model(nullptr) { }
654 
655  void SetPropertyModel(class C4ConsoleQtPropListModel *new_property_model) { property_model = new_property_model; }
656 };
657 
658 // One property in the prop list model view
659 struct C4ConsoleQtPropListModelProperty
660 {
661  C4PropertyPath property_path;
662  C4Value parent_value;
663  C4RefCntPointer<C4String> display_name;
664  C4RefCntPointer<C4String> help_text;
666  C4Value delegate_info;
667  C4PropertyDelegate *delegate;
668  bool about_to_edit;
669  int32_t priority;
670 
671  // Parent group index
672  int32_t group_idx;
673 
674  // Each property may be connected to one shape shown in the viewport for editing
675  C4ConsoleQtShapeHolder *shape;
676  const C4PropertyDelegate *shape_delegate;
677  C4PropertyPath shape_property_path;
678 
679  C4ConsoleQtPropListModelProperty() : delegate(nullptr), about_to_edit(false), priority(0), group_idx(-1), shape_delegate(nullptr) {}
680 };
681 
682 // Prop list view implemented as a model view
683 class C4ConsoleQtPropListModel : public QAbstractItemModel
684 {
685  Q_OBJECT
686 
687 public:
688  typedef C4ConsoleQtPropListModelProperty Property;
689  struct PropertyGroup
690  {
691  QString name;
692  std::vector<Property> props;
693  };
694  struct TargetStackEntry // elements of the path for setting child properties
695  {
696  C4PropertyPath path;
697  // TODO: Would be nice to store only path without values and info_proplist. However, info_proplist is hard to resolve when traversing up
698  // So just keep the value for now and hope that proplists do not change during selection
699  C4Value value, info_proplist;
700 
701  TargetStackEntry(const C4PropertyPath &path, const C4Value &value, const C4Value &info_proplist)
702  : path(path), value(value), info_proplist(info_proplist) {}
703  };
704  struct EditedPath // Information about how to find currently edited element (to restore after model update)
705  {
706  C4PropertyPath target_path;
707  int32_t major_index, minor_index;
708  };
709 private:
710  C4Value target_value; // Target value for which properties are listed (either proplist or array)
711  C4Value base_proplist; // Parent-most value, i.e. object or effect selected and framed in editor
712  C4Value info_proplist; // Proplist from which available properties are derived. May differ from target_proplist in child proplists.
713  C4PropertyPath target_path; // script path to target proplist to set values
714  std::list<TargetStackEntry> target_path_stack; // stack of target paths descended into by setting child properties
715  std::vector<PropertyGroup> property_groups;
716  QFont header_font, important_property_font;
717  C4PropertyDelegateFactory *delegate_factory;
718  QItemSelectionModel *selection_model;
719  bool layout_valid; // set to false when property numbers change
720  std::map<std::string, C4ConsoleQtShapeHolder> shapes; // shapes currently shown in editor. Indexed by get path
721 public:
722  C4ConsoleQtPropListModel(C4PropertyDelegateFactory *delegate_factory);
723  ~C4ConsoleQtPropListModel();
724 
725  void SetSelectionModel(QItemSelectionModel *m) { selection_model = m; }
726  QItemSelectionModel *GetSelectionModel() const { return selection_model; }
727 
728  bool AddPropertyGroup(C4PropList *add_proplist, int32_t group_index, QString name, C4PropList *target_proplist, const C4PropertyPath &group_target_path, C4Object *base_object, C4String *default_selection, int32_t *default_selection_index);
729  bool AddEffectGroup(int32_t group_index, C4Object *base_object);
730  void SetBasePropList(C4PropList *new_proplist); // Clear stack and select new proplist
731  void DescendPath(const C4Value &new_value, C4PropList *new_info_proplist, const C4PropertyPath &new_path); // Add proplist to stack
732  void AscendPath(); // go back one element in target path stack
733  void UpdateValue(bool select_default);
734  void DoOnUpdateCall(const C4PropertyPath &updated_path, const C4PropertyDelegate *delegate);
735 
736 private:
737  int32_t UpdateValuePropList(C4PropList *target_proplist, int32_t *default_selection_group, int32_t *default_selection_index);
738  int32_t UpdateValueArray(C4ValueArray *target_array, int32_t *default_selection_group, int32_t *default_selection_index);
739 
740 signals:
741  void ProplistChanged(int32_t major_sel, int32_t minor_sel) const;
742 
743 private slots:
744  void UpdateSelection(int32_t major_sel, int32_t minor_sel) const;
745 
746 public:
747  class C4PropList *GetTargetPropList() const { return target_value.getPropList(); }
748  class C4ValueArray *GetTargetArray() const { return target_value.getArray(); }
749  class C4PropList *GetBasePropList() const { return base_proplist.getPropList(); }
750  int32_t GetTargetPathStackSize() const { return target_path_stack.size(); }
751  const char *GetTargetPathText() const { return target_path.GetGetPath(); }
752  QString GetTargetPathHelp() const;
753  const char *GetTargetPathName() const;
754  bool IsArray() const { return !!target_value.getArray(); }
755  void AddArrayElement();
756  void RemoveArrayElement();
757  bool IsTargetReadonly() const;
758  C4ConsoleQtPropListModel::Property *GetPropByIndex(const QModelIndex &index) const;
759  class C4ConsoleQtShape *GetShapeByPropertyPath(const char *property_path);
760 
761 public:
762  int rowCount(const QModelIndex & parent = QModelIndex()) const override;
763  int columnCount(const QModelIndex & parent = QModelIndex()) const override;
764  QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
765  QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
766  QModelIndex index(int row, int column, const QModelIndex &parent) const override;
767  QModelIndex parent(const QModelIndex &index) const override;
768  Qt::ItemFlags flags(const QModelIndex &index) const override;
769  Qt::DropActions supportedDropActions() const override;
770  bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
771  QStringList mimeTypes() const override;
772  QMimeData *mimeData(const QModelIndexList &indexes) const override;
773 };
774 
775 #endif // WITH_QT_EDITOR
776 #endif // INC_C4ConsoleQtPropListViewer
const char * getData() const
Definition: StdBuf.h:450
C4V_Type
Definition: C4Value.h:23
void Clear()
Definition: StdBuf.h:474
const char * GetCStr() const
Definition: C4StringTable.h:49
T * Get() const
C4ValueArray * getArray() const
Definition: C4Value.h:118
size_t getLength() const
Definition: StdBuf.h:453
bool operator==(const C4TimeMilliseconds &lhs, const C4TimeMilliseconds &rhs)
C4PropList * getPropList() const
Definition: C4Value.h:116