1/*
2 * Copyright 2008-2011, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Pfeiffer <laplace@users.sourceforge.net>
7 */
8
9
10#include "DefaultPartitionPage.h"
11
12
13#include <Catalog.h>
14#include <ControlLook.h>
15#include <Locale.h>
16#include <Message.h>
17#include <MenuItem.h>
18#include <MenuField.h>
19#include <PopUpMenu.h>
20#include <RadioButton.h>
21#include <Slider.h>
22#include <string.h>
23#include <String.h>
24#include <TextView.h>
25
26
27#undef B_TRANSLATION_CONTEXT
28#define B_TRANSLATION_CONTEXT "DefaultPartitionPage"
29
30
31enum {
32	kMsgPartition = 'part',
33	kMsgTimeout = 'time'
34};
35
36
37// The timeout code to wait indefinitely
38// Note: The timeout is encoded in seconds, -1 indicates to wait indefinitely
39const int32 kTimeoutIndefinitely = -1;
40const int32 kDefaultTimeout = kTimeoutIndefinitely;
41
42struct TimeoutOption {
43	int32 timeout;
44	const char* label;
45};
46
47static const TimeoutOption gTimeoutOptions[] = {
48	{ 0, B_TRANSLATE_MARK("Immediately")},
49	{ 1, B_TRANSLATE_MARK("After one second")},
50	{ 2, B_TRANSLATE_MARK("After two seconds")},
51	{ 3, B_TRANSLATE_MARK("After three seconds")},
52	{ 4, B_TRANSLATE_MARK("After four seconds")},
53	{ 5, B_TRANSLATE_MARK("After five seconds")},
54	{ 60, B_TRANSLATE_MARK("After one minute")},
55	{ kTimeoutIndefinitely, B_TRANSLATE_MARK("Never")}
56};
57
58
59#define kNumberOfTimeoutOptions \
60	(int32)(sizeof(gTimeoutOptions) / sizeof(TimeoutOption))
61
62
63static int32
64get_index_for_timeout(int32 timeout)
65{
66	int32 defaultIndex = 0;
67	for (int32 i = 0; i < kNumberOfTimeoutOptions; i ++) {
68		if (gTimeoutOptions[i].timeout == timeout)
69			return i;
70
71		if (gTimeoutOptions[i].timeout == kDefaultTimeout)
72			defaultIndex = i;
73	}
74	return defaultIndex;
75}
76
77
78static int32
79get_timeout_for_index(int32 index)
80{
81	if (index < 0)
82		return gTimeoutOptions[0].timeout;
83	if (index >= kNumberOfTimeoutOptions)
84		return gTimeoutOptions[kNumberOfTimeoutOptions-1].timeout;
85	return gTimeoutOptions[index].timeout;
86}
87
88
89const char*
90get_label_for_timeout(int32 timeout)
91{
92	int32 index = get_index_for_timeout(timeout);
93	return gTimeoutOptions[index].label;
94}
95
96
97// #pragma mark -
98
99
100DefaultPartitionPage::DefaultPartitionPage(BMessage* settings, BRect frame,
101	const char* name)
102	:
103	WizardPageView(settings, frame, name, B_FOLLOW_ALL,
104		B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE)
105{
106	_BuildUI();
107}
108
109
110DefaultPartitionPage::~DefaultPartitionPage()
111{
112}
113
114
115void
116DefaultPartitionPage::FrameResized(float width, float height)
117{
118	WizardPageView::FrameResized(width, height);
119	_Layout();
120}
121
122
123void
124DefaultPartitionPage::AttachedToWindow()
125{
126	fDefaultPartition->Menu()->SetTargetForItems(this);
127	fTimeoutSlider->SetTarget(this);
128}
129
130
131void
132DefaultPartitionPage::MessageReceived(BMessage* msg)
133{
134	switch (msg->what) {
135		case kMsgPartition:
136		{
137			int32 index;
138			msg->FindInt32("index", &index);
139			fSettings->ReplaceInt32("defaultPartition", index);
140			break;
141		}
142		case kMsgTimeout:
143		{
144			int32 sliderValue = fTimeoutSlider->Value();
145			int32 timeout = get_timeout_for_index(sliderValue);
146			fSettings->ReplaceInt32("timeout", timeout);
147
148			BString label;
149			_GetTimeoutLabel(timeout, label);
150			fTimeoutSlider->SetLabel(label.String());
151			break;
152		}
153
154		default:
155			WizardPageView::MessageReceived(msg);
156	}
157}
158
159
160void
161DefaultPartitionPage::_BuildUI()
162{
163	const float kTextDistance = be_control_look->DefaultItemSpacing();
164	BRect rect(Bounds());
165
166	BString text;
167	text << B_TRANSLATE_COMMENT("Default Partition", "Title") << "\n"
168		<< B_TRANSLATE("Please specify a default partition and a timeout.\n"
169			"The boot menu will load the default partition after "
170			"the timeout unless you select another partition. You "
171			"can also have the boot menu wait indefinitely for you "
172			"to select a partition.\n"
173			"Keep the 'ALT' key pressed to disable the timeout at boot time.");
174
175	fDescription = CreateDescription(rect, "description", text);
176	MakeHeading(fDescription);
177	AddChild(fDescription);
178	LayoutDescriptionVertically(fDescription);
179	rect.top = fDescription->Frame().bottom + kTextDistance;
180
181	BPopUpMenu* popUpMenu = _CreatePopUpMenu();
182	fDefaultPartition = new BMenuField(rect, "partitions",
183		B_TRANSLATE_COMMENT("Default Partition:", "Menu field label"),
184		popUpMenu);
185	float divider = be_plain_font->StringWidth(fDefaultPartition->Label()) + 3;
186	fDefaultPartition->SetDivider(divider);
187	AddChild(fDefaultPartition);
188	fDefaultPartition->ResizeToPreferred();
189
190	// timeout slider
191	rect.top = fDefaultPartition->Frame().bottom + kTextDistance;
192	int32 timeout;
193	fSettings->FindInt32("timeout", &timeout);
194	BString timeoutLabel;
195	_GetTimeoutLabel(timeout, timeoutLabel);
196
197	int32 sliderValue = get_index_for_timeout(timeout);
198
199	fTimeoutSlider = new BSlider(rect, "timeout", timeoutLabel.String(),
200		new BMessage(kMsgTimeout), 0, kNumberOfTimeoutOptions-1,
201		B_BLOCK_THUMB,
202		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
203	fTimeoutSlider->SetModificationMessage(new BMessage(kMsgTimeout));
204	fTimeoutSlider->SetValue(sliderValue);
205	fTimeoutSlider->SetLimitLabels(B_TRANSLATE("Immediately"),
206		B_TRANSLATE("Never"));
207	fTimeoutSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
208	fTimeoutSlider->SetHashMarkCount(kNumberOfTimeoutOptions);
209	fTimeoutSlider->ResizeToPreferred();
210	AddChild(fTimeoutSlider);
211
212	_Layout();
213}
214
215
216BPopUpMenu*
217DefaultPartitionPage::_CreatePopUpMenu()
218{
219	int32 defaultPartitionIndex;
220	fSettings->FindInt32("defaultPartition", &defaultPartitionIndex);
221
222	BMenuItem* selectedItem = NULL;
223	int32 selectedItemIndex = 0;
224
225	BPopUpMenu* menu = new BPopUpMenu(B_TRANSLATE_COMMENT("Partitions",
226		"Pop up menu title"));
227	BMessage message;
228	for (int32 i = 0; fSettings->FindMessage("partition", i, &message) == B_OK;
229			i++) {
230		bool show;
231		if (message.FindBool("show", &show) != B_OK || !show)
232			continue;
233
234		BString name;
235		message.FindString("name", &name);
236
237		BMessage* msg = new BMessage(kMsgPartition);
238		msg->AddInt32("index", i);
239		BMenuItem* item = new BMenuItem(name.String(), msg);
240		menu->AddItem(item);
241		if (defaultPartitionIndex == i || selectedItem == NULL) {
242			selectedItem = item;
243			selectedItemIndex = i;
244		}
245	}
246	fSettings->ReplaceInt32("defaultPartition", selectedItemIndex);
247	selectedItem->SetMarked(true);
248	return menu;
249}
250
251
252void
253DefaultPartitionPage::_GetTimeoutLabel(int32 timeout, BString& label)
254{
255	const char* text = B_TRANSLATE_NOCOLLECT(get_label_for_timeout(timeout));
256	label = B_TRANSLATE("Timeout: %s");
257	label.ReplaceFirst("%s", text);
258}
259
260
261void
262DefaultPartitionPage::_Layout()
263{
264	LayoutDescriptionVertically(fDescription);
265
266	const float kTextDistance = be_control_look->DefaultItemSpacing();
267	float left = fDefaultPartition->Frame().left;
268	float top = fDescription->Frame().bottom + kTextDistance;
269
270	fDefaultPartition->MoveTo(left, top);
271	top = fDefaultPartition->Frame().bottom + kTextDistance;
272
273	fTimeoutSlider->MoveTo(left, top);
274}
275