diff --git a/docs/lcdproc-dev/language.docbook b/docs/lcdproc-dev/language.docbook
index 653e98f..fd7cf6b 100644
--- a/docs/lcdproc-dev/language.docbook
+++ b/docs/lcdproc-dev/language.docbook
@@ -348,7 +348,7 @@
<left> <top> <right> <bottom> <direction> <speed> <text>
- direction can be "h" or "v".
+ direction can be "h", "m" or "v".
speed is the number of movements per rendering stroke (8 times/second).
diff --git a/docs/netstuff.txt b/docs/netstuff.txt
index dc3cce7..c3f54c2 100644
--- a/docs/netstuff.txt
+++ b/docs/netstuff.txt
@@ -194,7 +194,9 @@ widget_set #screen #id data
The speed is how many display frames to delay
between scrolling. Each display frame is
1/8th of a second, by default.
- Direction must be "h" or "v".
+ Direction must be "h" for horizontal, "m" for
+ marquee style horizontal or "v" for vertical
+ scrolling..
Positive speeds indicate frames per movement.
Negative speeds indicate movements per frame.
diff --git a/server/commands/widget_commands.c b/server/commands/widget_commands.c
index ee21e98..26beb87 100644
--- a/server/commands/widget_commands.c
+++ b/server/commands/widget_commands.c
@@ -373,8 +373,9 @@ widget_set_func (Client * c, int argc, char **argv)
/*debug("dir: %c",(char)direction);*/
speed = atoi (argv[i + 5]);
/*debug("speed: %d",speed);*/
- /* Direction must be v or h*/
- if (((char) direction != 'h') && ((char) direction != 'v')) {
+ /* Direction must be m, v or h*/
+ if (((char) direction != 'h') && ((char) direction != 'v') &&
+ ((char) direction != 'm')) {
sock_send_string (c->sock, "huh? Invalid direction\n");
} else {
w->left = left;
diff --git a/server/render.c b/server/render.c
index b4dc68f..26bd02a 100644
--- a/server/render.c
+++ b/server/render.c
@@ -171,16 +171,12 @@ render_frame (LinkedList * list,
#define VerticalScrolling (fscroll == 'v')
#define HorizontalScrolling (fscroll == 'h')
- char str[BUFSIZE]; /* scratch buffer */
- Widget * w;
-
- int vis_width, vis_height; /* Width and height of visible frame area */
+ int vis_width = right - left; /* width of visible frame area */
+ int vis_height = bottom - top; /* height of visible frame area */
int x, y;
- int fx, fy; /* Scrolling offset for the frame... */
+ int fx = 0, fy = 0; /* Scrolling offset for the frame... */
int length, speed;
- /*int lines; */
int str_length = BUFSIZE-1;
-
int reset = 1;
debug( RPT_DEBUG, "%s( list=%p, fscroll='%c', left=%d, top=%d, "
@@ -188,50 +184,47 @@ render_frame (LinkedList * list,
__FUNCTION__, list, fscroll, left,top, right, bottom,
fwid, fhgt, fspeed, timer );
- vis_width = right - left; /* This is the size of the visible frame area */
- vis_height = bottom - top;
+ /* return on no data or illegal height */
+ if (!list || (fhgt <= 0))
+ return -1;
- fx = 0;
- fy = 0;
if (VerticalScrolling) {
- if (fspeed > 0)
- fy = (timer - fspeed) / fspeed;
- else if (fspeed < 0)
- fy = (-fspeed) * timer;
+ // FIXME: timer may be negative (this should be changed generally)
+ // 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 (fy < 0)
- fy = 0;
-
- if (fhgt == 0) { fy = 0; } else { fy %= fhgt; }
- if (fy > fhgt - vis_height)
- fy = fhgt - vis_height;
+ fy = (fspeed > 0)
+ ? (timer / fspeed) % fy_max
+ : (-fspeed * timer) % fy_max;
+ fy = max(fy, 0); // safeguard against negative values
+ }
} else if (HorizontalScrolling) {
/* TODO: Frames don't scroll horizontally yet! */
}
- if (!list)
- return -1;
-
+ /* reset widget list */
LL_Rewind (list);
+
+ /* loop over all widgets */
do {
- w = (Widget *) LL_Get (list);
+ char str[BUFSIZE]; /* scratch buffer */
+ Widget *w = (Widget *) LL_Get (list);
+
if (!w)
return -1;
/* TODO: Make this cleaner and more flexible!*/
switch (w->type) {
case WID_STRING:
- if (w->x>0 && w->y>0 && w->text) {
- if ((w->y <= vis_height + fy) && (w->y > fy)) {
- if (w->x > vis_width) w->x=vis_width;
- str_length = abs(vis_width - w->x + 1);
- if (str_length >= BUFSIZE)
- str_length = BUFSIZE - 1;
- strncpy (str, w->text, str_length);
- str[str_length] = 0;
- drivers_string (w->x + left, w->y + top - fy, str);
- }
+ if ((w->x > 0) && (w->y > 0) && (w->text) &&
+ (w->y <= vis_height + fy) && (w->y > fy)) {
+ w->x = min(w->x, vis_width);
+ str_length = min(vis_width - w->x + 1, BUFSIZE - 1);
+ strncpy (str, w->text, str_length);
+ str[str_length] = 0;
+ drivers_string (w->x + left, w->y + top - fy, str);
}
break;
case WID_HBAR:
@@ -239,29 +232,28 @@ render_frame (LinkedList * list,
//drivers_init_hbar ();
reset = 0;
}
- if ((w->x > 0) && (w->y > 0)) {
- if ((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.
- */
+ 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.
+ */
}
}
break;
@@ -299,8 +291,7 @@ render_frame (LinkedList * list,
drivers_icon (w->x + left + 1, w->y + top, ICON_BLOCK_FILLED);
length = strlen (w->text);
- if (length >= BUFSIZE)
- length = BUFSIZE - 1;
+ length = min(length, BUFSIZE - 1);
if (length <= vis_width - 6) {
strncpy (str, w->text, length);
str[length] = 0;
@@ -311,19 +302,15 @@ render_frame (LinkedList * list,
x = timer / speed;
y = x / length;
- x %= (length);
- if (x < 0)
- x = 0;
+ x %= length;
+ x = max(x, 0);
if (x > length - (vis_width - 6))
x = length - (vis_width - 6);
if (y & 1) /* Scrolling backwards...*/
- {
x = (length - (vis_width - 6)) - x;
- }
str_length = abs(vis_width - 6);
- if (str_length >= BUFSIZE)
- str_length = BUFSIZE -1;
+ str_length = min(str_length, BUFSIZE -1);
strncpy (str, w->text + x, str_length);
str[str_length] = 0;
x = vis_width - 1;
@@ -340,18 +327,54 @@ render_frame (LinkedList * list,
{
int offset;
int screen_width;
+
if (!w->text)
break;
if (w->right < w->left)
break;
/*debug(RPT_DEBUG, "%s: %s %d",__FUNCTION__,w->text,timer);*/
screen_width = abs(w->right - w->left + 1);
- if (screen_width >= BUFSIZE)
- screen_width = BUFSIZE -1;
+ screen_width = min(screen_width, BUFSIZE -1);
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) {
@@ -360,6 +383,7 @@ render_frame (LinkedList * list,
} else {
int effLength = length - screen_width;
int necessaryTimeUnits = 0;
+
if (w->speed > 0) {
necessaryTimeUnits = effLength * w->speed;
if (((timer / (effLength * w->speed)) % 2) == 0) {
@@ -400,6 +424,7 @@ render_frame (LinkedList * list,
case 'v':
{
int i = 0;
+
length = strlen (w->text);
if (length <= screen_width) {
/* no scrolling required... */
@@ -408,6 +433,7 @@ render_frame (LinkedList * list,
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...*/
for (i = 0; i < lines_required; i++) {
@@ -419,6 +445,7 @@ render_frame (LinkedList * list,
int necessaryTimeUnits = 0;
int effLines = lines_required - available_lines + 1;
int begin = 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;
@@ -465,19 +492,13 @@ render_frame (LinkedList * list,
/* FIXME: doesn't handle nested frames quite right!
* doesn't handle scrolling in nested frames at all...
*/
- int new_left, new_top, new_right, new_bottom;
- new_left = left + w->left - 1;
- new_top = top + w->top - 1;
- new_right = left + w->right;
- new_bottom = top + w->bottom;
- if (new_right > right)
- new_right = right;
- if (new_bottom > bottom)
- new_bottom = bottom;
- if (new_left >= right || new_top >= bottom) { /* Do nothing if it's invisible...*/
- } else {
+ 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);
+
+ 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);
- }
}
break;
case WID_NUM: /* FIXME: doesn't work in frames...*/