Compare commits

...

4 Commits

Author SHA1 Message Date
3934e4777f Set dimensions, position & alignment separately 2022-05-19 23:31:53 +02:00
9a6ae2c6d9 Keep list of widgets to render 2022-05-19 21:30:02 +02:00
1bfcfd3bf1 Add View superclass 2022-05-19 21:03:02 +02:00
8aa7267b21 Don't load font in TextWidget 2022-05-19 21:02:00 +02:00
7 changed files with 137 additions and 36 deletions

View File

@ -38,6 +38,7 @@ add_executable(
stw-display stw-display
src/main.cpp src/main.cpp
src/App.cpp src/App.cpp
src/View.cpp
src/AMI.cpp src/AMI.cpp
src/widgets.cpp src/widgets.cpp
src/util.cpp src/util.cpp

View File

@ -1,19 +1,26 @@
#pragma once #pragma once
#include "View.h"
#include "widgets.h" #include "widgets.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
constexpr const char* FT_LOGO_PATH = "resources/Fasttube_Logo-white.bmp"; #include <memory>
#include <vector>
class AMI { constexpr const char* FT_LOGO_PATH = "resources/Fasttube_Logo-white.bmp";
constexpr const char* AVENIR_FONT_PATH = "resources/Avenir-Book.ttf";
class AMI final : public View {
public: public:
AMI(SDL_Renderer* renderer); AMI(SDL_Renderer* renderer);
void draw(); void draw() override;
private: private:
SDL_Renderer* renderer; TTF_Font* avenir;
std::vector<Widget*> widgets;
ImageWidget ft_logo; ImageWidget ft_logo;
TextWidget choose; TextWidget choose;

14
include/View.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include <SDL2/SDL.h>
class View {
public:
View(SDL_Renderer* renderer);
virtual ~View();
virtual void draw() = 0;
protected:
SDL_Renderer* renderer;
};

View File

@ -6,23 +6,36 @@
#include <optional> #include <optional>
#include <string> #include <string>
enum class Alignment { LEFT, RIGHT, CENTER };
struct PositionInfo {
int x;
int y;
Alignment align;
};
class Widget { class Widget {
public: public:
Widget(SDL_Renderer* renderer, SDL_Rect dest_rect); Widget(SDL_Renderer* renderer);
virtual ~Widget();
virtual void update_rect(SDL_Rect new_rect); virtual void set_width(int width, bool preserve_aspect_ratio = true);
virtual void set_height(int height, bool preserve_aspect_ratio = true);
virtual void set_position(int x, int y);
virtual void set_alignment(Alignment align);
virtual void draw() = 0; virtual void draw() = 0;
protected: protected:
void recalculate_rect();
SDL_Renderer* renderer; SDL_Renderer* renderer;
SDL_Rect dest_rect; SDL_Rect rect;
PositionInfo pos;
}; };
class TextureWidget : public Widget { class TextureWidget : public Widget {
public: public:
TextureWidget(SDL_Renderer* renderer, SDL_Rect dest_rect, TextureWidget(SDL_Renderer* renderer, std::optional<SDL_Texture*> texture);
std::optional<SDL_Texture*> texture);
~TextureWidget(); ~TextureWidget();
virtual void draw() override; virtual void draw() override;
@ -30,19 +43,18 @@ public:
void update_texture(SDL_Texture* new_texture); void update_texture(SDL_Texture* new_texture);
private: private:
void update_dimensions_from_texture(SDL_Texture* texture);
std::optional<SDL_Texture*> texture; std::optional<SDL_Texture*> texture;
}; };
class ImageWidget : public TextureWidget { class ImageWidget : public TextureWidget {
public: public:
ImageWidget(SDL_Renderer* renderer, SDL_Rect dest_rect, ImageWidget(SDL_Renderer* renderer, const std::string& path);
const std::string& path);
}; };
class TextWidget : public TextureWidget { class TextWidget : public TextureWidget {
public: public:
TextWidget(SDL_Renderer* renderer, SDL_Rect dest_rect, TextWidget(SDL_Renderer* renderer, TTF_Font* font,
const std::string& font_path,
const std::string& initial_text = ""); const std::string& initial_text = "");
~TextWidget(); ~TextWidget();

View File

@ -1,17 +1,25 @@
#include "AMI.h" #include "AMI.h"
#include "App.h"
#include "util.h"
AMI::AMI(SDL_Renderer* renderer) AMI::AMI(SDL_Renderer* renderer)
: renderer{renderer}, ft_logo{renderer, : View{renderer}, avenir{util::load_font(AVENIR_FONT_PATH, 20)},
{.x = 182, .y = 0, .w = 116, .h = 40}, ft_logo{renderer, FT_LOGO_PATH}, choose{renderer, avenir,
FT_LOGO_PATH}, "Choose a mission:"} {
choose{renderer, ft_logo.set_height(40);
{.x = 0, .y = 45, .w = 480, .h = 40}, ft_logo.set_position(SCREEN_WIDTH / 2, 0);
"resources/Avenir-Book.ttf", ft_logo.set_alignment(Alignment::CENTER);
"Choose a Mission:"} {} widgets.push_back(&ft_logo);
choose.set_position(SCREEN_WIDTH / 2, 45);
choose.set_alignment(Alignment::CENTER);
widgets.push_back(&choose);
}
void AMI::draw() { void AMI::draw() {
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF); SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
ft_logo.draw(); for (const auto& widget : widgets) {
choose.draw(); widget->draw();
}
} }

4
src/View.cpp Normal file
View File

@ -0,0 +1,4 @@
#include "View.h"
View::View(SDL_Renderer* renderer) : renderer{renderer} {}
View::~View() {}

View File

@ -7,14 +7,64 @@
#include <stdexcept> #include <stdexcept>
Widget::Widget(SDL_Renderer* renderer, SDL_Rect rect) Widget::Widget(SDL_Renderer* renderer) : renderer{renderer}, rect{0, 0, 0, 0} {}
: renderer{renderer}, dest_rect{rect} {}
void Widget::update_rect(SDL_Rect new_rect) { dest_rect = new_rect; } Widget::~Widget() {}
TextureWidget::TextureWidget(SDL_Renderer* renderer, SDL_Rect dest_rect, void Widget::set_width(int width, bool preserve_aspect_ratio) {
if (preserve_aspect_ratio) {
float scale = width / rect.w;
rect.h = round(rect.h * scale);
}
rect.w = width;
}
void Widget::set_height(int height, bool preserve_aspect_ratio) {
if (preserve_aspect_ratio) {
float scale = ((float)height) / rect.h;
rect.w = round(rect.w * scale);
}
rect.h = height;
}
void Widget::set_position(int x, int y) {
pos.x = x;
pos.y = y;
recalculate_rect();
}
void Widget::set_alignment(Alignment align) {
pos.align = align;
recalculate_rect();
}
void Widget::recalculate_rect() {
int x = pos.x;
int y = pos.y;
switch (pos.align) {
case Alignment::LEFT:
break;
case Alignment::RIGHT:
x -= rect.w;
break;
case Alignment::CENTER:
x -= rect.w / 2;
break;
default:
throw std::runtime_error(
fmt::format("Unknown alignment: {}", (int)pos.align));
}
rect.x = x;
rect.y = y;
}
TextureWidget::TextureWidget(SDL_Renderer* renderer,
std::optional<SDL_Texture*> texture) std::optional<SDL_Texture*> texture)
: Widget{renderer, dest_rect}, texture{texture} {} : Widget{renderer}, texture{texture} {
if (texture) {
update_dimensions_from_texture(*texture);
}
}
TextureWidget::~TextureWidget() { TextureWidget::~TextureWidget() {
if (texture) { if (texture) {
@ -25,7 +75,7 @@ TextureWidget::~TextureWidget() {
void TextureWidget::draw() { void TextureWidget::draw() {
if (texture) { if (texture) {
SDL_RenderCopy(renderer, *texture, NULL, &dest_rect); SDL_RenderCopy(renderer, *texture, NULL, &rect);
} }
} }
@ -33,24 +83,29 @@ void TextureWidget::update_texture(SDL_Texture* new_texture) {
if (texture) { if (texture) {
SDL_DestroyTexture(*texture); SDL_DestroyTexture(*texture);
} }
update_dimensions_from_texture(new_texture);
texture = new_texture; texture = new_texture;
} }
ImageWidget::ImageWidget(SDL_Renderer* renderer, SDL_Rect dest_rect, void TextureWidget::update_dimensions_from_texture(SDL_Texture* texture) {
const std::string& path) if (SDL_QueryTexture(texture, nullptr, nullptr, &rect.w, &rect.h) != 0) {
: TextureWidget{renderer, dest_rect, util::load_img(renderer, path)} {} throw std::runtime_error(
fmt::format("Couldn't query texture: {}", SDL_GetError()));
}
}
TextWidget::TextWidget(SDL_Renderer* renderer, SDL_Rect dest_rect, ImageWidget::ImageWidget(SDL_Renderer* renderer, const std::string& path)
const std::string& font_path, : TextureWidget{renderer, util::load_img(renderer, path)} {}
TextWidget::TextWidget(SDL_Renderer* renderer, TTF_Font* font,
const std::string& initial_text) const std::string& initial_text)
: TextureWidget{renderer, dest_rect, std::nullopt}, : TextureWidget{renderer, std::nullopt}, font{font}, text{initial_text} {
font{util::load_font(font_path, 28)}, text{initial_text} {
if (text != "") { if (text != "") {
update_texture(generate_text(text)); update_texture(generate_text(text));
} }
} }
TextWidget::~TextWidget() { TTF_CloseFont(font); } TextWidget::~TextWidget() {}
void TextWidget::update_text(const std::string& new_text) { void TextWidget::update_text(const std::string& new_text) {
if (text != new_text) { if (text != new_text) {