ui: Add colorization parameters for the user interface

Add configuration parameters that lets you choose the color for the
various elements in the user interface.

Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
This commit is contained in:
Christophe de Dinechin 2024-04-09 00:57:19 +02:00
parent 2bc70413f2
commit 88009cc619
15 changed files with 554 additions and 350 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -178,7 +178,7 @@ struct blitter
static const pattern gray75 = pattern(192, 192, 192);
static const pattern gray90 = pattern(224, 224, 224);
static const pattern white = pattern(255, 255, 255);
static const pattern invert = pattern();
static const pattern invert = pattern();
};
@ -556,37 +556,34 @@ struct blitter
template <clipping Clip = COPY, mode SMode>
void copy(surface<SMode> &src,
const rect &r,
const point &spos = point(0, 0),
pattern clear = pattern::black)
const point &spos = point(0, 0))
// --------------------------------------------------------------------
// Copy a rectangular area from the source
// --------------------------------------------------------------------
{
blit<Clip>(*this, src, r, spos, blitop_source, clear);
blit<Clip>(*this, src, r, spos, blitop_source, pattern());
}
template <clipping Clip = COPY, mode SMode>
void copy(surface<SMode> &src,
const point &pos = point(0, 0),
pattern clear = pattern::black)
const point &pos = point(0, 0))
// --------------------------------------------------------------------
// Copy a rectangular area from the source
// --------------------------------------------------------------------
{
return copy(src, pos.x, pos.y, clear);
return copy(src, pos.x, pos.y, pattern());
}
template <clipping Clip = COPY, mode SMode>
void copy(surface<SMode> &src,
coord x,
coord y,
pattern clear = pattern::black)
coord y)
// --------------------------------------------------------------------
// Copy a rectangular area from the source
// --------------------------------------------------------------------
{
rect dest(x, y, x + src.w - 1, y + src.h - 1);
blit<Clip>(*this, src, dest, point(), blitop_source, clear);
blit<Clip>(*this, src, dest, point(), blitop_source, pattern());
}
@ -635,7 +632,7 @@ struct blitter
void draw_background(surface<SMode> &src,
coord x,
coord y,
pattern color = pattern::black,
pattern color = pattern::white,
blitop op = blitop_background)
// --------------------------------------------------------------------
// Draw a rectangular area from the source background
@ -908,7 +905,7 @@ public:
// This simly sets the color from the source
// -------------------------------------------------------------------------
{
return src ^ arg;
return src;
}
static pixword blitop_xor(pixword dst, pixword src, pixword arg)
@ -955,7 +952,7 @@ public:
// Colorize based on source
// ------------------------------------------------------------------------
{
return (dst & ~src) | (arg & src);
return (dst & src) | (arg & ~src);
}
@ -964,7 +961,7 @@ public:
// Colorize based on source
// ------------------------------------------------------------------------
{
return (dst & src) | (arg & ~src);
return (dst & ~src) | (arg & src);
}
};
@ -1567,8 +1564,9 @@ void blitter::blit(Dst &dst,
pixword dmask2 = xback ? lmask : rmask;
// Adjust the color pattern based on starting point
uint64_t cdata64 =
skip_col ? 0 : rotate(colors.bits, dx1 * CBPP + dy1 * cshift - dws);
uint64_t cdata64 = skip_col
? blitter::pattern<CMode>::white.bits
: rotate(colors.bits, dx1 * CBPP + dy1 * cshift - dws);
// Loop on all lines
while (ycount-- >= 0)
@ -1628,8 +1626,8 @@ void blitter::blit(Dst &dst,
ASSERT(dp >= dst.pixels);
ASSERT(dp <= dst.pixels + (dst.scanline*dst.h*DBPP+(BPW-1))/BPW);
pixword ddata = dp[0];
pixword sdc = convert<DMode, SMode>(sdata);
pixword cdc = convert<DMode, CMode>(cdata);
pixword sdc = skip_src ? sdata : convert<DMode, SMode>(sdata);
pixword cdc = skip_col ? cdata64 : convert<DMode, CMode>(cdata);
pixword tdata = op(ddata, sdc, cdc);
*dp = (tdata & dmask) | (ddata & ~dmask);
@ -1744,7 +1742,7 @@ CONVERT(MONOCHROME, MONOCHROME_REVERSE)
// The MONOCHROME_REVERSE mode flips black and white
// ----------------------------------------------------------------------------
{
return data;
return ~data;
}
@ -1753,7 +1751,7 @@ CONVERT(MONOCHROME_REVERSE, MONOCHROME)
// The MONOCHROME_REVERSE mode flips black and white
// ----------------------------------------------------------------------------
{
return data;
return ~data;
}
@ -1764,7 +1762,7 @@ CONVERT(GRAY_4BPP, MONOCHROME)
{
pixword cvt = 0;
for (unsigned shift = 0; shift < 8; shift++)
if (data & (1 << shift))
if (~data & (1 << shift))
cvt |= 0xF << (4 * shift);
return cvt;
}
@ -1777,7 +1775,7 @@ CONVERT(RGB_16BPP, MONOCHROME)
{
pixword cvt = 0;
for (unsigned shift = 0; shift < 2; shift++)
if (data & (1 << shift))
if (~data & (1 << shift))
cvt |= 0xFFFF << (16 * shift);
return cvt;
}

View file

@ -97,8 +97,8 @@ void redraw_lcd(bool force)
// Draw the various components handled by the user interface
ui.draw_start(force);
ui.draw_header();
ui.draw_annunciators();
ui.draw_battery();
ui.draw_annunciators();
ui.draw_menus();
if (!ui.draw_help())
{

View file

@ -33,11 +33,11 @@
surface Screen((pixword *) lcd_line_addr(0), LCD_W, LCD_H, LCD_SCANLINE);
// Pre-built patterns for shades of grey
const pattern pattern::black = pattern(0, 0, 0);
const pattern pattern::gray10 = pattern(32, 32, 32);
const pattern pattern::gray25 = pattern(64, 64, 64);
const pattern pattern::gray50 = pattern(128, 128, 128);
const pattern pattern::gray75 = pattern(192, 192, 192);
const pattern pattern::gray90 = pattern(224, 224, 224);
const pattern pattern::white = pattern(255, 255, 255);
const pattern pattern::invert = pattern();
const pattern pattern::black = pattern(0, 0, 0);
const pattern pattern::gray10 = pattern(32, 32, 32);
const pattern pattern::gray25 = pattern(64, 64, 64);
const pattern pattern::gray50 = pattern(128, 128, 128);
const pattern pattern::gray75 = pattern(192, 192, 192);
const pattern pattern::gray90 = pattern(224, 224, 224);
const pattern pattern::white = pattern(255, 255, 255);
const pattern pattern::invert = pattern(~0ULL);

View file

@ -1025,8 +1025,7 @@ COMMAND_BODY(ClLCD)
// ----------------------------------------------------------------------------
{
ui.draw_graphics();
Screen.fill(0, 0, LCD_W, LCD_H, pattern::white);
graphics_dirty(0, 0, LCD_W-1, LCD_H-1, 0);
refresh_dirty();
return OK;
}

View file

@ -335,12 +335,12 @@ object::result grob::command(grob::blitop op)
#ifdef CONFIG_COLOR
// Pre-built grob::patterns for shades of grey
const grob::pattern grob::pattern::black = grob::pattern(0, 0, 0);
const grob::pattern grob::pattern::gray10 = grob::pattern(32, 32, 32);
const grob::pattern grob::pattern::gray25 = grob::pattern(64, 64, 64);
const grob::pattern grob::pattern::gray50 = grob::pattern(128, 128, 128);
const grob::pattern grob::pattern::gray75 = grob::pattern(192, 192, 192);
const grob::pattern grob::pattern::gray90 = grob::pattern(224, 224, 224);
const grob::pattern grob::pattern::white = grob::pattern(255, 255, 255);
const grob::pattern grob::pattern::invert = grob::pattern();
const grob::pattern grob::pattern::black = grob::pattern(0, 0, 0);
const grob::pattern grob::pattern::gray10 = grob::pattern(32, 32, 32);
const grob::pattern grob::pattern::gray25 = grob::pattern(64, 64, 64);
const grob::pattern grob::pattern::gray50 = grob::pattern(128, 128, 128);
const grob::pattern grob::pattern::gray75 = grob::pattern(192, 192, 192);
const grob::pattern grob::pattern::gray90 = grob::pattern(224, 224, 224);
const grob::pattern grob::pattern::white = grob::pattern(255, 255, 255);
const grob::pattern grob::pattern::invert = grob::pattern();
#endif

View file

@ -852,6 +852,8 @@ SETTING_BITS(ResultFont, settings::font_id, 4, settings::FIRST_FONT,
SETTING_BITS(StackFont, settings::font_id, 4, settings::FIRST_FONT, settings::LAST_FONT, settings::STACK)
SETTING_BITS(EditorFont, settings::font_id, 4, settings::FIRST_FONT, settings::LAST_FONT, settings::STACK)
SETTING_BITS(MultilineEditorFont, settings::font_id, 4, settings::FIRST_FONT, settings::LAST_FONT, settings::STACK)
SETTING_BITS(CursorFont, settings::font_id, 4, settings::FIRST_FONT, settings::LAST_FONT, settings::HELP)
SETTING_BITS(MultilineCursorFont, settings::font_id, 4, settings::FIRST_FONT, settings::LAST_FONT, settings::HELP)
SETTING_ENUM(NumberSpaces, nullptr, NumberSeparatorCommand)
SETTING_ENUM(NumberDotOrComma, nullptr, NumberSeparatorCommand)
@ -885,11 +887,71 @@ SETTING_ENUM(FlatMenus, nullptr, MenuAppearance)
SETTING_ENUM(ThreeRowsMenus, nullptr, MenuAppearance)
SETTING_BITS(MenuAppearance, id, 2, ID_SingleRowMenus, ID_ThreeRowsMenus, ID_ThreeRowsMenus)
SETTING_BITS(LineWidth, uint, 8,0, 255, 1)
SETTING(Foreground, ularge(0), ~ularge(0), ularge(0))
SETTING(Background, ularge(0), ~ularge(0), ~ularge(0))
SETTING_BITS(LineWidth, uint, 8,0, 255, 1)
SETTING(CursorBlinkRate, 10, 10000, 500)
SETTING(Background, ularge(0), ~ularge(0), ~ularge(0))
SETTING(Foreground, ularge(0), ~ularge(0), ularge(0))
SETTING(StackBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(StackForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(StackLevelBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(StackLevelForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(StackLineForeground, ularge(0), ~ularge(0), ularge(0xAAAAAAAAAAAAAAAAULL))
SETTING(ResultBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(ResultForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(EditorBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(EditorForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(EditorLineForeground, ularge(0), ~ularge(0), ularge(0xAAAAAAAAAAAAAAAAULL))
SETTING(ErrorBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(ErrorForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(ErrorBorder, ularge(0), ~ularge(0), ularge(0xAAAAAAAAAAAAAAAAULL))
SETTING(SelectionBackground, ularge(0), ~ularge(0), ularge(0))
SETTING(SelectionForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(CursorSelBackground, ularge(0), ~ularge(0), ularge(0))
SETTING(CursorBackground, ularge(0), ~ularge(0), ularge(0))
SETTING(CursorForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(CursorBorder, ularge(0), ~ularge(0), ularge(0))
SETTING(CursorAlphaBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(CursorAlphaForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(CursorAlphaBorder, ularge(0), ~ularge(0), ularge(0))
SETTING(SearchBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(SearchForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(CommandBackground, ularge(0), ~ularge(0), ularge(0))
SETTING(CommandForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(UserCommandBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(UserCommandBorder, ularge(0), ~ularge(0), ularge(0))
SETTING(UserCommandForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(MenuBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(RoundMenuBackground, ularge(0), ~ularge(0), ularge(0))
SETTING(RoundMenuForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(SquareMenuBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(SquareMenuForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(SelectedMenuForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(SkippedMenuBackground, ularge(0), ~ularge(0), ularge(0xAAAAAAAAAAAAAAAAULL))
SETTING(FolderCornerForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(UnimplementedForeground,ularge(0), ~ularge(0), ularge(0xAAAAAAAAAAAAAAAAULL))
SETTING(HeaderBackground, ularge(0), ~ularge(0), ularge(0))
SETTING(DateForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(TimeForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(StateNameForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(RunningIconForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(SteppingIconForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(HaltedIconForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(GCIconForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(LeftShiftBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(LeftShiftForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(RightShiftBackground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(RightShiftForeground, ularge(0), ~ularge(0), ularge(0))
SETTING(AlphaForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(LowerAlphaForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(BatteryForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(BatteryBackground, ularge(0), ~ularge(0), ularge(0))
SETTING(VoltageForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(BatteryLevelForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(HalfBatteryForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(LowBatteryForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING(ChargingForeground, ularge(0), ~ularge(0), ~ularge(0))
SETTING_ENUM(DateSlash, nullptr, DateSeparatorCommand)
SETTING_ENUM(DateDash, nullptr, DateSeparatorCommand)
SETTING_ENUM(DateDot, nullptr, DateSeparatorCommand)

View file

@ -171,7 +171,7 @@ object::result program::run_loop(size_t depth)
if (stepping)
{
ui.draw_busy(L'');
ui.draw_busy(L'', Settings.SteppingIconForeground());
halted = --stepping == 0;
}
}

View file

@ -315,7 +315,7 @@ size_t runtime::gc()
object_p free = first;
object_p next;
ui.draw_busy(L'');
ui.draw_busy(L'', Settings.GCIconForeground());
record(gc, "Garbage collection, available %u, range %p-%p",
available(), first, last);

View file

@ -50,6 +50,86 @@
settings Settings;
settings::settings() :
// ----------------------------------------------------------------------------
// Initial values for all the settings
// ----------------------------------------------------------------------------
#define ID(id)
#define FLAG(Enable, Disable)
#define SETTING(Name,Low,High,Init) Name##_bits(Init),
#define SETTING_BITS(Name,Type,Bits,Low,High,Init)
#include "ids.tbl"
// Define the packed bits settings
#define ID(id)
#define FLAG(Enable, Disable)
#define SETTING(Name, Low, High, Init)
#define SETTING_BITS(Name,Type,Bits,Low,High,Init) Name##_bits(Init - Low),
#include "ids.tbl"
// Define the flags
#define ID(id)
#define FLAG(Enable, Disable) Enable##_bit(false),
#define SETTINGS(Name, Low, High, Init)
#define SETTING_BITS(Name,Type,Bits,Low,High,Init)
#include "ids.tbl"
reserved(false)
{
#ifdef CONFIG_COLOR
AlphaForeground (pattern(200, 224, 224).bits);
LowerAlphaForeground (pattern(200, 224, 255).bits);
LeftShiftForeground (pattern( 0, 0, 0).bits);
RightShiftForeground (pattern( 0, 0, 0).bits);
LeftShiftBackground (pattern(255, 230, 128).bits);
RightShiftBackground (pattern(128, 192, 255).bits);
ChargingForeground (pattern(128, 192, 255).bits);
LowBatteryForeground (pattern(192, 64, 64).bits);
HalfBatteryForeground (pattern(255, 192, 64).bits);
BatteryLevelForeground (pattern( 64, 192, 64).bits);
VoltageForeground (HeaderBackground());
RunningIconForeground (pattern(128, 192, 255).bits);
SteppingIconForeground (pattern( 64, 255, 128).bits);
HaltedIconForeground (pattern(255, 64, 64).bits);
GCIconForeground (pattern(255, 192, 64).bits);
UserCommandBorder (pattern(128, 128, 255).bits);
UserCommandBackground (pattern(224, 224, 224).bits);
CursorBackground (pattern( 0, 128, 64).bits);
CursorBorder (pattern( 0, 64, 0).bits);
CursorForeground (pattern(224, 255, 224).bits);
CursorAlphaBackground (pattern( 0, 64, 128).bits);
CursorAlphaBorder (pattern( 0, 0, 64).bits);
CursorAlphaForeground (pattern(224, 224, 255).bits);
CursorSelBackground (pattern(192, 224, 255).bits);
EditorBackground (pattern(224, 240, 255).bits);
ResultForeground (pattern( 32, 64, 32).bits);
StackForeground (pattern( 96, 96, 128).bits);
StackLevelBackground (pattern(240, 240, 240).bits);
StackLevelForeground (pattern( 96, 0, 0).bits);
SelectionBackground (pattern(255, 255, 128).bits);
SelectionForeground (pattern( 24, 24, 128).bits);
ErrorBackground (pattern(255, 240, 224).bits);
ErrorForeground (pattern( 64, 0, 0).bits);
ErrorBorder (pattern(192, 64, 64).bits);
#else
ChargingForeground (pattern::gray50.bits);
LowBatteryForeground (pattern::gray25.bits);
HalfBatteryForeground (pattern::gray75.bits);
BatteryLevelForeground (pattern::white.bits);
SearchBackground (pattern::gray25.bits);
CursorSelBackground (pattern::gray90.bits);
#endif // CONFIG_COLOR
}
// ============================================================================
//

View file

@ -140,29 +140,7 @@ public:
#include "ids.tbl"
settings() :
#define ID(id)
#define FLAG(Enable, Disable)
#define SETTING(Name,Low,High,Init) Name##_bits(Init),
#define SETTING_BITS(Name,Type,Bits,Low,High,Init)
#include "ids.tbl"
// Define the packed bits settings
#define ID(id)
#define FLAG(Enable, Disable)
#define SETTING(Name, Low, High, Init)
#define SETTING_BITS(Name,Type,Bits,Low,High,Init) Name##_bits(Init - Low),
#include "ids.tbl"
// Define the flags
#define ID(id)
#define FLAG(Enable, Disable) Enable##_bit(false),
#define SETTINGS(Name, Low, High, Init)
#define SETTING_BITS(Name,Type,Bits,Low,High,Init)
#include "ids.tbl"
reserved(false)
{}
settings();
// Accessor functions
#define ID(id)
@ -184,7 +162,7 @@ public:
font_p result_font() { return font(ResultFont()); }
font_p stack_font() { return font(StackFont()); }
font_p editor_font(bool ml) { return font(ml ? MultilineEditorFont() : EditorFont()); }
font_p cursor_font(bool ml) { return cursor_font(ml ? MultilineEditorFont() : EditorFont()); }
font_p cursor_font(bool ml) { return cursor_font(ml ? MultilineCursorFont() : CursorFont()); }
static unicode digit_separator(uint index);

View file

@ -88,18 +88,20 @@ void stack::draw_stack()
coord hdrx = idxfont->width('0') * digits + 2;
size avail = LCD_W - hdrx - 5;
Screen.fill(0, top, LCD_W, bottom, pattern::white);
Screen.fill(0, top, LCD_W, bottom, Settings.StackBackground());
if (rt.editing())
{
bottom--;
Screen.fill(0, bottom, LCD_W, bottom, Settings.EditorLineForeground());
bottom--;
}
if (!depth)
return;
rect clip = Screen.clip();
Screen.fill(hdrx, top, hdrx, bottom, pattern::gray50);
if (rt.editing())
{
bottom--;
Screen.fill(0, bottom, LCD_W, bottom, pattern::gray50);
}
Screen.fill(0, top, hdrx-1, bottom, Settings.StackLevelBackground());
Screen.fill(hdrx, top, hdrx, bottom, Settings.StackLineForeground());
char buf[16];
coord y = bottom;
@ -157,12 +159,15 @@ void stack::draw_stack()
coord yb = y + lineHeight-1;
Screen.clip(0, ytop, LCD_W, yb);
pattern fg = level == 0 ? Settings.ResultForeground()
: Settings.StackForeground();
pattern bg = level == 0 ? Settings.ResultBackground()
: Settings.StackBackground();
if (graph)
{
grob::surface s = graph->pixels();
rect r = s.area();
r.offset(LCD_W - 2 - w, y);
Screen.copy(s, r);
Screen.draw(s, LCD_W - 2 - w, y, fg);
Screen.draw_background(s, LCD_W - 2 - w, y, bg);
}
else
{
@ -249,17 +254,17 @@ void stack::draw_stack()
size offs = lineHeight / 5;
Screen.clip(x, ytop, split, yb);
Screen.text(x, y, out, len, font);
Screen.text(x, y, out, len, font, fg);
Screen.clip(split, ytop, split + skip, yb);
Screen.glyph(split + skip/8, y - offs, sep, font,
pattern::gray50);
Screen.clip(split+skip, y, LCD_W, yb);
Screen.text(LCD_W - 2 - w, y, out, len, font);
Screen.text(LCD_W - 2 - w, y, out, len, font, fg);
}
}
else
{
Screen.text(LCD_W - 2 - w, y, out, len, font);
Screen.text(LCD_W - 2 - w, y, out, len, font, fg);
}
font = Settings.stack_font();
@ -269,7 +274,8 @@ void stack::draw_stack()
Screen.clip(clip);
snprintf(buf, sizeof(buf), "%u", level + 1);
size hw = idxfont->width(utf8(buf));
Screen.text(hdrx - hw, y + idxOffset, utf8(buf), idxfont);
Screen.text(hdrx - hw, y + idxOffset, utf8(buf), idxfont,
Settings.StackLevelForeground());
lineHeight = font->height();
}

View file

@ -6972,6 +6972,7 @@ void tests::graphic_commands()
step("Displaying text, background and foreground");
test(CLEAR,
"1 Gray Background cllcd "
"0.25 Gray Foreground 0.75 Gray Background "
"\"Grayed\" { 0 0 } Disp", ENTER)
.noerror().image("text-gray").test(ENTER);

View file

@ -72,6 +72,7 @@ RECORDER(tests_ui, 16, "Test interaction with user interface");
#define NUM_TOPICS (sizeof(topics) / sizeof(topics[0]))
user_interface::user_interface()
// ----------------------------------------------------------------------------
// Initialize the user interface
@ -1254,16 +1255,16 @@ void user_interface::draw_dirty(const rect &r)
}
bool user_interface::draw_graphics()
bool user_interface::draw_graphics(bool erase)
// ----------------------------------------------------------------------------
// Start graphics mode
// ----------------------------------------------------------------------------
{
if (!graphics)
if (!graphics || erase)
{
draw_start(false);
graphics = true;
Screen.fill(pattern::white);
Screen.fill(pattern(Settings.Background()));
draw_dirty(0, 0, LCD_W, LCD_H);
return true;
}
@ -1369,6 +1370,11 @@ bool user_interface::draw_menus()
continue;
int my = LCD_H - (plane * !single + 1) * mh;
if (force || dirtyMenu)
{
pattern mbg = Settings.StackBackground();
Screen.fill(0, my, LCD_W-1, my+mh-1, mbg);
}
for (int m = 0; m < NUM_SOFTKEYS; m++)
{
uint animask = (1<<(m + plane * NUM_SOFTKEYS));
@ -1382,37 +1388,44 @@ bool user_interface::draw_menus()
draw_dirty(mrect);
bool alt = planes > 1 && plane != shplane;
pattern color = pattern::black;
pattern color = alt
? Settings.RoundMenuBackground()
: Settings.RoundMenuForeground();
if (square)
{
mrect.x2++;
mrect.y2++;
Screen.fill(mrect, alt ? pattern::gray50 : pattern::black);
color = Settings.SquareMenuForeground();
pattern border = alt
? Settings.SkippedMenuBackground()
: Settings.SelectedMenuForeground();
Screen.fill(mrect, border);
mrect.inset(1, 1);
Screen.fill(mrect, pattern::white);
Screen.fill(mrect, pattern(Settings.SquareMenuBackground()));
if (!alt)
{
rect trect(x - mw/2-1, my, x + mw/2, my+1);
Screen.fill(trect, pattern::black);
Screen.fill(trect, color);
trect.offset(0, mh-2);
Screen.fill(trect, pattern::black);
Screen.fill(trect, color);
}
}
else
{
if (!alt)
color = pattern::white;
Screen.fill(mrect, pattern::white);
pattern clr = Settings.MenuBackground();
pattern bg = Settings.RoundMenuBackground();
pattern fg = Settings.RoundMenuForeground();
Screen.fill(mrect, clr);
mrect.inset(3, 1);
Screen.fill(mrect, pattern::black);
Screen.fill(mrect, bg);
mrect.inset(-1, 1);
Screen.fill(mrect, pattern::black);
Screen.fill(mrect, bg);
mrect.inset(-1, 1);
Screen.fill(mrect, pattern::black);
Screen.fill(mrect, bg);
mrect.inset(2, 0);
if (alt)
Screen.fill(mrect, pattern::white);
Screen.fill(mrect, fg);
}
@ -1450,7 +1463,7 @@ bool user_interface::draw_menus()
}
if (mark == L'')
{
color = pattern::gray50;
color = Settings.UnimplementedForeground();
}
else
{
@ -1491,10 +1504,12 @@ bool user_interface::draw_menus()
bool dossier = marker == L'';
if (dossier)
{
pattern fldcol = Settings.FolderCornerForeground();
if (alt || square)
Screen.glyph(mkx+3, ty-3, marker, font, color);
Screen.clip(clip);
Screen.glyph(mkx+4, ty-4, marker, font, pattern::white);
trect.inset(-2,-2);
Screen.clip(trect);
Screen.glyph(mkx+4, ty-4, marker, font, fldcol);
}
else if (marker == '/')
{
@ -1513,7 +1528,8 @@ bool user_interface::draw_menus()
if (square && shplane < visiblePlanes)
{
int my = LCD_H - (shplane * !single + 1) * mh;
Screen.fill(0, my, LCD_W-1, my, pattern::black);
pattern sel = Settings.SelectedMenuForeground();
Screen.fill(0, my, LCD_W-1, my, sel);
}
if (animate)
@ -1525,6 +1541,9 @@ bool user_interface::draw_menus()
}
static const size header_width = 248;
bool user_interface::draw_header()
// ----------------------------------------------------------------------------
// Draw the header with the state name
@ -1535,7 +1554,7 @@ bool user_interface::draw_header()
static uint dow = 0;
bool changed = force;
if (!changed)
if (!changed || !day)
{
dt_t dt;
tm_t tm;
@ -1565,28 +1584,19 @@ bool user_interface::draw_header()
if (changed)
{
size h = HeaderFont->height() + 1;
const coord hdr_right = header_width - 1;
const coord hdr_bottom = HeaderFont->height() + 1;
rect clip = Screen.clip();
rect header(0, 0, LCD_W, h);
rect header = rect(0, 0, hdr_right, hdr_bottom);
Screen.clip(header);
Screen.fill(header, pattern(Settings.HeaderBackground()));
Screen.clip(0, 0, 259, h);
Screen.fill(header, pattern::black);
char buffer[MAX_LCD_LINE_LEN];
size_t sz = 0;
#define EMIT(...) \
do \
{ \
char *to = buffer + sz; \
size_t max = MAX_LCD_LINE_LEN - sz; \
size_t wr = snprintf(to, max, __VA_ARGS__); \
sz += wr; \
} while (0)
coord x = 1;
// Read the real-time clock
if (Settings.ShowDate())
{
renderer r;
char mname[4];
if (Settings.ShowMonthName())
snprintf(mname, 4, "%s", get_month_shortcut(month));
@ -1599,43 +1609,163 @@ bool user_interface::draw_header()
snprintf(ytext, 6, "%d", year);
if (Settings.ShowDayOfWeek())
EMIT("%s ", get_wday_shortcut(dow));
r.printf("%s ", get_wday_shortcut(dow));
char sep = Settings.DateSeparator();
uint index = 2 * Settings.YearFirst() + Settings.MonthBeforeDay();
switch(index)
{
case 0: EMIT("%d%c%s%c%s ", day, sep, mname, sep, ytext); break;
case 1: EMIT("%s%c%d%c%s ", mname, sep, day, sep, ytext); break;
case 2: EMIT("%s%c%d%c%s ", ytext, sep, day, sep, mname); break;
case 3: EMIT("%s%c%s%c%d ", ytext, sep, mname, sep, day); break;
case 0: r.printf("%d%c%s%c%s ", day, sep, mname, sep, ytext); break;
case 1: r.printf("%s%c%d%c%s ", mname, sep, day, sep, ytext); break;
case 2: r.printf("%s%c%d%c%s ", ytext, sep, day, sep, mname); break;
case 3: r.printf("%s%c%s%c%d ", ytext, sep, mname, sep, day); break;
}
pattern datecol = Settings.DateForeground();
x = Screen.text(x, 0, r.text(), r.size(), HeaderFont, datecol);
}
if (Settings.ShowTime())
{
EMIT("%d", Settings.Time24H() ? hour : hour % 12);
EMIT(":%02d", minute);
renderer r;
r.printf("%d", Settings.Time24H() ? hour : hour % 12);
r.printf(":%02d", minute);
if (Settings.ShowSeconds())
EMIT(":%02d", second);
r.printf(":%02d", second);
if (Settings.Time12H())
EMIT("%c", hour < 12 ? 'A' : 'P');
EMIT(" ");
r.printf("%c", hour < 12 ? 'A' : 'P');
r.printf(" ");
pattern timecol = Settings.TimeForeground();
x = Screen.text(x, 0, r.text(), r.size(), HeaderFont, timecol);
draw_refresh(Settings.ShowSeconds() ? 1000 : 1000 * (60 - second));
}
EMIT("%s", state_name());
renderer r;
r.printf("%s", state_name());
Screen.text(1, 0, utf8(buffer), HeaderFont, pattern::white);
pattern namecol = Settings.StateNameForeground();
x = Screen.text(x, 0, r.text(), r.size(), HeaderFont, namecol);
Screen.clip(clip);
draw_dirty(header);
return true;
if (x > coord(header_width))
x = header_width;
busy_left = x;
}
return false;
return changed;
}
static const uint ann_width = 15;
static const uint ann_height = 12;
static const uint ann_width = 15;
static const uint ann_height = 12;
static const uint alpha_width = 30;
bool user_interface::draw_battery()
// ----------------------------------------------------------------------------
// Draw the battery information
// ----------------------------------------------------------------------------
{
static uint last = 0;
uint time = sys_current_ms();
size h = HeaderFont->height() + 1;
coord ann_y = (h - 1 - ann_height) / 2;
// Print battery voltage
static int vdd = 3000;
static bool low = false;
static bool usb = false;
if (time - last > 2000)
{
vdd = (int) read_power_voltage();
low = get_lowbat_state();
usb = usb_powered();
last = time;
}
else if (!force)
{
return false;
}
// Experimentally, battery voltage below 2.6V cause calculator flakiness
const int vmax = BATTERY_VMAX;
const int vmin = BATTERY_VMIN;
const int vhalf = (BATTERY_VMAX + BATTERY_VMIN) / 2;
pattern vpat = usb ? Settings.ChargingForeground()
: low ? Settings.LowBatteryForeground()
: vdd <= vhalf ? Settings.HalfBatteryForeground()
: Settings.BatteryLevelForeground();
pattern bg = Settings.HeaderBackground();
coord x = LCD_W - 1;
if (Settings.ShowVoltage())
{
char buffer[16];
snprintf(buffer, sizeof(buffer), "%d.%03dV", vdd / 1000, vdd % 1000);
pattern vcol = Settings.VoltageForeground();
if (vcol.bits == Settings.HeaderBackground())
vcol = vpat;
size w = HeaderFont->width(utf8(buffer));
x -= w;
rect bgr(x-4, 0, LCD_W-1, h);
Screen.fill(bgr, bg);
Screen.text(x, 0, utf8(buffer), HeaderFont, vcol);
x -= 4;
}
size bat_width = 25;
size bat_tipw = 3;
x -= bat_width;
rect bat_bgr(x, 0, x + bat_width, h);
Screen.fill(bat_bgr, bg);
rect bat_body(x + bat_tipw, ann_y,
x + bat_width - 1, ann_y + ann_height);
pattern bfg = Settings.BatteryForeground();
pattern bbg = Settings.BatteryBackground();
rect bat_tip(x, ann_y + 3, x + 4, ann_y + ann_height - 3);
Screen.fill(bat_tip, bfg);
Screen.fill(bat_body, bfg);
bat_body.inset(1,1);
Screen.fill(bat_body, bbg);
bat_body.inset(1,1);
size batw = bat_body.width();
size w = (vdd - vmin) * batw / (vmax - vmin);
if (w > batw)
w = batw;
else if (w < 1)
w = 1;
bat_body.x1 = bat_body.x2 - w;
Screen.fill(bat_body, vpat);
if (!usb)
{
bat_body.x2 += 1;
while (bat_body.x2 > x + 8)
{
bat_body.x2 -= 4;
bat_body.x1 = bat_body.x2;
Screen.fill(bat_body, bbg);
}
}
battery_left = x;
draw_dirty(x, 0, LCD_W-1, h);
draw_refresh(2000);
// Power off if battery power is really low
if (vdd < BATTERY_VOFF)
power_off();
return true;
}
static const byte ann_right[] =
@ -1667,181 +1797,114 @@ bool user_interface::draw_annunciators()
// Draw the annunciators for Shift, Alpha, etc
// ----------------------------------------------------------------------------
{
bool result = false;
bool adraw = force || alpha != alpha_drawn || lowercase != lowerc_drawn;
bool sdraw = force || shift != shift_drawn || xshift != xshift_drawn;
size lh = HeaderFont->height();
if (force || alpha != alpha_drawn || lowercase != lowerc_drawn)
if (!adraw && !sdraw)
return false;
pattern bg = Settings.HeaderBackground();
size h = HeaderFont->height() + 1;
size alpha_w = alpha_width;
coord alpha_x = battery_left - alpha_w;
coord ann_x = alpha_x - ann_width;
if (busy_right > alpha_x)
adraw = true;
busy_right = battery_left - 1;
if (adraw)
{
utf8 label = utf8(lowercase ? "abc" : "ABC");
size lw = HeaderFont->width(label);
Screen.fill(280, 0, 280+lw, 1+lh, pattern::black);
rect r = rect(alpha_x, 0, battery_left - 1, h);
Screen.fill(r, bg);
if (alpha)
{
#ifdef CONFIG_COLOR
pattern apat = pattern(200, 224, 224);
#else
pattern apat = pattern::white;
#endif // COLOR_CONFIG
Screen.text(280, 0, label, HeaderFont, apat);
utf8 label = utf8(lowercase ? "abc" : "ABC");
pattern apat = lowercase
? Settings.LowerAlphaForeground()
: Settings.AlphaForeground();
Screen.text(alpha_x + 1, 0, label, HeaderFont, apat);
}
draw_dirty(280, 0, 280+lw, 1+lh);
alpha_drawn = alpha;
lowerc_drawn = lowercase;
result = true;
}
if (alpha)
busy_right = alpha_x - 1;
if (!force && shift == shift_drawn && xshift == xshift_drawn)
return result;
if (sdraw)
{
coord ann_y = (h - ann_height) / 2;
rect ann(ann_x, 0, alpha_x - 1, h);
Screen.fill(ann, bg);
const byte *source = xshift ? ann_right : shift ? ann_left : nullptr;
if (source)
{
pixword *sw = (pixword *) source;
grob::surface s(sw, ann_width, ann_height, 16);
pattern fg = shift
? Settings.LeftShiftForeground()
: Settings.RightShiftForeground();
pattern bg = shift
? Settings.LeftShiftBackground()
: Settings.RightShiftBackground();
Screen.draw(s, ann_x, ann_y, fg);
Screen.draw_background(s, ann_x, ann_y, bg);
}
shift_drawn = shift;
xshift_drawn = xshift;
}
if (shift || xshift)
busy_right = ann_x - 1;
coord ann_x = 260;
coord ann_y = (lh - ann_height) / 2;
const byte *source = xshift ? ann_right : shift ? ann_left : nullptr;
if (source)
{
pixword *sw = (pixword *) source;
grob::surface s(sw, ann_width, ann_height, 16);
#ifdef CONFIG_COLOR
pattern color = shift ? pattern(255, 230, 128)
: pattern(128, 192, 255);
Screen.fill(ann_x, ann_y,
260+ann_width, ann_y+ann_height, pattern::black);
Screen.draw(s, ann_x, ann_y, color);
#else
Screen.copy(s, ann_x, ann_y);
#endif
}
else if (!force)
{
Screen.fill(260, ann_y, 260+ann_width, ann_y+ann_height);
}
draw_dirty(260, ann_y, 260+ann_width, ann_y+ann_height);
shift_drawn = shift;
xshift_drawn = xshift;
rect dirty(busy_right+1, 0, battery_left - 1, h);
draw_dirty(dirty);
return true;
}
bool user_interface::draw_battery()
rect user_interface::draw_busy_background()
// ----------------------------------------------------------------------------
// Draw the battery information
// Draw the background behind the busy cursor and annunciators
// ----------------------------------------------------------------------------
{
static uint last = 0;
uint time = sys_current_ms();
const uint ann_height = 12;
size hfh = HeaderFont->height();
coord ann_y = (hfh - ann_height) / 2;
// Print battery voltage
static int vdd = 3000;
static bool low = false;
static bool usb = false;
if (time - last > 2000)
{
vdd = (int) read_power_voltage();
low = get_lowbat_state();
usb = usb_powered();
last = time;
}
else if (!force)
{
return false;
}
// Experimentally, battery voltage below 2.6V cause calculator flakiness
const int vmax = BATTERY_VMAX;
const int vmin = BATTERY_VMIN;
const int vhalf = (BATTERY_VMAX + BATTERY_VMIN) / 2;
#ifdef CONFIG_COLOR
pattern vpat = usb ? pattern(128, 192, 255)
: low ? pattern(192, 64, 64)
: vdd <= vhalf ? pattern(255, 192, 64)
: pattern(64, 192, 64);
#else
pattern vpat = usb ? pattern::gray50
: low ? pattern::gray25
: vdd <= vhalf ? pattern::gray75
: pattern::white;
#endif
bool showv = Settings.ShowVoltage();
coord x = showv ? 311 : 370;
rect bat(x + 3, ann_y+2, x + 25, ann_y + ann_height);
Screen.fill(x-3, 0, LCD_W, hfh + 1, pattern::black);
if (showv)
{
char buffer[64];
snprintf(buffer, sizeof(buffer), "%d.%03dV", vdd / 1000, vdd % 1000);
Screen.text(340, 1, utf8(buffer), HeaderFont, vpat);
}
Screen.fill(x, ann_y + 4, x+4, ann_y + ann_height - 2, pattern::white);
Screen.fill(bat, pattern::white);
bat.inset(1,1);
Screen.fill(bat, pattern::black);
bat.inset(1,1);
size batw = bat.width();
size w = (vdd - vmin) * batw / (vmax - vmin);
if (w > batw)
w = batw;
else if (w < 1)
w = 1;
bat.x1 = bat.x2 - w;
Screen.fill(bat, vpat);
if (!usb)
{
bat.x2 += 1;
while (bat.x2 > x + 8)
{
bat.x2 -= 4;
bat.x1 = bat.x2;
Screen.fill(bat, pattern::black);
}
}
draw_dirty(x, 0, LCD_W, hfh);
draw_refresh(2000);
// Power off if battery power is really low
if (vdd < BATTERY_VOFF)
power_off();
return true;
size h = HeaderFont->height() + 1;
pattern bg = Settings.HeaderBackground();
rect busy(busy_left, 0, busy_right, h);
Screen.fill(busy, bg);
return busy;
}
bool user_interface::draw_busy(unicode glyph)
bool user_interface::draw_busy()
// ----------------------------------------------------------------------------
// Draw the default busy cursor
// ----------------------------------------------------------------------------
{
return draw_busy(L'', Settings.RunningIconForeground());
}
bool user_interface::draw_busy(unicode glyph, pattern color)
// ----------------------------------------------------------------------------
// Draw the busy flying cursor
// ----------------------------------------------------------------------------
{
if (graphics || shift || xshift || alpha)
if (graphics)
return false;
size w = 32;
size h = HeaderFont->height();
size x = 279 - w;
size y = 0;
rect r(x, y, x + w, y + h + 1);
Screen.fill(r, pattern::black);
rect busy = draw_busy_background();
if (glyph)
{
rect clip = Screen.clip();
Screen.clip(r);
coord gx = x + sys_current_ms() / 16 % w;
#ifdef CONFIG_COLOR
Screen.glyph(gx, y, glyph, HeaderFont, pattern(128, 192, 255));
#else
Screen.glyph(gx, y, glyph, HeaderFont, pattern::white);
#endif // CONFIG_COLOR
Screen.clip(busy);
size w = HeaderFont->width('M');
coord x = busy.x1 + sys_current_ms() / 16 % (busy.width() - w);
coord y = busy.y1;
Screen.glyph(x, y, glyph, HeaderFont, color);
Screen.clip(clip);
}
draw_dirty(r);
draw_dirty(busy);
refresh_dirty();
return true;
}
@ -1860,7 +1923,7 @@ bool user_interface::draw_idle()
record(tests_ui, "Redraw LCD");
redraw_lcd(true);
}
draw_busy(0);
draw_busy(0, pattern::black);
alpha_drawn = !alpha_drawn;
shift_drawn = !shift;
xshift_drawn = !xshift;
@ -2083,8 +2146,9 @@ bool user_interface::draw_editor()
stack = y - 1;
dirtyStack = true;
}
Screen.fill(0, stack, LCD_W, bottom, pattern::white);
draw_dirty(0, stack, LCD_W, bottom);
rect edbck(0, stack, LCD_W, bottom);
Screen.fill(edbck, Settings.EditorBackground());
draw_dirty(edbck);
while (r < rows && display <= last)
{
@ -2104,7 +2168,8 @@ bool user_interface::draw_editor()
if (c == '\n')
{
if (sel && x >= 0 && x < LCD_W)
Screen.fill(x, y, LCD_W, y + lineHeight - 1, pattern::black);
Screen.fill(x, y, LCD_W, y + lineHeight - 1,
Settings.SelectionBackground());
y += lineHeight;
x = -xoffset;
r++;
@ -2113,10 +2178,13 @@ bool user_interface::draw_editor()
int cw = font->width(c);
if (x + cw >= 0 && x < LCD_W)
{
pattern fg = sel ? pattern::white : pattern::black;
pattern bg = sel ? (~searching ? pattern::gray25 : pattern::black)
: pattern::white;
x = Screen.glyph(x, y, c, font, fg, bg);
pattern fg = sel ? (~searching ? Settings.SearchForeground()
: Settings.SelectionForeground())
: Settings.EditorForeground();
pattern bg = sel ? (~searching ? Settings.SearchBackground()
: Settings.SelectionBackground())
: Settings.EditorBackground();
x = Screen.glyph(x, y, c, font, fg, bg);
}
else
{
@ -2195,41 +2263,45 @@ bool user_interface::draw_cursor(int show, uint ncursor)
spaces = true;
if (spaces)
cchar = ' ';
size cw = edFont->width(cchar);
bool gray = x == cx && !show;
Screen.fill(x, cy, x + cw - 1, cy + ch - 1,
gray ? pattern::gray75 : pattern::white);
draw_dirty(x, cy, x + cw - 1, cy + ch - 1);
size cw = edFont->width(cchar);
bool cur = x == cx && (!show || blink);
// Write the character under the cursor
uint pos = p - ed;
bool sel = ~select && int((pos - ncursor) ^ (pos - select)) < 0;
pattern fg = sel ? pattern::white : pattern::black;
pattern bg = sel ? (~searching ? pattern::gray25 : pattern::black)
: pattern::white;
x = Screen.glyph(x, cy, cchar, edFont, fg, bg);
uint pos = p - ed;
bool sel = ~select && int((pos - ncursor) ^ (pos - select)) < 0;
pattern fg = sel ? (~searching ? Settings.SearchForeground()
: Settings.SelectionForeground())
: Settings.EditorForeground();
pattern bg = sel ? (~searching ? Settings.SearchBackground()
: Settings.SelectionBackground())
: cur ? Settings.CursorSelBackground()
: Settings.EditorBackground();
x = Screen.glyph(x, cy, cchar, edFont, fg, bg);
draw_dirty(x, cy, x + cw - 1, cy + ch - 1);
if (p < last)
p = utf8_next(p);
}
if (blink)
{
coord csrx = cx + 1;
coord csrx = cx;
coord csry = cy + (ch - csrh)/2;
Screen.invert(csrx, cy, csrx+1, cy + ch - 1);
rect r(csrx, csry - 1, csrx+csrw, csry + csrh);
if (alpha)
{
Screen.fill(r, pattern::black);
r.inset(2,2);
Screen.fill(r, pattern::white);
Screen.glyph(csrx, csry, cursorChar, cursorFont, pattern::black);
}
else
{
Screen.fill(r, pattern::black);
Screen.glyph(csrx, csry, cursorChar, cursorFont, pattern::white);
}
pattern border = alpha
? Settings.CursorAlphaBorder()
: Settings.CursorBorder();
pattern bg = alpha
? Settings.CursorAlphaBackground()
: Settings.CursorBackground();
pattern fg = alpha
? Settings.CursorAlphaForeground()
: Settings.CursorForeground();
Screen.fill(r, border);
r.inset(1,1);
Screen.fill(r, bg);
Screen.glyph(csrx, csry, cursorChar, cursorFont, fg);
draw_dirty(r);
}
@ -2256,9 +2328,11 @@ bool user_interface::draw_command()
coord x = 25;
coord y = HeaderFont->height() + 6;
Screen.fill(x-2, y-1, x+w+2, y+h+1, pattern::black);
Screen.text(x, y, command, font, pattern::white);
draw_dirty(x-2, y-1, x+w+2, y+h+1);
pattern bg = Settings.CommandBackground();
pattern fg = Settings.CommandForeground();
Screen.fill(x - 2, y - 1, x + w + 2, y + h + 1, bg);
Screen.text(x, y, command, font, fg);
draw_dirty(x - 2, y - 1, x + w + 2, y + h + 1);
return true;
}
}
@ -2273,26 +2347,29 @@ void user_interface::draw_user_command(utf8 cmd, size_t len)
// ----------------------------------------------------------------------------
{
font_p font = ReducedFont;
size w = command ? font->width(command) : 0;
size w = font->width(cmd, len);
size h = font->height();
coord x = 25;
coord y = HeaderFont->height() + 6;
// Erase normal command
Screen.fill(x-2, y-1, x + w + 2, y + h + 1, pattern::gray50);
// Draw user command
size nw = font->width(cmd, len);
if (nw > w)
w = nw;
if (command)
{
size w = font->width(command);
pattern bg = Settings.StackBackground();
Screen.fill(x-2, y-1, x + w + 2, y + h + 1, bg);
}
// User-defined command, display in white
rect r(x-2, y-1, x+w+2, y+h+1);
pattern bg = Settings.UserCommandBackground();
pattern fg = Settings.UserCommandForeground();
pattern col = Settings.UserCommandBorder();
rect r(x - 2, y - 1, x + w + 2, y + h + 1);
draw_dirty(r);
Screen.fill(r, pattern::black);
Screen.fill(r, col);
r.inset(1,1);
Screen.fill(r, pattern::white);
Screen.text(x + (w - nw) / 2, y, cmd, len, font, pattern::black);
Screen.fill(r, bg);
Screen.text(x, y, cmd, len, font, fg);
// Update screen
refresh_dirty();
@ -2306,10 +2383,10 @@ bool user_interface::draw_stepping_object()
{
if (object_p obj = rt.run_stepping())
{
char buffer[40];
size_t length = obj->render(buffer, sizeof(buffer));
draw_user_command(utf8(buffer), length);
ui.draw_busy(L'');
renderer r(nullptr, 40);
obj->render(r);
draw_user_command(r.text(), r.size());
draw_busy(L'', Settings.HaltedIconForeground());
return true;
}
return false;
@ -2333,29 +2410,26 @@ bool user_interface::draw_error()
rect clip = Screen.clip();
rect r(x, y, x + width - 1, y + height - 1);
draw_dirty(r);
#ifdef CONFIG_COLOR
Screen.fill(r, pattern(192, 64, 64));
#else // CONFIG_COLOR
Screen.fill(r, pattern::gray50);
#endif // CONFIG_COLOR
Screen.fill(r, Settings.ErrorBorder());
r.inset(border);
Screen.fill(r, pattern::white);
Screen.fill(r, Settings.ErrorBackground());
r.inset(2);
Screen.clip(r);
pattern fg = Settings.ErrorForeground();
if (text_p cmd = rt.command())
{
size_t sz = 0;
utf8 cmdt = cmd->value(&sz);
coord x = Screen.text(r.x1, r.y1, cmdt, sz, ErrorFont);
coord x = Screen.text(r.x1, r.y1, cmdt, sz, ErrorFont, fg);
Screen.text(x, r.y1, utf8(" error:"), ErrorFont);
}
else
{
Screen.text(r.x1, r.y1, utf8("Error:"), ErrorFont);
Screen.text(r.x1, r.y1, utf8("Error:"), ErrorFont, fg);
}
r.y1 += ErrorFont->height();
Screen.text(r.x1, r.y1, err, ErrorFont);
Screen.text(r.x1, r.y1, err, ErrorFont, fg);
Screen.clip(clip);
refresh_dirty();

View file

@ -34,6 +34,7 @@
#include "file.h"
#include "object.h"
#include "runtime.h"
#include "target.h"
#include "text.h"
#include "types.h"
@ -82,10 +83,9 @@ struct user_interface
using result = object::result;
using id = object::id;
typedef blitter::coord coord;
typedef blitter::size size;
typedef blitter::rect rect;
using coord = blitter::coord;
using size = blitter::size;
using rect = blitter::rect;
bool key(int key, bool repeating, bool transalpha);
bool repeating() { return repeat; }
@ -119,10 +119,15 @@ struct user_interface
uint draw_refresh() { return nextRefresh; }
rect draw_dirty() { return dirty; }
void draw_clean() { dirty = rect(); }
bool draw_graphics();
bool draw_graphics(bool erase = false);
bool draw_header();
bool draw_annunciators();
bool draw_header(); // Left part of header
bool draw_battery(); // Rightmost part of header
bool draw_annunciators(); // Left of battery
bool draw_busy(unicode glyph, pattern col);
rect draw_busy_background();
bool draw_busy();
bool draw_idle();
bool draw_editor();
bool draw_stack();
bool draw_error();
@ -134,10 +139,7 @@ struct user_interface
bool draw_stepping_object();
bool draw_menus();
bool draw_battery();
bool draw_cursor(int show, uint ncursor);
bool draw_busy(unicode glyph = L'');
bool draw_idle();
modes editing_mode() { return mode; }
int stack_screen_bottom() { return stack; }
@ -201,6 +203,7 @@ protected:
bool noHelpForKey(int key);
bool do_search(unicode with = 0, bool restart = false);
public:
int evaluating; // Key being evaluated
@ -228,6 +231,9 @@ protected:
uint menuPages; // Number of menu pages
uint menuHeight; // Height of the menu
uint busy; // Busy counter
coord busy_left; // Left column for busy area in header
coord busy_right; // Right column for busy area in header
coord battery_left; // Left column for battery in header
uint nextRefresh; // Time for next refresh
rect dirty; // Dirty rectangles
object_g editing; // Object being edited if any
@ -270,7 +276,7 @@ protected:
file helpfile;
friend struct tests;
friend struct runtime;
};
};
inline int user_interface::evaluating_function_key() const