From bc87d740f55cfd0d283c6342abf641dfd0ff2e42 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 18 May 2019 15:54:26 -1000 Subject: GLK: TADS2: Yet more volumous code additions --- engines/glk/tads/os_banners.cpp | 812 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 812 insertions(+) create mode 100644 engines/glk/tads/os_banners.cpp (limited to 'engines/glk/tads/os_banners.cpp') diff --git a/engines/glk/tads/os_banners.cpp b/engines/glk/tads/os_banners.cpp new file mode 100644 index 0000000000..577e9f3dd3 --- /dev/null +++ b/engines/glk/tads/os_banners.cpp @@ -0,0 +1,812 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "glk/tads/os_banners.h" +#include "glk/tads/os_buffer.h" +#include "glk/tads/tads.h" +#include "glk/glk_api.h" +#include "glk/window_text_buffer.h" + +namespace Glk { +namespace TADS { + +struct os_banner_t; +struct banner_contents_t; +typedef os_banner_t *osbanid_t; +typedef banner_contents_t *contentid_t; + +/* for tracking banner windows */ +struct os_banner_t { + uint id; /* unique identifier */ + uint valid; /* banner status */ + + osbanid_t prev; /* previous sibling */ + osbanid_t next; /* next sibling */ + osbanid_t children; /* child's descendents */ + osbanid_t parent; /* child's parent */ + + uint method; /* glk window method */ + uint size; /* glk window size */ + uint type; /* glk window type */ + uint status; /* glk status style */ + + uint cheight; /* glk char height */ + uint cwidth; /* glk char width */ + + uint fgcolor; /* foreground color */ + uint bgcolor; /* background color */ + uint fgcustom; /* custom colors */ + uint bgcustom; + uint bgtrans; + + contentid_t contents; /* window contents */ + uint style; /* active Glk style value */ + uint newline; /* active newline */ + uint move, x, y; /* active cursor position */ + + winid_t win; /* glk window object */ +}; + +/* for reprinting banner contents */ +struct banner_contents_t { + osbanid_t banner; /* content owner */ + contentid_t next; /* next set of contents */ + + uint style; /* stored contents style */ + uint newline; /* stored newline */ + uint move, x, y; /* stored cursor position */ + + char *chars; + uint len; +}; + +static osbanid_t os_banners = NULL; +static uint os_banner_count = 999; + +extern winid_t mainwin; +extern winid_t statuswin; + +extern uint mainfg; +extern uint mainbg; + +extern uint statusfg; +extern uint statusbg; + +void banner_contents_display(contentid_t contents); + +/* Implementation-specific functions for managing banner windows */ +/* + os_banner_init(); + os_banner_insert(); + os_banner_styles_apply(); + os_banner_styles_reset(); + os_banners_close(); + os_banners_open(); + os_banners_redraw(); +*/ + +osbanid_t os_banner_init() { + osbanid_t instance; + instance = (osbanid_t)malloc(sizeof(os_banner_t)); + if (!instance) + return 0; + + instance->id = ++ os_banner_count; + instance->valid = 1; + + instance->prev = 0; + instance->next = 0; + instance->children = 0; + instance->parent = 0; + + instance->method = 0; + instance->size = 0; + instance->type = 0; + instance->status = 0; + + instance->cheight = 0; + instance->cwidth = 0; + + instance->contents = 0; + instance->style = style_Normal; + instance->newline = 0; + instance->move = 0; + instance->x = 0; + instance->y = 0; + + instance->win = 0; + + return instance; +} + +osbanid_t os_banner_insert(osbanid_t parent, uint operation, osbanid_t other, + uint method, uint size, uint type, uint status) +{ + if (!parent || !(parent->valid)) + return 0; + + if (operation == OS_BANNER_BEFORE || operation == OS_BANNER_AFTER) + if (!other || !(other->valid) || !(other->parent == parent)) + operation = OS_BANNER_LAST; + + osbanid_t baby = os_banner_init(); + if (!baby) + return 0; + baby->parent = parent; + + if (!(parent->children)) + { + parent->children = baby; + } + else + { + osbanid_t child = parent->children; + + switch (operation) + { + case OS_BANNER_FIRST: + parent->children = baby; + baby->next = child; + child->prev = baby; + break; + + case OS_BANNER_BEFORE: + while (child != other && child->next) + child = child->next; + + if (child->prev) + { + child->prev->next = baby; + baby->prev = child->prev; + } + else + { + parent->children = baby; + } + + baby->next = child; + child->prev = baby; + break; + + case OS_BANNER_LAST: + while(child->next) + child = child->next; + + baby->prev = child; + child->next = baby; + break; + + case OS_BANNER_AFTER: + while (child != other && child->next) + child = child->next; + + if (child->next) + { + child->next->prev = baby; + baby->next = child->next; + } + + baby->prev = child; + child->next = baby; + break; + + default: break; + } + } + + baby->method = method; + baby->size = size; + baby->type = type; + baby->status = status; + + return baby; +} + +void os_banner_styles_apply (osbanid_t banner) +{ + if (!banner || !(banner->valid)) + return; + + uint propval = banner->status ? 0 : (banner->type == wintype_TextGrid ? 0 : 1); + uint bgcustom = banner->bgtrans ? banner->bgcolor : banner->bgcustom; + + /* font style: monospace for text grid and tab aligned buffers, else proportional */ + g_vm->glk_stylehint_set(banner->type, style_Alert, stylehint_Proportional, propval); + g_vm->glk_stylehint_set(banner->type, style_Subheader, stylehint_Proportional, propval); + g_vm->glk_stylehint_set(banner->type, style_Emphasized, stylehint_Proportional, propval); + g_vm->glk_stylehint_set(banner->type, style_Normal, stylehint_Proportional, propval); + g_vm->glk_stylehint_set(banner->type, style_User1, stylehint_Proportional, propval); + g_vm->glk_stylehint_set(banner->type, style_User2, stylehint_Proportional, propval); + + /* foreground color: user1 reverse, user2 custom */ + g_vm->glk_stylehint_set(banner->type, style_Alert, stylehint_TextColor, banner->fgcolor); + g_vm->glk_stylehint_set(banner->type, style_Subheader, stylehint_TextColor, banner->fgcolor); + g_vm->glk_stylehint_set(banner->type, style_Emphasized, stylehint_TextColor, banner->fgcolor); + g_vm->glk_stylehint_set(banner->type, style_Normal, stylehint_TextColor, banner->fgcolor); + g_vm->glk_stylehint_set(banner->type, style_User1, stylehint_TextColor, banner->bgcolor); + g_vm->glk_stylehint_set(banner->type, style_User2, stylehint_TextColor, banner->fgcustom); + + /* background color: user1 reverse, user2 custom */ + g_vm->glk_stylehint_set(banner->type, style_Alert, stylehint_BackColor, banner->bgcolor); + g_vm->glk_stylehint_set(banner->type, style_Subheader, stylehint_BackColor, banner->bgcolor); + g_vm->glk_stylehint_set(banner->type, style_Emphasized, stylehint_BackColor, banner->bgcolor); + g_vm->glk_stylehint_set(banner->type, style_Normal, stylehint_BackColor, banner->bgcolor); + g_vm->glk_stylehint_set(banner->type, style_User1, stylehint_BackColor, banner->fgcolor); + g_vm->glk_stylehint_set(banner->type, style_User2, stylehint_BackColor, bgcustom); + +} + +void os_banner_styles_reset (void) +{ + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Alert, stylehint_Proportional); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Subheader, stylehint_Proportional); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Emphasized, stylehint_Proportional); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Normal, stylehint_Proportional); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User1, stylehint_Proportional); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User2, stylehint_Proportional); + + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Alert, stylehint_TextColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Subheader, stylehint_TextColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Emphasized, stylehint_TextColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Normal, stylehint_TextColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User1, stylehint_TextColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User2, stylehint_TextColor); + + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Alert, stylehint_BackColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Subheader, stylehint_BackColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Emphasized, stylehint_BackColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_Normal, stylehint_BackColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User1, stylehint_BackColor); + g_vm->glk_stylehint_clear(wintype_AllTypes, style_User2, stylehint_BackColor); + +#ifdef GARGLK + /* reset our default colors with a superfluous hint */ + g_vm->glk_stylehint_set(wintype_AllTypes, style_Normal, stylehint_TextColor, mainfg); + g_vm->glk_stylehint_set(wintype_AllTypes, style_Normal, stylehint_BackColor, mainbg); +#endif /* GARGLK */ +} + +void os_banners_close(osbanid_t banner) +{ + if (!banner) + return; + + os_banners_close(banner->children); + os_banners_close(banner->next); + + if (banner->win && (banner->win != mainwin)) + { + g_vm->glk_window_close(banner->win, 0); + banner->win = 0; + } +} + +void os_banners_open(osbanid_t banner) +{ + if (!banner) + return; + + if (banner->valid) + { + if (banner->size && banner->parent && banner->parent->win) + { + os_banner_styles_apply(banner); + banner->win = g_vm->glk_window_open(banner->parent->win, banner->method, + banner->size, banner->type, banner->id); + banner_contents_display(banner->contents); + } + os_banners_open(banner->children); + } + + os_banners_open(banner->next); +} + +void os_banners_redraw() +{ + if (!os_banners) + return; + + os_banners_close(os_banners); + os_banners_open(os_banners); + os_banner_styles_reset(); +} + +/* Implementation-specific functions for managing banner contents */ +/* + banner_contents_init(); + banner_contents_insert(); + banner_contents_display(); + banner_contents_clear(); +*/ + +contentid_t banner_contents_init(void) +{ + contentid_t instance; + instance = (contentid_t)malloc(sizeof(banner_contents_t)); + if (!instance) + return 0; + + instance->banner = 0; + instance->next = 0; + + instance->style = style_Normal; + instance->newline = 0; + instance->move = 0; + instance->x = 0; + instance->y = 0; + + instance->chars = 0; + instance->len = 0; + + return instance; +} + +void banner_contents_insert(contentid_t contents, const char *txt, size_t len) +{ + if (!contents) + return; + + contents->chars = (char *)malloc(sizeof(char) * (len + 1)); + if (!(contents->chars)) + return; + + memcpy(contents->chars, txt, len); + + contents->chars[len] = '\0'; + contents->len = len; +} + +void banner_contents_display(contentid_t contents) +{ + if (!contents || !(contents->banner)) + return; + + winid_t win = contents->banner->win; + uint len = contents->len; + + g_vm->glk_set_window(win); + + if (contents->newline) + { + char ch = '\n'; + os_put_buffer(&ch, 1); + } + + if (len && (contents->chars[len-1] == '\n')) + { + len --; + contents->banner->newline = 1; + } + else + { + contents->banner->newline = 0; + } + + if (contents->move) + { + g_vm->glk_window_move_cursor(win, contents->x, contents->y); + contents->banner->move = 0; + contents->banner->x = 0; + contents->banner->y = 0; + } + + g_vm->glk_set_style(contents->style); + os_put_buffer(contents->chars, len); + g_vm->glk_set_window(mainwin); + banner_contents_display(contents->next); +} + +void banner_contents_clear(contentid_t contents) +{ + if (!contents) + return; + + banner_contents_clear(contents->next); + + if (contents->chars) + free(contents->chars); + + free(contents); +} + +/* Banner API functions */ + +void *os_banner_create(void *parent, int where, void *other, int wintype, + int align, int siz, int siz_units, + unsigned long style) +{ + osbanid_t gparent = (osbanid_t)parent; + osbanid_t gbanner; + uint gwinmeth = 0; + uint gwinsize = siz; + uint gwintype = 0; + uint gstatus = (style & OS_BANNER_STYLE_TAB_ALIGN); + + if (gparent && !(gparent->valid)) + return 0; + + if (!os_banners) + { + os_banners = os_banner_init(); + if (!os_banners) + return 0; + os_banners->win = mainwin; + } + + if (!gparent) + gparent = os_banners; + + switch (wintype) + { + case OS_BANNER_TYPE_TEXT: gwintype = wintype_TextBuffer; break; + case OS_BANNER_TYPE_TEXTGRID: gwintype = wintype_TextGrid; break; + default: gwintype = wintype_TextGrid; break; + } + + switch (align) + { + case OS_BANNER_ALIGN_TOP: gwinmeth = winmethod_Above; break; + case OS_BANNER_ALIGN_BOTTOM: gwinmeth = winmethod_Below; break; + case OS_BANNER_ALIGN_LEFT: gwinmeth = winmethod_Left; break; + case OS_BANNER_ALIGN_RIGHT: gwinmeth = winmethod_Right; break; + default: gwinmeth = winmethod_Above; break; + } + + switch (siz_units) + { + case OS_BANNER_SIZE_PCT: gwinmeth |= winmethod_Proportional; break; + case OS_BANNER_SIZE_ABS: gwinmeth |= winmethod_Fixed; break; + default: gwinmeth |= winmethod_Fixed; break; + } + + gbanner = os_banner_insert(gparent, where, (osbanid_t)other, gwinmeth, gwinsize, gwintype, gstatus); + + if (gbanner) + { + gbanner->fgcolor = gstatus ? statusbg : mainfg; + gbanner->bgcolor = gstatus ? statusfg : mainbg; + gbanner->fgcustom = gbanner->fgcolor; + gbanner->bgcustom = gbanner->bgcolor; + gbanner->bgtrans = 1; + } + + os_banners_redraw(); + + return gbanner; +} + +void os_banner_set_size(void *banner_handle, int siz, int siz_units, int is_advisory) +{ + osbanid_t banner = (osbanid_t)banner_handle; + + if (!banner || !banner->valid) + return; + + uint gwinsize = siz; + uint gwinmeth = 0; + + gwinmeth = banner->method & + (winmethod_Above | winmethod_Below | + winmethod_Left | winmethod_Right); + + switch (siz_units) + { + case OS_BANNER_SIZE_PCT: gwinmeth |= winmethod_Proportional; break; + case OS_BANNER_SIZE_ABS: gwinmeth |= winmethod_Fixed; break; + default: gwinmeth |= winmethod_Fixed; break; + } + + banner->method = gwinmeth; + banner->size = gwinsize; + + os_banners_redraw(); +} + +void os_banner_size_to_contents(void *banner_handle) +{ + osbanid_t banner = (osbanid_t)banner_handle; + + if (!banner || !banner->valid || !banner->win) + return; + +#ifdef GARGLK + if (banner->type == wintype_TextBuffer) + { + TextBufferWindow *win = dynamic_cast(banner->win); + assert(win); + int size = win->_scrollMax; + if (win->_numChars) + size++; + os_banner_set_size(banner, size, OS_BANNER_SIZE_ABS, 0); + } +#endif /* GARGLK */ +} + +void os_banner_delete(void *banner_handle) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !(banner->valid)) + return; + + banner->valid = 0; + os_banners_redraw(); + + if (banner->parent && banner->parent->children == banner) + banner->parent->children = banner->next; + + if (banner->next) + banner->next->prev = banner->prev; + + if (banner->prev) + banner->prev->next = banner->next; + + banner_contents_clear(banner->contents); + + free(banner); +} + +void os_banner_orphan(void *banner_handle) +{ + os_banner_delete(banner_handle); +} + +int os_banner_getinfo(void *banner_handle, os_banner_info_t *info) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid || !banner->win) + return 1; + + //winid_t win = banner->win; + uint gwintype = banner->type; + uint gwinmeth = banner->method; + uint gstyletab = banner->status; + + if (gwinmeth & winmethod_Above) + info->align = OS_BANNER_ALIGN_TOP; + if (gwinmeth & winmethod_Below) + info->align = OS_BANNER_ALIGN_BOTTOM; + if (gwinmeth & winmethod_Left) + info->align = OS_BANNER_ALIGN_LEFT; + if (gwinmeth & winmethod_Right) + info->align = OS_BANNER_ALIGN_RIGHT; + + info->style = gstyletab ? OS_BANNER_STYLE_TAB_ALIGN : 0; + + g_vm->glk_window_get_size(banner->win, &(banner->cwidth), &(banner->cheight)); + + info->rows = banner->cheight; + info->columns = banner->cwidth; + + info->pix_width = 0; + info->pix_height = 0; + + info->os_line_wrap = gstyletab ? 0 : (gwintype == wintype_TextBuffer); + + return 1; +} + +int os_banner_get_charwidth(void *banner_handle) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid || !banner->win) + return 0; + + g_vm->glk_window_get_size(banner->win, &(banner->cwidth), &(banner->cheight)); + + return banner->cwidth; +} + +int os_banner_get_charheight(void *banner_handle) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid || !banner->win) + return 0; + + g_vm->glk_window_get_size(banner->win, &(banner->cwidth), &(banner->cheight)); + + return banner->cheight; +} + +void os_banner_clear(void *banner_handle) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid) + return; + + if (banner->win) + { + winid_t win = banner->win; + g_vm->glk_window_clear(win); + } + + banner_contents_clear(banner->contents); + banner->contents = 0; + banner->newline = 0; + banner->move = 0; + banner->x = 0; + banner->y = 0; +} + +void os_banner_disp(void *banner_handle, const char *txt, size_t len) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid || !banner->win) + return; + + contentid_t update = banner_contents_init(); + if (!update) + return; + update->banner = banner; + + if (!(banner->contents)) + { + banner->contents = update; + } + else + { + contentid_t contents = banner->contents; + while (contents->next) + contents = contents->next; + contents->next = update; + } + + update->style = banner->style; + update->newline = banner->newline; + update->move = banner->move; + update->x = banner->x; + update->y = banner->y; + + banner_contents_insert(update, txt, len); + banner_contents_display(update); +} + +void os_banner_goto(void *banner_handle, int row, int col) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid || !banner->win) + return; + + if (banner->type == wintype_TextGrid) + { + banner->move = 1; + banner->x = col; + banner->y = row; + } +} + +void os_banner_set_attr(void *banner_handle, int attr) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid) + return; + + if (attr & OS_ATTR_BOLD && attr & OS_ATTR_ITALIC) + banner->style = style_Alert; + else if (attr & OS_ATTR_BOLD) + banner->style = style_Subheader; + else if (attr & OS_ATTR_ITALIC) + banner->style = style_Emphasized; + else + banner->style = style_Normal; +} + +void os_banner_set_color(void *banner_handle, os_color_t fg, os_color_t bg) +{ + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid) + return; + + uint reversed = 0; + uint normal = 0; + uint transparent = 0; + + /* evaluate parameters */ + + if (os_color_is_param(fg)) + { + switch(fg) + { + case OS_COLOR_P_TEXTBG: + case OS_COLOR_P_STATUSBG: + reversed = 1; + break; + + case OS_COLOR_P_TEXT: + case OS_COLOR_P_STATUSLINE: + case OS_COLOR_P_INPUT: + normal = 1; + break; + + default: + break; + } + } + + if (os_color_is_param(bg)) + { + switch (bg) + { + case OS_COLOR_P_TRANSPARENT: + transparent = 1; + break; + + default: + break; + } + } + + /* choose a style */ + + if (normal && transparent) + banner->style = style_Normal; + else if (reversed) + banner->style = style_User1; + else + banner->style = style_User2; + + /* process our custom color */ + + if (banner->style == style_User2) + { + /* store current settings */ + uint oldfg = banner->fgcustom; + uint oldbg = banner->bgcustom; + uint oldtr = banner->bgtrans; + + /* reset custom color parameters */ + banner->fgcustom = banner->fgcolor; + banner->bgcustom = banner->bgcolor; + banner->bgtrans = 1; + + if (!normal) + banner->fgcustom = fg; + + if (!transparent) + { + banner->bgcustom = bg; + banner->bgtrans = 0; + } + + if (!(banner->fgcustom == oldfg + && banner->bgcustom == oldbg + && banner->bgtrans == oldtr)) + os_banners_redraw(); + } +} + +void os_banner_set_screen_color(void *banner_handle, os_color_t color) { + osbanid_t banner = (osbanid_t)banner_handle; + if (!banner || !banner->valid) + return; + + if (!(os_color_is_param(color))) + banner->bgcolor = color; + + os_banners_redraw(); +} + +void os_banner_flush(void *banner_handle) {} +void os_banner_start_html(void *banner_handle) {} +void os_banner_end_html(void *banner_handle) {} + +} // End of namespace TADS +} // End of namespace Glk -- cgit v1.2.3