Compare commits
2 Commits
882a645926
...
2e76523bf4
Author | SHA1 | Date |
---|---|---|
Jasper Blanckenburg | 2e76523bf4 | |
Jasper Blanckenburg | 654c71f3ee |
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
enum class Event { Next, Prev, Confirm };
|
|
@ -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);
|
||||
|
|
39
src/App.cpp
39
src/App.cpp
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
SDL_Rect fill_rect = {
|
||||
.x = pos.x, .y = element_pos.y, .w = rect.w, .h = element_height};
|
||||
SDL_RenderFillRect(renderer, &fill_rect);
|
||||
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) {
|
||||
|
|
Loading…
Reference in New Issue