wip general code improvement

This commit is contained in:
Andrea Blankenstijn 2021-08-06 14:22:56 +02:00
parent 2d4c6e3694
commit cab6fa0cf4
48 changed files with 963 additions and 756 deletions

View File

@ -1,2 +1,2 @@
Checks: 'bugprone-*,cert-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-misc-non-private-member-variables-in-classes,-bugprone-easily-swappable-parameters,-readability-braces-around-statements,-cppcoreguidelines-non-private-member-variables-in-classes,-readability-named-parameter' Checks: 'bugprone-*,cert-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-misc-non-private-member-variables-in-classes,-bugprone-easily-swappable-parameters,-readability-braces-around-statements,-cppcoreguidelines-non-private-member-variables-in-classes,-readability-named-parameter,-modernize-use-trailing-return-type'
FormatStyle: file FormatStyle: file

2
clang-format.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
find . -name "*.?pp" -print -exec clang-format -i {} \;

24
clang-tidy.py Executable file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env python3
from concurrent.futures import ProcessPoolExecutor
from pathlib import Path, PurePath
from subprocess import CompletedProcess, PIPE, STDOUT, run
files = sorted(Path().rglob("*.?pp"))
def tidy(file: PurePath) -> CompletedProcess:
return run(
["clang-tidy", "-p", "build", "--use-color", "--quiet", file], stdout=PIPE, stderr=STDOUT,
check=False
)
def main():
with ProcessPoolExecutor() as executor:
for task_done in executor.map(tidy, files):
print(task_done.stdout.decode())
if __name__ == "__main__":
main()

View File

