simplify this conditional a bit
[monky] / src / scroll.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  *
3  * Conky, a system monitor, based on torsmo
4  *
5  * Any original torsmo code is licensed under the BSD license
6  *
7  * All code written since the fork of torsmo is licensed under the GPL
8  *
9  * Please see COPYING for details
10  *
11  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
13  *      (see AUTHORS)
14  * All rights reserved.
15  *
16  * This program is free software: you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * You should have received a copy of the GNU General Public License
26  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27  *
28  */
29 #include "conky.h"
30 #include "core.h"
31 #include "logging.h"
32 #include "specials.h"
33 #include "text_object.h"
34
35 struct scroll_data {
36         char *text;
37         unsigned int show;
38         unsigned int step;
39         unsigned int start;
40         long resetcolor;
41 };
42
43 void parse_scroll_arg(struct text_object *obj, const char *arg, void *free_at_crash)
44 {
45         struct scroll_data *sd;
46         int n1 = 0, n2 = 0;
47
48         sd = malloc(sizeof(struct scroll_data));
49         memset(sd, 0, sizeof(struct scroll_data));
50
51         sd->resetcolor = get_current_text_color();
52         sd->step = 1;
53         if (!arg || sscanf(arg, "%u %n", &sd->show, &n1) <= 0)
54                 CRIT_ERR(obj, free_at_crash, "scroll needs arguments: <length> [<step>] <text>");
55
56         sscanf(arg + n1, "%u %n", &sd->step, &n2);
57         if (*(arg + n1 + n2)) {
58                 n1 += n2;
59         } else {
60                 sd->step = 1;
61         }
62         sd->text = malloc(strlen(arg + n1) + sd->show + 1);
63         for(n2 = 0; (unsigned int) n2 < sd->show; n2++) {
64                 sd->text[n2] = ' ';
65         }
66         sd->text[n2] = 0;
67         strcat(sd->text, arg + n1);
68         sd->start = 0;
69         obj->sub = malloc(sizeof(struct text_object));
70         extract_variable_text_internal(obj->sub, sd->text);
71
72         obj->data.opaque = sd;
73 }
74
75 void print_scroll(struct text_object *obj, char *p, int p_max_size, struct information *cur)
76 {
77         struct scroll_data *sd = obj->data.opaque;
78         unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
79         char *pwithcolors;
80         char buf[max_user_text];
81
82         if (!sd)
83                 return;
84
85         generate_text_internal(buf, max_user_text, *obj->sub, cur);
86         for(j = 0; buf[j] != 0; j++) {
87                 switch(buf[j]) {
88                         case '\n':      //place all the lines behind each other with LINESEPARATOR between them
89 #define LINESEPARATOR '|'
90                                 buf[j]=LINESEPARATOR;
91                                 break;
92                         case SPECIAL_CHAR:
93                                 colorchanges++;
94                                 break;
95                 }
96         }
97         //no scrolling necessary if the length of the text to scroll is too short
98         if (strlen(buf) - colorchanges <= sd->show) {
99                 snprintf(p, p_max_size, "%s", buf);
100                 return;
101         }
102         //make sure a colorchange at the front is not part of the string we are going to show
103         while(*(buf + sd->start) == SPECIAL_CHAR) {
104                 sd->start++;
105         }
106         //place all chars that should be visible in p, including colorchanges
107         for(j=0; j < sd->show + visibcolorchanges; j++) {
108                 p[j] = *(buf + sd->start + j);
109                 if(p[j] == SPECIAL_CHAR) {
110                         visibcolorchanges++;
111                 }
112                 //if there is still room fill it with spaces
113                 if( ! p[j]) break;
114         }
115         for(; j < sd->show + visibcolorchanges; j++) {
116                 p[j] = ' ';
117         }
118         p[j] = 0;
119         //count colorchanges in front of the visible part and place that many colorchanges in front of the visible part
120         for(j = 0; j < sd->start; j++) {
121                 if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
122         }
123         pwithcolors=malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
124         for(j = 0; j < frontcolorchanges; j++) {
125                 pwithcolors[j] = SPECIAL_CHAR;
126         }
127         pwithcolors[j] = 0;
128         strcat(pwithcolors,p);
129         strend = strlen(pwithcolors);
130         //and place the colorchanges not in front or in the visible part behind the visible part
131         for(j = 0; j < colorchanges - frontcolorchanges - visibcolorchanges; j++) {
132                 pwithcolors[strend + j] = SPECIAL_CHAR;
133         }
134         pwithcolors[strend + j] = 0;
135         strcpy(p, pwithcolors);
136         free(pwithcolors);
137         //scroll
138         sd->start += sd->step;
139         if(buf[sd->start] == 0){
140                 sd->start = 0;
141         }
142 #ifdef X11
143         //reset color when scroll is finished
144         new_fg(p + strlen(p), sd->resetcolor);
145 #endif
146 }
147
148 void free_scroll(struct text_object *obj)
149 {
150         struct scroll_data *sd = obj->data.opaque;
151
152         if (!sd)
153                 return;
154
155         if (sd->text)
156                 free(sd->text);
157         if (obj->sub) {
158                 free_text_objects(obj->sub, 1);
159                 free(obj->sub);
160                 obj->sub = NULL;
161         }
162         free(obj->data.opaque);
163         obj->data.opaque = NULL;
164 }