Refactoring, license, Box UI framework
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.o
|
||||
main
|
||||
172
box.c
172
box.c
@@ -1,112 +1,136 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Artsiom D.
|
||||
* Copyright (C) shit-co.de
|
||||
*/
|
||||
|
||||
|
||||
#include <curses.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
|
||||
72
box.h
72
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);
|
||||
|
||||
14
license
Normal file
14
license
Normal file
@@ -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.
|
||||
|
||||
225
main.c
225
main.c
@@ -1,214 +1,35 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* Copyright (C) Artsiom D.
|
||||
* Copyright (C) shit-co.de
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <curses.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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();
|
||||
draw_box(parent, 0, 0, 20, 30);
|
||||
ui_refresh();
|
||||
|
||||
sleep(300);
|
||||
endwin();
|
||||
|
||||
ui_end();
|
||||
}
|
||||
|
||||
16
makefile
16
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
|
||||
|
||||
64
ui.c
Normal file
64
ui.c
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Artsiom D.
|
||||
* Copyright (C) shit-co.de
|
||||
*/
|
||||
|
||||
|
||||
#include <curses.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#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();
|
||||
}
|
||||
28
ui.h
Normal file
28
ui.h
Normal file
@@ -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);
|
||||
34
util.c
Normal file
34
util.c
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Artsiom D.
|
||||
* Copyright (C) shit-co.de
|
||||
*/
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
||||
Reference in New Issue
Block a user