131 lines
4.3 KiB
C++
131 lines
4.3 KiB
C++
#ifndef BWIDGETS_ALIGNED_LAYOUT_IMPL_HPP
|
|
#define BWIDGETS_ALIGNED_LAYOUT_IMPL_HPP
|
|
|
|
#include <basic_widgets/core/math.hpp>
|
|
#include <basic_widgets/w/aligned_layout.hpp>
|
|
#include <basic_widgets/w/base/layout_impl.hpp>
|
|
#include <basic_widgets/w/base/widget_impl.hpp>
|
|
|
|
namespace bwidgets
|
|
{
|
|
enum struct LayoutAlignment
|
|
{
|
|
HORIZONTAL,
|
|
VERTICAL
|
|
};
|
|
|
|
template<LayoutAlignment alignment>
|
|
class AlignedLayoutImpl final : public virtual AlignedLayout,
|
|
public virtual LayoutImpl,
|
|
public virtual WidgetImpl
|
|
{
|
|
public:
|
|
using LayoutImpl::LayoutImpl;
|
|
|
|
void add_widget(std::shared_ptr<Widget> widget_ptr) override
|
|
{
|
|
widget_ptr->parent(this);
|
|
if (renderer()) widget_ptr->renderer(renderer());
|
|
_widgets.emplace_back(std::move(widget_ptr));
|
|
}
|
|
|
|
void do_layout() override
|
|
{
|
|
_handle_geometry_change(viewport());
|
|
if (auto* layout = dynamic_cast<Layout*>(parent()); layout != nullptr) layout->do_layout();
|
|
else parent()->viewport(parent()->viewport());
|
|
}
|
|
|
|
void for_widgets(const std::function<void(Widget*)>& f) override
|
|
{
|
|
for (const auto& w : _widgets) f(w.get());
|
|
}
|
|
|
|
void for_widgets(const std::function<void(const Widget*)>& f) const override
|
|
{
|
|
for (const auto& w : _widgets) f(w.get());
|
|
}
|
|
|
|
void remove_widget(const std::shared_ptr<Widget>& widget) override
|
|
{
|
|
remove_widget(widget.get());
|
|
}
|
|
|
|
void remove_widget(const Widget* widget) override
|
|
{
|
|
for (auto i = _widgets.cbegin(); i != _widgets.cend(); i++) {
|
|
if ((*i).get() == widget) {
|
|
_widgets.erase(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return smallest usable size.
|
|
[[nodiscard]] auto size() const noexcept -> Size override
|
|
{
|
|
const auto margins {
|
|
theme() ? theme()->size_layout_margin() : Size {4, 4}
|
|
};
|
|
Size min_size {0, 0};
|
|
|
|
if constexpr (alignment == LayoutAlignment::HORIZONTAL) {
|
|
for_widgets([&min_size](const Widget* w) {
|
|
if (w->size().w > min_size.w) min_size.w = w->size().w;
|
|
if (w->size().h > min_size.h) min_size.h = w->size().h;
|
|
});
|
|
|
|
return {(int)_widgets.size() * min_size.w
|
|
+ ((int)_widgets.size() + 1) * margins.w,
|
|
min_size.h + 2 * margins.h};
|
|
}
|
|
|
|
// Vertical
|
|
for_widgets([&min_size](const Widget* w) {
|
|
if (w->size().w > min_size.w) min_size.w = w->size().w;
|
|
|
|
min_size.h += w->size().h;
|
|
});
|
|
|
|
return {min_size.w + 2 * margins.w,
|
|
min_size.h + ((int)_widgets.size() + 1) * margins.h};
|
|
}
|
|
|
|
private:
|
|
std::vector<std::shared_ptr<Widget>> _widgets;
|
|
|
|
void _handle_geometry_change(const SDL_Rect& vp) override
|
|
{
|
|
const auto margins {
|
|
theme() ? theme()->size_layout_margin() : Size {4, 4}
|
|
};
|
|
if constexpr (alignment == LayoutAlignment::HORIZONTAL) {
|
|
const int widget_width =
|
|
(vp.w - ((int)_widgets.size() + 1) * margins.w) / (int)_widgets.size();
|
|
|
|
for (std::vector<Widget*>::size_type i = 0; i < _widgets.size(); i++) {
|
|
const auto& w {_widgets[i]};
|
|
w->viewport({vp.x + margins.w + (int)i * (widget_width + margins.w),
|
|
vp.y + center_line(vp.h, w->size().h), widget_width,
|
|
w->size().h});
|
|
}
|
|
}
|
|
else { // Vertical
|
|
int offset = 0;
|
|
for (std::vector<Widget*>::size_type i = 0; i < _widgets.size(); i++) {
|
|
const auto& w {_widgets[i]};
|
|
w->viewport({
|
|
vp.x,
|
|
vp.y + ((int)i + 1) * margins.h + offset,
|
|
vp.w,
|
|
w->size().h,
|
|
});
|
|
offset += w->size().h;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif
|