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