150 lines
4.5 KiB
C++
Raw Normal View History

2024-05-21 19:16:19 -04:00
#include <fstream>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/home/home.h>
#include <mods/touch/touch.h>
#include <mods/options/info.h>
2024-09-22 19:28:51 -04:00
#include <mods/misc/misc.h>
2024-05-21 19:16:19 -04:00
#include "title-screen-internal.h"
// Constants
2024-06-15 08:52:15 -04:00
static std::string line1 = "Welcome to " MCPI_APP_TITLE " v" MCPI_VERSION "!";
2024-09-22 19:28:51 -04:00
static constexpr int button_width = 120;
static constexpr int button_height = 24;
static constexpr int line_padding = 28;
static constexpr int button_padding = 4;
2024-05-21 19:16:19 -04:00
// Track Whether To Show Screen
static std::string get_tracker_file() {
return std::string(home_get()) + "/.welcome-tracker";
}
static bool should_show_welcome() {
// Open File
std::ifstream stream(get_tracker_file());
if (!stream) {
return true;
}
// Read Line
std::string line;
std::getline(stream, line);
2024-09-20 21:30:47 -04:00
const bool invalid = line != MCPI_VERSION;
2024-05-21 19:16:19 -04:00
// Close File
stream.close();
// Return
return invalid;
}
static void mark_welcome_as_shown() {
// Open File
std::ofstream stream(get_tracker_file());
if (!stream) {
return;
}
// Write
stream << MCPI_VERSION << std::endl;
// Close File
stream.close();
}
// Position GUI
static Button *getting_started;
static Button *changelog;
static Button *proceed;
static int text_y;
2024-09-20 21:30:47 -04:00
static void position_screen(const int width, const int height) {
2024-05-21 19:16:19 -04:00
// Width/Height
getting_started->width = changelog->width = proceed->width = button_width;
getting_started->height = changelog->height = proceed->height = button_height;
// X
proceed->x = (width / 2) - (button_width / 2);
getting_started->x = (width / 2) - button_padding - button_width;
changelog->x = (width / 2) + button_padding;
// Y
text_y = 0;
getting_started->y = changelog->y = line_height + line_padding;
proceed->y = getting_started->y + button_height + (button_padding * 2);
// Center
2024-09-20 21:30:47 -04:00
const int content_height = proceed->y + proceed->height;
const int y_offset = (height - content_height) / 2;
2024-05-21 19:16:19 -04:00
text_y += y_offset;
getting_started->y += y_offset;
changelog->y += y_offset;
proceed->y += y_offset;
}
// Welcome Screen
CUSTOM_VTABLE(welcome_screen, Screen) {
// Init
vtable->init = [](__attribute__((unused)) Screen *self) {
// Buttons
getting_started = touch_create_button(0, "Getting Started");
changelog = touch_create_button(1, "Changelog");
proceed = touch_create_button(2, "Proceed");
for (Button *button : {getting_started, changelog, proceed}) {
self->rendered_buttons.push_back(button);
self->selectable_buttons.push_back(button);
}
};
// Rendering
static Screen_render_t original_render = vtable->render;
2024-09-20 21:30:47 -04:00
vtable->render = [](Screen *self, const int x, const int y, const float param_1) {
2024-05-21 19:16:19 -04:00
// Background
self->renderBackground();
// Call Original Method
original_render(self, x, y, param_1);
// Text
2024-07-15 03:05:05 -04:00
self->drawCenteredString(self->font, line1, self->width / 2, text_y, 0xFFFFFFFF);
2024-05-21 19:16:19 -04:00
};
// Positioning
vtable->setupPositions = [](Screen *self) {
position_screen(self->width, self->height);
};
// Cleanup
vtable->removed = [](Screen *self) {
for (Button *button : self->rendered_buttons) {
button->destructor_deleting();
}
};
// Handle Button Click
vtable->buttonClicked = [](Screen *self, Button *button) {
if (button == getting_started) {
open_url(MCPI_DOCUMENTATION "GETTING_STARTED.md");
} else if (button == changelog) {
open_url(MCPI_DOCUMENTATION CHANGELOG_FILE);
} else if (button == proceed) {
mark_welcome_as_shown();
self->minecraft->screen_chooser.setScreen(1);
}
};
}
static Screen *create_welcome_screen() {
// Allocate
2024-09-20 21:30:47 -04:00
Screen *screen = Screen::allocate();
2024-05-21 19:16:19 -04:00
ALLOC_CHECK(screen);
screen->constructor();
// Set VTable
screen->vtable = get_welcome_screen_vtable();
// Return
return screen;
}
// Show Welcome Screen
static void NinecraftApp_init_ScreenChooser_setScreen_injection(ScreenChooser *self, int id) {
if (should_show_welcome()) {
// Show Welcome Screen
self->minecraft->setScreen(create_welcome_screen());
} else {
// Show Start Screen
self->setScreen(id);
}
}
// Init
void _init_welcome() {
// Hijack Start Screen
overwrite_call((void *) 0x14a34, (void *) NinecraftApp_init_ScreenChooser_setScreen_injection);
}