xref: /haiku/src/preferences/input/SettingsView.cpp (revision 7a617f59fd64449167bb190666bd44fae7efbe0b)
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 BOptionPopUp("type", B_TRANSLATE("Mouse type:"),
76 		new BMessage(kMsgMouseType));
77 	fTypeMenu->AddOption(B_TRANSLATE("1-Button"), 1);
78 	fTypeMenu->AddOption(B_TRANSLATE("2-Button"), 2);
79 	fTypeMenu->AddOption(B_TRANSLATE("3-Button"), 3);
80 	fTypeMenu->AddOption(B_TRANSLATE("4-Button"), 4);
81 	fTypeMenu->AddOption(B_TRANSLATE("5-Button"), 5);
82 
83 	// Create the "Double-click speed slider...
84 	fClickSpeedSlider = new BSlider("double_click_speed",
85 		B_TRANSLATE("Double-click speed"), new BMessage(kMsgDoubleClickSpeed),
86 		0, 1000, B_HORIZONTAL);
87 	fClickSpeedSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
88 	fClickSpeedSlider->SetHashMarkCount(7);
89 
90 	// Create the "Mouse Speed" slider...
91 	fMouseSpeedSlider = new BSlider("mouse_speed", B_TRANSLATE("Mouse speed"),
92 		new BMessage(kMsgMouseSpeed), 0, 1000, B_HORIZONTAL);
93 	fMouseSpeedSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
94 	fMouseSpeedSlider->SetHashMarkCount(7);
95 
96 	// Create the "Mouse Acceleration" slider...
97 	fAccelerationSlider = new BSlider("mouse_acceleration",
98 		B_TRANSLATE("Mouse acceleration"),
99 		new BMessage(kMsgAccelerationFactor), 0, 1000, B_HORIZONTAL);
100 	fAccelerationSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
101 	fAccelerationSlider->SetHashMarkCount(7);
102 
103 	fMouseView = new MouseView(fSettings);
104 
105 	// Create the "Double-click test area" text box...
106 	const char* label = B_TRANSLATE("Double-click test area");
107 	BTextControl* doubleClickTextControl = new BTextControl(NULL,
108 		label, NULL);
109 	doubleClickTextControl->SetAlignment(B_ALIGN_LEFT, B_ALIGN_CENTER);
110 	doubleClickTextControl->SetExplicitMinSize(
111 		BSize(StringWidth(label), B_SIZE_UNSET));
112 
113 	// Add the "Mouse focus mode" pop up menu
114 	fFocusMenu = new BPopUpMenu(B_TRANSLATE("Click to focus and raise"));
115 
116 	const char *focusLabels[] = {B_TRANSLATE_MARK("Click to focus and raise"),
117 		B_TRANSLATE_MARK("Click to focus"),
118 		B_TRANSLATE_MARK("Focus follows mouse")};
119 	const mode_mouse focusModes[] = {B_NORMAL_MOUSE, B_CLICK_TO_FOCUS_MOUSE,
120 										B_FOCUS_FOLLOWS_MOUSE};
121 
122 	for (int i = 0; i < 3; i++) {
123 		BMessage* message = new BMessage(kMsgMouseFocusMode);
124 		message->AddInt32("mode", focusModes[i]);
125 
126 		fFocusMenu->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(focusLabels[i]),
127 			message));
128 	}
129 
130 	BMenuField* focusField = new BMenuField(B_TRANSLATE("Focus mode:"),
131 		fFocusMenu);
132 	focusField->SetAlignment(B_ALIGN_LEFT);
133 
134 	// Add the "Focus follows mouse mode" pop up menu
135 	fFocusFollowsMouseMenu = new BPopUpMenu(B_TRANSLATE("Normal"));
136 
137 	const char *focusFollowsMouseLabels[] = {B_TRANSLATE_MARK("Normal"),
138 		B_TRANSLATE_MARK("Warp"), B_TRANSLATE_MARK("Instant warp")};
139 	const mode_focus_follows_mouse focusFollowsMouseModes[]
140 		= {B_NORMAL_FOCUS_FOLLOWS_MOUSE, B_WARP_FOCUS_FOLLOWS_MOUSE,
141 			B_INSTANT_WARP_FOCUS_FOLLOWS_MOUSE};
142 
143 	for (int i = 0; i < 3; i++) {
144 		BMessage* message = new BMessage(kMsgFollowsMouseMode);
145 		message->AddInt32("mode_focus_follows_mouse",
146 			focusFollowsMouseModes[i]);
147 
148 		fFocusFollowsMouseMenu->AddItem(new BMenuItem(
149 			B_TRANSLATE_NOCOLLECT(focusFollowsMouseLabels[i]), message));
150 	}
151 
152 	BMenuField* focusFollowsMouseField = new BMenuField(
153 		"Focus follows mouse mode:", fFocusFollowsMouseMenu);
154 	focusFollowsMouseField->SetAlignment(B_ALIGN_RIGHT);
155 
156 	// Add the "Click-through" check box
157 	fAcceptFirstClickBox = new BCheckBox(B_TRANSLATE("Accept first click"),
158 		new BMessage(kMsgAcceptFirstClick));
159 
160 	// Build the layout
161 
162 	// Layout is :
163 	// A | B
164 	// -----
165 	//   C
166 
167 	BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING)
168 		// Horizontal : A|B
169 		.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
170 
171 			// Vertical block A: mouse type/view/test
172 			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
173 				.Add(fTypeMenu)
174 				.AddGroup(B_HORIZONTAL, 0)
175 					.AddGlue()
176 					.Add(fMouseView)
177 					.AddGlue()
178 					.End()
179 				.AddGlue()
180 				.Add(doubleClickTextControl)
181 				.End()
182 			.Add(new BSeparatorView(B_VERTICAL))
183 
184 			// Vertical block B: speed settings
185 			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 3)
186 				.AddGroup(B_HORIZONTAL, 0)
187 					.Add(fClickSpeedSlider)
188 					.End()
189 				.AddGroup(B_HORIZONTAL, 0)
190 					.Add(fMouseSpeedSlider)
191 					.End()
192 				.AddGroup(B_HORIZONTAL, 0)
193 					.Add(fAccelerationSlider)
194 					.End()
195 				.End()
196 			.End()
197 		.AddStrut(B_USE_DEFAULT_SPACING)
198 
199 		// Horizontal Block C: focus mode
200 		.AddGroup(B_HORIZONTAL, B_USE_SMALL_SPACING)
201 			.Add(focusField)
202 			.AddGlue()
203 			.AddGroup(B_VERTICAL, 0)
204 				.Add(fAcceptFirstClickBox)
205 				.End()
206 			.End();
207 
208 	SetBorder(B_NO_BORDER);
209 }
210 
211 
212 SettingsView::~SettingsView()
213 {
214 
215 }
216 
217 
218 void
219 SettingsView::AttachedToWindow()
220 {
221 	UpdateFromSettings();
222 }
223 
224 
225 void
226 SettingsView::SetMouseType(int32 type)
227 {
228 	fMouseView->SetMouseType(type);
229 }
230 
231 
232 void
233 SettingsView::MouseMapUpdated()
234 {
235 	fMouseView->MouseMapUpdated();
236 }
237 
238 
239 void
240 SettingsView::UpdateFromSettings()
241 {
242 	int32 value = int32(fSettings.ClickSpeed() / 1000);
243 		// slow = 1000000, fast = 0
244 	fClickSpeedSlider->SetValue(value);
245 
246 	value = int32((log(fSettings.MouseSpeed() / 8192.0) / log(2)) * 1000 / 6);
247 		// slow = 8192, fast = 524287
248 	fMouseSpeedSlider->SetValue(value);
249 
250 	value = int32(sqrt(fSettings.AccelerationFactor() / 16384.0) * 1000 / 4);
251 		// slow = 0, fast = 262144
252 	fAccelerationSlider->SetValue(value);
253 
254 	fTypeMenu->SelectOptionFor(fSettings.MouseType());
255 	fMouseView->SetMouseType(fSettings.MouseType());
256 
257 	BMenuItem* item = fFocusMenu->ItemAt(
258 		mouse_mode_to_index(fSettings.MouseMode()));
259 	if (item != NULL)
260 		item->SetMarked(true);
261 
262 	item = fFocusFollowsMouseMenu->ItemAt(
263 		focus_follows_mouse_mode_to_index(fSettings.FocusFollowsMouseMode()));
264 	if (item != NULL)
265 		item->SetMarked(true);
266 
267 	fFocusFollowsMouseMenu->SetEnabled(fSettings.MouseMode()
268 		== B_FOCUS_FOLLOWS_MOUSE);
269 
270 	fAcceptFirstClickBox->SetValue(fSettings.AcceptFirstClick()
271 		? B_CONTROL_ON : B_CONTROL_OFF);
272 	fAcceptFirstClickBox->SetEnabled(fSettings.MouseMode()
273 		!= B_FOCUS_FOLLOWS_MOUSE);
274 }
275