Replace Draw, kill C TTK
This commit is contained in:
parent
2d35aebc03
commit
dbe7a93865
@ -1,483 +0,0 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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/yutani.h"
|
||||
#include "gui/ttk/ttk.h"
|
||||
#include "lib/list.h"
|
||||
|
||||
/* XXX TOOLKIT FUNCTIONS */
|
||||
|
||||
gfx_context_t * ctx;
|
||||
yutani_window_t * wina;
|
||||
yutani_t * yctx;
|
||||
|
||||
/* Active TTK window XXX */
|
||||
static yutani_window_t * ttk_window = NULL;
|
||||
|
||||
/* TTK Window's objects XXX */
|
||||
static list_t * ttk_objects = NULL;
|
||||
|
||||
#define TTK_BUTTON_TYPE 0x00000001
|
||||
#define TTK_RAW_SURFACE_TYPE 0x00000002
|
||||
|
||||
#define TTK_BUTTON_STATE_NORMAL 0
|
||||
#define TTK_BUTTON_STATE_DOWN 1
|
||||
|
||||
cairo_surface_t * internal_surface;
|
||||
|
||||
/*
|
||||
* 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 *, cairo_t * cr); /* (Internal) function to render the object */
|
||||
void (*click_callback)(void *, struct yutani_msg_window_mouse_event *); /* 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 */
|
||||
int button_state;
|
||||
} ttk_button;
|
||||
|
||||
typedef struct {
|
||||
ttk_object _super;
|
||||
gfx_context_t * surface;
|
||||
} ttk_raw_surface;
|
||||
|
||||
void ttk_render_button(void * s, cairo_t * cr) {
|
||||
ttk_object * self = (ttk_object *)s;
|
||||
|
||||
if (((ttk_button *)self)->button_state == TTK_BUTTON_STATE_DOWN) {
|
||||
_ttk_draw_button_select(cr, self->x, self->y, self->width, self->height, ((ttk_button *)self)->title);
|
||||
} else {
|
||||
_ttk_draw_button(cr, self->x, self->y, self->width, self->height, ((ttk_button *)self)->title);
|
||||
}
|
||||
#if 0
|
||||
/* 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);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ttk_render_raw_surface(void * s, cairo_t * cr) {
|
||||
ttk_object * self = (ttk_object *)s;
|
||||
|
||||
gfx_context_t * surface = ((ttk_raw_surface *)self)->surface;
|
||||
|
||||
{
|
||||
cairo_save(cr);
|
||||
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, surface->width);
|
||||
cairo_surface_t * internal_surface = cairo_image_surface_create_for_data(surface->backbuffer, CAIRO_FORMAT_ARGB32, surface->width, surface->height, stride);
|
||||
|
||||
cairo_set_source_surface(cr, internal_surface, self->x, self->y);
|
||||
cairo_paint(cr);
|
||||
|
||||
cairo_surface_destroy(internal_surface);
|
||||
cairo_restore(cr);
|
||||
}
|
||||
}
|
||||
|
||||
ttk_button * ttk_button_new(char * title, void (*callback)(void *, struct yutani_msg_window_mouse_event *)) {
|
||||
ttk_button * out = malloc(sizeof(ttk_button));
|
||||
out->title = title;
|
||||
out->fill_color = rgb(100,100,100);
|
||||
out->button_state = TTK_BUTTON_STATE_NORMAL;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
ttk_raw_surface * ttk_raw_surface_new(int width, int height) {
|
||||
ttk_raw_surface * out = malloc(sizeof(ttk_raw_surface));
|
||||
|
||||
ttk_object * obj = (ttk_object *)out;
|
||||
|
||||
out->surface = malloc(sizeof(gfx_context_t));
|
||||
out->surface->width = width;
|
||||
out->surface->height = height;
|
||||
out->surface->depth = 32;
|
||||
out->surface->buffer = malloc(sizeof(uint32_t) * width * height);
|
||||
out->surface->backbuffer = out->surface->buffer;
|
||||
|
||||
draw_fill(out->surface, rgb(255,255,255));
|
||||
|
||||
obj->width = width;
|
||||
obj->height = height;
|
||||
obj->x = decor_left_width + 4;
|
||||
obj->y = decor_top_height + 4;
|
||||
|
||||
obj->click_callback = NULL;
|
||||
obj->type = TTK_RAW_SURFACE_TYPE;
|
||||
|
||||
obj->render_func = ttk_render_raw_surface;
|
||||
|
||||
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, struct yutani_msg_window_mouse_event * 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(struct yutani_msg_window_mouse_event * evt) {
|
||||
if (evt->command == YUTANI_MOUSE_EVENT_CLICK) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (evt->command == YUTANI_MOUSE_EVENT_DOWN) {
|
||||
fprintf(stderr, "Mouse down: %d, %d\n", evt->new_x, evt->new_y);
|
||||
}
|
||||
}
|
||||
|
||||
void ttk_render() {
|
||||
/* XXX */
|
||||
ttk_window_t _window;
|
||||
ttk_window_t * window = &_window;
|
||||
|
||||
window->core_context = ctx;
|
||||
window->core_window = ttk_window;
|
||||
window->width = ctx->width; // - decor_width();
|
||||
window->height = ctx->height; //- decor_height();
|
||||
window->off_x = 0; //decor_left_width;
|
||||
window->off_y = 0; //decor_top_height;
|
||||
window->title = "Draw!";
|
||||
|
||||
draw_fill(ctx, rgb(TTK_BACKGROUND_DEFAULT));
|
||||
ttk_redraw_borders(window);
|
||||
|
||||
{
|
||||
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, window->core_window->width);
|
||||
cairo_surface_t * core_surface = cairo_image_surface_create_for_data(window->core_context->backbuffer, CAIRO_FORMAT_ARGB32, window->core_window->width, window->core_window->height, stride);
|
||||
cairo_t * cr_main = cairo_create(core_surface);
|
||||
|
||||
/* TODO move this surface to a ttk_frame_t or something; GUIs man, go look at some Qt or GTK APIs! */
|
||||
cairo_surface_t * internal_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, window->width, window->height);
|
||||
cairo_t * cr = cairo_create(internal_surface);
|
||||
|
||||
foreach(node, ttk_objects) {
|
||||
ttk_object * obj = (ttk_object *)node->value;
|
||||
if (obj->render_func) {
|
||||
obj->render_func(obj, cr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Paint the window's internal surface onto the backbuffer */
|
||||
cairo_set_source_surface(cr_main, internal_surface, (double)window->off_x, (double)window->off_y);
|
||||
cairo_paint(cr_main);
|
||||
cairo_surface_flush(internal_surface);
|
||||
cairo_destroy(cr);
|
||||
cairo_surface_destroy(internal_surface);
|
||||
|
||||
/* In theory, we don't actually want to destroy much of any of this; maybe the cairo_t */
|
||||
cairo_surface_flush(core_surface);
|
||||
cairo_destroy(cr_main);
|
||||
cairo_surface_destroy(core_surface);
|
||||
}
|
||||
|
||||
flip(window->core_context);
|
||||
yutani_flip(yctx, wina);
|
||||
}
|
||||
|
||||
void setup_ttk(yutani_window_t * window) {
|
||||
ttk_window = window;
|
||||
ttk_objects = list_create();
|
||||
init_shmemfonts();
|
||||
}
|
||||
|
||||
uint32_t drawing_color = 0;
|
||||
uint16_t quit = 0;
|
||||
|
||||
ttk_button * button_red;
|
||||
ttk_button * button_green;
|
||||
ttk_button * button_blue;
|
||||
|
||||
ttk_button * button_thick;
|
||||
ttk_button * button_thin;
|
||||
ttk_raw_surface * drawing_surface;
|
||||
int thick = 0;
|
||||
|
||||
static void set_color(void * button, struct yutani_msg_window_mouse_event * event) {
|
||||
ttk_button * self = (ttk_button *)button;
|
||||
|
||||
if (button_blue != self) button_blue->button_state = TTK_BUTTON_STATE_NORMAL;
|
||||
if (button_red != self) button_red->button_state = TTK_BUTTON_STATE_NORMAL;
|
||||
if (button_green != self) button_green->button_state = TTK_BUTTON_STATE_NORMAL;
|
||||
|
||||
self->button_state = TTK_BUTTON_STATE_DOWN;
|
||||
drawing_color = self->fill_color;
|
||||
|
||||
ttk_render();
|
||||
}
|
||||
|
||||
static void set_thickness_thick(void * button, struct yutani_msg_window_mouse_event * event) {
|
||||
#if 0
|
||||
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);
|
||||
#endif
|
||||
button_thick->button_state = TTK_BUTTON_STATE_DOWN;
|
||||
button_thin->button_state = TTK_BUTTON_STATE_NORMAL;
|
||||
thick = 1;
|
||||
ttk_render();
|
||||
}
|
||||
|
||||
static void set_thickness_thin(void * button, struct yutani_msg_window_mouse_event * event) {
|
||||
#if 0
|
||||
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);
|
||||
#endif
|
||||
button_thin->button_state = TTK_BUTTON_STATE_DOWN;
|
||||
button_thick->button_state = TTK_BUTTON_STATE_NORMAL;
|
||||
thick = 0;
|
||||
ttk_render();
|
||||
}
|
||||
|
||||
static void resize_finish(int width, int height) {
|
||||
yutani_window_resize_accept(yctx, wina, width, height);
|
||||
reinit_graphics_yutani(ctx, wina);
|
||||
ttk_render();
|
||||
yutani_window_resize_done(yctx, wina);
|
||||
yutani_flip(yctx, wina);
|
||||
}
|
||||
|
||||
static void resize_button(void * button, struct yutani_msg_window_mouse_event * event) {
|
||||
yutani_window_resize(yctx, wina, 600, 600);
|
||||
yutani_msg_t * m = yutani_wait_for(yctx, YUTANI_MSG_RESIZE_OFFER);
|
||||
struct yutani_msg_window_resize * wr = (void*)m->data;
|
||||
resize_finish(wr->width, wr->height);
|
||||
free(m);
|
||||
}
|
||||
|
||||
void keep_drawing(struct yutani_msg_window_mouse_event * mouse) {
|
||||
double thickness = thick ? 2.0 : 0.5;;
|
||||
|
||||
int old_x = mouse->old_x - ((ttk_object *)drawing_surface)->x;
|
||||
int old_y = mouse->old_y - ((ttk_object *)drawing_surface)->y;
|
||||
|
||||
int new_x = mouse->new_x - ((ttk_object *)drawing_surface)->x;
|
||||
int new_y = mouse->new_y - ((ttk_object *)drawing_surface)->y;
|
||||
|
||||
{
|
||||
cairo_t * cr = cairo_create(internal_surface);
|
||||
|
||||
cairo_set_source_rgb(cr, _RED(drawing_color) / 255.0, _GRE(drawing_color) / 255.0, _BLU(drawing_color) / 255.0);
|
||||
cairo_set_line_width(cr, thickness);
|
||||
|
||||
cairo_move_to(cr, old_x, old_y);
|
||||
cairo_line_to(cr, new_x, new_y);
|
||||
|
||||
cairo_stroke(cr);
|
||||
|
||||
cairo_destroy(cr);
|
||||
}
|
||||
|
||||
{
|
||||
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, wina->width);
|
||||
cairo_surface_t * core_surface = cairo_image_surface_create_for_data(ctx->backbuffer, CAIRO_FORMAT_ARGB32, wina->width, wina->height, stride);
|
||||
cairo_t * cr = cairo_create(core_surface);
|
||||
|
||||
cairo_rectangle(cr, ((ttk_object*)drawing_surface)->x, ((ttk_object*)drawing_surface)->y, ((ttk_object*)drawing_surface)->width, ((ttk_object*)drawing_surface)->height);
|
||||
cairo_clip(cr);
|
||||
|
||||
cairo_set_source_rgb(cr, _RED(drawing_color) / 255.0, _GRE(drawing_color) / 255.0, _BLU(drawing_color) / 255.0);
|
||||
cairo_set_line_width(cr, thickness);
|
||||
|
||||
cairo_move_to(cr, old_x + ((ttk_object*)drawing_surface)->x, old_y + ((ttk_object*)drawing_surface)->y);
|
||||
cairo_line_to(cr, new_x + ((ttk_object*)drawing_surface)->x, new_y + ((ttk_object*)drawing_surface)->y);
|
||||
|
||||
cairo_stroke(cr);
|
||||
cairo_destroy(cr);
|
||||
cairo_surface_destroy(core_surface);
|
||||
|
||||
flip(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
int left = 30;
|
||||
int top = 30;
|
||||
|
||||
int width = 450;
|
||||
int height = 450;
|
||||
|
||||
yctx = yutani_init();
|
||||
|
||||
init_decorations();
|
||||
|
||||
/* Do something with a window */
|
||||
wina = yutani_window_create(yctx, width + decor_width(), height+decor_height());
|
||||
yutani_window_move(yctx, wina, 100, 100);
|
||||
|
||||
ctx = init_graphics_yutani_double_buffer(wina);
|
||||
draw_fill(ctx, rgba(0,0,0,0));
|
||||
|
||||
yutani_window_advertise_icon(yctx, wina, "Draw!", "applications-painting");
|
||||
|
||||
setup_ttk(wina);
|
||||
|
||||
|
||||
button_blue = ttk_button_new("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);
|
||||
|
||||
button_green = ttk_button_new("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);
|
||||
|
||||
button_red = ttk_button_new("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_button_new("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_button_new("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_resize = ttk_button_new("*", resize_button);
|
||||
ttk_position((ttk_object *)button_resize, decor_left_width + 410, decor_top_height + 3, 20, 20);
|
||||
button_resize->fill_color = rgb(127,127,127);
|
||||
button_resize->fore_color = rgb(255,255,255);
|
||||
|
||||
drawing_surface = ttk_raw_surface_new(width - 30, height - 70);
|
||||
((ttk_object *)drawing_surface)->y += 19;
|
||||
|
||||
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, drawing_surface->surface->width);
|
||||
internal_surface = cairo_image_surface_create_for_data(drawing_surface->surface->backbuffer, CAIRO_FORMAT_ARGB32, drawing_surface->surface->width, drawing_surface->surface->height, stride);
|
||||
|
||||
drawing_color = rgb(255,0,0);
|
||||
|
||||
ttk_render();
|
||||
|
||||
while (!quit) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
if (m) {
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
struct yutani_msg_key_event * ke = (void*)m->data;
|
||||
if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') {
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
|
||||
{
|
||||
struct yutani_msg_window_focus_change * wf = (void*)m->data;
|
||||
yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
|
||||
if (win) {
|
||||
win->focused = wf->focused;
|
||||
ttk_render();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
{
|
||||
struct yutani_msg_window_mouse_event * me = (void*)m->data;
|
||||
if (decor_handle_event(yctx, m) == DECOR_CLOSE) {
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
if (me->command == YUTANI_MOUSE_EVENT_DRAG && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) {
|
||||
keep_drawing(me);
|
||||
yutani_flip(yctx, wina);
|
||||
} else if (me->command == YUTANI_MOUSE_EVENT_RAISE) {
|
||||
ttk_render();
|
||||
} else {
|
||||
ttk_check_click(me);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_RESIZE_OFFER:
|
||||
{
|
||||
struct yutani_msg_window_resize * wr = (void*)m->data;
|
||||
resize_finish(wr->width, wr->height);
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
quit = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(m);
|
||||
}
|
||||
}
|
||||
|
||||
yutani_close(yctx, wina);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,471 +0,0 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013-2014 Kevin Lange
|
||||
*/
|
||||
/*
|
||||
*
|
||||
* Toolkit Demo and Development Application
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
#include "lib/decorations.h"
|
||||
|
||||
#include "../ttk.h"
|
||||
|
||||
/* TTK {{{ */
|
||||
|
||||
static yutani_t * yctx;
|
||||
/* XXX ttk_app_t ? */
|
||||
static hashmap_t * ttk_wids_to_windows;
|
||||
|
||||
void cairo_rounded_rectangle(cairo_t * cr, double x, double y, double width, double height, double radius) {
|
||||
double degrees = M_PI / 180.0;
|
||||
|
||||
cairo_new_sub_path(cr);
|
||||
cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
|
||||
cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
|
||||
cairo_arc (cr, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
|
||||
cairo_arc (cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
|
||||
cairo_close_path(cr);
|
||||
}
|
||||
|
||||
|
||||
void ttk_redraw_borders(ttk_window_t * window) {
|
||||
render_decorations(window->core_window, window->core_context, window->title);
|
||||
}
|
||||
|
||||
void _ttk_draw_button(cairo_t * cr, int x, int y, int width, int height, char * title) {
|
||||
cairo_save(cr);
|
||||
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
|
||||
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
|
||||
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source_rgba(cr, 44.0/255.0, 71.0/255.0, 91.0/255.0, 29.0/255.0);
|
||||
cairo_set_line_width(cr, 4);
|
||||
cairo_stroke(cr);
|
||||
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source_rgba(cr, 158.0/255.0, 169.0/255.0, 177.0/255.0, 1.0);
|
||||
cairo_set_line_width(cr, 2);
|
||||
cairo_stroke(cr);
|
||||
|
||||
{
|
||||
cairo_pattern_t * pat = cairo_pattern_create_linear(2 + x, 2 + y, 2 + x, 2 + y + height - 4);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 0, 1, 1, 1, 1);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 1, 241.0/255.0, 241.0/255.0, 244.0/255.0, 1);
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source(cr, pat);
|
||||
cairo_fill(cr);
|
||||
cairo_pattern_destroy(pat);
|
||||
}
|
||||
|
||||
{
|
||||
cairo_pattern_t * pat = cairo_pattern_create_linear(3 + x, 3 + y, 3 + x, 3 + y + height - 4);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 0, 252.0/255.0, 252.0/255.0, 254.0/255.0, 1);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 1, 223.0/255.0, 225.0/255.0, 230.0/255.0, 1);
|
||||
cairo_rounded_rectangle(cr, 3 + x, 3 + y, width - 5, height - 5, 2.0);
|
||||
cairo_set_source(cr, pat);
|
||||
cairo_fill(cr);
|
||||
cairo_pattern_destroy(pat);
|
||||
}
|
||||
|
||||
{
|
||||
cairo_surface_t * surface = cairo_get_target(cr);
|
||||
gfx_context_t fake_context = {
|
||||
.width = cairo_image_surface_get_width(surface),
|
||||
.height = cairo_image_surface_get_height(surface),
|
||||
.depth = 32,
|
||||
.buffer = NULL,
|
||||
.backbuffer = cairo_image_surface_get_data(surface)
|
||||
};
|
||||
|
||||
set_font_face(FONT_SANS_SERIF);
|
||||
set_font_size(13);
|
||||
|
||||
int str_width = draw_string_width(title);
|
||||
draw_string(&fake_context, (width - str_width) / 2 + x, y + (height) / 2 + 4, rgb(49,49,49), title);
|
||||
}
|
||||
|
||||
cairo_restore(cr);
|
||||
}
|
||||
|
||||
void _ttk_draw_button_hover(cairo_t * cr, int x, int y, int width, int height, char * title) {
|
||||
cairo_save(cr);
|
||||
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
|
||||
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
|
||||
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source_rgba(cr, 44.0/255.0, 71.0/255.0, 91.0/255.0, 29.0/255.0);
|
||||
cairo_set_line_width(cr, 4);
|
||||
cairo_stroke(cr);
|
||||
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source_rgba(cr, 158.0/255.0, 169.0/255.0, 177.0/255.0, 1.0);
|
||||
cairo_set_line_width(cr, 2);
|
||||
cairo_stroke(cr);
|
||||
|
||||
{
|
||||
cairo_pattern_t * pat = cairo_pattern_create_linear(2 + x, 2 + y, 2 + x, 2 + y + height - 4);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 0, 1, 1, 1, 1);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 1, 229.0/255.0, 229.0/255.0, 246.0/255.0, 1);
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source(cr, pat);
|
||||
cairo_fill(cr);
|
||||
cairo_pattern_destroy(pat);
|
||||
}
|
||||
|
||||
{
|
||||
cairo_pattern_t * pat = cairo_pattern_create_linear(3 + x, 3 + y, 3 + x, 3 + y + height - 4);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 0, 252.0/255.0, 252.0/255.0, 254.0/255.0, 1);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 1, 212.0/255.0, 223.0/255.0, 251.0/255.0, 1);
|
||||
cairo_rounded_rectangle(cr, 3 + x, 3 + y, width - 5, height - 5, 2.0);
|
||||
cairo_set_source(cr, pat);
|
||||
cairo_fill(cr);
|
||||
cairo_pattern_destroy(pat);
|
||||
}
|
||||
|
||||
{
|
||||
cairo_surface_t * surface = cairo_get_target(cr);
|
||||
gfx_context_t fake_context = {
|
||||
.width = cairo_image_surface_get_width(surface),
|
||||
.height = cairo_image_surface_get_height(surface),
|
||||
.depth = 32,
|
||||
.buffer = NULL,
|
||||
.backbuffer = cairo_image_surface_get_data(surface)
|
||||
};
|
||||
|
||||
set_font_face(FONT_SANS_SERIF);
|
||||
set_font_size(13);
|
||||
|
||||
int str_width = draw_string_width(title);
|
||||
draw_string(&fake_context, (width - str_width) / 2 + x, y + (height) / 2 + 4, rgb(49,49,49), title);
|
||||
}
|
||||
|
||||
cairo_restore(cr);
|
||||
|
||||
}
|
||||
|
||||
void _ttk_draw_button_select(cairo_t * cr, int x, int y, int width, int height, char * title) {
|
||||
cairo_save(cr);
|
||||
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
|
||||
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
|
||||
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source_rgba(cr, 134.0/255.0, 173.0/255.0, 201.0/255.0, 1.0);
|
||||
cairo_set_line_width(cr, 2);
|
||||
cairo_stroke(cr);
|
||||
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source_rgba(cr, 202.0/255.0, 211.0/255.0, 232.0/255.0, 1.0);
|
||||
cairo_fill(cr);
|
||||
|
||||
{
|
||||
cairo_surface_t * surface = cairo_get_target(cr);
|
||||
gfx_context_t fake_context = {
|
||||
.width = cairo_image_surface_get_width(surface),
|
||||
.height = cairo_image_surface_get_height(surface),
|
||||
.depth = 32,
|
||||
.buffer = NULL,
|
||||
.backbuffer = cairo_image_surface_get_data(surface)
|
||||
};
|
||||
|
||||
set_font_face(FONT_SANS_SERIF);
|
||||
set_font_size(13);
|
||||
|
||||
int str_width = draw_string_width(title);
|
||||
draw_string(&fake_context, (width - str_width) / 2 + x, y + (height) / 2 + 4, rgb(49,49,49), title);
|
||||
}
|
||||
|
||||
cairo_restore(cr);
|
||||
|
||||
}
|
||||
|
||||
void _ttk_draw_button_disabled(cairo_t * cr, int x, int y, int width, int height, char * title) {
|
||||
cairo_save(cr);
|
||||
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
|
||||
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
|
||||
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source_rgba(cr, 44.0/255.0, 71.0/255.0, 91.0/255.0, 29.0/255.0);
|
||||
cairo_set_line_width(cr, 4);
|
||||
cairo_stroke(cr);
|
||||
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source_rgba(cr, 152.0/255.0, 152.0/255.0, 152.0/255.0, 1.0);
|
||||
cairo_set_line_width(cr, 2);
|
||||
cairo_stroke(cr);
|
||||
|
||||
{
|
||||
cairo_pattern_t * pat = cairo_pattern_create_linear(2 + x, 2 + y, 2 + x, 2 + y + height - 4);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 0, 229.0/255.0, 229.0/255.0, 229.0/255.0, 1);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 1, 178.0/255.0, 178.0/255.0, 178.0/255.0, 1);
|
||||
cairo_rounded_rectangle(cr, 2 + x, 2 + y, width - 4, height - 4, 2.0);
|
||||
cairo_set_source(cr, pat);
|
||||
cairo_fill(cr);
|
||||
cairo_pattern_destroy(pat);
|
||||
}
|
||||
|
||||
{
|
||||
cairo_pattern_t * pat = cairo_pattern_create_linear(3 + x, 3 + y, 3 + x, 3 + y + height - 4);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 0, 210.0/255.0, 210.0/255.0, 210.0/255.0, 1);
|
||||
cairo_pattern_add_color_stop_rgba(pat, 1, 165.0/255.0, 166.0/255.0, 170.0/255.0, 1);
|
||||
cairo_rounded_rectangle(cr, 3 + x, 3 + y, width - 5, height - 5, 2.0);
|
||||
cairo_set_source(cr, pat);
|
||||
cairo_fill(cr);
|
||||
cairo_pattern_destroy(pat);
|
||||
}
|
||||
|
||||
{
|
||||
cairo_surface_t * surface = cairo_get_target(cr);
|
||||
gfx_context_t fake_context = {
|
||||
.width = cairo_image_surface_get_width(surface),
|
||||
.height = cairo_image_surface_get_height(surface),
|
||||
.depth = 32,
|
||||
.buffer = NULL,
|
||||
.backbuffer = cairo_image_surface_get_data(surface)
|
||||
};
|
||||
|
||||
set_font_face(FONT_SANS_SERIF);
|
||||
set_font_size(13);
|
||||
|
||||
int str_width = draw_string_width(title);
|
||||
draw_string(&fake_context, (width - str_width) / 2 + x, y + (height) / 2 + 4, rgb(100,100,100), title);
|
||||
}
|
||||
|
||||
cairo_restore(cr);
|
||||
}
|
||||
|
||||
#define TTK_MENU_HEIGHT 24
|
||||
|
||||
void _ttk_draw_menu(cairo_t * cr, int x, int y, int width) {
|
||||
cairo_save(cr);
|
||||
|
||||
int height = TTK_MENU_HEIGHT;
|
||||
cairo_set_source_rgba(cr, 59.0/255.0, 59.0/255.0, 59.0/255.0, 1);
|
||||
cairo_rectangle(cr, x, y, width, height);
|
||||
cairo_fill(cr);
|
||||
|
||||
{
|
||||
cairo_surface_t * surface = cairo_get_target(cr);
|
||||
gfx_context_t fake_context = {
|
||||
.width = cairo_image_surface_get_width(surface),
|
||||
.height = cairo_image_surface_get_height(surface),
|
||||
.depth = 32,
|
||||
.buffer = NULL,
|
||||
.backbuffer = cairo_image_surface_get_data(surface)
|
||||
};
|
||||
|
||||
set_font_face(FONT_SANS_SERIF);
|
||||
set_font_size(13);
|
||||
|
||||
draw_string(&fake_context, x + 8, y + height - 6, rgb(248,248,248), "File");
|
||||
}
|
||||
|
||||
|
||||
cairo_restore(cr);
|
||||
}
|
||||
|
||||
void ttk_window_draw(ttk_window_t * window) {
|
||||
draw_fill(window->core_context, rgb(TTK_BACKGROUND_DEFAULT));
|
||||
ttk_redraw_borders(window);
|
||||
|
||||
/* TODO actual drawing */
|
||||
{
|
||||
/* TODO move these surfaces into the ttk_window_t object */
|
||||
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, window->core_window->width);
|
||||
cairo_surface_t * core_surface = cairo_image_surface_create_for_data(window->core_context->backbuffer, CAIRO_FORMAT_ARGB32, window->core_window->width, window->core_window->height, stride);
|
||||
cairo_t * cr_main = cairo_create(core_surface);
|
||||
|
||||
/* TODO move this surface to a ttk_frame_t or something; GUIs man, go look at some Qt or GTK APIs! */
|
||||
cairo_surface_t * internal_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, window->width, window->height);
|
||||
cairo_t * cr = cairo_create(internal_surface);
|
||||
|
||||
_ttk_draw_menu(cr, 0, 0, window->width);
|
||||
|
||||
_ttk_draw_button(cr, 4, TTK_MENU_HEIGHT + 4, window->width - 8, 40, "Regular Button");
|
||||
|
||||
_ttk_draw_button(cr, 4, TTK_MENU_HEIGHT + 48 + 4, (window->width / 2) - 8, 40, "Regular Button");
|
||||
_ttk_draw_button_hover(cr, 4 + (window->width / 2), TTK_MENU_HEIGHT + 48 + 4, (window->width / 2) - 8, 40, "Hover Button");
|
||||
|
||||
_ttk_draw_button_select(cr, 4, TTK_MENU_HEIGHT + 2 * 48 + 4, (window->width / 2) - 8, 40, "Selected");
|
||||
_ttk_draw_button_disabled(cr, 4 + (window->width / 2), TTK_MENU_HEIGHT + 2 * 48 + 4, (window->width / 2) - 8, 40, "Disabled Button");
|
||||
|
||||
_ttk_draw_button(cr, 4, TTK_MENU_HEIGHT + 3 * 48 + 4, window->width - 8, window->height - (3 * 48) - TTK_MENU_HEIGHT - 8, "Regular Button");
|
||||
|
||||
/* Paint the window's internal surface onto the backbuffer */
|
||||
cairo_set_source_surface(cr_main, internal_surface, (double)window->off_x, (double)window->off_y);
|
||||
cairo_paint(cr_main);
|
||||
cairo_surface_flush(internal_surface);
|
||||
cairo_destroy(cr);
|
||||
cairo_surface_destroy(internal_surface);
|
||||
|
||||
/* In theory, we don't actually want to destroy much of any of this; maybe the cairo_t */
|
||||
cairo_surface_flush(core_surface);
|
||||
cairo_destroy(cr_main);
|
||||
cairo_surface_destroy(core_surface);
|
||||
}
|
||||
|
||||
flip(window->core_context);
|
||||
yutani_flip(yctx, window->core_window);
|
||||
}
|
||||
|
||||
void ttk_move_callback(ttk_window_t * window_ttk, int x, int y) {
|
||||
if (!window_ttk) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX Do we want to do things with the old position? */
|
||||
|
||||
window_ttk->x = x;
|
||||
window_ttk->y = y;
|
||||
|
||||
}
|
||||
|
||||
void ttk_resize_callback(ttk_window_t * window_ttk, int width, int height) {
|
||||
if (!window_ttk) {
|
||||
fprintf(stderr, "[ttk] received window callback for a window not registered with TTK, ignoring.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
yutani_window_resize_accept(yctx, window_ttk->core_window, width, height);
|
||||
|
||||
/* Update window size */
|
||||
window_ttk->width = width - decor_width();
|
||||
window_ttk->height = height - decor_height();
|
||||
|
||||
/* Reinitialize graphics context */
|
||||
reinit_graphics_yutani(window_ttk->core_context, window_ttk->core_window);
|
||||
|
||||
ttk_window_draw(window_ttk);
|
||||
|
||||
yutani_window_resize_done(yctx, window_ttk->core_window);
|
||||
yutani_flip(yctx, window_ttk->core_window);
|
||||
}
|
||||
|
||||
void ttk_focus_callback(ttk_window_t * window_ttk, int focused) {
|
||||
if (!window_ttk) {
|
||||
fprintf(stderr, "[ttk] received window callback for a window not registered with TTK, ignoring.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
window_ttk->core_window->focused = focused;
|
||||
ttk_window_draw(window_ttk);
|
||||
}
|
||||
|
||||
|
||||
void ttk_initialize() {
|
||||
/* Connect to the windowing server */
|
||||
yctx = yutani_init();
|
||||
|
||||
/* Initialize the decoration library */
|
||||
init_decorations();
|
||||
|
||||
ttk_wids_to_windows = hashmap_create_int(5); /* wids are ints, ergo... */
|
||||
}
|
||||
|
||||
ttk_window_t * ttk_window_new(char * title, uint16_t width, uint16_t height) {
|
||||
ttk_window_t * new_win = malloc(sizeof(ttk_window_t));
|
||||
new_win->title = strdup(title);
|
||||
new_win->width = width;
|
||||
new_win->height = height;
|
||||
new_win->off_x = decor_left_width;
|
||||
new_win->off_y = decor_top_height;
|
||||
|
||||
new_win->core_window = yutani_window_create(yctx, new_win->width + decor_width(), new_win->height + decor_height());
|
||||
yutani_window_move(yctx, new_win->core_window, TTK_DEFAULT_X, TTK_DEFAULT_Y);
|
||||
assert(new_win->core_window && "Oh dear, I've failed to allocate a new window from the server. This is terrible.");
|
||||
|
||||
/* XXX icon; also need to do this if we change the title later */
|
||||
yutani_window_advertise(yctx, new_win->core_window, new_win->title);
|
||||
|
||||
new_win->core_context = init_graphics_yutani_double_buffer(new_win->core_window);
|
||||
draw_fill(new_win->core_context, rgb(TTK_BACKGROUND_DEFAULT));
|
||||
|
||||
ttk_window_draw(new_win);
|
||||
|
||||
hashmap_set(ttk_wids_to_windows, (void*)new_win->core_window->wid, new_win);
|
||||
}
|
||||
|
||||
void ttk_quit() {
|
||||
list_t * windows = hashmap_values(ttk_wids_to_windows);
|
||||
|
||||
foreach(node, windows) {
|
||||
ttk_window_t * win = node->value;
|
||||
yutani_close(yctx, win->core_window);
|
||||
}
|
||||
|
||||
list_free(windows);
|
||||
free(windows);
|
||||
hashmap_free(ttk_wids_to_windows);
|
||||
free(ttk_wids_to_windows);
|
||||
}
|
||||
|
||||
int ttk_run(ttk_window_t * window) {
|
||||
while (1) {
|
||||
yutani_msg_t * m = yutani_poll(yctx);
|
||||
if (m) {
|
||||
switch (m->type) {
|
||||
case YUTANI_MSG_KEY_EVENT:
|
||||
{
|
||||
struct yutani_msg_key_event * ke = (void*)m->data;
|
||||
if (ke->event.action == KEY_ACTION_DOWN && ke->event.keycode == 'q') {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
|
||||
{
|
||||
struct yutani_msg_window_focus_change * fc = (void*)m->data;
|
||||
ttk_focus_callback(hashmap_get(ttk_wids_to_windows, (void*)fc->wid), fc->focused);
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_RESIZE_OFFER:
|
||||
{
|
||||
struct yutani_msg_window_resize * wr = (void*)m->data;
|
||||
ttk_resize_callback(hashmap_get(ttk_wids_to_windows, (void*)wr->wid), wr->width, wr->height);
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOVE:
|
||||
{
|
||||
struct yutani_msg_window_move * wm = (void*)m->data;
|
||||
ttk_move_callback(hashmap_get(ttk_wids_to_windows, (void*)wm->wid), wm->x, wm->y);
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_WINDOW_MOUSE_EVENT:
|
||||
{
|
||||
struct yutani_msg_window_mouse_event * me = (void*)m->data;
|
||||
if (decor_handle_event(yctx, m) == DECOR_CLOSE) {
|
||||
goto done;
|
||||
}
|
||||
if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) {
|
||||
ttk_window_t * win = hashmap_get(ttk_wids_to_windows, (void*)me->wid);
|
||||
if (win) {
|
||||
/* Do something */
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YUTANI_MSG_SESSION_END:
|
||||
goto done;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(m);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
ttk_quit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* }}} end TTK */
|
@ -1,21 +0,0 @@
|
||||
/* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2013 Kevin Lange
|
||||
*/
|
||||
/*
|
||||
*
|
||||
* Toolkit Demo and Development Application
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "gui/ttk/ttk.h"
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
|
||||
ttk_initialize();
|
||||
ttk_window_t * main_window = ttk_window_new("TTK Demo", 500, 500);
|
||||
|
||||
return ttk_run(main_window);
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
#ifndef _TTK_H
|
||||
#define _TTK_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <cairo.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_CACHE_H
|
||||
|
||||
#include "lib/yutani.h"
|
||||
#include "lib/graphics.h"
|
||||
#include "lib/decorations.h"
|
||||
#include "lib/shmemfonts.h"
|
||||
#include "lib/hashmap.h"
|
||||
|
||||
typedef struct ttk_window {
|
||||
yutani_window_t * core_window;
|
||||
gfx_context_t * core_context;
|
||||
char * title;
|
||||
cairo_surface_t * cairo_surface;
|
||||
uint16_t width; /* internal space */
|
||||
uint16_t height;
|
||||
uint16_t off_x; /* decor_left_width */
|
||||
uint16_t off_y; /* decor_top_height */
|
||||
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} ttk_window_t;
|
||||
|
||||
#define TTK_BACKGROUND_DEFAULT 204,204,204
|
||||
#define TTK_DEFAULT_X 300
|
||||
#define TTK_DEFAULT_Y 300
|
||||
|
||||
void cairo_rounded_rectangle(cairo_t * cr, double x, double y, double width, double height, double radius);
|
||||
void ttk_redraw_borders(ttk_window_t * window);
|
||||
void _ttk_draw_button(cairo_t * cr, int x, int y, int width, int height, char * title);
|
||||
void _ttk_draw_button_hover(cairo_t * cr, int x, int y, int width, int height, char * title);
|
||||
void _ttk_draw_button_select(cairo_t * cr, int x, int y, int width, int height, char * title);
|
||||
void _ttk_draw_button_disabled(cairo_t * cr, int x, int y, int width, int height, char * title);
|
||||
void _ttk_draw_menu(cairo_t * cr, int x, int y, int width);
|
||||
void ttk_window_draw(ttk_window_t * window);
|
||||
void ttk_initialize();
|
||||
ttk_window_t * ttk_window_new(char * title, uint16_t width, uint16_t height);
|
||||
void ttk_quit();
|
||||
int ttk_run(ttk_window_t * window);
|
||||
|
||||
|
||||
#endif
|
260
userspace/py/bin/painting.py
Executable file
260
userspace/py/bin/painting.py
Executable file
@ -0,0 +1,260 @@
|
||||
#!/usr/bin/python3
|
||||
"""
|
||||
Painting
|
||||
"""
|
||||
import os
|
||||
import math
|
||||
import stat
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
import cairo
|
||||
|
||||
import yutani
|
||||
import text_region
|
||||
import toaru_fonts
|
||||
import toaru_package
|
||||
|
||||
from color_picker import ColorPickerWindow
|
||||
|
||||
from menu_bar import MenuBarWidget, MenuEntryAction, MenuEntrySubmenu, MenuEntryDivider, MenuWindow
|
||||
from icon_cache import get_icon
|
||||
|
||||
version = "0.1.0"
|
||||
_description = f"<b>ToaruPaint {version}</b>\n© 2017 Kevin Lange\n\nDraw stuff, maybe.\n\n<color 0x0000FF>http://github.com/klange/toaruos</color>"
|
||||
|
||||
class PaintingWindow(yutani.Window):
|
||||
|
||||
base_width = 600
|
||||
base_height = 600
|
||||
|
||||
def __init__(self, decorator):
|
||||
super(PaintingWindow, self).__init__(self.base_width + decorator.width(), self.base_height + decorator.height(), title="ToaruPaint", icon="applications-painting", doublebuffer=True)
|
||||
self.move(100,100)
|
||||
self.x = 100
|
||||
self.y = 100
|
||||
self.decorator = decorator
|
||||
self.picker = None
|
||||
self.last_color = (0,0,0)
|
||||
|
||||
def exit_app(action):
|
||||
menus = [x for x in self.menus.values()]
|
||||
for x in menus:
|
||||
x.definitely_close()
|
||||
self.close()
|
||||
sys.exit(0)
|
||||
|
||||
def about_window(action):
|
||||
subprocess.Popen(["about-applet.py","About ToaruPaint","applications-painting","/usr/share/icons/48/applications-painting.png",_description])
|
||||
|
||||
def help_browser(action):
|
||||
subprocess.Popen(["help-browser.py","painting.trt"])
|
||||
|
||||
def close_picker():
|
||||
self.last_color = self.picker.color
|
||||
self.picker = None
|
||||
|
||||
def select_color(action):
|
||||
if self.picker:
|
||||
return
|
||||
else:
|
||||
self.picker = ColorPickerWindow(self.decorator, close_picker)
|
||||
self.picker.draw()
|
||||
|
||||
menus = [
|
||||
("File", [
|
||||
MenuEntryAction("Exit","exit",exit_app,None),
|
||||
]),
|
||||
("Tools", [
|
||||
MenuEntryAction("Color",None,select_color,None),
|
||||
]),
|
||||
("Help", [
|
||||
MenuEntryAction("Contents","help",help_browser,None),
|
||||
MenuEntryDivider(),
|
||||
MenuEntryAction("About ToaruPaint","star",about_window,None),
|
||||
]),
|
||||
]
|
||||
|
||||
self.menubar = MenuBarWidget(self,menus)
|
||||
|
||||
self.menus = {}
|
||||
self.hovered_menu = None
|
||||
|
||||
self.buf = yutani.GraphicsBuffer(500,500)
|
||||
self.surface = self.buf.get_cairo_surface()
|
||||
self.draw_ctx = cairo.Context(self.surface)
|
||||
self.draw_ctx.rectangle(0,0,self.surface.get_width(),self.surface.get_height())
|
||||
self.draw_ctx.set_source_rgb(1,1,1)
|
||||
self.draw_ctx.fill()
|
||||
|
||||
self.hilighted = None
|
||||
self.was_drawing = False
|
||||
self.line_width = 1.0
|
||||
self.curs_x = None
|
||||
self.curs_y = None
|
||||
|
||||
def color(self):
|
||||
if self.picker:
|
||||
return self.picker.color
|
||||
else:
|
||||
return self.last_color
|
||||
|
||||
def draw(self):
|
||||
surface = self.get_cairo_surface()
|
||||
|
||||
WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height()
|
||||
|
||||
ctx = cairo.Context(surface)
|
||||
ctx.translate(self.decorator.left_width(), self.decorator.top_height())
|
||||
ctx.rectangle(0,0,WIDTH,HEIGHT)
|
||||
ctx.set_source_rgb(0.5,0.5,0.5)
|
||||
ctx.fill()
|
||||
|
||||
ctx.save()
|
||||
ctx.translate(0,self.menubar.height)
|
||||
ctx.set_source_surface(self.surface,0,0)
|
||||
ctx.paint()
|
||||
|
||||
if not self.curs_x is None:
|
||||
ctx.arc(self.curs_x,self.curs_y,self.line_width/2,0,2*math.pi)
|
||||
ctx.set_line_width(0.5)
|
||||
ctx.set_source_rgba(0,0,0,0.7)
|
||||
ctx.stroke()
|
||||
ctx.arc(self.curs_x,self.curs_y,self.line_width/2-0.5,0,2*math.pi)
|
||||
ctx.set_line_width(0.5)
|
||||
ctx.set_source_rgba(1,1,1,0.7)
|
||||
ctx.stroke()
|
||||
|
||||
ctx.restore()
|
||||
|
||||
self.menubar.draw(ctx,0,0,WIDTH)
|
||||
|
||||
self.decorator.render(self)
|
||||
self.flip()
|
||||
|
||||
def finish_resize(self, msg):
|
||||
"""Accept a resize."""
|
||||
if msg.width < 120 or msg.height < 120:
|
||||
self.resize_offer(max(msg.width,120),max(msg.height,120))
|
||||
return
|
||||
self.resize_accept(msg.width, msg.height)
|
||||
self.reinit()
|
||||
self.draw()
|
||||
self.resize_done()
|
||||
self.flip()
|
||||
|
||||
def mouse_event(self, msg):
|
||||
if d.handle_event(msg) == yutani.Decor.EVENT_CLOSE:
|
||||
window.close()
|
||||
sys.exit(0)
|
||||
x,y = msg.new_x - self.decorator.left_width(), msg.new_y - self.decorator.top_height()
|
||||
w,h = self.width - self.decorator.width(), self.height - self.decorator.height()
|
||||
|
||||
if not self.was_drawing:
|
||||
self.curs_x = None
|
||||
self.curs_y = None
|
||||
if x >= 0 and x < w and y >= 0 and y < self.menubar.height:
|
||||
self.menubar.mouse_event(msg, x, y)
|
||||
return
|
||||
|
||||
if x < 0 or x >= w or y < 0 or y >= h:
|
||||
return
|
||||
|
||||
if x >= 0 and x < w and y >= self.menubar.height and y < h:
|
||||
if msg.buttons & yutani.MouseButton.BUTTON_RIGHT:
|
||||
if not self.menus:
|
||||
menu_entries = [
|
||||
MenuEntryAction("Up",None,self.go_up,None),
|
||||
]
|
||||
menu = MenuWindow(menu_entries,(self.x+msg.new_x,self.y+msg.new_y),root=self)
|
||||
return
|
||||
|
||||
if y < 0: return
|
||||
|
||||
if msg.buttons & yutani.MouseButton.SCROLL_UP:
|
||||
self.line_width *= 1.2
|
||||
elif msg.buttons & yutani.MouseButton.SCROLL_DOWN:
|
||||
self.line_width /= 1.2
|
||||
|
||||
redraw = False
|
||||
|
||||
if not (msg.buttons & yutani.MouseButton.BUTTON_LEFT):
|
||||
self.was_drawing = False
|
||||
|
||||
if msg.command == yutani.MouseEvent.DRAG and msg.buttons & yutani.MouseButton.BUTTON_LEFT:
|
||||
self.was_drawing = True
|
||||
self.draw_ctx.set_line_cap(cairo.LINE_CAP_ROUND)
|
||||
self.draw_ctx.set_line_join(cairo.LINE_JOIN_ROUND)
|
||||
self.draw_ctx.set_source_rgb(*self.color())
|
||||
self.draw_ctx.set_line_width(self.line_width)
|
||||
self.draw_ctx.move_to(0.5+msg.old_x - self.decorator.left_width(), 0.5+msg.old_y - self.decorator.top_height() - self.menubar.height);
|
||||
self.draw_ctx.line_to(0.5+msg.new_x - self.decorator.left_width(), 0.5+msg.new_y - self.decorator.top_height() - self.menubar.height);
|
||||
self.draw_ctx.stroke()
|
||||
|
||||
|
||||
self.curs_x = 0.5+msg.new_x - self.decorator.left_width()
|
||||
self.curs_y = 0.5+msg.new_y - self.decorator.top_height() - self.menubar.height
|
||||
self.draw()
|
||||
|
||||
def keyboard_event(self, msg):
|
||||
if msg.event.action != yutani.KeyAction.ACTION_DOWN:
|
||||
return # Ignore anything that isn't a key down.
|
||||
if msg.event.key == b"q":
|
||||
self.close()
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
yutani.Yutani()
|
||||
d = yutani.Decor()
|
||||
|
||||
window = PaintingWindow(d)
|
||||
window.draw()
|
||||
|
||||
while 1:
|
||||
# Poll for events.
|
||||
msg = yutani.yutani_ctx.poll()
|
||||
if msg.type == yutani.Message.MSG_SESSION_END:
|
||||
window.close()
|
||||
break
|
||||
elif msg.type == yutani.Message.MSG_KEY_EVENT:
|
||||
if msg.wid == window.wid:
|
||||
window.keyboard_event(msg)
|
||||
elif msg.wid in window.menus:
|
||||
window.menus[msg.wid].keyboard_event(msg)
|
||||
elif msg.type == yutani.Message.MSG_WINDOW_FOCUS_CHANGE:
|
||||
if msg.wid == window.wid:
|
||||
if msg.focused == 0 and window.menus:
|
||||
window.focused = 1
|
||||
else:
|
||||
window.focused = msg.focused
|
||||
window.draw()
|
||||
elif msg.wid in window.menus and msg.focused == 0:
|
||||
window.menus[msg.wid].leave_menu()
|
||||
if not window.menus and window.focused:
|
||||
window.focused = 0
|
||||
window.draw()
|
||||
elif window.picker and msg.wid == window.picker.wid:
|
||||
window.picker.focused = msg.focused
|
||||
window.picker.draw()
|
||||
elif msg.type == yutani.Message.MSG_RESIZE_OFFER:
|
||||
if msg.wid == window.wid:
|
||||
window.finish_resize(msg)
|
||||
elif window.picker and msg.wid == window.picker.wid:
|
||||
window.picker.resize_finish(msg)
|
||||
elif msg.type == yutani.Message.MSG_WINDOW_MOVE:
|
||||
if msg.wid == window.wid:
|
||||
window.x = msg.x
|
||||
window.y = msg.y
|
||||
elif msg.type == yutani.Message.MSG_WINDOW_MOUSE_EVENT:
|
||||
if msg.wid == window.wid:
|
||||
window.mouse_event(msg)
|
||||
elif msg.wid in window.menus:
|
||||
m = window.menus[msg.wid]
|
||||
if msg.new_x >= 0 and msg.new_x < m.width and msg.new_y >= 0 and msg.new_y < m.height:
|
||||
window.hovered_menu = m
|
||||
elif window.hovered_menu == m:
|
||||
window.hovered_menu = None
|
||||
m.mouse_action(msg)
|
||||
elif window.picker and msg.wid == window.picker.wid:
|
||||
window.picker.mouse_event(msg)
|
||||
|
@ -339,7 +339,7 @@ class ApplicationsMenuWidget(BaseWidget):
|
||||
]
|
||||
games.extend(self.extra('games'))
|
||||
graphics = [
|
||||
MenuEntryAction("Draw!","applications-painting",launch_app,"draw"),
|
||||
MenuEntryAction("ToaruPaint","applications-painting",launch_app,"painting.py"),
|
||||
]
|
||||
graphics.extend(self.extra('graphics'))
|
||||
settings = [
|
||||
|
240
userspace/py/lib/color_picker.py
Executable file
240
userspace/py/lib/color_picker.py
Executable file
@ -0,0 +1,240 @@
|
||||
#!/usr/bin/python3
|
||||
"""
|
||||
Color picker
|
||||
"""
|
||||
import colorsys
|
||||
import math
|
||||
import sys
|
||||
|
||||
import cairo
|
||||
|
||||
import yutani
|
||||
|
||||
def s(p1,p2,p3):
|
||||
return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1])
|
||||
|
||||
def dist(a,b):
|
||||
return math.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2)
|
||||
|
||||
def closest_point(pt, v1, v2):
|
||||
ap = (pt[0] - v1[0]),(pt[1] - v1[1])
|
||||
ab = (v2[0] - v1[0]),(v2[1] - v1[1])
|
||||
ab2 = ab[0]**2 + ab[1]**2
|
||||
ap_ab = ap[0]*ab[0] + ap[1]*ab[1]
|
||||
t = ap_ab / ab2
|
||||
return (v1[0] + ab[0] * t, v1[1] + ab[1] * t)
|
||||
|
||||
def point_inside(pt, v1, v2, v3):
|
||||
a = s(pt,v1,v2)
|
||||
b = s(pt,v2,v3)
|
||||
c = s(pt,v3,v1)
|
||||
return (a < 0) == (b < 0) == (c < 0)
|
||||
|
||||
class ColorPickerWindow(yutani.Window):
|
||||
|
||||
base_width = 200
|
||||
|
||||
def __init__(self, decorator, close_callback):
|
||||
super(ColorPickerWindow,self).__init__(self.base_width + decorator.width(), self.base_width + decorator.height(), title="Color Picker", doublebuffer=True)
|
||||
self.move(100,100)
|
||||
self.decorator = decorator
|
||||
self.close_callback = close_callback
|
||||
|
||||
self.hue = math.radians(240)
|
||||
self.angle = -self.hue
|
||||
self.pat = cairo.MeshGradient()
|
||||
self.pat.begin_patch()
|
||||
self.pat.move_to(-1.0,0.0)
|
||||
self.pat.curve_to(-1.0,0.3886666666666667,-0.7746666666666667,0.742,-0.4226666666666667,0.906)
|
||||
self.pat.curve_to(-0.12666666666666668,1.044,0.2173333333333333,1.0293333333333334,0.5,0.866)
|
||||
self.pat.curve_to(0.8093333333333331,0.6873333333333332,1.0,0.3573333333333333,1.0,0.0)
|
||||
self.pat.set_corner_color_rgb (0, 0, 1, 1)
|
||||
self.pat.set_corner_color_rgb (1, 0, 0, 1)
|
||||
self.pat.set_corner_color_rgb (2, 1, 0, 1)
|
||||
self.pat.set_corner_color_rgb (3, 1, 0, 0)
|
||||
self.pat.end_patch()
|
||||
self.pat.begin_patch()
|
||||
self.pat.move_to(-1.0,0.0)
|
||||
self.pat.curve_to(-1.0,-0.3886666666666667,-0.7746666666666667,-0.742,-0.4226666666666667,-0.906)
|
||||
self.pat.curve_to(-0.12666666666666668,-1.044,0.2173333333333333,-1.0293333333333334,0.5,-0.866)
|
||||
self.pat.curve_to(0.8093333333333331,-0.6873333333333332,1.0,-0.3573333333333333,1.0,0.0)
|
||||
self.pat.set_corner_color_rgb (0, 0, 1, 1)
|
||||
self.pat.set_corner_color_rgb (1, 0, 1, 0)
|
||||
self.pat.set_corner_color_rgb (2, 1, 1, 0)
|
||||
self.pat.set_corner_color_rgb (3, 1, 0, 0)
|
||||
self.pat.end_patch()
|
||||
|
||||
self.dit_th = 0.0
|
||||
self.dit_r = 0.0
|
||||
self.color = (0,0,0)
|
||||
|
||||
self.v1,self.v2,self.v3 = (0,0),(0,0),(0,0)
|
||||
|
||||
self.down_in_circle = False
|
||||
self.down_in_triangle = False
|
||||
|
||||
def draw(self):
|
||||
surface = self.get_cairo_surface()
|
||||
|
||||
WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height()
|
||||
|
||||
ctx = cairo.Context(surface)
|
||||
ctx.translate(self.decorator.left_width(),self.decorator.top_height())
|
||||
ctx.rectangle(0,0,WIDTH,HEIGHT)
|
||||
ctx.set_source_rgb(204/255,204/255,204/255)
|
||||
ctx.fill()
|
||||
ctx.scale (WIDTH/2.0, HEIGHT/2.0)
|
||||
ctx.translate(1,1)
|
||||
|
||||
# Draw the concentric circles for the hue selection.
|
||||
ctx.arc(0.0,0.0,1.0,0,2*math.pi)
|
||||
ctx.set_fill_rule(cairo.FILL_RULE_EVEN_ODD)
|
||||
ctx.arc(0.0,0.0,0.8,0,2*math.pi)
|
||||
ctx.set_source (self.pat)
|
||||
ctx.fill()
|
||||
|
||||
self.v1 = math.cos(self.angle+4*math.pi/3)*0.8,math.sin(self.angle+4*math.pi/3)*0.8
|
||||
self.v2 = math.cos(self.angle+6*math.pi/3)*0.8,math.sin(self.angle+6*math.pi/3)*0.8
|
||||
self.v3 = math.cos(self.angle+8*math.pi/3)*0.8,math.sin(self.angle+8*math.pi/3)*0.8
|
||||
|
||||
# Temporary pattern for inner triangle.
|
||||
pat2 = cairo.MeshGradient()
|
||||
pat2.begin_patch()
|
||||
pat2.move_to(*self.v3)
|
||||
pat2.line_to(*self.v1)
|
||||
pat2.line_to(*self.v2)
|
||||
pat2.line_to(*self.v3)
|
||||
pat2.set_corner_color_rgb (0, 1, 1, 1)
|
||||
pat2.set_corner_color_rgb (1, 0, 0, 0)
|
||||
pat2.set_corner_color_rgb (2, *colorsys.hsv_to_rgb(self.hue/(2*math.pi),1.0,1.0))
|
||||
pat2.set_corner_color_rgb (3, 1, 1, 1)
|
||||
pat2.end_patch()
|
||||
|
||||
ctx.move_to(*self.v3)
|
||||
ctx.line_to(*self.v1)
|
||||
ctx.line_to(*self.v2)
|
||||
ctx.line_to(*self.v3)
|
||||
ctx.set_source (pat2)
|
||||
ctx.fill()
|
||||
|
||||
ctx.set_line_width(0.04)
|
||||
ctx.move_to(*self.v2)
|
||||
ctx.line_to(self.v2[0]/0.8,self.v2[1]/0.8)
|
||||
ctx.set_source_rgb(0,0,0)
|
||||
ctx.stroke()
|
||||
|
||||
dit_x,dit_y = math.cos(math.radians(self.dit_th)+self.angle)*self.dit_r,math.sin(math.radians(self.dit_th)+self.angle)*self.dit_r
|
||||
|
||||
ctx.set_line_width(0.02)
|
||||
ctx.arc(dit_x,dit_y,0.05,0,2*math.pi)
|
||||
ctx.set_source_rgb(0,0,0)
|
||||
ctx.stroke()
|
||||
|
||||
dit = dit_x,dit_y
|
||||
sat_p = closest_point(dit,self.v1,self.v2)
|
||||
exp_p = closest_point(dit,self.v1,self.v3)
|
||||
m_exp = closest_point(self.v2,self.v1,self.v3)
|
||||
m_sat = closest_point(self.v3,self.v1,self.v2)
|
||||
white_amount = dist(sat_p,dit)/dist(m_sat,self.v3)
|
||||
mix_amount = dist(exp_p,dit)/dist(m_exp,self.v2)
|
||||
r,g,b = colorsys.hsv_to_rgb(self.hue/(2*math.pi),1.0,1.0)
|
||||
_r = white_amount * 1.0 + mix_amount * r
|
||||
_g = white_amount * 1.0 + mix_amount * g
|
||||
_b = white_amount * 1.0 + mix_amount * b
|
||||
self.color = (_r,_g,_b)
|
||||
ctx.arc(-0.85,-0.85,0.1,0,2*math.pi)
|
||||
ctx.set_source_rgb(_r,_g,_b)
|
||||
ctx.fill()
|
||||
|
||||
self.decorator.render(self)
|
||||
self.flip()
|
||||
|
||||
def finish_resize(self,msg):
|
||||
"""Accept a resize."""
|
||||
WIDTH, HEIGHT = msg.width - d.width(), msg.height - d.height()
|
||||
if WIDTH != HEIGHT:
|
||||
self.resize_offer(WIDTH+d.width(),WIDTH+d.height())
|
||||
return
|
||||
self.resize_accept(msg.width, msg.height)
|
||||
self.reinit()
|
||||
self.draw()
|
||||
self.resize_done()
|
||||
self.flip()
|
||||
|
||||
def mouse_event(self,msg):
|
||||
if self.decorator.handle_event(msg) == yutani.Decor.EVENT_CLOSE:
|
||||
# Close the window when the 'X' button is clicked.
|
||||
self.close()
|
||||
self.close_callback()
|
||||
if msg.buttons & yutani.MouseButton.BUTTON_LEFT:
|
||||
WIDTH, HEIGHT = self.width - self.decorator.width(), self.height - self.decorator.height()
|
||||
x = msg.new_x - self.decorator.left_width() - WIDTH/2
|
||||
y = msg.new_y - self.decorator.top_height() - HEIGHT/2
|
||||
r = math.sqrt(x*x + y*y)/(WIDTH/2)
|
||||
a = 0
|
||||
if x > 0 and y > 0:
|
||||
a = math.degrees(math.atan(y/x))
|
||||
if y == 0 and x < 0:
|
||||
a = 180
|
||||
if x == 0 and y > 0:
|
||||
a = 90
|
||||
if x == 0 and y < 0:
|
||||
a = 90*3
|
||||
if x < 0 and y > 0:
|
||||
a = 180 + math.degrees(math.atan(y/x))
|
||||
if x < 0 and y < 0:
|
||||
a = 180 + math.degrees(math.atan(y/x))
|
||||
if x > 0 and y < 0:
|
||||
a = 360 + math.degrees(math.atan(y/x))
|
||||
if msg.command == yutani.MouseEvent.DOWN:
|
||||
self.down_in_circle = False
|
||||
self.down_in_triangle = False
|
||||
if r < 0.8:
|
||||
self.down_in_triangle = True
|
||||
elif r <= 1.0:
|
||||
self.down_in_circle = True
|
||||
if self.down_in_triangle:
|
||||
_x,_y = x/WIDTH*2, y/HEIGHT*2
|
||||
if point_inside((_x,_y),self.v1,self.v2,self.v3):
|
||||
self.dit_th = a - math.degrees(self.angle)
|
||||
self.dit_r = r
|
||||
self.draw()
|
||||
if self.down_in_circle:
|
||||
self.hue = math.radians(360-a)
|
||||
self.angle = -self.hue
|
||||
self.draw()
|
||||
if msg.command == yutani.MouseEvent.RAISE or msg.command == yutani.MouseEvent.CLICK:
|
||||
self.down_in_circle = False
|
||||
self.down_in_triangel = False
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Connect to the server.
|
||||
yutani.Yutani()
|
||||
d = yutani.Decor()
|
||||
|
||||
def on_close():
|
||||
sys.exit(0)
|
||||
|
||||
w = ColorPickerWindow(d,on_close)
|
||||
w.draw()
|
||||
|
||||
while 1:
|
||||
# Poll for events.
|
||||
msg = yutani.yutani_ctx.poll()
|
||||
if msg.type == yutani.Message.MSG_SESSION_END:
|
||||
w.close()
|
||||
sys.exit(0)
|
||||
elif msg.type == yutani.Message.MSG_KEY_EVENT:
|
||||
if msg.event.key == b'q':
|
||||
w.close()
|
||||
sys.exit(0)
|
||||
elif msg.type == yutani.Message.MSG_WINDOW_FOCUS_CHANGE:
|
||||
if msg.wid == w.wid:
|
||||
w.focused = msg.focused
|
||||
w.draw()
|
||||
elif msg.type == yutani.Message.MSG_RESIZE_OFFER:
|
||||
if msg.wid == w.wid:
|
||||
w.resize_finish(msg)
|
||||
elif msg.type == yutani.Message.MSG_WINDOW_MOUSE_EVENT:
|
||||
if msg.wid == w.wid:
|
||||
w.mouse_event(msg)
|
@ -49,7 +49,6 @@ class Classifier(object):
|
||||
# Yutani Libraries
|
||||
'"lib/yutani.h"': (None, '-ltoaru-yutani', ['"lib/kbd.h"', '"lib/list.h"', '"lib/pex.h"', '"lib/graphics.h"', '"lib/hashmap.h"']),
|
||||
'"lib/decorations.h"': (None, '-ltoaru-decorations', ['"lib/shmemfonts.h"', '"lib/graphics.h"', '"lib/yutani.h"','"lib/dlfcn.h"']),
|
||||
'"gui/ttk/ttk.h"': (None, '-ltoaru-ttk', ['"lib/decorations.h"', '"lib/hashmap.h"', '<cairo.h>', '<math.h>']),
|
||||
'"gui/terminal/lib/termemu.h"': (None, '-ltoaru-termemu', ['"lib/graphics.h"']),
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user