1 | #include "editor.h" |
2 | |
3 | #include <engine/textrender.h> |
4 | |
5 | #include <game/editor/mapitems/image.h> |
6 | #include <game/editor/mapitems/sound.h> |
7 | |
8 | using namespace FontIcons; |
9 | |
10 | const ColorRGBA CEditor::ms_DefaultPropColor = ColorRGBA(1, 1, 1, 0.5f); |
11 | |
12 | int CEditor::DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIds, int *pNewVal, const std::vector<ColorRGBA> &vColors) |
13 | { |
14 | auto Res = DoPropertiesWithState<int>(pToolBox: pToolbox, pProps, pIds, pNewVal, vColors); |
15 | return Res.m_Value; |
16 | } |
17 | |
18 | template<typename E> |
19 | SEditResult<E> CEditor::DoPropertiesWithState(CUIRect *pToolBox, CProperty *pProps, int *pIds, int *pNewVal, const std::vector<ColorRGBA> &vColors) |
20 | { |
21 | int Change = -1; |
22 | EEditState State = EEditState::NONE; |
23 | |
24 | for(int i = 0; pProps[i].m_pName; i++) |
25 | { |
26 | const ColorRGBA *pColor = i >= (int)vColors.size() ? &ms_DefaultPropColor : &vColors[i]; |
27 | |
28 | CUIRect Slot; |
29 | pToolBox->HSplitTop(Cut: 13.0f, pTop: &Slot, pBottom: pToolBox); |
30 | CUIRect Label, Shifter; |
31 | Slot.VSplitMid(pLeft: &Label, pRight: &Shifter); |
32 | Shifter.HMargin(Cut: 1.0f, pOtherRect: &Shifter); |
33 | Ui()->DoLabel(pRect: &Label, pText: pProps[i].m_pName, Size: 10.0f, Align: TEXTALIGN_ML); |
34 | |
35 | if(pProps[i].m_Type == PROPTYPE_INT) |
36 | { |
37 | CUIRect Inc, Dec; |
38 | char aBuf[64]; |
39 | |
40 | Shifter.VSplitRight(Cut: 10.0f, pLeft: &Shifter, pRight: &Inc); |
41 | Shifter.VSplitLeft(Cut: 10.0f, pLeft: &Dec, pRight: &Shifter); |
42 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%d" , pProps[i].m_Value); |
43 | auto NewValueRes = UiDoValueSelector(pId: (char *)&pIds[i], pRect: &Shifter, pLabel: "" , Current: pProps[i].m_Value, Min: pProps[i].m_Min, Max: pProps[i].m_Max, Step: 1, Scale: 1.0f, pToolTip: "Use left mouse button to drag and change the value. Hold shift to be more precise. Rightclick to edit as text." , IsDegree: false, IsHex: false, corners: 0, pColor); |
44 | int NewValue = NewValueRes.m_Value; |
45 | if(NewValue != pProps[i].m_Value || (NewValueRes.m_State != EEditState::NONE && NewValueRes.m_State != EEditState::EDITING)) |
46 | { |
47 | *pNewVal = NewValue; |
48 | Change = i; |
49 | State = NewValueRes.m_State; |
50 | } |
51 | if(DoButton_FontIcon(pId: (char *)&pIds[i] + 1, pText: FONT_ICON_MINUS, Checked: 0, pRect: &Dec, Flags: 0, pToolTip: "Decrease" , Corners: IGraphics::CORNER_L, FontSize: 7.0f)) |
52 | { |
53 | *pNewVal = pProps[i].m_Value - 1; |
54 | Change = i; |
55 | State = EEditState::ONE_GO; |
56 | } |
57 | if(DoButton_FontIcon(pId: ((char *)&pIds[i]) + 2, pText: FONT_ICON_PLUS, Checked: 0, pRect: &Inc, Flags: 0, pToolTip: "Increase" , Corners: IGraphics::CORNER_R, FontSize: 7.0f)) |
58 | { |
59 | *pNewVal = pProps[i].m_Value + 1; |
60 | Change = i; |
61 | State = EEditState::ONE_GO; |
62 | } |
63 | } |
64 | else if(pProps[i].m_Type == PROPTYPE_BOOL) |
65 | { |
66 | CUIRect No, Yes; |
67 | Shifter.VSplitMid(pLeft: &No, pRight: &Yes); |
68 | if(DoButton_Ex(pId: &pIds[i], pText: "No" , Checked: !pProps[i].m_Value, pRect: &No, Flags: 0, pToolTip: "" , Corners: IGraphics::CORNER_L)) |
69 | { |
70 | *pNewVal = 0; |
71 | Change = i; |
72 | State = EEditState::ONE_GO; |
73 | } |
74 | if(DoButton_Ex(pId: ((char *)&pIds[i]) + 1, pText: "Yes" , Checked: pProps[i].m_Value, pRect: &Yes, Flags: 0, pToolTip: "" , Corners: IGraphics::CORNER_R)) |
75 | { |
76 | *pNewVal = 1; |
77 | Change = i; |
78 | State = EEditState::ONE_GO; |
79 | } |
80 | } |
81 | else if(pProps[i].m_Type == PROPTYPE_ANGLE_SCROLL) |
82 | { |
83 | CUIRect Inc, Dec; |
84 | Shifter.VSplitRight(Cut: 10.0f, pLeft: &Shifter, pRight: &Inc); |
85 | Shifter.VSplitLeft(Cut: 10.0f, pLeft: &Dec, pRight: &Shifter); |
86 | const bool Shift = Input()->ShiftIsPressed(); |
87 | int Step = Shift ? 1 : 45; |
88 | int Value = pProps[i].m_Value; |
89 | |
90 | auto NewValueRes = UiDoValueSelector(pId: &pIds[i], pRect: &Shifter, pLabel: "" , Current: Value, Min: pProps[i].m_Min, Max: pProps[i].m_Max, Step: Shift ? 1 : 45, Scale: Shift ? 1.0f : 10.0f, pToolTip: "Use left mouse button to drag and change the value. Hold shift to be more precise. Rightclick to edit as text." , IsDegree: false, IsHex: false, corners: 0); |
91 | int NewValue = NewValueRes.m_Value; |
92 | if(DoButton_FontIcon(pId: &pIds[i] + 1, pText: FONT_ICON_MINUS, Checked: 0, pRect: &Dec, Flags: 0, pToolTip: "Decrease" , Corners: IGraphics::CORNER_L, FontSize: 7.0f)) |
93 | { |
94 | NewValue = (std::ceil(x: (pProps[i].m_Value / (float)Step)) - 1) * Step; |
95 | if(NewValue < 0) |
96 | NewValue += 360; |
97 | State = EEditState::ONE_GO; |
98 | } |
99 | if(DoButton_FontIcon(pId: &pIds[i] + 2, pText: FONT_ICON_PLUS, Checked: 0, pRect: &Inc, Flags: 0, pToolTip: "Increase" , Corners: IGraphics::CORNER_R, FontSize: 7.0f)) |
100 | { |
101 | NewValue = (pProps[i].m_Value + Step) / Step * Step; |
102 | State = EEditState::ONE_GO; |
103 | } |
104 | |
105 | if(NewValue != pProps[i].m_Value || (NewValueRes.m_State != EEditState::NONE && NewValueRes.m_State != EEditState::EDITING)) |
106 | { |
107 | *pNewVal = NewValue % 360; |
108 | Change = i; |
109 | State = NewValueRes.m_State; |
110 | } |
111 | } |
112 | else if(pProps[i].m_Type == PROPTYPE_COLOR) |
113 | { |
114 | const auto &&SetColor = [&](ColorRGBA NewColor) { |
115 | const int NewValue = NewColor.PackAlphaLast(); |
116 | if(NewValue != pProps[i].m_Value || m_ColorPickerPopupContext.m_State != EEditState::EDITING) |
117 | { |
118 | *pNewVal = NewValue; |
119 | Change = i; |
120 | State = m_ColorPickerPopupContext.m_State; |
121 | } |
122 | }; |
123 | DoColorPickerButton(pId: &pIds[i], pRect: &Shifter, Color: ColorRGBA::UnpackAlphaLast<ColorRGBA>(Color: pProps[i].m_Value), SetColor); |
124 | } |
125 | else if(pProps[i].m_Type == PROPTYPE_IMAGE) |
126 | { |
127 | const char *pName; |
128 | if(pProps[i].m_Value < 0) |
129 | pName = "None" ; |
130 | else |
131 | pName = m_Map.m_vpImages[pProps[i].m_Value]->m_aName; |
132 | |
133 | if(DoButton_Ex(pId: &pIds[i], pText: pName, Checked: 0, pRect: &Shifter, Flags: 0, pToolTip: nullptr, Corners: IGraphics::CORNER_ALL)) |
134 | PopupSelectImageInvoke(Current: pProps[i].m_Value, x: Ui()->MouseX(), y: Ui()->MouseY()); |
135 | |
136 | int r = PopupSelectImageResult(); |
137 | if(r >= -1) |
138 | { |
139 | *pNewVal = r; |
140 | Change = i; |
141 | State = EEditState::ONE_GO; |
142 | } |
143 | } |
144 | else if(pProps[i].m_Type == PROPTYPE_SHIFT) |
145 | { |
146 | CUIRect Left, Right, Up, Down; |
147 | Shifter.VSplitMid(pLeft: &Left, pRight: &Up, Spacing: 2.0f); |
148 | Left.VSplitLeft(Cut: 10.0f, pLeft: &Left, pRight: &Shifter); |
149 | Shifter.VSplitRight(Cut: 10.0f, pLeft: &Shifter, pRight: &Right); |
150 | Shifter.Draw(Color: ColorRGBA(1, 1, 1, 0.5f), Corners: IGraphics::CORNER_NONE, Rounding: 0.0f); |
151 | Ui()->DoLabel(pRect: &Shifter, pText: "X" , Size: 10.0f, Align: TEXTALIGN_MC); |
152 | Up.VSplitLeft(Cut: 10.0f, pLeft: &Up, pRight: &Shifter); |
153 | Shifter.VSplitRight(Cut: 10.0f, pLeft: &Shifter, pRight: &Down); |
154 | Shifter.Draw(Color: ColorRGBA(1, 1, 1, 0.5f), Corners: IGraphics::CORNER_NONE, Rounding: 0.0f); |
155 | Ui()->DoLabel(pRect: &Shifter, pText: "Y" , Size: 10.0f, Align: TEXTALIGN_MC); |
156 | if(DoButton_FontIcon(pId: &pIds[i], pText: FONT_ICON_MINUS, Checked: 0, pRect: &Left, Flags: 0, pToolTip: "Left" , Corners: IGraphics::CORNER_L, FontSize: 7.0f)) |
157 | { |
158 | *pNewVal = DIRECTION_LEFT; |
159 | Change = i; |
160 | State = EEditState::ONE_GO; |
161 | } |
162 | if(DoButton_FontIcon(pId: ((char *)&pIds[i]) + 3, pText: FONT_ICON_PLUS, Checked: 0, pRect: &Right, Flags: 0, pToolTip: "Right" , Corners: IGraphics::CORNER_R, FontSize: 7.0f)) |
163 | { |
164 | *pNewVal = DIRECTION_RIGHT; |
165 | Change = i; |
166 | State = EEditState::ONE_GO; |
167 | } |
168 | if(DoButton_FontIcon(pId: ((char *)&pIds[i]) + 1, pText: FONT_ICON_MINUS, Checked: 0, pRect: &Up, Flags: 0, pToolTip: "Up" , Corners: IGraphics::CORNER_L, FontSize: 7.0f)) |
169 | { |
170 | *pNewVal = DIRECTION_UP; |
171 | Change = i; |
172 | State = EEditState::ONE_GO; |
173 | } |
174 | if(DoButton_FontIcon(pId: ((char *)&pIds[i]) + 2, pText: FONT_ICON_PLUS, Checked: 0, pRect: &Down, Flags: 0, pToolTip: "Down" , Corners: IGraphics::CORNER_R, FontSize: 7.0f)) |
175 | { |
176 | *pNewVal = DIRECTION_DOWN; |
177 | Change = i; |
178 | State = EEditState::ONE_GO; |
179 | } |
180 | } |
181 | else if(pProps[i].m_Type == PROPTYPE_SOUND) |
182 | { |
183 | const char *pName; |
184 | if(pProps[i].m_Value < 0) |
185 | pName = "None" ; |
186 | else |
187 | pName = m_Map.m_vpSounds[pProps[i].m_Value]->m_aName; |
188 | |
189 | if(DoButton_Ex(pId: &pIds[i], pText: pName, Checked: 0, pRect: &Shifter, Flags: 0, pToolTip: nullptr, Corners: IGraphics::CORNER_ALL)) |
190 | PopupSelectSoundInvoke(Current: pProps[i].m_Value, x: Ui()->MouseX(), y: Ui()->MouseY()); |
191 | |
192 | int r = PopupSelectSoundResult(); |
193 | if(r >= -1) |
194 | { |
195 | *pNewVal = r; |
196 | Change = i; |
197 | State = EEditState::ONE_GO; |
198 | } |
199 | } |
200 | else if(pProps[i].m_Type == PROPTYPE_AUTOMAPPER) |
201 | { |
202 | const char *pName; |
203 | if(pProps[i].m_Value < 0 || pProps[i].m_Min < 0 || pProps[i].m_Min >= (int)m_Map.m_vpImages.size()) |
204 | pName = "None" ; |
205 | else |
206 | pName = m_Map.m_vpImages[pProps[i].m_Min]->m_AutoMapper.GetConfigName(Index: pProps[i].m_Value); |
207 | |
208 | if(DoButton_Ex(pId: &pIds[i], pText: pName, Checked: 0, pRect: &Shifter, Flags: 0, pToolTip: nullptr, Corners: IGraphics::CORNER_ALL)) |
209 | PopupSelectConfigAutoMapInvoke(Current: pProps[i].m_Value, x: Ui()->MouseX(), y: Ui()->MouseY()); |
210 | |
211 | int r = PopupSelectConfigAutoMapResult(); |
212 | if(r >= -1) |
213 | { |
214 | *pNewVal = r; |
215 | Change = i; |
216 | State = EEditState::ONE_GO; |
217 | } |
218 | } |
219 | else if(pProps[i].m_Type == PROPTYPE_ENVELOPE) |
220 | { |
221 | CUIRect Inc, Dec; |
222 | char aBuf[8]; |
223 | int CurValue = pProps[i].m_Value; |
224 | |
225 | Shifter.VSplitRight(Cut: 10.0f, pLeft: &Shifter, pRight: &Inc); |
226 | Shifter.VSplitLeft(Cut: 10.0f, pLeft: &Dec, pRight: &Shifter); |
227 | |
228 | if(CurValue <= 0) |
229 | str_copy(dst&: aBuf, src: "None:" ); |
230 | else if(m_Map.m_vpEnvelopes[CurValue - 1]->m_aName[0]) |
231 | { |
232 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s:" , m_Map.m_vpEnvelopes[CurValue - 1]->m_aName); |
233 | if(!str_endswith(str: aBuf, suffix: ":" )) |
234 | { |
235 | aBuf[sizeof(aBuf) - 2] = ':'; |
236 | aBuf[sizeof(aBuf) - 1] = '\0'; |
237 | } |
238 | } |
239 | else |
240 | aBuf[0] = '\0'; |
241 | |
242 | auto NewValueRes = UiDoValueSelector(pId: (char *)&pIds[i], pRect: &Shifter, pLabel: aBuf, Current: CurValue, Min: 0, Max: m_Map.m_vpEnvelopes.size(), Step: 1, Scale: 1.0f, pToolTip: "Set Envelope" , IsDegree: false, IsHex: false, corners: IGraphics::CORNER_NONE); |
243 | int NewVal = NewValueRes.m_Value; |
244 | if(NewVal != CurValue || (NewValueRes.m_State != EEditState::NONE && NewValueRes.m_State != EEditState::EDITING)) |
245 | { |
246 | *pNewVal = NewVal; |
247 | Change = i; |
248 | State = NewValueRes.m_State; |
249 | } |
250 | |
251 | if(DoButton_FontIcon(pId: (char *)&pIds[i] + 1, pText: FONT_ICON_MINUS, Checked: 0, pRect: &Dec, Flags: 0, pToolTip: "Previous Envelope" , Corners: IGraphics::CORNER_L, FontSize: 7.0f)) |
252 | { |
253 | *pNewVal = pProps[i].m_Value - 1; |
254 | Change = i; |
255 | State = EEditState::ONE_GO; |
256 | } |
257 | if(DoButton_FontIcon(pId: ((char *)&pIds[i]) + 2, pText: FONT_ICON_PLUS, Checked: 0, pRect: &Inc, Flags: 0, pToolTip: "Next Envelope" , Corners: IGraphics::CORNER_R, FontSize: 7.0f)) |
258 | { |
259 | *pNewVal = pProps[i].m_Value + 1; |
260 | Change = i; |
261 | State = EEditState::ONE_GO; |
262 | } |
263 | } |
264 | } |
265 | |
266 | return SEditResult<E>{State, static_cast<E>(Change)}; |
267 | } |
268 | |
269 | template SEditResult<ECircleShapeProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
270 | template SEditResult<ERectangleShapeProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
271 | template SEditResult<EGroupProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
272 | template SEditResult<ELayerProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
273 | template SEditResult<ELayerQuadsProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
274 | template SEditResult<ETilesProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
275 | template SEditResult<ETilesCommonProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
276 | template SEditResult<ELayerSoundsProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
277 | template SEditResult<EQuadProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
278 | template SEditResult<EQuadPointProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
279 | template SEditResult<ESoundProp> CEditor::DoPropertiesWithState(CUIRect *, CProperty *, int *, int *, const std::vector<ColorRGBA> &); |
280 | |