263 lines
7.0 KiB
C
263 lines
7.0 KiB
C
/*
|
|
* draw
|
|
*
|
|
* Windowed graphical drawing tool.
|
|
* Simple painting application.
|
|
*
|
|
* This is also the playground for the work-in-progress
|
|
* ToaruToolKit GUI toolkit.
|
|
*/
|
|
#include <stdlib.h>
|
|
|
|
#include "lib/window.h"
|
|
#include "lib/graphics.h"
|
|
#include "lib/list.h"
|
|
#include "lib/shmemfonts.h"
|
|
#include "lib/decorations.h"
|
|
|
|
/* XXX TOOLKIT FUNCTIONS */
|
|
|
|
gfx_context_t * ctx;
|
|
window_t * wina;
|
|
|
|
/* Active TTK window XXX */
|
|
static window_t * ttk_window = NULL;
|
|
|
|
/* TTK Window's objects XXX */
|
|
static list_t * ttk_objects = NULL;
|
|
|
|
#define TTK_BUTTON_TYPE 0x00000001
|
|
|
|
/*
|
|
* Core TTK GUI object
|
|
*/
|
|
typedef struct {
|
|
uint32_t type; /* Object type indicator (for introspection) */
|
|
int32_t x; /* Coordinates */
|
|
int32_t y;
|
|
int32_t width; /* Sizes */
|
|
int32_t height;
|
|
void (*render_func)(void *); /* (Internal) function to render the object */
|
|
void (*click_callback)(void *, w_mouse_t *); /* Callback function for clicking */
|
|
} ttk_object;
|
|
|
|
/* TTK Button */
|
|
typedef struct {
|
|
ttk_object _super; /* Parent type (Object -> Button) */
|
|
char * title; /* Button text */
|
|
uint32_t fill_color; /* Fill color */
|
|
uint32_t fore_color; /* Text color */
|
|
} ttk_button;
|
|
|
|
void ttk_render_button(void * s) {
|
|
ttk_object * self = (ttk_object *)s;
|
|
/* Fill the button */
|
|
for (uint16_t y = self->y + 1; y < self->y + self->height; y++) {
|
|
draw_line(ctx, self->x, self->x + self->width, y, y, ((ttk_button *)self)->fill_color);
|
|
}
|
|
/* Then draw the border */
|
|
uint32_t border_color = rgb(0,0,0);
|
|
draw_line(ctx, self->x, self->x + self->width, self->y, self->y, border_color);
|
|
draw_line(ctx, self->x, self->x, self->y, self->y + self->height, border_color);
|
|
draw_line(ctx, self->x + self->width, self->x + self->width, self->y, self->y + self->height, border_color);
|
|
draw_line(ctx, self->x, self->x + self->width, self->y + self->height, self->y + self->height, border_color);
|
|
/* button-specific stuff */
|
|
uint32_t w = draw_string_width(((ttk_button * )self)->title);
|
|
uint16_t offset = (self->width - w) / 2;
|
|
draw_string(ctx, self->x + offset, self->y + self->height - 3, ((ttk_button *)self)->fore_color, ((ttk_button * )self)->title);
|
|
}
|
|
|
|
ttk_button * ttk_new_button(char * title, void (*callback)(void *, w_mouse_t *)) {
|
|
ttk_button * out = malloc(sizeof(ttk_button));
|
|
out->title = title;
|
|
out->fill_color = rgb(100,100,100);
|
|
|
|
/* Standard */
|
|
ttk_object * obj = (ttk_object *)out;
|
|
obj->click_callback = callback;;
|
|
obj->render_func = ttk_render_button;
|
|
obj->type = TTK_BUTTON_TYPE;
|
|
obj->x = 0;
|
|
obj->y = 0;
|
|
obj->width = 20;
|
|
obj->height = 20;
|
|
|
|
list_insert(ttk_objects, obj);
|
|
return out;
|
|
}
|
|
|
|
/*
|
|
* Reposition a TTK object
|
|
*/
|
|
void ttk_position(ttk_object * obj, int x, int y, int width, int height) {
|
|
obj->x = x;
|
|
obj->y = y;
|
|
obj->width = width;
|
|
obj->height = height;
|
|
}
|
|
|
|
int ttk_within(ttk_object * obj, w_mouse_t * evt) {
|
|
if (evt->new_x >= obj->x && evt->new_x < obj->x + obj->width &&
|
|
evt->new_y >= obj->y && evt->new_y < obj->y + obj->height) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void ttk_check_click(w_mouse_t * evt) {
|
|
if (evt->command == WE_MOUSECLICK) {
|
|
foreach(node, ttk_objects) {
|
|
ttk_object * obj = (ttk_object *)node->value;
|
|
if (ttk_within(obj, evt)) {
|
|
if (obj->click_callback) {
|
|
obj->click_callback(obj, evt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ttk_render() {
|
|
foreach(node, ttk_objects) {
|
|
ttk_object * obj = (ttk_object *)node->value;
|
|
if (obj->render_func) {
|
|
obj->render_func(obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
void setup_ttk(window_t * window) {
|
|
ttk_window = window;
|
|
ttk_objects = list_create();
|
|
mouse_action_callback = ttk_check_click;
|
|
init_shmemfonts();
|
|
}
|
|
|
|
uint32_t drawing_color = 0;
|
|
uint16_t quit = 0;
|
|
|
|
static void set_color(void * button, w_mouse_t * event) {
|
|
ttk_button * self = (ttk_button *)button;
|
|
drawing_color = self->fill_color;
|
|
}
|
|
|
|
static void quit_app(void * button, w_mouse_t * event) {
|
|
quit = 1;
|
|
teardown_windowing();
|
|
exit(0);
|
|
}
|
|
|
|
ttk_button * button_thick;
|
|
ttk_button * button_thin;
|
|
int thick = 0;
|
|
|
|
static void set_thickness_thick(void * button, w_mouse_t * event) {
|
|
button_thick->fill_color = rgb(127,127,127);
|
|
button_thick->fore_color = rgb(255,255,255);
|
|
button_thin->fill_color = rgb(40,40,40);
|
|
button_thin->fore_color = rgb(255,255,255);
|
|
thick = 1;
|
|
ttk_render();
|
|
}
|
|
|
|
static void set_thickness_thin(void * button, w_mouse_t * event) {
|
|
button_thin->fill_color = rgb(127,127,127);
|
|
button_thin->fore_color = rgb(255,255,255);
|
|
button_thick->fill_color = rgb(40,40,40);
|
|
button_thick->fore_color = rgb(255,255,255);
|
|
thick = 0;
|
|
ttk_render();
|
|
}
|
|
|
|
void decors(window_t * win) {
|
|
render_decorations(win, ctx, "Draw!");
|
|
}
|
|
|
|
void resize_callback(window_t * window) {
|
|
reinit_graphics_window(ctx, wina);
|
|
decors(wina);
|
|
ttk_render();
|
|
}
|
|
|
|
void focus_callback(window_t * window) {
|
|
decors(wina);
|
|
ttk_render();
|
|
}
|
|
|
|
int main (int argc, char ** argv) {
|
|
int left = 30;
|
|
int top = 30;
|
|
|
|
int width = 450;
|
|
int height = 450;
|
|
|
|
setup_windowing();
|
|
|
|
resize_window_callback = resize_callback;
|
|
focus_changed_callback = focus_callback;
|
|
|
|
/* Do something with a window */
|
|
wina = window_create(left, top, width, height);
|
|
ctx = init_graphics_window(wina);
|
|
draw_fill(ctx, rgb(255,255,255));
|
|
init_decorations();
|
|
|
|
win_use_threaded_handler();
|
|
|
|
setup_ttk(wina);
|
|
ttk_button * button_blue = ttk_new_button("Blue", set_color);
|
|
ttk_position((ttk_object *)button_blue, decor_left_width + 3, decor_top_height + 3, 100, 20);
|
|
button_blue->fill_color = rgb(0,0,255);
|
|
button_blue->fore_color = rgb(255,255,255);
|
|
|
|
ttk_button * button_green = ttk_new_button("Green", set_color);
|
|
ttk_position((ttk_object *)button_green, decor_left_width + 106, decor_top_height + 3, 100, 20);
|
|
button_green->fill_color = rgb(0,255,0);
|
|
button_green->fore_color = rgb(0,0,0);
|
|
|
|
ttk_button * button_red = ttk_new_button("Red", set_color);
|
|
ttk_position((ttk_object *)button_red, decor_left_width + 209, decor_top_height + 3, 100, 20);
|
|
button_red->fill_color = rgb(255,0,0);
|
|
button_red->fore_color = rgb(255,255,255);
|
|
|
|
button_thick = ttk_new_button("Thick", set_thickness_thick);
|
|
ttk_position((ttk_object *)button_thick, decor_left_width + 312, decor_top_height + 3, 50, 20);
|
|
button_thick->fill_color = rgb(40,40,40);
|
|
button_thick->fore_color = rgb(255,255,255);
|
|
|
|
button_thin = ttk_new_button("Thin", set_thickness_thin);
|
|
ttk_position((ttk_object *)button_thin, decor_left_width + 362, decor_top_height + 3, 50, 20);
|
|
button_thin->fill_color = rgb(127,127,127);
|
|
button_thin->fore_color = rgb(255,255,255);
|
|
|
|
ttk_button * button_quit = ttk_new_button("X", quit_app);
|
|
ttk_position((ttk_object *)button_quit, width - 33, 12, 20, 20);
|
|
button_quit->fill_color = rgb(255,0,0);
|
|
button_quit->fore_color = rgb(255,255,255);
|
|
|
|
drawing_color = rgb(255,0,0);
|
|
|
|
decors(wina);
|
|
ttk_render();
|
|
|
|
while (!quit) {
|
|
w_mouse_t * mouse = poll_mouse();
|
|
if (mouse != NULL) {
|
|
if (mouse->command == WE_MOUSEMOVE && mouse->buttons & MOUSE_BUTTON_LEFT) {
|
|
if (thick) {
|
|
draw_line_thick(ctx, mouse->old_x, mouse->new_x, mouse->old_y, mouse->new_y, drawing_color, 2);
|
|
} else {
|
|
draw_line(ctx, mouse->old_x, mouse->new_x, mouse->old_y, mouse->new_y, drawing_color);
|
|
}
|
|
decors(wina);
|
|
ttk_render();
|
|
}
|
|
free(mouse);
|
|
}
|
|
}
|
|
|
|
teardown_windowing();
|
|
|
|
return 0;
|
|
}
|