4 Copyright (C) 1999-2001 Timo Sirainen
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "statusbar.h"
27 #include "gui-windows.h"
29 static int backs[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; /* FIXME: should be in some more generic place.. */
31 void statusbar_items_init(void);
32 void statusbar_items_deinit(void);
34 static GSList *statusbars;
35 static int sbar_uppest, sbar_lowest, sbars_up, sbars_down;
37 static void statusbar_item_destroy(SBAR_ITEM_REC *rec)
39 rec->bar->items = g_slist_remove(rec->bar->items, rec);
43 static int sbar_item_cmp(SBAR_ITEM_REC *item1, SBAR_ITEM_REC *item2)
45 return item1->priority == item2->priority ? 0 :
46 item1->priority < item2->priority ? -1 : 1;
49 static int statusbar_shrink_to_min(GSList *items, int size, int max_width)
53 for (tmp = items; tmp != NULL; tmp = tmp->next) {
54 SBAR_ITEM_REC *rec = tmp->data;
56 size -= (rec->max_size-rec->min_size);
57 rec->size = rec->min_size;
59 if (size <= max_width) {
60 rec->size += max_width-size;
65 /* min_size was 0, item removed.
66 remove the marginal too */
74 static void statusbar_shrink_forced(GSList *items, int size, int max_width)
78 for (tmp = items; tmp != NULL; tmp = tmp->next) {
79 SBAR_ITEM_REC *rec = tmp->data;
81 if (size-rec->size > max_width) {
82 /* remove the whole item */
83 size -= rec->size+1; /* +1 == the marginal */
87 rec->size -= size-max_width;
93 static void statusbar_get_sizes(STATUSBAR_REC *bar, int max_width)
95 GSList *tmp, *prior_sorted;
98 /* first give items their max. size */
100 width = -1; /* -1 because of the marginals */
101 for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
102 SBAR_ITEM_REC *rec = tmp->data;
104 rec->func(rec, TRUE);
105 rec->size = rec->max_size;
108 /* +1 == marginal between items */
109 width += rec->max_size+1;
111 prior_sorted = g_slist_insert_sorted(prior_sorted, rec,
117 if (width > max_width) {
118 /* too big, start shrinking from items with lowest priority
119 and shrink until everything fits or until we've shrinked
121 width = statusbar_shrink_to_min(prior_sorted, width,
123 if (width > max_width) {
124 /* still need to shrink, remove the items with lowest
125 priority until everything fits to screen */
126 statusbar_shrink_forced(prior_sorted, width,
131 g_slist_free(prior_sorted);
134 static void statusbar_redraw_line(STATUSBAR_REC *bar)
136 WINDOW_REC *old_active_win;
140 old_active_win = active_win;
141 if (bar->window != NULL)
142 active_win = bar->window->active;
144 statusbar_get_sizes(bar, COLS-2);
147 for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
148 SBAR_ITEM_REC *rec = tmp->data;
150 if (!rec->right_justify && rec->size > 0) {
153 rec->func(rec, FALSE);
158 for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
159 SBAR_ITEM_REC *rec = tmp->data;
161 if (rec->right_justify && rec->size > 0) {
162 rxpos -= rec->size+1;
164 rec->func(rec, FALSE);
168 active_win = old_active_win;
171 static void statusbar_redraw_all(void)
173 screen_refresh_freeze();
174 g_slist_foreach(statusbars, (GFunc) statusbar_redraw, NULL);
175 screen_refresh_thaw();
178 STATUSBAR_REC *statusbar_find(int pos, int line)
182 for (tmp = statusbars; tmp != NULL; tmp = tmp->next) {
183 STATUSBAR_REC *rec = tmp->data;
185 if (rec->pos == pos && rec->line == line)
192 void statusbar_redraw(STATUSBAR_REC *bar)
195 statusbar_redraw_all();
199 set_bg(stdscr, backs[bar->color] << 4);
200 move(bar->ypos, 0); clrtoeol();
203 statusbar_redraw_line(bar);
205 screen_refresh(NULL);
208 void statusbar_item_redraw(SBAR_ITEM_REC *item)
210 g_return_if_fail(item != NULL);
212 item->func(item, TRUE);
213 if (item->max_size != item->size)
214 statusbar_redraw(item->bar);
216 item->func(item, FALSE);
217 screen_refresh(NULL);
221 static int get_last_bg(const char *str)
225 while (*str != '\0') {
226 if (*str == '%' && str[1] != '\0') {
228 if (*str >= '0' && *str <= '7')
237 /* ypos is used only when pos == STATUSBAR_POS_MIDDLE */
238 STATUSBAR_REC *statusbar_create(int pos, int ypos)
243 rec = g_new0(STATUSBAR_REC, 1);
244 statusbars = g_slist_append(statusbars, rec);
247 rec->line = pos == STATUSBAR_POS_MIDDLE ? ypos :
248 mainwindows_reserve_lines(1, pos == STATUSBAR_POS_UP);
249 rec->ypos = pos == STATUSBAR_POS_MIDDLE ? ypos :
250 pos == STATUSBAR_POS_UP ? rec->line : LINES-1-rec->line;
252 /* get background color from sb_background abstract */
253 str = theme_format_expand(current_theme, "{sb_background}");
254 if (str == NULL) str = g_strdup("%n%8");
255 rec->color_string = g_strconcat("%n", str, NULL);
258 rec->color = get_last_bg(rec->color_string);
259 if (rec->color < 0) rec->color = current_theme->default_real_color;
261 if (pos == STATUSBAR_POS_UP) {
262 if (sbars_up == 0) sbar_uppest = rec->line;
264 rec->line -= sbar_uppest;
265 } else if (pos == STATUSBAR_POS_DOWN) {
266 if (sbars_down == 0) sbar_lowest = rec->line;
268 rec->line -= sbar_lowest;
271 set_bg(stdscr, backs[rec->color] << 4);
272 move(rec->ypos, 0); clrtoeol();
278 static void statusbars_pack(int pos, int line)
282 for (tmp = statusbars; tmp != NULL; tmp = tmp->next) {
283 STATUSBAR_REC *rec = tmp->data;
285 if (rec->pos == pos && rec->line > line) {
287 rec->ypos += (pos == STATUSBAR_POS_UP ? -1 : 1);
292 void statusbar_destroy(STATUSBAR_REC *bar)
294 g_return_if_fail(bar != NULL);
296 if (bar->pos != STATUSBAR_POS_MIDDLE)
297 mainwindows_reserve_lines(-1, bar->pos == STATUSBAR_POS_UP);
299 if (bar->pos == STATUSBAR_POS_UP) sbars_up--;
300 if (bar->pos == STATUSBAR_POS_DOWN) sbars_down--;
301 statusbars = g_slist_remove(statusbars, bar);
303 while (bar->items != NULL)
304 statusbar_item_destroy(bar->items->data);
306 if (bar->pos != STATUSBAR_POS_MIDDLE)
307 statusbars_pack(bar->pos, bar->pos);
308 g_free(bar->color_string);
311 if (!quitting) statusbar_redraw_all();
314 SBAR_ITEM_REC *statusbar_item_create(STATUSBAR_REC *bar,
315 int priority, int right_justify,
320 g_return_val_if_fail(bar != NULL, NULL);
321 g_return_val_if_fail(func != NULL, NULL);
323 rec = g_new0(SBAR_ITEM_REC, 1);
325 bar->items = g_slist_append(bar->items, rec);
327 rec->priority = priority;
328 rec->right_justify = right_justify;
334 void statusbar_item_remove(SBAR_ITEM_REC *item)
336 g_return_if_fail(item != NULL);
338 statusbar_item_destroy(item);
339 if (!quitting) statusbar_redraw_all();
342 static void sig_mainwindow_resized(MAIN_WINDOW_REC *window)
346 rec = window->statusbar;
347 rec->ypos = window->first_line+window->height;
350 void statusbar_init(void)
353 sbars_up = sbars_down = 0;
355 statusbar_items_init();
356 signal_add("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
357 signal_add("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);
360 void statusbar_deinit(void)
362 statusbar_items_deinit();
364 while (statusbars != NULL)
365 statusbar_destroy(statusbars->data);
367 signal_remove("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized);
368 signal_remove("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized);