xref: /haiku/src/preferences/input/SettingsView.cpp (revision 68d37cfb3a755a7270d772b505ee15c8b18aa5e0)
1 /*
2  * Copyright 2019, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Author:
6  *		Preetpal Kaur <preetpalok123@gmail.com>
7  */
8 
9 
10 #include "InputMouse.h"
11 
12 #include <Bitmap.h>
13 #include <Box.h>
14 #include <Button.h>
15 #include <Catalog.h>
16 #include <ControlLook.h>
17 #include <Debug.h>
18 #include <InterfaceDefs.h>
19 #include <LayoutBuilder.h>
20 #include <Locale.h>
21 #include <MenuField.h>
22 #include <MenuItem.h>
23 #include <PopUpMenu.h>
24 #include <SeparatorView.h>
25 #include <Slider.h>
26 #include <TextControl.h>
27 #include <TranslationUtils.h>
28 #include <Window.h>
29 
30 #include "InputConstants.h"
31 #include "MouseSettings.h"
32 #include "MouseView.h"
33 
34 
35 static int32
36 mouse_mode_to_index(mode_mouse mode)
37 {
38 	switch (mode) {
39 		case B_NORMAL_MOUSE:
40 		default:
41 			return 0;
42 		case B_CLICK_TO_FOCUS_MOUSE:
43 			return 1;
44 		case B_FOCUS_FOLLOWS_MOUSE:
45 			return 2;
46 	}
47 }
48 
49 
50 static int32
51 focus_follows_mouse_mode_to_index(mode_focus_follows_mouse mode)
52 {
53 	switch (mode) {
54 		case B_NORMAL_FOCUS_FOLLOWS_MOUSE:
55 		default:
56 			return 0;
57 		case B_WARP_FOCUS_FOLLOWS_MOUSE:
58 			return 1;
59 		case B_INSTANT_WARP_FOCUS_FOLLOWS_MOUSE:
60 			return 2;
61 	}
62 }
63 
64 
65 //	#pragma mark -
66 
67 #undef B_TRANSLATION_CONTEXT
68 #define B_TRANSLATION_CONTEXT "SettingsView"
69 
70 SettingsView::SettingsView(MouseSettings& settings)
71 	: BBox("main_view"),
72 	fSettings(settings)
73 {
74 	if (fSettings.MouseType() > 6)
75 		debugger("Mouse type is invalid");
76 
77 	// Add the "Mouse Type" pop up menu
78 	fTypeMenu = new BOptionPopUp("type", B_TRANSLATE("Mouse type:"),
79 		new BMessage(kMsgMouseType));
80 	fTypeMenu->AddOption(B_TRANSLATE("1-Button"), 1);
81 	fTypeMenu->AddOption(B_TRANSLATE("2-Button"), 2);
82 	fTypeMenu->AddOption(B_TRANSLATE("3-Button"), 3);
83 	fTypeMenu->AddOption(B_TRANSLATE("4-Button"), 4);
84 	fTypeMenu->AddOption(B_TRANSLATE("5-Button"), 5);
85 	fTypeMenu->AddOption(B_TRANSLATE("6-Button"), 6);
86 
87 	// Create the "Double-click speed slider...
88 	fClickSpeedSlider = new BSlider("double_click_speed",
89 		B_TRANSLATE("Double-click speed"), new BMessage(kMsgDoubleClickSpeed),
90 		0, 1000, B_HORIZONTAL);
91 	fClickSpeedSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
92 	fClickSpeedSlider->SetHashMarkCount(7);
93 
94 	// Create the "Mouse Speed" slider...
95 	fMouseSpeedSlider = new BSlider("mouse_speed", B_TRANSLATE("Mouse speed"),
96 		new BMessage(kMsgMouseSpeed), 0, 1000, B_HORIZONTAL);
97 	fMouseSpeedSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
98 	fMouseSpeedSlider->SetHashMarkCount(7);
99 
100 	// Create the "Mouse Acceleration" slider...
101 	fAccelerationSlider = new BSlider("mouse_acceleration",
102 		B_TRANSLATE("Mouse acceleration"),
103 		new BMessage(kMsgAccelerationFactor), 0, 1000, B_HORIZONTAL);
104 	fAccelerationSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
105 	fAccelerationSlider->SetHashMarkCount(7);
106 
107 	fMouseView = new MouseView(fSettings);
108 
109 	// Create the "Double-click test area" text box...
110 	const char* label = B_TRANSLATE("Double-click test area");
111 	BTextControl* doubleClickTextControl = new BTextControl(NULL,
112 		label, NULL);
113 	doubleClickTextControl->SetAlignment(B_ALIGN_LEFT, B_ALIGN_CENTER);
114 	doubleClickTextControl->SetExplicitMinSize(
115 		BSize(StringWidth(label), B_SIZE_UNSET));
116 
117 	// Add the "Mouse focus mode" pop up menu
118 	fFocusMenu = new BPopUpMenu(B_TRANSLATE("Click to focus and raise"));
119 
120 	const char *focusLabels[] = {B_TRANSLATE_MARK("Click to focus and raise"),
121 		B_TRANSLATE_MARK("Click to focus"),
122 		B_TRANSLATE_MARK("Focus follows mouse")};
123 	const mode_mouse focusModes[] = {B_NORMAL_MOUSE, B_CLICK_TO_FOCUS_MOUSE,
124 										B_FOCUS_FOLLOWS_MOUSE};
125 
126 	for (int i = 0; i < 3; i++) {
127 		BMessage* message = new BMessage(kMsgMouseFocusMode);
128 		message->AddInt32("mode", focusModes[i]);
129 
130 		fFocusMenu->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(focusLabels[i]),
131 			message));
132 	}
133 
134 	BMenuField* focusField = new BMenuField(B_TRANSLATE("Focus mode:"),
135 		fFocusMenu);
136 	focusField->SetAlignment(B_ALIGN_LEFT);
137 
138 	// Add the "Focus follows mouse mode" pop up menu
139 	fFocusFollowsMouseMenu = new BPopUpMenu(B_TRANSLATE("Normal"));
140 
141 	const char *focusFollowsMouseLabels[] = {B_TRANSLATE_MARK("Normal"),
142 		B_TRANSLATE_MARK("Warp"), B_TRANSLATE_MARK("Instant warp")};
143 	const mode_focus_follows_mouse focusFollowsMouseModes[]
144 		= {B_NORMAL_FOCUS_FOLLOWS_MOUSE, B_WARP_FOCUS_FOLLOWS_MOUSE,
145 			B_INSTANT_WARP_FOCUS_FOLLOWS_MOUSE};
146 
147 	for (int i = 0; i < 3; i++) {
148 		BMessage* message = new BMessage(kMsgFollowsMouseMode);
149 		message->AddInt32("mode_focus_follows_mouse",
150 			focusFollowsMouseModes[i]);
151 
152 		fFocusFollowsMouseMenu->AddItem(new BMenuItem(
153 			B_TRANSLATE_NOCOLLECT(focusFollowsMouseLabels[i]), message));
154 	}
155 
156 	BMenuField* focusFollowsMouseField = new BMenuField(
157 		"Focus follows mouse mode:", fFocusFollowsMouseMenu);
158 	focusFollowsMouseField->SetAlignment(B_ALIGN_RIGHT);
159 
160 	// Add the "Click-through" check box
161 	fAcceptFirstClickBox = new BCheckBox(B_TRANSLATE("Accept first click"),
162 		new BMessage(kMsgAcceptFirstClick));
163 
164 	// Build the layout
165 
166 	// Layout is :
167 	// A | B
168 	// -----
169 	//   C
170 
171 	BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING)
172 		// Horizontal : A|B
173 		.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
174 
175 			// Vertical block A: mouse type/view/test
176 			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
177 				.Add(fTypeMenu)
178 				.AddGroup(B_HORIZONTAL, 0)
179 					.AddGlue()
180 					.Add(fMouseView)
181 					.AddGlue()
182 					.End()
183 				.AddGlue()
184 				.Add(doubleClickTextControl)
185 				.End()
186 			.Add(new BSeparatorView(B_VERTICAL))
187 
188 			// Vertical block B: speed settings
189 			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 3)
190 				.AddGroup(B_HORIZONTAL, 0)
191 					.Add(fClickSpeedSlider)
192 					.End()
193 				.AddGroup(B_HORIZONTAL, 0)
194 					.Add(fMouseSpeedSlider)
195 					.End()
196 				.AddGroup(B_HORIZONTAL, 0)
197 					.Add(fAccelerationSlider)
198 					.End()
199 				.End()
200 			.End()
201 		.AddStrut(B_USE_DEFAULT_SPACING)
202 
203 		// Horizontal Block C: focus mode
204 		.AddGroup(B_HORIZONTAL, B_USE_SMALL_SPACING)
205 			.Add(focusField)
206 			.AddGlue()
207 			.AddGroup(B_VERTICAL, 0)
208 				.Add(fAcceptFirstClickBox)
209 				.End()
210 			.End();
211 
212 	SetBorder(B_NO_BORDER);
213 }
214 
215 
216 SettingsView::~SettingsView()
217 {
218 
219 }
220 
221 
222 void
223 SettingsView::AttachedToWindow()
224 {
225 	UpdateFromSettings();
226 }
227 
228 
229 void
230 SettingsView::SetMouseType(int32 type)
231 {
232 	if (type > 6)
233 		debugger("Mouse type is invalid");
234 	fMouseView->SetMouseType(type);
235 }
236 
237 
238 void
239 SettingsView::MouseMapUpdated()
240 {
241 	fMouseView->MouseMapUpdated();
242 }
243 
244 
245 void
246 SettingsView::UpdateFromSettings()
247 {
248 	int32 value = int32(fSettings.ClickSpeed() / 1000);
249 		// slow = 1000000, fast = 0
250 	fClickSpeedSlider->SetValue(value);
251 
252 	value = int32((log(fSettings.MouseSpeed() / 8192.0) / log(2)) * 1000 / 6);
253 		// slow = 8192, fast = 524287
254 	fMouseSpeedSlider->SetValue(value);
255 
256 	value = int32(sqrt(fSettings.AccelerationFactor() / 16384.0) * 1000 / 4);
257 		// slow = 0, fast = 262144
258 	fAccelerationSlider->SetValue(value);
259 
260 	fTypeMenu->SelectOptionFor(fSettings.MouseType());
261 	fMouseView->SetMouseType(fSettings.MouseType());
262 
263 	BMenuItem* item = fFocusMenu->ItemAt(
264 		mouse_mode_to_index(fSettings.MouseMode()));
265 	if (item != NULL)
266 		item->SetMarked(true);
267 
268 	item = fFocusFollowsMouseMenu->ItemAt(
269 		focus_follows_mouse_mode_to_index(fSettings.FocusFollowsMouseMode()));
270 	if (item != NULL)
271 		item->SetMarked(true);
272 
273 	fFocusFollowsMouseMenu->SetEnabled(fSettings.MouseMode()
274 		== B_FOCUS_FOLLOWS_MOUSE);
275 
276 	fAcceptFirstClickBox->SetValue(fSettings.AcceptFirstClick()
277 		? B_CONTROL_ON : B_CONTROL_OFF);
278 	fAcceptFirstClickBox->SetEnabled(fSettings.MouseMode()
279 		!= B_FOCUS_FOLLOWS_MOUSE);
280 }
281