bwidgets/inc/basic_widgets/w/aligned_layout_impl.hpp

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