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