Horizontal and vertical layouts.

This commit is contained in:
Andrea Blankenstijn 2021-06-08 14:30:38 +02:00
parent cc8b231623
commit 51fa4f53a3
12 changed files with 288 additions and 78 deletions

View file

@ -1,15 +1,12 @@
#include <iostream>
#include "SDL_ttf.h"
#include "button.hpp"
#include "widget.hpp"
Button::Button(SDL_Renderer* r, SDL_Rect& vp, TTF_Font* f)
: Widget(r, vp), _font(f), _font_height(TTF_FontHeight(f))
Button::Button(SDL_Renderer* r, TTF_Font* f)
: Widget(r), _font(f), _font_height(TTF_FontHeight(f))
{
set_caption("");
_update_caption_area();
set_viewport(vp);
}
Button::~Button()
@ -24,6 +21,8 @@ void Button::handle_event(const SDL_Event& ev)
void Button::render()
{
Widget::render();
SDL_Rect old_vp;
SDL_RenderGetViewport(_renderer, &old_vp);
@ -92,7 +91,7 @@ void Button::set_font(TTF_Font* font)
_render_caption_text();
}
void Button::set_viewport(SDL_Rect& vp)
void Button::set_viewport(SDL_Rect vp)
{
_padding_v = vp.h / 2.0 - (
_font_height * _caption_height_multiplicator + 2 * border_width
@ -110,6 +109,7 @@ void Button::_render_caption_text()
_font,
_caption_text.c_str(),
color_foreground);
SDL_DestroyTexture(_caption_texture);
_caption_texture = SDL_CreateTextureFromSurface(_renderer, surface);
SDL_FreeSurface(surface);
}

View file

@ -1,8 +1,6 @@
#ifndef BUTTON_HPP
#define BUTTON_HPP
#include <SDL2/SDL_pixels.h>
#include <SDL2/SDL_rect.h>
#include <string>
#include <SDL2/SDL_ttf.h>
@ -13,12 +11,12 @@ class Button : public Widget
{
protected:
SDL_Rect _caption_area;
float _caption_height_multiplicator = 1.2;
SDL_Rect _caption_size;
std::string _caption_text;
SDL_Texture* _caption_texture = NULL;
TTF_Font* _font = NULL;
int _font_height;
float _caption_height_multiplicator = 1.2;
virtual void _render_caption_text();
virtual void _update_caption_area();
@ -29,13 +27,13 @@ public:
SDL_Color color_background_hover = {200, 200, 200, SDL_ALPHA_OPAQUE};
SDL_Color color_foreground = {0, 0, 0, SDL_ALPHA_OPAQUE};
Button(SDL_Renderer*, SDL_Rect&, TTF_Font*);
Button(SDL_Renderer*, TTF_Font*);
~Button();
virtual void handle_event(const SDL_Event&);
virtual void render();
virtual void set_caption(std::string);
virtual void set_font(TTF_Font*);
virtual void set_viewport(SDL_Rect&);
virtual void set_viewport(SDL_Rect);
};
#endif

26
horizontal_layout.cpp Normal file
View file

@ -0,0 +1,26 @@
#include "iostream"
#include "horizontal_layout.hpp"
Horizontal_Layout::Horizontal_Layout(SDL_Renderer* r)
: Layout::Layout(r)
{
}
void Horizontal_Layout::_update_layout()
{
float widget_size = (float)_viewport.w / _widgets.size();
for (std::vector<Widget*>::size_type i = 0; i < _widgets.size(); i++)
{
SDL_Rect widget_vp = {
_viewport.x + (int)(i * (widget_size + _interspace / 2)),
_viewport.y,
(int)(widget_size - _interspace),
_viewport.h
};
_widgets.at(i)->set_viewport(widget_vp);
std::cerr << "h-layout:widget:" << i << " " << widget_vp.x << ","
<< widget_vp.y << "," << widget_vp.w << "," << widget_vp.h << std::endl;
}
}

15
horizontal_layout.hpp Normal file
View file

@ -0,0 +1,15 @@
#ifndef HORIZONTAL_LAYOUT_HPP
#define HORIZONTAL_LAYOUT_HPP
#include "layout.hpp"
class Horizontal_Layout : public Layout
{
protected:
void _update_layout();
public:
Horizontal_Layout(SDL_Renderer*);
};
#endif

47
layout.cpp Normal file
View file

