📄 dismgr.c
字号:
/*
* Display manager.
*
* This is a beta implementation of VYn_wbu3836 v1.0.
*
* Copyright (C) 2004-2005 Cambridge Silicon Radio Ltd.
*/
/*#define NOBF*/
#include "dismgr.h"
#include "lcd.h"
#include <font.h>
#if 0
#include <pio.h>
#else
#define PioSetDir(x,y)
#define PioSet(x,y)
#endif
#include <util.h>
#include <message.h>
#include <vm.h>
#include <panic.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define ASSERT assert
#if LCD_WIDTH <= LCD_COLUMN_LEFT + DISMGR_MAX_COLUMN
#error Display too wide for LCD
#endif
#if LCD_HEIGHT <= 15
#error Display too tall for LCD
#endif
static struct DISMGR_STATE {
TaskData task;
/*
* The prompt to display, its length, the current index within it,
* its bounds, and its framebuffer.
*/
const uint16 *prompt;
#ifdef NOBF
unsigned int prompt_len;
unsigned int prompt_index;
unsigned int prompt_first;
unsigned int prompt_wid;
unsigned int left_to_right; /* see below */
#else
# define DISMGR_BITS_PROMPT_LEN 8
unsigned int prompt_len : DISMGR_BITS_PROMPT_LEN;
unsigned int prompt_index : DISMGR_BITS_PROMPT_LEN;
# define DISMGR_BITS_PROMPT_POS 7
unsigned int prompt_first : DISMGR_BITS_PROMPT_POS;
unsigned int prompt_wid : DISMGR_BITS_PROMPT_POS;
# if DISMGR_MAX_COLUMN >= (1 << DISMGR_BITS_PROMPT_POS)
# error "prompt_first and prompt_last bitfields too small"
# endif
unsigned int left_to_right : 1; /* see below */
/* 1 spare bit */
#endif
uint16 *framebuf; /* one word per column; NULL iff not scrolling */
/*
* The glyph currently being rendered, its width, and the current
* index within it.
*/
#ifdef NOBF
uint16 glyph[DISMGR_MAX_GLYPH_WID];
unsigned int glyph_wid;
unsigned int glyph_index;
unsigned int incrementing;
unsigned int next_thing;
# define DISMGR_NEXT_THING_STOP_NOW 0
# define DISMGR_NEXT_THING_STOP 1
# define DISMGR_NEXT_THING_CHANGE_DIR_THEN_STOP 2
# define DISMGR_NEXT_THING_CHANGE_DIR 3
# define DISMGR_NEXT_THING_CONTINUE 4
unsigned int font;
unsigned int prompt_font;
#else
# define DISMGR_BITS_GLYPH_WID 4
uint16 glyph[DISMGR_MAX_GLYPH_WID];
unsigned int glyph_wid : DISMGR_BITS_GLYPH_WID;
unsigned int glyph_index : DISMGR_BITS_GLYPH_WID;
# if DISMGR_MAX_GLYPH_WID >= (1 << DISMGR_BITS_GLYPH_WID)
# error "glyph_wid and glyph_index bitfields too small"
# endif
/*
* The scroll state consists of four elements:
* - which way we're indexing the prompt
* - which way we started indexing the prompt (variable moved above)
* - what we should do at the end of the current scroll
* - whether we need to delay the next step (variable moved below)
*/
unsigned int incrementing : 1;
unsigned int next_thing : 3;
# define DISMGR_NEXT_THING_STOP_NOW 0
# define DISMGR_NEXT_THING_STOP 1
# define DISMGR_NEXT_THING_CHANGE_DIR_THEN_STOP 2
# define DISMGR_NEXT_THING_CHANGE_DIR 3
# define DISMGR_NEXT_THING_CONTINUE 4
/*
* The font selected, and the font currently in use.
*/
# define DISMGR_BITS_FONT 2
unsigned int font : DISMGR_BITS_FONT;
unsigned int prompt_font : DISMGR_BITS_FONT;
/* 0 spare bits */
unsigned int delay;
#endif
} dismgr_state;
/*
* Like FontGetGlyph() but on failure try various other options
* in increasing order of desperation.
* If FONT_REPLACEMENT_CHARACTER is #defined then panics on failure,
* else returns (size_t) -1 on failure.
*/
static size_t FontGetGlyphAny (FontId font, ucs2char c, uint16 *glyph, size_t max_glyph_wid)
{
size_t wid;
wid = FontGetGlyph (font, c, glyph, max_glyph_wid);
if (wid != (size_t) -1)
{
return wid;
}
wid = FontGetGlyph (0, c, glyph, max_glyph_wid);
if (wid != (size_t) -1)
{
return wid;
}
#ifdef FONT_REPLACEMENT_CHARACTER
wid = FontGetGlyph (font, FONT_REPLACEMENT_CHARACTER, glyph, max_glyph_wid);
if (wid != (size_t) -1)
{
return wid;
}
wid = FontGetGlyph (0, FONT_REPLACEMENT_CHARACTER, glyph, max_glyph_wid);
if (wid != (size_t) -1)
{
return wid;
}
Panic ();
#endif
return (size_t) -1;
}
/*
* Render the whole buffer.
* Returns TRUE iff entire prompt fits.
* If not_really then only render the last logical column.
* If dots then add (up to) three dots at the end (even if not_really),
* starting on a glyph boundary.
* If the entire prompt fits or dots were added then the final
* dismgr_state is indeterminate and should not be reused.
*/
static bool DismgrRenderFramebuffer (bool not_really, bool dots)
{
uint8 prompt_pos;
uint16 dots_width = 0;
uint8 prompt_wid = dismgr_state.prompt_wid;
size_t glyph_wid, glyph_index;
bool incrementing = dismgr_state.incrementing;
if (dots)
{
glyph_wid = FontGetGlyphAny (dismgr_state.prompt_font, '.', NULL, 0);
if (glyph_wid != (size_t) -1)
{
dots_width = 3 * glyph_wid;
}
#ifndef FONT_REPLACEMENT_CHARACTER
else
{
/* No dot glyph, no dots! */
dots = FALSE;
dots_width = 0;
}
#endif
}
prompt_pos = 0;
for (dismgr_state.prompt_index = 0;
dismgr_state.prompt_index < dismgr_state.prompt_len;
++dismgr_state.prompt_index)
{
glyph_wid = FontGetGlyphAny (dismgr_state.prompt_font,
dismgr_state.prompt[incrementing ?
dismgr_state.prompt_index :
dismgr_state.prompt_len - dismgr_state.prompt_index - 1],
dismgr_state.glyph, sizeof (dismgr_state.glyph));
/*
* The glyph must exist if we get here (otherwise we'd either
* have rejected the prompt in DismgrDisplayPrompt() or panicked
* in the FontGetGlyphAny() above).
*/
if (prompt_pos + glyph_wid + dots_width <= prompt_wid)
{
/*
* Glyph fits entirely -- copy over.
*/
if (!not_really)
{
memcpy (&dismgr_state.framebuf[incrementing ?
prompt_pos : prompt_wid - glyph_wid - prompt_pos],
dismgr_state.glyph, glyph_wid);
}
prompt_pos += glyph_wid;
continue;
}
else if (dots)
{
/*
* Glyph does not fit -- add three dots and padding.
* Could in principle use 0x2026 HORIZONTAL ELLIPSIS
* but this might (a) not be present and (b) be more directional.
*/
uint8 ndots;
glyph_wid = FontGetGlyphAny (dismgr_state.prompt_font, '.', dismgr_state.glyph, sizeof (dismgr_state.glyph));
for (ndots = 0; ndots < 3; ++ndots)
{
if (prompt_pos + glyph_wid > prompt_wid)
{
/*
* Dot glyph does not fit -- copy over the part that fits.
*/
glyph_index = prompt_wid - prompt_pos;
if (incrementing)
{
memcpy (&dismgr_state.framebuf[prompt_pos],
dismgr_state.glyph,
glyph_index);
}
else
{
memcpy (dismgr_state.framebuf,
&dismgr_state.glyph[glyph_wid - glyph_index],
glyph_index);
}
return FALSE;
}
/*
* Dot glyph fits entirely -- copy over.
*/
memcpy (&dismgr_state.framebuf[incrementing ?
prompt_pos : prompt_wid - glyph_wid - prompt_pos],
dismgr_state.glyph,
glyph_wid);
prompt_pos += glyph_wid;
}
/*
* Pad out.
*/
memset (&dismgr_state.framebuf[incrementing ? prompt_pos : 0],
0, prompt_wid - prompt_pos);
return FALSE;
}
/*
* Glyph does not fit -- copy over the part that fits.
*/
dismgr_state.glyph_index = glyph_index = prompt_wid - prompt_pos;
dismgr_state.glyph_wid = glyph_wid;
if (incrementing)
{
memcpy (&dismgr_state.framebuf[prompt_pos],
dismgr_state.glyph, glyph_index);
}
else
{
memcpy (dismgr_state.framebuf,
&dismgr_state.glyph[glyph_wid - glyph_index], glyph_index);
}
return FALSE;
}
/*
* Prompt fits -- pad out.
*/
memset (&dismgr_state.framebuf[incrementing ? prompt_pos : 0],
0, prompt_wid - prompt_pos);
return TRUE;
}
/*
* Output the prompt.
*/
static bool DismgrOutputPrompt (void)
{
bool ok;
if (!LcdOutput ((const uint8 *) dismgr_state.framebuf,
dismgr_state.prompt_wid,
LCD_COLUMN_LEFT + dismgr_state.prompt_first,
LCD_LINE_BOTTOM))
{
/* Try to maintain display integrity -- abort on failure */
return FALSE;
}
ok = TRUE;
UtilSwap (dismgr_state.framebuf, dismgr_state.prompt_wid);
if (!LcdOutput ((const uint8 *) dismgr_state.framebuf,
dismgr_state.prompt_wid,
LCD_COLUMN_LEFT + dismgr_state.prompt_first,
LCD_LINE_TOP))
{
/* ... of course, this won't work if the second output fails */
ok = FALSE;
}
UtilSwap (dismgr_state.framebuf, dismgr_state.prompt_wid);
return ok;
}
/*
* Scroll by one.
*/
static void DismgrScroll (Task task, MessageId id, Message message)
{
#ifndef DISMGR_SCROLL_SIZE
#define DISMGR_SCROLL_SIZE 1
#endif
uint32 t = VmGetClock ();
#if DISMGR_SCROLL_SIZE > 1
/*
* SCROLLING BY MORE THAN ONE PIXEL PER STEP IS NOT FORMALLY SUPPORTED.
* THE CORRESPONDING CODE IS A PROTOTYPE WHICH IS KNOWN TO BE INCOMPLETE
* AND MAY NOT BE MAINTAINED.
*/
uint16 step;
#else
uint8 prompt_wid_minus_one = dismgr_state.prompt_wid - 1;
#endif
uint16 glyph_column;
/*
* Update the LCD.
* Do this first so that the LCD is updated as regularly as possible,
* however long the scrolling takes to perform.
*/
/*
BP
PioSet (1 << 10, 1 << 10);
DismgrOutputPrompt ();
PioSet (1 << 10, 0 << 10);
*/
PioSet (1 << 8, 1 << 8);
DismgrOutputPrompt ();
PioSet (1 << 8, 0 << 8);
/*
* Are we just to delay a bit?
*/
if (dismgr_state.delay)
{
if (dismgr_state.next_thing == DISMGR_NEXT_THING_STOP_NOW)
{
/* Add the dots and render from the other end */
dismgr_state.incrementing = dismgr_state.left_to_right;
DismgrRenderFramebuffer (FALSE, TRUE);
}
MessageSendLater (&dismgr_state.task, 0, NULL, dismgr_state.delay);
dismgr_state.delay = 0;
return;
}
/*
* Stop if we've reached the end.
*/
if (dismgr_state.next_thing == DISMGR_NEXT_THING_STOP_NOW)
{
free (dismgr_state.framebuf);
dismgr_state.framebuf = NULL;
return;
}
/*
* Shift and insert the next glyph column.
*/
/*
BP
PioSet (1 << 10, 1 << 10);
*/
PioSet (1 << 8, 1 << 8);
#if DISMGR_SCROLL_SIZE > 1
if (dismgr_state.incrementing)
{
memmove (dismgr_state.framebuf,
dismgr_state.framebuf + DISMGR_SCROLL_SIZE,
dismgr_state.prompt_wid - DISMGR_SCROLL_SIZE);
}
else
{
memmove (dismgr_state.framebuf + DISMGR_SCROLL_SIZE,
dismgr_state.framebuf,
dismgr_state.prompt_wid - DISMGR_SCROLL_SIZE);
}
for (step = 0; step < DISMGR_SCROLL_SIZE; ++step)
{
if (dismgr_state.incrementing)
{
glyph_column = dismgr_state.glyph[dismgr_state.glyph_index++];
dismgr_state.framebuf[dismgr_state.prompt_wid - DISMGR_SCROLL_SIZE + step] = glyph_column;
}
else
{
glyph_column = dismgr_state.glyph[dismgr_state.glyph_wid - dismgr_state.glyph_index++ - 1];
dismgr_state.framebuf[DISMGR_SCROLL_SIZE - step - 1] = glyph_column;
}
#else
if (dismgr_state.incrementing)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -