2008-11-30 22:31:20 +00:00
|
|
|
/** \file server/render.c
|
2010-11-16 21:51:25 +00:00
|
|
|
* This file contains code that actually generates the full screen data to
|
|
|
|
|
* send to the LCD. render_screen() takes a screen definition and calls
|
|
|
|
|
* render_frame() which in turn builds the screen according to the definition.
|
|
|
|
|
* It may recursively call itself (for nested frames).
|
2001-12-27 23:30:36 +00:00
|
|
|
*
|
|
|
|
|
* This needs to be greatly expanded and redone for greater flexibility.
|
|
|
|
|
* For example, it should support multiple screen sizes, more flexible
|
|
|
|
|
* widgets, and multiple simultaneous screens.
|
|
|
|
|
*
|
|
|
|
|
* This will probably take a while to do. :(
|
|
|
|
|
*
|
|
|
|
|
* THIS FILE IS MESSY! Anyone care to rewrite it nicely? Please?? :)
|
|
|
|
|
*
|
|
|
|
|
* NOTE: (from David Douthitt) Multiple screen sizes? Multiple simultaneous
|
|
|
|
|
* screens? Horrors of horrors... next thing you know it'll be making coffee...
|
|
|
|
|
* Better believe it'll take a while to do...
|
2008-11-30 22:31:20 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* This file is part of LCDd, the lcdproc server.
|
2001-12-27 23:30:36 +00:00
|
|
|
*
|
2008-11-30 22:31:20 +00:00
|
|
|
* This file is released under the GNU General Public License.
|
|
|
|
|
* Refer to the COPYING file distributed with this package.
|
|
|
|
|
*
|
|
|
|
|
* Copyright (c) 1999, William Ferrell, Scott Scriven
|
|
|
|
|
* 2001, Joris Robijn
|
|
|
|
|
* 2007, Peter Marschall
|
1999-12-09 23:15:14 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
2003-02-28 15:19:58 +00:00
|
|
|
#include <stdlib.h>
|
1999-12-09 23:15:14 +00:00
|
|
|
|
2001-11-29 14:09:13 +00:00
|
|
|
#include "shared/report.h"
|
2001-05-25 03:14:27 +00:00
|
|
|
#include "shared/LL.h"
|
2009-11-22 15:15:53 +00:00
|
|
|
#include "shared/defines.h"
|
1999-12-09 23:15:14 +00:00
|
|
|
|
2001-12-30 00:15:25 +00:00
|
|
|
#include "drivers.h"
|
1999-12-09 23:15:14 +00:00
|
|
|
|
|
|
|
|
#include "screen.h"
|
|
|
|
|
#include "screenlist.h"
|
|
|
|
|
#include "widget.h"
|
|
|
|
|
#include "render.h"
|
|
|
|
|
|
2007-04-30 13:06:06 +00:00
|
|
|
#define BUFSIZE 1024 /* larger than display width => large enough */
|
|
|
|
|
|
2002-03-27 22:38:12 +00:00
|
|
|
int heartbeat = HEARTBEAT_OPEN;
|
2005-06-12 16:07:49 +00:00
|
|
|
static int heartbeat_fallback = HEARTBEAT_ON; /* If no heartbeat setting has been set at all */
|
2007-04-30 13:06:06 +00:00
|
|
|
|
2000-03-30 20:20:41 +00:00
|
|
|
int backlight = BACKLIGHT_OPEN;
|
2005-06-12 16:07:49 +00:00
|
|
|
static int backlight_fallback = BACKLIGHT_ON; /* If no backlight setting has been set at all */
|
2007-04-30 13:06:06 +00:00
|
|
|
|
|
|
|
|
int titlespeed = 1;
|
|
|
|
|
|
1999-12-09 23:15:14 +00:00
|
|
|
int output_state = 0;
|
2007-04-02 21:29:53 +00:00
|
|
|
char *server_msg_text;
|
2003-02-28 15:19:58 +00:00
|
|
|
int server_msg_expire = 0;
|
1999-12-09 23:15:14 +00:00
|
|
|
|
|
|
|
|
|
2007-04-29 12:08:16 +00:00
|
|
|
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);
|
|
|
|
|
|
1999-12-09 23:15:14 +00:00
|
|
|
|
2000-03-30 20:20:41 +00:00
|
|
|
int
|
2007-04-28 21:16:39 +00:00
|
|
|
render_screen(Screen *s, long timer)
|
1999-12-09 23:15:14 +00:00
|
|
|
{
|
2002-05-26 19:21:23 +00:00
|
|
|
int tmp_state = 0;
|
2000-03-30 20:20:41 +00:00
|
|
|
|
2007-04-28 21:16:39 +00:00
|
|
|
debug(RPT_DEBUG, "%s(screen=[%.40s], timer=%ld) ==== START RENDERING ====", __FUNCTION__, s->id, timer);
|
1999-12-09 23:15:14 +00:00
|
|
|
|
2007-04-28 21:16:39 +00:00
|
|
|
if (s == NULL)
|
2000-04-03 22:13:57 +00:00
|
|
|
return -1;
|
2000-03-30 20:20:41 +00:00
|
|
|
|
2001-12-30 00:15:25 +00:00
|
|
|
/* Clear the LCD screen... */
|
2007-04-02 21:29:53 +00:00
|
|
|
drivers_clear();
|
1999-12-09 23:15:14 +00:00
|
|
|
|
2001-12-30 00:15:25 +00:00
|
|
|
/* FIXME drivers_backlight --
|
|
|
|
|
*
|
2002-05-26 19:21:23 +00:00
|
|
|
* If the screen's backlight isn't set (default) then we
|
2001-12-30 00:15:25 +00:00
|
|
|
* inherit the backlight state from the parent client. This allows
|
|
|
|
|
* the client to override it's childrens settings.
|
2002-05-26 19:21:23 +00:00
|
|
|
* The server can also override the clients and screens settings.
|
2001-12-30 00:15:25 +00:00
|
|
|
*/
|
2002-05-26 19:21:23 +00:00
|
|
|
if (backlight != BACKLIGHT_OPEN) {
|
|
|
|
|
tmp_state = backlight;
|
2007-04-28 21:16:39 +00:00
|
|
|
}
|
|
|
|
|
else if ((s->client != NULL) && (s->client->backlight != BACKLIGHT_OPEN)) {
|
2002-05-26 19:21:23 +00:00
|
|
|
tmp_state = s->client->backlight;
|
2007-04-28 21:16:39 +00:00
|
|
|
}
|
|
|
|
|
else if (s->backlight != BACKLIGHT_OPEN) {
|
2002-04-26 00:00:31 +00:00
|
|
|
tmp_state = s->backlight;
|
2007-04-28 21:16:39 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2002-05-26 19:21:23 +00:00
|
|
|
tmp_state = backlight_fallback;
|
2001-11-14 13:57:25 +00:00
|
|
|
}
|
|
|
|
|
|
2001-12-30 00:15:25 +00:00
|
|
|
/* Set up backlight to the correct state... */
|
|
|
|
|
/* NOTE: dirty stripping of other options... */
|
2002-05-26 19:21:23 +00:00
|
|
|
/* Backlight flash: check timer and flip backlight as appropriate */
|
|
|
|
|
if (tmp_state & BACKLIGHT_FLASH) {
|
2007-04-02 21:29:53 +00:00
|
|
|
drivers_backlight(
|
2002-05-26 19:21:23 +00:00
|
|
|
(
|
|
|
|
|
(tmp_state & BACKLIGHT_ON)
|
|
|
|
|
^ ((timer & 7) == 7)
|
2007-04-02 21:29:53 +00:00
|
|
|
) ? BACKLIGHT_ON : BACKLIGHT_OFF);
|
2002-05-26 19:21:23 +00:00
|
|
|
}
|
2007-04-28 21:16:39 +00:00
|
|
|
/* Backlight blink: check timer and flip backlight as appropriate */
|
2002-05-26 19:21:23 +00:00
|
|
|
else if (tmp_state & BACKLIGHT_BLINK) {
|
2007-04-02 21:29:53 +00:00
|
|
|
drivers_backlight(
|
2002-05-26 19:21:23 +00:00
|
|
|
(
|
|
|
|
|
(tmp_state & BACKLIGHT_ON)
|
|
|
|
|
^ ((timer & 14) == 14)
|
2007-04-02 21:29:53 +00:00
|
|
|
) ? BACKLIGHT_ON : BACKLIGHT_OFF);
|
2007-04-28 21:16:39 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Simple: Only send lowest bit then... */
|
2007-04-02 21:29:53 +00:00
|
|
|
drivers_backlight(tmp_state & BACKLIGHT_ON);
|
2000-04-03 22:13:57 +00:00
|
|
|
}
|
1999-12-09 23:15:14 +00:00
|
|
|
|
2001-12-30 00:15:25 +00:00
|
|
|
/* Output ports from LCD - outputs depend on the current screen */
|
2007-04-02 21:29:53 +00:00
|
|
|
drivers_output(output_state);
|
2000-03-30 20:20:41 +00:00
|
|
|
|
2001-12-30 00:15:25 +00:00
|
|
|
/* Draw a frame... */
|
2007-04-29 12:08:16 +00:00
|
|
|
render_frame(s->widgetlist, 0, 0,
|
2007-04-28 21:16:39 +00:00
|
|
|
display_props->width, display_props->height,
|
2007-04-29 12:08:16 +00:00
|
|
|
s->width, s->height, 'v', max(s->duration / s->height, 1), timer);
|
2000-03-30 20:20:41 +00:00
|
|
|
|
2002-05-26 19:21:23 +00:00
|
|
|
/* Set the cursor */
|
2007-04-02 21:29:53 +00:00
|
|
|
drivers_cursor(s->cursor_x, s->cursor_y, s->cursor);
|
2002-05-26 19:21:23 +00:00
|
|
|
|
|
|
|
|
if (heartbeat != HEARTBEAT_OPEN) {
|
|
|
|
|
tmp_state = heartbeat;
|
2007-04-28 21:16:39 +00:00
|
|
|
}
|
|
|
|
|
else if ((s->client != NULL) && (s->client->heartbeat != HEARTBEAT_OPEN)) {
|
2002-05-26 19:21:23 +00:00
|
|
|
tmp_state = s->client->heartbeat;
|
2007-04-28 21:16:39 +00:00
|
|
|
}
|
|
|
|
|
else if (s->heartbeat != HEARTBEAT_OPEN) {
|
2002-05-26 19:21:23 +00:00
|
|
|
tmp_state = s->heartbeat;
|
2007-04-28 21:16:39 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2002-05-26 19:21:23 +00:00
|
|
|
tmp_state = heartbeat_fallback;
|
2000-04-03 22:13:57 +00:00
|
|
|
}
|
2002-05-26 19:21:23 +00:00
|
|
|
drivers_heartbeat(tmp_state);
|
2000-03-30 20:20:41 +00:00
|
|
|
|
2003-02-28 15:19:58 +00:00
|
|
|
/* If there is an server message that is not expired, display it */
|
2007-04-02 21:29:53 +00:00
|
|
|
if (server_msg_expire > 0) {
|
|
|
|
|
drivers_string(display_props->width - strlen(server_msg_text) + 1,
|
|
|
|
|
display_props->height, server_msg_text);
|
2007-04-28 21:16:39 +00:00
|
|
|
server_msg_expire--;
|
2007-04-02 21:29:53 +00:00
|
|
|
if (server_msg_expire == 0) {
|
|
|
|
|
free(server_msg_text);
|
2003-02-28 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-30 00:15:25 +00:00
|
|
|
/* flush display out, frame and all... */
|
2007-04-02 21:29:53 +00:00
|
|
|
drivers_flush();
|
2000-03-30 20:20:41 +00:00
|
|
|
|
2007-04-02 21:29:53 +00:00
|
|
|
debug(RPT_DEBUG, "==== END RENDERING ====");
|
2000-04-03 22:13:57 +00:00
|
|
|
return 0;
|
2000-03-30 20:20:41 +00:00
|
|
|
|
1999-12-09 23:15:14 +00:00
|
|
|
}
|
|
|
|
|
|
2001-12-30 00:15:25 +00:00
|
|
|
/* The following function is positively ghastly (as was mentioned above!) */
|
|
|
|
|
/* Best thing to do is to remove support for frames... but anyway... */
|
|
|
|
|
/* */
|
2000-03-30 20:20:41 +00:00
|
|
|
static int
|
2007-04-02 21:29:53 +00:00
|
|
|
render_frame(LinkedList *list,
|
2001-12-30 00:15:25 +00:00
|
|
|
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? */
|
2007-04-29 12:08:16 +00:00
|
|
|
char fscroll, /* direction of scrolling */
|
2001-12-30 00:15:25 +00:00
|
|
|
int fspeed, /* speed of scrolling... */
|
2007-04-28 21:16:39 +00:00
|
|
|
long timer) /* current timer tick */
|
1999-12-09 23:15:14 +00:00
|
|
|
{
|
2007-04-29 12:08:16 +00:00
|
|
|
int fy = 0; /* Scrolling offset for the frame... */
|
1999-12-09 23:15:14 +00:00
|
|
|
|
2007-04-29 12:08:16 +00:00
|
|
|
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);
|
2001-12-30 00:15:25 +00:00
|
|
|
|
2004-12-30 17:34:02 +00:00
|
|
|
/* return on no data or illegal height */
|
2007-04-28 21:16:39 +00:00
|
|
|
if ((list == NULL) || (fhgt <= 0))
|
2004-12-30 17:34:02 +00:00
|
|
|
return -1;
|
1999-12-09 23:15:14 +00:00
|
|
|
|
2007-04-28 21:16:39 +00:00
|
|
|
if (fscroll == 'v') { /* vertical scrolling */
|
2004-12-30 17:34:02 +00:00
|
|
|
// only set offset !=0 when fspeed is != 0 and there is something to scroll
|
2007-04-29 12:08:16 +00:00
|
|
|
if ((fspeed != 0) && (fhgt > bottom - top)) {
|
|
|
|
|
int fy_max = fhgt - (bottom - top) + 1;
|
2001-09-21 21:08:10 +00:00
|
|
|
|
2004-12-30 17:34:02 +00:00
|
|
|
fy = (fspeed > 0)
|
|
|
|
|
? (timer / fspeed) % fy_max
|
|
|
|
|
: (-fspeed * timer) % fy_max;
|
2000-03-30 20:20:41 +00:00
|
|
|
|
2004-12-30 17:34:02 +00:00
|
|
|
fy = max(fy, 0); // safeguard against negative values
|
2007-04-29 12:08:16 +00:00
|
|
|
|
|
|
|
|
debug(RPT_DEBUG, "%s: fy=%d", __FUNCTION__, fy);
|
2004-12-30 17:34:02 +00:00
|
|
|
}
|
2007-04-28 21:16:39 +00:00
|
|
|
}
|
|
|
|
|
else if (fscroll == 'h') { /* horizontal scrolling */
|
2001-12-30 00:15:25 +00:00
|
|
|
/* TODO: Frames don't scroll horizontally yet! */
|
2000-04-03 22:13:57 +00:00
|
|
|
}
|
2000-03-30 20:20:41 +00:00
|
|
|
|
2004-12-30 17:34:02 +00:00
|
|
|
/* reset widget list */
|
2007-04-02 21:29:53 +00:00
|
|
|
LL_Rewind(list);
|
2004-12-30 17:34:02 +00:00
|
|
|
|
|
|
|
|
/* loop over all widgets */
|
2000-04-03 22:13:57 +00:00
|
|
|
do {
|
2007-04-02 21:29:53 +00:00
|
|
|
Widget *w = (Widget *) LL_Get(list);
|
2004-12-30 17:34:02 +00:00
|
|
|
|
2007-04-28 21:16:39 +00:00
|
|
|
if (w == NULL)
|
2000-04-03 22:13:57 +00:00
|
|
|
return -1;
|
1999-12-09 23:15:14 +00:00
|
|
|
|
2007-04-28 21:16:39 +00:00
|
|
|
/* TODO: Make this cleaner and more flexible! */
|
2000-04-03 22:13:57 +00:00
|
|
|
switch (w->type) {
|
2001-09-21 21:08:10 +00:00
|
|
|
case WID_STRING:
|
2007-04-29 12:08:16 +00:00
|
|
|
render_string(w, left, top - fy, right, bottom, fy);
|
2001-09-21 21:08:10 +00:00
|
|
|
break;
|
|
|
|
|
case WID_HBAR:
|
2007-04-29 12:08:16 +00:00
|
|
|
render_hbar(w, left, top - fy, right, bottom, fy);
|
2001-09-21 21:08:10 +00:00
|
|
|
break;
|
2007-04-28 21:16:39 +00:00
|
|
|
case WID_VBAR: /* FIXME: Vbars don't work in frames! */
|
2007-04-29 12:08:16 +00:00
|
|
|
render_vbar(w, left, top, right, bottom);
|
2000-04-03 22:13:57 +00:00
|
|
|
break;
|
2010-05-11 20:55:23 +00:00
|
|
|
case WID_ICON: /* FIXME: Vbars don't work in frames! */
|
2007-04-02 21:29:53 +00:00
|
|
|
drivers_icon(w->x, w->y, w->length);
|
2000-04-03 22:13:57 +00:00
|
|
|
break;
|
2007-04-28 21:16:39 +00:00
|
|
|
case WID_TITLE: /* FIXME: Doesn't work quite right in frames... */
|
2007-04-29 12:08:16 +00:00
|
|
|
render_title(w, left, top, right, bottom, timer);
|
2001-09-21 21:08:10 +00:00
|
|
|
break;
|
2007-04-28 21:16:39 +00:00
|
|
|
case WID_SCROLLER: /* FIXME: doesn't work in frames... */
|
2007-04-29 12:08:16 +00:00
|
|
|
render_scroller(w, left, top, right, bottom, timer);
|
2007-04-28 21:16:39 +00:00
|
|
|
break;
|
2001-09-21 21:08:10 +00:00
|
|
|
case WID_FRAME:
|
|
|
|
|
{
|
2001-12-30 00:15:25 +00:00
|
|
|
/* FIXME: doesn't handle nested frames quite right!
|
|
|
|
|
* doesn't handle scrolling in nested frames at all...
|
|
|
|
|
*/
|
2004-12-30 17:34:02 +00:00
|
|
|
int new_left = left + w->left - 1;
|
|
|
|
|
int new_top = top + w->top - 1;
|
|
|
|
|
int new_right = min(left + w->right, right);
|
|
|
|
|
int new_bottom = min(top + w->bottom, bottom);
|
|
|
|
|
|
2007-04-28 21:16:39 +00:00
|
|
|
if ((new_left < right) && (new_top < bottom)) /* Render only if it's visible... */
|
2007-04-29 12:08:16 +00:00
|
|
|
render_frame(w->frame_screen->widgetlist, new_left, new_top,
|
|
|
|
|
new_right, new_bottom, w->width, w->height,
|
|
|
|
|
w->length, w->speed, timer);
|
2000-04-03 22:13:57 +00:00
|
|
|
}
|
|
|
|
|
break;
|
2007-04-28 21:16:39 +00:00
|
|
|
case WID_NUM: /* FIXME: doesn't work in frames... */
|
|
|
|
|
/* NOTE: y=10 means COLON (:) */
|
2001-09-21 21:08:10 +00:00
|
|
|
if ((w->x > 0) && (w->y >= 0) && (w->y <= 10)) {
|
2007-04-02 21:29:53 +00:00
|
|
|
drivers_num(w->x + left, w->y);
|
2000-04-03 22:13:57 +00:00
|
|
|
}
|
2001-09-21 21:08:10 +00:00
|
|
|
break;
|
|
|
|
|
case WID_NONE:
|
2010-05-11 20:55:23 +00:00
|
|
|
/* FALLTHROUGH */
|
2001-09-21 21:08:10 +00:00
|
|
|
default:
|
|
|
|
|
break;
|
2000-04-03 22:13:57 +00:00
|
|
|
}
|
2007-04-02 21:29:53 +00:00
|
|
|
} while (LL_Next(list) == 0);
|
2000-04-03 22:13:57 +00:00
|
|
|
|
|
|
|
|
return 0;
|
1999-12-09 23:15:14 +00:00
|
|
|
}
|
2003-02-28 15:19:58 +00:00
|
|
|
|
2007-04-29 12:08:16 +00:00
|
|
|
|
|
|
|
|
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);
|
2010-10-28 20:50:16 +00:00
|
|
|
length = min(right - left - w->x + 1, sizeof(str)-1);
|
2007-04-29 12:08:16 +00:00
|
|
|
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;
|
2008-02-10 16:01:39 +00:00
|
|
|
int promille = (long) 1000 * w->length / (display_props->cellheight * full_len);
|
2007-04-29 12:08:16 +00:00
|
|
|
|
2008-02-10 16:01:39 +00:00
|
|
|
drivers_vbar(w->x + left, w->y + top, full_len, promille, BAR_PATTERN_FILLED);
|
2007-04-29 12:08:16 +00:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2009-11-01 08:32:50 +00:00
|
|
|
int vis_width = right - left;
|
|
|
|
|
|
2007-04-29 12:08:16 +00:00
|
|
|
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 != NULL) && (w->text != NULL) && (vis_width >= 8)) {
|
|
|
|
|
char str[BUFSIZE];
|
|
|
|
|
int length = strlen(w->text);
|
2007-04-30 13:06:06 +00:00
|
|
|
int width = vis_width - 6;
|
2007-04-29 12:08:16 +00:00
|
|
|
int x;
|
2007-04-30 13:06:06 +00:00
|
|
|
/* calculate delay from titlespeed: <=0 -> 0, [1 - infty] -> [10 - 1] */
|
|
|
|
|
int delay = (titlespeed <= TITLESPEED_NO)
|
|
|
|
|
? TITLESPEED_NO
|
|
|
|
|
: max(TITLESPEED_MIN, TITLESPEED_MAX - titlespeed);
|
2007-04-29 12:08:16 +00:00
|
|
|
|
2007-04-30 13:06:06 +00:00
|
|
|
/* display leading fillers */
|
2007-04-29 12:08:16 +00:00
|
|
|
drivers_icon(w->x + left, w->y + top, ICON_BLOCK_FILLED);
|
|
|
|
|
drivers_icon(w->x + left + 1, w->y + top, ICON_BLOCK_FILLED);
|
|
|
|
|
|
2010-10-28 20:50:16 +00:00
|
|
|
length = min(length, sizeof(str)-1);
|
2007-04-30 13:06:06 +00:00
|
|
|
if ((length <= width) || (delay == 0)) {
|
|
|
|
|
|
|
|
|
|
/* copy test starting from the beginning */
|
|
|
|
|
length = min(length, width);
|
2007-04-29 12:08:16 +00:00
|
|
|
strncpy(str, w->text, length);
|
|
|
|
|
str[length] = '\0';
|
|
|
|
|
|
2007-04-30 13:06:06 +00:00
|
|
|
/* set x value for trailing fillers */
|
2007-04-29 12:08:16 +00:00
|
|
|
x = length + 4;
|
|
|
|
|
}
|
|
|
|
|
else { /* Scroll the title, if it doesn't fit... */
|
2007-04-30 13:06:06 +00:00
|
|
|
int offset = timer;
|
|
|
|
|
int reverse;
|
2007-04-29 12:08:16 +00:00
|
|
|
|
2007-04-30 13:06:06 +00:00
|
|
|
/* if the delay is "too large" increase cycle length */
|
|
|
|
|
if ((delay != 0) && (delay < length / (length - width)))
|
|
|
|
|
offset /= delay;
|
|
|
|
|
|
|
|
|
|
/* reverse direction every length ticks */
|
|
|
|
|
reverse = (offset / length) & 1;
|
|
|
|
|
|
|
|
|
|
/* restrict offset to cycle length */
|
2007-04-29 12:08:16 +00:00
|
|
|
offset %= length;
|
|
|
|
|
offset = max(offset, 0);
|
|
|
|
|
|
2007-04-30 13:06:06 +00:00
|
|
|
/* if the delay is "low enough" slow down as requested */
|
|
|
|
|
if ((delay != 0) && (delay >= length / (length - width)))
|
|
|
|
|
offset /= delay;
|
|
|
|
|
|
|
|
|
|
/* restrict offset to the max. allowed offset: length - width */
|
|
|
|
|
offset = min(offset, length - width);
|
|
|
|
|
|
|
|
|
|
/* scroll backward by mirroring offset at max. offset */
|
|
|
|
|
if (reverse)
|
|
|
|
|
offset = (length - width) - offset;
|
|
|
|
|
|
|
|
|
|
/* copy test starting from offset */
|
2010-10-28 20:50:16 +00:00
|
|
|
length = min(width, sizeof(str)-1);
|
2007-04-29 12:08:16 +00:00
|
|
|
strncpy(str, w->text + offset, length);
|
|
|
|
|
str[length] = '\0';
|
|
|
|
|
|
2007-04-30 13:06:06 +00:00
|
|
|
/* set x value for trailing fillers */
|
2007-04-29 12:08:16 +00:00
|
|
|
x = vis_width - 2;
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-30 13:06:06 +00:00
|
|
|
/* display text */
|
2007-04-29 12:08:16 +00:00
|
|
|
drivers_string(w->x + 3 + left, w->y + top, str);
|
|
|
|
|
|
2007-04-30 13:06:06 +00:00
|
|
|
/* display trailing fillers */
|
2007-04-29 12:08:16 +00:00
|
|
|
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);
|
2010-10-28 20:50:16 +00:00
|
|
|
screen_width = min(screen_width, sizeof(str)-1);
|
2007-04-29 12:08:16 +00:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2007-10-29 21:30:55 +00:00
|
|
|
return 0;
|
2007-04-29 12:08:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-02-28 15:19:58 +00:00
|
|
|
int
|
2007-04-02 21:29:53 +00:00
|
|
|
server_msg(const char *text, int expire)
|
2003-02-28 15:19:58 +00:00
|
|
|
{
|
2007-04-02 21:29:53 +00:00
|
|
|
debug(RPT_DEBUG, "%s(text=\"%.40s\", expire=%d)", __FUNCTION__, text, expire);
|
2003-02-28 15:19:58 +00:00
|
|
|
|
2007-04-02 21:29:53 +00:00
|
|
|
if (strlen(text) > 15 || expire <= 0) {
|
2003-02-28 15:19:58 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Still a message active ? */
|
|
|
|
|
|
2007-04-02 21:29:53 +00:00
|
|
|
if (server_msg_expire > 0) {
|
|
|
|
|
free(server_msg_text);
|
2003-02-28 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Store new message */
|
2007-04-02 21:29:53 +00:00
|
|
|
server_msg_text = malloc(strlen(text) + 3);
|
|
|
|
|
strcpy(server_msg_text, "| ");
|
|
|
|
|
strcat(server_msg_text, text);
|
2003-02-28 15:19:58 +00:00
|
|
|
|
|
|
|
|
server_msg_expire = expire;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|