@ -0,0 +1,47 @@
#include <iostream>
#include "layout.hpp"
Layout::Layout(SDL_Renderer* r)
: Widget(r)
{
}
Layout::~Layout()
{
for (Widget* widget_ptr : _widgets)
delete widget_ptr;
}
void Layout::add_widget(Widget *widget_ptr)
{
_widgets.push_back(widget_ptr);
}
void Layout::handle_event(const SDL_Event& ev)
{
for (Widget* widget_ptr : _widgets)
widget_ptr->handle_event(ev);
}
void Layout::render()
{
SDL_Rect old_vp;
SDL_RenderGetViewport(_renderer, &old_vp);
SDL_RenderSetViewport(_renderer, &_viewport);
SDL_SetRenderDrawColor(_renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderDrawRect(_renderer, NULL);
for (Widget* widget_ptr : _widgets)
widget_ptr->render();
SDL_RenderSetViewport(_renderer, &old_vp);
}
void Layout::set_viewport(SDL_Rect vp)
{
Widget::set_viewport(vp);
_update_layout();
}

25
layout.hpp Normal file
View file

@ -0,0 +1,25 @@
#ifndef LAYOUT_HPP
#define LAYOUT_HPP
#include <vector>
#include "widget.hpp"
class Layout : public Widget
{
protected:
float _interspace = 16;
std::vector<Widget*> _widgets;
virtual void _update_layout() = 0;
public:
Layout(SDL_Renderer*);
virtual ~Layout();
virtual void add_widget(Widget*);
virtual void handle_event(const SDL_Event&);
virtual void render();
virtual void set_viewport(SDL_Rect);
};
#endif

View file

@ -3,8 +3,12 @@ project('sdl2_basic_widgets', 'cpp',
default_options : ['warning_level=3', 'cpp_std=c++14'])
executable('sdl2_basic_widgets',
'widget_test.cpp',
'horizontal_layout.cpp',
'layout.cpp',
'button.cpp',
'vertical_layout.cpp',
'widget.cpp',
'widget_test.cpp',
dependencies : [
dependency('sdl2'),
dependency('SDL2_ttf')

26
vertical_layout.cpp Normal file
View file

@ -0,0 +1,26 @@
#include <iostream>
#include "vertical_layout.hpp"
Vertical_Layout::Vertical_Layout(SDL_Renderer* r)
: Layout(r)
{
}
void Vertical_Layout::_update_layout()
{
float widget_size = (float)_viewport.h / _widgets.size();
for (std::vector<Widget*>::size_type i = 0; i < _widgets.size(); i++)
{
SDL_Rect widget_vp = {
_viewport.x,
_viewport.y + (int)(i * (widget_size + _interspace / 2)),
_viewport.w,
(int)(widget_size - _interspace),
};
_widgets.at(i)->set_viewport(widget_vp);
std::cerr << "v-layout:widget:" << i << " " << widget_vp.x << ","
<< widget_vp.y << "," << widget_vp.w << "," << widget_vp.h << std::endl;
}
}

15
vertical_layout.hpp Normal file
View file

@ -0,0 +1,15 @@
#ifndef VERTICAL_LAYOUT_HPP
#define VERTICAL_LAYOUT_HPP
#include "layout.hpp"
class Vertical_Layout : public Layout
{
protected:
void _update_layout();
public:
Vertical_Layout(SDL_Renderer*);
};
#endif

78
widget.cpp Normal file
View file

@ -0,0 +1,78 @@
#include <iostream>
#include "widget.hpp"
Widget::Widget(SDL_Renderer* r)
: _renderer(r)
{
}
Widget::~Widget()
{
}
void Widget::handle_event(const SDL_Event &ev)
{
switch (ev.type)
{
case SDL_MOUSEMOTION:
_update_hover_state(ev.motion);
break;
case SDL_MOUSEBUTTONDOWN:
_on_push(ev.button);
break;
case SDL_MOUSEBUTTONUP:
_on_release(ev.button);
break;
}
}
void Widget::render()
{
SDL_Rect old_vp;
SDL_RenderGetViewport(_renderer, &old_vp);
SDL_RenderSetViewport(_renderer, &_viewport);
SDL_SetRenderDrawColor(_renderer, 0, 255, 0, SDL_ALPHA_OPAQUE);
SDL_RenderDrawRect(_renderer, NULL);
SDL_RenderSetViewport(_renderer, &old_vp);
}
void Widget::set_viewport(SDL_Rect vp)
{
_viewport = vp;
_widget_area = {
_padding_h,
_padding_v,
vp.w - 2 * _padding_h,
vp.h - 2 * _padding_v
};
}
void Widget::_on_push(const SDL_MouseButtonEvent& button)
{
SDL_Point position = {button.x - _viewport.x, button.y - _viewport.y};
if (SDL_PointInRect(&position, &_widget_area) == SDL_TRUE)
{
_pushed = true;
}
}
void Widget::_on_release(const SDL_MouseButtonEvent& button)
{
if (_pushed)
{
if (click_handler != NULL)
click_handler(button);
}
_pushed = false;
}
void Widget::_update_hover_state(const SDL_MouseMotionEvent& mouse)
{
SDL_Point position = {mouse.x - _viewport.x, mouse.y - _viewport.y};
_hovered = SDL_PointInRect(&position, &_widget_area) == SDL_TRUE;
}

View file

@ -2,7 +2,6 @@
#define WIDGET_HPP
#include <functional>
#include <iostream>
#include <SDL2/SDL.h>
@ -10,70 +9,25 @@ class Widget
{
protected:
bool _hovered = false;
bool _pushed = false;
SDL_Renderer* _renderer;
SDL_Rect& _viewport;
SDL_Rect _widget_area;
int _padding_h = 0;
int _padding_v = 0;
bool _pushed = false;
SDL_Renderer* _renderer;
SDL_Rect _viewport;
SDL_Rect _widget_area;
virtual void _on_release(const SDL_MouseButtonEvent& button)
{
if (_pushed && click_handler != NULL)
{
click_handler(button);
}
_pushed = false;
}
virtual void _on_push(const SDL_MouseButtonEvent& button)
{
SDL_Point position = {button.x - _viewport.x, button.y - _viewport.y};
if (SDL_PointInRect(&position, &_widget_area) == SDL_TRUE)
{
_pushed = true;
}
}
virtual void _update_hover_state(const SDL_MouseMotionEvent& mouse)
{
SDL_Point position = {mouse.x - _viewport.x, mouse.y - _viewport.y};
_hovered = SDL_PointInRect(&position, &_widget_area) == SDL_TRUE;
}
virtual void _on_push(const SDL_MouseButtonEvent&);
virtual void _on_release(const SDL_MouseButtonEvent&);
virtual void _update_hover_state(const SDL_MouseMotionEvent&);
public:
std::function<void (const SDL_MouseButtonEvent&)> click_handler = NULL;
Widget(SDL_Renderer* r, SDL_Rect& vp)
: _renderer(r), _viewport(vp)
{
set_viewport(vp);
}
virtual ~Widget() {}
virtual void handle_event(const SDL_Event& ev)
{
switch (ev.type)
{
case SDL_MOUSEMOTION:
_update_hover_state(ev.motion);
break;
case SDL_MOUSEBUTTONDOWN:
_on_push(ev.button);
break;
case SDL_MOUSEBUTTONUP:
_on_release(ev.button);
break;
}
}
virtual void render() = 0;
virtual void set_viewport(SDL_Rect& vp)
{
_viewport = vp;
_widget_area = {
_padding_h,
_padding_v,
vp.w - 2 * _padding_h,
vp.h - 2 * _padding_v
};
}
Widget(SDL_Renderer*);
virtual ~Widget();
virtual void handle_event(const SDL_Event&);
virtual void render();
virtual void set_viewport(SDL_Rect);
};
#endif

View file

@ -1,6 +1,8 @@
#include <iostream>
#include "button.hpp"
#include "horizontal_layout.hpp"
#include "vertical_layout.hpp"
int main()
{
@ -22,9 +24,27 @@ int main()
SDL_Renderer* rend = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawBlendMode(rend, SDL_BLENDMODE_BLEND);
SDL_Rect widget_vp = {50, 100, width - 100, height - 200};
Button widget = Button(rend, widget_vp, font);
widget.set_caption("Hrtdyjhguk yukvu");
SDL_Rect layout_vp = {0, 0, width, height};
Layout* layout = new Vertical_Layout(rend);
for (int i = 0; i < 4; i++)
{
std::cerr << "Layout " << i << " Widget:";
Layout* column = new Horizontal_Layout(rend);
layout->add_widget(column);
for (int j = 0; j < 3; j++)
{
Button* widget = new Button(rend, font);
column->add_widget(widget);
std::cerr << " " << j << "@" << widget;
widget->set_caption("Hi!");
widget->click_handler = [i, j] (const SDL_MouseButtonEvent&) {
std::cerr << "click row:" << i
<< ":col:" << j << std::endl;
};
}
std::cerr << std::endl << "Append v-layout" << std::endl;
}
layout->set_viewport(layout_vp);
bool quit = false;
while (!quit)
{
@ -40,25 +60,27 @@ int main()
if (ev.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
SDL_GetRendererOutputSize(rend, &width, &height);
widget_vp.w = width - 100;
widget_vp.h = height - 200;
widget.set_viewport(widget_vp);
layout_vp.w = width;
layout_vp.h = height;
std::cerr << "Screen resized " << width << "x" << height << std::endl;
layout->set_viewport(layout_vp);
}
break;
case SDL_MOUSEBUTTONUP:
//_handle_click({ev.button.x, ev.button.y});
break;
}
widget.handle_event(ev);
layout->handle_event(ev);
}
SDL_SetRenderDrawColor(rend, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(rend);
widget.render();
layout->render();
SDL_RenderPresent(rend);
}
delete layout;
SDL_DestroyRenderer(rend);
SDL_DestroyWindow(win);
SDL_Quit();