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