diff options
author | Krow Savcik <krow@savcik.xyz> | 2023-09-26 22:32:35 +0300 |
---|---|---|
committer | Krow Savcik <krow@savcik.xyz> | 2023-09-26 22:32:35 +0300 |
commit | 9e660e594f6d3a43ea1427fb872801a2fcedad93 (patch) | |
tree | 459cd0c6fc5fef0366f7ef249ae19dd67c363772 /src/ui.c |
initial commit
Diffstat (limited to 'src/ui.c')
-rw-r--r-- | src/ui.c | 692 |
1 files changed, 692 insertions, 0 deletions
diff --git a/src/ui.c b/src/ui.c new file mode 100644 index 0000000..ccc2de9 --- /dev/null +++ b/src/ui.c @@ -0,0 +1,692 @@ +#include <stdio.h> +#include <assert.h> +#include <SDL2/SDL.h> +#include <SDL2/SDL_image.h> + +#include "ui.h" +#include "cdraw.h" +#include "types.h" +#include "canvas.h" +#include "tools.h" +#include "debug.h" +#include "palette.h" + +#define fpan main_ui->focus_panel +#define LENGTH(X) (sizeof X / sizeof *X) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)); + +static const SDL_Rect ui_frame_rect[] = { + {0, 0, 8, 8}, + {16, 0, 8, 8}, + {0, 16, 8, 8}, + {16, 16, 8, 8}, + {8, 0, 8, 8}, + {8, 16, 8, 8}, + {0, 8, 8, 8}, + {16, 8, 8, 8}, +}; +static const SDL_Rect ui_buttons_rect[] = { + {0, 24, 28, 28}, + {0, 52, 28, 28}, + {0, 80, 32, 32}, + /* TODO: y -= 2 all the rects below */ + {28, 26, 28, 28}, /* Pencil */ + {28, 54, 28, 28}, /* Eraser */ + {84, 26, 28, 28}, /* Fill Bucket */ + {56, 26, 28, 28}, /* Zoom in */ + {56, 54, 28, 28}, /* Zoom out */ + {84, 54, 28, 28}, /* Clown */ + {56, 82, 28, 28}, /* Color Picker */ +}; + +struct UIPanel { + uint8 type, redraw; + SDL_Rect geom; + SDL_Texture *pres; +}; + +struct UIPanelCanvas { + UIPanel head; + /* Canvas *canv; */ +}; + +struct UIPanelPalette { + UIPanel head; +}; + +struct UIPanelButtons { + UIPanel head; +}; + +struct UIPanelDivider { + UIPanel head; + UIPanel *x, *y; + uint8 st; /* states: (0 bit - hor/vert, 1 bit - ra/lb) */ + int fw, lw, of; +}; + +struct UIPanelTimeline { + UIPanel head; +}; + +struct UI { + SDL_Texture *theme; + int w, h; + UIPanel *focus_panel; + UIPanelDivider p_divs[3]; + UIPanelCanvas p_canvas; + UIPanelPalette p_palette; + UIPanelButtons p_buttons; + UIPanelTimeline p_timeline; +}; + +UI *main_ui; + +static UIPanel *ui_focus_panel(int, int); +static void ui_focus_panel_change(int, int); + +/* Panel functions */ +static uint8 ui_panel_init(UIPanel *, uint8); +static uint8 ui_panel_resize(UIPanel *, int, int, uint, uint); +static uint8 ui_panel_draw_frame(UIPanel *); +static uint8 ui_panel_redraw(UIPanel *); +static uint8 ui_panel_present(UIPanel *); + +/* Panel canvas functions */ +static uint8 ui_panel_canvas_init(UIPanelCanvas *); +static uint8 ui_panel_canvas_redraw(UIPanelCanvas *); + +/* Panel palette functions */ +static uint8 ui_panel_palette_init(UIPanelPalette *); +static uint8 ui_panel_palette_redraw(UIPanelPalette *); + +/* Panel buttons functions */ +static uint8 ui_panel_buttons_init(UIPanelButtons *); +static uint8 ui_panel_buttons_redraw(UIPanelButtons *); + +/* Panel timeline functions */ +static uint8 ui_panel_timeline_init(UIPanelTimeline *); +static uint8 ui_panel_timeline_redraw(UIPanelTimeline *); + +/* Panel divider functions */ +static uint8 ui_panel_divider_init(UIPanelDivider *, int, int, int, uint8, UIPanel *, UIPanel *); +static uint8 ui_panel_divider_resize(UIPanelDivider *, int, int, int, int); + +void +ui_create(const char *path) +{ +/* TODO: error checking */ + int i; + main_ui = malloc(sizeof *main_ui); + main_ui->theme = NULL; + main_ui->focus_panel = NULL; + main_ui->w = main_ui->h = -1; + if (ui_theme_load(path)) + exit(1); + + SDL_SetTextureBlendMode(main_ui->theme, SDL_BLENDMODE_BLEND); + + ui_panel_canvas_init(&main_ui->p_canvas); + ui_panel_palette_init(&main_ui->p_palette); + ui_panel_buttons_init(&main_ui->p_buttons); + ui_panel_timeline_init(&main_ui->p_timeline); + + /* ui_panel_divider_init(&main_ui->p_divs[0], 5, 10, 100, 1, &main_ui->p_canvas, &main_ui->p_timeline); */ + ui_panel_divider_init(&main_ui->p_divs[0], 5, 5, 120, 0, &main_ui->p_divs[1], &main_ui->p_divs[2]); + ui_panel_divider_init(&main_ui->p_divs[1], 0, 8, 22+31*((tool_array_size()+2)/3), 3, &main_ui->p_palette, &main_ui->p_buttons); + ui_panel_divider_init(&main_ui->p_divs[2], 0, 5, 70, 3, &main_ui->p_canvas, &main_ui->p_timeline); + + ui_resize(); +} + +void +ui_destroy() +{ + if (main_ui == NULL) return; + if (main_ui->theme) SDL_DestroyTexture(main_ui->theme); + free(main_ui); +} + +uint8 +ui_resize() +{ + static int w, h; + if (main_ui == NULL) + return 1; + + SDL_GetRendererOutputSize(ren, &w, &h); + if (w != main_ui->w || h != main_ui->h) { + main_ui->w = w; + main_ui->h = h; + ui_panel_resize(&main_ui->p_divs[0], 0, 0, w, h); + /* ui_panel_resize(&main_ui->p_palette.head, 5, 5, 120, main_ui->h-42-31*((tool_array_size()+2)/3)); */ + /* ui_panel_resize(&main_ui->p_buttons.head, 5, main_ui->h-27-31*((tool_array_size()+2)/3), 120, 22+31*((tool_array_size()+2)/3)); */ + /* ui_panel_resize(&main_ui->p_canvas.head, 130, 5, main_ui->w - 135, main_ui->h-85); */ + /* ui_panel_resize(&main_ui->p_timeline.head, 130, main_ui->h-75, main_ui->w - 135,70); */ + ui_redraw(); + } + return 0; +} + +void +ui_redraw() +{ + main_ui->p_canvas.head.redraw = 1; + main_ui->p_palette.head.redraw = 1; + main_ui->p_buttons.head.redraw = 1; + main_ui->p_timeline.head.redraw = 1; +} + +void +ui_redraw_panel(uint8 type) +{ + switch (type) { + case UI_PANELTYPE_PALETTE: + main_ui->p_palette.head.redraw = 1; + break; + case UI_PANELTYPE_CANVAS: + main_ui->p_canvas.head.redraw = 1; + break; + case UI_PANELTYPE_BUTTONS: + main_ui->p_buttons.head.redraw = 1; + break; + case UI_PANELTYPE_TIMELINE: + main_ui->p_timeline.head.redraw = 1; + break; + default: + fprintf(stderr, "%s:%d:ui_redraw_panel: No implementation for %u\n", __FILE__, __LINE__, type); + break; + } +} + +void +ui_present() +{ + if (main_ui->p_palette.head.redraw) + ui_panel_redraw(&main_ui->p_palette.head); + if (main_ui->p_canvas.head.redraw) + ui_panel_redraw(&main_ui->p_canvas.head); + if (main_ui->p_buttons.head.redraw) + ui_panel_redraw(&main_ui->p_buttons.head); + if (main_ui->p_timeline.head.redraw) + ui_panel_redraw(&main_ui->p_timeline.head); + ui_panel_present(&main_ui->p_palette.head); + ui_panel_present(&main_ui->p_canvas.head); + ui_panel_present(&main_ui->p_buttons.head); + ui_panel_present(&main_ui->p_timeline.head); +} + +void +ui_mousel_down(int x, int y) +{ + int col; + Arg arg; + ui_focus_panel_change(x, y); + + if (main_ui->focus_panel == NULL) + return; + + switch (main_ui->focus_panel->type) { + case UI_PANELTYPE_CANVAS: + if (cur_canvas != NULL) { + canvas_mousel_down(cur_canvas, + x - fpan->geom.x - 8, + y - fpan->geom.y - 8); + fpan->redraw = 1; + } + break; + case UI_PANELTYPE_PALETTE: + if (cur_canvas == NULL) + return; + col = (x - fpan->geom.x - 8) / 26; + if (col > 3) col = 3; + col += (((y - fpan->geom.y - 8) / 26) << 2); + + + if (col < ((Palette *)def_palette)->num && col >= 0) + cur_canvas->cur_col = col; + break; + case UI_PANELTYPE_BUTTONS: + + /* TODO Better */ + col = (x - fpan->geom.x - 15) / 30; + if (col > 2) + break; + + col += 3 * ((y - fpan->geom.y - 2) / 30); + + if (col >= tool_array_size() || col < 0) + break; + switch (tool_array[col]) { + case TOOL_TYPE_ZOOMOUT: + /* TODO: user functions must mostly be wrappers for internal fucntions */ + arg.i = -1; + user_canvas_zoom_change(&arg); + break; + case TOOL_TYPE_ZOOMIN: + arg.i = 1; + user_canvas_zoom_change(&arg); + break; + case TOOL_TYPE_CLOWN: + fprintf(stdout, "You have been clowned 🤡\n"); + break; + case TOOL_TYPE_EMPTY: + break; + default: + tool_change(col); + break; + } + break; + } +} + +void +ui_mousel_up(int x, int y) +{ + ui_focus_panel_change(x, y); + + if (main_ui->focus_panel == NULL) + return; + + switch (main_ui->focus_panel->type) { + case UI_PANELTYPE_CANVAS: + if (cur_canvas != NULL) + canvas_mousel_up(cur_canvas); + fpan->redraw = 1; + break; + } +} + +void +ui_mouse_move(int x, int y) +{ + ui_focus_panel_change(x, y); + + if (main_ui->focus_panel == NULL) + return; + + switch (main_ui->focus_panel->type) { + case UI_PANELTYPE_CANVAS: + if (cur_canvas != NULL) { + canvas_mouse_move(cur_canvas, + x - fpan->geom.x - 8, + y - fpan->geom.y - 8); + fpan->redraw = 1; + } + break; + } +} + +uint8 +ui_theme_load(const char *path) +{ +/* TODO: check path */ + if (main_ui->theme != NULL) + SDL_DestroyTexture(main_ui->theme); + + SDL_Surface *surf = IMG_Load(path); + if (surf == NULL) return 1; + main_ui->theme = SDL_CreateTextureFromSurface(ren, surf); + SDL_FreeSurface(surf); + if (main_ui->theme == NULL) return 1; + + return 0; +} + +static UIPanel * +ui_focus_panel(int x, int y) +{ + SDL_Rect *r; + if (main_ui == NULL) return NULL; + + r = &main_ui->p_palette.head.geom; + if (r->x <= x && r->y <= y + && x - r->x < r->w && y - r->y < r->h) + return &main_ui->p_palette.head; + + r = &main_ui->p_buttons.head.geom; + if (r->x <= x && r->y <= y + && x - r->x < r->w && y - r->y < r->h) + return &main_ui->p_buttons.head; + + r = &main_ui->p_canvas.head.geom; + if (r->x <= x && r->y <= y + && x - r->x < r->w && y - r->y < r->h) + return &main_ui->p_canvas.head; + + return NULL; +} + +static void +ui_focus_panel_change(int x, int y) +{ + UIPanel *u; + u = ui_focus_panel(x, y); + + if (u == main_ui->focus_panel) + return; + + if (main_ui->focus_panel != NULL) { + switch (main_ui->focus_panel->type) { + case UI_PANELTYPE_CANVAS: + is_drawing = 0; + main_ui->focus_panel = u; + ui_redraw_panel(UI_PANELTYPE_CANVAS); + break; + default: + break; + } + } + + main_ui->focus_panel = u; +} + +/* Panel functions */ +static uint8 +ui_panel_init(UIPanel *p, uint8 type) +{ + p->pres = NULL; + p->type = type; + p->redraw = 1; + p->geom.w = p->geom.h = 0; + + return 0; +} + +static uint8 +ui_panel_resize(UIPanel *p, int x, int y, uint w, uint h) +{ + if (p->type == UI_PANELTYPE_DIVIDER) + return ui_panel_divider_resize((UIPanelDivider *)p, x, y, w, h); + p->geom.x = x; + p->geom.y = y; + + /* assert(w > 16 && h > 16); */ + if (w < 16 || h < 16) + return 1; + if (p->geom.w == w && p->geom.h == h) + return 0; + + p->geom.w = w; + p->geom.h = h; + + if (p->pres != NULL) + SDL_DestroyTexture(p->pres); + + p->pres = SDL_CreateTexture( + ren, SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_TARGET, + w, h); + + SDL_SetTextureBlendMode(p->pres, SDL_BLENDMODE_BLEND); + + return 0; +} + +static uint8 +ui_panel_redraw(UIPanel *p) +{ +/* TODO: something for paralel threads? */ +/* TODO: Correct switch case intendation(not here) */ + if (p->pres == NULL) + return 1; + + p->redraw = 0; + + SDL_SetRenderTarget(ren, p->pres); + SDL_SetRenderDrawColor(ren, 0, 0, 0, 0); + SDL_RenderClear(ren); + switch (p->type) { + case UI_PANELTYPE_CANVAS: + ui_panel_canvas_redraw((UIPanelCanvas *)p); + break; + case UI_PANELTYPE_PALETTE: + ui_panel_palette_redraw((UIPanelPalette *)p); + break; + case UI_PANELTYPE_BUTTONS: + ui_panel_buttons_redraw((UIPanelButtons *)p); + break; + case UI_PANELTYPE_TIMELINE: + ui_panel_draw_frame(p); + break; + default: + fprintf(stderr, "%s:%d:ui_panel_redraw: No redraw fuction for %u\n", __FILE__, __LINE__, p->type); + break; + } + SDL_SetRenderTarget(ren, NULL); + + return 0; +} + +static uint8 +ui_panel_draw_frame(UIPanel *p) +{ + static SDL_Rect dest; + dest.x = 0; + dest.y = 0; + dest.h = 8; + dest.w = p->geom.w; + SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[4], &dest); + dest.y = p->geom.h-8; + SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[5], &dest); + dest.w = 8; + dest.h = p->geom.h; + dest.y = 0; + SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[6], &dest); + dest.x = p->geom.w-8; + SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[7], &dest); + + dest.h = 8; + SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[1], &dest); + dest.x = 0; + SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[0], &dest); + dest.y = p->geom.h-8; + SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[2], &dest); + dest.x = p->geom.w-8; + SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[3], &dest); + + return 0; +} + +static uint8 +ui_panel_present(UIPanel *p) +{ + return SDL_RenderCopy(ren, p->pres, NULL, &p->geom); +} + +/* Panel canvas functions */ +static uint8 +ui_panel_canvas_init(UIPanelCanvas *p) +{ + return ui_panel_init((UIPanel *)p, UI_PANELTYPE_CANVAS); +} + +static uint8 +ui_panel_canvas_redraw(UIPanelCanvas *p) +{ + static SDL_Rect dest; + dest.x = 8; + dest.y = 8; + dest.w = p->head.geom.w - 16; + dest.h = p->head.geom.h - 16; + SDL_RenderSetViewport(ren, &dest); + SDL_SetRenderDrawColor(ren, 18, 18, 18, 255); + SDL_RenderClear(ren); + if (cur_canvas != NULL) { + SDL_RenderSetViewport(ren, NULL); + canvas_redraw(cur_canvas, ren, + mouseX - p->head.geom.x - 8, + mouseY - p->head.geom.y - 8); + SDL_SetRenderTarget(ren, p->head.pres); + SDL_RenderSetViewport(ren, &dest); + canvas_present(cur_canvas, ren); + } + SDL_RenderSetViewport(ren, NULL); + ui_panel_draw_frame(&p->head); + return 0; +} + +/* Panel palette functions */ +static uint8 +ui_panel_palette_init(UIPanelPalette *p) +{ + return ui_panel_init((UIPanel *)p, UI_PANELTYPE_PALETTE); +} + +static uint8 +ui_panel_palette_redraw(UIPanelPalette *p) +{ + static SDL_Rect dest; + Palette *pp; + int i; + + pp = def_palette; + dest.x = 8; + dest.y = 8; + dest.w = p->head.geom.w - 16; + dest.h = p->head.geom.h - 16; + SDL_RenderSetViewport(ren, &dest); + SDL_SetRenderDrawColor(ren, 18, 18, 18, 255); + SDL_RenderClear(ren); + + SDL_SetRenderDrawColor(ren, 0, 0, 0, 255); + if (pp != NULL) { + dest.x = dest.y = 0; + dest.w = 120; + if (pp->num > 3) { + dest.h = 26 * (pp->num >> 2); + SDL_RenderFillRect(ren, &dest); + } + + if (pp->num % 4) { + dest.w = 26 * (pp->num % 4); + dest.h = 26; + dest.y = 26 * (pp->num >> 2); + SDL_RenderFillRect(ren, &dest); + } + + dest.w = dest.h = 24; + for (i = 0; i < pp->num; ++i) { + dest.x = 1 + (i % 4) * 26; + dest.y = 1 + (i / 4) * 26; + SDL_SetRenderDrawColor(ren, + pp->clist[i].r, pp->clist[i].g, + pp->clist[i].b, 255); + SDL_RenderFillRect(ren, &dest); + } + } + SDL_RenderSetViewport(ren, NULL); + ui_panel_draw_frame(&p->head); + return 0; +} + +/* Panel buttons functions */ +static uint8 +ui_panel_buttons_init(UIPanelButtons *p) +{ + return ui_panel_init((UIPanel *)p, UI_PANELTYPE_BUTTONS); +} + +static uint8 +ui_panel_buttons_redraw(UIPanelButtons *p) +{ + static SDL_Rect dest1; + static SDL_Rect dest2; + int i; + + dest1.x = 14; + dest1.y = 0; + dest1.w = p->head.geom.w - 28; + dest1.h = p->head.geom.h; + SDL_RenderSetViewport(ren, &dest1); + SDL_SetRenderDrawColor(ren, INTTOCOL(back_c), 255); + SDL_RenderClear(ren); + dest1.w = 28; + dest1.h = 28; + dest2.w = 32; + dest2.h = 32; + for (i = 0; i < tool_array_size(); ++i) { + if (tool_array[i] == TOOL_TYPE_EMPTY) continue; + dest1.x = 2 + (i % 3) * 30; + dest1.y = 2 + (i / 3) * 30; + dest2.x = (i % 3) * 30; + dest2.y = (i / 3) * 30; + SDL_RenderCopy(ren, main_ui->theme, &ui_buttons_rect[2], &dest2); + if (i == tool_cur) + SDL_RenderCopy(ren, main_ui->theme, &ui_buttons_rect[0], &dest1); + else + SDL_RenderCopy(ren, main_ui->theme, &ui_buttons_rect[1], &dest1); + SDL_RenderCopy(ren, main_ui->theme, &ui_buttons_rect[tool_array[i]+3], &dest1); + } + SDL_RenderSetViewport(ren, NULL); + /* ui_panel_draw_frame(&p->head); */ + return 0; +} + +/* Panel timeline functions */ +static uint8 +ui_panel_timeline_init(UIPanelTimeline *p) +{ + return ui_panel_init((UIPanel *)p, UI_PANELTYPE_TIMELINE); +} + +/* Panel divider functions */ +static uint8 +ui_panel_divider_init(UIPanelDivider *p, int fw, int lw, int of, uint8 st, UIPanel *p1, UIPanel *p2) +{ + ui_panel_init((UIPanel *)p, UI_PANELTYPE_DIVIDER); + p->fw = fw; + p->lw = lw; + p->of = of; + p->st = st; + p->x = p1; + p->y = p2; + return 0; +} + +static uint8 +ui_panel_divider_resize(UIPanelDivider *p, int x, int y, int w, int h) +{ + SDL_Rect g1, g2; + p->head.geom.x = x; + p->head.geom.y = y; + p->head.geom.w = w; + p->head.geom.h = h; + + if (p->st & 1) { + /* Horizontal line */ + g1.w = g2.w = MAX(0, p->head.geom.w - 2 * p->fw); + + if (p->st & 2) { + g2.h = p->of; + g1.h = MAX(0, p->head.geom.h - 2 * p->fw - p->of - p->lw); + } else { + g1.h = p->of; + g2.h = MAX(0, p->head.geom.h - 2 * p->fw - p->of - p->lw); + } + + g1.x = g2.x = x + p->fw; + g1.y = y + p->fw; + g2.y = y + p->fw + p->lw + g1.h; + } else { + /* Vertical line */ + g1.h = g2.h = MAX(0, p->head.geom.h - 2 * p->fw); + + if (p->st & 2) { + g2.w = p->of; + g1.w = MAX(0, p->head.geom.w - 2 * p->fw - p->of - p->lw); + } else { + g1.w = p->of; + g2.w = MAX(0, p->head.geom.w - 2 * p->fw - p->of - p->lw); + } + + g1.y = g2.y = x + p->fw; + g1.x = x + p->fw; + g2.x = x + p->fw + p->lw + g1.w; + } + + ui_panel_resize(p->x, g1.x, g1.y, g1.w, g1.h); + ui_panel_resize(p->y, g2.x, g2.y, g2.w, g2.h); + + return 0; +} |