editor: fix off-by-one error
This fixes multiple comparisons between the buffer length and the cursor row. Also refactor the key-binding logic for better flexibility.
This commit is contained in:
parent
c86fcbd6af
commit
d313bdd855
@ -18,6 +18,11 @@ struct cursor {
|
|||||||
int32_t col;
|
int32_t col;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum struct mode {
|
||||||
|
normal,
|
||||||
|
mark
|
||||||
|
};
|
||||||
|
|
||||||
template <int C, int R>
|
template <int C, int R>
|
||||||
struct buffer {
|
struct buffer {
|
||||||
line<C> row[R];
|
line<C> row[R];
|
||||||
@ -31,6 +36,8 @@ struct buffer {
|
|||||||
int32_t left;
|
int32_t left;
|
||||||
} window;
|
} window;
|
||||||
struct cursor cursor;
|
struct cursor cursor;
|
||||||
|
struct cursor mark;
|
||||||
|
enum mode mode;
|
||||||
|
|
||||||
typedef line<C> line_type;
|
typedef line<C> line_type;
|
||||||
|
|
||||||
@ -49,6 +56,8 @@ struct buffer {
|
|||||||
inline constexpr bool cursor_home();
|
inline constexpr bool cursor_home();
|
||||||
inline constexpr bool cursor_end();
|
inline constexpr bool cursor_end();
|
||||||
inline constexpr bool enter();
|
inline constexpr bool enter();
|
||||||
|
inline constexpr void set_mark();
|
||||||
|
inline constexpr void quit();
|
||||||
private:
|
private:
|
||||||
inline constexpr void scroll_left();
|
inline constexpr void scroll_left();
|
||||||
inline constexpr void scroll_right();
|
inline constexpr void scroll_right();
|
||||||
@ -217,7 +226,7 @@ inline constexpr bool buffer<C, R>::cursor_right()
|
|||||||
line<C> const * const l = this->lines[cur.row];
|
line<C> const * const l = this->lines[cur.row];
|
||||||
int32_t length = (l == nullptr) ? 0 : l->length;
|
int32_t length = (l == nullptr) ? 0 : l->length;
|
||||||
if (cur.col >= length) {
|
if (cur.col >= length) {
|
||||||
if (cur.row >= this->length)
|
if (cur.row >= (this->length - 1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
cur.row++;
|
cur.row++;
|
||||||
@ -256,7 +265,7 @@ inline constexpr bool buffer<C, R>::cursor_down()
|
|||||||
{
|
{
|
||||||
struct cursor& cur = this->cursor;
|
struct cursor& cur = this->cursor;
|
||||||
|
|
||||||
if (cur.row >= this->length)
|
if (cur.row >= (this->length - 1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
cur.row++;
|
cur.row++;
|
||||||
@ -305,7 +314,7 @@ inline constexpr bool buffer<C, R>::enter()
|
|||||||
if (cur.row >= R || cur.row < 0)
|
if (cur.row >= R || cur.row < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (this->length > cur.row) {
|
if ((this->length - 1) > cur.row) {
|
||||||
// first, move all lines down one
|
// first, move all lines down one
|
||||||
int32_t n_lines = this->length - (cur.row + 1);
|
int32_t n_lines = this->length - (cur.row + 1);
|
||||||
// don't care about nullptr here, this never dereferences
|
// don't care about nullptr here, this never dereferences
|
||||||
@ -338,6 +347,20 @@ inline constexpr bool buffer<C, R>::enter()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <int C, int R>
|
||||||
|
inline constexpr void buffer<C, R>::set_mark()
|
||||||
|
{
|
||||||
|
this->mark.row = this->cursor.row;
|
||||||
|
this->mark.col = this->cursor.col;
|
||||||
|
this->mode = mode::mark;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int C, int R>
|
||||||
|
inline constexpr void buffer<C, R>::quit()
|
||||||
|
{
|
||||||
|
this->mode = mode::normal;
|
||||||
|
}
|
||||||
|
|
||||||
template <int C, int R>
|
template <int C, int R>
|
||||||
inline constexpr void buffer<C, R>::scroll_up()
|
inline constexpr void buffer<C, R>::scroll_up()
|
||||||
{
|
{
|
||||||
|
@ -20,13 +20,21 @@ constexpr int32_t viewport_max_row = 240 / 8;
|
|||||||
|
|
||||||
static buffer_type buffer {viewport_max_col, viewport_max_row};
|
static buffer_type buffer {viewport_max_col, viewport_max_row};
|
||||||
|
|
||||||
|
constexpr inline uint16_t rgb15(int32_t r, int32_t g, int32_t b)
|
||||||
|
{
|
||||||
|
return ((b & 31) << 10) | ((g & 31) << 5) | ((r & 31) << 0);
|
||||||
|
}
|
||||||
|
|
||||||
void palette_data()
|
void palette_data()
|
||||||
{
|
{
|
||||||
vdp2.cram.u16[1 + 0 ] = 0;
|
vdp2.cram.u16[1 + 0 ] = rgb15( 0, 0, 0);
|
||||||
vdp2.cram.u16[2 + 0 ] = 0x7fff;
|
vdp2.cram.u16[2 + 0 ] = rgb15(31, 31, 31);
|
||||||
|
|
||||||
vdp2.cram.u16[1 + 16] = 0x7fff;
|
vdp2.cram.u16[1 + 16] = rgb15(31, 31, 31);
|
||||||
vdp2.cram.u16[2 + 16] = 0;
|
vdp2.cram.u16[2 + 16] = rgb15( 0, 0, 0);
|
||||||
|
|
||||||
|
vdp2.cram.u16[1 + 32] = rgb15(15, 15, 15);
|
||||||
|
vdp2.cram.u16[2 + 32] = rgb15(31, 31, 31);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace pix_fmt_4bpp
|
namespace pix_fmt_4bpp
|
||||||
@ -64,42 +72,103 @@ void cell_data()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct modifiers {
|
enum modifier {
|
||||||
uint8_t left_shift;
|
MODIFIER_NONE = 0,
|
||||||
uint8_t right_shift;
|
MODIFIER_LEFT_SHIFT = (1 << 0),
|
||||||
|
MODIFIER_RIGHT_SHIFT = (1 << 1),
|
||||||
|
MODIFIER_BOTH_SHIFT = MODIFIER_LEFT_SHIFT | MODIFIER_RIGHT_SHIFT,
|
||||||
|
MODIFIER_LEFT_CTRL = (1 << 2),
|
||||||
|
MODIFIER_RIGHT_CTRL = (1 << 3),
|
||||||
|
MODIFIER_BOTH_CTRL = MODIFIER_LEFT_CTRL | MODIFIER_RIGHT_CTRL,
|
||||||
|
MODIFIER_LEFT_ALT = (1 << 4),
|
||||||
|
MODIFIER_RIGHT_ALT = (1 << 5),
|
||||||
|
MODIFIER_BOTH_ALT = MODIFIER_LEFT_ALT | MODIFIER_RIGHT_ALT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static modifiers modifier_state = { 0 };
|
static uint32_t modifier_state = 0;
|
||||||
|
|
||||||
|
inline void keyboard_regular_key(const enum keysym k)
|
||||||
|
{
|
||||||
|
switch (modifier_state) {
|
||||||
|
case MODIFIER_NONE:
|
||||||
|
switch (k) {
|
||||||
|
case keysym::BACKSPACE : buffer.backspace(); break;
|
||||||
|
case keysym::ARROW_LEFT : buffer.cursor_left(); break;
|
||||||
|
case keysym::ARROW_RIGHT: buffer.cursor_right(); break;
|
||||||
|
case keysym::ARROW_UP : buffer.cursor_up(); break;
|
||||||
|
case keysym::ARROW_DOWN : buffer.cursor_down(); break;
|
||||||
|
case keysym::HOME : buffer.cursor_home(); break;
|
||||||
|
case keysym::END : buffer.cursor_end(); break;
|
||||||
|
case keysym::ENTER : buffer.enter(); break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
uint8_t c = keysym_to_char(k, false);
|
||||||
|
if (c != -1) buffer.put(c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODIFIER_LEFT_SHIFT: [[fallthrough]];
|
||||||
|
case MODIFIER_RIGHT_SHIFT: [[fallthrough]];
|
||||||
|
case MODIFIER_BOTH_SHIFT:
|
||||||
|
switch (k) {
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
uint8_t c = keysym_to_char(k, true);
|
||||||
|
if (c != -1) buffer.put(c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODIFIER_LEFT_CTRL: [[fallthrough]];
|
||||||
|
case MODIFIER_RIGHT_CTRL: [[fallthrough]];
|
||||||
|
case MODIFIER_BOTH_CTRL:
|
||||||
|
switch (k) {
|
||||||
|
case keysym::SPACE : buffer.set_mark(); break;
|
||||||
|
case keysym::G : buffer.quit(); break;
|
||||||
|
case keysym::B : buffer.cursor_left(); break;
|
||||||
|
case keysym::F : buffer.cursor_right(); break;
|
||||||
|
case keysym::P : buffer.cursor_up(); break;
|
||||||
|
case keysym::N : buffer.cursor_down(); break;
|
||||||
|
case keysym::A : buffer.cursor_home(); break;
|
||||||
|
case keysym::E : buffer.cursor_end(); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODIFIER_LEFT_ALT: [[fallthrough]];
|
||||||
|
case MODIFIER_RIGHT_ALT: [[fallthrough]];
|
||||||
|
case MODIFIER_BOTH_ALT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void keyboard_callback(const enum keysym k, uint8_t kbd_bits)
|
void keyboard_callback(const enum keysym k, uint8_t kbd_bits)
|
||||||
{
|
{
|
||||||
int32_t shift = modifier_state.left_shift || modifier_state.right_shift;
|
|
||||||
int32_t c = keysym_to_char(k, shift);
|
|
||||||
if (KEYBOARD__MAKE(kbd_bits)) {
|
if (KEYBOARD__MAKE(kbd_bits)) {
|
||||||
if (k == keysym::UNKNOWN)
|
switch (k) {
|
||||||
return;
|
case keysym::LEFT_SHIFT : modifier_state |= MODIFIER_LEFT_SHIFT; break;
|
||||||
|
case keysym::RIGHT_SHIFT: modifier_state |= MODIFIER_RIGHT_SHIFT; break;
|
||||||
if (c != -1) {
|
case keysym::LEFT_CTRL : modifier_state |= MODIFIER_LEFT_CTRL; break;
|
||||||
buffer.put(c);
|
case keysym::RIGHT_CTRL : modifier_state |= MODIFIER_RIGHT_CTRL; break;
|
||||||
} else {
|
case keysym::LEFT_ALT : modifier_state |= MODIFIER_LEFT_ALT; break;
|
||||||
switch (k) {
|
case keysym::RIGHT_ALT : modifier_state |= MODIFIER_RIGHT_ALT; break;
|
||||||
case keysym::BACKSPACE : buffer.backspace(); break;
|
default:
|
||||||
case keysym::ARROW_LEFT : buffer.cursor_left(); break;
|
keyboard_regular_key(k);
|
||||||
case keysym::ARROW_RIGHT: buffer.cursor_right(); break;
|
break;
|
||||||
case keysym::ARROW_UP : buffer.cursor_up(); break;
|
|
||||||
case keysym::ARROW_DOWN : buffer.cursor_down(); break;
|
|
||||||
case keysym::HOME : buffer.cursor_home(); break;
|
|
||||||
case keysym::END : buffer.cursor_end(); break;
|
|
||||||
case keysym::ENTER : buffer.enter(); break;
|
|
||||||
case keysym::LEFT_SHIFT : modifier_state.left_shift = 1; break;
|
|
||||||
case keysym::RIGHT_SHIFT: modifier_state.right_shift = 1; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (KEYBOARD__BREAK(kbd_bits)) {
|
} else if (KEYBOARD__BREAK(kbd_bits)) {
|
||||||
switch (k) {
|
switch (k) {
|
||||||
case keysym::LEFT_SHIFT : modifier_state.left_shift = 0; break;
|
case keysym::LEFT_SHIFT : modifier_state &= ~(MODIFIER_LEFT_SHIFT); break;
|
||||||
case keysym::RIGHT_SHIFT: modifier_state.right_shift = 0; break;
|
case keysym::RIGHT_SHIFT: modifier_state &= ~(MODIFIER_RIGHT_SHIFT); break;
|
||||||
|
case keysym::LEFT_CTRL : modifier_state &= ~(MODIFIER_LEFT_CTRL); break;
|
||||||
|
case keysym::RIGHT_CTRL : modifier_state &= ~(MODIFIER_RIGHT_CTRL); break;
|
||||||
|
case keysym::LEFT_ALT : modifier_state &= ~(MODIFIER_LEFT_ALT); break;
|
||||||
|
case keysym::RIGHT_ALT : modifier_state &= ~(MODIFIER_RIGHT_ALT); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user