mirror of
https://github.com/vanilla-wiiu/vanilla.git
synced 2026-10-28 09:43:51 +00:00
various UI improvements and progress
This commit is contained in:
1 parent
7320fd7891
commit
9c5852606f
15 files changed
+1069
-317
No files matched your search
+2
-2
@@ -10,8 +10,8 @@ SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
set(CMAKE_C_STANDARD 23)
|
||||
|
||||
OPTION(VANILLA_BUILD_DESKTOP "Build Qt app for Linux desktop" ON)
|
||||
OPTION(VANILLA_BUILD_RPI "Build SDL2 app for Raspberry Pi" OFF)
|
||||
OPTION(VANILLA_BUILD_DESKTOP "Build Qt app for Linux desktop" OFF)
|
||||
OPTION(VANILLA_BUILD_RPI "Build SDL2 app for Raspberry Pi" ON)
|
||||
OPTION(VANILLA_BUILD_TESTS "Build unit tests for Vanilla" OFF)
|
||||
|
||||
add_subdirectory(lib)
|
||||
|
||||
@@ -6,7 +6,10 @@ add_executable(vanilla-pi
|
||||
drm.c
|
||||
main2.c
|
||||
menu/menu.c
|
||||
menu/menu_main.c
|
||||
menu/menu_sync.c
|
||||
ui/ui.c
|
||||
ui/ui_anim.c
|
||||
ui/ui_sdl2.c
|
||||
)
|
||||
|
||||
|
||||
+14
-87
@@ -1,4 +1,3 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "menu/menu.h"
|
||||
@@ -10,99 +9,27 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
// Initialize SDL
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER) < 0) {
|
||||
fprintf(stderr, "Failed to initialize SDL\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize VUI
|
||||
if (vui_init_sdl2()) {
|
||||
fprintf(stderr, "Failed to initialize VUI\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize UI system
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
|
||||
vui_context_t *vui = vui_alloc(SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
|
||||
SDL_Window *window = SDL_CreateWindow("vanilla", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_RESIZABLE);
|
||||
|
||||
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
|
||||
SDL_Texture *maintex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
|
||||
int running = 1;
|
||||
|
||||
vui_context_t *vui = vui_alloc();
|
||||
// Initialize SDL2
|
||||
int ret = 1;
|
||||
if (vui_init_sdl2(vui)) {
|
||||
fprintf(stderr, "Failed to initialize VUI\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
vanilla_menu_init(vui);
|
||||
|
||||
SDL_Rect dst_rect = {0};
|
||||
|
||||
while (running) {
|
||||
SDL_Event ev;
|
||||
while (SDL_PollEvent(&ev)) {
|
||||
if (ev.type == SDL_QUIT) {
|
||||
running = 0;
|
||||
goto exit_loop;
|
||||
} else if (ev.type == SDL_MOUSEBUTTONDOWN) {
|
||||
if (dst_rect.w > 0 && dst_rect.h > 0) {
|
||||
int tr_x, tr_y;
|
||||
tr_x = (ev.button.x - dst_rect.x) * SCREEN_WIDTH / dst_rect.w;
|
||||
tr_y = (ev.button.y - dst_rect.y) * SCREEN_HEIGHT / dst_rect.h;
|
||||
vui_process_click(vui, tr_x, tr_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vui_update(vui);
|
||||
|
||||
// Draw vui to a custom texture
|
||||
SDL_SetRenderTarget(renderer, maintex);
|
||||
vui_draw_sdl2(vui, renderer);
|
||||
|
||||
// Calculate our destination rectangle
|
||||
int win_w, win_h;
|
||||
SDL_GetWindowSize(window, &win_w, &win_h);
|
||||
if (win_w == SCREEN_WIDTH && win_h == SCREEN_HEIGHT) {
|
||||
dst_rect.x = 0;
|
||||
dst_rect.y = 0;
|
||||
dst_rect.w = SCREEN_WIDTH;
|
||||
dst_rect.h = SCREEN_HEIGHT;
|
||||
} else if (win_w * 100 / win_h > SCREEN_WIDTH * 100 / SCREEN_HEIGHT) {
|
||||
// Window is wider than texture, scale by height
|
||||
dst_rect.h = win_h;
|
||||
dst_rect.y = 0;
|
||||
dst_rect.w = win_h * SCREEN_WIDTH / SCREEN_HEIGHT;
|
||||
dst_rect.x = win_w / 2 - dst_rect.w / 2;
|
||||
} else {
|
||||
// Window is taller than texture, scale by width
|
||||
dst_rect.w = win_w;
|
||||
dst_rect.x = 0;
|
||||
dst_rect.h = win_w * SCREEN_HEIGHT / SCREEN_WIDTH;
|
||||
dst_rect.y = win_h / 2 - dst_rect.h / 2;
|
||||
}
|
||||
|
||||
// Copy texture to window
|
||||
SDL_SetRenderTarget(renderer, NULL);
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderCopy(renderer, maintex, NULL, &dst_rect);
|
||||
|
||||
// Flip surfaces
|
||||
SDL_RenderPresent(renderer);
|
||||
while (vui_update_sdl2(vui)) {
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit:
|
||||
vui_close_sdl2(vui);
|
||||
|
||||
vui_free(vui);
|
||||
|
||||
exit_loop:
|
||||
SDL_DestroyRenderer(renderer);
|
||||
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
vui_close_sdl2();
|
||||
|
||||
SDL_Quit();
|
||||
return ret;
|
||||
}
|
||||
+2
-106
@@ -4,114 +4,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
int btn;
|
||||
int ox;
|
||||
int oy;
|
||||
int ow;
|
||||
int oh;
|
||||
} vanilla_btn_anim_data_t;
|
||||
|
||||
static vanilla_btn_anim_data_t button_anim_data;
|
||||
|
||||
#define BUTTON_CLICK_ANIM_LENGTH 150000
|
||||
#define FADE_ANIM_LENGTH 250000
|
||||
|
||||
void button_click_animation_step(vui_context_t *ctx, int64_t time, void *v)
|
||||
{
|
||||
vanilla_btn_anim_data_t *a = (vanilla_btn_anim_data_t *) v;
|
||||
|
||||
float y = sin(time / (float) BUTTON_CLICK_ANIM_LENGTH * M_PI);
|
||||
|
||||
y *= 0.2f; // Range will be 0.0 - 0.1
|
||||
|
||||
int new_w = a->ow * (1.0f - y);
|
||||
int new_h = a->oh * (1.0f - y);
|
||||
|
||||
vui_button_update_geometry(
|
||||
ctx,
|
||||
a->btn,
|
||||
a->ox + a->ow/2 - new_w/2,
|
||||
a->oy + a->oh/2 - new_h/2,
|
||||
new_w,
|
||||
new_h
|
||||
);
|
||||
}
|
||||
|
||||
void fade_to_black_step(vui_context_t *vui, int64_t time, void *v)
|
||||
{
|
||||
vui_set_overlay_color(vui, 1, 0, 0, 0, time / (float) FADE_ANIM_LENGTH);
|
||||
}
|
||||
|
||||
void fade_from_black_step(vui_context_t *vui, int64_t time, void *v)
|
||||
{
|
||||
vui_set_overlay_color(vui, 1, 0, 0, 0, (FADE_ANIM_LENGTH - time) / (float) FADE_ANIM_LENGTH);
|
||||
}
|
||||
|
||||
void vanilla_menu_sync(vui_context_t *vui, void *d)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
vui_button_create(vui, 640, 360, 100, 100, "Back", VUI_BUTTON_STYLE_BUTTON, NULL, NULL);
|
||||
|
||||
vui_start_animation(vui, FADE_ANIM_LENGTH, fade_from_black_step, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void vanilla_default_button_action(vui_context_t *vui, int button, void *v)
|
||||
{
|
||||
vanilla_btn_anim_data_t *a = &button_anim_data;
|
||||
|
||||
a->btn = button;
|
||||
vui_button_get_geometry(vui, button, &a->ox, &a->oy, &a->ow, &a->oh);
|
||||
|
||||
vui_start_animation(vui, BUTTON_CLICK_ANIM_LENGTH, button_click_animation_step, a, (vui_callback_t) v, NULL);
|
||||
}
|
||||
|
||||
void vanilla_menu_main_sync_action(vui_context_t *vui, void *v)
|
||||
{
|
||||
vui_start_animation(vui, FADE_ANIM_LENGTH, fade_to_black_step, NULL, vanilla_menu_sync, NULL);
|
||||
}
|
||||
|
||||
void vanilla_menu_main(vui_context_t *vui)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
const int SCREEN_WIDTH = 854;
|
||||
const int SCREEN_HEIGHT = 480;
|
||||
const int BTN_SZ = 80;
|
||||
|
||||
int arrow_y = SCREEN_HEIGHT / 2 - BTN_SZ / 2;
|
||||
|
||||
// Left arrow
|
||||
vui_button_create(vui, 0, arrow_y, BTN_SZ, BTN_SZ, "<", VUI_BUTTON_STYLE_BUTTON, vanilla_default_button_action, NULL);
|
||||
|
||||
// Right arrow
|
||||
vui_button_create(vui, SCREEN_WIDTH-BTN_SZ, arrow_y, BTN_SZ, BTN_SZ, ">", VUI_BUTTON_STYLE_BUTTON, vanilla_default_button_action, NULL);
|
||||
|
||||
// Sync button
|
||||
vui_button_create(vui, BTN_SZ, SCREEN_HEIGHT-BTN_SZ, (SCREEN_WIDTH-BTN_SZ*2)/2, BTN_SZ, "Sync", VUI_BUTTON_STYLE_BUTTON, vanilla_default_button_action, vanilla_menu_main_sync_action);
|
||||
|
||||
// Connect button
|
||||
vui_button_create(vui, BTN_SZ + (SCREEN_WIDTH-BTN_SZ*2)/2, SCREEN_HEIGHT-BTN_SZ, (SCREEN_WIDTH-BTN_SZ*2)/2, BTN_SZ, "Connect", VUI_BUTTON_STYLE_BUTTON, vanilla_default_button_action, NULL);
|
||||
|
||||
// Delete button
|
||||
vui_button_create(vui, 0, 0, BTN_SZ, BTN_SZ, "Delete", VUI_BUTTON_STYLE_CORNER, vanilla_default_button_action, NULL);
|
||||
vui_button_create(vui, SCREEN_WIDTH-BTN_SZ, 0, BTN_SZ, BTN_SZ, "Settings", VUI_BUTTON_STYLE_CORNER, vanilla_default_button_action, NULL);
|
||||
|
||||
// Console list
|
||||
int list_item_width = SCREEN_WIDTH - BTN_SZ - BTN_SZ;
|
||||
int list_item_height = (SCREEN_HEIGHT - BTN_SZ - BTN_SZ) / 4;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "Wii U %i", i + 1);
|
||||
vui_button_create(vui, BTN_SZ, BTN_SZ + list_item_height * i, list_item_width, list_item_height, buf, VUI_BUTTON_STYLE_LIST, NULL, NULL);
|
||||
}
|
||||
|
||||
vui_start_animation(vui, FADE_ANIM_LENGTH, fade_from_black_step, NULL, NULL, NULL);
|
||||
}
|
||||
#include "menu_main.h"
|
||||
|
||||
void vanilla_menu_init(vui_context_t *vui)
|
||||
{
|
||||
// Start with main menu
|
||||
vanilla_menu_main(vui);
|
||||
vanilla_menu_main(vui, 0);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "menu_main.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "menu_sync.h"
|
||||
#include "ui/ui_anim.h"
|
||||
|
||||
#define MAIN_MENU_ENTRIES 3
|
||||
#define BTN_SZ 80
|
||||
|
||||
static int main_menu_btns[MAIN_MENU_ENTRIES] = {0};
|
||||
|
||||
static int main_menu_first_run = 1;
|
||||
static int main_menu_current = 0;
|
||||
|
||||
static int console_menu_layer = 0;
|
||||
|
||||
void vanilla_menu_main_sync_action(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
vui_transition_fade_layer_out(vui, (int) (intptr_t) v, vanilla_menu_sync, 0);
|
||||
}
|
||||
|
||||
void vanilla_menu_main_populate(vui_context_t *vui)
|
||||
{
|
||||
for (int i = 0; i < MAIN_MENU_ENTRIES; i++) {
|
||||
int b = main_menu_btns[i];
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "Wii U %i", main_menu_current + i + 1);
|
||||
vui_button_update_text(vui, b, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void vanilla_menu_main_finish_transition(vui_context_t *vui, void *v)
|
||||
{
|
||||
intptr_t data = (intptr_t) v;
|
||||
|
||||
int layer = data & 0xFF;
|
||||
int target = data >> 8;
|
||||
|
||||
main_menu_current = target;
|
||||
|
||||
vanilla_menu_main_populate(vui);
|
||||
|
||||
vui_transition_fade_layer_in(vui, layer, 0, 0);
|
||||
}
|
||||
|
||||
void vanilla_menu_main_start_transition(vui_context_t *vui, int layer, int to)
|
||||
{
|
||||
if (to < 0) {
|
||||
// Can't go into negatives
|
||||
return;
|
||||
}
|
||||
|
||||
vui_transition_fade_layer_out(vui, layer, vanilla_menu_main_finish_transition, (void *) (intptr_t) (layer | to << 8));
|
||||
}
|
||||
|
||||
void vanilla_menu_main_left_arrow(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
vanilla_menu_main_start_transition(vui, (intptr_t) v, main_menu_current - MAIN_MENU_ENTRIES);
|
||||
}
|
||||
|
||||
void vanilla_menu_main_right_arrow(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
vanilla_menu_main_start_transition(vui, (intptr_t) v, main_menu_current + MAIN_MENU_ENTRIES);
|
||||
}
|
||||
|
||||
void vanilla_menu_main(vui_context_t *vui, void *v)
|
||||
{
|
||||
vui_reset(vui);
|
||||
|
||||
int SCREEN_WIDTH, SCREEN_HEIGHT;
|
||||
vui_get_screen_size(vui, &SCREEN_WIDTH, &SCREEN_HEIGHT);
|
||||
|
||||
int arrow_y = SCREEN_HEIGHT / 2 - BTN_SZ / 2;
|
||||
|
||||
// Layer
|
||||
int layer = vui_layer_create(vui);
|
||||
console_menu_layer = vui_layer_create(vui);
|
||||
|
||||
// Left arrow
|
||||
vui_button_create(vui, 0, arrow_y, BTN_SZ, BTN_SZ, "<", VUI_BUTTON_STYLE_BUTTON, layer, vanilla_menu_main_left_arrow, (void *) (intptr_t) console_menu_layer);
|
||||
|
||||
// Right arrow
|
||||
vui_button_create(vui, SCREEN_WIDTH-BTN_SZ, arrow_y, BTN_SZ, BTN_SZ, ">", VUI_BUTTON_STYLE_BUTTON, layer, vanilla_menu_main_right_arrow, (void *) (intptr_t) console_menu_layer);
|
||||
|
||||
// Sync button
|
||||
vui_button_create(vui, BTN_SZ, SCREEN_HEIGHT-BTN_SZ, (SCREEN_WIDTH-BTN_SZ*2)/2, BTN_SZ, "Sync", VUI_BUTTON_STYLE_BUTTON, layer, vanilla_menu_main_sync_action, (void *) (intptr_t) layer);
|
||||
|
||||
// Connect button
|
||||
vui_button_create(vui, BTN_SZ + (SCREEN_WIDTH-BTN_SZ*2)/2, SCREEN_HEIGHT-BTN_SZ, (SCREEN_WIDTH-BTN_SZ*2)/2, BTN_SZ, "Connect", VUI_BUTTON_STYLE_BUTTON, layer, NULL, NULL);
|
||||
|
||||
// Delete button
|
||||
vui_button_create(vui, 0, 0, BTN_SZ, BTN_SZ, "Edit", VUI_BUTTON_STYLE_CORNER, layer, NULL, NULL);
|
||||
vui_button_create(vui, SCREEN_WIDTH-BTN_SZ, 0, BTN_SZ, BTN_SZ, "Settings", VUI_BUTTON_STYLE_CORNER, layer, NULL, NULL);
|
||||
|
||||
// Console list
|
||||
int list_item_width = SCREEN_WIDTH - BTN_SZ - BTN_SZ;
|
||||
int list_item_height = (SCREEN_HEIGHT - BTN_SZ - BTN_SZ) / MAIN_MENU_ENTRIES;
|
||||
for (int i = 0; i < MAIN_MENU_ENTRIES; i++) {
|
||||
main_menu_btns[i] = vui_button_create(vui, BTN_SZ, BTN_SZ + list_item_height * i, list_item_width, list_item_height, NULL, VUI_BUTTON_STYLE_LIST, console_menu_layer, NULL, NULL);
|
||||
}
|
||||
vanilla_menu_main_populate(vui);
|
||||
|
||||
if (main_menu_first_run) {
|
||||
vui_transition_fade_black_out(vui, NULL, NULL);
|
||||
main_menu_first_run = 0;
|
||||
} else {
|
||||
vui_transition_fade_layer_in(vui, layer, NULL, NULL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef VANILLA_PI_MENU_MAIN_H
|
||||
#define VANILLA_PI_MENU_MAIN_H
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
void vanilla_menu_main(vui_context_t *vui, void *v);
|
||||
|
||||
#endif // VANILLA_PI_MENU_MAIN_H
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "menu_sync.h"
|
||||
|
||||
#include "menu_main.h"
|
||||
#include "ui/ui_anim.h"
|
||||
|
||||
void vanilla_sync_menu_back_action(vui_context_t *vui, int btn, void *v)
|
||||
{
|
||||
vui_transition_fade_layer_out(vui, (int) (intptr_t) v, vanilla_menu_main, 0);
|
||||
}
|
||||
|
||||
void vanilla_menu_sync(vui_context_t *vui, void *d)
|
||||
{
|
||||
// Clears all extra layers
|
||||
vui_reset(vui);
|
||||
|
||||
// int bglayer = vui_layer_create(vui);
|
||||
int layer = vui_layer_create(vui);
|
||||
|
||||
int scrw, scrh;
|
||||
vui_get_screen_size(vui, &scrw, &scrh);
|
||||
|
||||
const int margin = scrw/75;
|
||||
vui_rect_t bkg_rect;
|
||||
bkg_rect.x = margin;
|
||||
bkg_rect.y = margin;
|
||||
bkg_rect.w = scrw-margin-margin;
|
||||
bkg_rect.h = scrh-margin-margin;
|
||||
|
||||
vui_rect_create(vui, bkg_rect.x, bkg_rect.y, bkg_rect.w, bkg_rect.h, scrh*2/10, vui_color_create(0, 0, 0, 0.66f), layer);
|
||||
|
||||
const int lbl_margin = margin * 3;
|
||||
vui_label_create(vui, bkg_rect.x + lbl_margin, bkg_rect.y + lbl_margin, bkg_rect.w - lbl_margin - lbl_margin, bkg_rect.h - lbl_margin - lbl_margin, "Touch the symbols in the order they are displayed on the TV screen from left to right.", vui_color_create(1,1,1,1), layer);
|
||||
|
||||
int back_btn_h = scrh/6;
|
||||
vui_button_create(vui, 0, scrh-back_btn_h, scrw/4, back_btn_h, "Cancel", VUI_BUTTON_STYLE_CORNER, layer, vanilla_sync_menu_back_action, (void *) (intptr_t) layer);
|
||||
|
||||
vui_transition_fade_layer_in(vui, layer, 0, 0);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef VANILLA_PI_MENU_SYNC_H
|
||||
#define VANILLA_PI_MENU_SYNC_H
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
void vanilla_menu_sync(vui_context_t *vui, void *d);
|
||||
|
||||
#endif // VANILLA_PI_MENU_SYNC_H
|
||||
+220
-39
@@ -4,11 +4,17 @@
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "ui_anim.h"
|
||||
#include "ui_priv.h"
|
||||
|
||||
vui_context_t *vui_alloc()
|
||||
vui_context_t *vui_alloc(int width, int height)
|
||||
{
|
||||
return malloc(sizeof(vui_context_t));
|
||||
vui_context_t *vui = malloc(sizeof(vui_context_t));
|
||||
vui_reset(vui);
|
||||
vui->platform_data = 0;
|
||||
vui->screen_width = width;
|
||||
vui->screen_height = height;
|
||||
return vui;
|
||||
}
|
||||
|
||||
void vui_free(vui_context_t *vui)
|
||||
@@ -20,11 +26,21 @@ void vui_free(vui_context_t *vui)
|
||||
int vui_reset(vui_context_t *ctx)
|
||||
{
|
||||
ctx->button_count = 0;
|
||||
ctx->label_count = 0;
|
||||
ctx->rect_count = 0;
|
||||
ctx->animation_enabled = 0;
|
||||
ctx->overlay_enabled = 0;
|
||||
ctx->button_active = -1;
|
||||
ctx->layers = 1;
|
||||
ctx->layer_opacity[0] = 1;
|
||||
}
|
||||
|
||||
int vui_button_create(vui_context_t *ctx, int x, int y, int w, int h, const char *text, vui_button_style style, vui_button_callback_t onclick, void *onclick_data)
|
||||
void vui_get_screen_size(vui_context_t *ctx, int *width, int *height)
|
||||
{
|
||||
if (width) *width = ctx->screen_width;
|
||||
if (height) *height = ctx->screen_height;
|
||||
}
|
||||
|
||||
int vui_button_create(vui_context_t *ctx, int x, int y, int w, int h, const char *text, vui_button_style style, int layer, vui_button_callback_t callback, void *callback_data)
|
||||
{
|
||||
if (ctx->button_count == MAX_BUTTON_COUNT) {
|
||||
return -1;
|
||||
@@ -32,47 +48,70 @@ int vui_button_create(vui_context_t *ctx, int x, int y, int w, int h, const char
|
||||
|
||||
int index = ctx->button_count;
|
||||
|
||||
vui_button_update_geometry(ctx, index, x, y, w, h);
|
||||
vui_button_t *btn = &ctx->buttons[index];
|
||||
|
||||
btn->layer = layer;
|
||||
|
||||
// Inset rect by dividing by 1.1
|
||||
btn->x = x;
|
||||
btn->y = y;
|
||||
btn->w = w;
|
||||
btn->h = h;
|
||||
|
||||
int new_w = w * 10 / 11;
|
||||
int new_h = h * 10 / 11;
|
||||
int new_x = x + w / 2 - new_w / 2;
|
||||
int new_y = y + h / 2 - new_h / 2;
|
||||
|
||||
vui_button_update_geometry(ctx, index, new_x, new_y, new_w, new_h);
|
||||
vui_button_update_text(ctx, index, text);
|
||||
vui_button_update_onclick(ctx, index, onclick, onclick_data);
|
||||
vui_button_update_style(ctx, index, style);
|
||||
vui_button_update_click_handler(ctx, index, callback, callback_data);
|
||||
|
||||
ctx->button_count++;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void vui_button_update_click_handler(vui_context_t *ctx, int index, vui_button_callback_t handler, void *userdata)
|
||||
{
|
||||
vui_button_t *btn = &ctx->buttons[index];
|
||||
btn->onclick = handler;
|
||||
btn->onclick_data = userdata;
|
||||
}
|
||||
|
||||
void vui_button_get_geometry(vui_context_t *ctx, int index, int *x, int *y, int *w, int *h)
|
||||
{
|
||||
vui_button_t *btn = &ctx->buttons[index];
|
||||
*x = btn->x;
|
||||
*y = btn->y;
|
||||
*w = btn->w;
|
||||
*h = btn->h;
|
||||
*x = btn->sx;
|
||||
*y = btn->sy;
|
||||
*w = btn->sw;
|
||||
*h = btn->sh;
|
||||
}
|
||||
|
||||
void vui_button_update_geometry(vui_context_t *ctx, int index, int x, int y, int w, int h)
|
||||
{
|
||||
vui_button_t *btn = &ctx->buttons[index];
|
||||
btn->x = x;
|
||||
btn->y = y;
|
||||
btn->w = w;
|
||||
btn->h = h;
|
||||
btn->sx = x;
|
||||
btn->sy = y;
|
||||
btn->sw = w;
|
||||
btn->sh = h;
|
||||
}
|
||||
|
||||
void vui_strcpy(char *dst, const char *src)
|
||||
{
|
||||
if (src)
|
||||
strncpy(dst, src, MAX_BUTTON_TEXT);
|
||||
else
|
||||
dst[0] = 0;
|
||||
dst[MAX_BUTTON_TEXT-1] = 0;
|
||||
}
|
||||
|
||||
void vui_button_update_text(vui_context_t *ctx, int index, const char *text)
|
||||
{
|
||||
// Copy text (enforce null terminator)
|
||||
vui_button_t *btn = &ctx->buttons[index];
|
||||
strncpy(btn->text, text, MAX_BUTTON_TEXT);
|
||||
btn->text[MAX_BUTTON_TEXT-1] = 0;
|
||||
}
|
||||
|
||||
void vui_button_update_onclick(vui_context_t *ctx, int index, vui_button_callback_t onclick, void *onclick_data)
|
||||
{
|
||||
vui_button_t *btn = &ctx->buttons[index];
|
||||
btn->onclick = onclick;
|
||||
btn->onclick_data = onclick_data;
|
||||
vui_strcpy(btn->text, text);
|
||||
}
|
||||
|
||||
void vui_button_update_style(vui_context_t *ctx, int index, vui_button_style style)
|
||||
@@ -81,9 +120,18 @@ void vui_button_update_style(vui_context_t *ctx, int index, vui_button_style sty
|
||||
btn->style = style;
|
||||
}
|
||||
|
||||
void vui_process_click(vui_context_t *ctx, int x, int y)
|
||||
int point_inside_button(vui_button_t *btn, int x, int y)
|
||||
{
|
||||
// Don't process any inputs while an animation is playing
|
||||
return x >= btn->x && y >= btn->y && x < btn->x + btn->w && y < btn->y + btn->h;
|
||||
}
|
||||
|
||||
void vui_process_mousedown(vui_context_t *ctx, int x, int y)
|
||||
{
|
||||
if (ctx->button_active != -1) {
|
||||
// Button already mousedown'd, ignore this
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->animation_enabled) {
|
||||
return;
|
||||
}
|
||||
@@ -91,21 +139,61 @@ void vui_process_click(vui_context_t *ctx, int x, int y)
|
||||
for (int i = 0; i < ctx->button_count; i++) {
|
||||
vui_button_t *btn = &ctx->buttons[i];
|
||||
|
||||
if (x >= btn->x && y >= btn->y && x < btn->x + btn->w && y < btn->y + btn->h) {
|
||||
if (btn->onclick) {
|
||||
btn->onclick(ctx, i, btn->onclick_data);
|
||||
}
|
||||
if (point_inside_button(btn, x, y)) {
|
||||
vui_animation_button_mousedown(ctx, i, 0, 0);
|
||||
ctx->button_active = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vui_button_callback(vui_context_t *ctx, void *data)
|
||||
{
|
||||
int index = (int) (intptr_t) data;
|
||||
vui_button_t *btn = &ctx->buttons[index];
|
||||
if (btn->onclick) {
|
||||
btn->onclick(ctx, ctx->button_active, btn->onclick_data);
|
||||
}
|
||||
}
|
||||
|
||||
void vui_process_mouseup(vui_context_t *ctx, int x, int y)
|
||||
{
|
||||
if (ctx->button_active == -1) {
|
||||
// No button was mousedown'd, do nothing here
|
||||
return;
|
||||
}
|
||||
|
||||
vui_button_t *btn = &ctx->buttons[ctx->button_active];
|
||||
|
||||
// Only do action if mouse is still inside button's rect
|
||||
vui_callback_t callback = 0;
|
||||
void *callback_data = 0;
|
||||
if (point_inside_button(btn, x, y)) {
|
||||
callback = vui_button_callback;
|
||||
callback_data = (void *) (intptr_t) ctx->button_active;
|
||||
}
|
||||
|
||||
vui_animation_button_mouseup(ctx, ctx->button_active, callback, callback_data);
|
||||
|
||||
ctx->button_active = -1;
|
||||
}
|
||||
|
||||
void vui_cancel_animation(vui_context_t *ctx)
|
||||
{
|
||||
if (ctx->animation_enabled) {
|
||||
// Finish current animation immediately before starting next one
|
||||
if (ctx->animation.step) {
|
||||
ctx->animation.step(ctx, ctx->animation.length, ctx->animation.step_data);
|
||||
}
|
||||
if (ctx->animation.complete) {
|
||||
ctx->animation.complete(ctx, ctx->animation.complete_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vui_start_animation(vui_context_t *ctx, int64_t length, vui_anim_step_callback_t step, void *step_data, vui_callback_t complete, void *complete_data)
|
||||
{
|
||||
// Prevent second animation from starting while another is active
|
||||
if (ctx->animation_enabled) {
|
||||
return;
|
||||
}
|
||||
vui_cancel_animation(ctx);
|
||||
|
||||
ctx->animation_enabled = 1;
|
||||
ctx->animation.progress = 0;
|
||||
@@ -143,11 +231,104 @@ void vui_update(vui_context_t *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
void vui_set_overlay_color(vui_context_t *vui, int enabled, float r, float g, float b, float a)
|
||||
int vui_layer_create(vui_context_t *ctx)
|
||||
{
|
||||
vui->overlay_enabled = enabled;
|
||||
vui->overlay_r = r;
|
||||
vui->overlay_g = g;
|
||||
vui->overlay_b = b;
|
||||
vui->overlay_a = a;
|
||||
int cur_layer = ctx->layers;
|
||||
if (cur_layer == MAX_BUTTON_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->layers++;
|
||||
|
||||
// Set layer defaults
|
||||
ctx->layer_opacity[cur_layer] = 1.0f;
|
||||
|
||||
vui_color_t *layerbg = &ctx->layer_color[cur_layer];
|
||||
layerbg->r = 0;
|
||||
layerbg->g = 0;
|
||||
layerbg->b = 0;
|
||||
layerbg->a = 0;
|
||||
|
||||
return cur_layer;
|
||||
}
|
||||
|
||||
int vui_layer_destroy(vui_context_t *ctx)
|
||||
{
|
||||
int cur_layer = ctx->layers;
|
||||
if (cur_layer == 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->layers--;
|
||||
|
||||
return cur_layer;
|
||||
}
|
||||
|
||||
void vui_layer_set_opacity(vui_context_t *ctx, int layer, float opacity)
|
||||
{
|
||||
ctx->layer_opacity[layer] = opacity;
|
||||
}
|
||||
|
||||
vui_color_t vui_color_create(float r, float g, float b, float a)
|
||||
{
|
||||
vui_color_t c;
|
||||
c.r = r;
|
||||
c.g = g;
|
||||
c.b = b;
|
||||
c.a = a;
|
||||
return c;
|
||||
}
|
||||
|
||||
void vui_layer_set_bgcolor(vui_context_t *ctx, int layer, vui_color_t color)
|
||||
{
|
||||
ctx->layer_color[layer] = color;
|
||||
}
|
||||
|
||||
int vui_label_create(vui_context_t *ctx, int x, int y, int w, int h, const char *text, vui_color_t color, int layer)
|
||||
{
|
||||
if (ctx->label_count == MAX_BUTTON_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index = ctx->label_count;
|
||||
|
||||
vui_label_t *lbl = &ctx->labels[index];
|
||||
|
||||
lbl->x = x;
|
||||
lbl->y = y;
|
||||
lbl->w = w;
|
||||
lbl->h = h;
|
||||
|
||||
lbl->color = color;
|
||||
|
||||
lbl->layer = layer;
|
||||
vui_strcpy(lbl->text, text);
|
||||
|
||||
ctx->label_count++;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int vui_rect_create(vui_context_t *ctx, int x, int y, int w, int h, int border_radius, vui_color_t color, int layer)
|
||||
{
|
||||
if (ctx->rect_count == MAX_BUTTON_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index = ctx->rect_count;
|
||||
|
||||
vui_rect_priv_t *rect = &ctx->rects[index];
|
||||
|
||||
rect->x = x;
|
||||
rect->y = y;
|
||||
rect->w = w;
|
||||
rect->h = h;
|
||||
|
||||
rect->layer = layer;
|
||||
rect->color = color;
|
||||
rect->border_radius = border_radius;
|
||||
|
||||
ctx->rect_count++;
|
||||
|
||||
return index;
|
||||
}
|
||||
+48
-9
@@ -10,6 +10,20 @@ typedef enum {
|
||||
VUI_BUTTON_STYLE_LIST
|
||||
} vui_button_style;
|
||||
|
||||
typedef struct {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
} vui_color_t;
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
} vui_rect_t;
|
||||
|
||||
typedef struct vui_context_t vui_context_t;
|
||||
|
||||
typedef void (*vui_callback_t)(vui_context_t *ctx, void *userdata);
|
||||
@@ -19,34 +33,59 @@ typedef void (*vui_anim_step_callback_t)(vui_context_t *ctx, int64_t time, void
|
||||
/**
|
||||
* Context-related functions
|
||||
*/
|
||||
vui_context_t *vui_alloc();
|
||||
vui_context_t *vui_alloc(int width, int height);
|
||||
int vui_reset(vui_context_t *ctx);
|
||||
void vui_free(vui_context_t *ctx);
|
||||
void vui_update(vui_context_t *ctx);
|
||||
|
||||
/**
|
||||
* Screen-related functions
|
||||
*/
|
||||
void vui_get_screen_size(vui_context_t *ctx, int *width, int *height);
|
||||
|
||||
/**
|
||||
* Layer-related functions
|
||||
*/
|
||||
int vui_layer_create(vui_context_t *ctx);
|
||||
void vui_layer_set_opacity(vui_context_t *ctx, int layer, float opacity);
|
||||
void vui_layer_set_bgcolor(vui_context_t *ctx, int layer, vui_color_t color);
|
||||
int vui_layer_destroy(vui_context_t *ctx);
|
||||
|
||||
/**
|
||||
* Button-related functions
|
||||
*/
|
||||
int vui_button_create(vui_context_t *ctx, int x, int y, int w, int h, const char *text, vui_button_style style, vui_button_callback_t onclick, void *onclick_data);
|
||||
int vui_button_create(vui_context_t *ctx, int x, int y, int w, int h, const char *text, vui_button_style style, int layer, vui_button_callback_t callback, void *callback_data);
|
||||
void vui_button_get_geometry(vui_context_t *ctx, int button, int *x, int *y, int *w, int *h);
|
||||
void vui_button_update_click_handler(vui_context_t *ctx, int index, vui_button_callback_t handler, void *userdata);
|
||||
void vui_button_update_geometry(vui_context_t *ctx, int button, int x, int y, int w, int h);
|
||||
void vui_button_update_text(vui_context_t *ctx, int button, const char *text);
|
||||
void vui_button_update_onclick(vui_context_t *ctx, int button, vui_button_callback_t onclick, void *onclick_data);
|
||||
void vui_button_update_style(vui_context_t *ctx, int button, vui_button_style style);
|
||||
|
||||
/**
|
||||
* Label-related functions
|
||||
*/
|
||||
int vui_label_create(vui_context_t *ctx, int x, int y, int w, int h, const char *text, vui_color_t color, int layer);
|
||||
|
||||
/**
|
||||
* Rect-related functions
|
||||
*/
|
||||
int vui_rect_create(vui_context_t *ctx, int x, int y, int w, int h, int border_radius, vui_color_t color, int layer);
|
||||
|
||||
/**
|
||||
* Color-related functions
|
||||
*/
|
||||
vui_color_t vui_color_create(float r, float g, float b, float a);
|
||||
|
||||
/**
|
||||
* Animation-related functions
|
||||
*/
|
||||
void vui_start_animation(vui_context_t *ctx, int64_t length, vui_anim_step_callback_t step, void *step_data, vui_callback_t complete, void *complete_data);
|
||||
void vui_cancel_animation(vui_context_t *ctx);
|
||||
|
||||
/**
|
||||
* Input-related functions
|
||||
*/
|
||||
void vui_process_click(vui_context_t *ctx, int x, int y);
|
||||
|
||||
/**
|
||||
* Miscellaneous functions
|
||||
*/
|
||||
void vui_set_overlay_color(vui_context_t *vui, int enabled, float r, float g, float b, float a);
|
||||
void vui_process_mousedown(vui_context_t *ctx, int x, int y);
|
||||
void vui_process_mouseup(vui_context_t *ctx, int x, int y);
|
||||
|
||||
#endif // VANILLA_PI_UI_H
|
||||
@@ -0,0 +1,150 @@
|
||||
#include "ui.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
int btn;
|
||||
int ox;
|
||||
int oy;
|
||||
int ow;
|
||||
int oh;
|
||||
} vui_btn_anim_data_t;
|
||||
static vui_btn_anim_data_t current_button_anim;
|
||||
|
||||
typedef struct {
|
||||
int pop_layer;
|
||||
vui_callback_t callback;
|
||||
void *callback_data;
|
||||
} vui_anim_callback_t;
|
||||
|
||||
#define BUTTON_MOUSEDOWN_ANIM_LENGTH 50000
|
||||
#define BUTTON_MOUSEUP_ANIM_LENGTH 133333
|
||||
#define FADE_ANIM_LENGTH 250000
|
||||
|
||||
void button_mousedown_animation_step(vui_context_t *ctx, int64_t time, void *v)
|
||||
{
|
||||
vui_btn_anim_data_t *a = (vui_btn_anim_data_t *) v;
|
||||
|
||||
// Create a multiplier that goes from 1.0 to 1.1
|
||||
float x = time / (float) BUTTON_MOUSEDOWN_ANIM_LENGTH;
|
||||
float y = x * 0.1f + 1.0f;
|
||||
|
||||
int new_w = a->ow * y;
|
||||
int new_h = a->oh * y;
|
||||
|
||||
vui_button_update_geometry(
|
||||
ctx,
|
||||
a->btn,
|
||||
a->ox + a->ow/2 - new_w/2,
|
||||
a->oy + a->oh/2 - new_h/2,
|
||||
new_w,
|
||||
new_h
|
||||
);
|
||||
}
|
||||
|
||||
void button_mouseup_animation_step(vui_context_t *ctx, int64_t time, void *v)
|
||||
{
|
||||
vui_btn_anim_data_t *a = (vui_btn_anim_data_t *) v;
|
||||
|
||||
// Create a multiplier that goes from 1.0 to 1.1
|
||||
float x = time / (float) BUTTON_MOUSEUP_ANIM_LENGTH;
|
||||
float y = powf(2 * x - 1, 2);
|
||||
|
||||
// 1.1 -> 0.98 -> 1.0
|
||||
|
||||
if (time < BUTTON_MOUSEUP_ANIM_LENGTH/2) {
|
||||
y = y * 0.12f + 0.98f;
|
||||
} else {
|
||||
y = y * 0.02f + 0.98f;
|
||||
}
|
||||
|
||||
int new_w = a->ow * y;
|
||||
int new_h = a->oh * y;
|
||||
|
||||
vui_button_update_geometry(
|
||||
ctx,
|
||||
a->btn,
|
||||
a->ox + a->ow/2 - new_w/2,
|
||||
a->oy + a->oh/2 - new_h/2,
|
||||
new_w,
|
||||
new_h
|
||||
);
|
||||
}
|
||||
|
||||
void fade_layer_in_step(vui_context_t *vui, int64_t time, void *v)
|
||||
{
|
||||
int layer = (int) (intptr_t) v;
|
||||
vui_layer_set_opacity(vui, layer, time / (float) FADE_ANIM_LENGTH);
|
||||
}
|
||||
|
||||
void fade_layer_out_step(vui_context_t *vui, int64_t time, void *v)
|
||||
{
|
||||
int layer = (int) (intptr_t) v;
|
||||
vui_layer_set_opacity(vui, layer, (FADE_ANIM_LENGTH - time) / (float) FADE_ANIM_LENGTH);
|
||||
}
|
||||
|
||||
void vui_transition_fade_layer_complete(vui_context_t *vui, void *v)
|
||||
{
|
||||
vui_anim_callback_t *data = (vui_anim_callback_t *) v;
|
||||
|
||||
// TODO: Some kind of check to ensure this was the correct layer?
|
||||
if (data->pop_layer)
|
||||
vui_layer_destroy(vui);
|
||||
|
||||
if (data->callback) {
|
||||
data->callback(vui, data->callback_data);
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
void vui_animation_button_mousedown(vui_context_t *vui, int button, vui_callback_t callback, void *callback_data)
|
||||
{
|
||||
vui_cancel_animation(vui);
|
||||
|
||||
vui_btn_anim_data_t *a = ¤t_button_anim;
|
||||
a->btn = button;
|
||||
vui_button_get_geometry(vui, button, &a->ox, &a->oy, &a->ow, &a->oh);
|
||||
|
||||
vui_start_animation(vui, BUTTON_MOUSEDOWN_ANIM_LENGTH, button_mousedown_animation_step, a, callback, callback_data);
|
||||
}
|
||||
|
||||
void vui_animation_button_mouseup(vui_context_t *vui, int button, vui_callback_t callback, void *callback_data)
|
||||
{
|
||||
vui_btn_anim_data_t *a = ¤t_button_anim;
|
||||
vui_start_animation(vui, BUTTON_MOUSEUP_ANIM_LENGTH, button_mouseup_animation_step, a, callback, callback_data);
|
||||
}
|
||||
|
||||
void vui_transition_fade_layer(vui_context_t *ctx, int layer, vui_anim_step_callback_t step, vui_callback_t callback, void *callback_data, int pop_layer)
|
||||
{
|
||||
vui_anim_callback_t *data = (vui_anim_callback_t *) malloc(sizeof(vui_anim_callback_t));
|
||||
data->callback = callback;
|
||||
data->callback_data = callback_data;
|
||||
data->pop_layer = pop_layer;
|
||||
vui_start_animation(ctx, FADE_ANIM_LENGTH, step, (void *) (intptr_t) layer, vui_transition_fade_layer_complete, data);
|
||||
}
|
||||
|
||||
void vui_transition_fade_layer_in(vui_context_t *ctx, int layer, vui_callback_t callback, void *callback_data)
|
||||
{
|
||||
vui_transition_fade_layer(ctx, layer, fade_layer_in_step, callback, callback_data, 0);
|
||||
}
|
||||
|
||||
void vui_transition_fade_layer_out(vui_context_t *ctx, int layer, vui_callback_t callback, void *callback_data)
|
||||
{
|
||||
vui_transition_fade_layer(ctx, layer, fade_layer_out_step, callback, callback_data, 0);
|
||||
}
|
||||
|
||||
void vui_transition_fade_black_in(vui_context_t *ctx, vui_callback_t callback, void *callback_data)
|
||||
{
|
||||
int layer = vui_layer_create(ctx);
|
||||
vui_layer_set_bgcolor(ctx, layer, vui_color_create(0, 0, 0, 1));
|
||||
vui_transition_fade_layer(ctx, layer, fade_layer_in_step, callback, callback_data, 1);
|
||||
}
|
||||
|
||||
void vui_transition_fade_black_out(vui_context_t *ctx, vui_callback_t callback, void *callback_data)
|
||||
{
|
||||
int layer = vui_layer_create(ctx);
|
||||
vui_layer_set_bgcolor(ctx, layer, vui_color_create(0, 0, 0, 1));
|
||||
vui_transition_fade_layer(ctx, layer, fade_layer_out_step, callback, callback_data, 1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef VANILLA_PI_UI_ANIM_H
|
||||
#define VANILLA_PI_UI_ANIM_H
|
||||
|
||||
#include "ui.h"
|
||||
|
||||
void vui_transition_fade_layer_in(vui_context_t *ctx, int layer, vui_callback_t callback, void *callback_data);
|
||||
void vui_transition_fade_layer_out(vui_context_t *ctx, int layer, vui_callback_t callback, void *callback_data);
|
||||
|
||||
void vui_transition_fade_black_in(vui_context_t *ctx, vui_callback_t callback, void *callback_data);
|
||||
void vui_transition_fade_black_out(vui_context_t *ctx, vui_callback_t callback, void *callback_data);
|
||||
|
||||
void vui_animation_button_mousedown(vui_context_t *vui, int button, vui_callback_t callback, void *callback_data);
|
||||
void vui_animation_button_mouseup(vui_context_t *vui, int button, vui_callback_t callback, void *callback_data);
|
||||
|
||||
#endif // VANILLA_PI_UI_ANIM_H
|
||||
+41
-10
@@ -2,7 +2,23 @@
|
||||
#define VANILLA_PI_UI_PRIV_H
|
||||
|
||||
#define MAX_BUTTON_COUNT 16
|
||||
#define MAX_BUTTON_TEXT 16
|
||||
#define MAX_BUTTON_TEXT 256
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
int sx;
|
||||
int sy;
|
||||
int sw;
|
||||
int sh;
|
||||
char text[MAX_BUTTON_TEXT];
|
||||
vui_button_style style;
|
||||
vui_button_callback_t onclick;
|
||||
void *onclick_data;
|
||||
int layer;
|
||||
} vui_button_t;
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
@@ -10,10 +26,19 @@ typedef struct {
|
||||
int w;
|
||||
int h;
|
||||
char text[MAX_BUTTON_TEXT];
|
||||
vui_button_style style;
|
||||
vui_button_callback_t onclick;
|
||||
void *onclick_data;
|
||||
} vui_button_t;
|
||||
int layer;
|
||||
vui_color_t color;
|
||||
} vui_label_t;
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
int border_radius;
|
||||
vui_color_t color;
|
||||
int layer;
|
||||
} vui_rect_priv_t;
|
||||
|
||||
typedef struct {
|
||||
/// @brief System/game time that the animation starts
|
||||
@@ -39,15 +64,21 @@ typedef struct {
|
||||
} vui_animation_t;
|
||||
|
||||
typedef struct vui_context_t {
|
||||
void *platform_data;
|
||||
vui_button_t buttons[MAX_BUTTON_COUNT];
|
||||
int button_count;
|
||||
vui_label_t labels[MAX_BUTTON_COUNT];
|
||||
int label_count;
|
||||
vui_rect_priv_t rects[MAX_BUTTON_COUNT];
|
||||
int rect_count;
|
||||
vui_animation_t animation;
|
||||
int animation_enabled;
|
||||
float overlay_r;
|
||||
float overlay_g;
|
||||
float overlay_b;
|
||||
float overlay_a;
|
||||
int overlay_enabled;
|
||||
int button_active;
|
||||
int screen_width;
|
||||
int screen_height;
|
||||
int layers;
|
||||
float layer_opacity[MAX_BUTTON_COUNT];
|
||||
vui_color_t layer_color[MAX_BUTTON_COUNT];
|
||||
} vui_context_t;
|
||||
|
||||
#endif // VANILLA_PI_UI_PRIV_H
|
||||
+400
-60
@@ -1,21 +1,67 @@
|
||||
#include "ui_sdl2.h"
|
||||
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "ui_priv.h"
|
||||
|
||||
static TTF_Font *sysfont = 0;
|
||||
static TTF_Font *sysfont_mini = 0;
|
||||
|
||||
int vui_init_sdl2()
|
||||
typedef struct {
|
||||
SDL_Texture *texture;
|
||||
int w;
|
||||
int h;
|
||||
char text[MAX_BUTTON_TEXT];
|
||||
} vui_sdl2_cached_texture_t;
|
||||
|
||||
typedef struct {
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Rect dst_rect;
|
||||
SDL_Texture *background;
|
||||
SDL_Texture *layer_data[MAX_BUTTON_COUNT];
|
||||
vui_sdl2_cached_texture_t button_cache[MAX_BUTTON_COUNT];
|
||||
} vui_sdl2_context_t;
|
||||
|
||||
int intmin(int a, int b) { return a < b ? a : b; }
|
||||
int intmax(int a, int b) { return a > b ? a : b; }
|
||||
|
||||
int vui_init_sdl2(vui_context_t *ctx)
|
||||
{
|
||||
// Initialize SDL
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER) < 0) {
|
||||
fprintf(stderr, "Failed to initialize SDL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vui_sdl2_context_t *sdl2_ctx = malloc(sizeof(vui_sdl2_context_t));
|
||||
ctx->platform_data = sdl2_ctx;
|
||||
|
||||
memset(&sdl2_ctx->dst_rect, 0, sizeof(SDL_Rect));
|
||||
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2");
|
||||
|
||||
sdl2_ctx->window = SDL_CreateWindow("Vanilla", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, ctx->screen_width, ctx->screen_height, SDL_WINDOW_RESIZABLE);
|
||||
if (!sdl2_ctx->window) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sdl2_ctx->renderer = SDL_CreateRenderer(sdl2_ctx->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
if (!sdl2_ctx->renderer) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Enable blending
|
||||
SDL_SetRenderDrawBlendMode(sdl2_ctx->renderer, SDL_BLENDMODE_BLEND);
|
||||
|
||||
if (TTF_Init()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *font_filename = "/home/matt/src/vanilla/rpi/font/system.ttf";
|
||||
|
||||
sysfont = TTF_OpenFont(font_filename, 34);
|
||||
sysfont = TTF_OpenFont(font_filename, 36);
|
||||
if (!sysfont) {
|
||||
return -1;
|
||||
}
|
||||
@@ -25,84 +71,378 @@ int vui_init_sdl2()
|
||||
return -1;
|
||||
}
|
||||
|
||||
sdl2_ctx->background = 0;
|
||||
memset(sdl2_ctx->layer_data, 0, sizeof(sdl2_ctx->layer_data));
|
||||
memset(sdl2_ctx->button_cache, 0, sizeof(sdl2_ctx->button_cache));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vui_close_sdl2()
|
||||
void vui_close_sdl2(vui_context_t *ctx)
|
||||
{
|
||||
vui_sdl2_context_t *sdl2_ctx = (vui_sdl2_context_t *) ctx->platform_data;
|
||||
if (!sdl2_ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_BUTTON_COUNT; i++) {
|
||||
if (sdl2_ctx->layer_data[i]) {
|
||||
SDL_DestroyTexture(sdl2_ctx->layer_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TTF_CloseFont(sysfont);
|
||||
|
||||
TTF_Quit();
|
||||
|
||||
SDL_DestroyRenderer(sdl2_ctx->renderer);
|
||||
|
||||
SDL_DestroyWindow(sdl2_ctx->window);
|
||||
|
||||
free(sdl2_ctx);
|
||||
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
float lerp(float a, float b, float f)
|
||||
{
|
||||
return a * (1.0 - f) + (b * f);
|
||||
}
|
||||
|
||||
void vui_sdl2_set_render_color(SDL_Renderer *renderer, vui_color_t color)
|
||||
{
|
||||
SDL_SetRenderDrawColor(
|
||||
renderer,
|
||||
color.r * 0xFF,
|
||||
color.g * 0xFF,
|
||||
color.b * 0xFF,
|
||||
color.a * 0xFF
|
||||
);
|
||||
}
|
||||
|
||||
void vui_sdl2_draw_button(vui_sdl2_context_t *sdl2_ctx, vui_button_t *btn)
|
||||
{
|
||||
SDL_SetRenderDrawColor(sdl2_ctx->renderer, 0, 0, 0, 0);
|
||||
SDL_RenderClear(sdl2_ctx->renderer);
|
||||
|
||||
SDL_Color text_color;
|
||||
TTF_Font *text_font = sysfont;
|
||||
|
||||
SDL_Rect rect;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.w = btn->w;
|
||||
rect.h = btn->h;
|
||||
|
||||
switch (btn->style) {
|
||||
case VUI_BUTTON_STYLE_CORNER:
|
||||
text_font = sysfont_mini;
|
||||
case VUI_BUTTON_STYLE_BUTTON:
|
||||
case VUI_BUTTON_STYLE_LIST:
|
||||
static const float button_x_gradient_positions[] = {
|
||||
0.0f,
|
||||
0.1f,
|
||||
0.9f,
|
||||
1.0f,
|
||||
};
|
||||
static const uint8_t button_x_gradient_colors[] = {
|
||||
0xE8,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xE8,
|
||||
};
|
||||
static const float button_y_gradient_positions[] = {
|
||||
0.0f,
|
||||
0.1f,
|
||||
0.66f,
|
||||
0.875f,
|
||||
1.0f
|
||||
};
|
||||
static const uint8_t button_y_gradient_colors[] = {
|
||||
0xE8,
|
||||
0xFF,
|
||||
0xF8,
|
||||
0xE0,
|
||||
0xF0,
|
||||
};
|
||||
|
||||
const int btn_radius = rect.h * 2 / 10;
|
||||
for (int y = 0; y < rect.h; y++) {
|
||||
int coord = rect.y + y;
|
||||
|
||||
// Determine color
|
||||
float l = 0;
|
||||
{
|
||||
float yf = y / (float) rect.h;
|
||||
for (size_t j = 1; j < sizeof(button_y_gradient_positions)/sizeof(float); j++) {
|
||||
float min = button_y_gradient_positions[j - 1];
|
||||
float max = button_y_gradient_positions[j];
|
||||
if (yf >= min && yf < max) {
|
||||
yf -= min;
|
||||
yf /= max - min;
|
||||
|
||||
uint8_t minc = button_y_gradient_colors[j - 1];
|
||||
uint8_t maxc = button_y_gradient_colors[j];
|
||||
l = lerp(minc, maxc, yf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle rounded corners
|
||||
float x_inset = 0;
|
||||
{
|
||||
if (y < btn_radius) {
|
||||
int yb = y - btn_radius;
|
||||
x_inset = btn_radius - sqrtf(btn_radius*btn_radius - yb*yb);
|
||||
} else {
|
||||
if (y >= rect.h - btn_radius) {
|
||||
int yb = (rect.h - y) - btn_radius;
|
||||
x_inset = btn_radius - sqrtf(btn_radius*btn_radius - yb*yb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(sdl2_ctx->renderer, l, l, l, 0xFF);
|
||||
SDL_RenderDrawLineF(sdl2_ctx->renderer, rect.x + x_inset, coord, rect.x + rect.w - x_inset, coord);
|
||||
}
|
||||
|
||||
text_color.r = text_color.g = text_color.b = 0x40;
|
||||
text_color.a = 0xFF;
|
||||
break;
|
||||
/*case VUI_BUTTON_STYLE_CORNER:
|
||||
text_font = sysfont_mini;
|
||||
break;
|
||||
case VUI_BUTTON_STYLE_LIST:
|
||||
if (list_item_count % 2 == 0) {
|
||||
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
|
||||
} else {
|
||||
SDL_SetRenderDrawColor(renderer, 0xF0, 0xF0, 0xF0, 0xFF);
|
||||
}
|
||||
list_item_count++;
|
||||
|
||||
SDL_RenderFillRect(renderer, &rect);
|
||||
|
||||
text_color.r = text_color.g = text_color.b = 0;
|
||||
text_color.a = 0xFF;
|
||||
break;*/
|
||||
case VUI_BUTTON_STYLE_NONE:
|
||||
// No background
|
||||
text_color.r = text_color.g = text_color.b = text_color.a = 0xFF;
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw text
|
||||
if (btn->text[0]) {
|
||||
SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped(text_font, btn->text, text_color, rect.w);
|
||||
SDL_Texture *texture = SDL_CreateTextureFromSurface(sdl2_ctx->renderer, surface);
|
||||
|
||||
SDL_Rect text_rect;
|
||||
text_rect.w = surface->w;
|
||||
text_rect.h = surface->h;
|
||||
text_rect.x = rect.x + rect.w / 2 - text_rect.w / 2;
|
||||
text_rect.y = rect.y + rect.h / 2 - text_rect.h / 2;
|
||||
|
||||
SDL_RenderCopy(sdl2_ctx->renderer, texture, NULL, &text_rect);
|
||||
SDL_DestroyTexture(texture);
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
}
|
||||
|
||||
void vui_sdl2_draw_background(vui_context_t *ctx, SDL_Renderer *renderer)
|
||||
{
|
||||
const int bg_r1 = 0xB8;
|
||||
const int bg_g1 = 0xB8;
|
||||
const int bg_b1 = 0xC8;
|
||||
const int bg_r2 = 0xE0;
|
||||
const int bg_g2 = 0xF0;
|
||||
const int bg_b2 = 0xF0;
|
||||
for (int x = 0; x < ctx->screen_width; x++) {
|
||||
float xf = x / (float) ctx->screen_width;
|
||||
SDL_SetRenderDrawColor(renderer, lerp(bg_r1, bg_r2, xf), lerp(bg_g1, bg_g2, xf), lerp(bg_b1, bg_b2, xf), 0xFF);
|
||||
SDL_RenderDrawLine(renderer, x, 0, x, ctx->screen_height);
|
||||
}
|
||||
}
|
||||
|
||||
void vui_draw_sdl2(vui_context_t *ctx, SDL_Renderer *renderer)
|
||||
{
|
||||
SDL_SetRenderDrawColor(renderer, 0x0, 0x0, 0x0, 0x0);
|
||||
SDL_RenderClear(renderer);
|
||||
vui_sdl2_context_t *sdl2_ctx = (vui_sdl2_context_t *) ctx->platform_data;
|
||||
|
||||
int list_item_count = 0;
|
||||
for (int layer = 0; layer < ctx->layers; layer++) {
|
||||
if (!sdl2_ctx->layer_data[layer]) {
|
||||
// Create a new layer here
|
||||
sdl2_ctx->layer_data[layer] = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, ctx->screen_width, ctx->screen_height);
|
||||
SDL_SetTextureBlendMode(sdl2_ctx->layer_data[layer], SDL_BLENDMODE_BLEND);
|
||||
}
|
||||
SDL_SetRenderTarget(renderer, sdl2_ctx->layer_data[layer]);
|
||||
|
||||
for (int i = 0; i < ctx->button_count; i++) {
|
||||
// Draw background
|
||||
vui_button_t *btn = &ctx->buttons[i];
|
||||
SDL_Rect rect;
|
||||
rect.x = btn->x;
|
||||
rect.y = btn->y;
|
||||
rect.w = btn->w;
|
||||
rect.h = btn->h;
|
||||
|
||||
SDL_Color text_color;
|
||||
TTF_Font *text_font = sysfont;
|
||||
|
||||
switch (btn->style) {
|
||||
case VUI_BUTTON_STYLE_BUTTON:
|
||||
SDL_SetRenderDrawColor(renderer, 0xFF, 0x0, 0x0, 0xFF);
|
||||
SDL_RenderFillRect(renderer, &rect);
|
||||
|
||||
text_color.r = text_color.g = text_color.b = text_color.a = 0xFF;
|
||||
break;
|
||||
case VUI_BUTTON_STYLE_CORNER:
|
||||
text_font = sysfont_mini;
|
||||
break;
|
||||
case VUI_BUTTON_STYLE_LIST:
|
||||
if (list_item_count % 2 == 0) {
|
||||
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
|
||||
} else {
|
||||
SDL_SetRenderDrawColor(renderer, 0xF0, 0xF0, 0xF0, 0xFF);
|
||||
if (layer == 0) {
|
||||
// Draw background
|
||||
if (!sdl2_ctx->background) {
|
||||
sdl2_ctx->background = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, ctx->screen_width, ctx->screen_height);
|
||||
SDL_Texture *old_target = SDL_GetRenderTarget(renderer);
|
||||
SDL_SetRenderTarget(renderer, sdl2_ctx->background);
|
||||
vui_sdl2_draw_background(ctx, renderer);
|
||||
SDL_SetRenderTarget(renderer, old_target);
|
||||
}
|
||||
list_item_count++;
|
||||
|
||||
SDL_RenderFillRect(renderer, &rect);
|
||||
|
||||
text_color.r = text_color.g = text_color.b = 0;
|
||||
text_color.a = 0xFF;
|
||||
break;
|
||||
case VUI_BUTTON_STYLE_NONE:
|
||||
// No background
|
||||
text_color.r = text_color.g = text_color.b = text_color.a = 0xFF;
|
||||
break;
|
||||
SDL_RenderCopy(renderer, sdl2_ctx->background, 0, 0);
|
||||
} else {
|
||||
vui_sdl2_set_render_color(renderer, ctx->layer_color[layer]);
|
||||
SDL_RenderClear(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw rects
|
||||
for (int i = 0; i < ctx->rect_count; i++) {
|
||||
vui_rect_priv_t *rect = &ctx->rects[i];
|
||||
|
||||
SDL_SetRenderTarget(renderer, sdl2_ctx->layer_data[rect->layer]);
|
||||
|
||||
SDL_Rect sr;
|
||||
sr.x = rect->x;
|
||||
sr.y = rect->y;
|
||||
sr.w = rect->w;
|
||||
sr.h = rect->h;
|
||||
vui_sdl2_set_render_color(renderer, rect->color);
|
||||
SDL_RenderFillRect(renderer, &sr);
|
||||
}
|
||||
|
||||
// Draw labels
|
||||
for (int i = 0; i < ctx->label_count; i++) {
|
||||
vui_label_t *lbl = &ctx->labels[i];
|
||||
|
||||
SDL_SetRenderTarget(renderer, sdl2_ctx->layer_data[lbl->layer]);
|
||||
|
||||
SDL_Color c;
|
||||
c.r = lbl->color.r * 0xFF;
|
||||
c.g = lbl->color.g * 0xFF;
|
||||
c.b = lbl->color.b * 0xFF;
|
||||
c.a = lbl->color.a * 0xFF;
|
||||
|
||||
SDL_Surface *surface = TTF_RenderText_Blended_Wrapped(sysfont, lbl->text, c, lbl->w);
|
||||
|
||||
SDL_Rect sr;
|
||||
sr.x = 0;
|
||||
sr.y = 0;
|
||||
sr.w = intmin(lbl->w, surface->w);
|
||||
sr.h = intmin(lbl->h, surface->h);
|
||||
|
||||
SDL_Rect dr;
|
||||
dr.x = lbl->x;
|
||||
dr.y = lbl->y;
|
||||
dr.w = sr.w;
|
||||
dr.h = sr.h;
|
||||
|
||||
// Draw text
|
||||
if (btn->text[0]) {
|
||||
SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped(text_font, btn->text, text_color, rect.w);
|
||||
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
|
||||
SDL_Rect text_rect;
|
||||
text_rect.w = surface->w;
|
||||
text_rect.h = surface->h;
|
||||
text_rect.x = rect.x + rect.w / 2 - text_rect.w / 2;
|
||||
text_rect.y = rect.y + rect.h / 2 - text_rect.h / 2;
|
||||
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
SDL_RenderCopy(renderer, texture, &sr, &dr);
|
||||
SDL_DestroyTexture(texture);
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
|
||||
SDL_RenderCopy(renderer, texture, NULL, &text_rect);
|
||||
SDL_DestroyTexture(texture);
|
||||
SDL_FreeSurface(surface);
|
||||
// Draw buttons
|
||||
for (int i = 0; i < ctx->button_count; i++) {
|
||||
vui_button_t *btn = &ctx->buttons[i];
|
||||
|
||||
SDL_SetRenderTarget(renderer, sdl2_ctx->layer_data[btn->layer]);
|
||||
|
||||
// Check if button needs to be redrawn
|
||||
vui_sdl2_cached_texture_t *btn_tex = &sdl2_ctx->button_cache[i];
|
||||
if (!btn_tex->texture || btn_tex->w != btn->w || btn_tex->h != btn->h || strcmp(btn_tex->text, btn->text)) {
|
||||
// Must re-draw texture
|
||||
if (btn_tex->texture && (btn_tex->w != btn->w || btn_tex->h != btn->h)) {
|
||||
SDL_DestroyTexture(btn_tex->texture);
|
||||
btn_tex->texture = 0;
|
||||
}
|
||||
|
||||
if (!btn_tex->texture) {
|
||||
btn_tex->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, btn->w, btn->h);
|
||||
SDL_SetTextureBlendMode(btn_tex->texture, SDL_BLENDMODE_BLEND);
|
||||
}
|
||||
|
||||
SDL_Texture *old_target = SDL_GetRenderTarget(renderer);
|
||||
SDL_SetRenderTarget(renderer, btn_tex->texture);
|
||||
vui_sdl2_draw_button(sdl2_ctx, btn);
|
||||
SDL_SetRenderTarget(renderer, old_target);
|
||||
|
||||
btn_tex->w = btn->w;
|
||||
btn_tex->h = btn->h;
|
||||
strcpy(btn_tex->text, btn->text);
|
||||
}
|
||||
|
||||
// Draw cached texture onto screen
|
||||
SDL_Rect rect;
|
||||
rect.x = btn->sx;
|
||||
rect.y = btn->sy;
|
||||
rect.w = btn->sw;
|
||||
rect.h = btn->sh;
|
||||
|
||||
SDL_RenderCopy(renderer, btn_tex->texture, 0, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
int vui_update_sdl2(vui_context_t *vui)
|
||||
{
|
||||
vui_sdl2_context_t *sdl2_ctx = (vui_sdl2_context_t *) vui->platform_data;
|
||||
|
||||
SDL_Rect *dst_rect = &sdl2_ctx->dst_rect;
|
||||
|
||||
SDL_Event ev;
|
||||
while (SDL_PollEvent(&ev)) {
|
||||
if (ev.type == SDL_QUIT) {
|
||||
return 0;
|
||||
} else if (ev.type == SDL_MOUSEBUTTONDOWN || ev.type == SDL_MOUSEBUTTONUP) {
|
||||
if (dst_rect->w > 0 && dst_rect->h > 0) {
|
||||
int tr_x, tr_y;
|
||||
tr_x = (ev.button.x - dst_rect->x) * vui->screen_width / dst_rect->w;
|
||||
tr_y = (ev.button.y - dst_rect->y) * vui->screen_height / dst_rect->h;
|
||||
if (ev.type == SDL_MOUSEBUTTONDOWN)
|
||||
vui_process_mousedown(vui, tr_x, tr_y);
|
||||
else
|
||||
vui_process_mouseup(vui, tr_x, tr_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->overlay_enabled) {
|
||||
SDL_SetRenderDrawColor(renderer, ctx->overlay_r * 0xFF, ctx->overlay_g * 0xFF, ctx->overlay_b * 0xFF, ctx->overlay_a * 0xFF);
|
||||
SDL_RenderFillRect(renderer, NULL);
|
||||
vui_update(vui);
|
||||
|
||||
// Draw vui to a custom texture
|
||||
vui_draw_sdl2(vui, sdl2_ctx->renderer);
|
||||
|
||||
// Calculate our destination rectangle
|
||||
int win_w, win_h;
|
||||
SDL_GetWindowSize(sdl2_ctx->window, &win_w, &win_h);
|
||||
if (win_w == vui->screen_width && win_h == vui->screen_height) {
|
||||
dst_rect->x = 0;
|
||||
dst_rect->y = 0;
|
||||
dst_rect->w = vui->screen_width;
|
||||
dst_rect->h = vui->screen_height;
|
||||
} else if (win_w * 100 / win_h > vui->screen_width * 100 / vui->screen_height) {
|
||||
// Window is wider than texture, scale by height
|
||||
dst_rect->h = win_h;
|
||||
dst_rect->y = 0;
|
||||
dst_rect->w = win_h * vui->screen_width / vui->screen_height;
|
||||
dst_rect->x = win_w / 2 - dst_rect->w / 2;
|
||||
} else {
|
||||
// Window is taller than texture, scale by width
|
||||
dst_rect->w = win_w;
|
||||
dst_rect->x = 0;
|
||||
dst_rect->h = win_w * vui->screen_height / vui->screen_width;
|
||||
dst_rect->y = win_h / 2 - dst_rect->h / 2;
|
||||
}
|
||||
|
||||
// Copy texture to window
|
||||
SDL_SetRenderTarget(sdl2_ctx->renderer, NULL);
|
||||
SDL_SetRenderDrawColor(sdl2_ctx->renderer, 0, 0, 0, 0);
|
||||
SDL_RenderClear(sdl2_ctx->renderer);
|
||||
float layer_opacity = 1.0f;
|
||||
for (int i = 0; i < vui->layers; i++) {
|
||||
layer_opacity *= vui->layer_opacity[i];
|
||||
SDL_SetTextureAlphaMod(sdl2_ctx->layer_data[i], layer_opacity* 0xFF);
|
||||
SDL_RenderCopy(sdl2_ctx->renderer, sdl2_ctx->layer_data[i], NULL, dst_rect);
|
||||
}
|
||||
|
||||
// Flip surfaces
|
||||
SDL_RenderPresent(sdl2_ctx->renderer);
|
||||
|
||||
return 1;
|
||||
}
|
||||
+10
-4
@@ -5,13 +5,19 @@
|
||||
|
||||
#include "ui.h"
|
||||
|
||||
|
||||
/**
|
||||
* System-related functions
|
||||
*/
|
||||
int vui_init_sdl2();
|
||||
void vui_close_sdl2();
|
||||
int vui_init_sdl2(vui_context_t *ctx);
|
||||
void vui_close_sdl2(vui_context_t *ctx);
|
||||
|
||||
void vui_draw_sdl2(vui_context_t *ctx, SDL_Renderer *renderer);
|
||||
/**
|
||||
* Main loop
|
||||
*
|
||||
* Intended to be called from a semi-infinite loop.
|
||||
*
|
||||
* Returns 1 if the loop should continue, 0 if the loop should exit
|
||||
*/
|
||||
int vui_update_sdl2(vui_context_t *ctx);
|
||||
|
||||
#endif // VANILLA_PI_UI_SDL_H
|
||||
Reference in new issue
Block a user