neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
i_geometry.hpp
Go to the documentation of this file.
1// i_geometry.hpp
2/*
3 neogfx C++ App/Game Engine
4 Copyright (c) 2015, 2020 Leigh Johnston. All Rights Reserved.
5
6 This program is free software: you can redistribute it and / or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#pragma once
21
22#include <neogfx/neogfx.hpp>
23#include <iostream>
25#include <neogfx/core/units.hpp>
26
27namespace neogfx
28{
29 enum class size_constraint : uint32_t
30 {
31 Fixed,
32 Minimum,
33 Maximum,
35 MinimumExpanding, // minimum unless a weight is defined
36 DefaultMinimumExpanding, // default minimum unless a weight is defined
37 ExpandingUniform, // leftover pixels are unwanted to ensure siblings are the same (pixel perfect) size after weighting
38 Manual
39 };
40
41 enum class visibility_constraint : uint32_t
42 {
43 Ignore,
45 };
46
47 enum class aspect_ratio : uint32_t
48 {
49 Ignore,
50 Stretch,
51 Keep,
53 };
54
55 enum class cardinal : uint32_t
56 {
58 North,
60 West,
61 Center,
62 East,
64 South,
66 };
67
68 enum class corner : uint32_t
69 {
70 TopLeft,
74 };
75}
76
83declare_enum_string(neogfx::size_constraint, DefaultMinimumExpanding)
87
92
99
111
118
119namespace neogfx
120{
121 class size_policy
122 {
123 public:
124 typedef size_policy abstract_type; // todo
125 public:
126 struct no_aspect_ratio : std::logic_error { no_aspect_ratio() : std::logic_error("neogfx::size_policy::no_aspect_ratio") {} };
127 public:
128 size_policy(
129 size_constraint aSizeConstraint,
130 visibility_constraint aVisibility = visibility_constraint::Consider,
131 optional_size const& aAspectRatio = {}) :
132 iHorizontalConstraint{ aSizeConstraint },
133 iVerticalConstraint{ aSizeConstraint },
134 iVisibility{ aVisibility },
135 iAspectRatio{ aAspectRatio }
136 {
137 }
138 size_policy(
139 size_constraint aHorizontalConstraint,
140 size_constraint aVerticalConstraint,
141 visibility_constraint aVisibility = visibility_constraint::Consider,
142 optional_size const& aAspectRatio = {}) :
143 iHorizontalConstraint{ aHorizontalConstraint },
144 iVerticalConstraint{ aVerticalConstraint },
145 iVisibility{ aVisibility },
146 iAspectRatio{ aAspectRatio }
147 {
148 }
149 public:
150 bool operator==(const size_policy& aRhs) const
151 {
152 return iHorizontalConstraint == aRhs.iHorizontalConstraint &&
153 iVerticalConstraint == aRhs.iVerticalConstraint &&
154 iVisibility == aRhs.iVisibility &&
155 iAspectRatio == aRhs.iAspectRatio;
156 }
157 bool operator!=(const size_policy& aRhs) const
158 {
159 return !(*this == aRhs);
160 }
161 public:
162 size_constraint horizontal_constraint(bool aIgnoreUniformity = true) const
163 {
164 if (iHorizontalConstraint != size_constraint::ExpandingUniform)
165 return iHorizontalConstraint;
166 return aIgnoreUniformity ? size_constraint::Expanding : size_constraint::ExpandingUniform;
167 }
168 size_constraint vertical_constraint(bool aIgnoreUniformity = true) const
169 {
170 if (iVerticalConstraint != size_constraint::ExpandingUniform)
171 return iVerticalConstraint;
172 return aIgnoreUniformity ? size_constraint::Expanding : size_constraint::ExpandingUniform;
173 }
174 size_policy& set_constraint(size_constraint aConstraint)
175 {
176 iHorizontalConstraint = aConstraint;
177 iVerticalConstraint = aConstraint;
178 return *this;
179 }
180 size_policy& set_horizontal_constraint(size_constraint aHorizontalConstraint)
181 {
182 iHorizontalConstraint = aHorizontalConstraint;
183 return *this;
184 }
185 size_policy& set_vertical_constraint(size_constraint aVerticalConstraint)
186 {
187 iVerticalConstraint = aVerticalConstraint;
188 return *this;
189 }
190 visibility_constraint visibility() const
191 {
192 return iVisibility;
193 }
194 bool ignore_visibility() const
195 {
196 return iVisibility == visibility_constraint::Ignore;
197 }
198 size_policy& set_ignore_visibility(bool aIgnoreVisibility)
199 {
200 iVisibility = (aIgnoreVisibility ? visibility_constraint::Ignore : visibility_constraint::Consider);
201 return *this;
202 }
203 bool maintain_aspect_ratio() const
204 {
205 return iAspectRatio != std::nullopt;
206 }
207 size aspect_ratio() const
208 {
209 if (maintain_aspect_ratio())
210 return *iAspectRatio;
211 throw no_aspect_ratio();
212 }
213 size_policy& set_aspect_ratio(optional_size const& aAspectRatio)
214 {
215 iAspectRatio = aAspectRatio;
216 return *this;
217 }
218 public:
219 static size_policy from_string(std::string const& aHorizontalConstraint, std::string const& aVerticalConstraint)
220 {
221 return size_policy{
222 neolib::string_to_enum<size_constraint>(aHorizontalConstraint),
223 neolib::string_to_enum<size_constraint>(aVerticalConstraint) };
224 }
225 void to_string(std::string& aHorizontalConstraint, std::string& aVerticalConstraint) const
226 {
227 aHorizontalConstraint = enum_to_string(horizontal_constraint());
228 aVerticalConstraint = enum_to_string(vertical_constraint());
229 }
230 private:
231 size_constraint iHorizontalConstraint;
232 size_constraint iVerticalConstraint;
233 visibility_constraint iVisibility;
234 optional_size iAspectRatio;
235 };
236
237 template <typename Elem, typename Traits>
238 inline std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& aStream, const size_policy& aPolicy)
239 {
240 aStream << "{" << aPolicy.horizontal_constraint() << " " << aPolicy.vertical_constraint() << " " << aPolicy.visibility() << " " << (aPolicy.maintain_aspect_ratio() ? aPolicy.aspect_ratio() : optional_size{}) << "}";
241 return aStream;
242 }
243
244 using optional_size_policy = optional<size_policy>;
245
246 template <typename Elem, typename Traits>
247 inline std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& aStream, const optional_size_policy& aPolicy)
248 {
249 if (aPolicy != std::nullopt)
250 return aStream << *aPolicy;
251 return aStream << "{ nullopt }";
252 }
253
254 class i_geometry : public i_units_context
255 {
256 template <typename>
257 friend class layout_item;
258 public:
259 virtual point origin() const = 0;
260 virtual void reset_origin() const = 0;
261 virtual point position() const = 0;
262 virtual void set_position(const point& aPosition) = 0;
263 virtual size extents() const = 0;
264 virtual void set_extents(const size& aExtents) = 0;
265 virtual bool has_size_policy() const noexcept = 0;
266 virtual neogfx::size_policy size_policy() const = 0;
267 virtual void set_size_policy(const optional_size_policy& aSizePolicy, bool aUpdateLayout = true) = 0;
268 virtual bool has_weight() const noexcept = 0;
269 virtual size weight() const = 0;
270 virtual void set_weight(optional_size const& aWeight, bool aUpdateLayout = true) = 0;
271 virtual bool has_ideal_size() const noexcept = 0;
272 virtual bool is_ideal_size_constrained() const noexcept = 0;
273 virtual size ideal_size(optional_size const& aAvailableSpace = {}) const = 0;
274 virtual void set_ideal_size(optional_size const& aIdealSize, bool aUpdateLayout = true) = 0;
275 virtual bool has_minimum_size() const noexcept = 0;
276 virtual bool is_minimum_size_constrained() const noexcept = 0;
277 virtual size minimum_size(optional_size const& aAvailableSpace = {}) const = 0;
278 virtual void set_minimum_size(optional_size const& aMinimumSize, bool aUpdateLayout = true) = 0;
279 virtual bool has_maximum_size() const noexcept = 0;
280 virtual bool is_maximum_size_constrained() const noexcept = 0;
281 virtual size maximum_size(optional_size const& aAvailableSpace = {}) const = 0;
282 virtual void set_maximum_size(optional_size const& aMaximumSize, bool aUpdateLayout = true) = 0;
283 virtual bool has_fixed_size() const noexcept = 0;
284 virtual size fixed_size(optional_size const& aAvailableSpace = {}) const = 0;
285 virtual void set_fixed_size(optional_size const& aFixedSize, bool aUpdateLayout = true) = 0;
286 virtual bool has_transformation() const noexcept = 0;
287 virtual mat33 const& transformation(bool aCombineAncestorTransformations = false) const = 0;
288 virtual void set_transformation(optional_mat33 const& aTransformation, bool aUpdateLayout = true) = 0;
289 public:
290 virtual bool has_margin() const noexcept = 0;
291 virtual neogfx::margin margin() const = 0;
292 virtual void set_margin(optional_margin const& aMargin, bool aUpdateLayout = true) = 0;
293 virtual bool has_border() const noexcept = 0;
294 virtual neogfx::border border() const = 0;
295 virtual void set_border(optional_border const& aBorder, bool aUpdateLayout = true) = 0;
296 virtual bool has_padding() const noexcept = 0;
297 virtual neogfx::padding padding() const = 0;
298 virtual void set_padding(optional_padding const& aPadding, bool aUpdateLayout = true) = 0;
299 protected:
300 virtual point unconstrained_origin() const = 0;
301 virtual point unconstrained_position() const = 0;
302 // helpers
303 public:
304 size apply_fixed_size(size const& aResult) const
305 {
306 auto newResult = aResult;
307 if (size_policy().horizontal_constraint() == size_constraint::Fixed && has_fixed_size())
308 newResult.cx = fixed_size().cx;
309 if (size_policy().vertical_constraint() == size_constraint::Fixed && has_fixed_size())
310 newResult.cy = fixed_size().cy;
311 return newResult;
312 }
313 neogfx::size_policy effective_size_policy() const
314 {
315 auto effectivePolicy = size_policy();
316 if (effectivePolicy.horizontal_constraint() == size_constraint::MinimumExpanding)
317 effectivePolicy.set_horizontal_constraint(has_weight() ? size_constraint::Expanding : size_constraint::Minimum);
318 else if (effectivePolicy.horizontal_constraint() == size_constraint::DefaultMinimumExpanding)
319 effectivePolicy.set_horizontal_constraint(has_weight() ? size_constraint::Expanding : size_constraint::Minimum);
320 if (effectivePolicy.vertical_constraint() == size_constraint::MinimumExpanding)
321 effectivePolicy.set_vertical_constraint(has_weight() ? size_constraint::Expanding : size_constraint::Minimum);
322 else if (effectivePolicy.vertical_constraint() == size_constraint::DefaultMinimumExpanding)
323 effectivePolicy.set_vertical_constraint(has_weight() ? size_constraint::Expanding : size_constraint::Minimum);
324 return effectivePolicy;
325 }
326 void set_size_policy(size_constraint aConstraint, bool aUpdateLayout = true)
327 {
328 set_size_policy(neogfx::size_policy{ aConstraint }, aUpdateLayout);
329 }
330 void set_size_policy(size_constraint aConstraint, visibility_constraint aVisibility, bool aUpdateLayout = true)
331 {
332 set_size_policy(neogfx::size_policy{ aConstraint, aVisibility }, aUpdateLayout);
333 }
334 void set_size_policy(size_constraint aConstraint, visibility_constraint aVisibility, const size& aAspectRatio, bool aUpdateLayout = true)
335 {
336 set_size_policy(neogfx::size_policy{ aConstraint, aVisibility, aAspectRatio }, aUpdateLayout);
337 }
338 void set_size_policy(size_constraint aHorizontalConstraint, size_constraint aVerticalConstraint, bool aUpdateLayout = true)
339 {
340 set_size_policy(neogfx::size_policy{ aHorizontalConstraint, aVerticalConstraint }, aUpdateLayout);
341 }
342 void set_size_policy(size_constraint aHorizontalConstraint, size_constraint aVerticalConstraint, visibility_constraint aVisibility, bool aUpdateLayout = true)
343 {
344 set_size_policy(neogfx::size_policy{ aHorizontalConstraint, aVerticalConstraint, aVisibility }, aUpdateLayout);
345 }
346 void set_size_policy(size_constraint aHorizontalConstraint, size_constraint aVerticalConstraint, visibility_constraint aVisibility, const size& aAspectRatio, bool aUpdateLayout = true)
347 {
348 set_size_policy(neogfx::size_policy{ aHorizontalConstraint, aVerticalConstraint, aVisibility, aAspectRatio }, aUpdateLayout);
349 }
350 void set_minimum_width(dimension aWidth, bool aUpdateLayout = true)
351 {
352 auto newSize = minimum_size();
353 newSize.cx = aWidth;
354 set_minimum_size(newSize, aUpdateLayout);
355 }
356 void set_minimum_height(dimension aHeight, bool aUpdateLayout = true)
357 {
358 auto newSize = minimum_size();
359 newSize.cy = aHeight;
360 set_minimum_size(newSize, aUpdateLayout);
361 }
362 void set_maximum_width(dimension aWidth, bool aUpdateLayout = true)
363 {
364 auto newSize = maximum_size();
365 newSize.cx = aWidth;
366 set_maximum_size(newSize, aUpdateLayout);
367 }
368 void set_maximum_height(dimension aHeight, bool aUpdateLayout = true)
369 {
370 auto newSize = maximum_size();
371 newSize.cy = aHeight;
372 set_maximum_size(newSize, aUpdateLayout);
373 }
374 public:
375 box_areas internal_spacing(bool aExtendIntoPadding = true) const
376 {
377 return margin() + border() + (aExtendIntoPadding ? padding() : box_areas{});
378 }
379 };
380
381 class i_size_hint
382 {
383 public:
384 typedef i_size_hint abstract_type;
385 public:
386 virtual ~i_size_hint() = default;
387 public:
388 virtual i_string const& primary_hint() const = 0;
389 virtual i_string const& secondary_hint() const = 0;
390 };
391
392 class size_hint : public i_size_hint
393 {
394 public:
395 size_hint(i_size_hint const& aOther) :
396 iPrimaryHint{ aOther.primary_hint() },
397 iSecondaryHint{ aOther.secondary_hint() }
398 {
399 }
400 size_hint(string const& aPrimaryHint = {}, string const& aSecondaryHint = {}) :
401 iPrimaryHint{ aPrimaryHint },
402 iSecondaryHint{ aSecondaryHint }
403 {
404 }
405 public:
406 operator bool() const
407 {
408 return !primary_hint().empty() || !secondary_hint().empty();
409 }
410 bool operator==(const size_hint& aOther) const
411 {
412 return primary_hint() == aOther.primary_hint() && secondary_hint() == aOther.secondary_hint();
413 }
414 bool operator!=(const size_hint& aOther) const
415 {
416 return !(*this == aOther);
417 }
418 public:
419 string const& primary_hint() const final
420 {
421 return iPrimaryHint;
422 }
423 string const& secondary_hint() const final
424 {
425 return iSecondaryHint;
426 }
427 private:
428 string iPrimaryHint;
429 string iSecondaryHint;
430 };
431}
#define end_declare_enum(enumName)
Definition i_enum.hpp:62
#define declare_enum_string(enumName, enumEnumerator)
Definition i_enum.hpp:59
#define begin_declare_enum(enumName)
Definition i_enum.hpp:52
std::basic_ostream< Elem, Traits > & operator<<(std::basic_ostream< Elem, Traits > &aStream, const basic_point< T > &aPoint)
basic_box_areas< double > box_areas
basic_margin< dimension > margin
bool operator!=(color_or_gradient const &lhs, color const &rhs) noexcept
basic_padding< dimension > padding
visibility_constraint
std::string to_string(note const &aNote)
bool operator==(const basic_rect< CoordinateType, CoordinateSystem > &left, const basic_rect< CoordinateType, CoordinateSystem > &right)
optional< size > optional_size
basic_point< coordinate > point
basic_border< dimension > border
basic_size< coordinate > size
ref_ptr< ConcreteType > make_ref(Args &&... args)
StringT enum_to_string(Enum aEnumerator, bool aMustEnumerate=false)
Definition i_enum.hpp:78
T from_string(i_string const &aValueAsString)
Definition plf_hive.h:79