Add line drawing command, along with line attributes

Add `line` command to draw a line
Add `foreground` and `bacground` commands to set patterns
Add `LineWidth` command to set line width

Fixes: #311
Fixes: #312

Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
This commit is contained in:
Christophe de Dinechin 2023-08-09 00:16:46 +02:00
parent ab33b7d663
commit 7dce12544a
9 changed files with 184 additions and 14 deletions

View file

@ -7,7 +7,7 @@ extern const unsigned char EditorFont_sparse_font_data[];
const unsigned char EditorFont_sparse_font_data[73676] FONT_QSPI =
{
0x9C, 0x02, 0xC7, 0xBF, 0x04, 0x36, 0x00, 0x01, 0x00, 0x2C, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01,
0xA0, 0x02, 0xC7, 0xBF, 0x04, 0x36, 0x00, 0x01, 0x00, 0x2C, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01,
0x00, 0x2C, 0x01, 0x01, 0x08, 0x00, 0x20, 0x5F, 0x00, 0x2C, 0x01, 0x01, 0x08, 0x00, 0x02, 0x0B,
0x05, 0x21, 0x09, 0xEF, 0xBD, 0xF7, 0xDE, 0x7B, 0xEF, 0xBD, 0xF7, 0xDE, 0x7B, 0xEF, 0xBD, 0xF7,
0x1E, 0x00, 0x00, 0xB8, 0xFF, 0xFF, 0xFF, 0x0E, 0x03, 0x0B, 0x0B, 0x0F, 0x11, 0x8F, 0x7F, 0xFC,

View file

@ -7,7 +7,7 @@ extern const unsigned char HelpFont_sparse_font_data[];
const unsigned char HelpFont_sparse_font_data[15010] FONT_QSPI =
{
0x9C, 0x02, 0x9E, 0x75, 0x14, 0x00, 0x01, 0x00, 0x11, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01, 0x00,
0xA0, 0x02, 0x9E, 0x75, 0x14, 0x00, 0x01, 0x00, 0x11, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01, 0x00,
0x11, 0x01, 0x01, 0x03, 0x00, 0x20, 0x5F, 0x00, 0x11, 0x01, 0x01, 0x03, 0x00, 0x01, 0x04, 0x02,
0x0D, 0x04, 0xFF, 0xFF, 0xF3, 0x03, 0x01, 0x04, 0x04, 0x05, 0x06, 0xFF, 0xFF, 0x0F, 0x01, 0x04,
0x08, 0x0D, 0x0A, 0x12, 0x12, 0x14, 0x7F, 0x7F, 0x24, 0x24, 0x24, 0xFE, 0xFE, 0x28, 0x48, 0x48,

View file

@ -7,7 +7,7 @@ extern const unsigned char StackFont_sparse_font_data[];
const unsigned char StackFont_sparse_font_data[36409] FONT_QSPI =
{
0x9C, 0x02, 0xB4, 0x9C, 0x02, 0x24, 0x00, 0x01, 0x00, 0x1C, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01,
0xA0, 0x02, 0xB4, 0x9C, 0x02, 0x24, 0x00, 0x01, 0x00, 0x1C, 0x01, 0x01, 0x00, 0x00, 0x0D, 0x01,
0x00, 0x1C, 0x01, 0x01, 0x06, 0x00, 0x20, 0x5F, 0x00, 0x1C, 0x01, 0x01, 0x06, 0x00, 0x02, 0x05,
0x03, 0x17, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xC0, 0xFF, 0x1F, 0x02, 0x05, 0x08, 0x0A,
0x0C, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x01, 0x05, 0x0E, 0x17, 0x10,

View file

@ -473,6 +473,15 @@ struct blitter
// --------------------------------------------------------------------
// Draw a text with a foreground and background
// --------------------------------------------------------------------
template<clipping Clip = CLIP_DST>
void line(coord x1, coord y1, coord x2, coord y2,
size width, pattern fg);
// --------------------------------------------------------------------
// Draw a line between the given coordinates
// --------------------------------------------------------------------
protected:
offset pixel_offset(coord x, coord y) const
// ---------------------------------------------------------------------
@ -1436,4 +1445,40 @@ blitter::coord blitter::surface<Mode>::text(coord x,
return x;
}
template <blitter::mode Mode>
template<blitter::clipping Clip>
void blitter::surface<Mode>::line(coord x1, coord y1,
coord x2, coord y2,
size width, pattern fg)
// --------------------------------------------------------------------
// Draw a line between the given coordinates
// --------------------------------------------------------------------
{
size dx = x1 > x2 ? x1 - x2 : x2 - x1;
size dy = y1 > y2 ? y1 - y2 : y2 - y1;
int sx = x2 < x1 ? -1 : 1;
int sy = y2 < y1 ? -1 : 1;
coord d = dx - dy;
coord x = x1;
coord y = y1;
size wn = (width - 1) / 2;
size wp = width / 2;
while (x != x2 && y != y2)
{
fill<Clip>(x - wn, y - wn, x + wp, y + wp, fg);
if (d >= 0)
{
x += sx;
d -= dy;
}
if (d < 0)
{
y += sy;
d += dx;
}
}
}
#endif // BLITTER_H

View file

@ -43,9 +43,11 @@
typedef const based_integer *based_integer_p;
typedef const based_bignum *based_bignum_p;
using std::min;
using std::max;
static coord to_coord(object_g pos, uint scaling)
static coord to_coord(object_g pos, int scaling)
// ----------------------------------------------------------------------------
// Convert an object to a coordinate
// ----------------------------------------------------------------------------
@ -56,16 +58,18 @@ static coord to_coord(object_g pos, uint scaling)
switch(ty)
{
case object::ID_integer:
y = scaling * (integer_p(pos.Safe())->value<coord>() - 1);
case object::ID_neg_integer:
y = integer_p(pos.Safe())->value<uint16_t>();
if (ty == object::ID_neg_integer)
y = -y;
y = scaling * (y - 1);
break;
case object::ID_bignum:
y = scaling * (bignum_p(pos.Safe())->value<coord>() - 1);
break;
case object::ID_neg_integer:
case object::ID_neg_bignum:
case object::ID_neg_fraction:
case object::ID_neg_big_fraction:
y = bignum_p(pos.Safe())->value<uint16_t>();
if (ty == object::ID_neg_bignum)
y = -y;
y = scaling * (y - 1);
break;
#if CONFIG_FIXED_BASED_OBJECTS
@ -88,11 +92,15 @@ static coord to_coord(object_g pos, uint scaling)
y = based_bignum_p(pos.Safe())->value<coord>();
break;
case object::ID_neg_fraction:
case object::ID_neg_big_fraction:
case object::ID_fraction:
case object::ID_big_fraction:
y = scaling
* fraction_p(pos.Safe())->numerator()->value<coord>()
/ fraction_p(pos.Safe())->denominator()->value<coord>()
* (1 - 2 * (ty == object::ID_neg_fraction ||
ty == object::ID_neg_big_fraction))
- scaling;
break;
@ -246,6 +254,35 @@ COMMAND_BODY(dispxy)
}
COMMAND_BODY(line)
// ----------------------------------------------------------------------------
// Draw a line between the coordinates
// ----------------------------------------------------------------------------
{
object_p x1o = rt.stack(3);
object_p y1o = rt.stack(2);
object_p x2o = rt.stack(1);
object_p y2o = rt.stack(0);
if (x1o && y1o && x2o && y2o)
{
coord x1 = to_coord(x1o, 1);
coord y1 = to_coord(y1o, 1);
coord x2 = to_coord(x2o, 1);
coord y2 = to_coord(y2o, 1);
if (!rt.error())
{
rt.drop(4);
Screen.line(x1, y1, x2, y2,
Settings.line_width, Settings.foreground);
ui.draw_dirty(min(x1,x2), min(y1,y2), max(x1,x2), max(y1,y2));
refresh_dirty();
return OK;
}
}
return ERROR;
}
COMMAND_BODY(cllcd)
// ----------------------------------------------------------------------------
// Clear the LCD screen before drawing stuff on it

View file

@ -34,6 +34,7 @@
COMMAND_DECLARE(disp);
COMMAND_DECLARE(dispxy);
COMMAND_DECLARE(line);
COMMAND_DECLARE(cllcd);
#endif // GRAPHICS_H

View file

@ -325,8 +325,9 @@ NAMED(errn, "ErrorNumber")
NAMED(err0, "ClearError")
NAMED(doerr, "DoError")
NAMED(disp, "DisplayText")
NAMED(dispxy, "DisplayStyledText")
NAMED(disp, "DrawText")
NAMED(dispxy, "DrawStyledText")
NAMED(line, "DrawLine")
NAMED(cllcd, "ClearLCD")
@ -406,6 +407,10 @@ CMD(ThreeRowsMenus)
CMD(RoundedMenus)
CMD(SquareMenus)
CMD(LineWidth)
CMD(Foreground)
CMD(Background)
CMD(Modes)
CMD(Version)

View file

@ -30,6 +30,7 @@
#include "settings.h"
#include "arithmetic.h"
#include "bignum.h"
#include "command.h"
#include "font.h"
#include "functions.h"
@ -1112,3 +1113,72 @@ SETTINGS_COMMAND_BODY(SquareMenus, Settings.menu_square)
ui.menuNeedsRefresh();
return OK;
}
SETTINGS_COMMAND_BODY(LineWidth, false)
// ----------------------------------------------------------------------------
// Set the line width
// ----------------------------------------------------------------------------
{
uint width = integer_arg(0, 128);
if (!rt.error())
{
Settings.line_width = width;
return object::OK;
}
return object::ERROR;
}
SETTINGS_COMMAND_LABEL(LineWidth)
// ----------------------------------------------------------------------------
// Line width label
// ----------------------------------------------------------------------------
{
static char buffer[16];
snprintf(buffer, sizeof(buffer), "LineW %u", Settings.line_width);
return buffer;
}
static uint64_t pattern_arg()
// ----------------------------------------------------------------------------
// Return a 64-bit argument value
// ----------------------------------------------------------------------------
{
if (object_p obj = rt.pop())
{
if (const based_integer *based = obj->as<based_integer>())
return based->value<uint64_t>();
if (const based_bignum *based = obj->as<based_bignum>())
return based->value<uint64_t>();
rt.type_error();
}
return ~0uLL;
}
SETTINGS_COMMAND_BODY(Foreground, false)
// ----------------------------------------------------------------------------
// Set the pattern for foreground
// ----------------------------------------------------------------------------
{
uint64_t pat = pattern_arg();
if (rt.error())
return ERROR;
Settings.foreground.bits = pat;
return OK;
}
SETTINGS_COMMAND_BODY(Background, false)
// ----------------------------------------------------------------------------
// Set the pattern for background
// ----------------------------------------------------------------------------
{
uint64_t pat = pattern_arg();
if (rt.error())
return ERROR;
Settings.background.bits = pat;
return OK;
}

View file

@ -31,6 +31,7 @@
#include "command.h"
#include "menu.h"
#include "target.h"
#include <types.h>
@ -100,7 +101,10 @@ struct settings
result_sz(STACK),
stack_sz(STACK),
editor_sz(EDITOR),
editor_ml_sz(STACK)
editor_ml_sz(STACK),
line_width(1),
background(pattern::white),
foreground(pattern::black)
{}
enum angles
@ -202,6 +206,9 @@ public:
font_id stack_sz; // Size for other stack levels
font_id editor_sz; // Size for normal editor
font_id editor_ml_sz; // Size for editor in multi-line mode
size line_width; // Line width for drawing
pattern background; // Background color
pattern foreground; // Foreground color
};
@ -323,4 +330,9 @@ SETTINGS_COMMAND_DECLARE(ThreeRowsMenus);
SETTINGS_COMMAND_DECLARE(RoundedMenus);
SETTINGS_COMMAND_DECLARE(SquareMenus);
SETTINGS_COMMAND_DECLARE(LineWidth);
SETTINGS_COMMAND_DECLARE(Foreground);
SETTINGS_COMMAND_DECLARE(Background);
#endif // SETTINGS_H