diskeditor.c revision 237253
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: head/usr.sbin/bsdinstall/partedit/diskeditor.c 237253 2012-06-19 06:09:47Z eadler $
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
37static void
38print_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
61int
62diskeditor_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 = 0, 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	/*
98	 * Set up editor window.
99	 */
100	prompt = dlg_strclone(cprompt);
101
102	min_width = 50;
103	height = width = 0;
104	partlist_height = 10;
105	dlg_tab_correct_str(prompt);
106	dlg_button_layout(buttons, &min_width);
107	dlg_auto_size(title, prompt, &height, &width, 2, min_width);
108	height += partlist_height;
109	partlist_width = width - 2*MARGIN;
110	dlg_print_size(height, width);
111	dlg_ctl_size(height, width);
112
113	x = dlg_box_x_ordinate(width);
114	y = dlg_box_y_ordinate(height);
115
116	dialog = dlg_new_window(height, width, y, x);
117	dlg_register_window(dialog, "diskeditorbox", binding);
118	dlg_register_buttons(dialog, "diskeditorbox", buttons);
119
120	dlg_draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
121	dlg_draw_bottom_box(dialog);
122	dlg_draw_title(dialog, title);
123	wattrset(dialog, dialog_attr);
124
125	/* Partition list sub-window */
126	partitions = dlg_sub_window(dialog, partlist_height, partlist_width,
127	    y + 3, x + 1);
128	dlg_register_window(partitions, "partlist", binding);
129	dlg_register_buttons(partitions, "partlist", buttons);
130	wattrset(partitions, menubox_attr);
131
132	dlg_item_help(help_text[cur_button]);
133	dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
134	    cur_button, FALSE, width);
135	dlg_print_autowrap(dialog, prompt, height, width);
136
137	if (selected != NULL)
138		cur_part = *selected;
139	if (nscroll != NULL)
140		cur_scroll = *nscroll;
141	if (cur_part - cur_scroll >= partlist_height - 2 ||
142	    cur_part - cur_scroll < 0)
143		cur_scroll = cur_part;
144
145repaint:
146	dlg_draw_box(dialog, 3, 1,  partlist_height, partlist_width,
147	    menubox_border_attr, menubox_attr);
148	for (i = cur_scroll; i < MIN(cur_scroll + partlist_height - 2, nitems);
149	    i++)
150		print_partedit_item(partitions, items, i, cur_scroll,
151		    i == cur_part);
152	if (nitems > partlist_height - 2)
153		dlg_draw_arrows(partitions, cur_scroll > 0,
154		    nitems > cur_scroll + partlist_height - 2,
155		    partlist_width - 5, 0, partlist_height - 1);
156	wrefresh(partitions);
157
158	while (result == DLG_EXIT_UNKNOWN) {
159		key = dlg_mouse_wgetch(dialog, &fkey);
160		if ((i = dlg_char_to_button(key, buttons)) >= 0) {
161			cur_button = i;
162			dlg_item_help(help_text[cur_button]);
163			dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
164			    cur_button, FALSE, width);
165			break;
166		}
167
168		if (!fkey)
169			continue;
170
171		switch (key) {
172		case DLGK_FIELD_NEXT:
173			cur_button = dlg_next_button(buttons, cur_button);
174			if (cur_button < 0)
175				cur_button = 0;
176			dlg_item_help(help_text[cur_button]);
177			dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
178			    cur_button, FALSE, width);
179			break;
180		case DLGK_FIELD_PREV:
181			cur_button = dlg_prev_button(buttons, cur_button);
182			if (cur_button < 0)
183				cur_button = 0;
184			dlg_item_help(help_text[cur_button]);
185			dlg_draw_buttons(dialog, height - 2*MARGIN, 0, buttons,
186			    cur_button, FALSE, width);
187			break;
188		case DLGK_ITEM_NEXT:
189			if (cur_part == nitems - 1)
190				break; /* End of list */
191
192			/* Deselect old item */
193			print_partedit_item(partitions, items, cur_part,
194			    cur_scroll, 0);
195			/* Select new item */
196			cur_part++;
197			if (cur_part - cur_scroll >= partlist_height - 2) {
198				cur_scroll = cur_part;
199				goto repaint;
200			}
201			print_partedit_item(partitions, items, cur_part,
202			    cur_scroll, 1);
203			wrefresh(partitions);
204			break;
205		case DLGK_ITEM_PREV:
206			if (cur_part == 0)
207				break; /* Start of list */
208
209			/* Deselect old item */
210			print_partedit_item(partitions, items, cur_part,
211			    cur_scroll, 0);
212			/* Select new item */
213			cur_part--;
214			if (cur_part - cur_scroll < 0) {
215				cur_scroll = cur_part;
216				goto repaint;
217			}
218			print_partedit_item(partitions, items, cur_part,
219			    cur_scroll, 1);
220			wrefresh(partitions);
221			break;
222		case DLGK_PAGE_NEXT:
223			cur_scroll += (partlist_height - 2);
224			if (cur_scroll + partlist_height - 2 >= nitems)
225				cur_scroll = nitems - (partlist_height - 2);
226			if (cur_scroll < 0)
227				cur_scroll = 0;
228			if (cur_part < cur_scroll)
229				cur_part = cur_scroll;
230			goto repaint;
231		case DLGK_PAGE_PREV:
232			cur_scroll -= (partlist_height - 2);
233			if (cur_scroll < 0)
234				cur_scroll = 0;
235			if (cur_part >= cur_scroll + partlist_height - 2)
236				cur_part = cur_scroll;
237			goto repaint;
238		case DLGK_PAGE_FIRST:
239			cur_scroll = 0;
240			cur_part = cur_scroll;
241			goto repaint;
242		case DLGK_PAGE_LAST:
243			cur_scroll = nitems - (partlist_height - 2);
244			if (cur_scroll < 0)
245				cur_scroll = 0;
246			cur_part = cur_scroll;
247			goto repaint;
248		case DLGK_ENTER:
249			goto done;
250		default:
251			if (is_DLGK_MOUSE(key)) {
252				cur_button = key - M_EVENT;
253				dlg_item_help(help_text[cur_button]);
254				dlg_draw_buttons(dialog, height - 2*MARGIN, 0,
255				    buttons, cur_button, FALSE, width);
256				goto done;
257			}
258			break;
259		}
260	}
261
262done:
263	if (selected != NULL)
264		*selected = cur_part;
265	if (nscroll != NULL)
266		*nscroll = cur_scroll;
267
268	dlg_del_window(partitions);
269	dlg_del_window(dialog);
270	dlg_mouse_free_regions();
271
272	return (cur_button);
273}
274
275