Back the canvas with a real bitmap
The first step towards making this actually useful. Also the canvas can be now scrolled with the middle mouse button.
This commit is contained in:
parent
47e6e7fa23
commit
de3c8b89bb
181
autistdraw.c
181
autistdraw.c
|
@ -17,6 +17,9 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#define PALETTE_WIDTH 9 ///< Width of the palette
|
#define PALETTE_WIDTH 9 ///< Width of the palette
|
||||||
|
#define TOP_BAR_CUTOFF 3 ///< Height of the top bar
|
||||||
|
|
||||||
|
#define BITMAP_BLOCK_SIZE 50 ///< Step for extending bitmap size
|
||||||
|
|
||||||
typedef struct app_context app_context_t;
|
typedef struct app_context app_context_t;
|
||||||
struct app_context
|
struct app_context
|
||||||
|
@ -25,6 +28,23 @@ struct app_context
|
||||||
|
|
||||||
chtype palette[2 * 9]; ///< Attribute palette
|
chtype palette[2 * 9]; ///< Attribute palette
|
||||||
|
|
||||||
|
uint8_t *bitmap; ///< Canvas data for drawing
|
||||||
|
int bitmap_x; ///< X coord. of left top bitmap corner
|
||||||
|
int bitmap_y; ///< Y coord. of left top bitmap corner
|
||||||
|
size_t bitmap_w; ///< Canvas data width
|
||||||
|
size_t bitmap_h; ///< Canvas data height
|
||||||
|
|
||||||
|
int center_x; ///< X coordinate at center
|
||||||
|
int center_y; ///< Y coordinate at center
|
||||||
|
|
||||||
|
// These two are computed from `center_x' and `center_y':
|
||||||
|
|
||||||
|
int corner_x; ///< X coordinate of LT screen corner
|
||||||
|
int corner_y; ///< Y coordinate of LT screen corner
|
||||||
|
|
||||||
|
int move_saved_x; ///< Saved X coord. for moving
|
||||||
|
int move_saved_y; ///< Saved Y coord. for moving
|
||||||
|
|
||||||
uint8_t current_color_left; ///< Left mouse button color
|
uint8_t current_color_left; ///< Left mouse button color
|
||||||
uint8_t current_color_right; ///< Right mouse button color
|
uint8_t current_color_right; ///< Right mouse button color
|
||||||
};
|
};
|
||||||
|
@ -82,6 +102,13 @@ init_palette (app_context_t *app)
|
||||||
app->current_color_left = app->current_color_right = 9;
|
app->current_color_left = app->current_color_right = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_canvas_for_screen (app_context_t *app)
|
||||||
|
{
|
||||||
|
app->corner_x = app->center_x - COLS / 2;
|
||||||
|
app->corner_y = app->center_y - (LINES - TOP_BAR_CUTOFF) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
redraw (app_context_t *app)
|
redraw (app_context_t *app)
|
||||||
{
|
{
|
||||||
|
@ -102,6 +129,117 @@ redraw (app_context_t *app)
|
||||||
refresh ();
|
refresh ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_in_bitmap_data (app_context_t *app, int x, int y)
|
||||||
|
{
|
||||||
|
return x >= app->bitmap_x
|
||||||
|
&& y >= app->bitmap_y
|
||||||
|
&& x < app->bitmap_x + (int) app->bitmap_w
|
||||||
|
&& y < app->bitmap_y + (int) app->bitmap_h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
redraw_canvas (app_context_t *app)
|
||||||
|
{
|
||||||
|
int y = app->corner_y;
|
||||||
|
for (int screen_y = TOP_BAR_CUTOFF; screen_y < LINES; screen_y++, y++)
|
||||||
|
{
|
||||||
|
move (screen_y, 0);
|
||||||
|
|
||||||
|
int x = app->corner_x;
|
||||||
|
for (int screen_x = 0; screen_x < COLS; screen_x++, x++)
|
||||||
|
{
|
||||||
|
uint8_t color;
|
||||||
|
if (!is_in_bitmap_data (app, x, y))
|
||||||
|
color = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int data_x = x - app->bitmap_x;
|
||||||
|
int data_y = y - app->bitmap_y;
|
||||||
|
color = app->bitmap[data_y * app->bitmap_w + data_x];
|
||||||
|
}
|
||||||
|
|
||||||
|
addch (app->palette[color]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refresh ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_visible (app_context_t *app, int x, int y)
|
||||||
|
{
|
||||||
|
return x >= app->corner_x
|
||||||
|
&& y >= app->corner_y
|
||||||
|
&& x < app->corner_x + COLS
|
||||||
|
&& y < app->corner_y + LINES - TOP_BAR_CUTOFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
make_place_for_point (app_context_t *app, int x, int y)
|
||||||
|
{
|
||||||
|
if (is_in_bitmap_data (app, x, y))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Make sure the point has some place to go
|
||||||
|
int new_bitmap_x = app->bitmap_x;
|
||||||
|
int new_bitmap_y = app->bitmap_y;
|
||||||
|
|
||||||
|
while (new_bitmap_x > x)
|
||||||
|
new_bitmap_x -= BITMAP_BLOCK_SIZE;
|
||||||
|
while (new_bitmap_y > y)
|
||||||
|
new_bitmap_y -= BITMAP_BLOCK_SIZE;
|
||||||
|
|
||||||
|
int new_bitmap_w = app->bitmap_w + (app->bitmap_x - new_bitmap_x);
|
||||||
|
int new_bitmap_h = app->bitmap_h + (app->bitmap_y - new_bitmap_y);
|
||||||
|
|
||||||
|
while (new_bitmap_x + new_bitmap_w <= x)
|
||||||
|
new_bitmap_w += BITMAP_BLOCK_SIZE;
|
||||||
|
while (new_bitmap_y + new_bitmap_h <= y)
|
||||||
|
new_bitmap_h += BITMAP_BLOCK_SIZE;
|
||||||
|
|
||||||
|
uint8_t *new_bitmap = calloc (new_bitmap_w * new_bitmap_h,
|
||||||
|
sizeof *new_bitmap);
|
||||||
|
if (app->bitmap)
|
||||||
|
{
|
||||||
|
// Copy data, assuming that the area can only get larger
|
||||||
|
for (size_t data_y = 0; data_y < app->bitmap_h; data_y++)
|
||||||
|
memcpy (new_bitmap
|
||||||
|
+ ((data_y + app->bitmap_y - new_bitmap_y) * new_bitmap_w)
|
||||||
|
+ (app->bitmap_x - new_bitmap_x),
|
||||||
|
app->bitmap + (data_y * app->bitmap_w),
|
||||||
|
app->bitmap_w * sizeof *new_bitmap);
|
||||||
|
|
||||||
|
free (app->bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the bitmap with the reallocated version
|
||||||
|
app->bitmap_x = new_bitmap_x;
|
||||||
|
app->bitmap_y = new_bitmap_y;
|
||||||
|
app->bitmap_w = new_bitmap_w;
|
||||||
|
app->bitmap_h = new_bitmap_h;
|
||||||
|
app->bitmap = new_bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw_point (app_context_t *app, int x, int y, uint8_t color)
|
||||||
|
{
|
||||||
|
make_place_for_point (app, x, y);
|
||||||
|
|
||||||
|
int data_x = x - app->bitmap_x;
|
||||||
|
int data_y = y - app->bitmap_y;
|
||||||
|
app->bitmap[data_y * app->bitmap_w + data_x] = color;
|
||||||
|
|
||||||
|
if (is_visible (app, x, y))
|
||||||
|
{
|
||||||
|
int screen_x = x - app->corner_x;
|
||||||
|
int screen_y = y - app->corner_y + TOP_BAR_CUTOFF;
|
||||||
|
|
||||||
|
move (screen_y, screen_x);
|
||||||
|
addch (app->palette[color]);
|
||||||
|
refresh ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
on_key (app_context_t *app, termo_key_t *key)
|
on_key (app_context_t *app, termo_key_t *key)
|
||||||
{
|
{
|
||||||
|
@ -117,13 +255,31 @@ on_key (app_context_t *app, termo_key_t *key)
|
||||||
if (key->type != TERMO_TYPE_MOUSE)
|
if (key->type != TERMO_TYPE_MOUSE)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
int line, col, button;
|
int screen_y, screen_x, button;
|
||||||
termo_mouse_event_t event;
|
termo_mouse_event_t event;
|
||||||
|
|
||||||
termo_interpret_mouse (app->tk, key, &event, &button, &line, &col);
|
termo_interpret_mouse (app->tk, key, &event, &button, &screen_y, &screen_x);
|
||||||
if (event != TERMO_MOUSE_PRESS && event != TERMO_MOUSE_DRAG)
|
if (event != TERMO_MOUSE_PRESS && event != TERMO_MOUSE_DRAG)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (button == 2)
|
||||||
|
{
|
||||||
|
if (event == TERMO_MOUSE_DRAG)
|
||||||
|
{
|
||||||
|
app->corner_x += app->move_saved_x - screen_x;
|
||||||
|
app->corner_y += app->move_saved_y - screen_y;
|
||||||
|
|
||||||
|
app->center_x += app->move_saved_x - screen_x;
|
||||||
|
app->center_y += app->move_saved_y - screen_y;
|
||||||
|
|
||||||
|
redraw_canvas (app);
|
||||||
|
}
|
||||||
|
|
||||||
|
app->move_saved_x = screen_x;
|
||||||
|
app->move_saved_y = screen_y;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *color;
|
uint8_t *color;
|
||||||
if (button == 1)
|
if (button == 1)
|
||||||
color = &app->current_color_left;
|
color = &app->current_color_left;
|
||||||
|
@ -132,16 +288,15 @@ on_key (app_context_t *app, termo_key_t *key)
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
move (line, col);
|
int canvas_x = app->corner_x + screen_x;
|
||||||
if (line >= 3)
|
int canvas_y = app->corner_y + screen_y - TOP_BAR_CUTOFF;
|
||||||
|
|
||||||
|
if (screen_y >= TOP_BAR_CUTOFF)
|
||||||
|
draw_point (app, canvas_x, canvas_y, *color);
|
||||||
|
else if (screen_y > 0 && event != TERMO_MOUSE_DRAG)
|
||||||
{
|
{
|
||||||
addch (app->palette[*color]);
|
int pair = (float) screen_x / COLS * PALETTE_WIDTH;
|
||||||
refresh ();
|
*color = pair + (screen_y - 1) * PALETTE_WIDTH;
|
||||||
}
|
|
||||||
else if (line > 0 && event != TERMO_MOUSE_DRAG)
|
|
||||||
{
|
|
||||||
int pair = (float) col / COLS * PALETTE_WIDTH;
|
|
||||||
*color = pair + (line - 1) * PALETTE_WIDTH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -197,7 +352,9 @@ main (int argc, char *argv[])
|
||||||
app.tk = tk;
|
app.tk = tk;
|
||||||
|
|
||||||
init_palette (&app);
|
init_palette (&app);
|
||||||
|
update_canvas_for_screen (&app);
|
||||||
redraw (&app);
|
redraw (&app);
|
||||||
|
redraw_canvas (&app);
|
||||||
|
|
||||||
termo_result_t ret;
|
termo_result_t ret;
|
||||||
termo_key_t key;
|
termo_key_t key;
|
||||||
|
@ -228,7 +385,9 @@ main (int argc, char *argv[])
|
||||||
endwin ();
|
endwin ();
|
||||||
refresh ();
|
refresh ();
|
||||||
|
|
||||||
|
update_canvas_for_screen (&app);
|
||||||
redraw (&app);
|
redraw (&app);
|
||||||
|
redraw_canvas (&app);
|
||||||
}
|
}
|
||||||
if (fds[0].revents & (POLLIN | POLLHUP | POLLERR))
|
if (fds[0].revents & (POLLIN | POLLHUP | POLLERR))
|
||||||
termo_advisereadable (tk);
|
termo_advisereadable (tk);
|
||||||
|
|
Loading…
Reference in New Issue