OpenClonk
C4ConsoleQtShapes.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 /* Editable shapes in the viewports (like e.g. AI guard range rectangles) */
18 
19 #ifndef INC_C4ConsoleQtShapes
20 #define INC_C4ConsoleQtShapes
21 #ifdef WITH_QT_EDITOR
22 
23 #include "C4Include.h" // needed for automoc
24 #include "editor/C4ConsoleGUI.h" // for OpenGL
25 #include "editor/C4ConsoleQt.h"
26 #include "script/C4Value.h"
27 
28 // Shape base class
29 class C4ConsoleQtShape : public QObject
30 {
31  Q_OBJECT
32 protected:
33  C4Value rel_obj; // Object relative to which shape is defined
34  C4Value properties;
35  bool is_relative;
36  int32_t dragging_border, selected_border;
37  uint32_t border_color;
38  const class C4PropertyDelegateShape *parent_delegate;
39  class C4ConsoleQtShapes *shape_list;
40 
41 protected:
42  // Return shape color, or dragged border color if index is the border currently being dragged
43  uint32_t GetBorderColor(int32_t border_index, bool dragging_border_is_bitmask, uint32_t default_color = 0u) const;
44 public:
45  C4ConsoleQtShape(class C4Object *for_obj, C4PropList *props, const class C4PropertyDelegateShape *parent_delegate, class C4ConsoleQtShapes *shape_list);
46 
47  virtual bool IsHit(int32_t x, int32_t y, int32_t hit_range, Qt::CursorShape *drag_cursor, int32_t *drag_border, bool shift_down, bool ctrl_down) = 0;
48  virtual void Draw(class C4TargetFacet &cgo, float line_width) = 0;
49 
50  // Coordinate transform: Add object
51  int32_t AbsX(int32_t rel_x=0) const;
52  int32_t AbsY(int32_t rel_y=0) const;
53 
54  // Start/stop dragging
55  virtual bool StartDragging(int32_t *border, int32_t x, int32_t y, bool shift_down, bool ctrl_down) { dragging_border = *border; return true; }
56  virtual void StopDragging();
57  virtual void Drag(int32_t x, int32_t y, int32_t dx, int32_t dy, int32_t hit_range, Qt::CursorShape *drag_cursor) = 0;
58  bool IsDragging() const { return dragging_border != -1; }
59 
60  virtual void SetValue(const C4Value &val) = 0;
61  virtual C4Value GetValue() const = 0; // Return current shape as C4Value to be stored back to property
62 
63  const class C4PropertyDelegateShape *GetParentDelegate() const { return parent_delegate; }
64  const C4PropList *GetProperties() const { return properties.getPropList(); }
65 
66  virtual bool IsSelectionAllowed(int32_t border) const { return false; }
67  bool Select(int32_t border);
68  void ResetSelection();
69  virtual bool GetSelectedData(const C4Value &shape_val, const class C4PropertyPath &shape_property_path, C4PropList **shape_item_editorprops, C4PropList **shape_item_value, C4String **shape_item_name, class C4PropertyPath *shape_item_target_path) const
70  {
71  return false;
72  }
73 
74  // Specialization
75  virtual class C4ConsoleQtGraph *GetGraphShape() { return nullptr; }
76 
77 signals:
78  void ShapeDragged();
79  void BorderSelectionChanged();
80 };
81 
82 // Rectangular shape
83 class C4ConsoleQtRect : public C4ConsoleQtShape
84 {
85 private:
86  int32_t left, top, right, bottom;
87  bool store_as_proplist;
88  bool properties_lowercase;
89 public:
90  C4ConsoleQtRect(class C4Object *for_obj, C4PropList *props, const class C4PropertyDelegateShape *parent_delegate, class C4ConsoleQtShapes *shape_list);
91 
92  bool IsHit(int32_t x, int32_t y, int32_t hit_range, Qt::CursorShape *drag_cursor, int32_t *drag_border, bool shift_down, bool ctrl_down) override;
93  void Draw(class C4TargetFacet &cgo, float line_width) override;
94  void Drag(int32_t x, int32_t y, int32_t dx, int32_t dy, int32_t hit_range, Qt::CursorShape *drag_cursor) override;
95 
96  void SetValue(const C4Value &val) override;
97  C4Value GetValue() const override;
98 };
99 
100 // Circular shape
101 class C4ConsoleQtCircle : public C4ConsoleQtShape
102 {
103 private:
104  int32_t radius;
105  int32_t cx, cy;
106  bool can_move_center;
107 public:
108  C4ConsoleQtCircle(class C4Object *for_obj, C4PropList *props, const class C4PropertyDelegateShape *parent_delegate, class C4ConsoleQtShapes *shape_list);
109 
110  bool IsHit(int32_t x, int32_t y, int32_t hit_range, Qt::CursorShape *drag_cursor, int32_t *drag_border, bool shift_down, bool ctrl_down) override;
111  void Draw(class C4TargetFacet &cgo, float line_width) override;
112  void Drag(int32_t x, int32_t y, int32_t dx, int32_t dy, int32_t hit_range, Qt::CursorShape *drag_cursor) override;
113 
114  void SetValue(const C4Value &val) override;
115  C4Value GetValue() const override;
116 };
117 
118 // Single position shape
119 class C4ConsoleQtPoint : public C4ConsoleQtShape
120 {
121 private:
122  int32_t cx, cy;
123  bool horizontal_fix{ false };
124  bool vertical_fix{ false };
125 public:
126  C4ConsoleQtPoint(class C4Object *for_obj, C4PropList *props, const class C4PropertyDelegateShape *parent_delegate, class C4ConsoleQtShapes *shape_list);
127 
128  bool IsHit(int32_t x, int32_t y, int32_t hit_range, Qt::CursorShape *drag_cursor, int32_t *drag_border, bool shift_down, bool ctrl_down) override;
129  void Draw(class C4TargetFacet &cgo, float line_width) override;
130  void Drag(int32_t x, int32_t y, int32_t dx, int32_t dy, int32_t hit_range, Qt::CursorShape *drag_cursor) override;
131 
132  void SetValue(const C4Value &val) override;
133  C4Value GetValue() const override;
134 };
135 
136 // Vertices and edges
137 class C4ConsoleQtGraph : public C4ConsoleQtShape
138 {
139  Q_OBJECT
140 protected:
141  struct Vertex
142  {
143  int32_t x{0}, y{0};
144  uint32_t color{0u}; // 0 = default color
145 
146  Vertex() = default;
147  };
148 
149  struct Edge
150  {
151  int32_t vertex_indices[2]; // index into vertices array
152  uint32_t color{0u}; // 0 = default color
153  uint32_t line_thickness{1};
154 
155  Edge() { vertex_indices[0] = vertex_indices[1] = -1; }
156  bool connects_to(int32_t vertex_index) const;
157  bool connects_to(int32_t vertex_index, int32_t *idx) const;
158  };
159 
160  // Actual vertex and edge data
161  struct GraphData
162  {
163  std::vector<Vertex> vertices;
164  std::vector<Edge> edges;
165 
166  // Convert elements to/from C4Value
167  C4ValueArray *GetVerticesValue() const;
168  C4ValueArray *GetEdgesValue() const;
169  void SetVerticesValue(const C4ValueArray *vvertices);
170  void SetEdgesValue(const C4ValueArray *vedges);
171 
172  int32_t GetEdgeCountForVertex(int32_t vertex_index) const;
173 
174  // Graph modification. Called from C4ConsoleQtGraph::EditGraph only, which propagates the change to the value via the queue
175  void SetVertexPos(int32_t vertex_index, int32_t new_x, int32_t new_y);
176  void EditEdge(int32_t edge_index, int32_t change_vertex_index, int32_t new_vertex_index);
177  void InsertEdgeBefore(int32_t insert_edge_index, int32_t vertex1, int32_t vertex2);
178  void InsertVertexBefore(int32_t insert_vertex_index, int32_t x, int32_t y);
179  void RemoveEdge(int32_t edge_index);
180  void RemoveVertex(int32_t vertex_index);
181 
182  // Graph modification on internal C4Value script data. Called from C4ConsoleQtGraph::EditGraphValue.
183  static void EditGraphValue_SetVertexPos(C4ValueArray *vvertices, int32_t vertex_index, int32_t new_x, int32_t new_y);
184  static void EditGraphValue_EditEdge(C4ValueArray *vvertices, C4ValueArray *vedges, int32_t edge_index, int32_t change_vertex_index, int32_t new_vertex_index);
185  static void EditGraphValue_InsertEdgeBefore(C4ValueArray *vvertices, C4ValueArray *vedges, int32_t insert_edge_index, int32_t vertex1, int32_t vertex2);
186  static void EditGraphValue_InsertVertexBefore(C4ValueArray *vvertices, C4ValueArray *vedges, int32_t insert_vertex_index, int32_t x, int32_t y);
187  static void EditGraphValue_RemoveEdge(C4ValueArray *vvertices, C4ValueArray *vedges, int32_t edge_index);
188  static void EditGraphValue_RemoveVertex(C4ValueArray *vvertices, C4ValueArray *vedges, int32_t vertex_index);
189  static bool EditGraphValue_EdgeConnectsTo(C4PropList *edge, int32_t vertex_index);
190  } graph;
191 
192  bool allow_vertex_selection = false; // If vertices on the graph can be selected
193  bool allow_edge_selection = false; // If edges on the graph can be selected
194  bool horizontal_fix = false; // If edges are locked horizontally
195  bool vertical_fix = false; // If edges are locked vertically
196  bool structure_fix = false; // If edge+vertex insertion/deletion is blocked
197  bool draw_arrows = false; // If directions on edges are to be signified with arrowheads
198 
199  C4Value vertex_delegate, edge_delegate;
200 
201  // Drag snap to other vertices
202  int32_t drag_snap_offset_x = 0, drag_snap_offset_y = 0;
203  bool drag_snapped = false;
204  int32_t drag_snap_vertex = -1, drag_source_vertex_index = -1;
205 
206  // Resolve border_index to vertices/edges: Use negative indices for edges and zero/positive indices for vertices
207  static bool IsVertexDrag(int32_t border) { return border >= 0; }
208  static bool IsEdgeDrag(int32_t border) { return border < -1; }
209  static int32_t DragBorderToVertex(int32_t border) { return border; }
210  static int32_t DragBorderToEdge(int32_t border) { return -2 - border; }
211  static int32_t VertexToDragBorder(int32_t vertex) { return vertex; }
212  static int32_t EdgeToDragBorder(int32_t edge) { return -edge - 2; }
213 
214  void DrawEdge(class C4TargetFacet &cgo, const Vertex &v0, const Vertex &v2, uint32_t clr, float line_width, float edge_width, bool highlight);
215 public:
216  C4ConsoleQtGraph(class C4Object *for_obj, C4PropList *props, const class C4PropertyDelegateShape *parent_delegate, class C4ConsoleQtShapes *shape_list);
217 
218  bool IsHit(int32_t x, int32_t y, int32_t hit_range, Qt::CursorShape *drag_cursor, int32_t *drag_border, bool shift_down, bool ctrl_down) override;
219  void Draw(class C4TargetFacet &cgo, float line_width) override;
220  void Drag(int32_t x, int32_t y, int32_t dx, int32_t dy, int32_t hit_range, Qt::CursorShape *drag_cursor) override;
221  bool StartDragging(int32_t *border, int32_t x, int32_t y, bool shift_down, bool ctrl_down) override;
222  void StopDragging() override;
223 
224  void SetValue(const C4Value &val) override;
225  C4Value GetValue() const override;
226 
227  bool IsSelectionAllowed(int32_t border) const override;
228  bool GetSelectedData(const C4Value &shape_val, const class C4PropertyPath &shape_property_path, C4PropList **shape_item_editorprops, C4PropList **shape_item_value, C4String **shape_item_name, class C4PropertyPath *shape_item_target_path) const override;
229 
230  void EditGraph(bool signal_change, C4ControlEditGraph::Action action, int32_t index, int32_t x, int32_t y);
231  static void EditGraphValue(C4Value &val, C4ControlEditGraph::Action action, int32_t index, int32_t x, int32_t y);
232 
233  class C4ConsoleQtGraph *GetGraphShape() override { return this; }
234 
235 protected:
236  void EditEdge(int32_t edge_index, int32_t change_vertex_index, int32_t new_vertex);
237  int32_t AddVertex(int32_t new_x, int32_t new_y);
238  int32_t AddEdge(int32_t connect_vertex_index_1, int32_t connect_vertex_index_2);
239  void InsertVertexBefore(int32_t insert_vertex_index, int32_t x, int32_t y);
240  void InsertEdgeBefore(int32_t insert_edge_index, int32_t connect_vertex_index_1, int32_t connect_vertex_index_2);
241  virtual int32_t InsertVertexOnEdge(int32_t split_edge_index, int32_t x, int32_t y);
242  virtual int32_t InsertVertexOnVertex(int32_t target_vertex_index, int32_t x, int32_t y);
243  virtual void RemoveEdge(int32_t edge_index);
244  virtual void RemoveVertex(int32_t vertex_index, bool create_skip_connection);
245 
246  virtual bool IsPolyline() const { return false; }
247 
248  // Check if given vertex/edge can be modified under given shift state
249  virtual bool IsVertexHit(int32_t vertex_index, Qt::CursorShape *drag_cursor, bool shift_down, bool ctrl_down);
250  virtual bool IsEdgeHit(int32_t edge_index, Qt::CursorShape *drag_cursor, bool shift_down, bool ctrl_down);
251 
252 signals:
253  void GraphEdit(C4ControlEditGraph::Action action, int32_t index, int32_t x, int32_t y);
254 };
255 
256 // Specialization of graph: One line of connected vertices
257 class C4ConsoleQtPolyline : public C4ConsoleQtGraph
258 {
259 private:
260  bool start_from_object = false;
261 public:
262  C4ConsoleQtPolyline(class C4Object *for_obj, C4PropList *props, const class C4PropertyDelegateShape *parent_delegate, class C4ConsoleQtShapes *shape_list);
263 
264  void Draw(class C4TargetFacet &cgo, float line_width) override;
265  void SetValue(const C4Value &val) override;
266  C4Value GetValue() const override;
267 
268 protected:
269  int32_t InsertVertexOnEdge(int32_t split_edge_index, int32_t x, int32_t y) override;
270  int32_t InsertVertexOnVertex(int32_t target_vertex_index, int32_t x, int32_t y) override;
271  void RemoveEdge(int32_t edge_index) override;
272 
273  bool IsVertexHit(int32_t vertex_index, Qt::CursorShape *drag_cursor, bool shift_down, bool ctrl_down) override;
274  bool IsPolyline() const override { return true; }
275 };
276 
277 // Specialization of graph: One closed line of connected vertices
278 class C4ConsoleQtPolygon : public C4ConsoleQtPolyline
279 {
280 public:
281  C4ConsoleQtPolygon(class C4Object *for_obj, C4PropList *props, const class C4PropertyDelegateShape *parent_delegate, class C4ConsoleQtShapes *shape_list)
282  : C4ConsoleQtPolyline(for_obj, props, parent_delegate, shape_list) {}
283 
284  void SetValue(const C4Value &val) override;
285 
286 protected:
287  int32_t InsertVertexOnEdge(int32_t split_edge_index, int32_t x, int32_t y) override;
288  int32_t InsertVertexOnVertex(int32_t target_vertex_index, int32_t x, int32_t y) override;
289  void RemoveEdge(int32_t edge_index) override;
290 
291  bool IsVertexHit(int32_t vertex_index, Qt::CursorShape *drag_cursor, bool shift_down, bool ctrl_down) override;
292 };
293 
294 /* List of all current editable Qt shapes */
295 class C4ConsoleQtShapes
296 {
297  typedef std::list<std::unique_ptr<C4ConsoleQtShape> > ShapeList;
298  ShapeList shapes;
299  C4ConsoleQtShape *dragging_shape{nullptr}, *selected_shape{nullptr};
300  Qt::CursorShape drag_cursor{Qt::CursorShape::ArrowCursor};
301  float drag_x{0}, drag_y{0};
302 public:
303  C4ConsoleQtShapes() = default;
304 
305  C4ConsoleQtShape *CreateShape(class C4Object *for_obj, C4PropList *props, const C4Value &val, const class C4PropertyDelegateShape *parent_delegate);
306  void AddShape(C4ConsoleQtShape *shape);
307  void RemoveShape(C4ConsoleQtShape *shape);
308  void ClearShapes();
309 
310  // Mouse callbacks from viewports to execute shape dragging
311  bool MouseDown(float x, float y, float hit_range, bool shift_down, bool ctrl_down); // return true if a shape was hit
312  void MouseMove(float x, float y, bool left_down, float hit_range, bool shift_down, bool ctrl_down); // move move: Execute shape dragging
313  void MouseUp(float x, float y, bool shift_down, bool ctrl_down);
314 
315  void Draw(C4TargetFacet &cgo);
316 
317  // Dragging info
318  bool HasDragCursor() const { return drag_cursor != Qt::CursorShape::ArrowCursor; }
319  Qt::CursorShape GetDragCursor() const { return drag_cursor; }
320  bool IsDragging() const { return !!dragging_shape; }
321 
322  // Selected shapes
323  void SetSelectedShape(C4ConsoleQtShape *new_selection, int32_t selected_border);
324  C4ConsoleQtShape *GetSelectedShape() const { return selected_shape; }
325  bool GetSelectedShapeData(const C4Value &shape_val, const class C4PropertyPath &shape_property_path, C4PropList **shape_item_editorprops, C4PropList **shape_item_value, C4String **shape_item_name, class C4PropertyPath *shape_item_target_path) const;
326 };
327 
328 /* Shape holder class: Handles adding/removal of shape to shapes list */
329 class C4ConsoleQtShapeHolder
330 {
331  C4ConsoleQtShape *shape{nullptr};
332  bool last_visit;
333  C4Value last_value;
334 
335  static bool last_visit_flag;
336 
337 public:
338  C4ConsoleQtShapeHolder() = default;
339  ~C4ConsoleQtShapeHolder() { Clear(); }
340 
341  void Clear();
342  void Set(C4ConsoleQtShape *new_shape);
343  C4ConsoleQtShape *Get() const { return shape; }
344 
345  // Check counter to determine unused shapes
346  void visit() { last_visit = last_visit_flag; }
347  bool was_visited() const { return last_visit == last_visit_flag; }
348  static void begin_visit() { last_visit_flag = !last_visit_flag; }
349 
350  // Remember pointer to last proplist or array set in value to reflect scripted updates
351  const C4Value &GetLastValue() const { return last_value; }
352  void SetLastValue(const C4Value &new_val) { last_value = new_val; }
353 };
354 
355 
356 #endif // WITH_QT_EDITOR
357 #endif // INC_C4ConsoleQtShapes
C4PropList * getPropList() const
Definition: C4Value.h:116
void MouseMove(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam, class C4Viewport *pVP)
Definition: C4Gui.h:2832