first implementation of console buffer. This has to be tested first - might contain bugs

ugfx_release_2.6
Joel Bodenmann 2013-12-18 16:49:49 +01:00
parent 92750f0207
commit aa2f7585ce
4 changed files with 147 additions and 21 deletions

View File

@ -31,6 +31,13 @@ typedef struct GConsoleObject {
GWindowObject g;
coord_t cx, cy; // Cursor position
#if GWIN_CONSOLE_NEED_HISTORY
char* buffer; // buffer to store console content
uint16_t last_char; // the last rendered character
size_t size; // size of buffer
bool_t store; // shall PutChar() store into buffer
#endif
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
struct GConsoleWindowStream_t {
const struct GConsoleWindowVMT_t *vmt;
@ -82,6 +89,22 @@ GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *p
BaseSequentialStream *gwinConsoleGetStream(GHandle gh);
#endif
#if GWIN_CONSOLE_NEED_HISTORY
/**
* @brief Assing a buffer to keep track of the content while the widget is invisible.
* @pre GWIN_CONSOLE_NEED_HISTORY must be set to TRUE in your gfxconf.h
*
* @param[in] gh The window handle (must be a console window)
* @param[in] buffer The pointer of the buffer that shall be used. Buffer will be
* dynamically allocated when this is NULL.
* @param[in] size Size of the buffer that has been passed. If buffer is NULL, this
* will be the size of the dynamically allocated buffer.
*
* @return TRUE on success
*/
bool_t gwinConsoleSetBuffer(GHandle gh, void* buffer, size_t size);
#endif
/**
* @brief Put a character at the cursor position in the window.
* @note Uses the current foreground color to draw the character and fills the background using the background drawing color

View File

@ -105,6 +105,17 @@
#ifndef GWIN_BUTTON_LAZY_RELEASE
#define GWIN_BUTTON_LAZY_RELEASE FALSE
#endif
/**
* @brief Should the content of the console be logged or not
* @details If this feature is enable, the content of the console will be stored.
* Every content that gets printed to the console while being invisible
* will be rendered once the console is visible again. All previous written
* content will be restored too.
* @details Defaults to FALSE
*/
#ifndef GWIN_NEED_CONSOLE_HISTORY
#define GWIN_NEED_CONSOLE_HISTORY FALSE
#endif
/**
* @brief Console Windows need floating point support in @p gwinPrintf
* @details Defaults to FALSE

View File

@ -53,28 +53,68 @@
};
#endif
#if GWIN_CONSOLE_NEED_HISTORY
static void CustomRedraw(GWindowObject *gh) {
#define gcw ((GConsoleObject *)gh)
uint16_t i;
// loop through buffer and don't add it again
gcw->store = FALSE;
for (i = 0; i < gcw->last_char; i++) {
gwinPutChar(gh, gcw->buffer[i]);
}
gcw->store = TRUE;
#undef gcw
}
#endif
static void AfterClear(GWindowObject *gh) {
((GConsoleObject *)gh)->cx = 0;
((GConsoleObject *)gh)->cy = 0;
#define gcw ((GConsoleObject *)gh)
gcw->cx = 0;
gcw->cy = 0;
#if GWIN_CONSOLE_NEED_HISTORY
// issue an overflow, this is some kind
// of emptying the buffer
gcw->last_char = gcw->size;
#endif
#undef gcw
}
static const gwinVMT consoleVMT = {
"Console", // The classname
sizeof(GConsoleObject), // The object size
0, // The destroy routine
0, // The redraw routine
AfterClear, // The after-clear routine
"Console", // The classname
sizeof(GConsoleObject), // The object size
0, // The destroy routine
#if GWIN_CONSOLE_NEED_HISTORY
CustomRedraw, // The redraw routine (custom)
#else
0, // The redraw routine (default)
#endif
AfterClear, // The after-clear routine
};
GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *pInit) {
if (!(gc = (GConsoleObject *)_gwindowCreate(g, &gc->g, pInit, &consoleVMT, 0)))
return 0;
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
gc->stream.vmt = &GWindowConsoleVMT;
#endif
#if GWIN_CONSOLE_NEED_HISTORY
gc->buffer = 0;
gc->size = 0;
gc->last_char = 0;
#endif
gc->cx = 0;
gc->cy = 0;
gwinSetVisible((GHandle)gc, pInit->show);
return (GHandle)gc;
}
@ -82,20 +122,72 @@ GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *p
BaseSequentialStream *gwinConsoleGetStream(GHandle gh) {
if (gh->vmt != &consoleVMT)
return 0;
return (BaseSequentialStream *)&(((GConsoleObject *)(gh))->stream);
}
#endif
#if GWIN_CONSOLE_NEED_HISTORY
bool_t gwinConsoleSetBuffer(GHandle gh, void* buffer, size_t size) {
#define gcw ((GConsoleObject *)gh)
uint8_t buf_width, buf_height, fp, fy;
if (gh->vmt != &consoleVMT)
return FALSE;
// assign buffer or allocate new one
if (buffer == 0) {
(void)size;
// calculate buffer size
fy = gdispGetFontMetric(gh->font, fontHeight);
fp = gdispGetFontMetric(gh->font, fontMinWidth);
buf_height = (gh->height / fy);
buf_width = (gh->width / fp);
if ((gcw->buffer = (char*)gfxAlloc(buf_width * buf_height)) == 0)
return FALSE;
gcw->size = buf_width * buf_height;
} else {
if (size <= 0)
return FALSE;
gcw->buffer = (char*)buffer;
gcw->size = size;
}
gcw->last_char = 0;
return TRUE;
#undef gcw
}
#endif
void gwinPutChar(GHandle gh, char c) {
#define gcw ((GConsoleObject *)gh)
uint8_t width, fy, fp;
if (!gwinGetVisible(gh))
return;
if (gh->vmt != &consoleVMT || !gh->font)
return;
#if GWIN_CONSOLE_NEED_HISTORY
// buffer overflow check
if (gcw->last_char >= gcw->size)
gcw->last_char = 0;
// store new character in buffer
if (gcw->store && gcw->buffer != 0)
gcw->buffer[gcw->last_char++] = c;
// only render new character and don't issue a complete redraw (performance...)
if (!gwinGetVisible(gh))
return;
#endif
fy = gdispGetFontMetric(gh->font, fontHeight);
fp = gdispGetFontMetric(gh->font, fontCharPadding);
@ -150,17 +242,11 @@ void gwinPutChar(GHandle gh, char c) {
}
void gwinPutString(GHandle gh, const char *str) {
if (!gwinGetVisible(gh))
return;
while(*str)
gwinPutChar(gh, *str++);
}
void gwinPutCharArray(GHandle gh, const char *str, size_t n) {
if (!gwinGetVisible(gh))
return;
while(n--)
gwinPutChar(gh, *str++);
}
@ -220,9 +306,6 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) {
char tmpbuf[MAX_FILLER + 1];
#endif
if (!gwinGetVisible(gh))
return;
if (gh->vmt != &consoleVMT || !gh->font)
return;

View File

@ -251,15 +251,24 @@ void gwinRedraw(GHandle gh) {
#endif
void gwinClear(GHandle gh) {
if (!((gh->flags & GWIN_FLG_VISIBLE)))
return;
/*
* Don't render anything when the window is not visible but
* still call the AfterClear() routine as some widgets will
* need this to clear internal buffers or similar
*/
if (!((gh->flags & GWIN_FLG_VISIBLE))) {
if (gh->vmt->AfterClear)
gh->vmt->AfterClear(gh);
} else {
#if GDISP_NEED_CLIP
gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height);
#endif
gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
if (gh->vmt->AfterClear)
gh->vmt->AfterClear(gh);
}
}
void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) {