1 /*
2 * Copyright (c) 2010, 2011 Ryan Flannery <ryan.flannery@gmail.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "uinterface.h"
18
19 /* the global user interface object */
20 uinterface ui;
21
22 /*****************************************************************************
23 * scrollable window stuff
24 ****************************************************************************/
25
26 swindow*
swindow_new(int h,int w,int y,int x)27 swindow_new(int h, int w, int y, int x)
28 {
29 swindow *swin = malloc(sizeof(swindow));
30 if (swin == NULL)
31 err(1, "swindow_new failed to allocate swin");
32
33 swin->w = w;
34 swin->h = h;
35 swin->voffset = 0;
36 swin->hoffset = 0;
37 swin->crow = 0;
38 swin->nrows = 0;
39 swin->cwin = newwin(h, w, y, x);
40 if (swin->cwin == NULL)
41 errx(1, "swindow_new: failed to create window");
42
43 return swin;
44 }
45
46 void
swindow_resize(swindow * win,int h,int w,int y,int x)47 swindow_resize(swindow *win, int h, int w, int y, int x)
48 {
49 wresize(win->cwin, h, w);
50 mvwin(win->cwin, y, x);
51
52 win->w = w;
53 win->h = h;
54
55 if (win->crow >= h)
56 win->crow = h - 1;
57 }
58
59 void
swindow_free(swindow * win)60 swindow_free(swindow *win)
61 {
62 delwin(win->cwin);
63 free(win);
64 }
65
66 void
swindow_scroll(swindow * win,Direction d,int n)67 swindow_scroll(swindow *win, Direction d, int n)
68 {
69 switch (d) {
70 case UP:
71 win->voffset -= n;
72 if (win->voffset < 0)
73 win->voffset = 0;
74 break;
75
76 case DOWN:
77 win->voffset += n;
78 if (win->voffset >= win->nrows - win->h)
79 win->voffset = win->nrows - win->h;
80 if (win->voffset < 0)
81 win->voffset = 0;
82 break;
83
84 case LEFT:
85 win->hoffset -= n;
86 if (win->hoffset < 0)
87 win->hoffset = 0;
88 break;
89
90 case RIGHT:
91 win->hoffset += n;
92 /* NOTE: "overflow" here is handled elsewhere.
93 * see input_handlers.c, scroll_col()
94 */
95 break;
96
97 default:
98 err(1, "swindow_scroll: bad direction");
99 }
100 }
101
102 /*****************************************************************************
103 * UI Create / Resize / Destroy Functions
104 ****************************************************************************/
105
106 void
ui_init(int library_width)107 ui_init(int library_width)
108 {
109 int lines, cols;
110
111 /* ncurses init */
112 initscr();
113 raw();
114 noecho();
115 nonl();
116 keypad(stdscr, TRUE);
117 start_color();
118 curs_set(0);
119 ESCDELAY = 0;
120 refresh();
121
122 getmaxyx(stdscr, lines, cols);
123
124 /* setup width of library window */
125 ui.lwidth = library_width;
126 ui.lhide = false;
127
128 /* create the player and command windows */
129 ui.player = newwin(1, cols, 0, 0);
130 ui.command = newwin(1, cols, lines - 1, 0);
131 if (ui.player == NULL || ui.command == NULL)
132 errx(1, "ui_init: failed to create player/command windows");
133
134 /* and the rest */
135 ui.library = swindow_new(lines - 3, ui.lwidth, 2, 0);
136 ui.playlist = swindow_new(lines - 3, cols - ui.lwidth - 1, 2, ui.lwidth + 1);
137
138 ui.active = ui.library;
139 }
140
141 bool
ui_is_init()142 ui_is_init()
143 {
144 return isendwin() == TRUE;
145 }
146
147 void
ui_destroy()148 ui_destroy()
149 {
150 /* destroy each window (this also free()'s the mem for each window) */
151 delwin(ui.player);
152 delwin(ui.command);
153 swindow_free(ui.playlist);
154 if (ui.library != NULL)
155 swindow_free(ui.library);
156
157 /* reset other properties of the ui to sane 'empty' defaults */
158 ui.player = NULL;
159 ui.command = NULL;
160 ui.library = NULL;
161 ui.playlist = NULL;
162 ui.active = NULL;
163
164 /* end ncurses */
165 endwin();
166 }
167
168 void
ui_resize()169 ui_resize()
170 {
171 struct winsize ws;
172
173 /* get new dimensions and check for changes */
174 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
175 err(1, "ui_resize: ioctl failed");
176
177 /* can we even handle the new display size? if not, just exit */
178 if (ws.ws_col < ui.lwidth + 2) {
179 endwin();
180 errx(1, "ui_resize: not enough columns to render vitunes nicely");
181 }
182 if (ws.ws_row < 4) {
183 endwin();
184 errx(1, "ui_resize: not enough rows to render vitunes nicely");
185 }
186
187 /* resize ncurses */
188 resizeterm(ws.ws_row, ws.ws_col);
189
190 /* resize player & command windows */
191 wresize(ui.player, 1, ws.ws_col);
192 wresize(ui.command, 1, ws.ws_col);
193
194 /* resize library and playlist windows */
195 if (ui.library->cwin == NULL)
196 swindow_resize(ui.playlist, ws.ws_row - 3, ws.ws_col, 2, 0);
197 else {
198 swindow_resize(ui.library, ws.ws_row - 3, ui.lwidth, 2, 0);
199 swindow_resize(ui.playlist, ws.ws_row - 3, ws.ws_col - ui.lwidth - 1, 2, ui.lwidth + 1);
200 }
201
202 /* move the command window to the new bottom row */
203 mvwin(ui.command, ws.ws_row - 1, 0);
204
205 }
206
207 void
ui_hide_library()208 ui_hide_library()
209 {
210 int w, h;
211
212 /* if already hidden, nothing to do */
213 if (ui.library->cwin == NULL) return;
214
215 /* remove library window */
216 delwin(ui.library->cwin);
217 ui.library->cwin = NULL;
218
219 /* resize & move playlist window */
220 getmaxyx(stdscr, h, w);
221 swindow_resize(ui.playlist, h - 3, w, 2, 0);
222 }
223
224 void
ui_unhide_library()225 ui_unhide_library()
226 {
227 int w, h;
228
229 /* if not hidden, nothing to do */
230 if (ui.library->cwin != NULL) return;
231
232 getmaxyx(stdscr, h, w);
233
234 /* create library window */
235 ui.library->cwin = newwin(h - 3, ui.lwidth, 2, 0);
236 if (ui.library->cwin == NULL)
237 errx(1, "ui_unhide_library: failed to create newwin");
238
239 /* resize & move playlist window */
240 swindow_resize(ui.playlist, h - 3, w - ui.lwidth - 1, 2, ui.lwidth + 1);
241 }
242
243 void
ui_clear()244 ui_clear()
245 {
246 wclear(ui.player);
247 wclear(ui.command);
248 wclear(ui.library->cwin);
249 wclear(ui.playlist->cwin);
250 clear();
251
252 wrefresh(ui.player);
253 wrefresh(ui.command);
254 wrefresh(ui.library->cwin);
255 wrefresh(ui.playlist->cwin);
256 refresh(); /* XXX needed? */
257 }
258