gadget-kspconsole/ui.c

363 lines
8.5 KiB
C
Raw Normal View History

2023-11-27 15:13:55 +01:00
/*
* Copyright (C) 2023 Daniele Lacamera <root@danielinux.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include "stm32f7_ltdc.h"
#include "ui.h"
#include "systick.h"
#include "button.h"
static uint8_t menu_on = 0;
uint8_t ui_menu_is_on(void)
{
return menu_on;
}
void ui_menu(uint8_t onoff)
{
menu_on = onoff;
}
#define BUTTON_RIGHT 1
#define BUTTON_LEFT 2
#define BUTTON_UP 0
#define BUTTON_DOWN 3
#define BUTTON_IN 7
#define BUTTON_OUT 6
#define BUTTON_FIRE 5
#define NO_CHANNEL (-1)
enum control_mode_e {
CTL_RUN,
CTL_STOP,
CTL_PAUSE,
CTL_TRIGGER,
CTL_MAX
};
int res[] = {
1000000 , 500000 , 200000 , 100000 , 50000 , 20000 , 10000 , 5000 , 2000 , 1000 , 500 , 200 , 100 , 50 , 20 , 0
};
#define FONT_HEIGHT 8
#define FONT_WIDTH 8
extern const unsigned char fb_font[256][FONT_WIDTH];
uint8_t *ui_get_screen(int layer)
{
if (layer == 0)
return (uint8_t *)Screen_address;
else
return (uint8_t *)Overlay_address;
}
void ui_draw_h_segment(int layer, uint8_t color, uint32_t row, uint32_t start, uint32_t len)
{
uint32_t i;
uint32_t pos = row * xres + start;
uint8_t *screen = ui_get_screen(layer);
for (i = 0; i < len; i++) {
screen[pos + i] = color;
}
}
void ui_draw_v_segment(int layer, uint8_t color, uint32_t col, uint32_t start, uint32_t len)
{
uint32_t i;
uint32_t pos = start * xres + col;
uint8_t *screen = ui_get_screen(layer);
for (i = 0; i < len; i++) {
screen[pos + i * xres] = color;
}
}
void ui_fill_area(int layer, uint8_t color, uint32_t x, uint32_t y, uint32_t x1, uint32_t y1)
{
int i;
for (i = y; i < y1; i++) {
ui_draw_h_segment(layer, color, i, x, x1 - x);
}
}
void ui_text_at(int layer, uint8_t color, uint32_t x, uint32_t y, char *text)
{
uint32_t i, j;
char fc;
const uint8_t *render;
uint32_t pos = y * xres + x;
uint8_t *screen = ui_get_screen(layer);
while(text[0]) {
uint32_t cur = pos;
fc = text[0];
render = fb_font[(int)fc];
for (i = 0; i < FONT_HEIGHT; i++) {
for (j = 0; j < FONT_WIDTH; j++) {
int right_shift = (FONT_HEIGHT - 1) - j;
cur = pos + i * xres + j;
if (render[i] & (1 << (7 - j))) {
screen[cur] = color;
}
}
}
pos += FONT_WIDTH;
text++;
}
}
void ui_selected_text_at(int layer, uint8_t color, uint8_t highlight, uint32_t x, uint32_t y, char *text)
{
ui_fill_area(layer, highlight, x, y, x + (FONT_WIDTH * strlen(text)), y + FONT_HEIGHT);
ui_text_at(layer, color, x, y, text);
}
void image_at(int layer, const uint8_t *img, uint32_t x, uint32_t y, uint32_t size_x, uint32_t size_y)
{
uint32_t i, j;
uint32_t pos = y * xres + x;
uint8_t *screen = ui_get_screen(layer);
for (i = 0; i < size_y; i++) {
for (j = 0; j < size_x; j++) {
screen[pos + i * xres + j] = img[i * size_x + j];
}
}
}
/**** ****/
static char _ui_printn_res[20];
char *ui_printn(uint32_t n)
{
int i = 0;
uint32_t div = 1000000000;
int started = 0;
while (div >= 10) {
if ((n >= div) || started) {
_ui_printn_res[i++] = '0' + n / div;
n = n % div;
started++;
}
div /= 10;
}
_ui_printn_res[i++] = '0' + n;
_ui_printn_res[i] = '\0';
return (char *)(&_ui_printn_res[0]);
}
char *ui_printn2(uint32_t n)
{
_ui_printn_res[0] = '`';
_ui_printn_res[1] = '0' + (n % 10);
if (n > 9)
_ui_printn_res[0] = '0' + (n / 10);
_ui_printn_res[2] = 0;
return _ui_printn_res;
}
char *ui_printhex(uint8_t n)
{
uint8_t a = (n & 0xF0) >> 4;
uint8_t b = (n & 0x0F);
if (a < 10)
_ui_printn_res[0] = a + '0';
else
_ui_printn_res[0] = (a - 0xa) + 'A';
if (b < 10)
_ui_printn_res[1] = b + '0';
else
_ui_printn_res[1] = (b - 0xa) + 'A';
_ui_printn_res[2] = '\0';
return _ui_printn_res;
}
char *ui_printhex1(uint8_t n)
{
uint8_t a = (n & 0x0F);
if (a < 10)
_ui_printn_res[0] = a + '0';
else
_ui_printn_res[0] = (a - 0xa) + 'A';
_ui_printn_res[1] = '\0';
return _ui_printn_res;
}
static void ui_switch_screen(int newscreen);
static void force_redraw(void)
{
struct screen *s = screen_get_focus();
if (s && s->draw)
s->draw();
}
int ui_process_button_pressed(void)
{
int i;
for (i = 0; i < N_BUTTONS; i++) {
if (Input_status.b[i].pressed == 1) {
Input_status.b[i].pressed = 0;
return i;
}
}
return -1;
}
void ui_draw_blocks(void)
{
ui_fill_area(0, BLACK, 420, 90, 440, 120);
ui_fill_area(0, DARKRED, 420, 100, 440, 110);
}
struct point {
int x, y;
};
const struct point pot[] = {
{-9, 17}, {-10, 17}, {-11, 16}, {-12, 16}, {-13, 15}, {-14, 14}, {-15, 13}, {-16, 12}, {-17, 10}, {-18, 8}, {-19, 6}, {-20, 0},
{-19, -6}, {-18, -8}, {-16, -12}, {-15, -13}, {-14, -14}, {-13, -15}, {-12, -16}, {-11, -16}, {-10, -17}, {-9, -17}, {-8, -18}, {-7, -18}, {-6, -19}, {-5, -19}, {-4, -19}, {-3, -19}, {-2, -19}, {-1, -19}, {0, -20},
{1, -19}, {2, -19}, {3, -19}, {4, -19}, {5, -19}, {6, -19}, {7, -18}, {8, -18}, {9, -17}, {10, -17}, {11, -16}, {12, -16}, {13, -15}, {14, -14}, {15, -13}, {16, -12}, {17, -10}, {18, -8}, {19, -6}, {20, 0},
{19, 6}, {18, 8}, {17, 10}, {16, 12}, {15, 13}, {14, 14}, {13, 15}, {12, 16}, {11, 16}, {10, 17}, {9, 17},
};
static void ui_run(uint16_t event)
{
if (event & EV_BUTTON) {
int button = ui_process_button_pressed();
switch(button) {
case 7:
if (menu_on) {
menu_on = 0;
force_redraw();
} else {
menu_on = 1;
ui_redraw(EV_NONE);
}
break;
}
clear_event(EV_BUTTON);
}
}
static struct screen *ui_get_screen_by_id(int id)
{
struct screen *s = screens();
while(s) {
if (id == s->id) {
return s;
}
s = s->next;
}
return NULL;
}
void ui_switch_screen(int newscreen)
{
struct screen *s = ui_get_screen_by_id(newscreen);
if (s)
screen_set_focus(s);
}
void ui_menu_redraw(uint16_t event)
{
static int selected;
int button;
int i;
int n;
n = screen_n_screens();
if (event & EV_BUTTON) {
button = ui_process_button_pressed();
switch(button) {
case 1:
selected--;
if (selected < 0)
selected = n - 1;
ui_redraw(EV_NONE);
break;
case 3:
selected++;
if (selected > n - 1)
selected = 0;
ui_redraw(EV_NONE);
break;
case 7:
menu_on = 0;
force_redraw();
break;
default:
menu_on = 0;
ui_switch_screen(selected);
}
return;
}
ui_fill_area(0, BLACK, 400, 200, 480, 240);
for (i = 0; i < n; i++) {
if (i == selected) {
ui_fill_area(0, WHITE, 400, 200 + i * 10, 480, 210 + i * 10);
ui_text_at(0, PURPLE, 400, 200 + i*10, ui_get_screen_by_id(i)->name);
} else {
ui_text_at(0, WHITE, 400, 200 + i*10, ui_get_screen_by_id(i)->name);
}
}
}
void ui_redraw(uint16_t event)
{
struct screen *sc;
if (menu_on) {
ui_menu_redraw(event);
} else {
sc = screen_get_focus();
if (sc && sc->draw)
sc->draw();
}
}
void ui_init(void)
{
int i;
force_redraw();
}
struct task task_ui = {
.init = ui_init,
.run = ui_run,
.events = EV_BUTTON,
.name = "ui"
};
void ui_setup(void)
{
register_task(&task_ui);
}