1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #include "GUI/BsDropDownAreaPlacement.h" |
4 | #include "Debug/BsDebug.h" |
5 | |
6 | namespace bs |
7 | { |
8 | DropDownAreaPlacement DropDownAreaPlacement::aroundPosition(const Vector2I& position) |
9 | { |
10 | DropDownAreaPlacement instance; |
11 | instance.mType = Type::Position; |
12 | instance.mPosition = position; |
13 | |
14 | return instance; |
15 | } |
16 | |
17 | DropDownAreaPlacement DropDownAreaPlacement::aroundBoundsVert(const Rect2I& bounds) |
18 | { |
19 | DropDownAreaPlacement instance; |
20 | instance.mType = Type::BoundsVert; |
21 | instance.mBounds = bounds; |
22 | |
23 | return instance; |
24 | } |
25 | |
26 | DropDownAreaPlacement DropDownAreaPlacement::aroundBoundsHorz(const Rect2I& bounds) |
27 | { |
28 | DropDownAreaPlacement instance; |
29 | instance.mType = Type::BoundsHorz; |
30 | instance.mBounds = bounds; |
31 | |
32 | return instance; |
33 | } |
34 | |
35 | DropDownAreaPlacement DropDownAreaPlacement::aroundBounds(const Rect2I& bounds) |
36 | { |
37 | DropDownAreaPlacement instance; |
38 | instance.mType = Type::BoundsAll; |
39 | instance.mBounds = bounds; |
40 | |
41 | return instance; |
42 | } |
43 | |
44 | Rect2I DropDownAreaPlacement::getOptimalBounds(UINT32 width, UINT32 height, const Rect2I& availableArea, HorzDir& horzDir, VertDir& vertDir) const |
45 | { |
46 | Rect2I output; |
47 | |
48 | int potentialLeftStart = 0; |
49 | int potentialRightStart = 0; |
50 | int potentialTopStart = 0; |
51 | int potentialBottomStart = 0; |
52 | |
53 | switch (getType()) |
54 | { |
55 | case DropDownAreaPlacement::Type::Position: |
56 | potentialLeftStart = potentialRightStart = getPosition().x; |
57 | potentialTopStart = potentialBottomStart = getPosition().y; |
58 | break; |
59 | case DropDownAreaPlacement::Type::BoundsHorz: |
60 | potentialRightStart = getBounds().x; |
61 | potentialLeftStart = getBounds().x + getBounds().width; |
62 | potentialBottomStart = getBounds().y + getBounds().height; |
63 | potentialTopStart = getBounds().y; |
64 | break; |
65 | case DropDownAreaPlacement::Type::BoundsVert: |
66 | potentialRightStart = getBounds().x + getBounds().width; |
67 | potentialLeftStart = getBounds().x; |
68 | potentialBottomStart = getBounds().y; |
69 | potentialTopStart = getBounds().y + getBounds().height; |
70 | break; |
71 | case DropDownAreaPlacement::Type::BoundsAll: |
72 | potentialRightStart = getBounds().x + getBounds().width; |
73 | potentialLeftStart = getBounds().x; |
74 | potentialBottomStart = getBounds().y + getBounds().height; |
75 | potentialTopStart = getBounds().y; |
76 | break; |
77 | } |
78 | |
79 | // Determine x position and whether to align to left or right side of the drop down list |
80 | UINT32 availableRightwardWidth = (UINT32)std::max(0, (availableArea.x + (INT32)availableArea.width) - potentialRightStart); |
81 | UINT32 availableLeftwardWidth = (UINT32)std::max(0, potentialLeftStart - availableArea.x); |
82 | |
83 | //// Prefer right if possible |
84 | if (width <= availableRightwardWidth) |
85 | { |
86 | output.x = potentialRightStart; |
87 | output.width = width; |
88 | horzDir = HorzDir::Right; |
89 | } |
90 | else |
91 | { |
92 | if (availableRightwardWidth >= availableLeftwardWidth) |
93 | { |
94 | output.x = potentialRightStart; |
95 | output.width = std::min(width, availableRightwardWidth); |
96 | horzDir = HorzDir::Right; |
97 | } |
98 | else |
99 | { |
100 | output.x = potentialLeftStart - std::min(width, availableLeftwardWidth); |
101 | output.width = std::min(width, availableLeftwardWidth); |
102 | horzDir = HorzDir::Left; |
103 | } |
104 | } |
105 | |
106 | // Determine y position and whether to open upward or downward |
107 | UINT32 availableDownwardHeight = (UINT32)std::max(0, (availableArea.y + (INT32)availableArea.height) - potentialBottomStart); |
108 | UINT32 availableUpwardHeight = (UINT32)std::max(0, potentialTopStart - availableArea.y); |
109 | |
110 | //// Prefer down if possible |
111 | if (height <= availableDownwardHeight) |
112 | { |
113 | output.y = potentialBottomStart; |
114 | output.height = height; |
115 | vertDir = VertDir::Down; |
116 | } |
117 | else |
118 | { |
119 | if (availableDownwardHeight >= availableUpwardHeight) |
120 | { |
121 | output.y = potentialBottomStart; |
122 | output.height = std::min(height, availableDownwardHeight);; |
123 | vertDir = VertDir::Down; |
124 | } |
125 | else |
126 | { |
127 | output.y = potentialTopStart - (INT32)std::min(height, availableUpwardHeight); |
128 | output.height = std::min(height, availableUpwardHeight); |
129 | vertDir = VertDir::Up; |
130 | } |
131 | } |
132 | |
133 | return output; |
134 | } |
135 | } |