xref: /haiku/src/preferences/input/SettingsView.cpp (revision 15fb7d88e971c4d6c787c6a3a5c159afb1ebf77b)
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 	// Add the "Mouse Type" pop up menu
75 	fTypeMenu = new BPopUpMenu("unknown");
76 	fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("1-Button"),
77 		new BMessage(kMsgMouseType)));
78 	fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("2-Button"),
79 		new BMessage(kMsgMouseType)));
80 	fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("3-Button"),
81 		new BMessage(kMsgMouseType)));
82 
83 	BMenuField* typeField = new BMenuField(B_TRANSLATE("Mouse type:"),
84 		fTypeMenu);
85 	typeField->SetAlignment(B_ALIGN_LEFT);
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 				.AddGroup(B_HORIZONTAL, 0)
178 					.AddGlue()
179 					.Add(typeField)
180 					.AddGlue()
181 					.End()
182 				.AddGlue()
183 				.AddGroup(B_HORIZONTAL, 0)
184 					.AddGlue()
185 					.Add(fMouseView)
186 					.AddGlue()
187 					.End()
188 				.AddGlue()
189 				.Add(doubleClickTextControl)
190 				.End()
191 			.Add(new BSeparatorView(B_VERTICAL))
192 
193 			// Vertical block B: speed settings
194 			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 3)
195 				.AddGroup(B_HORIZONTAL, 0)
196 					.Add(fClickSpeedSlider)
197 					.End()
198 				.AddGroup(B_HORIZONTAL, 0)
199 					.Add(fMouseSpeedSlider)
200 					.End()
201 				.AddGroup(B_HORIZONTAL, 0)
202 					.Add(fAccelerationSlider)
203 					.End()
204 				.End()
205 			.End()
206 		.AddStrut(B_USE_DEFAULT_SPACING)
207 
208 		// Horizontal Block C: focus mode
209 		.AddGroup(B_HORIZONTAL, B_USE_SMALL_SPACING)
210 			.Add(focusField)
211 			.AddGlue()
212 			.AddGroup(B_VERTICAL, 0)
213 				.Add(fAcceptFirstClickBox)
214 				.End()
215 			.End();
216 
217 	SetBorder(B_NO_BORDER);
218 }
219 
220 
221 SettingsView::~SettingsView()
222 {
223 
224 }
225 
226 
227 void
228 SettingsView::AttachedToWindow()
229 {
230 	UpdateFromSettings();
231 }
232 
233 
234 void
235 SettingsView::SetMouseType(int32 type)
236 {
237 	fMouseView->SetMouseType(type);
238 }
239 
240 
241 void
242 SettingsView::MouseMapUpdated()
243 {
244 	fMouseView->MouseMapUpdated();
245 }
246 
247 
248 void
249 SettingsView::UpdateFromSettings()
250 {
251 	int32 value = int32(fSettings.ClickSpeed() / 1000);
252 		// slow = 1000000, fast = 0
253 	fClickSpeedSlider->SetValue(value);
254 
255 	value = int32((log(fSettings.MouseSpeed() / 8192.0) / log(2)) * 1000 / 6);
256 		// slow = 8192, fast = 524287
257 	fMouseSpeedSlider->SetValue(value);
258 
259 	value = int32(sqrt(fSettings.AccelerationFactor() / 16384.0) * 1000 / 4);
260 		// slow = 0, fast = 262144
261 	fAccelerationSlider->SetValue(value);
262 
263 	BMenuItem* item = fTypeMenu->ItemAt(fSettings.MouseType() - 1);
264 	if (item != NULL)
265 		item->SetMarked(true);
266 
267 	fMouseView->SetMouseType(fSettings.MouseType());
268 
269 	item = fFocusMenu->ItemAt(mouse_mode_to_index(fSettings.MouseMode()));
270 	if (item != NULL)
271 		item->SetMarked(true);
272 
273 	item = fFocusFollowsMouseMenu->ItemAt(
274 		focus_follows_mouse_mode_to_index(fSettings.FocusFollowsMouseMode()));
275 	if (item != NULL)
276 		item->SetMarked(true);
277 
278 	fFocusFollowsMouseMenu->SetEnabled(fSettings.MouseMode()
279 		== B_FOCUS_FOLLOWS_MOUSE);
280 
281 	fAcceptFirstClickBox->SetValue(fSettings.AcceptFirstClick()
282 		? B_CONTROL_ON : B_CONTROL_OFF);
283 	fAcceptFirstClickBox->SetEnabled(fSettings.MouseMode()
284 		!= B_FOCUS_FOLLOWS_MOUSE);
285 }