From 2e63f102d9ccae0238bd3602364ee3abaf1998e5 Mon Sep 17 00:00:00 2001 From: marschap Date: Sun, 29 Apr 2007 12:08:16 +0000 Subject: [PATCH] refactor rendering engine --- server/render.c | 636 +++++++++++++++++++++++++++--------------------- 1 file changed, 354 insertions(+), 282 deletions(-) diff --git a/server/render.c b/server/render.c index f6be668..f39929a 100644 --- a/server/render.c +++ b/server/render.c @@ -51,7 +51,14 @@ int server_msg_expire = 0; #define BUFSIZE 1024 /* larger than display width => large enough */ -static int render_frame(LinkedList *list, char fscroll, int left, int top, int right, int bottom, int fwid, int fhgt, int fspeed, long timer); +static int render_frame(LinkedList *list, int left, int top, int right, int bottom, int fwid, int fhgt, char fscroll, int fspeed, long timer); +static int render_string(Widget *w, int left, int top, int right, int bottom, int fy); +static int render_hbar(Widget *w, int left, int top, int right, int bottom, int fy); +static int render_vbar(Widget *w, int left, int top, int right, int bottom); +static int render_title(Widget *w, int left, int top, int right, int bottom, long timer); +static int render_scroller(Widget *w, int left, int top, int right, int bottom, long timer); +static int render_num(Widget *w, int left, int top, int right, int bottom); + int render_screen(Screen *s, long timer) @@ -113,9 +120,9 @@ render_screen(Screen *s, long timer) drivers_output(output_state); /* Draw a frame... */ - render_frame(s->widgetlist, 'v', 0, 0, + render_frame(s->widgetlist, 0, 0, display_props->width, display_props->height, - s->width, s->height, max(s->duration / s->height, 1), timer); + s->width, s->height, 'v', max(s->duration / s->height, 1), timer); /* Set the cursor */ drivers_cursor(s->cursor_x, s->cursor_y, s->cursor); @@ -157,24 +164,23 @@ render_screen(Screen *s, long timer) /* */ static int render_frame(LinkedList *list, - char fscroll, /* direction of scrolling */ int left, /* left edge of frame */ int top, /* top edge of frame */ int right, /* right edge of frame */ int bottom, /* bottom edge of frame */ int fwid, /* frame width? */ int fhgt, /* frame height? */ + char fscroll, /* direction of scrolling */ int fspeed, /* speed of scrolling... */ long timer) /* current timer tick */ { - int vis_width = right - left; /* width of visible frame area */ - int vis_height = bottom - top; /* height of visible frame area */ - int /*fx = 0,*/ fy = 0; /* Scrolling offset for the frame... */ + int fy = 0; /* Scrolling offset for the frame... */ - debug(RPT_DEBUG, "%s(list=%p, fscroll='%c', left=%d, top=%d, " - "right=%d, bottom=%d, fwid=%d, fhgt=%d, fspeed=%d, timer=%ld)", - __FUNCTION__, list, fscroll, left,top, right, bottom, - fwid, fhgt, fspeed, timer); + debug(RPT_DEBUG, "%s(list=%p, left=%d, top=%d, " + "right=%d, bottom=%d, fwid=%d, fhgt=%d, " + "fscroll='%c', fspeed=%d, timer=%ld)", + __FUNCTION__, list, left, top, right, bottom, + fwid, fhgt, fscroll, fspeed, timer); /* return on no data or illegal height */ if ((list == NULL) || (fhgt <= 0)) @@ -182,14 +188,16 @@ render_frame(LinkedList *list, if (fscroll == 'v') { /* vertical scrolling */ // only set offset !=0 when fspeed is != 0 and there is something to scroll - if (fspeed && (fhgt > vis_height)) { - int fy_max = fhgt - vis_height + 1; + if ((fspeed != 0) && (fhgt > bottom - top)) { + int fy_max = fhgt - (bottom - top) + 1; fy = (fspeed > 0) ? (timer / fspeed) % fy_max : (-fspeed * timer) % fy_max; fy = max(fy, 0); // safeguard against negative values + + debug(RPT_DEBUG, "%s: fy=%d", __FUNCTION__, fy); } } else if (fscroll == 'h') { /* horizontal scrolling */ @@ -201,7 +209,6 @@ render_frame(LinkedList *list, /* loop over all widgets */ do { - char str[BUFSIZE]; /* scratch buffer */ Widget *w = (Widget *) LL_Get(list); if (w == NULL) @@ -210,283 +217,22 @@ render_frame(LinkedList *list, /* TODO: Make this cleaner and more flexible! */ switch (w->type) { case WID_STRING: - if ((w->x > 0) && (w->y > 0) && (w->text) && - (w->y <= vis_height + fy) && (w->y > fy)) { - int length; - - w->x = min(w->x, vis_width); - length = min(vis_width - w->x + 1, sizeof(str)); - strncpy(str, w->text, length); - str[length] = '\0'; - drivers_string(w->x + left, w->y + top - fy, str); - } + render_string(w, left, top - fy, right, bottom, fy); break; case WID_HBAR: - if ((w->x > 0) && (w->y > 0) && - (w->y <= vis_height + fy) && (w->y > fy)) { - if (w->length > 0) { - if ((w->length / display_props->cellwidth) < vis_width - w->x + 1) { - /*was: drivers_hbar(w->x + left, w->y + top - fy, w->length); */ - /* improvised len and promille */ - int full_len = display_props->width - w->x - left + 1; - int promille = (long) 1000 * w->length / (display_props->cellwidth * full_len); - drivers_hbar(w->x + left, w->y + top - fy, full_len, promille, BAR_PATTERN_FILLED); - } - else { - /*was: drivers_hbar(w->x + left, w->y + top - fy, wid * display_props->cellwidth); */ - /* Improvised len and promille while we have the old widget language */ - int full_len = (display_props->width - w->x - left + 1); - drivers_hbar(w->x + left, w->y + top - fy, full_len, 1000, BAR_PATTERN_FILLED); - } - } - else if (w->length < 0) { - /* TODO: Rearrange stuff to get left-extending - * hbars to draw correctly... - * .. er, this'll require driver modifications, - * so I'll leave it out for now. - */ - } - } + render_hbar(w, left, top - fy, right, bottom, fy); break; case WID_VBAR: /* FIXME: Vbars don't work in frames! */ - if ((w->x > 0) && (w->y > 0)) { - if (w->length > 0) { - /* Improvised len and promille while we have the old widget language */ - int full_len = display_props->height; - int promille = (long) 1000 * w->length / display_props->cellheight / full_len; - drivers_vbar(w->x, display_props->height, full_len, promille, BAR_PATTERN_FILLED); - } - else if (w->length < 0) { - /* TODO: Rearrange stuff to get down-extending - * vbars to draw correctly... - * .. er, this'll require driver modifications, - * so I'll leave it out for now. - */ - } - } + render_vbar(w, left, top, right, bottom); break; case WID_ICON: drivers_icon(w->x, w->y, w->length); - break; case WID_TITLE: /* FIXME: Doesn't work quite right in frames... */ - if ((w->text != NULL) && (vis_width >= 8)) { - int length = strlen(w->text); - int x; - - drivers_icon(w->x + left, w->y + top, ICON_BLOCK_FILLED); - drivers_icon(w->x + left + 1, w->y + top, ICON_BLOCK_FILLED); - - length = min(length, sizeof(str)); - if (length <= vis_width - 6) { - strncpy(str, w->text, length); - str[length] = '\0'; - - x = length + 4; - } - else { /* Scroll the title, if it doesn't fit... */ - int speed = 1; - int offset = timer / speed; - int reverse = offset / length; - - offset %= length; - offset = max(offset, 0); - if (offset > length - (vis_width - 6)) - offset = length - (vis_width - 6); - - if (reverse & 1) /* Scrolling backwards... */ - offset = (length - (vis_width - 6)) - offset; - length = abs(vis_width - 6); - length = min(length, sizeof(str)); - strncpy(str, w->text + offset, length); - str[length] = '\0'; - - x = vis_width - 2; - } - - drivers_string(w->x + 3 + left, w->y + top, str); - - for ( ; x < vis_width; x++) { - drivers_icon(w->x + x + left, w->y + top, ICON_BLOCK_FILLED); - } - } + render_title(w, left, top, right, bottom, timer); break; case WID_SCROLLER: /* FIXME: doesn't work in frames... */ - if ((w->text != NULL) && (w->right >= w->left)) { - int length; - int offset; - int screen_width; - - /*debug(RPT_DEBUG, "%s: %s %d",__FUNCTION__,w->text,timer);*/ - screen_width = abs(w->right - w->left + 1); - screen_width = min(screen_width, sizeof(str)); - switch (w->length) { /* actually, direction... */ - /* FIXED: Horz scrollers don't show the - * last letter in the string... (1-off error?) - */ - case 'm': // Marquee - length = strlen(w->text); - if (length <= screen_width) { - /* it fits within the box, just render it */ - drivers_string(w->left, w->top, w->text); - } - else { - int necessaryTimeUnits = 0; - - if (w->speed > 0) { - necessaryTimeUnits = length * w->speed; - offset = (timer % (length * w->speed)) / w->speed; - } - else if (w->speed < 0) { - necessaryTimeUnits = length / (w->speed * -1); - offset = (timer % (length / (w->speed * -1))) * w->speed * -1; - } - else { - offset = 0; - } - if (offset <= length) { - int room = screen_width - (length - offset); - - strncpy(str, &w->text[offset], screen_width); - - // if there's more room, restart at the beginning - if (room > 0) { - strncat(str, w->text, room); - } - - str[screen_width] = '\0'; - - /*debug(RPT_DEBUG, "scroller %s : %d", str, length-offset);*/ - } - else { - str[0] = '\0'; - } - drivers_string(w->left, w->top, str); - } - break; - case 'h': - length = strlen(w->text) + 1; - if (length <= screen_width) { - /* it fits within the box, just render it */ - drivers_string(w->left, w->top, w->text); - } - else { - int effLength = length - screen_width; - int necessaryTimeUnits = 0; - - if (w->speed > 0) { - necessaryTimeUnits = effLength * w->speed; - if (((timer / (effLength * w->speed)) % 2) == 0) { - /* wiggle one way */ - offset = (timer % (effLength * w->speed)) - / w->speed; - } - else { - /* wiggle the other */ - offset = (((timer % (effLength * w->speed)) - - (effLength * w->speed) + 1) - / w->speed) * -1; - } - } - else if (w->speed < 0) { - necessaryTimeUnits = effLength / (w->speed * -1); - if (((timer / (effLength / (w->speed * -1))) % 2) == 0) { - offset = (timer % (effLength / (w->speed * -1))) - * w->speed * -1; - } - else { - offset = (((timer % (effLength / (w->speed * -1))) - * w->speed * -1) - - effLength + 1) * -1; - } - } - else { - offset = 0; - } - if (offset <= length) { - strncpy(str, &((w->text)[offset]), screen_width); - str[screen_width] = '\0'; - /*debug(RPT_DEBUG, "scroller %s : %d", str, length-offset); */ - } - else { - str[0] = '\0'; - } - drivers_string(w->left, w->top, str); - } - break; - /* FIXME: Vert scrollers don't always seem to scroll */ - /* back up after hitting the bottom. They jump back to */ - /* the top instead... (nevermind?) */ - case 'v': - length = strlen(w->text); - if (length <= screen_width) { - /* no scrolling required... */ - drivers_string(w->left, w->top, w->text); - } - else { - int lines_required = (length / screen_width) - + (length % screen_width ? 1 : 0); - int available_lines = (w->bottom - w->top + 1); - - if (lines_required <= available_lines) { - /* easy... */ - int i; - - for (i = 0; i < lines_required; i++) { - strncpy(str, &((w->text)[i * screen_width]), screen_width); - str[screen_width] = '\0'; - drivers_string(w->left, w->top + i, str); - } - } - else { - int necessaryTimeUnits = 0; - int effLines = lines_required - available_lines + 1; - int begin = 0; - int i = 0; - - /*debug(RPT_DEBUG, "length: %d sw: %d lines req: %d avail lines: %d effLines: %d ",length,screen_width,lines_required,available_lines,effLines);*/ - if (w->speed > 0) { - necessaryTimeUnits = effLines * w->speed; - if (((timer / (effLines * w->speed)) % 2) == 0) { - /*debug(RPT_DEBUG, "up ");*/ - begin = (timer % (effLines * w->speed)) - / w->speed; - } - else { - /*debug(RPT_DEBUG, "down ");*/ - begin = (((timer % (effLines * w->speed)) - - (effLines * w->speed) + 1) / w->speed) - * -1; - } - } - else if (w->speed < 0) { - necessaryTimeUnits = effLines / (w->speed * -1); - if (((timer / (effLines / (w->speed * -1))) % 2) == 0) { - begin = (timer % (effLines / (w->speed * -1))) - * w->speed * -1; - } - else { - begin = (((timer % (effLines / (w->speed * -1))) - * w->speed * -1) - effLines + 1) - * -1; - } - } - else { - begin = 0; - } - /*debug(RPT_DEBUG, "rendering begin: %d timer: %d effLines: %d",begin,timer,effLines); */ - for (i = begin; i < begin + available_lines; i++) { - strncpy(str, &((w->text)[i * (screen_width)]), screen_width); - str[screen_width] = '\0'; - /*debug(RPT_DEBUG, "rendering: '%s' of %s", */ - /*str,w->text); */ - drivers_string(w->left, w->top + (i - begin), str); - } - } - } - break; - } - } + render_scroller(w, left, top, right, bottom, timer); break; case WID_FRAME: { @@ -499,8 +245,9 @@ render_frame(LinkedList *list, int new_bottom = min(top + w->bottom, bottom); if ((new_left < right) && (new_top < bottom)) /* Render only if it's visible... */ - render_frame(w->frame_screen->widgetlist, w->length, new_left, new_top, - new_right, new_bottom, w->width, w->height, w->speed, timer); + render_frame(w->frame_screen->widgetlist, new_left, new_top, + new_right, new_bottom, w->width, w->height, + w->length, w->speed, timer); } break; case WID_NUM: /* FIXME: doesn't work in frames... */ @@ -518,6 +265,331 @@ render_frame(LinkedList *list, return 0; } + +static int +render_string(Widget *w, int left, int top, int right, int bottom, int fy) +{ + debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d, fy=%d)", + __FUNCTION__, w, left, top, right, bottom, fy); + + if ((w != NULL) && (w->text != NULL) && + (w->x > 0) && (w->y > 0) && (w->y > fy) && (w->y <= bottom - top)) { + int length; + char str[BUFSIZE]; + + w->x = min(w->x, right - left); + length = min(right - left - w->x + 1, sizeof(str)); + strncpy(str, w->text, length); + str[length] = '\0'; + drivers_string(w->x + left, w->y + top, str); + } + return 0; +} + + +static int +render_hbar(Widget *w, int left, int top, int right, int bottom, int fy) +{ + debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d, fy=%d)", + __FUNCTION__, w, left, top, right, bottom, fy); + + if ((w != NULL) && + (w->x > 0) && (w->y > 0) && (w->y > fy) && (w->y <= bottom - top)) { + if (w->length > 0) { + int full_len = display_props->width - w->x - left + 1; + int promille = 1000; + + if ((w->length / display_props->cellwidth) < right - left - w->x + 1) + promille = (long) 1000 * w->length / (display_props->cellwidth * full_len); + + drivers_hbar(w->x + left, w->y + top, full_len, promille, BAR_PATTERN_FILLED); + } + else if (w->length < 0) { + /* TODO: Rearrange stuff to get left-extending + * hbars to draw correctly... + * .. er, this'll require driver modifications, + * so I'll leave it out for now. + */ + } + } + return 0; +} + + +static int +render_vbar(Widget *w, int left, int top, int right, int bottom) +{ + debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d)", + __FUNCTION__, w, left, top, right, bottom); + + if ((w != NULL) && (w->x > 0) && (w->y > 0)) { + if (w->length > 0) { + int full_len = display_props->height; + int promille = (long) 1000 * w->length / display_props->cellheight / full_len; + + drivers_vbar(w->x, display_props->height, full_len, promille, BAR_PATTERN_FILLED); + } + else if (w->length < 0) { + /* TODO: Rearrange stuff to get down-extending + * vbars to draw correctly... + * .. er, this'll require driver modifications, + * so I'll leave it out for now. + */ + } + } + return 0; +} + + +static int +render_title(Widget *w, int left, int top, int right, int bottom, long timer) +{ + debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d, timer=%ld)", + __FUNCTION__, w, left, top, right, bottom, timer); + + int vis_width = right - left; + + if ((w != NULL) && (w->text != NULL) && (vis_width >= 8)) { + char str[BUFSIZE]; + int length = strlen(w->text); + int x; + + drivers_icon(w->x + left, w->y + top, ICON_BLOCK_FILLED); + drivers_icon(w->x + left + 1, w->y + top, ICON_BLOCK_FILLED); + + length = min(length, sizeof(str)); + if (length <= vis_width - 6) { + strncpy(str, w->text, length); + str[length] = '\0'; + + x = length + 4; + } + else { /* Scroll the title, if it doesn't fit... */ + int speed = 1; + int offset = timer / speed; + int reverse = offset / length; + + offset %= length; + offset = max(offset, 0); + if (offset > length - (vis_width - 6)) + offset = length - (vis_width - 6); + + if (reverse & 1) /* Scrolling backwards... */ + offset = (length - (vis_width - 6)) - offset; + length = abs(vis_width - 6); + length = min(length, sizeof(str)); + strncpy(str, w->text + offset, length); + str[length] = '\0'; + + x = vis_width - 2; + } + + drivers_string(w->x + 3 + left, w->y + top, str); + + for ( ; x < vis_width; x++) { + drivers_icon(w->x + x + left, w->y + top, ICON_BLOCK_FILLED); + } + } + return 0; +} + + +static int +render_scroller(Widget *w, int left, int top, int right, int bottom, long timer) +{ + debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d, timer=%ld)", + __FUNCTION__, w, left, top, right, bottom, timer); + + if ((w->text != NULL) && (w->right >= w->left)) { + char str[BUFSIZE]; + int length; + int offset; + int screen_width; + + /*debug(RPT_DEBUG, "%s: %s %d",__FUNCTION__,w->text,timer);*/ + screen_width = abs(w->right - w->left + 1); + screen_width = min(screen_width, sizeof(str)); + + switch (w->length) { /* actually, direction... */ + case 'm': // Marquee + length = strlen(w->text); + if (length <= screen_width) { + /* it fits within the box, just render it */ + drivers_string(w->left, w->top, w->text); + } + else { + int necessaryTimeUnits = 0; + + if (w->speed > 0) { + necessaryTimeUnits = length * w->speed; + offset = (timer % (length * w->speed)) / w->speed; + } + else if (w->speed < 0) { + necessaryTimeUnits = length / (w->speed * -1); + offset = (timer % (length / (w->speed * -1))) * w->speed * -1; + } + else { + offset = 0; + } + if (offset <= length) { + int room = screen_width - (length - offset); + + strncpy(str, &w->text[offset], screen_width); + + // if there's more room, restart at the beginning + if (room > 0) { + strncat(str, w->text, room); + } + + str[screen_width] = '\0'; + + /*debug(RPT_DEBUG, "scroller %s : %d", str, length-offset);*/ + } + else { + str[0] = '\0'; + } + drivers_string(w->left, w->top, str); + } + break; + case 'h': + length = strlen(w->text) + 1; + if (length <= screen_width) { + /* it fits within the box, just render it */ + drivers_string(w->left, w->top, w->text); + } + else { + int effLength = length - screen_width; + int necessaryTimeUnits = 0; + + if (w->speed > 0) { + necessaryTimeUnits = effLength * w->speed; + if (((timer / (effLength * w->speed)) % 2) == 0) { + /* wiggle one way */ + offset = (timer % (effLength * w->speed)) + / w->speed; + } + else { + /* wiggle the other */ + offset = (((timer % (effLength * w->speed)) + - (effLength * w->speed) + 1) + / w->speed) * -1; + } + } + else if (w->speed < 0) { + necessaryTimeUnits = effLength / (w->speed * -1); + if (((timer / (effLength / (w->speed * -1))) % 2) == 0) { + offset = (timer % (effLength / (w->speed * -1))) + * w->speed * -1; + } + else { + offset = (((timer % (effLength / (w->speed * -1))) + * w->speed * -1) + - effLength + 1) * -1; + } + } + else { + offset = 0; + } + if (offset <= length) { + strncpy(str, &((w->text)[offset]), screen_width); + str[screen_width] = '\0'; + /*debug(RPT_DEBUG, "scroller %s : %d", str, length-offset); */ + } + else { + str[0] = '\0'; + } + drivers_string(w->left, w->top, str); + } + break; + /* FIXME: Vert scrollers don't always seem to scroll */ + /* back up after hitting the bottom. They jump back to */ + /* the top instead... (nevermind?) */ + case 'v': + length = strlen(w->text); + if (length <= screen_width) { + /* no scrolling required... */ + drivers_string(w->left, w->top, w->text); + } + else { + int lines_required = (length / screen_width) + + (length % screen_width ? 1 : 0); + int available_lines = (w->bottom - w->top + 1); + + if (lines_required <= available_lines) { + /* easy... */ + int i; + + for (i = 0; i < lines_required; i++) { + strncpy(str, &((w->text)[i * screen_width]), screen_width); + str[screen_width] = '\0'; + drivers_string(w->left, w->top + i, str); + } + } + else { + int necessaryTimeUnits = 0; + int effLines = lines_required - available_lines + 1; + int begin = 0; + int i = 0; + + /*debug(RPT_DEBUG, "length: %d sw: %d lines req: %d avail lines: %d effLines: %d ",length,screen_width,lines_required,available_lines,effLines);*/ + if (w->speed > 0) { + necessaryTimeUnits = effLines * w->speed; + if (((timer / (effLines * w->speed)) % 2) == 0) { + /*debug(RPT_DEBUG, "up ");*/ + begin = (timer % (effLines * w->speed)) + / w->speed; + } + else { + /*debug(RPT_DEBUG, "down ");*/ + begin = (((timer % (effLines * w->speed)) + - (effLines * w->speed) + 1) / w->speed) + * -1; + } + } + else if (w->speed < 0) { + necessaryTimeUnits = effLines / (w->speed * -1); + if (((timer / (effLines / (w->speed * -1))) % 2) == 0) { + begin = (timer % (effLines / (w->speed * -1))) + * w->speed * -1; + } + else { + begin = (((timer % (effLines / (w->speed * -1))) + * w->speed * -1) - effLines + 1) + * -1; + } + } + else { + begin = 0; + } + /*debug(RPT_DEBUG, "rendering begin: %d timer: %d effLines: %d",begin,timer,effLines); */ + for (i = begin; i < begin + available_lines; i++) { + strncpy(str, &((w->text)[i * (screen_width)]), screen_width); + str[screen_width] = '\0'; + /*debug(RPT_DEBUG, "rendering: '%s' of %s", */ + /*str,w->text); */ + drivers_string(w->left, w->top + (i - begin), str); + } + } + } + break; + } + } + return 0; +} + + +static int render_num(Widget *w, int left, int top, int right, int bottom) +{ + debug(RPT_DEBUG, "%s(w=%p, left=%d, top=%d, right=%d, bottom=%d)", + __FUNCTION__, w, left, top, right, bottom); + + /* NOTE: y=10 means COLON (:) */ + if ((w != NULL) && (w->x > 0) && (w->y >= 0) && (w->y <= 10)) { + drivers_num(w->x + left, w->y); + } +} + + int server_msg(const char *text, int expire) {