add :refresh command
[cmus.git] / window.c
blob91dc5fff42ba5034ca5c44b5a93835ed4740b941
1 /*
2 * Copyright 2004-2005 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include <window.h>
21 #include <xmalloc.h>
22 #include <debug.h>
24 #include <stdlib.h>
26 static void sel_changed(struct window *win)
28 if (win->sel_changed)
29 win->sel_changed();
30 win->changed = 1;
33 struct window *window_new(int (*get_prev)(struct iter *), int (*get_next)(struct iter *))
35 struct window *win;
37 win = xnew(struct window, 1);
38 win->get_next = get_next;
39 win->get_prev = get_prev;
40 win->sel_changed = NULL;
41 win->nr_rows = 1;
42 win->changed = 1;
43 iter_init(&win->head);
44 iter_init(&win->top);
45 iter_init(&win->sel);
46 return win;
49 void window_free(struct window *win)
51 free(win);
54 void window_set_empty(struct window *win)
56 iter_init(&win->head);
57 iter_init(&win->top);
58 iter_init(&win->sel);
59 sel_changed(win);
62 void window_set_contents(struct window *win, void *head)
64 struct iter first;
66 win->head.data0 = head;
67 win->head.data1 = NULL;
68 win->head.data2 = NULL;
69 first = win->head;
70 win->get_next(&first);
71 win->top = first;
72 win->sel = first;
73 sel_changed(win);
76 void window_set_nr_rows(struct window *win, int nr_rows)
78 struct iter old_sel;
80 if (nr_rows < 1)
81 return;
82 win->nr_rows = nr_rows;
83 old_sel = win->sel;
84 window_changed(win);
85 win->changed = 1;
88 void window_up(struct window *win, int rows)
90 int i;
92 for (i = 0; i < rows; i++) {
93 struct iter prev = win->sel;
95 if (!win->get_prev(&prev))
96 break;
97 if (iters_equal(&win->sel, &win->top))
98 win->top = prev;
99 win->sel = prev;
101 if (i)
102 sel_changed(win);
105 void window_down(struct window *win, int rows)
107 struct iter iter;
108 int delta, sel_down, top_down;
110 /* distance between top and sel */
111 delta = 0;
112 iter = win->top;
113 while (!iters_equal(&iter, &win->sel)) {
114 win->get_next(&iter);
115 delta++;
118 for (sel_down = 0; sel_down < rows; sel_down++) {
119 iter = win->sel;
120 if (!win->get_next(&iter))
121 break;
122 win->sel = iter;
125 top_down = sel_down - (win->nr_rows - delta - 1);
126 while (top_down > 0) {
127 win->get_next(&win->top);
128 top_down--;
130 if (sel_down)
131 sel_changed(win);
135 * minimize number of empty lines visible
136 * make sure selection is visible
138 void window_changed(struct window *win)
140 struct iter iter;
141 int delta, rows;
143 if (iter_is_null(&win->head)) {
144 BUG_ON(!iter_is_null(&win->top));
145 BUG_ON(!iter_is_null(&win->sel));
146 return;
148 BUG_ON(iter_is_null(&win->top));
149 BUG_ON(iter_is_null(&win->sel));
151 /* make sure top and sel point to real row if possible */
152 if (iter_is_head(&win->top)) {
153 win->get_next(&win->top);
154 win->sel = win->top;
155 sel_changed(win);
156 return;
159 /* make sure the selected row is visible */
161 /* get distance between top and sel */
162 delta = 0;
163 iter = win->top;
164 while (!iters_equal(&iter, &win->sel)) {
165 if (!win->get_next(&iter)) {
166 /* sel < top, scroll up until top == sel */
167 while (!iters_equal(&win->top, &win->sel))
168 BUG_ON(!win->get_prev(&win->top));
169 goto minimize;
171 delta++;
174 /* scroll down until sel is visible */
175 while (delta > win->nr_rows - 1) {
176 win->get_next(&win->top);
177 delta--;
179 minimize:
180 /* minimize number of empty lines shown */
181 iter = win->top;
182 rows = 1;
183 while (rows < win->nr_rows) {
184 if (!win->get_next(&iter))
185 break;
186 rows++;
188 while (rows < win->nr_rows) {
189 iter = win->top;
190 if (!win->get_prev(&iter))
191 break;
192 win->top = iter;
193 rows++;
195 win->changed = 1;
198 void window_row_vanishes(struct window *win, struct iter *iter)
200 struct iter new = *iter;
202 BUG_ON(iter->data0 != win->head.data0);
203 if (!win->get_next(&new)) {
204 new = *iter;
205 win->get_prev(&new);
207 if (iters_equal(&win->top, iter))
208 win->top = new;
209 if (iters_equal(&win->sel, iter)) {
210 win->sel = new;
211 sel_changed(win);
213 win->changed = 1;
216 int window_get_top(struct window *win, struct iter *iter)
218 *iter = win->top;
219 return !iter_is_empty(iter);
222 int window_get_sel(struct window *win, struct iter *iter)
224 *iter = win->sel;
225 return !iter_is_empty(iter);
228 int window_get_prev(struct window *win, struct iter *iter)
230 return win->get_prev(iter);
233 int window_get_next(struct window *win, struct iter *iter)
235 return win->get_next(iter);
238 void window_set_sel(struct window *win, struct iter *iter)
240 int sel_nr, top_nr;
241 struct iter tmp;
243 BUG_ON(iter_is_null(&win->head));
244 BUG_ON(iter_is_empty(&win->top));
245 BUG_ON(iter_is_empty(&win->sel));
246 BUG_ON(iter_is_empty(iter));
247 BUG_ON(iter->data0 != win->head.data0);
249 if (iters_equal(&win->sel, iter))
250 return;
251 win->sel = *iter;
253 tmp = win->head;
254 win->get_next(&tmp);
255 top_nr = 0;
256 while (!iters_equal(&tmp, &win->top)) {
257 BUG_ON(!win->get_next(&tmp));
258 top_nr++;
261 tmp = win->head;
262 win->get_next(&tmp);
263 sel_nr = 0;
264 while (!iters_equal(&tmp, &win->sel)) {
265 BUG_ON(!win->get_next(&tmp));
266 sel_nr++;
269 if (sel_nr < top_nr)
270 win->top = win->sel;
271 while (sel_nr - top_nr >= win->nr_rows) {
272 BUG_ON(!win->get_next(&win->top));
273 top_nr++;
275 sel_changed(win);
278 void window_goto_top(struct window *win)
280 struct iter old_sel;
282 old_sel = win->sel;
283 win->sel = win->head;
284 win->get_next(&win->sel);
285 win->top = win->sel;
286 if (!iters_equal(&old_sel, &win->sel))
287 sel_changed(win);
290 void window_goto_bottom(struct window *win)
292 struct iter old_sel;
293 int count;
295 old_sel = win->sel;
296 win->sel = win->head;
297 win->get_prev(&win->sel);
298 win->top = win->sel;
299 count = win->nr_rows - 1;
300 while (count) {
301 struct iter iter = win->top;
303 if (!win->get_prev(&iter))
304 break;
305 win->top = iter;
306 count--;
308 if (!iters_equal(&old_sel, &win->sel))
309 sel_changed(win);
312 void window_page_up(struct window *win)
314 window_up(win, win->nr_rows - 1);
317 void window_page_down(struct window *win)
319 window_down(win, win->nr_rows - 1);
322 int window_get_nr_rows(struct window *win)
324 return win->nr_rows;