Compare commits

...

2 Commits

Author SHA1 Message Date
Jasper Blanckenburg 2e76523bf4 AMI -> MissionSelect 2022-05-22 14:30:42 +02:00
Jasper Blanckenburg 654c71f3ee Select a mission 2022-05-22 14:25:21 +02:00
9 changed files with 133 additions and 22 deletions

View File

@ -39,7 +39,7 @@ add_executable(
src/main.cpp
src/App.cpp
src/View.cpp
src/AMI.cpp
src/MissionSelect.cpp
src/widgets.cpp
src/util.cpp
)

View File

@ -1,13 +1,13 @@
#pragma once
#include "AMI.h"
#include "MissionSelect.h"
#include "defines.h"
#include <SDL2/SDL.h>
#include <memory>
enum class AppView { AMI, DRIVER, TESTING };
enum class AppView { MISSION_SELECT, AMI, DRIVER, TESTING };
class SDLManager {
public:
@ -33,7 +33,7 @@ private:
// others and its destructor is called after the others.
SDLManager sdl_manager;
std::unique_ptr<AMI> ami;
std::unique_ptr<MissionSelect> mission_select;
bool running;
AppView view;

View File

@ -1,19 +1,22 @@
#pragma once
#include "View.h"
#include "events.h"
#include "widgets.h"
#include <SDL2/SDL.h>
#include <memory>
#include <queue>
#include <vector>
class AMI final : public View {
class MissionSelect final : public View {
public:
AMI(SDL_Renderer* renderer);
~AMI();
MissionSelect(SDL_Renderer* renderer);
~MissionSelect();
void draw() override;
void handle_events(std::queue<Event>& events) override;
private:
TTF_Font* avenir;

View File

@ -1,13 +1,18 @@
#pragma once
#include "events.h"
#include <SDL2/SDL.h>
#include <queue>
class View {
public:
View(SDL_Renderer* renderer);
virtual ~View();
virtual void draw() = 0;
virtual void handle_events(std::queue<Event>& events) = 0;
protected:
SDL_Renderer* renderer;

3
include/events.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
enum class Event { Next, Prev, Confirm };

View File

@ -85,10 +85,16 @@ public:
virtual void draw() override;
void select_next();
void select_prev();
size_t get_selection();
protected:
int element_height;
Alignment element_alignment;
size_t selection;
std::vector<Widget*> elements;
void place_element(Widget* element, int index);

View File

@ -1,14 +1,18 @@
#include "App.h"
#include "AMI.h"
#include "MissionSelect.h"
#include "events.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_keycode.h>
#include <fmt/format.h>
#include <queue>
#include <stdexcept>
App::App() : view{AppView::AMI} { init_sdl(); }
App::App() : view{AppView::MISSION_SELECT} { init_sdl(); }
App::~App() {
// Destroy window
@ -34,7 +38,7 @@ void App::init_sdl() {
}
int App::run() {
ami = std::make_unique<AMI>(renderer);
mission_select = std::make_unique<MissionSelect>(renderer);
running = true;
@ -48,18 +52,43 @@ int App::run() {
}
void App::handle_events() {
std::queue<Event> events;
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
running = false;
} else if (e.type == SDL_KEYUP) {
switch (e.key.keysym.sym) {
case SDLK_DOWN:
case SDLK_RIGHT:
events.push(Event::Next);
break;
case SDLK_UP:
case SDLK_LEFT:
events.push(Event::Prev);
break;
case SDLK_RETURN:
case SDLK_KP_ENTER:
events.push(Event::Confirm);
break;
// We can just ignore other keypresses, so no need for a default clause
}
}
}
switch (view) {
case AppView::MISSION_SELECT:
mission_select->handle_events(events);
break;
default:
throw std::runtime_error(fmt::format("Unknown view: {}", (int)view));
}
}
void App::render() {
switch (view) {
case AppView::AMI:
ami->draw();
case AppView::MISSION_SELECT:
mission_select->draw();
break;
default:
throw std::runtime_error(fmt::format("Unknown view: {}", (int)view));

View File

@ -1,10 +1,14 @@
#include "AMI.h"
#include "MissionSelect.h"
#include "defines.h"
#include "events.h"
#include "util.h"
#include "widgets.h"
#include <fmt/format.h>
#include <array>
#include <iostream>
#include <memory>
constexpr const char* FT_LOGO_PATH = "resources/Fasttube_Logo-white.bmp";
@ -20,7 +24,7 @@ constexpr std::array MISSIONS = {"ACCELERATION", "SKIDPAD", "AUTOCROSS",
"TRACKDRIVE", "EBS TEST", "INSPECTION",
"MANUAL DRIVING"};
AMI::AMI(SDL_Renderer* renderer)
MissionSelect::MissionSelect(SDL_Renderer* renderer)
: View{renderer}, avenir{util::load_font(AVENIR_FONT_PATH, AVENIR_PTS)},
chinat{util::load_font(CHINAT_FONT_PATH, CHINAT_PTS)} {
ft_logo = std::make_unique<ImageWidget>(renderer, FT_LOGO_PATH);
@ -51,15 +55,36 @@ AMI::AMI(SDL_Renderer* renderer)
widgets.push_back(missions_widget.get());
}
AMI::~AMI() {
MissionSelect::~MissionSelect() {
TTF_CloseFont(avenir);
TTF_CloseFont(chinat);
}
void AMI::draw() {
void MissionSelect::draw() {
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer);
for (const auto& widget : widgets) {
widget->draw();
}
}
void MissionSelect::handle_events(std::queue<Event>& events) {
while (!events.empty()) {
Event e = events.front();
events.pop();
switch (e) {
case Event::Next:
missions_widget->select_next();
break;
case Event::Prev:
missions_widget->select_prev();
break;
case Event::Confirm:
std::cout << fmt::format("Selected mission {}\n",
missions_widget->get_selection());
break;
default:
throw std::runtime_error(fmt::format("Unknown event: {}", (int)e));
}
}
}

View File

@ -7,8 +7,19 @@
#include <SDL2/SDL_image.h>
#include <fmt/format.h>
#include <cstdint>
#include <stdexcept>
constexpr uint8_t LIST_SELECTION_BG_R = 0x77;
constexpr uint8_t LIST_SELECTION_BG_G = 0x33;
constexpr uint8_t LIST_SELECTION_BG_B = 0x33;
constexpr uint8_t LIST_OTHER_BG_R = 0x22;
constexpr uint8_t LIST_OTHER_BG_G = 0x22;
constexpr uint8_t LIST_OTHER_BG_B = 0x22;
constexpr uint8_t LIST_NORMAL_BG_R = 0x00;
constexpr uint8_t LIST_NORMAL_BG_G = 0x00;
constexpr uint8_t LIST_NORMAL_BG_B = 0x00;
PositionInfo::PositionInfo() : x{0}, y{0}, align{Alignment::LEFT} {}
Widget::Widget(SDL_Renderer* renderer) : renderer{renderer}, rect{0, 0, 0, 0} {}
@ -144,7 +155,7 @@ SDL_Texture* TextWidget::generate_text(const std::string& text) {
ListWidget::ListWidget(SDL_Renderer* renderer, int element_height,
Alignment element_alignment)
: Widget{renderer}, element_height{element_height},
element_alignment{element_alignment} {}
element_alignment{element_alignment}, selection{0} {}
ListWidget::~ListWidget() {}
@ -163,12 +174,19 @@ void ListWidget::draw() {
// Since the elements are sorted, we can stop the loop now.
break;
}
if (i % 2 == 1) {
SDL_SetRenderDrawColor(renderer, 0x11, 0x11, 0x11, 0xFF);
if (i == selection) {
SDL_SetRenderDrawColor(renderer, LIST_SELECTION_BG_R, LIST_SELECTION_BG_G,
LIST_SELECTION_BG_B, 0xFF);
} else if (i % 2 == 1) {
SDL_SetRenderDrawColor(renderer, LIST_OTHER_BG_R, LIST_OTHER_BG_G,
LIST_OTHER_BG_B, 0xFF);
} else {
SDL_SetRenderDrawColor(renderer, LIST_NORMAL_BG_R, LIST_NORMAL_BG_G,
LIST_NORMAL_BG_B, 0xFF);
}
SDL_Rect fill_rect = {
.x = pos.x, .y = element_pos.y, .w = rect.w, .h = element_height};
SDL_RenderFillRect(renderer, &fill_rect);
}
element->draw();
if (i != elements.size() - 1) {
int border_y = element_pos.y + element->get_height();
@ -178,6 +196,28 @@ void ListWidget::draw() {
}
}
void ListWidget::select_next() {
size_t n = elements.size();
if (n == 0) {
return;
}
selection = (selection + 1) % n;
}
void ListWidget::select_prev() {
size_t n = elements.size();
if (n == 0) {
return;
}
if (selection == 0) {
selection = n - 1;
} else {
selection = selection - 1;
}
}
size_t ListWidget::get_selection() { return selection; }
void ListWidget::place_element(Widget* element, int index) {
int x = rect.x;
switch (element_alignment) {