xref: /NextBSD/usr.sbin/bsdinstall/partedit/diskeditor.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
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
print_partedit_item(WINDOW * partitions,struct partedit_item * items,int item,int nscroll,int selected)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, 10, &attr);
48 	wmove(partitions, y, 17);
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
diskeditor_show(const char * title,const char * cprompt,struct partedit_item * items,int nitems,int * selected,int * nscroll)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", "Finish", NULL };
69 	const char *help_text[] = {
70 	    "Add a new partition", "Delete selected partition or partitions",
71 	    "Change partition type or mountpoint",
72 	    "Revert changes to disk setup", "Use guided partitioning tool",
73 	    "Exit partitioner (will ask whether to save changes)", NULL };
74 	int x, y;
75 	int i;
76 	int height, width, min_width;
77 	int partlist_height, partlist_width;
78 	int cur_scroll = 0;
79 	int key, fkey;
80 	int cur_button = 5, cur_part = 0;
81 	int result = DLG_EXIT_UNKNOWN;
82 
83 	static DLG_KEYS_BINDING binding[] = {
84 		ENTERKEY_BINDINGS,
85 		DLG_KEYS_DATA( DLGK_ENTER,      ' ' ),
86 		DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ),
87 		DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ),
88 		DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ),
89 		DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
90 		DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
91 		DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ),
92 
93 		SCROLLKEY_BINDINGS,
94 		END_KEYS_BINDING
95 	};
96 
97 	static DLG_KEYS_BINDING binding2[] = {
98 		INPUTSTR_BINDINGS,
99 		ENTERKEY_BINDINGS,
100 		DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
101 		DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
102 		DLG_KEYS_DATA( DLGK_ITEM_NEXT,  CHR_NEXT ),
103 		DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_DOWN ),
104 		DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_NEXT ),
105 		DLG_KEYS_DATA( DLGK_ITEM_PREV,  CHR_PREVIOUS ),
106 		DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_PREVIOUS ),
107 		DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_UP ),
108 		DLG_KEYS_DATA( DLGK_PAGE_NEXT,  KEY_NPAGE ),
109 		DLG_KEYS_DATA( DLGK_PAGE_PREV,  KEY_PPAGE ),
110 		END_KEYS_BINDING
111 	};
112 
113 	/*
114 	 * Set up editor window.
115 	 */
116 	prompt = dlg_strclone(cprompt);
117 
118 	min_width = 50;
119 	height = width = 0;
120 	partlist_height = 10;
121 	dlg_tab_correct_str(prompt);
122 	dlg_button_layout(buttons, &min_width);
123 	dlg_auto_size(title, prompt, &height, &width, 2, min_width);
124 	height += partlist_height;
125 	partlist_width = width - 2*MARGIN;
126 	dlg_print_size(height, width);
127 	dlg_ctl_size(height, width);
128 
129 	x = dlg_box_x_ordinate(width);
130 	y = dlg_box_y_ordinate(height);
131 
132 	dialog = dlg_new_window(height, width, y, x);
133 	dlg_register_window(dialog, "diskeditorbox", binding);
134 	dlg_register_buttons(dialog, "diskeditorbox", buttons);
135 
136 	dlg_draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
137 	dlg_draw_bottom_box(dialog);
138 	dlg_draw_title(dialog, title);
139 	wattrset(dialog, dialog_attr);
140 
141 	/* Partition list sub-window */
142 	partitions = dlg_sub_window(dialog, partlist_height, partlist_width,
143 	    y + 3, x + 1);
144 	dlg_register_window(partitions, "partlist", binding2);
145 	dlg_register_buttons(partitions, "partlist", buttons);
146 	wattrset(partitions, menubox_attr);
147 
148 	dlg_item_help(help_text[cur_button]);
149 	dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
150 	    cur_button, FALSE, width);
151 	dlg_print_autowrap(dialog, prompt, height, width);
152 
153 	if (selected != NULL)
154 		cur_part = *selected;
155 	if (nscroll != NULL)
156 		cur_scroll = *nscroll;
157 	if (cur_part - cur_scroll >= partlist_height - 2 ||
158 	    cur_part - cur_scroll < 0)
159 		cur_scroll = cur_part;
160 
161 repaint:
162 	dlg_draw_box(dialog, 3, 1,  partlist_height, partlist_width,
163 	    menubox_border_attr, menubox_attr);
164 	for (i = cur_scroll; i < MIN(cur_scroll + partlist_height - 2, nitems);
165 	    i++)
166 		print_partedit_item(partitions, items, i, cur_scroll,
167 		    i == cur_part);
168 	if (nitems > partlist_height - 2)
169 		dlg_draw_arrows(partitions, cur_scroll > 0,
170 		    nitems > cur_scroll + partlist_height - 2,
171 		    partlist_width - 5, 0, partlist_height - 1);
172 	wrefresh(partitions);
173 
174 	while (result == DLG_EXIT_UNKNOWN) {
175 		key = dlg_mouse_wgetch(dialog, &fkey);
176 		if ((i = dlg_char_to_button(key, buttons)) >= 0) {
177 			cur_button = i;
178 			dlg_item_help(help_text[cur_button]);
179 			dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
180 			    cur_button, FALSE, width);
181 			break;
182 		}
183 
184 		if (!fkey)
185 			continue;
186 
187 		switch (key) {
188 		case DLGK_FIELD_NEXT:
189 			cur_button = dlg_next_button(buttons, cur_button);
190 			if (cur_button < 0)
191 				cur_button = 0;
192 			dlg_item_help(help_text[cur_button]);
193 			dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
194 			    cur_button, FALSE, width);
195 			break;
196 		case DLGK_FIELD_PREV:
197 			cur_button = dlg_prev_button(buttons, cur_button);
198 			if (cur_button < 0)
199 				cur_button = 0;
200 			dlg_item_help(help_text[cur_button]);
201 			dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
202 			    cur_button, FALSE, width);
203 			break;
204 		case DLGK_ITEM_NEXT:
205 			if (cur_part == nitems - 1)
206 				break; /* End of list */
207 
208 			/* Deselect old item */
209 			print_partedit_item(partitions, items, cur_part,
210 			    cur_scroll, 0);
211 			/* Select new item */
212 			cur_part++;
213 			if (cur_part - cur_scroll >= partlist_height - 2) {
214 				cur_scroll = cur_part;
215 				goto repaint;
216 			}
217 			print_partedit_item(partitions, items, cur_part,
218 			    cur_scroll, 1);
219 			wrefresh(partitions);
220 			break;
221 		case DLGK_ITEM_PREV:
222 			if (cur_part == 0)
223 				break; /* Start of list */
224 
225 			/* Deselect old item */
226 			print_partedit_item(partitions, items, cur_part,
227 			    cur_scroll, 0);
228 			/* Select new item */
229 			cur_part--;
230 			if (cur_part - cur_scroll < 0) {
231 				cur_scroll = cur_part;
232 				goto repaint;
233 			}
234 			print_partedit_item(partitions, items, cur_part,
235 			    cur_scroll, 1);
236 			wrefresh(partitions);
237 			break;
238 		case DLGK_PAGE_NEXT:
239 			cur_scroll += (partlist_height - 2);
240 			if (cur_scroll + partlist_height - 2 >= nitems)
241 				cur_scroll = nitems - (partlist_height - 2);
242 			if (cur_scroll < 0)
243 				cur_scroll = 0;
244 			if (cur_part < cur_scroll)
245 				cur_part = cur_scroll;
246 			goto repaint;
247 		case DLGK_PAGE_PREV:
248 			cur_scroll -= (partlist_height - 2);
249 			if (cur_scroll < 0)
250 				cur_scroll = 0;
251 			if (cur_part >= cur_scroll + partlist_height - 2)
252 				cur_part = cur_scroll;
253 			goto repaint;
254 		case DLGK_PAGE_FIRST:
255 			cur_scroll = 0;
256 			cur_part = cur_scroll;
257 			goto repaint;
258 		case DLGK_PAGE_LAST:
259 			cur_scroll = nitems - (partlist_height - 2);
260 			if (cur_scroll < 0)
261 				cur_scroll = 0;
262 			cur_part = cur_scroll;
263 			goto repaint;
264 		case DLGK_ENTER:
265 			goto done;
266 		default:
267 			if (is_DLGK_MOUSE(key)) {
268 				cur_button = key - M_EVENT;
269 				dlg_item_help(help_text[cur_button]);
270 				dlg_draw_buttons(dialog, height - 2*MARGIN, 0,
271 				    buttons, cur_button, FALSE, width);
272 				goto done;
273 			}
274 			break;
275 		}
276 	}
277 
278 done:
279 	if (selected != NULL)
280 		*selected = cur_part;
281 	if (nscroll != NULL)
282 		*nscroll = cur_scroll;
283 
284 	dlg_del_window(partitions);
285 	dlg_del_window(dialog);
286 	dlg_mouse_free_regions();
287 
288 	return (cur_button);
289 }
290 
291