@ -4,11 +4,11 @@
#include "run.hpp" #include "run.hpp"
using widget::Button; using bwidgets::Button;
auto main() -> int auto main() -> int
{ {
run_example<Button>([](Button* w, core::Font* f, int x, int y) { run_example<Button>([](auto* w, auto* f, auto x, auto y) {
w->click_handler = [x, y](const SDL_MouseButtonEvent&) { w->click_handler = [x, y](const SDL_MouseButtonEvent&) {
std::cout << "button(" << x << ',' << y << "):click!" << std::endl; std::cout << "button(" << x << ',' << y << "):click!" << std::endl;
}; };

View File

@ -2,12 +2,12 @@
#include "run.hpp" #include "run.hpp"
using widget::Caption; using bwidgets::Caption;
auto main() -> int auto main() -> int
{ {
run_example<Caption>( run_example<Caption>(
[](Caption* w, core::Font* f, int, int) { [](auto* w, auto* f, auto, auto) {
w->alignment = Caption::Alignment::CENTER; w->alignment = Caption::Alignment::CENTER;
w->text("¡jello!"); w->text("¡jello!");
w->font(f); w->font(f);

View File

@ -3,7 +3,7 @@
auto main() -> int auto main() -> int
{ {
run_example<Example>([](Example* w, core::Font*, int x, int y) { run_example<Example>([](auto* w, auto*, auto x, auto y) {
w->cycle_r = (x + 1) * 3000; // NOLINT(readability-magic-numbers) w->cycle_r = (x + 1) * 3000; // NOLINT(readability-magic-numbers)
w->cycle_b = (y + 1) * 3000; // NOLINT(readability-magic-numbers) w->cycle_b = (y + 1) * 3000; // NOLINT(readability-magic-numbers)
w->cycle_b = (1 + x + y) * (y + 1) * 400; // NOLINT(readability-magic-numbers) w->cycle_b = (1 + x + y) * (y + 1) * 400; // NOLINT(readability-magic-numbers)

View File

@ -1,5 +1,5 @@
#ifndef BWIDGET_EXAMPLES_EXAMPLE_WIDGET_ #ifndef BWIDGETS_EXAMPLES_EXAMPLE_WIDGET
#define BWIDGET_EXAMPLES_EXAMPLE_WIDGET_ #define BWIDGETS_EXAMPLES_EXAMPLE_WIDGET
#include <SDL2/SDL_timer.h> #include <SDL2/SDL_timer.h>
@ -7,9 +7,10 @@
#include <basic_widgets/core/renderer.hpp> #include <basic_widgets/core/renderer.hpp>
#include <basic_widgets/w/base/widget.hpp> #include <basic_widgets/w/base/widget.hpp>
using bwidgets::core::rect_margin; using bwidgets::Color;
using bwidgets::core::Size; using bwidgets::rect_margin;
using bwidgets::widget::Widget; using bwidgets::Size;
using bwidgets::Widget;
class Example final : public Widget class Example final : public Widget
{ {
@ -21,16 +22,20 @@ private:
void _handle_rendering() override void _handle_rendering() override
{ {
auto now = SDL_GetTicks(); auto now = SDL_GetTicks();
uint8_t r = 255 * (now % cycle_r / (float)cycle_r); // NOLINT uint8_t r = 255 * (now % cycle_r / (float)cycle_r); // NOLINT
uint8_t g = 255 * (now % cycle_g / (float)cycle_g); // NOLINT uint8_t g = 255 * (now % cycle_g / (float)cycle_g); // NOLINT
uint8_t b = 255 * (now % cycle_b / (float)cycle_b); // NOLINT uint8_t b = 255 * (now % cycle_b / (float)cycle_b); // NOLINT
SDL_Color base_color {r, g, b, 255}; // NOLINT // NOLINTNEXTLINE(readability-magic-numbers)
Color base_color {r, g, b, 255};
int border = 10; // NOLINT const int border = 10;
for (auto i = 0; i < border; i += 3) { for (auto i = 0; i < border; i += 3) {
uint8_t alpha = 255 * i / border; // NOLINT uint8_t alpha = 255 * i / border; // NOLINT(readability-magic-numbers)
_renderer->draw_color({base_color.r, base_color.g, base_color.b, alpha}) _renderer
->draw_color({
{base_color().r, base_color().g, base_color().b, alpha}
})
->draw_rect(rect_margin(_widget_area, {i, i})); ->draw_rect(rect_margin(_widget_area, {i, i}));
} }
@ -40,13 +45,13 @@ private:
} }
public: public:
unsigned int cycle_r {3500}; // NOLINT unsigned int cycle_r {3500}; // NOLINT(readability-magic-numbers)
unsigned int cycle_g {3500}; // NOLINT unsigned int cycle_g {3500}; // NOLINT(readability-magic-numbers)
unsigned int cycle_b {3500}; // NOLINT unsigned int cycle_b {3500}; // NOLINT(readability-magic-numbers)
[[nodiscard]] auto size() const noexcept -> Size override [[nodiscard]] auto size() const noexcept -> Size override
{ {
return {128, 64}; // NOLINT return {128, 64}; // NOLINT(readability-magic-numbers)
} }
}; };

View File

@ -2,15 +2,14 @@
#include "run.hpp" #include "run.hpp"
using widget::NumericInput; using bwidgets::NumericInput;
auto main() -> int auto main() -> int
{ {
run_example<NumericInput<float>>( run_example<NumericInput<float>>([](auto* w, auto* f, auto, auto) {
[](NumericInput<float>* w, core::Font* f, int, int) { w->font(f);
w->font(f); w->button_step = 0.5; // NOLINT(readability-magic-numbers)
w->button_step = 0.5; // NOLINT(readability-magic-numbers) w->value_range(-3.14, 8.5); // NOLINT(readability-magic-numbers)
w->value_range(-3.14, 8.5); // NOLINT(readability-magic-numbers) });
});
return 0; return 0;
} }

View File

@ -1,46 +1,54 @@
#ifndef BWIDGETS_EXAMPLES_RUN_HPP_ #ifndef BWIDGETS_EXAMPLES_RUN_HPP
#define BWIDGETS_EXAMPLES_RUN_HPP_ #define BWIDGETS_EXAMPLES_RUN_HPP
#include <concepts>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <stack>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h> #include <SDL2/SDL_ttf.h>
#include <basic_widgets/core/font.hpp> #include <basic_widgets/core/font.hpp>
#include <basic_widgets/core/renderer.hpp> #include <basic_widgets/core/renderer.hpp>
#include <basic_widgets/w/aligned_layout.hpp>
#include <basic_widgets/w/base/widget.hpp> #include <basic_widgets/w/base/widget.hpp>
#include <basic_widgets/w/horizontal_layout.hpp>
#include <basic_widgets/w/vertical_layout.hpp>
using namespace bwidgets;
template<typename T> template<typename T>
concept WidgetType = std::derived_from<T, widget::Widget>; concept WidgetType = std::derived_from<T, bwidgets::Widget>;
template<WidgetType W> template<WidgetType W>
void run_example(std::function<void(W*, core::Font*, int, int)> setup, int w = 3, void run_example(std::function<void(W*, bwidgets::Font*, int, int)> setup, int w = 3,
int h = 3) int h = 3)
{ {
std::stack<std::function<void()>> cleaners;
try { try {
core::SDLError::success_or_throw(SDL_Init(SDL_INIT_VIDEO), __FILE__, bwidgets::SDLError::success_or_throw(SDL_Init(SDL_INIT_VIDEO), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
core::SDLError::success_or_throw(TTF_Init(), __FILE__, __FUNCTION__, __LINE__); cleaners.emplace([]() { SDL_Quit(); });
bwidgets::SDLError::success_or_throw(TTF_Init(), __FILE__, __FUNCTION__,
__LINE__);
cleaners.emplace([]() { TTF_Quit(); });
const core::Size size_init {854, 480}; const bwidgets::Size size_init {854, 480};
auto* font {new core::Font(core::Font::find("Monospace"), 16)}; // NOLINT auto* font {new bwidgets::Font(bwidgets::Font::find("Monospace"),
16)}; // NOLINT(readability-magic-numbers)
cleaners.emplace([font]() { delete font; });
auto* win {SDL_CreateWindow("basic_widgets example", SDL_WINDOWPOS_CENTERED, auto* win {SDL_CreateWindow("basic_widgets example", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, size_init.w, size_init.h, SDL_WINDOWPOS_CENTERED, size_init.w, size_init.h,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
| SDL_WINDOW_UTILITY)}; | SDL_WINDOW_UTILITY)};
auto* renderer {new core::Renderer(win, -1, SDL_RENDERER_ACCELERATED)}; cleaners.emplace([win]() { SDL_DestroyWindow(win); });
auto* renderer {new bwidgets::Renderer(win, -1, SDL_RENDERER_ACCELERATED)};
cleaners.emplace([renderer]() { delete renderer; });
renderer->blend_mode(SDL_BLENDMODE_BLEND); renderer->blend_mode(SDL_BLENDMODE_BLEND);
auto* layout {new widget::HorizontalLayout()}; auto* layout {
new bwidgets::AlignedLayout(bwidgets::AlignedLayout::Alignment::HORIZONTAL)};
cleaners.emplace([layout]() { delete layout; });
for (auto x = 0; x < w; x++) { for (auto x = 0; x < w; x++) {
auto* col = new widget::VerticalLayout(); auto* col =
new bwidgets::AlignedLayout(bwidgets::AlignedLayout::Alignment::VERTICAL);
for (auto y = 0; y < h; y++) { for (auto y = 0; y < h; y++) {
auto* widget = new W(); auto* widget = new W();
setup(widget, font, x, y); setup(widget, font, x, y);
@ -70,15 +78,18 @@ void run_example(std::function<void(W*, core::Font*, int, int)> setup, int w = 3
layout->handle_event(ev); layout->handle_event(ev);
} }
renderer->draw_color({50, 60, 70, SDL_ALPHA_OPAQUE}); // NOLINT // NOLINTNEXTLINE(readability-magic-numbers)
renderer->draw_color({50, 60, 70, SDL_ALPHA_OPAQUE});
renderer->clear(); renderer->clear();
layout->render(); layout->render();
renderer->present(); renderer->present();
} }
} catch (const core::SDLError& e) { while (!cleaners.empty()) cleaners.top()(), cleaners.pop();
} catch (const bwidgets::SDLError& e) {
std::cerr << "Error: " << e.file << ":" << e.func << ":" << e.line << ": " std::cerr << "Error: " << e.file << ":" << e.func << ":" << e.line << ": "
<< e.what << std::endl; << e.what << std::endl;
while (!cleaners.empty()) cleaners.top()(), cleaners.pop();
} }
} }

View File

@ -1,24 +1,24 @@
#ifndef BWIDGETS_DRAW_HPP_ #ifndef BWIDGETS_DRAW_HPP
#define BWIDGETS_DRAW_HPP_ #define BWIDGETS_DRAW_HPP
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
struct SDL_Color;
struct SDL_PixelFormat; struct SDL_PixelFormat;
struct SDL_Point; struct SDL_Point;
namespace bwidgets::core namespace bwidgets
{ {
struct Renderer; class Color;
struct Texture; class Renderer;
class Texture;
auto aa(const SDL_Color&, int, float) noexcept -> SDL_Color; [[nodiscard]] auto aa(const Color&, int, float) noexcept -> Color;
auto filled_circle(const SDL_Color&, int resolution, Renderer*, int aa_pixels = 3) [[nodiscard]] auto filled_circle(const Color&, int resolution, Renderer*,
-> core::Texture*; int aa_pixels = 3) -> Texture*;
void set_pixels_color( void set_pixels_color(
Texture*, Texture*,
const std::function<uint32_t(const SDL_Point&, const SDL_PixelFormat*)>&); const std::function<uint32_t(const SDL_Point&, const SDL_PixelFormat*)>&);
} }
#endif #endif

View File

@ -1,16 +1,15 @@
#ifndef BWIDGETS_FONT_HPP_ #ifndef BWIDGETS_FONT_HPP
#define BWIDGETS_FONT_HPP_ #define BWIDGETS_FONT_HPP
#include <string> #include <string>
#include <SDL2/SDL_ttf.h> #include <SDL2/SDL_ttf.h>
#include <basic_widgets/core/type/color.hpp>
#include <basic_widgets/core/type/opaque_struct.hpp> #include <basic_widgets/core/type/opaque_struct.hpp>
#include <basic_widgets/core/type/size.hpp> #include <basic_widgets/core/type/size.hpp>
/* struct SDL_Surface; */ namespace bwidgets
namespace bwidgets::core
{ {
struct Font final : OpaqueStruct<TTF_Font> struct Font final : OpaqueStruct<TTF_Font>
{ {
@ -29,16 +28,18 @@ namespace bwidgets::core
BLENDED BLENDED
}; };
struct Style enum struct Style
{ {
Style() = delete; BOLD = TTF_STYLE_BOLD,
ITALIC = TTF_STYLE_ITALIC,
static const uint8_t BOLD = TTF_STYLE_BOLD, ITALIC = TTF_STYLE_ITALIC, NORMAL = TTF_STYLE_NORMAL,
NORMAL = TTF_STYLE_NORMAL, STRIKETHROUGH = TTF_STYLE_STRIKETHROUGH,
STRIKETHROUGH = TTF_STYLE_STRIKETHROUGH, UNDERLINE = TTF_STYLE_UNDERLINE
UNDERLINE = TTF_STYLE_UNDERLINE;
}; };
inline static const Color default_color_bg {255, 255, 255, SDL_ALPHA_OPAQUE};
inline static const Color default_color_fg {0, 0, 0, SDL_ALPHA_OPAQUE};
const int ascent; const int ascent;
const int descent; const int descent;
const long faces; const long faces;
@ -53,27 +54,21 @@ namespace bwidgets::core
Font(const Font&) = delete; Font(const Font&) = delete;
~Font() override; ~Font() override;
auto operator=(const Font) -> Font& = delete;
auto operator=(const Font&) -> Font& = delete; auto operator=(const Font&) -> Font& = delete;
auto hinting() -> Hinting; [[nodiscard]] auto hinting() -> Hinting;
auto hinting(Hinting) -> Font*; auto hinting(Hinting) -> Font*;
auto kerning() -> bool; [[nodiscard]] auto kerning() -> bool;
auto kerning(bool) -> Font*; auto kerning(bool) -> Font*;
auto outline() -> int; [[nodiscard]] auto outline() -> int;
auto outline(int) -> Font*; auto outline(int) -> Font*;
auto render(RenderMode, const std::string&, auto render(RenderMode, const std::string&, const Color& fg = default_color_fg,
const SDL_Color& fg = {0, 0, 0, const Color& bg = default_color_bg) -> SDL_Surface*;
255}, // NOLINT(readability-magic-numbers) [[nodiscard]] auto style() -> uint8_t;
// NOLINTNEXTLINE(readability-magic-numbers) auto style(uint8_t) -> Font*;
const SDL_Color& bg = {255, 255, 255, [[nodiscard]] auto text_size(const std::string&) -> Size;
255}) // NOLINT(readability-magic-numbers)
-> SDL_Surface*;
auto style() -> uint8_t;
auto style(uint8_t) -> Font*;
auto text_size(const std::string&) -> Size;
static auto find(const std::string&) -> std::string; [[nodiscard]] static auto find(const std::string&) -> std::string;
}; };
} }

View File

@ -6,35 +6,51 @@
#include <SDL2/SDL_rect.h> #include <SDL2/SDL_rect.h>
#include <basic_widgets/core/type/color.hpp>
#include <basic_widgets/core/type/concepts.hpp> #include <basic_widgets/core/type/concepts.hpp>
#include <basic_widgets/core/type/size.hpp> #include <basic_widgets/core/type/size.hpp>
namespace bwidgets::core namespace bwidgets
{ {
static inline auto center_line(int available_len, int used_len) noexcept -> int // NOLINTNEXTLINE(clang-diagnostic-unused-function)
[[nodiscard]] static inline auto center_line(int available_len, int used_len) noexcept -> int
{ {
return (available_len - used_len) / 2; return (available_len - used_len) / 2;
} }
static inline auto distance_sqrd(const SDL_Point& a, const SDL_Point& b) noexcept [[nodiscard]] static inline auto distance_sqrd(const SDL_Point& a, const SDL_Point& b) noexcept
-> float -> float
{ {
return (a.x - b.x) * (a.x - b.x) // NOLINT(bugprone-narrowing-conversions) // NOLINTNEXTLINE(bugprone-narrowing-conversions)
return (a.x - b.x) * (a.x - b.x)
+ (a.y - b.y) * (a.y - b.y); + (a.y - b.y) * (a.y - b.y);
} }
static inline auto distance(const SDL_Point& a, const SDL_Point& b) noexcept -> float // NOLINTNEXTLINE(clang-diagnostic-unused-function)
[[nodiscard]] static inline auto distance(const SDL_Point& a, const SDL_Point& b) noexcept -> float
{ {
return std::sqrt(distance_sqrd(a, b)); return std::sqrt(distance_sqrd(a, b));
} }
template<FloatingPoint F>
[[nodiscard]] static inline auto lerp(const Color& a, const Color& b, F x, bool op_alpha=false, bool op_color=true) -> Color
{
return {{
op_color ? (uint8_t)std::lerp(a().r, b().r, x) : a().r,
op_color ? (uint8_t)std::lerp(a().g, b().g, x) : a().g,
op_color ? (uint8_t)std::lerp(a().b, b().b, x) : a().b,
op_alpha ? (uint8_t)std::lerp(a().a, b().a, x) : a().a,
}};
}
template<Numeric N> template<Numeric N>
static inline auto linear(N x, N a, N b) noexcept -> float [[nodiscard]] static inline auto linear(N x, N a, N b) noexcept -> float
{ {
return (float)(x - a) / (float)(b - a); return (float)(x - a) / (float)(b - a);
} }
static inline auto rect_in_rect(const SDL_Rect outer, const SDL_Rect inner) noexcept // NOLINTNEXTLINE(clang-diagnostic-unused-function)
[[nodiscard]] static inline auto rect_in_rect(const SDL_Rect outer, const SDL_Rect inner) noexcept
-> bool -> bool
{ {
SDL_Point top_left {inner.x, inner.y}; SDL_Point top_left {inner.x, inner.y};
@ -44,26 +60,28 @@ namespace bwidgets::core
&& (SDL_PointInRect(&bottom_right, &outer) == SDL_TRUE); && (SDL_PointInRect(&bottom_right, &outer) == SDL_TRUE);
} }
static inline auto rect_margin(const SDL_Rect& r, const Size& margin) noexcept // NOLINTNEXTLINE(clang-diagnostic-unused-function)
[[nodiscard]] static inline auto rect_margin(const SDL_Rect& r, const Size& margin) noexcept
-> SDL_Rect -> SDL_Rect
{ {
return {r.x + margin.w, r.y + margin.h, r.w - 2 * margin.w, r.h - 2 * margin.h}; return {r.x + margin.w, r.y + margin.h, r.w - 2 * margin.w, r.h - 2 * margin.h};
} }
static inline auto rect_offset(const SDL_Rect& r, const SDL_Point& offset) noexcept [[nodiscard]] static inline auto rect_offset(const SDL_Rect& r, const SDL_Point& offset) noexcept
-> SDL_Rect -> SDL_Rect
{ {
return {r.x + offset.x, r.y + offset.y, r.w, r.h}; return {r.x + offset.x, r.y + offset.y, r.w, r.h};
} }
static inline auto rect_offset(const SDL_Rect& r, const SDL_Rect& offset) noexcept // NOLINTNEXTLINE(clang-diagnostic-unused-function)
[[nodiscard]] static inline auto rect_offset(const SDL_Rect& r, const SDL_Rect& offset) noexcept
-> SDL_Rect -> SDL_Rect
{ {
return rect_offset(r, SDL_Point {offset.x, offset.y}); return rect_offset(r, SDL_Point {offset.x, offset.y});
} }
template<Numeric N> template<Numeric N>
static inline auto smoothstep(N x, N a, N b) noexcept -> float [[nodiscard]] static inline auto smoothstep(N x, N a, N b) noexcept -> float
{ {
const float x_norm = linear(std::clamp<float>(x, a, b), a, b); const float x_norm = linear(std::clamp<float>(x, a, b), a, b);
return 3 * x_norm * x_norm - 2 * x_norm * x_norm * x_norm; return 3 * x_norm * x_norm - 2 * x_norm * x_norm * x_norm;

View File

@ -1,22 +1,22 @@
#ifndef BWIDGETS_RENDERER_HPP_ #ifndef BWIDGETS_RENDERER_HPP
#define BWIDGETS_RENDERER_HPP_ #define BWIDGETS_RENDERER_HPP
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include <basic_widgets/core/type/color.hpp>
#include <basic_widgets/core/type/opaque_struct.hpp> #include <basic_widgets/core/type/opaque_struct.hpp>
#include <basic_widgets/core/type/sdl_error.hpp> #include <basic_widgets/core/type/sdl_error.hpp>
#include <basic_widgets/core/type/size.hpp> #include <basic_widgets/core/type/size.hpp>
namespace bwidgets::core namespace bwidgets
{ {
struct Texture; class Texture;
struct Renderer final : OpaqueStruct<SDL_Renderer> class Renderer final : public OpaqueStruct<SDL_Renderer>
{ {
private:
static inline auto _info(SDL_Renderer* r) -> SDL_RendererInfo static inline auto _info(SDL_Renderer* r) -> SDL_RendererInfo
{ {
SDL_RendererInfo info; SDL_RendererInfo info;
@ -27,61 +27,61 @@ namespace bwidgets::core
} }
public: public:
Renderer(SDL_Renderer*);
Renderer(SDL_Window*, int, uint32_t);
~Renderer() override;
const SDL_RendererInfo info; const SDL_RendererInfo info;
auto blend_mode() -> SDL_BlendMode; Renderer(SDL_Renderer*);
auto blend_mode(SDL_BlendMode) -> Renderer*; Renderer(SDL_Window*, int, uint32_t);
auto clear() -> Renderer*; Renderer(const Renderer&) = delete;
auto copy(Texture*, const SDL_Rect*, const SDL_Rect*) -> Renderer*; ~Renderer() override;
auto draw_color() -> SDL_Color;
auto draw_color(const SDL_Color&) -> Renderer*;
auto draw_line(const SDL_Point&, const SDL_Point&) -> Renderer*;
auto draw_lines(const std::vector<SDL_Point>&) -> Renderer*;
auto draw_point(const SDL_Point&) -> Renderer*;
auto draw_points(const std::vector<SDL_Point>&) -> Renderer*;
auto draw_rect(const SDL_Rect*) -> Renderer*;
auto draw_rects(const std::vector<SDL_Rect>&) -> Renderer*;
auto fill_rect(const SDL_Rect*) -> Renderer*;
auto fill_rects(const std::vector<SDL_Rect>&) -> Renderer*;
auto output_size() -> Size;
void present();
auto viewport() -> SDL_Rect;
auto viewport(const SDL_Rect*) -> Renderer*;
inline auto copy(Texture* t, const SDL_Rect* src, const SDL_Rect& dst) auto operator=(const Renderer&) = delete;
-> Renderer*
[[nodiscard]] auto blend_mode() -> SDL_BlendMode;
auto blend_mode(SDL_BlendMode) -> Renderer*;
auto clear() -> Renderer*;
auto copy(Texture*, const SDL_Rect*, const SDL_Rect*) -> Renderer*;
[[nodiscard]] auto draw_color() -> Color;
auto draw_color(const Color&) -> Renderer*;
auto draw_line(const SDL_Point&, const SDL_Point&) -> Renderer*;
auto draw_lines(const std::vector<SDL_Point>&) -> Renderer*;
auto draw_point(const SDL_Point&) -> Renderer*;
auto draw_points(const std::vector<SDL_Point>&) -> Renderer*;
auto draw_rect(const SDL_Rect*) -> Renderer*;
auto draw_rects(const std::vector<SDL_Rect>&) -> Renderer*;
auto fill_rect(const SDL_Rect*) -> Renderer*;
auto fill_rects(const std::vector<SDL_Rect>&) -> Renderer*;
[[nodiscard]] auto output_size() -> Size;
void present();
[[nodiscard]] auto viewport() -> SDL_Rect;
auto viewport(const SDL_Rect*) -> Renderer*;
inline auto* copy(Texture* t, const SDL_Rect* src, const SDL_Rect& dst)
{ {
auto d = dst; auto d = dst;
return copy(t, src, &d); return copy(t, src, &d);
} }
inline auto copy(Texture* t, const SDL_Rect& src, const SDL_Rect* dst) inline auto* copy(Texture* t, const SDL_Rect& src, const SDL_Rect* dst)
-> Renderer*
{ {
auto s = src; auto s = src;
return copy(t, &s, dst); return copy(t, &s, dst);
} }
inline auto copy(Texture* t, const SDL_Rect& src, const SDL_Rect& dst) inline auto* copy(Texture* t, const SDL_Rect& src, const SDL_Rect& dst)
-> Renderer*
{ {
auto s = src; auto s = src;
auto d = dst; auto d = dst;
return copy(t, &s, &d); return copy(t, &s, &d);
} }
inline auto draw_rect(const SDL_Rect& r) -> Renderer* inline auto* draw_rect(const SDL_Rect& r)
{ {
auto rect = r; auto rect = r;
return draw_rect(&rect); return draw_rect(&rect);
} }
inline auto fill_rect(const SDL_Rect& r) -> Renderer* inline auto* fill_rect(const SDL_Rect& r)
{ {
auto rect = r; auto rect = r;
return fill_rect(&rect); return fill_rect(&rect);
} }
inline auto viewport(const SDL_Rect& vp) -> Renderer* inline auto* viewport(const SDL_Rect& vp)
{ {
auto v = vp; auto v = vp;
return viewport(&v); return viewport(&v);

View File

@ -1,19 +1,20 @@
#ifndef BWIDGETS_TEXTURE_HPP_ #ifndef BWIDGETS_TEXTURE_HPP
#define BWIDGETS_TEXTURE_HPP_ #define BWIDGETS_TEXTURE_HPP
#include <cstdint> #include <cstdint>
#include <SDL2/SDL_pixels.h> #include <SDL2/SDL_pixels.h>
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include <basic_widgets/core/type/color.hpp>
#include <basic_widgets/core/type/opaque_struct.hpp> #include <basic_widgets/core/type/opaque_struct.hpp>
#include <basic_widgets/core/type/sdl_error.hpp> #include <basic_widgets/core/type/sdl_error.hpp>
namespace bwidgets::core namespace bwidgets
{ {
struct Renderer; class Renderer;
struct Texture final : OpaqueStruct<SDL_Texture> class Texture final : public OpaqueStruct<SDL_Texture>
{ {
struct Attr struct Attr
{ {
@ -27,25 +28,27 @@ namespace bwidgets::core
Texture(SDL_Texture*); Texture(SDL_Texture*);
Texture(Renderer* r, SDL_PixelFormatEnum f, SDL_TextureAccess a, int w, int h); Texture(Renderer* r, SDL_PixelFormatEnum f, SDL_TextureAccess a, int w, int h);
Texture(Renderer*, SDL_Surface*); Texture(Renderer*, SDL_Surface*);
Texture(const Texture&) = delete;
~Texture() noexcept override; ~Texture() noexcept override;
auto alpha_mode() -> uint8_t; auto operator=(const Texture&) = delete;
auto alpha_mode(uint8_t) -> Texture*;
auto blend_mode() -> SDL_BlendMode;
auto blend_mode(SDL_BlendMode) -> Texture*;
auto color_mode() -> SDL_Color;
auto color_mode(const SDL_Color&) -> Texture*;
auto scale_mode() -> SDL_ScaleMode;
auto scale_mode(SDL_ScaleMode) -> Texture*;
auto update(SDL_Rect*, const void*, int) -> Texture*;
[[nodiscard]] inline auto attributes() const -> const Attr& [[nodiscard]] auto alpha_mode() -> uint8_t;
auto alpha_mode(uint8_t) -> Texture*;
[[nodiscard]] auto blend_mode() -> SDL_BlendMode;
auto blend_mode(SDL_BlendMode) -> Texture*;
[[nodiscard]] auto color_mode() -> Color;
auto color_mode(const Color&) -> Texture*;
[[nodiscard]] auto scale_mode() -> SDL_ScaleMode;
auto scale_mode(SDL_ScaleMode) -> Texture*;
auto update(SDL_Rect*, const void*, int) -> Texture*;
[[nodiscard]] inline const auto& attributes() const
{ {
return _attributes; return _attributes;
} }
inline auto update(const SDL_Rect& r, const void* pix, int pitch) -> Texture* inline auto update(const SDL_Rect& r, const void* pix, int pitch)
{ {
SDL_Rect rect = r; SDL_Rect rect = r;
update(&rect, pix, pitch); update(&rect, pix, pitch);
@ -53,7 +56,7 @@ namespace bwidgets::core
return this; return this;
} }
static inline auto attributes(SDL_Texture* t) -> Attr [[nodiscard]] static inline auto attributes(SDL_Texture* t)
{ {
Attr attr {}; Attr attr {};
SDLError::success_or_throw(SDL_QueryTexture(t, &attr.format_raw, SDLError::success_or_throw(SDL_QueryTexture(t, &attr.format_raw,

View File

@ -0,0 +1,136 @@
#ifndef BWIDGETS_COLOR_HPP
#define BWIDGETS_COLOR_HPP
#include <cstdint>
#include <functional>
#include <SDL2/SDL_assert.h>
#include <SDL2/SDL_pixels.h>
#include <basic_widgets/core/type/concepts.hpp>
namespace bwidgets
{
class Color final
{
public:
[[nodiscard]] inline auto& operator()()
{
return sdl_type;
}
[[nodiscard]] inline const auto& operator()() const
{
return sdl_type;
}
private:
bool _operate_on_alpha;
bool _operate_on_colors;
template<Numeric N>
inline auto _operate(const N& operand,
const std::function<N(const N&, const N&)>& operator_) const
{
Color c(sdl_type, _operate_on_alpha, _operate_on_colors);
if (_operate_on_alpha) {
auto a = std::round(operator_(c().a, operand));
SDL_assert_release(a == (uint8_t)a); // NOLINT
c().a = (uint8_t)a;
}
if (_operate_on_colors) {
auto r = std::round(operator_(c().r, operand));
auto g = std::round(operator_(c().g, operand));
auto b = std::round(operator_(c().b, operand));
// NOLINTNEXTLINE
SDL_assert_release(r == (uint8_t)r && g == (uint8_t)g
&& b == (uint8_t)b);
c().r = (uint8_t)r;
c().g = (uint8_t)g;
c().b = (uint8_t)b;
}
return c;
}
public:
SDL_Color sdl_type;
inline Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a,
bool op_on_alpha = false, bool op_on_colors = true) noexcept
: _operate_on_alpha(op_on_alpha),
_operate_on_colors(op_on_colors),
sdl_type({r, g, b, a})
{}
inline Color(const SDL_Color& c = {}, bool op_on_alpha = false,
bool op_on_colors = true) noexcept
: _operate_on_alpha(op_on_alpha), _operate_on_colors(op_on_colors), sdl_type(c)
{}
inline Color(const Color&) noexcept = default;
[[nodiscard]] inline auto alpha() const -> Color
{
return {sdl_type, _operate_on_colors, true};
}
[[nodiscard]] inline auto colors() const -> Color
{
return {sdl_type, true, _operate_on_alpha};
}
template<Numeric N>
[[nodiscard]] inline auto operator+(const N& operand) const
{
return _operate(operand, [](const N& a, const N& b) { return a + b; });
}
template<Numeric N>
[[nodiscard]] inline auto operator-(const N& operand) const
{
return _operate(operand, [](const N& a, const N& b) { return a - b; });
}
template<Numeric N>
[[nodiscard]] inline auto operator*(const N& operand) const
{
return _operate(operand, [](const N& a, const N& b) { return a * b; });
}
template<Numeric N>
[[nodiscard]] inline auto operator/(const N& operand) const
{
SDL_assert(operand != 0); // NOLINT
return _operate<N>(operand, [](const N& a, const N& b) { return a / b; });
}
inline auto& operator=(const Color& c)
{
if (this != &c) {
sdl_type = c.sdl_type;
}
return *this;
}
inline auto& operator=(const SDL_Color& c)
{
sdl_type = c;
return *this;
}
[[nodiscard]] inline auto operator==(const Color& other) const
{
return (_operate_on_colors && sdl_type.r == other().r
&& sdl_type.g == other().g && sdl_type.b == other().b)
|| (_operate_on_alpha && sdl_type.a == other().a);
}
[[nodiscard]] inline auto operator!=(const Color& other) const
{
return (sdl_type.r != other().r || sdl_type.g != other().g
|| sdl_type.b != other().b)
&& ((_operate_on_alpha && sdl_type.a != other().a)
|| !_operate_on_alpha);
}
};
}
#endif

View File

@ -6,7 +6,7 @@
#include <type_traits> #include <type_traits>
namespace bwidgets::core namespace bwidgets
{ {
template<typename T> template<typename T>
concept CanToString = requires(T value) concept CanToString = requires(T value)
@ -14,6 +14,9 @@ namespace bwidgets::core
std::to_string(value); std::to_string(value);
}; };
template<typename T>
concept FloatingPoint = std::is_floating_point_v<T>;
template<typename T> template<typename T>
concept Numeric = std::is_arithmetic_v<T>; concept Numeric = std::is_arithmetic_v<T>;

View File

@ -2,14 +2,13 @@
#define BWIDGETS_EXCEPTION_HPP #define BWIDGETS_EXCEPTION_HPP
#include <any> #include <any>
#include <cstdlib>
#include <exception> #include <exception>
#include <functional> #include <functional>
#include <map> #include <map>
#include <basic_widgets/core/type/concepts.hpp> #include <basic_widgets/core/type/concepts.hpp>
namespace bwidgets::core namespace bwidgets
{ {
struct BaseException : std::exception struct BaseException : std::exception
{ {
@ -37,9 +36,8 @@ namespace bwidgets::core
template<Exception E, typename T> template<Exception E, typename T>
static inline auto success_or_throw( static inline auto success_or_throw(
T code, const char* file, const char* func, const int l, const char* w = nullptr, T code, const char* file, const char* func, const int l, const char* w = nullptr,
std::function<bool(const T&)> success = [](const T& code) { std::function<bool(const T&)> success = [](const T& code) { return code == 0; })
return code == EXIT_SUCCESS; -> T
}) -> T
{ {
if (!success(code)) throw E(file, func, l, w); if (!success(code)) throw E(file, func, l, w);
return code; return code;

View File

@ -1,9 +1,9 @@
#ifndef BWIDGETS_FC_ERROR_HPP_ #ifndef BWIDGETS_FC_ERROR_HPP
#define BWIDGETS_FC_ERROR_HPP_ #define BWIDGETS_FC_ERROR_HPP
#include <basic_widgets/core/type/exception.hpp> #include <basic_widgets/core/type/exception.hpp>
namespace bwidgets::core namespace bwidgets
{ {
struct FCError final : BaseException struct FCError final : BaseException
{ {

View File

@ -1,15 +1,23 @@
#ifndef BWIDGETS_OPAQUE_STRUCT_HPP #ifndef BWIDGETS_OPAQUE_STRUCT_HPP
#define BWIDGETS_OPAQUE_STRUCT_HPP #define BWIDGETS_OPAQUE_STRUCT_HPP
namespace bwidgets::core namespace bwidgets
{ {
template<typename T> template<typename T>
struct OpaqueStruct class OpaqueStruct
{ {
T* c_pod; protected:
T* _c_pod;
OpaqueStruct(T* ptr = nullptr) : c_pod(ptr) {} public:
OpaqueStruct(T* ptr = nullptr) : _c_pod(ptr) {}
virtual ~OpaqueStruct<T>() noexcept = default; virtual ~OpaqueStruct<T>() noexcept = default;
// NOLINTNEXTLINE(modernize-use-trailing-return-type)
[[nodiscard]] inline auto& operator()()
{
return _c_pod;
}
}; };
template<typename... Ts> template<typename... Ts>

View File

@ -1,5 +1,5 @@
#ifndef BWIDGETS_SDL_ERROR_HPP_ #ifndef BWIDGETS_SDL_ERROR_HPP
#define BWIDGETS_SDL_ERROR_HPP_ #define BWIDGETS_SDL_ERROR_HPP
#include <basic_widgets/core/type/exception.hpp> #include <basic_widgets/core/type/exception.hpp>
@ -7,7 +7,7 @@ extern "C" {
auto SDL_GetError() -> const char*; auto SDL_GetError() -> const char*;
} }
namespace bwidgets::core namespace bwidgets
{ {
struct SDLError final : BaseException struct SDLError final : BaseException
{ {
@ -17,11 +17,12 @@ namespace bwidgets::core
{} {}
template<typename T> template<typename T>
static inline auto ptr_or_throw(T* ptr, const char* file, const char* func, [[nodiscard]] static inline auto ptr_or_throw(T* ptr, const char* file,
const int l, const char* w = nullptr) -> T* const char* func, const int l,
const char* w = nullptr) -> T*
{ {
if (ptr == nullptr) { if (!ptr) {
if (w == nullptr) w = SDL_GetError(); if (!w) w = SDL_GetError();
throw SDLError(file, func, l, w); throw SDLError(file, func, l, w);
} }
return ptr; return ptr;

View File

@ -1,30 +1,30 @@
#ifndef BWIDGETS_SIZE_HPP_ #ifndef BWIDGETS_SIZE_HPP
#define BWIDGETS_SIZE_HPP_ #define BWIDGETS_SIZE_HPP
#include <basic_widgets/core/type/concepts.hpp> #include <basic_widgets/core/type/concepts.hpp>
namespace bwidgets::core namespace bwidgets
{ {
struct Size struct Size
{ {
int w; int w;
int h; int h;
inline auto operator-() const -> Size [[nodiscard]] inline auto operator-() const -> Size
{ {
return {-w, -h}; return {-w, -h};
} }
inline auto operator+(const Size& s) const -> Size [[nodiscard]] inline auto operator+(const Size& s) const -> Size
{ {
return {w + s.w, h + s.h}; return {w + s.w, h + s.h};
} }
inline auto operator-(const Size& s) const -> Size [[nodiscard]] inline auto operator-(const Size& s) const -> Size
{ {
return {w - s.w, h - s.h}; return {w - s.w, h - s.h};
} }
template<Numeric T> template<Numeric N>
inline auto operator*(T a) -> Size [[nodiscard]] inline auto operator*(N a) const -> Size
{ {
return {a * w, a * h}; return {a * w, a * h};
} }

View File

@ -0,0 +1,26 @@
#ifndef BWIDGETS_ALIGNED_LAYOUT_HPP
#define BWIDGETS_ALIGNED_LAYOUT_HPP
#include <basic_widgets/w/base/layout.hpp>
namespace bwidgets
{
class AlignedLayout final : public Layout
{
private:
void _update_layout(const SDL_Rect&) noexcept override;
public:
enum struct Alignment
{
HORIZONTAL,
VERTICAL
} alignment;
AlignedLayout(Alignment align) : alignment(align) {}
[[nodiscard]] auto size() const noexcept -> Size override;
};
}
#endif

View File

@ -1,6 +1,7 @@
#ifndef BWIDGETS_INPUT_HPP_ #ifndef BWIDGETS_INPUT_HPP
#define BWIDGETS_INPUT_HPP_ #define BWIDGETS_INPUT_HPP
#include <cmath>
#include <exception> #include <exception>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
@ -15,7 +16,7 @@
#include <basic_widgets/w/feat/keyboard_handler.hpp> #include <basic_widgets/w/feat/keyboard_handler.hpp>
#include <basic_widgets/w/feat/mouse_handler.hpp> #include <basic_widgets/w/feat/mouse_handler.hpp>
namespace bwidgets::widget namespace bwidgets
{ {
template<typename T> template<typename T>
@ -25,10 +26,9 @@ namespace bwidgets::widget
public MouseHandler public MouseHandler
{ {
protected: protected:
const int _border_width {3}; Caption _input_caption;
Caption _input_caption;
Input(Widget* parent = nullptr) : Widget(parent) Input(Widget* parent = nullptr) : Widget(parent), _input_caption(this)
{ {
FocusHandler::_focus_area = &_widget_area; FocusHandler::_focus_area = &_widget_area;
MouseHandler::_click_area = &_widget_area; MouseHandler::_click_area = &_widget_area;
@ -47,24 +47,24 @@ namespace bwidgets::widget
} }
} }
void _handle_font_change(core::Font* f) override void _handle_font_change(Font* f) override
{ {
_input_caption.font(f); _input_caption.font(f);
_handle_geometry_change(_viewport); _handle_geometry_change(_viewport);
} }
void _handle_font_color_change(const SDL_Color& fg, const SDL_Color& bg) override void _handle_font_color_change(const Color& fg, const Color& bg) override
{ {
_input_caption.color_bg(bg)->color_fg(fg); _input_caption.font_color_bg(bg)->font_color_fg(fg);
} }
void _handle_geometry_change(const SDL_Rect& vp) noexcept override void _handle_geometry_change(const SDL_Rect& vp) noexcept override
{ {
const auto input_h = _input_caption.size().h + 2 * _border_width; const auto input_h = _input_caption.size().h + 2 * border_width;
_widget_area = {0, core::center_line(vp.h, input_h), vp.w, input_h}; _widget_area = {0, center_line(vp.h, input_h), vp.w, input_h};
_input_caption.viewport(core::rect_offset( _input_caption.viewport(rect_offset(
{core::rect_margin(_widget_area, {_border_width, _border_width})}, vp)); {rect_margin(_widget_area, {border_width, border_width})}, vp));
} }
void _handle_key(const SDL_KeyboardEvent& key) override void _handle_key(const SDL_KeyboardEvent& key) override
@ -89,26 +89,24 @@ namespace bwidgets::widget
} }
} }
void _handle_renderer_change(core::Renderer* r) override void _handle_renderer_change(Renderer* r) override
{ {
_input_caption.renderer(r); _input_caption.renderer(r);
} }
void _handle_rendering() override void _handle_rendering() override
{ {
// TODO: smoothstep for (int i = border_width - 1; i >= 0; i--) {
for (int i = _border_width - 1; i >= 0; i--) { const auto factor = linear(i, 0, border_width);
_renderer const auto& color_end = _has_focus ? color_bg_focused : color_bg;
->draw_color({(uint8_t)(color_border.r / (i + 1)), const auto color_start = color_end / 2;
(uint8_t)(color_border.g / (i + 1)), _renderer->draw_color(lerp(color_start, color_end, factor))
(uint8_t)(color_border.b / (i + 1)), color_border.a}) ->draw_rect(rect_margin(_widget_area, {i, i}));
->draw_rect({_widget_area.x + i, _widget_area.y + i,
_widget_area.w - 2 * i, _widget_area.h - 2 * i});
} }
if (MouseHandler::_is_hovered || FocusHandler::_has_focus) if (MouseHandler::_is_hovered || FocusHandler::_has_focus)
_input_caption.color_bg(color_bg_focused); _input_caption.font_color_bg(color_bg_focused);
else _input_caption.color_bg(color_bg); else _input_caption.font_color_bg(color_bg);
_input_caption.render(); _input_caption.render();
} }
@ -121,20 +119,21 @@ namespace bwidgets::widget
} }
public: public:
SDL_Color color_border {160, 160, 160, // NOLINT(readability-magic-numbers) static const int border_width = 3;
SDL_ALPHA_OPAQUE}; inline static const Color default_color_bg = {200, 200, 200, SDL_ALPHA_OPAQUE};
SDL_Color color_bg {200, 200, 200, // NOLINT(readability-magic-numbers) inline static const Color default_color_bg_focused = {255, 255, 255,
SDL_ALPHA_OPAQUE}; SDL_ALPHA_OPAQUE};
SDL_Color color_bg_focused {
255, 255, 255, SDL_ALPHA_OPAQUE}; // NOLINT(readability-magic-numbers)
int float_precision {2};
int input_min_width {1};
char input_width_unit {'W'};
T value {};
virtual auto color_fg(const SDL_Color& c) noexcept -> Input<T>* Color color_bg = default_color_bg;
Color color_bg_focused = default_color_bg_focused;
int float_precision = 2;
int input_min_width = 1;
char input_width_unit = 'W';
T value {};
virtual auto color_fg(const Color& c) noexcept -> Input<T>*
{ {
_input_caption.color_fg(c); _input_caption.font_color_fg(c);
return this; return this;
} }
@ -149,27 +148,29 @@ namespace bwidgets::widget
return this; return this;
} }
[[nodiscard]] virtual auto [[nodiscard]] virtual auto is_valid_input(const std::string&) const noexcept
is_valid_input(const std::string& /*unused*/) const noexcept -> bool -> bool
{ {
return true; return true;
} }
virtual auto process_value(T x) const noexcept -> T [[nodiscard]] virtual auto process_value(T x) const noexcept -> T
{ {
return x; return x;
} }
[[nodiscard]] inline auto size() const noexcept -> core::Size override [[nodiscard]] inline auto size() const noexcept -> Size override
{ {
if (_font == nullptr) return {0, 0};
return { return {
_font->text_size(std::string(input_min_width, input_width_unit)).w _font->text_size(std::string(input_min_width, input_width_unit)).w
+ 2 * _border_width, + 2 * border_width,
_font->line_skip + 4 * _border_width // _why_ 4 and not 2?… _font->line_skip + 4 * border_width // _why_ 4 and not 2?…
}; };
} }
auto value_from_string(std::string s) -> T [[nodiscard]] auto value_from_string(std::string s)
{ {
T v; T v;
@ -182,33 +183,33 @@ namespace bwidgets::widget
T, std::string> || std::convertible_to<std::string, T>) T, std::string> || std::convertible_to<std::string, T>)
v = s; v = s;
else else
static_assert((bool)sizeof(T) // NOLINTNEXTLINE(readability-simplify-boolean-expr)
&& false, // NOLINT(readability-simplify-boolean-expr) static_assert((bool)sizeof(T) && false,
"string cannot be converted to v type T."); "string cannot be converted to v type T.");
return process_value(v); return process_value(v);
} }
auto value_to_string(T value) -> std::string [[nodiscard]] auto value_to_string(T value)
{ {
std::string s; std::string s;
if constexpr (std::is_same_v<std::string, if constexpr (std::is_same_v<std::string,
T> || std::convertible_to<T, std::string>) T> || std::convertible_to<T, std::string>)
s = std::move(value); s = std::move(value);
else if constexpr (core::CanToString<T>) { else if constexpr (CanToString<T>) {
std::stringstream ss; std::stringstream ss;
ss << std::fixed << std::setprecision(float_precision) << value; ss << std::fixed << std::setprecision(float_precision) << value;
s = std::move(ss).str(); s = std::move(ss).str();
} }
else if constexpr (core::Printable<T>) { else if constexpr (Printable<T>) {
std::stringstream ss; std::stringstream ss;
ss << value; ss << value;
s = std::move(ss).str(); s = std::move(ss).str();
} }
else else
static_assert((bool)sizeof(T) // NOLINTNEXTLINE(readability-simplify-boolean-expr)
&& false, // NOLINT(readability-simplify-boolean-expr) static_assert((bool)sizeof(T) && false,
"value cannot be converted to string."); "value cannot be converted to string.");
return s; return s;

View File

@ -1,5 +1,5 @@
#ifndef BWIDGETS_LAYOUT_HPP_ #ifndef BWIDGETS_LAYOUT_HPP
#define BWIDGETS_LAYOUT_HPP_ #define BWIDGETS_LAYOUT_HPP
#include <functional> #include <functional>
#include <vector> #include <vector>
@ -7,34 +7,36 @@
#include <basic_widgets/core/type/size.hpp> #include <basic_widgets/core/type/size.hpp>
#include <basic_widgets/w/base/widget.hpp> #include <basic_widgets/w/base/widget.hpp>
namespace bwidgets::core namespace bwidgets
{ {
struct Renderer; class Renderer;
} }
namespace bwidgets::widget namespace bwidgets
{ {
class Layout : public Widget class Layout : public Widget
{ {
protected: protected:
std::vector<Widget*> _widgets; std::vector<Widget*> _widgets;
void _handle_geometry_change(const SDL_Rect& /*unused*/) noexcept override; void _handle_geometry_change(const SDL_Rect&) noexcept override;
void _handle_renderer_change(core::Renderer* /*unused*/) override; void _handle_renderer_change(Renderer*) override;
void _handle_rendering() override; void _handle_rendering() override;
virtual void _update_layout(const SDL_Rect&) noexcept = 0; virtual void _update_layout(const SDL_Rect&) noexcept = 0;
public: public:
core::Size margins {8, 8}; // NOLINT(readability-magic-numbers) inline static const Size default_margins {8, 8};
Size margins = default_margins;
~Layout() noexcept override; ~Layout() noexcept override;
auto handle_event(const SDL_Event&) -> Layout* override;
[[nodiscard]] auto size() const noexcept -> Size override = 0;
virtual auto add_widget(Widget*) -> Layout*; virtual auto add_widget(Widget*) -> Layout*;
virtual void for_widgets(const std::function<void(Widget*)>&); virtual void for_widgets(const std::function<void(Widget*)>&);
auto handle_event(const SDL_Event&) // NOLINT(readability-named-parameter)
-> Layout* override;
[[nodiscard]] auto size() const noexcept -> core::Size override = 0;
}; };
} }

View File

@ -1,5 +1,5 @@
#ifndef BWIDGETS_WIDGET_HPP_ #ifndef BWIDGETS_WIDGET_HPP
#define BWIDGETS_WIDGET_HPP_ #define BWIDGETS_WIDGET_HPP
#include <basic_widgets/core/renderer.hpp> #include <basic_widgets/core/renderer.hpp>
#include <basic_widgets/core/type/size.hpp> #include <basic_widgets/core/type/size.hpp>
@ -8,17 +8,17 @@ union SDL_Event;
struct SDL_Renderer; struct SDL_Renderer;
namespace bwidgets::widget namespace bwidgets
{ {
class Widget class Widget
{ {
protected: protected:
core::Renderer* _renderer {nullptr}; Renderer* _renderer {nullptr};
SDL_Rect _viewport {0, 0, 0, 0}; SDL_Rect _viewport {0, 0, 0, 0};
SDL_Rect _widget_area {0, 0, 0, 0}; SDL_Rect _widget_area {0, 0, 0, 0};
virtual void _handle_geometry_change(const SDL_Rect&) noexcept = 0; virtual void _handle_geometry_change(const SDL_Rect&) noexcept = 0;
virtual void _handle_renderer_change(core::Renderer* /*unused*/) {} virtual void _handle_renderer_change(Renderer*) {}
virtual void _handle_rendering() = 0; virtual void _handle_rendering() = 0;
public: public:
@ -27,30 +27,13 @@ namespace bwidgets::widget
Widget(Widget* p = nullptr) : parent(p) {} Widget(Widget* p = nullptr) : parent(p) {}
virtual ~Widget() noexcept = default; virtual ~Widget() noexcept = default;
virtual auto handle_event(const SDL_Event&) -> Widget*;
[[nodiscard]] inline virtual auto size() const noexcept -> core::Size = 0; virtual auto handle_event(const SDL_Event&) -> Widget*;
[[nodiscard]] virtual auto size() const noexcept -> Size = 0;
virtual auto render() -> Widget* final; virtual auto render() -> Widget* final;
virtual auto renderer(Renderer*) -> Widget* final;
virtual inline auto renderer(core::Renderer* r) -> Widget* final virtual auto viewport(const SDL_Rect&) noexcept -> Widget* final;
{ [[nodiscard]] virtual auto viewport() const noexcept -> const SDL_Rect& final;
_handle_renderer_change(r);
_renderer = r;
return this;
}
[[nodiscard]] virtual inline auto viewport() const noexcept
-> const SDL_Rect& final
{
return _viewport;
}
virtual inline auto viewport(const SDL_Rect& vp) noexcept -> Widget* final
{
_handle_geometry_change(vp);
_viewport = vp;
return this;
}
}; };
} }

View File

@ -1,44 +1,48 @@
#ifndef BWIDGETS_BUTTON_HPP_ #ifndef BWIDGETS_BUTTON_HPP
#define BWIDGETS_BUTTON_HPP_ #define BWIDGETS_BUTTON_HPP
#include <functional> #include <functional>
#include <string> #include <string>
#include <basic_widgets/core/type/color.hpp>
#include <basic_widgets/w/caption.hpp> #include <basic_widgets/w/caption.hpp>
#include <basic_widgets/w/feat/mouse_handler.hpp> #include <basic_widgets/w/feat/mouse_handler.hpp>
namespace bwidgets::widget namespace bwidgets
{ {
class Button : public Widget, class Button : public Widget,
public FontHandler, public FontHandler,
public MouseHandler public MouseHandler
{ {
protected: protected:
Caption _caption; Caption _caption;
SDL_Rect _caption_area {}; SDL_Rect _caption_area {};
SDL_Color _color_foreground {0, 0, 0, SDL_ALPHA_OPAQUE}; Color _color_foreground = default_color_fg;
void _handle_focus_change(bool /*unused*/) override {} void _handle_focus_change(bool) override {}
void _handle_font_change(core::Font* /*unused*/) override; void _handle_font_change(Font*) override;
void _handle_font_color_change(const SDL_Color& /*unused*/, void _handle_font_color_change(const Color&, const Color&) override;
const SDL_Color& /*unused*/) override; void _handle_geometry_change(const SDL_Rect&) noexcept override;
void _handle_geometry_change(const SDL_Rect& /*unused*/) noexcept override; void _handle_renderer_change(Renderer*) override;
void _handle_renderer_change(core::Renderer* /*unused*/) override;
void _handle_rendering() override; void _handle_rendering() override;
void _on_push(bool) override; void _on_push(bool) override;
public: public:
std::function<SDL_Color(int, int)> border_gradient; inline static const Color default_color_bg {150, 150, 150, SDL_ALPHA_OPAQUE};
std::function<SDL_Color(int, int)> border_gradient_pushed; inline static const Color default_color_bg_hover {175, 175, 175,
core::Size border_size {3, 3}; SDL_ALPHA_OPAQUE};
SDL_Color color_bg {150, 150, 150, // NOLINT(readability-magic-numbers) inline static const Color default_color_fg {0, 0, 0, SDL_ALPHA_OPAQUE};
SDL_ALPHA_OPAQUE};
SDL_Color color_bg_hover {175, 175, 175, // NOLINT(readability-magic-numbers) std::function<Color(int, int)> border_gradient;
SDL_ALPHA_OPAQUE}; std::function<Color(int, int)> border_gradient_pushed;
Size border_size {3, 3};
Color color_bg = default_color_bg;
Color color_bg_hover = default_color_bg_hover;
Button(Widget* parent = nullptr); Button(Widget* parent = nullptr);
[[nodiscard]] auto size() const noexcept -> core::Size override; [[nodiscard]] auto size() const noexcept -> Size override;
[[nodiscard]] virtual auto text() const noexcept -> const std::string&; [[nodiscard]] virtual auto text() const noexcept -> const std::string&;
virtual auto text(const std::string&) -> Button*; virtual auto text(const std::string&) -> Button*;
}; };

View File

@ -1,5 +1,5 @@
#ifndef BWIDGETS_CAPTION_HPP_ #ifndef BWIDGETS_CAPTION_HPP
#define BWIDGETS_CAPTION_HPP_ #define BWIDGETS_CAPTION_HPP
#include <basic_widgets/core/texture.hpp> #include <basic_widgets/core/texture.hpp>
#include <basic_widgets/core/type/size.hpp> #include <basic_widgets/core/type/size.hpp>
@ -9,12 +9,24 @@
struct SDL_Surface; struct SDL_Surface;
namespace bwidgets::widget namespace bwidgets
{ {
class Caption : public Widget, class Caption : public Widget,
public FontHandler, public FontHandler,
public TextureHandler public TextureHandler
{ {
protected:
Font::RenderMode _render_mode {Font::RenderMode::SHADED};
std::string _text;
Texture* _text_texture {nullptr};
void _handle_font_change(Font*) override;
void _handle_font_color_change(const Color&, const Color&) override;
void _handle_geometry_change(const SDL_Rect&) noexcept override;
void _handle_renderer_change(Renderer*) override;
void _handle_rendering() override;
void _handle_texture_update() override;
public: public:
enum struct Alignment enum struct Alignment
{ {
@ -23,36 +35,20 @@ namespace bwidgets::widget
RIGHT RIGHT
}; };
protected: inline static const Color default_color_bg = {255, 255, 255, SDL_ALPHA_OPAQUE};
SDL_Color _color_fg {0, 0, 0, SDL_ALPHA_OPAQUE}; inline static const Color default_color_fg = {0, 0, 0, SDL_ALPHA_OPAQUE};
SDL_Color _color_bg {255, 255, 255, // NOLINT(readability-magic-numbers)
SDL_ALPHA_TRANSPARENT};
core::Font::RenderMode _render_mode {core::Font::RenderMode::SHADED};
std::string _text;
core::Texture* _text_texture {nullptr};
void _handle_font_change(core::Font* /*unused*/) override; Alignment alignment {Alignment::LEFT};
void _handle_font_color_change(const SDL_Color& /*unused*/, Size margins {3, 3};
const SDL_Color& /*unused*/) override;
void _handle_geometry_change(const SDL_Rect& /*unused*/) noexcept override;
void _handle_renderer_change(core::Renderer* /*unused*/) override;
void _handle_rendering() override;
void _handle_texture_update() override;
public: Caption(Widget* parent = nullptr);
Alignment alignment {Alignment::LEFT};
core::Size margins {3, 3};
Caption(Widget* parent = nullptr) : Widget(parent) {}
~Caption() noexcept override; ~Caption() noexcept override;
virtual auto color_bg(const SDL_Color&) -> Caption*; virtual auto render_mode(Font::RenderMode) noexcept -> Caption*;
virtual auto color_fg(const SDL_Color&) -> Caption*;
virtual auto render_mode(core::Font::RenderMode) noexcept -> Caption*;
[[nodiscard]] virtual auto text() const noexcept -> const std::string&; [[nodiscard]] virtual auto text() const noexcept -> const std::string&;
virtual auto text(const std::string&) -> Caption*; virtual auto text(const std::string&) -> Caption*;
[[nodiscard]] auto size() const noexcept -> core::Size override; [[nodiscard]] auto size() const noexcept -> Size override;
}; };
} }

View File

@ -1,9 +1,9 @@
#ifndef BWIDGETS_FOCUS_HANDLER_HPP_ #ifndef BWIDGETS_FOCUS_HANDLER_HPP
#define BWIDGETS_FOCUS_HANDLER_HPP_ #define BWIDGETS_FOCUS_HANDLER_HPP
struct SDL_Rect; struct SDL_Rect;
namespace bwidgets::widget namespace bwidgets
{ {
class FocusHandler class FocusHandler
{ {

View File

@ -1,43 +1,57 @@
#ifndef BWIDGETS_FONT_HANDLER_HPP_ #ifndef BWIDGETS_FONT_HANDLER_HPP
#define BWIDGETS_FONT_HANDLER_HPP_ #define BWIDGETS_FONT_HANDLER_HPP
#include <basic_widgets/core/font.hpp> #include <basic_widgets/core/font.hpp>
namespace bwidgets::widget namespace bwidgets
{ {
class FontHandler class FontHandler
{ {
protected: protected:
core::Font* _font {nullptr}; Font* _font {nullptr};
SDL_Color _font_color_bg {255, 255, 255, // NOLINT(readability-magic-numbers) Color _font_color_bg = default_font_color_bg;
SDL_ALPHA_OPAQUE}; Color _font_color_fg = default_font_color_fg;
SDL_Color _font_color_fg {0, 0, 0, SDL_ALPHA_OPAQUE}; Font::RenderMode _font_render_mode {Font::RenderMode::SHADED};
core::Font::RenderMode _font_render_mode {core::Font::RenderMode::SHADED};
virtual void _handle_font_change(core::Font*) = 0; virtual void _handle_font_change(Font*) = 0;
virtual void _handle_font_color_change(const SDL_Color&, const SDL_Color&) = 0; virtual void _handle_font_color_change(const Color&, const Color&) = 0;
public: public:
inline static const Color default_font_color_bg {255, 255, 255,
SDL_ALPHA_OPAQUE};
inline static const Color default_font_color_fg {0, 0, 0, SDL_ALPHA_OPAQUE};
virtual ~FontHandler() = default; virtual ~FontHandler() = default;
virtual inline auto font(core::Font* f) -> FontHandler* final virtual inline auto font(Font* f) -> FontHandler* final
{ {
_handle_font_change(f); if (f != nullptr
_font = f; && (f != _font || f->family_name != _font->family_name
|| f->height != _font->height || f->hinting() != _font->hinting()
|| f->kerning() != _font->kerning()
|| f->outline() != _font->outline()
|| f->style_name != _font->style_name))
{
_handle_font_change(f);
_font = f;
}
return this; return this;
} }
virtual inline auto font_color_bg(const SDL_Color& c) -> FontHandler* final virtual inline auto font_color_bg(const Color& c) -> FontHandler* final
{ {
_handle_font_color_change(_font_color_bg, c); if (c != _font_color_bg) {
_font_color_bg = c; _handle_font_color_change(_font_color_bg, c);
_font_color_bg = c;
}
return this; return this;
} }
virtual inline auto font_color_fg(const SDL_Color& c) -> FontHandler* final virtual inline auto font_color_fg(const Color& c) -> FontHandler* final
{ {
_handle_font_color_change(c, _font_color_bg); if (c != _font_color_fg) {
_font_color_fg = c; _handle_font_color_change(c, _font_color_fg);
_font_color_fg = c;
}
return this; return this;
} }
}; };

View File

@ -1,12 +1,12 @@
#ifndef BWIDGETS_KEYBOARD_HANDLER_ #ifndef BWIDGETS_KEYBOARD_HANDLER
#define BWIDGETS_KEYBOARD_HANDLER_ #define BWIDGETS_KEYBOARD_HANDLER
#include <basic_widgets/w/feat/focus_handler.hpp> #include <basic_widgets/w/feat/focus_handler.hpp>
struct SDL_KeyboardEvent; struct SDL_KeyboardEvent;
struct SDL_TextInputEvent; struct SDL_TextInputEvent;
namespace bwidgets::widget namespace bwidgets
{ {
class KeyboardHandler : public virtual FocusHandler class KeyboardHandler : public virtual FocusHandler
{ {
@ -15,14 +15,18 @@ namespace bwidgets::widget
virtual void _handle_text_input(const SDL_TextInputEvent&) = 0; virtual void _handle_text_input(const SDL_TextInputEvent&) = 0;
public: public:
virtual inline void handle_keyboard(const SDL_KeyboardEvent& ev) final virtual inline auto handle_keyboard(const SDL_KeyboardEvent& ev)
-> KeyboardHandler* final
{ {
if (_has_focus) _handle_key(ev); if (_has_focus) _handle_key(ev);
return this;
} }
virtual inline void handle_keyboard(const SDL_TextInputEvent& ev) final virtual inline auto handle_keyboard(const SDL_TextInputEvent& ev)
-> KeyboardHandler* final
{ {
if (_has_focus) _handle_text_input(ev); if (_has_focus) _handle_text_input(ev);
return this;
} }
}; };
} }

View File

@ -1,5 +1,5 @@
#ifndef BWIDGETS_MOUSE_HANDLER_HPP_ #ifndef BWIDGETS_MOUSE_HANDLER_HPP
#define BWIDGETS_MOUSE_HANDLER_HPP_ #define BWIDGETS_MOUSE_HANDLER_HPP
#include <functional> #include <functional>
@ -8,7 +8,7 @@
struct SDL_MouseButtonEvent; struct SDL_MouseButtonEvent;
struct SDL_MouseMotionEvent; struct SDL_MouseMotionEvent;
namespace bwidgets::widget namespace bwidgets
{ {
class MouseHandler : public virtual FocusHandler class MouseHandler : public virtual FocusHandler
{ {

View File

@ -1,12 +1,12 @@
#ifndef BWIDGETS_TEXTURE_HANDLER_ #ifndef BWIDGETS_TEXTURE_HANDLER
#define BWIDGETS_TEXTURE_HANDLER_ #define BWIDGETS_TEXTURE_HANDLER
namespace bwidgets::core namespace bwidgets
{ {
struct Renderer; class Renderer;
} }
namespace bwidgets::widget namespace bwidgets
{ {
class TextureHandler class TextureHandler
{ {

View File

@ -1,18 +0,0 @@
#ifndef BWIDGETS_HORIZONTAL_LAYOUT_HPP_
#define BWIDGETS_HORIZONTAL_LAYOUT_HPP_
#include <basic_widgets/w/base/layout.hpp>
namespace bwidgets::widget
{
class HorizontalLayout final : public Layout
{
private:
void _update_layout(const SDL_Rect& /*unused*/) noexcept override;
public:
[[nodiscard]] auto size() const noexcept -> core::Size override;
};
}
#endif

View File

@ -1,5 +1,5 @@
#ifndef BWIDGETS_NUMERIC_INPUT_HPP_ #ifndef BWIDGETS_NUMERIC_INPUT_HPP
#define BWIDGETS_NUMERIC_INPUT_HPP_ #define BWIDGETS_NUMERIC_INPUT_HPP
#include <limits> #include <limits>
@ -10,12 +10,12 @@
#include <type_traits> #include <type_traits>
namespace bwidgets::widget namespace bwidgets
{ {
template<core::Numeric T> template<Numeric T>
class NumericInput : public Input<T> class NumericInput : public Input<T>
{ {
private: protected:
Button _increment_button; Button _increment_button;
SDL_Rect _increment_button_area {}; SDL_Rect _increment_button_area {};
Button _decrement_button; Button _decrement_button;
@ -23,14 +23,14 @@ namespace bwidgets::widget
std::pair<T, T> _value_range {std::numeric_limits<T>::lowest(), std::pair<T, T> _value_range {std::numeric_limits<T>::lowest(),
std::numeric_limits<T>::max()}; std::numeric_limits<T>::max()};
void _handle_font_change(core::Font* f) override void _handle_font_change(Font* f) override
{ {
_decrement_button.font(f); _decrement_button.font(f);
_increment_button.font(f); _increment_button.font(f);
Input<T>::_handle_font_change(f); Input<T>::_handle_font_change(f);
} }
void _handle_font_color_change(const SDL_Color& fg, const SDL_Color& bg) override void _handle_font_color_change(const Color& fg, const Color& bg) override
{ {
Input<T>::_handle_font_color_change(fg, bg); Input<T>::_handle_font_color_change(fg, bg);
_decrement_button.font_color_bg(bg)->font_color_fg(fg); _decrement_button.font_color_bg(bg)->font_color_fg(fg);
@ -45,16 +45,16 @@ namespace bwidgets::widget
? _increment_button.size().w ? _increment_button.size().w
: _decrement_button.size().w; : _decrement_button.size().w;
const int button_area_width = 2 * widest_button; const int button_area_width = 2 * widest_button;
const int spacing = core::center_line(button_area_width, widest_button); const int spacing = center_line(button_area_width, widest_button);
const int field_width = vp.w - 2 * button_area_width; const int field_width = vp.w - 2 * button_area_width;
Widget::_widget_area.x = Widget::_widget_area.x + button_area_width; Widget::_widget_area.x = Widget::_widget_area.x + button_area_width;
Widget::_widget_area.w = field_width; Widget::_widget_area.w = field_width;
Input<T>::_input_caption.viewport(core::rect_offset( Input<T>::_input_caption.viewport(
core::rect_margin(Widget::_widget_area, rect_offset(rect_margin(Widget::_widget_area,
{Input<T>::_border_width, Input<T>::_border_width}), {Input<T>::border_width, Input<T>::border_width}),
vp)); vp));
_decrement_button_area = {spacing, Widget::_widget_area.y, _decrement_button_area = {spacing, Widget::_widget_area.y,
_decrement_button.size().w, _decrement_button.size().w,
_decrement_button.size().h}; _decrement_button.size().h};
@ -63,11 +63,11 @@ namespace bwidgets::widget
Widget::_widget_area.y, _increment_button.size().w, Widget::_widget_area.y, _increment_button.size().w,
_increment_button.size().h}; _increment_button.size().h};
_increment_button.viewport(core::rect_offset(_increment_button_area, vp)); _increment_button.viewport(rect_offset(_increment_button_area, vp));
_decrement_button.viewport(core::rect_offset(_decrement_button_area, vp)); _decrement_button.viewport(rect_offset(_decrement_button_area, vp));
} }
void _handle_renderer_change(core::Renderer* r) override void _handle_renderer_change(Renderer* r) override
{ {
Input<T>::_handle_renderer_change(r); Input<T>::_handle_renderer_change(r);
_decrement_button.renderer(r); _decrement_button.renderer(r);
@ -87,7 +87,7 @@ namespace bwidgets::widget
NumericInput(Widget* parent = nullptr) NumericInput(Widget* parent = nullptr)
: Input<T>(parent), _increment_button(this), _decrement_button(this) : Input<T>(parent), _increment_button(this), _decrement_button(this)
{ {
Input<T>::_input_caption.alignment = widget::Caption::Alignment::RIGHT; Input<T>::_input_caption.alignment = Caption::Alignment::RIGHT;
Input<T>::input_min_width = 10; // NOLINT(readability-magic-numbers) Input<T>::input_min_width = 10; // NOLINT(readability-magic-numbers)
Input<T>::input_width_unit = '0'; Input<T>::input_width_unit = '0';
@ -117,7 +117,7 @@ namespace bwidgets::widget
auto handle_event(const SDL_Event& ev) -> Widget* override auto handle_event(const SDL_Event& ev) -> Widget* override
{ {
Widget::handle_event(ev); Input<T>::handle_event(ev);
_increment_button.handle_event(ev); _increment_button.handle_event(ev);
_decrement_button.handle_event(ev); _decrement_button.handle_event(ev);
return this; return this;
@ -128,19 +128,19 @@ namespace bwidgets::widget
{ {
bool valid = false; bool valid = false;
if (input.at(0) >= '0' && input.at(0) <= '9') valid = true; if (input[0] >= '0' && input[0] <= '9') valid = true;
if constexpr (std::is_floating_point_v<T>) if constexpr (std::is_floating_point_v<T>)
if (input.at(0) == '.' if (input[0] == '.'
&& Input<T>::input_text().find('.') == std::string::npos) && Input<T>::input_text().find('.') == std::string::npos)
valid = true; valid = true;
if constexpr (std::is_signed_v<T>) { if constexpr (std::is_signed_v<T>) {
std::string displayed_value = Input<T>::input_text(); std::string displayed_value = Input<T>::input_text();
if (input.at(0) == '-' && displayed_value.empty()) valid = true; if (input[0] == '-' && displayed_value.empty()) valid = true;
} }
return valid; return valid;
} }
auto process_value(T x) const noexcept -> T override [[nodiscard]] auto process_value(T x) const noexcept -> T override
{ {
T value = x; T value = x;
if (x < _value_range.first) value = _value_range.first; if (x < _value_range.first) value = _value_range.first;
@ -149,14 +149,14 @@ namespace bwidgets::widget
return value; return value;
} }
[[nodiscard]] inline auto size() const noexcept -> core::Size override [[nodiscard]] inline auto size() const noexcept -> Size override
{ {
auto base = Input<T>::size(); auto base = Input<T>::size();
auto btns_width = 4 * _increment_button.size().w; auto btns_width = 4 * _increment_button.size().w;
return {base.w + btns_width, base.h}; return {base.w + btns_width, base.h};
} }
virtual auto value_range() const noexcept -> std::pair<T, T> [[nodiscard]] virtual auto value_range() const noexcept -> const std::pair<T, T>&
{ {
return _value_range; return _value_range;
} }

View File

@ -1,18 +0,0 @@
#ifndef BWIDGETS_VERTICAL_LAYOUT_HPP_
#define BWIDGETS_VERTICAL_LAYOUT_HPP_
#include <basic_widgets/w/base/layout.hpp>
namespace bwidgets::widget
{
class VerticalLayout final : public Layout
{
private:
void _update_layout(const SDL_Rect& /*unused*/) noexcept override;
public:
[[nodiscard]] auto size() const noexcept -> core::Size override;
};
}
#endif

View File

@ -1,13 +1,16 @@
project('sdl2_basic_widgets', 'cpp', project('sdl2_basic_widgets', 'cpp',
version : '0.1pre', version : '0.1pre',
default_options : [ default_options : [
'warning_level=3', 'b_lundef=false',
'b_sanitize=address,undefined',
'cpp_std=c++20', 'cpp_std=c++20',
'd_ndebug=if-release', 'd_ndebug=if-release',
'optimization=g'], 'optimization=g',
'warning_level=3',
],
license: 'EUPL-1.2') license: 'EUPL-1.2')
add_project_arguments('-pedantic', language: 'cpp') add_project_arguments('-pedantic', '-Winline', language: 'cpp')
sdl = [ sdl = [
dependency('sdl2', version: '>=2.0.5'), dependency('sdl2', version: '>=2.0.5'),
@ -22,15 +25,14 @@ libbasic_widgets = static_library('basic_widgets',
'src/core/font.cpp', 'src/core/font.cpp',
'src/core/renderer.cpp', 'src/core/renderer.cpp',
'src/core/texture.cpp', 'src/core/texture.cpp',
'src/w/aligned_layout.cpp',
'src/w/base/layout.cpp', 'src/w/base/layout.cpp',
'src/w/base/widget.cpp', 'src/w/base/widget.cpp',
'src/w/button.cpp',
'src/w/caption.cpp',
'src/w/feat/font_handler.cpp', 'src/w/feat/font_handler.cpp',
'src/w/feat/keyboard_handler.cpp', 'src/w/feat/keyboard_handler.cpp',
'src/w/feat/mouse_handler.cpp', 'src/w/feat/mouse_handler.cpp',
'src/w/button.cpp',
'src/w/caption.cpp',
'src/w/horizontal_layout.cpp',
'src/w/vertical_layout.cpp',
dependencies : [sdl, fontconfig], dependencies : [sdl, fontconfig],
include_directories : pub_api, include_directories : pub_api,
install : true) install : true)

View File

@ -8,28 +8,34 @@
#include <basic_widgets/core/math.hpp> #include <basic_widgets/core/math.hpp>
#include <basic_widgets/core/texture.hpp> #include <basic_widgets/core/texture.hpp>
namespace bwidgets::core namespace bwidgets
{ {
auto aa(const SDL_Color& base_color, const int aa_pixels, const float d) noexcept auto aa(const Color& base_color, const int aa_pixels, const float d) noexcept
-> SDL_Color -> Color
{ {
SDL_Color c {base_color}; Color c(base_color);
if (aa_pixels == 0) { if (aa_pixels == 0) {
if (d > 0) c.a = 0; if (d > 0) c().a = 0;
} }
else { else {
const auto factor = 1.0 - smoothstep<float>(d, (float)-aa_pixels, 0.); const auto factor = 1.0 - smoothstep<float>(d, (float)-aa_pixels, 0.);
c.a = (uint8_t)((float)c.a * factor); c().a = (uint8_t)((float)c().a * factor);
} }
return c; return c;
} }
auto filled_circle(const SDL_Color& c, const int resolution, core::Renderer* r, auto filled_circle(const Color& c, const int resolution, Renderer* r,
const int aa_pixels) -> core::Texture* const int aa_pixels) -> Texture*
{ {
auto* texture {new core::Texture( // clang-format off
r, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, resolution, resolution)}; auto* texture {new Texture(
r,
SDL_PIXELFORMAT_RGBA32,
SDL_TEXTUREACCESS_STATIC,
resolution,
resolution)};
// clang-format on
const auto radius {resolution / 2}; const auto radius {resolution / 2};
const SDL_Point center {radius, radius}; const SDL_Point center {radius, radius};
@ -37,10 +43,11 @@ namespace bwidgets::core
texture, texture,
[aa_pixels, c, center, radius](const SDL_Point& p, [aa_pixels, c, center, radius](const SDL_Point& p,
const SDL_PixelFormat* format) -> uint32_t { const SDL_PixelFormat* format) -> uint32_t {
const auto d_delta = core::distance(center, p) - (float)radius; const auto d_delta = distance(center, p) - (float)radius;
const auto aa_color = aa(c, aa_pixels, d_delta); const auto aa_color = aa(c, aa_pixels, d_delta);
return SDL_MapRGBA(format, aa_color.r, aa_color.g, aa_color.b, aa_color.a); return SDL_MapRGBA(format, aa_color().r, aa_color().g, aa_color().b,
aa_color().a);
}); });
texture->blend_mode(SDL_BLENDMODE_BLEND); texture->blend_mode(SDL_BLENDMODE_BLEND);
texture->scale_mode(SDL_ScaleModeNearest); texture->scale_mode(SDL_ScaleModeNearest);
@ -49,8 +56,9 @@ namespace bwidgets::core
} }
void set_pixels_color( void set_pixels_color(
core::Texture* t, Texture* t,
const std::function<Uint32(const SDL_Point&, const SDL_PixelFormat*)>& pixel_color) const std::function<uint32_t(const SDL_Point&, const SDL_PixelFormat*)>&
pixel_color)
{ {
auto attr = t->attributes(); auto attr = t->attributes();
auto pitch = attr.w * attr.format->BytesPerPixel; auto pitch = attr.w * attr.format->BytesPerPixel;
@ -59,7 +67,7 @@ namespace bwidgets::core
pixels.reserve(attr.h * (std::vector<uint32_t>::size_type)pitch); pixels.reserve(attr.h * (std::vector<uint32_t>::size_type)pitch);
for (auto y = 0; y < attr.h; y++) { for (auto y = 0; y < attr.h; y++) {
for (auto x = 0; x < attr.w; x++) { for (auto x = 0; x < attr.w; x++) {
pixels.push_back(pixel_color({x, y}, attr.format)); pixels.emplace_back(pixel_color({x, y}, attr.format));
} }
} }

View File

@ -1,6 +1,5 @@
#include <any>
#include <functional> #include <functional>
#include <vector> #include <stack>
#include <fontconfig/fontconfig.h> #include <fontconfig/fontconfig.h>
@ -8,7 +7,7 @@
#include <basic_widgets/core/type/fc_error.hpp> #include <basic_widgets/core/type/fc_error.hpp>
#include <basic_widgets/core/type/sdl_error.hpp> #include <basic_widgets/core/type/sdl_error.hpp>
namespace bwidgets::core namespace bwidgets
{ {
Font::Font(TTF_Font* f) Font::Font(TTF_Font* f)
: OpaqueStruct(f), : OpaqueStruct(f),
@ -29,44 +28,44 @@ namespace bwidgets::core
Font::~Font() Font::~Font()
{ {
TTF_CloseFont(c_pod); TTF_CloseFont(_c_pod);
} }
auto Font::hinting() -> Font::Hinting auto Font::hinting() -> Font::Hinting
{ {
return (Hinting)TTF_GetFontHinting(c_pod); return (Hinting)TTF_GetFontHinting(_c_pod);
} }
auto Font::hinting(Font::Hinting h) -> Font* auto Font::hinting(Font::Hinting h) -> Font*
{ {
TTF_SetFontHinting(c_pod, (int)h); TTF_SetFontHinting(_c_pod, (int)h);
return this; return this;
} }
auto Font::kerning() -> bool auto Font::kerning() -> bool
{ {
return TTF_GetFontHinting(c_pod) != 0; return TTF_GetFontKerning(_c_pod) != 0;
} }
auto Font::kerning(bool allowed) -> Font* auto Font::kerning(bool allowed) -> Font*
{ {
TTF_SetFontKerning(c_pod, static_cast<int>(allowed)); TTF_SetFontKerning(_c_pod, static_cast<int>(allowed));
return this; return this;
} }
auto Font::outline() -> int auto Font::outline() -> int
{ {
return TTF_GetFontOutline(c_pod); return TTF_GetFontOutline(_c_pod);
} }
auto Font::outline(int size) -> Font* auto Font::outline(int size) -> Font*
{ {
TTF_SetFontOutline(c_pod, size); TTF_SetFontOutline(_c_pod, size);
return this; return this;
} }
auto Font::render(RenderMode m, const std::string& str, const SDL_Color& fg, auto Font::render(RenderMode m, const std::string& str, const Color& fg,
const SDL_Color& bg) -> SDL_Surface* const Color& bg) -> SDL_Surface*
{ {
std::function<SDL_Surface*()> renderer; std::function<SDL_Surface*()> renderer;
const char* c_str = str.empty() ? " " : str.c_str(); const char* c_str = str.empty() ? " " : str.c_str();
@ -74,17 +73,17 @@ namespace bwidgets::core
switch (m) { switch (m) {
case RenderMode::BLENDED: case RenderMode::BLENDED:
renderer = [&fg, c_str, this]() { renderer = [&fg, c_str, this]() {
return TTF_RenderUTF8_Blended(c_pod, c_str, fg); return TTF_RenderUTF8_Blended(_c_pod, c_str, fg());
}; };
break; break;
case RenderMode::SHADED: case RenderMode::SHADED:
renderer = [&bg, &fg, c_str, this]() { renderer = [&bg, &fg, c_str, this]() {
return TTF_RenderUTF8_Shaded(c_pod, c_str, fg, bg); return TTF_RenderUTF8_Shaded(_c_pod, c_str, fg(), bg());
}; };
break; break;
case RenderMode::SOLID: case RenderMode::SOLID:
renderer = [&fg, c_str, this]() { renderer = [&fg, c_str, this]() {
return TTF_RenderUTF8_Solid(c_pod, c_str, fg); return TTF_RenderUTF8_Solid(_c_pod, c_str, fg());
}; };
break; break;
} }
@ -94,53 +93,45 @@ namespace bwidgets::core
auto Font::style() -> uint8_t auto Font::style() -> uint8_t
{ {
return TTF_GetFontStyle(c_pod); return TTF_GetFontStyle(_c_pod);
} }
auto Font::style(uint8_t s) -> Font* auto Font::style(uint8_t s) -> Font*
{ {
TTF_SetFontStyle(c_pod, s); TTF_SetFontStyle(_c_pod, s);
return this; return this;
} }
auto Font::text_size(const std::string& str) -> Size auto Font::text_size(const std::string& str) -> Size
{ {
Size s {}; Size s {};
TTF_SizeUTF8(c_pod, str.c_str(), &s.w, &s.h); TTF_SizeUTF8(_c_pod, str.c_str(), &s.w, &s.h);
return s; return s;
} }
auto Font::find(const std::string& pat) -> std::string auto Font::find(const std::string& pat) -> std::string
{ {
std::vector<std::any> ptrs; std::stack<std::function<void()>> cleaners;
auto clean = [&ptrs](int lvl) mutable {
switch (lvl) {
case 2:
FcPatternDestroy(std::any_cast<FcPattern*>(ptrs.at(1)));
[[fallthrough]];
case 1:
FcConfigDestroy(std::any_cast<FcConfig*>(ptrs.at(0)));
FcFini();
}
};
FcConfig* conf = ptr_or_throw<FCError>(FcInitLoadConfigAndFonts(), __FILE__, FcConfig* conf = ptr_or_throw<FCError>(FcInitLoadConfigAndFonts(), __FILE__,
__FUNCTION__, __LINE__, "init failed"); __FUNCTION__, __LINE__, "init failed");
ptrs.emplace_back(conf); cleaners.emplace([conf]() { FcConfigDestroy(conf); });
FcPattern* pattern = nullptr; FcPattern* pattern = nullptr;
try { try {
pattern = pattern =
ptr_or_throw<FCError>(FcNameParse((FcChar8*)pat.c_str()), __FILE__, ptr_or_throw<FCError>(FcNameParse((FcChar8*)pat.c_str()), __FILE__,
__FUNCTION__, __LINE__, "pattern parsing failed"); __FUNCTION__, __LINE__, "pattern parsing failed");
ptrs.emplace_back(pattern); cleaners.emplace([pattern]() { FcPatternDestroy(pattern); });
if (FcConfigSubstitute(conf, pattern, FcMatchPattern) == FcFalse) if (FcConfigSubstitute(conf, pattern, FcMatchPattern) == FcFalse)
throw FCError {__FILE__, __FUNCTION__, __LINE__, throw FCError {__FILE__, __FUNCTION__, __LINE__,
"FcConfigSubstitute failed"}; "FcConfigSubstitute failed"};
} catch (const std::exception& e) { } catch (const std::exception& e) {
clean((int)ptrs.size()); while (!cleaners.empty()) {
cleaners.top()();
cleaners.pop();
}
throw e; throw e;
} }
@ -157,7 +148,10 @@ namespace bwidgets::core
FcPatternDestroy(font); FcPatternDestroy(font);
} }
clean((int)ptrs.size()); while (!cleaners.empty()) {
cleaners.top()();
cleaners.pop();
}
if (file_path.empty()) if (file_path.empty())
throw FCError {__FILE__, __FUNCTION__, __LINE__, "no font found"}; throw FCError {__FILE__, __FUNCTION__, __LINE__, "no font found"};

View File

@ -3,101 +3,103 @@
using namespace bwidgets; using namespace bwidgets;
core::Renderer::Renderer(SDL_Renderer* r) : OpaqueStruct(r), info(_info(r)) {} Renderer::Renderer(SDL_Renderer* r) : OpaqueStruct(r), info(_info(r)) {}
core::Renderer::Renderer(SDL_Window* w, int index, uint32_t flags = 0) Renderer::Renderer(SDL_Window* w, int index, uint32_t flags = 0)
: Renderer(ptr_or_throw<SDLError>(SDL_CreateRenderer(w, index, flags), __FILE__, : Renderer(ptr_or_throw<SDLError>(SDL_CreateRenderer(w, index, flags), __FILE__,
__FUNCTION__, __LINE__)) __FUNCTION__, __LINE__))
{} {}
core::Renderer::~Renderer() Renderer::~Renderer()
{ {
SDL_DestroyRenderer(c_pod); SDL_DestroyRenderer(_c_pod);
} }
auto core::Renderer::blend_mode() -> SDL_BlendMode auto Renderer::blend_mode() -> SDL_BlendMode
{ {
SDL_BlendMode mode {}; SDL_BlendMode mode {};
SDLError::success_or_throw(SDL_GetRenderDrawBlendMode(c_pod, &mode), __FILE__, SDLError::success_or_throw(SDL_GetRenderDrawBlendMode(_c_pod, &mode), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
return mode; return mode;
} }
auto core::Renderer::blend_mode(SDL_BlendMode mode) -> core::Renderer* auto Renderer::blend_mode(SDL_BlendMode mode) -> Renderer*
{ {
SDLError::success_or_throw(SDL_SetRenderDrawBlendMode(c_pod, mode), __FILE__, SDLError::success_or_throw(SDL_SetRenderDrawBlendMode(_c_pod, mode), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Renderer::clear() -> core::Renderer* auto Renderer::clear() -> Renderer*
{ {
SDLError::success_or_throw(SDL_RenderClear(c_pod), __FILE__, __FUNCTION__, __LINE__); SDLError::success_or_throw(SDL_RenderClear(_c_pod), __FILE__, __FUNCTION__,
__LINE__);
return this; return this;
} }
auto core::Renderer::copy(core::Texture* t, const SDL_Rect* src, const SDL_Rect* dst) auto Renderer::copy(Texture* t, const SDL_Rect* src, const SDL_Rect* dst) -> Renderer*
-> core::Renderer*
{ {
SDLError::success_or_throw(SDL_RenderCopy(c_pod, t->c_pod, src, dst), __FILE__, SDLError::success_or_throw(SDL_RenderCopy(_c_pod, (*t)(), src, dst), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Renderer::draw_color() -> SDL_Color auto Renderer::draw_color() -> Color
{ {
SDL_Color c; Color c;
SDLError::success_or_throw(SDL_GetRenderDrawColor(c_pod, &c.r, &c.g, &c.b, &c.a), SDLError::success_or_throw(
__FILE__, __FUNCTION__, __LINE__); SDL_GetRenderDrawColor(_c_pod, &c().r, &c().g, &c().b, &c().a), __FILE__,
__FUNCTION__, __LINE__);
return c; return c;
} }
auto core::Renderer::draw_color(const SDL_Color& c) -> core::Renderer* auto Renderer::draw_color(const Color& c) -> Renderer*
{ {
SDLError::success_or_throw(SDL_SetRenderDrawColor(c_pod, c.r, c.g, c.b, c.a), SDLError::success_or_throw(
__FILE__, __FUNCTION__, __LINE__); SDL_SetRenderDrawColor(_c_pod, c().r, c().g, c().b, c().a), __FILE__, __FUNCTION__,
__LINE__);
return this; return this;
} }
auto core::Renderer::draw_line(const SDL_Point& a, const SDL_Point& b) -> core::Renderer* auto Renderer::draw_line(const SDL_Point& a, const SDL_Point& b) -> Renderer*
{ {
SDLError::success_or_throw(SDL_RenderDrawLine(c_pod, a.x, a.y, b.x, b.y), __FILE__, SDLError::success_or_throw(SDL_RenderDrawLine(_c_pod, a.x, a.y, b.x, b.y), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Renderer::draw_lines(const std::vector<SDL_Point>& pts) -> core::Renderer* auto Renderer::draw_lines(const std::vector<SDL_Point>& pts) -> Renderer*
{ {
SDLError::success_or_throw(SDL_RenderDrawLines(c_pod, pts.data(), (int)pts.size()), SDLError::success_or_throw(SDL_RenderDrawLines(_c_pod, pts.data(), (int)pts.size()),
__FILE__, __FUNCTION__, __LINE__); __FILE__, __FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Renderer::draw_point(const SDL_Point& p) -> core::Renderer* auto Renderer::draw_point(const SDL_Point& p) -> Renderer*
{ {
SDLError::success_or_throw(SDL_RenderDrawPoint(c_pod, p.x, p.y), __FILE__, SDLError::success_or_throw(SDL_RenderDrawPoint(_c_pod, p.x, p.y), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Renderer::draw_points(const std::vector<SDL_Point>& pts) -> core::Renderer* auto Renderer::draw_points(const std::vector<SDL_Point>& pts) -> Renderer*
{ {
SDLError::success_or_throw(SDL_RenderDrawPoints(c_pod, pts.data(), (int)pts.size()), SDLError::success_or_throw(SDL_RenderDrawPoints(_c_pod, pts.data(), (int)pts.size()),
__FILE__, __FUNCTION__, __LINE__); __FILE__, __FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Renderer::draw_rect(const SDL_Rect* r) -> core::Renderer* auto Renderer::draw_rect(const SDL_Rect* r) -> Renderer*
{ {
auto vp = viewport(); auto vp = viewport();
// Has glitch at top-left and bottom-right corner. // Has glitch at top-left and bottom-right corner.
@ -105,10 +107,10 @@ auto core::Renderer::draw_rect(const SDL_Rect* r) -> core::Renderer*
// The second corner is missing a pixel. // The second corner is missing a pixel.
if (r != nullptr) if (r != nullptr)
viewport({vp.x + r->x, vp.y + r->y, r->w - 1, r->h - 1}); // crop extra pixel viewport({vp.x + r->x, vp.y + r->y, r->w - 1, r->h - 1}); // crop extra pixel
SDLError::success_or_throw(SDL_RenderDrawRect(c_pod, nullptr), __FILE__, SDLError::success_or_throw(SDL_RenderDrawRect(_c_pod, nullptr), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
// add missing pixel. works sometimes…
if (r != nullptr) draw_point({r->w - 1, r->h - 1}); // add missing pixel if (r != nullptr) draw_point({r->w - 1, r->h - 1});
else draw_point({vp.w - 1, vp.h - 1}); else draw_point({vp.w - 1, vp.h - 1});
viewport(vp); viewport(vp);
@ -116,55 +118,55 @@ auto core::Renderer::draw_rect(const SDL_Rect* r) -> core::Renderer*
return this; return this;
} }
auto core::Renderer::draw_rects(const std::vector<SDL_Rect>& rs) -> core::Renderer* auto Renderer::draw_rects(const std::vector<SDL_Rect>& rs) -> Renderer*
{ {
SDLError::success_or_throw(SDL_RenderDrawRects(c_pod, rs.data(), (int)rs.size()), SDLError::success_or_throw(SDL_RenderDrawRects(_c_pod, rs.data(), (int)rs.size()),
__FILE__, __FUNCTION__, __LINE__); __FILE__, __FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Renderer::fill_rect(const SDL_Rect* r) -> core::Renderer* auto Renderer::fill_rect(const SDL_Rect* r) -> Renderer*
{ {
SDLError::success_or_throw(SDL_RenderFillRect(c_pod, r), __FILE__, __FUNCTION__, SDLError::success_or_throw(SDL_RenderFillRect(_c_pod, r), __FILE__, __FUNCTION__,
__LINE__); __LINE__);
return this; return this;
} }
auto core::Renderer::fill_rects(const std::vector<SDL_Rect>& rs) -> core::Renderer* auto Renderer::fill_rects(const std::vector<SDL_Rect>& rs) -> Renderer*
{ {
SDLError::success_or_throw(SDL_RenderFillRects(c_pod, rs.data(), (int)rs.size()), SDLError::success_or_throw(SDL_RenderFillRects(_c_pod, rs.data(), (int)rs.size()),
__FILE__, __FUNCTION__, __LINE__); __FILE__, __FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Renderer::output_size() -> core::Size auto Renderer::output_size() -> Size
{ {
Size s {}; Size s {};
SDLError::success_or_throw(SDL_GetRendererOutputSize(c_pod, &s.w, &s.h), __FILE__, SDLError::success_or_throw(SDL_GetRendererOutputSize(_c_pod, &s.w, &s.h), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
return s; return s;
} }
void core::Renderer::present() void Renderer::present()
{ {
SDL_RenderPresent(c_pod); SDL_RenderPresent(_c_pod);
} }
auto core::Renderer::viewport() -> SDL_Rect auto Renderer::viewport() -> SDL_Rect
{ {
SDL_Rect vp; SDL_Rect vp;
SDL_RenderGetViewport(c_pod, &vp); SDL_RenderGetViewport(_c_pod, &vp);
return vp; return vp;
} }
auto core::Renderer::viewport(const SDL_Rect* vp) -> core::Renderer* auto Renderer::viewport(const SDL_Rect* vp) -> Renderer*
{ {
SDLError::success_or_throw(SDL_RenderSetViewport(c_pod, vp), __FILE__, __FUNCTION__, SDLError::success_or_throw(SDL_RenderSetViewport(_c_pod, vp), __FILE__, __FUNCTION__,
__LINE__); __LINE__);
return this; return this;

View File

@ -3,101 +3,101 @@
using namespace bwidgets; using namespace bwidgets;
core::Texture::Texture(SDL_Texture* t) : OpaqueStruct(t) Texture::Texture(SDL_Texture* t) : OpaqueStruct(t)
{ {
_attributes = attributes(t); _attributes = attributes(t);
} }
core::Texture::Texture(Renderer* r, SDL_PixelFormatEnum f, SDL_TextureAccess a, int w, Texture::Texture(Renderer* r, SDL_PixelFormatEnum f, SDL_TextureAccess a, int w, int h)
int h) : Texture(ptr_or_throw<SDLError>(SDL_CreateTexture((*r)(), f, a, w, h), __FILE__,
: Texture(ptr_or_throw<SDLError>(SDL_CreateTexture(r->c_pod, f, a, w, h), __FILE__,
__FUNCTION__, __LINE__)) __FUNCTION__, __LINE__))
{} {}
core::Texture::Texture(Renderer* r, SDL_Surface* s) Texture::Texture(Renderer* r, SDL_Surface* s)
: OpaqueStruct(ptr_or_throw<SDLError>(SDL_CreateTextureFromSurface(r->c_pod, s), : OpaqueStruct(ptr_or_throw<SDLError>(SDL_CreateTextureFromSurface((*r)(), s),
__FILE__, __FUNCTION__, __LINE__)) __FILE__, __FUNCTION__, __LINE__))
{ {
_attributes = attributes(c_pod); _attributes = attributes(_c_pod);
} }
core::Texture::~Texture() noexcept Texture::~Texture() noexcept
{ {
SDL_DestroyTexture(c_pod); SDL_DestroyTexture(_c_pod);
c_pod = nullptr; _c_pod = nullptr;
} }
auto core::Texture::alpha_mode() -> uint8_t auto Texture::alpha_mode() -> uint8_t
{ {
uint8_t mode = 0; uint8_t mode = 0;
SDLError::success_or_throw(SDL_GetTextureAlphaMod(c_pod, &mode), __FILE__, SDLError::success_or_throw(SDL_GetTextureAlphaMod(_c_pod, &mode), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
return mode; return mode;
} }
auto core::Texture::alpha_mode(uint8_t m) -> core::Texture* auto Texture::alpha_mode(uint8_t m) -> Texture*
{ {
SDLError::success_or_throw(SDL_SetTextureAlphaMod(c_pod, m), __FILE__, __FUNCTION__, SDLError::success_or_throw(SDL_SetTextureAlphaMod(_c_pod, m), __FILE__, __FUNCTION__,
__LINE__); __LINE__);
return this; return this;
} }
auto core::Texture::blend_mode() -> SDL_BlendMode auto Texture::blend_mode() -> SDL_BlendMode
{ {
SDL_BlendMode mode {}; SDL_BlendMode mode {};
SDLError::success_or_throw(SDL_GetTextureBlendMode(c_pod, &mode), __FILE__, SDLError::success_or_throw(SDL_GetTextureBlendMode(_c_pod, &mode), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
return mode; return mode;
} }
auto core::Texture::blend_mode(SDL_BlendMode m) -> core::Texture* auto Texture::blend_mode(SDL_BlendMode m) -> Texture*
{ {
SDLError::success_or_throw(SDL_SetTextureBlendMode(c_pod, m), __FILE__, __FUNCTION__, SDLError::success_or_throw(SDL_SetTextureBlendMode(_c_pod, m), __FILE__,
__LINE__); __FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Texture::color_mode() -> SDL_Color auto Texture::color_mode() -> Color
{ {
SDL_Color mode; Color mode;
SDLError::success_or_throw(SDL_GetTextureColorMod(c_pod, &mode.r, &mode.g, &mode.b), SDLError::success_or_throw(
SDL_GetTextureColorMod(_c_pod, &mode().r, &mode().g, &mode().b), __FILE__,
__FUNCTION__, __LINE__);
return mode;
}
auto Texture::color_mode(const Color& m) -> Texture*
{
SDLError::success_or_throw(SDL_SetTextureColorMod(_c_pod, m().r, m().g, m().b),
__FILE__, __FUNCTION__, __LINE__); __FILE__, __FUNCTION__, __LINE__);
return mode;
}
auto core::Texture::color_mode(const SDL_Color& m) -> core::Texture*
{
SDLError::success_or_throw(SDL_SetTextureColorMod(c_pod, m.r, m.g, m.b), __FILE__,
__FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Texture::scale_mode() -> SDL_ScaleMode auto Texture::scale_mode() -> SDL_ScaleMode
{ {
SDL_ScaleMode mode {}; SDL_ScaleMode mode {};
SDLError::success_or_throw(SDL_GetTextureScaleMode(c_pod, &mode), __FILE__, SDLError::success_or_throw(SDL_GetTextureScaleMode(_c_pod, &mode), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
return mode; return mode;
} }
auto core::Texture::scale_mode(SDL_ScaleMode m) -> core::Texture* auto Texture::scale_mode(SDL_ScaleMode m) -> Texture*
{ {
SDLError::success_or_throw(SDL_SetTextureScaleMode(c_pod, m), __FILE__, __FUNCTION__, SDLError::success_or_throw(SDL_SetTextureScaleMode(_c_pod, m), __FILE__,
__LINE__); __FUNCTION__, __LINE__);
return this; return this;
} }
auto core::Texture::update(SDL_Rect* r, const void* pixels, int pitch) -> core::Texture* auto Texture::update(SDL_Rect* r, const void* pixels, int pitch) -> Texture*
{ {
SDLError::success_or_throw(SDL_UpdateTexture(c_pod, r, pixels, pitch), __FILE__, SDLError::success_or_throw(SDL_UpdateTexture(_c_pod, r, pixels, pitch), __FILE__,
__FUNCTION__, __LINE__); __FUNCTION__, __LINE__);
return this; return this;

57
src/w/aligned_layout.cpp Normal file
View File

@ -0,0 +1,57 @@
#include <basic_widgets/core/math.hpp>
#include <basic_widgets/w/aligned_layout.hpp>
using namespace bwidgets;
auto AlignedLayout::size() const noexcept -> Size
{
Size min_size {0, 0};
if (alignment == Alignment::HORIZONTAL) {
for (const auto* w : _widgets) {
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};
}
for (const auto* w : _widgets) {
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};
}
void AlignedLayout::_update_layout(const SDL_Rect& vp) noexcept
{
if (alignment == Alignment::HORIZONTAL) {
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++) {
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 {
int offset = 0;
for (std::vector<Widget*>::size_type i = 0; i < _widgets.size(); i++) {
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;
}
}
}

View File

@ -2,40 +2,41 @@
using namespace bwidgets; using namespace bwidgets;
widget::Layout::~Layout() noexcept Layout::~Layout() noexcept
{ {
for (Widget* widget_ptr : _widgets) delete widget_ptr; for (auto* widget_ptr : _widgets) delete widget_ptr;
} }
auto widget::Layout::add_widget(Widget* widget_ptr) -> widget::Layout* auto Layout::add_widget(Widget* widget_ptr) -> Layout*
{ {
widget_ptr->renderer(_renderer); widget_ptr->renderer(_renderer);
_widgets.push_back(widget_ptr); _widgets.emplace_back(widget_ptr);
_update_layout(_viewport);
return this; return this;
} }
void widget::Layout::for_widgets(const std::function<void(Widget*)>& f) void Layout::for_widgets(const std::function<void(Widget*)>& f)
{ {
for (auto* w : _widgets) f(w); for (auto* w : _widgets) f(w);
} }
auto widget::Layout::handle_event(const SDL_Event& ev) -> widget::Layout* auto Layout::handle_event(const SDL_Event& ev) -> Layout*
{ {
for (Widget* widget_ptr : _widgets) widget_ptr->handle_event(ev); for (auto* widget_ptr : _widgets) widget_ptr->handle_event(ev);
return this; return this;
} }
void widget::Layout::_handle_geometry_change(const SDL_Rect& vp) noexcept void Layout::_handle_geometry_change(const SDL_Rect& vp) noexcept
{ {
_update_layout(vp); _update_layout(vp);
} }
void widget::Layout::_handle_renderer_change(core::Renderer* r) void Layout::_handle_renderer_change(Renderer* r)
{ {
for (auto* w : _widgets) w->renderer(r); for (auto* w : _widgets) w->renderer(r);
} }
void widget::Layout::_handle_rendering() void Layout::_handle_rendering()
{ {
for (Widget* widget_ptr : _widgets) widget_ptr->render(); for (auto* widget_ptr : _widgets) widget_ptr->render();
} }

View File

@ -7,9 +7,9 @@
using namespace bwidgets; using namespace bwidgets;
auto widget::Widget::handle_event(const SDL_Event& ev) -> widget::Widget* auto Widget::handle_event(const SDL_Event& ev) -> Widget*
{ {
if (auto* handler = dynamic_cast<KeyboardHandler*>(this); handler != nullptr) { if (auto* handler = dynamic_cast<KeyboardHandler*>(this); handler) {
switch (ev.type) { switch (ev.type) {
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_KEYUP: case SDL_KEYUP:
@ -21,7 +21,7 @@ auto widget::Widget::handle_event(const SDL_Event& ev) -> widget::Widget*
} }
} }
if (auto* handler = dynamic_cast<MouseHandler*>(this); handler != nullptr) { if (auto* handler = dynamic_cast<MouseHandler*>(this); handler) {
switch (ev.type) { switch (ev.type) {
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
@ -36,13 +36,18 @@ auto widget::Widget::handle_event(const SDL_Event& ev) -> widget::Widget*
return this; return this;
} }
auto widget::Widget::render() -> widget::Widget* auto Widget::render() -> Widget*
{ {
SDL_assert_release(_renderer); // NOLINT SDL_assert_release(_renderer); // NOLINT
if (_renderer == nullptr) return this; if (_renderer == nullptr) return this;
#ifdef _NDEBUG #ifndef _NDEBUG
_renderer->draw_color({0, 255, 0, SDL_ALPHA_TRANSPARENT})->draw_rect(nullptr); _renderer
->draw_color({
// NOLINTNEXTLINE(readability-magic-numbers)
{0, 255, 0, SDL_ALPHA_TRANSPARENT}
})
->draw_rect(nullptr);
#endif #endif
_renderer->viewport(_viewport); _renderer->viewport(_viewport);
@ -50,3 +55,24 @@ auto widget::Widget::render() -> widget::Widget*
return this; return this;
} }
auto Widget::renderer(Renderer* r) -> Widget*
{
if (r != _renderer) {
_handle_renderer_change(r);
_renderer = r;
}
return this;
}
auto Widget::viewport(const SDL_Rect& vp) noexcept -> Widget*
{
_handle_geometry_change(vp);
_viewport = vp;
return this;
}
auto Widget::viewport() const noexcept -> const SDL_Rect&
{
return _viewport;
}

View File

@ -1,3 +1,5 @@
#include <cmath>
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include <basic_widgets/core/math.hpp> #include <basic_widgets/core/math.hpp>
@ -5,105 +7,96 @@
using namespace bwidgets; using namespace bwidgets;
widget::Button::Button(Widget* parent) : Widget(parent), _caption(this) Button::Button(Widget* parent) : Widget(parent), _caption(this)
{ {
_focus_area = _click_area = &_widget_area; _focus_area = _click_area = &_widget_area;
_caption.alignment = Caption::Alignment::CENTER; _caption.alignment = Caption::Alignment::CENTER;
_caption.render_mode(core::Font::RenderMode::BLENDED); _caption.render_mode(Font::RenderMode::BLENDED);
border_gradient = [this](int len, int pos) -> SDL_Color { border_gradient = [this](int len, int pos) -> Color {
const auto& end_color = _is_hovered ? color_bg_hover : color_bg; const auto& end_color = _is_hovered ? color_bg_hover : color_bg;
const SDL_Color start_color {(uint8_t)(end_color.r / 1.4), const auto start_color = end_color / 2;
(uint8_t)(end_color.g / 1.4), const auto factor = linear(pos, 0, len);
(uint8_t)(end_color.b / 1.4), end_color.a}; return lerp(start_color, end_color, factor);
const auto factor = core::linear(pos, 0, len);
return {(uint8_t)(std::lerp(start_color.r, end_color.r, factor)),
(uint8_t)(std::lerp(start_color.g, end_color.g, factor)),
(uint8_t)(std::lerp(start_color.b, end_color.b, factor)), end_color.a};
}; };
border_gradient_pushed = [this](int len, int pos) -> SDL_Color { border_gradient_pushed = [this](int len, int pos) -> Color {
const auto& end_color = _is_hovered ? color_bg_hover : color_bg; const auto& end_color = _is_hovered ? color_bg_hover : color_bg;
const SDL_Color start_color {(uint8_t)(end_color.r / 1.8), const Color start_color = end_color / 1.5;
(uint8_t)(end_color.g / 1.8), const auto factor = linear(pos, 0, len);
(uint8_t)(end_color.b / 1.8), end_color.a}; return lerp(start_color, end_color, factor);
const auto factor = core::linear(pos, 0, len);
return {(uint8_t)(std::lerp(start_color.r, end_color.r, factor)),
(uint8_t)(std::lerp(start_color.g, end_color.g, factor)),
(uint8_t)(std::lerp(start_color.b, end_color.b, factor)), end_color.a};
}; };
} }
auto widget::Button::size() const noexcept -> core::Size auto Button::size() const noexcept -> Size
{ {
return {_caption.size().w + 2 * border_size.w, return _caption.size() + border_size * 2;
_caption.size().h + 2 * border_size.h};
} }
auto widget::Button::text() const noexcept -> const std::string& auto Button::text() const noexcept -> const std::string&
{ {
return _caption.text(); return _caption.text();
} }
auto widget::Button::text(const std::string& txt) -> widget::Button* auto Button::text(const std::string& txt) -> Button*
{ {
_caption.text(txt); _caption.text(txt);
_handle_geometry_change(_viewport); _handle_geometry_change(_viewport);
return this; return this;
} }
void widget::Button::_handle_font_change(core::Font* f) void Button::_handle_font_change(Font* f)
{ {
_caption.font(f); _caption.font(f);
_handle_geometry_change(_viewport); _handle_geometry_change(_viewport);
} }
void widget::Button::_handle_font_color_change(const SDL_Color& fg, const SDL_Color&) void Button::_handle_font_color_change(const Color& fg, const Color&)
{ {
_caption.color_fg(fg); _caption.font_color_fg(fg);
} }
void widget::Button::_handle_geometry_change(const SDL_Rect& vp) noexcept void Button::_handle_geometry_change(const SDL_Rect& vp) noexcept
{ {
int h = _caption.size().h + 2 * border_size.h; int h = _caption.size().h + 2 * border_size.h;
_widget_area = {0, core::center_line(vp.h, _caption.size().h) - border_size.h, vp.w, _widget_area = {0, center_line(vp.h, _caption.size().h) - border_size.h, vp.w, h};
h};
auto txt_size = _caption.size(); auto txt_size = _caption.size();
_caption_area = {core::center_line(vp.w, txt_size.w), _caption_area = {center_line(vp.w, txt_size.w), center_line(vp.h, txt_size.h),
core::center_line(vp.h, txt_size.h), txt_size.w, txt_size.h}; txt_size.w, txt_size.h};
_caption.viewport(core::rect_offset(_caption_area, vp)); _caption.viewport(rect_offset(_caption_area, vp));
} }
void widget::Button::_handle_renderer_change(core::Renderer* r) void Button::_handle_renderer_change(Renderer* r)
{ {
_caption.renderer(r); _caption.renderer(r);
} }
void widget::Button::_handle_rendering() void Button::_handle_rendering()
{ {
const SDL_Color& c = _is_hovered ? color_bg_hover : color_bg; const Color& c = _is_hovered ? color_bg_hover : color_bg;
const auto& gradient = _is_pushed ? border_gradient_pushed : border_gradient; const auto& gradient = _is_pushed ? border_gradient_pushed : border_gradient;
auto x = 0; auto x = 0;
auto y = 0; auto y = 0;
const auto biggest = border_size.w > border_size.h ? border_size.w : border_size.h; const auto biggest = border_size.w > border_size.h ? border_size.w : border_size.h;
while (x < border_size.w || y < border_size.h) { while (x < border_size.w || y < border_size.h) {
const auto max = x > y ? x : y; const auto max = x > y ? x : y;
const auto margin = core::Size({x, y}); const auto margin = Size({x, y});
_renderer->draw_color(gradient(biggest, max)) _renderer->draw_color(gradient(biggest, max)())
->draw_rect(core::rect_margin(_widget_area, margin)); ->draw_rect(rect_margin(_widget_area, margin));
if (x < border_size.w) x++; if (x < border_size.w) x++;
if (y < border_size.h) y++; if (y < border_size.h) y++;
} }
_renderer->draw_color(c)->fill_rect(core::rect_margin(_widget_area, border_size)); _renderer->draw_color(c())->fill_rect(rect_margin(_widget_area, border_size));
_caption.color_bg(c)->render(); _caption.font_color_bg(c());
_caption.render();
} }
void widget::Button::_on_push(bool state) void Button::_on_push(bool state)
{ {
SDL_Point offset {_viewport.x, _viewport.y}; SDL_Point offset {_viewport.x, _viewport.y};
if (state) { if (state) {
@ -111,5 +104,5 @@ void widget::Button::_on_push(bool state)
offset.y += 1; offset.y += 1;
} }
_caption.viewport(core::rect_offset(_caption_area, offset)); _caption.viewport(rect_offset(_caption_area, offset));
} }

View File

@ -3,106 +3,96 @@
#include <basic_widgets/core/math.hpp> #include <basic_widgets/core/math.hpp>
#include <basic_widgets/core/texture.hpp> #include <basic_widgets/core/texture.hpp>
#include <basic_widgets/w/caption.hpp> #include <basic_widgets/w/caption.hpp>
#include <basic_widgets/w/numeric_input.hpp>
using namespace bwidgets; using namespace bwidgets;
widget::Caption::~Caption() noexcept Caption::Caption(Widget* parent) : Widget(parent)
{ {
core::discard(_text_texture); _font_color_bg = default_font_color_bg;
_font_color_fg = default_font_color_fg;
} }
auto widget::Caption::color_bg(const SDL_Color& c) -> widget::Caption* Caption::~Caption() noexcept
{ {
_color_bg = c; discard(_text_texture);
if (_render_mode == core::Font::RenderMode::SHADED) }
core::discard(_text_texture);
auto Caption::render_mode(Font::RenderMode m) noexcept -> Caption*
{
if (m != _render_mode) {
discard(_text_texture);
_render_mode = m;
}
return this; return this;
} }
auto widget::Caption::color_fg(const SDL_Color& c) -> widget::Caption* auto Caption::size() const noexcept -> Size
{ {
_color_fg = c; if (_font == nullptr) return {0, 0};
core::discard(_text_texture);
return this;
}
auto widget::Caption::render_mode(core::Font::RenderMode m) noexcept -> widget::Caption* Size size = _font->text_size(_text);
{
_render_mode = m;
core::discard(_text_texture);
return this;
}
auto widget::Caption::size() const noexcept -> core::Size
{
if (_font == nullptr) return {-1, -1};
core::Size size = _font->text_size(_text);
return {size.w + 2 * margins.w, size.h + 2 * margins.h}; return {size.w + 2 * margins.w, size.h + 2 * margins.h};
} }
auto widget::Caption::text() const noexcept -> const std::string& auto Caption::text() const noexcept -> const std::string&
{ {
return _text; return _text;
} }
auto widget::Caption::text(const std::string& t) -> widget::Caption* auto Caption::text(const std::string& t) -> Caption*
{ {
_text = t; if (t != _text) {
core::discard(_text_texture); discard(_text_texture);
_text = t;
}
return this; return this;
} }
void widget::Caption::_handle_font_change(core::Font* /*unused*/) void Caption::_handle_font_change(Font*)
{ {
core::discard(_text_texture); discard(_text_texture);
} }
static inline auto operator!=(const SDL_Color& a, const SDL_Color& b) -> bool void Caption::_handle_font_color_change(const Color& fg, const Color& bg)
{
return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a;
}
void widget::Caption::_handle_font_color_change(const SDL_Color& fg, const SDL_Color& bg)
{ {
if (fg != _font_color_fg if (fg != _font_color_fg
|| (bg != _font_color_bg && _font_render_mode == core::Font::RenderMode::SHADED)) || (bg != _font_color_bg && _font_render_mode == Font::RenderMode::SHADED))
{ {
core::discard(_text_texture); discard(_text_texture);
_font_color_bg = bg;
} }
} }
void widget::Caption::_handle_geometry_change(const SDL_Rect& vp) noexcept void Caption::_handle_geometry_change(const SDL_Rect& vp) noexcept
{ {
if (vp.w != _viewport.w || vp.h != _viewport.h) { if (vp.w != _viewport.w || vp.h != _viewport.h) {
_widget_area = core::rect_margin({0, 0, vp.w, vp.h}, margins); _widget_area = rect_margin({0, 0, vp.w, vp.h}, margins);
} }
} }
void widget::Caption::_handle_renderer_change(core::Renderer* /*unused*/) void Caption::_handle_renderer_change(Renderer*)
{ {
core::discard(_text_texture); discard(_text_texture);
} }
void widget::Caption::_handle_rendering() void Caption::_handle_rendering()
{ {
if (_text_texture == nullptr) _handle_texture_update(); if (_text_texture == nullptr) _handle_texture_update();
if (_render_mode == core::Font::RenderMode::SHADED) if (_render_mode == Font::RenderMode::SHADED) {
_renderer->draw_color(_color_bg)->fill_rect({0, 0, _viewport.w, _viewport.h}); _renderer->draw_color(_font_color_bg)
->fill_rect({0, 0, _viewport.w, _viewport.h});
}
if (_text_texture == nullptr) _handle_texture_update(); Size size_dst {(int)((float)_text_texture->attributes().w
/ (float)_text_texture->attributes().h * (float)_widget_area.h),
core::Size size_dst { _widget_area.h};
(int)((float)_text_texture->attributes().w / (float)_text_texture->attributes().h
* _widget_area.h), // NOLINT(bugprone-narrowing-conversions)
_widget_area.h};
SDL_Rect texture_dst {margins.w, margins.h, size_dst.w, size_dst.h}; SDL_Rect texture_dst {margins.w, margins.h, size_dst.w, size_dst.h};
switch (alignment) { switch (alignment) {
case Alignment::CENTER: case Alignment::CENTER:
texture_dst.x = texture_dst.x = center_line(_widget_area.w, texture_dst.w) + _widget_area.x;
core::center_line(_widget_area.w, texture_dst.w) + _widget_area.x;
break; break;
case Alignment::LEFT: case Alignment::LEFT:
break; break;
@ -113,19 +103,18 @@ void widget::Caption::_handle_rendering()
_renderer->copy(_text_texture, nullptr, texture_dst); _renderer->copy(_text_texture, nullptr, texture_dst);
} }
void widget::Caption::_handle_texture_update() void Caption::_handle_texture_update()
{ {
SDL_assert_release(_font); // NOLINT SDL_assert_release(_font && _text_texture == nullptr); // NOLINT
core::discard(_text_texture); SDL_Surface* s;
SDL_Surface* s = nullptr;
switch (_render_mode) { switch (_render_mode) {
case core::Font::RenderMode::SHADED: case Font::RenderMode::SHADED:
s = _font->render(_render_mode, _text, _color_fg, _color_bg); s = _font->render(_render_mode, _text, _font_color_fg, _font_color_bg);
break; break;
default: default:
s = _font->render(_render_mode, _text, _color_fg); s = _font->render(_render_mode, _text, _font_color_fg);
break; break;
} }
_text_texture = new core::Texture(_renderer, s); _text_texture = new Texture(_renderer, s);
SDL_FreeSurface(s); SDL_FreeSurface(s);
} }

View File

@ -6,13 +6,13 @@
using namespace bwidgets; using namespace bwidgets;
auto widget::MouseHandler::handle_mouse(const SDL_MouseButtonEvent& ev, auto MouseHandler::handle_mouse(const SDL_MouseButtonEvent& ev, const SDL_Rect& orig)
const SDL_Rect& orig) -> MouseHandler* -> MouseHandler*
{ {
if (_click_area == nullptr) return this; if (_click_area == nullptr) return this;
SDL_Point p {ev.x, ev.y}; SDL_Point p {ev.x, ev.y};
SDL_Rect vp {core::rect_offset(*_click_area, orig)}; SDL_Rect vp {rect_offset(*_click_area, orig)};
if (ev.type == SDL_MOUSEBUTTONDOWN) { if (ev.type == SDL_MOUSEBUTTONDOWN) {
if (SDL_PointInRect(&p, &vp) == SDL_TRUE) { if (SDL_PointInRect(&p, &vp) == SDL_TRUE) {
@ -36,13 +36,13 @@ auto widget::MouseHandler::handle_mouse(const SDL_MouseButtonEvent& ev,
return this; return this;
} }
auto widget::MouseHandler::handle_mouse(const SDL_MouseMotionEvent& ev, auto MouseHandler::handle_mouse(const SDL_MouseMotionEvent& ev, const SDL_Rect& orig)
const SDL_Rect& orig) -> MouseHandler* -> MouseHandler*
{ {
if (_click_area == nullptr) return this; if (_click_area == nullptr) return this;
SDL_Point p {ev.x, ev.y}; SDL_Point p {ev.x, ev.y};
SDL_Rect vp {core::rect_offset(*_click_area, orig)}; SDL_Rect vp {rect_offset(*_click_area, orig)};
_is_hovered = SDL_PointInRect(&p, &vp) != 0; _is_hovered = SDL_PointInRect(&p, &vp) != 0;
@ -51,7 +51,7 @@ auto widget::MouseHandler::handle_mouse(const SDL_MouseMotionEvent& ev,
return this; return this;
} }
auto widget::MouseHandler::push(bool state) -> MouseHandler* auto MouseHandler::push(bool state) -> MouseHandler*
{ {
_on_push(state); _on_push(state);
_is_pushed = state; _is_pushed = state;

View File

@ -1,30 +0,0 @@
#include <basic_widgets/core/math.hpp>
#include <basic_widgets/w/horizontal_layout.hpp>
using namespace bwidgets;
auto widget::HorizontalLayout::size() const noexcept -> core::Size
{
core::Size max {0, 0};
for (const auto* w : _widgets) {
if (w->size().w > max.w) max.w = w->size().w;
if (w->size().h > max.h) max.h = w->size().h;
}
return {(int)_widgets.size() * max.w + ((int)_widgets.size() + 1) * margins.w,
max.h + 2 * margins.h};
}
void widget::HorizontalLayout::_update_layout(const SDL_Rect& vp) noexcept
{
int widget_size =
(int)((vp.w - (_widgets.size() + 1) * margins.w) / _widgets.size());
for (std::vector<Widget*>::size_type i = 0; i < _widgets.size(); i++) {
auto* w = _widgets[i];
w->viewport({vp.x + margins.w + (int)i * (widget_size + margins.w),
vp.y + core::center_line(vp.h, w->size().h), widget_size,
w->size().h});
}
}

View File

@ -1,32 +0,0 @@
#include <basic_widgets/core/math.hpp>
#include <basic_widgets/w/vertical_layout.hpp>
using namespace bwidgets;
auto widget::VerticalLayout::size() const noexcept -> core::Size
{
core::Size size {0, 0};
for (const auto* w : _widgets) {
if (w->size().w > size.w) size.w = w->size().w;
size.h += w->size().h;
}
return {size.w + 2 * margins.w, size.h + ((int)_widgets.size() + 1) * margins.h};
}
void widget::VerticalLayout::_update_layout(const SDL_Rect& vp) noexcept
{
int offset = 0;
for (std::vector<Widget*>::size_type i = 0; i < _widgets.size(); i++) {
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;
}
}