43 float vThumbRatio = 1.0f;
44 float hThumbRatio = 1.0f;
46 Vector2Int contentAnchor = {0, 0};
64 return (p_amount >= p_value ? 0 : p_value - p_amount);
67 static Vector2UInt _resolveContentSize(
const Vector2UInt &p_minimal,
const Vector2UInt &p_desired,
const Vector2UInt &p_maximal)
71 Vector2UInt result = p_maximal;
73 if (result.
x == MaxValue)
75 result.
x = fallback.
x;
77 if (result.
y == MaxValue)
79 result.
y = fallback.
y;
85 static Vector2UInt _availableSize(
const Vector2UInt &p_base,
bool p_showVertical,
bool p_showHorizontal,
Vector2UInt::value_type p_scrollbarThickness)
87 Vector2UInt available = p_base;
90 available.
x = _subtractOrZero(available.
x, p_scrollbarThickness);
94 available.
y = _subtractOrZero(available.
y, p_scrollbarThickness);
99 static std::pair<bool, bool> _resolveVisibility(
const Vector2UInt &p_containerSize,
const Vector2UInt &p_contentSize,
Vector2UInt::value_type p_scrollbarThickness)
107 const Vector2UInt avail = _availableSize(p_containerSize, showV, showH, p_scrollbarThickness);
109 const bool needV = (p_contentSize.
y > avail.
y);
110 const bool needH = (p_contentSize.
x > avail.
x);
112 dirty = (needV != showV) || (needH != showH);
117 return {showV, showH};
120 ScrollLayout _computeLayout()
const
125 const Vector2UInt containerSize = g.size;
128 out.contentSize = _resolveContentSize(
129 _content.sizeHint().minimal(),
130 _content.sizeHint().desired(),
131 _content.sizeHint().maximal());
133 std::tie(out.showV, out.showH) = _resolveVisibility(containerSize, out.contentSize, thickness);
134 out.viewportSize = _availableSize(containerSize, out.showV, out.showH, thickness);
139 {
static_cast<int>(containerSize.
x) -
static_cast<int>(thickness), 0},
140 {thickness, _subtractOrZero(containerSize.
y, out.showH ? thickness : 0)}};
146 {0,
static_cast<int>(containerSize.
y) -
static_cast<int>(thickness)},
147 {_subtractOrZero(containerSize.
x, out.showV ? thickness : 0), thickness}};
150 out.hThumbRatio = (out.contentSize.
x == 0) ? 1.0f : std::clamp(
static_cast<float>(out.viewportSize.
x) /
static_cast<float>(out.contentSize.
x), 0.0f, 1.0f);
152 out.vThumbRatio = (out.contentSize.
y == 0) ? 1.0f : std::clamp(
static_cast<float>(out.viewportSize.
y) /
static_cast<float>(out.contentSize.
y), 0.0f, 1.0f);
154 const float hRatio = out.showH ? _horizontalScrollBar.slider().ratioValue() : 0.0f;
155 const float vRatio = out.showV ? _verticalScrollBar.slider().ratioValue() : 0.0f;
157 const float hRange = (out.contentSize.
x > out.viewportSize.
x) ?
float(out.contentSize.
x - out.viewportSize.
x) : 0.0f;
158 const float vRange = (out.contentSize.
y > out.viewportSize.
y) ?
float(out.contentSize.
y - out.viewportSize.
y) : 0.0f;
160 const int32_t hOffset =
static_cast<int32_t
>(std::lround(hRange * hRatio));
161 const int32_t vOffset =
static_cast<int32_t
>(std::lround(vRange * vRatio));
164 out.contentAnchor.
x -= hOffset;
165 out.contentAnchor.
y -= vOffset;
170 void _applyLayout(
const ScrollLayout &p_layout)
172 _lastViewportSize = p_layout.viewportSize;
174 _contentContainer.setGeometry({{0, 0}, p_layout.viewportSize});
176 _horizontalScrollBar.slider().setThumbSizeRatio(p_layout.hThumbRatio);
177 _verticalScrollBar.slider().setThumbSizeRatio(p_layout.vThumbRatio);
181 _verticalScrollBar.setGeometry(p_layout.vBar);
182 _verticalScrollBar.activate();
186 auto block = _verticalScrollBar.slider().ratio().onEdition().block();
187 _verticalScrollBar.slider().setRatio(0.0f);
188 _verticalScrollBar.deactivate();
193 _horizontalScrollBar.setGeometry(p_layout.hBar);
194 _horizontalScrollBar.activate();
198 auto block = _horizontalScrollBar.slider().ratio().onEdition().block();
199 _horizontalScrollBar.slider().setRatio(0.0f);
200 _horizontalScrollBar.deactivate();
203 _content.setGeometry({p_layout.contentAnchor, p_layout.contentSize});
212 _applyLayout(_computeLayout());
221 const ScrollLayout layout = _computeLayout();
222 if (layout.showV ==
false || layout.viewportSize.
y == 0)
227 const float contentHeight =
static_cast<float>(layout.contentSize.
y);
228 const float viewportHeight =
static_cast<float>(layout.viewportSize.
y);
229 const float verticalRange = contentHeight > viewportHeight ? contentHeight - viewportHeight : 0.0f;
230 if (verticalRange <= 0.0f)
235 constexpr float ScrollFactor = 0.25f;
236 const float scrollPixels = std::max(1.0f, viewportHeight * ScrollFactor);
237 const float ratioDelta = -p_event.
wheel * (scrollPixels / verticalRange);
238 if (ratioDelta == 0.0f)
243 _verticalScrollBar.slider().adjustRatio(ratioDelta);
248 template <
typename... TContentArguments>
258 _contentContainer(p_name + L
"/ScrolableArea_ContentContainer", this),
259 _horizontalScrollBar(p_name + L
"/ScrolableArea_HorizontalScrollBar", this),
260 _verticalScrollBar(p_name + L
"/ScrolableArea_VerticalScrollBar", this),
261 _content(p_name + L
"/ScrolableArea_ContentContainer/Content", &_contentContainer,
std::forward<TContentArguments>(p_contentArgs)...)
263 _horizontalScrollBar.setMinimalWidth(32);
264 _verticalScrollBar.setMinimalWidth(32);
266 _contentContainer.setLayer(0);
267 _contentContainer.activate();
268 _content.setLayer(0);
271 _horizontalScrollBar.setOrientation(Orientation::Horizontal);
272 _horizontalScrollBar.setButtonVisibility(Enablement::Disable);
274 _verticalScrollBar.setOrientation(Orientation::Vertical);
275 _verticalScrollBar.setButtonVisibility(Enablement::Disable);
278 const Vector2UInt viewport = _content.sizeHint().minimal();
279 const Vector2UInt extent = _resolveContentSize(
280 _content.sizeHint().minimal(),
281 _content.sizeHint().desired(),
282 _content.sizeHint().maximal());
287 std::tie(showV, showH) = _resolveVisibility(viewport, extent, thickness);
289 Vector2UInt result = viewport;
292 result.
x += thickness;
296 result.
y += thickness;
302 return _resolveContentSize(
303 _content.sizeHint().minimal(),
304 _content.sizeHint().desired(),
305 _content.sizeHint().maximal());
308 _horizontalRatioContract = _horizontalScrollBar.slider().ratio().onEdition().subscribe([
this]() {
311 _verticalRatioContract = _verticalScrollBar.slider().ratio().onEdition().subscribe([
this]() {
324 _verticalScrollBar.setMinimalWidth(p_scrollBarWidth);
325 _horizontalScrollBar.setMinimalWidth(p_scrollBarWidth);
335 return (std::max(_verticalScrollBar.minimalWidth(), _horizontalScrollBar.minimalWidth()));