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