flac: Saner EOF handling
[cmus.git] / window.c
blobd40de855939a630eef441bc0f58b8936e6f0fea8
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 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_empty(&win->top));
244 BUG_ON(iter_is_empty(iter));
245 BUG_ON(iter->data0 != win->head.data0);
247 if (iters_equal(&win->sel, iter))
248 return;
249 win->sel = *iter;
251 tmp = win->head;
252 win->get_next(&tmp);
253 top_nr = 0;
254 while (!iters_equal(&tmp, &win->top)) {
255 win->get_next(&tmp);
256 top_nr++;
259 tmp = win->head;
260 win->get_next(&tmp);
261 sel_nr = 0;
262 while (!iters_equal(&tmp, &win->sel)) {
263 BUG_ON(!win->get_next(&tmp));
264 sel_nr++;
267 if (sel_nr < top_nr)
268 win->top = win->sel;
269 while (sel_nr - top_nr >= win->nr_rows) {
270 win->get_next(&win->top);
271 top_nr++;
273 sel_changed(win);
276 void window_goto_top(struct window *win)
278 struct iter old_sel;
280 old_sel = win->sel;
281 win->sel = win->head;
282 win->get_next(&win->sel);
283 win->top = win->sel;
284 if (!iters_equal(&old_sel, &win->sel))
285 sel_changed(win);
288 void window_goto_bottom(struct window *win)
290 struct iter old_sel;
291 int count;
293 old_sel = win->sel;
294 win->sel = win->head;
295 win->get_prev(&win->sel);
296 win->top = win->sel;
297 count = win->nr_rows - 1;
298 while (count) {
299 struct iter iter = win->top;
301 if (!win->get_prev(&iter))
302 break;
303 win->top = iter;
304 count--;
306 if (!iters_equal(&old_sel, &win->sel))
307 sel_changed(win);
310 void window_page_up(struct window *win)
312 window_up(win, win->nr_rows - 1);
315 void window_page_down(struct window *win)
317 window_down(win, win->nr_rows - 1);
320 int window_get_nr_rows(struct window *win)
322 return win->nr_rows;