first implementation of console buffer. This has to be tested first - might contain bugs
This commit is contained in:
parent
92750f0207
commit
aa2f7585ce
4 changed files with 147 additions and 21 deletions
|
@ -31,6 +31,13 @@ typedef struct GConsoleObject {
|
||||||
GWindowObject g;
|
GWindowObject g;
|
||||||
coord_t cx, cy; // Cursor position
|
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
|
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
|
||||||
struct GConsoleWindowStream_t {
|
struct GConsoleWindowStream_t {
|
||||||
const struct GConsoleWindowVMT_t *vmt;
|
const struct GConsoleWindowVMT_t *vmt;
|
||||||
|
@ -82,6 +89,22 @@ GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *p
|
||||||
BaseSequentialStream *gwinConsoleGetStream(GHandle gh);
|
BaseSequentialStream *gwinConsoleGetStream(GHandle gh);
|
||||||
#endif
|
#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.
|
* @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
|
* @note Uses the current foreground color to draw the character and fills the background using the background drawing color
|
||||||
|
|
|
@ -105,6 +105,17 @@
|
||||||
#ifndef GWIN_BUTTON_LAZY_RELEASE
|
#ifndef GWIN_BUTTON_LAZY_RELEASE
|
||||||
#define GWIN_BUTTON_LAZY_RELEASE FALSE
|
#define GWIN_BUTTON_LAZY_RELEASE FALSE
|
||||||
#endif
|
#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
|
* @brief Console Windows need floating point support in @p gwinPrintf
|
||||||
* @details Defaults to FALSE
|
* @details Defaults to FALSE
|
||||||
|
|
|
@ -53,28 +53,68 @@
|
||||||
};
|
};
|
||||||
#endif
|
#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) {
|
static void AfterClear(GWindowObject *gh) {
|
||||||
((GConsoleObject *)gh)->cx = 0;
|
#define gcw ((GConsoleObject *)gh)
|
||||||
((GConsoleObject *)gh)->cy = 0;
|
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 = {
|
static const gwinVMT consoleVMT = {
|
||||||
"Console", // The classname
|
"Console", // The classname
|
||||||
sizeof(GConsoleObject), // The object size
|
sizeof(GConsoleObject), // The object size
|
||||||
0, // The destroy routine
|
0, // The destroy routine
|
||||||
0, // The redraw routine
|
#if GWIN_CONSOLE_NEED_HISTORY
|
||||||
|
CustomRedraw, // The redraw routine (custom)
|
||||||
|
#else
|
||||||
|
0, // The redraw routine (default)
|
||||||
|
#endif
|
||||||
AfterClear, // The after-clear routine
|
AfterClear, // The after-clear routine
|
||||||
};
|
};
|
||||||
|
|
||||||
GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *pInit) {
|
GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *pInit) {
|
||||||
if (!(gc = (GConsoleObject *)_gwindowCreate(g, &gc->g, pInit, &consoleVMT, 0)))
|
if (!(gc = (GConsoleObject *)_gwindowCreate(g, &gc->g, pInit, &consoleVMT, 0)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
|
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
|
||||||
gc->stream.vmt = &GWindowConsoleVMT;
|
gc->stream.vmt = &GWindowConsoleVMT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if GWIN_CONSOLE_NEED_HISTORY
|
||||||
|
gc->buffer = 0;
|
||||||
|
gc->size = 0;
|
||||||
|
gc->last_char = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
gc->cx = 0;
|
gc->cx = 0;
|
||||||
gc->cy = 0;
|
gc->cy = 0;
|
||||||
|
|
||||||
gwinSetVisible((GHandle)gc, pInit->show);
|
gwinSetVisible((GHandle)gc, pInit->show);
|
||||||
|
|
||||||
return (GHandle)gc;
|
return (GHandle)gc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,20 +122,72 @@ GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *p
|
||||||
BaseSequentialStream *gwinConsoleGetStream(GHandle gh) {
|
BaseSequentialStream *gwinConsoleGetStream(GHandle gh) {
|
||||||
if (gh->vmt != &consoleVMT)
|
if (gh->vmt != &consoleVMT)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (BaseSequentialStream *)&(((GConsoleObject *)(gh))->stream);
|
return (BaseSequentialStream *)&(((GConsoleObject *)(gh))->stream);
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
void gwinPutChar(GHandle gh, char c) {
|
||||||
#define gcw ((GConsoleObject *)gh)
|
#define gcw ((GConsoleObject *)gh)
|
||||||
uint8_t width, fy, fp;
|
uint8_t width, fy, fp;
|
||||||
|
|
||||||
if (!gwinGetVisible(gh))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (gh->vmt != &consoleVMT || !gh->font)
|
if (gh->vmt != &consoleVMT || !gh->font)
|
||||||
return;
|
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);
|
fy = gdispGetFontMetric(gh->font, fontHeight);
|
||||||
fp = gdispGetFontMetric(gh->font, fontCharPadding);
|
fp = gdispGetFontMetric(gh->font, fontCharPadding);
|
||||||
|
|
||||||
|
@ -150,17 +242,11 @@ void gwinPutChar(GHandle gh, char c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void gwinPutString(GHandle gh, const char *str) {
|
void gwinPutString(GHandle gh, const char *str) {
|
||||||
if (!gwinGetVisible(gh))
|
|
||||||
return;
|
|
||||||
|
|
||||||
while(*str)
|
while(*str)
|
||||||
gwinPutChar(gh, *str++);
|
gwinPutChar(gh, *str++);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gwinPutCharArray(GHandle gh, const char *str, size_t n) {
|
void gwinPutCharArray(GHandle gh, const char *str, size_t n) {
|
||||||
if (!gwinGetVisible(gh))
|
|
||||||
return;
|
|
||||||
|
|
||||||
while(n--)
|
while(n--)
|
||||||
gwinPutChar(gh, *str++);
|
gwinPutChar(gh, *str++);
|
||||||
}
|
}
|
||||||
|
@ -220,9 +306,6 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) {
|
||||||
char tmpbuf[MAX_FILLER + 1];
|
char tmpbuf[MAX_FILLER + 1];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!gwinGetVisible(gh))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (gh->vmt != &consoleVMT || !gh->font)
|
if (gh->vmt != &consoleVMT || !gh->font)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -251,16 +251,25 @@ void gwinRedraw(GHandle gh) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void gwinClear(GHandle gh) {
|
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
|
#if GDISP_NEED_CLIP
|
||||||
gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height);
|
gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
|
gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
|
||||||
if (gh->vmt->AfterClear)
|
if (gh->vmt->AfterClear)
|
||||||
gh->vmt->AfterClear(gh);
|
gh->vmt->AfterClear(gh);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) {
|
void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) {
|
||||||
if (!((gh->flags & GWIN_FLG_VISIBLE)))
|
if (!((gh->flags & GWIN_FLG_VISIBLE)))
|
||||||
|
|
Loading…
Add table
Reference in a new issue