1 /*-
2  * Copyright (c) 2011 Nathan Whitehorn
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <libutil.h>
32 #include <dialog.h>
33 #include <dlg_keys.h>
34 
35 #include "diskeditor.h"
36 
37 static void
38 print_partedit_item(WINDOW *partitions, struct partedit_item *items,
39     int item, int nscroll, int selected)
40 {
41 	chtype attr = A_NORMAL;
42 	char sizetext[16];
43 	int y = item - nscroll + 1;
44 
45 	wattrset(partitions, selected ? item_selected_attr : item_attr);
46 	wmove(partitions, y, MARGIN + items[item].indentation*2);
47 	dlg_print_text(partitions, items[item].name, 8, &attr);
48 	wmove(partitions, y, 15);
49 	wattrset(partitions, item_attr);
50 
51 	humanize_number(sizetext, 7, items[item].size, "B", HN_AUTOSCALE,
52 	    HN_DECIMAL);
53 	dlg_print_text(partitions, sizetext, 8, &attr);
54 	wmove(partitions, y, 25);
55 	dlg_print_text(partitions, items[item].type, 15, &attr);
56 	wmove(partitions, y, 40);
57 	if (items[item].mountpoint != NULL)
58 		dlg_print_text(partitions, items[item].mountpoint, 8, &attr);
59 }
60 
61 int
62 diskeditor_show(const char *title, const char *cprompt,
63     struct partedit_item *items, int nitems, int *selected, int *nscroll)
64 {
65 	WINDOW *dialog, *partitions;
66 	char *prompt;
67 	const char *buttons[] =
68 	    { "Create", "Delete", "Modify", "Revert", "Auto", "Exit", NULL };
69 	int x, y;
70 	int i;
71 	int height, width, min_width;
72 	int partlist_height, partlist_width, min_partlist_width;
73 	int cur_scroll = 0;
74 	int key, fkey;
75 	int cur_button = 0, cur_part = 0;
76 	int result = DLG_EXIT_UNKNOWN;
77 
78 	static DLG_KEYS_BINDING binding[] = {
79 		ENTERKEY_BINDINGS,
80 		DLG_KEYS_DATA( DLGK_ENTER,      ' ' ),
81 		DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ),
82 		DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ),
83 		DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ),
84 		DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
85 		DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
86 		DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ),
87 
88 		SCROLLKEY_BINDINGS,
89 		END_KEYS_BINDING
90 	};
91 
92 	/*
93 	 * Set up editor window.
94 	 */
95 	prompt = dlg_strclone(cprompt);
96 
97 	min_width = 50;
98 	height = width = 0;
99 	partlist_height = 10;
100 	min_partlist_width = 0;
101 	dlg_tab_correct_str(prompt);
102 	dlg_button_layout(buttons, &min_width);
103 	dlg_auto_size(title, prompt, &height, &width, 2, min_width);
104 	height += partlist_height;
105 	partlist_width = width - 2*MARGIN;
106 	dlg_print_size(height, width);
107 	dlg_ctl_size(height, width);
108 
109 	x = dlg_box_x_ordinate(width);
110 	y = dlg_box_y_ordinate(height);
111 
112 	dialog = dlg_new_window(height, width, y, x);
113 	dlg_register_window(dialog, "diskeditorbox", binding);
114 	dlg_register_buttons(dialog, "diskeditorbox", buttons);
115 
116 	dlg_draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
117 	dlg_draw_bottom_box(dialog);
118 	dlg_draw_title(dialog, title);
119 	wattrset(dialog, dialog_attr);
120 
121 	/* Partition list sub-window */
122 	partitions = dlg_sub_window(dialog, partlist_height, partlist_width,
123 	    y + 3, x + 1);
124 	dlg_register_window(partitions, "partlist", binding);
125 	dlg_register_buttons(partitions, "partlist", buttons);
126 	wattrset(partitions, menubox_attr);
127 
128 	dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
129 	    cur_button, FALSE, width);
130 	dlg_print_autowrap(dialog, prompt, height, width);
131 
132 	if (selected != NULL)
133 		cur_part = *selected;
134 	if (nscroll != NULL)
135 		cur_scroll = *nscroll;
136 	if (cur_part - cur_scroll >= partlist_height - 2 ||
137 	    cur_part - cur_scroll < 0)
138 		cur_scroll = cur_part;
139 
140 repaint:
141 	dlg_draw_box(dialog, 3, 1,  partlist_height, partlist_width,
142 	    menubox_border_attr, menubox_attr);
143 	for (i = cur_scroll; i < MIN(cur_scroll + partlist_height - 2, nitems);
144 	    i++)
145 		print_partedit_item(partitions, items, i, cur_scroll,
146 		    i == cur_part);
147 	if (nitems > partlist_height - 2)
148 		dlg_draw_arrows(partitions, cur_scroll > 0,
149 		    nitems > cur_scroll + partlist_height - 2,
150 		    partlist_width - 5, 0, partlist_height - 1);
151 	wrefresh(partitions);
152 
153 	while (result == DLG_EXIT_UNKNOWN) {
154 		key = dlg_mouse_wgetch(dialog, &fkey);
155 		if ((i = dlg_char_to_button(key, buttons)) >= 0) {
156 			cur_button = i;
157 			dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
158 			    cur_button, FALSE, width);
159 			break;
160 		}
161 
162 		if (!fkey)
163 			continue;
164 
165 		switch (key) {
166 		case DLGK_FIELD_NEXT:
167 			cur_button = dlg_next_button(buttons, cur_button);
168 			if (cur_button < 0)
169 				cur_button = 0;
170 			dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
171 			    cur_button, FALSE, width);
172 			break;
173 		case DLGK_FIELD_PREV:
174 			cur_button = dlg_prev_button(buttons, cur_button);
175 			if (cur_button < 0)
176 				cur_button = 0;
177 			dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
178 			    cur_button, FALSE, width);
179 			break;
180 		case DLGK_ITEM_NEXT:
181 			if (cur_part == nitems - 1)
182 				break; /* End of list */
183 
184 			/* Deselect old item */
185 			print_partedit_item(partitions, items, cur_part,
186 			    cur_scroll, 0);
187 			/* Select new item */
188 			cur_part++;
189 			if (cur_part - cur_scroll >= partlist_height - 2) {
190 				cur_scroll = cur_part;
191 				goto repaint;
192 			}
193 			print_partedit_item(partitions, items, cur_part,
194 			    cur_scroll, 1);
195 			wrefresh(partitions);
196 			break;
197 		case DLGK_ITEM_PREV:
198 			if (cur_part == 0)
199 				break; /* Start of list */
200 
201 			/* Deselect old item */
202 			print_partedit_item(partitions, items, cur_part,
203 			    cur_scroll, 0);
204 			/* Select new item */
205 			cur_part--;
206 			if (cur_part - cur_scroll < 0) {
207 				cur_scroll = cur_part;
208 				goto repaint;
209 			}
210 			print_partedit_item(partitions, items, cur_part,
211 			    cur_scroll, 1);
212 			wrefresh(partitions);
213 			break;
214 		case DLGK_PAGE_NEXT:
215 			cur_scroll += (partlist_height - 2);
216 			if (cur_scroll + partlist_height - 2 >= nitems)
217 				cur_scroll = nitems - (partlist_height - 2);
218 			if (cur_part < cur_scroll)
219 				cur_part = cur_scroll;
220 			goto repaint;
221 		case DLGK_PAGE_PREV:
222 			cur_scroll -= (partlist_height - 2);
223 			if (cur_scroll < 0)
224 				cur_scroll = 0;
225 			if (cur_part >= cur_scroll + partlist_height - 2)
226 				cur_part = cur_scroll;
227 			goto repaint;
228 		case DLGK_PAGE_FIRST:
229 			cur_scroll = 0;
230 			cur_part = cur_scroll;
231 			goto repaint;
232 		case DLGK_PAGE_LAST:
233 			cur_scroll = nitems - (partlist_height - 2);
234 			cur_part = cur_scroll;
235 			goto repaint;
236 		case DLGK_ENTER:
237 			goto done;
238 		default:
239 			if (is_DLGK_MOUSE(key)) {
240 				cur_button = key - M_EVENT;
241 				dlg_draw_buttons(dialog, height - 2*MARGIN, 0,
242 				    buttons, cur_button, FALSE, width);
243 				goto done;
244 			}
245 			break;
246 		}
247 	}
248 
249 done:
250 	if (selected != NULL)
251 		*selected = cur_part;
252 	if (nscroll != NULL)
253 		*nscroll = cur_scroll;
254 
255 	dlg_del_window(partitions);
256 	dlg_del_window(dialog);
257 	dlg_mouse_free_regions();
258 
259 	return (cur_button);
260 }
261 
262