aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2014-10-23 23:23:09 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2014-10-23 23:27:48 +0200
commitde3c8b89bbc4e728df93552267099106966d3651 (patch)
tree6ffdafc8c681e8d529f5ae7119f3d08a37a06216
parent47e6e7fa23df7cdde3f1e77bd401c898d3330861 (diff)
downloadneetdraw-de3c8b89bbc4e728df93552267099106966d3651.tar.gz
neetdraw-de3c8b89bbc4e728df93552267099106966d3651.tar.xz
neetdraw-de3c8b89bbc4e728df93552267099106966d3651.zip
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.
-rw-r--r--autistdraw.c181
1 files changed, 170 insertions, 11 deletions
diff --git a/autistdraw.c b/autistdraw.c
index effd220..90b5ed8 100644
--- a/autistdraw.c
+++ b/autistdraw.c
@@ -17,6 +17,9 @@
#include "config.h"
#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;
struct app_context
@@ -25,6 +28,23 @@ struct app_context
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_right; ///< Right mouse button color
};
@@ -83,6 +103,13 @@ init_palette (app_context_t *app)
}
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
redraw (app_context_t *app)
{
int i;
@@ -103,6 +130,117 @@ redraw (app_context_t *app)
}
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
on_key (app_context_t *app, termo_key_t *key)
{
if (key->type == TERMO_TYPE_KEYSYM
@@ -117,13 +255,31 @@ on_key (app_context_t *app, termo_key_t *key)
if (key->type != TERMO_TYPE_MOUSE)
return true;
- int line, col, button;
+ int screen_y, screen_x, button;
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)
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;
if (button == 1)
color = &app->current_color_left;
@@ -132,16 +288,15 @@ on_key (app_context_t *app, termo_key_t *key)
else
return true;
- move (line, col);
- if (line >= 3)
- {
- addch (app->palette[*color]);
- refresh ();
- }
- else if (line > 0 && event != TERMO_MOUSE_DRAG)
+ int canvas_x = app->corner_x + screen_x;
+ 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)
{
- int pair = (float) col / COLS * PALETTE_WIDTH;
- *color = pair + (line - 1) * PALETTE_WIDTH;
+ int pair = (float) screen_x / COLS * PALETTE_WIDTH;
+ *color = pair + (screen_y - 1) * PALETTE_WIDTH;
}
return true;
@@ -197,7 +352,9 @@ main (int argc, char *argv[])
app.tk = tk;
init_palette (&app);
+ update_canvas_for_screen (&app);
redraw (&app);
+ redraw_canvas (&app);
termo_result_t ret;
termo_key_t key;
@@ -228,7 +385,9 @@ main (int argc, char *argv[])
endwin ();
refresh ();
+ update_canvas_for_screen (&app);
redraw (&app);
+ redraw_canvas (&app);
}
if (fds[0].revents & (POLLIN | POLLHUP | POLLERR))
termo_advisereadable (tk);