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
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 = 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
161repaint:
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
278done:
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