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
6namespace 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}