diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0c9b81 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +main diff --git a/box.c b/box.c index 083d141..33217c2 100644 --- a/box.c +++ b/box.c @@ -1,112 +1,136 @@ + +/* + * Copyright (C) Artsiom D. + * Copyright (C) shit-co.de + */ + + +#include +#include +#include +#include + #include "box.h" +#include "ui.h" +#include "util.h" -static void draw_rectangle(size_t x, size_t y, size_t width, size_t height) + +static void draw_rectangle(size_t x, size_t y, size_t width, size_t height); +static void draw_vertical(struct box *, size_t x, size_t y, size_t width, size_t height); +static void draw_horizontal(struct box *, size_t x, size_t y, size_t width, size_t height); +static void draw_button(struct box *, size_t x, size_t y, size_t width, size_t height); + + +static void +draw_rectangle(size_t x, size_t y, size_t width, size_t height) { - mvaddch(y, x, '+'); - mvaddch(y + height - 1, x, '+'); - mvaddch(y + height - 1, x + width - 1, '+'); - mvaddch(y, x + width - 1, '+'); + size_t w = width - 1; + size_t h = height - 1; - for (size_t i = 1; i < height - 1; i++) { - mvaddch(y + i, x, '|'); + /* corners */ + + ui_char(x, y, '+'); + ui_char(x, y + h, '+'); + ui_char(x + w, y + h, '+'); + ui_char(x + w, y, '+'); + + /* vertical borders */ + + for (size_t i = 1; i < h; i++) { + ui_char(x, y + i, '|'); } - for (size_t i = 1; i < height - 1; i++) { - mvaddch(y + i, x + width - 1, '|'); + for (size_t i = 1; i < h; i++) { + ui_char(x + w, y + i, '|'); } - for (size_t i = 1; i < width - 1; i++) { - mvaddch(y, x + i, '-'); + /* horizontal borders */ + + for (size_t i = 1; i < w; i++) { + ui_char(x + i, y, '-'); } - for (size_t i = 1; i < width - 1; i++) { - mvaddch(y + height - 1, x + i, '-'); + for (size_t i = 1; i < w; i++) { + ui_char(x + i, y + h, '-'); } } -void draw_button(struct box *b) -{ - draw_rectangle(x, y, b->width, b->height); - - if (b->highlighted) { - attron(A_UNDERLINE); - } - - attron(COLOR_PAIR(b->color)); - - mvaddstr(y + b->height / 2, x + b->width / 2 - strlen(b->name) / 2, b->name); - - if (b->highlighted) { - attroff(A_UNDERLINE); - } - - attroff(COLOR_PAIR(b->color)); -} - -void draw_chart(struct box *b, size_t x, size_t y, size_t width, size_t height) + +static void +draw_button(struct box *b, size_t x, size_t y, size_t width, size_t height) { + ui_color_on(b->color); draw_rectangle(x, y, width, height); - - size_t chart_width = width - 2; - size_t chart_height = height - 2; - size_t chart_x = x + 1; - size_t chart_y = y + 1; - - for (size_t i = 0; i < chart->length; i++) { - for (size_t j = 0; j < chart->prices[i]; j++) { - mvaddch(chart_height - (chart_y + j), chart_x * i, '?'); - } - } + ui_string(x + width / 2 - strlen(b->name) / 2, y + height / 2, b->name); + ui_color_off(b->color); } -void draw_vertical(struct box *b, size_t x, size_t y, size_t width, size_t height) + +static void +draw_horizontal(struct box *b, size_t x, size_t y, size_t width, size_t height) +{ + die("Don't call me"); +} + + +static void +draw_vertical(struct box *b, size_t x, size_t y, size_t width, size_t height) { - size_t total_pixels = 0; double total_fills = 0; for (size_t i = 0; i < b->length; i++) { - struct box *child = b->children[i]; - - switch (child.length.type) { - case LENGTH_PIXEL: - total_pixels += child.length.pixels; - break; - case LENGTH_FILL: - total_fills += child.length.fills; - break; - } + total_fills += b->children[i]->fills; } - size_t fill_pixels = height - total_pixels; - double pixels_per_fill = fill_pixels / total_fills; + double pixels_per_fill = (double)height / total_fills; - double current_y = 0; + double current_y = y; for (size_t i = 0; i < b->length; i++) { struct box *child = b->children[i]; - - double width; - - switch (child.length.type) { - case LENGTH_PIXEL: - width = child.length.pixels; - break; - case LENGTH_FILL: - width = child.length.fills * pixels_per_fill; - break; - } + double height = child->fills * pixels_per_fill; + draw_box(child, x, current_y, width, height); + current_y += height; } } -void draw_box(struct box *b, size_t x, size_t y, size_t width, size_t height) + +struct box * +new_button_box(char *name) +{ + struct box *button = malloc(sizeof(struct box)); + + button->type = BOX_BUTTON; + button->name = name; + button->fills = 1; + button->color = UI_RED; + + return button; +} + + +struct box * +new_vertical_box(void) +{ + struct box *box = emalloc(sizeof(struct box)); + + box->type = BOX_VERTICAL; + box->fills = 1; + box->color = UI_RED; + box->children = emalloc(sizeof(struct box *) * 100); + box->length = 0; + + return box; +} + + +void +draw_box(struct box *b, size_t x, size_t y, size_t width, size_t height) { switch (b->type) { case BOX_BUTTON: draw_button(b, x, y, width, height); break; - case BOX_CHART: - draw_chart(b, x, y, width, height); - break; case BOX_VERTICAL: draw_vertical(b, x, y, width, height); break; diff --git a/box.h b/box.h index bea1485..09af1b7 100644 --- a/box.h +++ b/box.h @@ -1,54 +1,44 @@ + +/* + * Copyright (C) Artsiom D. + * Copyright (C) shit-co.de + */ + + + #pragma once -#include "chart.h" +#include "ui.h" + enum box_type { - BOX_VERTICAL, - BOX_HORIZONTAL, - BOX_CHART, - BOX_BUTTON, -}; - -enum length_type { - LENGTH_FILL, - LENGTH_PIXEL, -}; - -struct length { - enum length_type type; - union { - double fill; - double pixel; - }; + BOX_VERTICAL, + BOX_HORIZONTAL, + BOX_BUTTON, }; struct box { - enum box_type; + enum box_type type; + enum ui_color color; + double fills; - size_t width; - size_t height; + union { + /* button */ + struct { + char *name; + }; - enum color color; - - union { - struct chart *chart; - - /* button */ - struct { - char *name; + /* container boxes */ + struct { + struct box **children; + size_t length; + }; }; - - /* container boxes */ - struct { - struct box *children; - size_t length; - }; - }; }; -box *new_chart_box(struct box *, size_t width, size_t height); -box *new_button_box(struct button *, size_t width, size_t height); -box *new_vertical_box(size_t width, size_t height); -box *new_horizontal_box(size_t width, size_t height); -void draw_box(struct box *); +struct box *new_button_box(char *name); +struct box *new_vertical_box(void); +struct box *new_horizontal_box(void); + +void draw_box(struct box *, size_t x, size_t y, size_t width, size_t height); diff --git a/license b/license new file mode 100644 index 0000000..a960c05 --- /dev/null +++ b/license @@ -0,0 +1,14 @@ +Copyright (c) 2025 shit-co.de + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + diff --git a/main.c b/main.c index 3b670e8..7dc2131 100644 --- a/main.c +++ b/main.c @@ -1,214 +1,35 @@ -#include -#include + +/* + * Copyright (C) Artsiom D. + * Copyright (C) shit-co.de + */ + + #include -#include -#include -#include -#include +#include -struct coin { - const char *name; - const char *description; - struct chart chart; -}; +#include "box.h" +#include "ui.h" -struct chart { - double *prices; - size_t length; -}; -struct chart new_chart(size_t length) +int +main(void) { - double *prices = malloc(length * sizeof(double)); + struct box *parent; - prices[0] = 20; - for (size_t i = 1; i < length; i++) { - prices[i] = prices[i - 1] + (rand() % 3 - 1.5); - } + ui_init(); - return (struct chart) { - .length = length, - .prices = prices - }; -} + parent = new_vertical_box(); -enum game_state { - GAME_BEGIN, - GAME_IDLE, - GAME_BUY, - GAME_SELL, - GAME_END, -}; + parent->length = 2; + parent->children[0] = new_button_box("hello!"); + parent->children[0]->color = UI_BLUE; + parent->children[1] = new_button_box("quit"); -enum color { - color_red, - color_green, - color_blue, -}; + draw_box(parent, 0, 0, 20, 30); + ui_refresh(); -struct button *new_button(char *name, enum color color, size_t width, size_t height) -{ - struct button *button = malloc(sizeof(struct button)); - button->name = name; - button->width = width; - button->height = height; - button->next = NULL; - button->color = color; - button->highlighted = false; - return button; -} - -struct game { - enum game_state state; - int bank; - struct coin coin; - struct button *button; -}; - -void draw_button(struct button *b, size_t x, size_t y) -{ - draw_box(x, y, b->width, b->height); - - if (b->highlighted) { - attron(A_UNDERLINE); - } - - attron(COLOR_PAIR(b->color)); - - mvaddstr(y + b->height / 2, x + b->width / 2 - strlen(b->name) / 2, b->name); - - if (b->highlighted) { - attroff(A_UNDERLINE); - } - - attroff(COLOR_PAIR(b->color)); -} - -void draw_chart(struct chart *chart, size_t x, size_t y) -{ - const size_t height = 30; - const size_t width = chart->length * 2 + 1; - - draw_box(x, y, width, height + 1); - - for (size_t i = 0; i < chart->length; i++) { - for (size_t j = 0; j < chart->prices[i]; j++) { - mvaddch(30 - (y + j), x + (i * 2) + 1, '?'); - } - } - - const size_t button_width = (double)(width) / 3; - - struct button *buy = new_button("buy", color_red, button_width, 5); - struct button *sell = new_button("sell", color_blue, button_width, 5); - struct button *scam = new_button("scam", color_green, button_width, 5); - - buy->next = sell; - sell->next = scam; - scam->next = buy; - - buy->highlighted = true; - - draw_button(buy, x, y + height + 1); - draw_button(sell, x + button_width, y + height + 1); - draw_button(scam, x + button_width * 2, y + height + 1); -} - -enum box_type { - BOX_TYPE_BUTTON, - BOX_TYPE_CHART, - BOX_TYPE_HORIZONTAL, - BOX_TYPE_VERTICAL, -}; - -struct box { - enum box_type type; - size_t width; - size_t height; - enum color color; - - union { - /* chart */ - struct { - double *prices; - size_t length; - }; - - /* button */ - char *name; - - /* horizontal/vertical box */ - struct { - struct box *children; - size_t length; - }; - } -}; - -void draw_game(struct game *game) -{ - clear(); - mvaddstr(0, 0, game->coin.name); - mvaddstr(1, 0, game->coin.description); - draw_chart(&game->coin.chart, 5, 5); - refresh(); -} - -struct box *new_chart_box() - -struct box *new_container_box(enum box_type type) -{ - struct box *box = malloc(sizeof(box)); - box->width = 0; - box->height = 0; - box->type = type; - box->children = malloc(sizeof(box) * 100); - box->length = 0; - return box; -} - -struct box *new_vertical_box(void) -{ - return new_container_box(BOX_TYPE_VERTICAL); -} - -struct box *new_horizontal_box(void) -{ - return new_container_box(BOX_TYPE_HORIZONTAL); -} - -struct box *new - -int main(void) -{ - srand(time(NULL)); - initscr(); - start_color(); - init_pair(color_green, COLOR_GREEN, COLOR_BLACK); - init_pair(color_red, COLOR_RED, COLOR_BLACK); - init_pair(color_blue, COLOR_BLUE, COLOR_BLACK); - cbreak(); - noecho(); - nonl(); - intrflush(stdscr, FALSE); - keypad(stdscr, TRUE); - clear(); - refresh(); - - struct game game = { - .state = GAME_BEGIN, - .bank = 1000, - .coin = (struct coin) { - .name = "Bitcoin", - .description = "A fucking scam.", - .chart = new_chart(30) - } - }; - - draw_game(&game); - - refresh(); - sleep(300); - endwin(); + + ui_end(); } diff --git a/makefile b/makefile index 18469f3..9c1a055 100644 --- a/makefile +++ b/makefile @@ -1,2 +1,14 @@ -CFLAGS = -lcurses -std=c23 -Wextra -pedantic -Wall -main: main.c +CFLAGS = -std=c23 -Wextra -pedantic -Wall -pedantic +LDFLAGS = -lncurses + +main: box.o main.o ui.o util.o + +.PHONY: clean + +box.o: box.c +main.o: main.c +ui.o: ui.c +util.o: util.c + +clean: + rm *.o main diff --git a/ui.c b/ui.c new file mode 100644 index 0000000..56fdf55 --- /dev/null +++ b/ui.c @@ -0,0 +1,64 @@ + +/* + * Copyright (C) Artsiom D. + * Copyright (C) shit-co.de + */ + + +#include +#include +#include +#include "ui.h" + + +void ui_init(void) +{ + srand(time(NULL)); + initscr(); + start_color(); + init_pair(UI_GREEN, COLOR_GREEN, COLOR_BLACK); + init_pair(UI_RED, COLOR_RED, COLOR_BLACK); + init_pair(UI_BLUE, COLOR_BLUE, COLOR_BLACK); + cbreak(); + noecho(); + nonl(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + clear(); + refresh(); +} + +void ui_end() +{ + endwin(); +} + +void ui_string(size_t x, size_t y, char *s) +{ + mvaddstr(y, x, s); +} + +void ui_char(size_t x, size_t y, char c) +{ + mvaddch(y, x, c); +} + +void ui_color_on(enum ui_color c) +{ + attron(COLOR_PAIR(c)); +} + +void ui_color_off(enum ui_color c) +{ + attroff(COLOR_PAIR(c)); +} + +void ui_refresh(void) +{ + refresh(); +} + +void ui_clear(void) +{ + clear(); +} diff --git a/ui.h b/ui.h new file mode 100644 index 0000000..40c90ba --- /dev/null +++ b/ui.h @@ -0,0 +1,28 @@ + +/* + * Copyright (C) Artsiom D. + * Copyright (C) shit-co.de + */ + + +#pragma once + + +enum ui_color { + UI_RED = 1, + UI_GREEN, + UI_BLUE, +}; + + +void ui_init(void); +void ui_end(void); + +void ui_color_on(enum ui_color); +void ui_color_off(enum ui_color); + +void ui_char(size_t x, size_t y, char c); +void ui_string(size_t x, size_t y, char *s); + +void ui_refresh(void); +void ui_clear(void); diff --git a/util.c b/util.c new file mode 100644 index 0000000..c3727b5 --- /dev/null +++ b/util.c @@ -0,0 +1,34 @@ + +/* + * Copyright (C) Artsiom D. + * Copyright (C) shit-co.de + */ + + +#include +#include +#include +#include "util.h" + + +void * +emalloc(size_t n) +{ + void *p = malloc(n); + if (p == NULL) { + die("malloc fail\n"); + } + + return p; +} + + +void +die(char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); + exit(1); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..d7f02bd --- /dev/null +++ b/util.h @@ -0,0 +1,14 @@ + +/* + * Copyright (C) Artsiom D. + * Copyright (C) shit-co.de + */ + + +#pragma once + +#include + + +void *emalloc(size_t n); +void die(char *fmt, ...);