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//	#pragma mark -
36
37#undef B_TRANSLATION_CONTEXT
38#define B_TRANSLATION_CONTEXT "SettingsView"
39
40
41SettingsView::SettingsView(MouseSettings& settings)
42	:
43	BBox("main_view"),
44	fSettings(settings)
45{
46	if (fSettings.MouseType() > 6)
47		debugger("Mouse type is invalid");
48
49	// Add the "Mouse Type" pop up menu
50	fTypeMenu = new BOptionPopUp(
51		"type", B_TRANSLATE("Mouse type:"), new BMessage(kMsgMouseType));
52	fTypeMenu->AddOption(B_TRANSLATE("1-Button"), 1);
53	fTypeMenu->AddOption(B_TRANSLATE("2-Button"), 2);
54	fTypeMenu->AddOption(B_TRANSLATE("3-Button"), 3);
55	fTypeMenu->AddOption(B_TRANSLATE("4-Button"), 4);
56	fTypeMenu->AddOption(B_TRANSLATE("5-Button"), 5);
57	fTypeMenu->AddOption(B_TRANSLATE("6-Button"), 6);
58
59	// Create the "Double-click speed slider...
60	fClickSpeedSlider
61		= new BSlider("double_click_speed", B_TRANSLATE("Double-click speed"),
62			new BMessage(kMsgDoubleClickSpeed), 0, 1000, B_HORIZONTAL);
63	fClickSpeedSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
64	fClickSpeedSlider->SetHashMarkCount(7);
65
66	// Create the "Mouse Speed" slider...
67	fMouseSpeedSlider = new BSlider("mouse_speed", B_TRANSLATE("Mouse speed"),
68		new BMessage(kMsgMouseSpeed), 0, 1000, B_HORIZONTAL);
69	fMouseSpeedSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
70	fMouseSpeedSlider->SetHashMarkCount(7);
71
72	// Create the "Mouse Acceleration" slider...
73	fAccelerationSlider
74		= new BSlider("mouse_acceleration", B_TRANSLATE("Mouse acceleration"),
75			new BMessage(kMsgAccelerationFactor), 0, 1000, B_HORIZONTAL);
76	fAccelerationSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
77	fAccelerationSlider->SetHashMarkCount(7);
78
79	fMouseView = new MouseView(fSettings);
80
81	// Create the "Double-click test area" text box...
82	const char* label = B_TRANSLATE("Double-click test area");
83	BTextControl* doubleClickTextControl = new BTextControl(NULL, label, NULL);
84	doubleClickTextControl->SetAlignment(B_ALIGN_LEFT, B_ALIGN_CENTER);
85	doubleClickTextControl->SetExplicitMinSize(
86		BSize(StringWidth(label), B_SIZE_UNSET));
87
88	// Add the "Mouse focus mode" pop up menu
89	fFocusMenu = new BOptionPopUp("focus_mode", B_TRANSLATE("Focus mode:"),
90		new BMessage(kMsgMouseFocusMode));
91
92	const char* focusLabels[] = {B_TRANSLATE_MARK("Click to focus and raise"),
93		B_TRANSLATE_MARK("Click to focus"),
94		B_TRANSLATE_MARK("Focus follows mouse")};
95	const mode_mouse focusModes[]
96		= {B_NORMAL_MOUSE, B_CLICK_TO_FOCUS_MOUSE, B_FOCUS_FOLLOWS_MOUSE};
97
98	for (size_t i = 0; i < B_COUNT_OF(focusModes); i++)
99		fFocusMenu->AddOption(
100			B_TRANSLATE_NOCOLLECT(focusLabels[i]), focusModes[i]);
101
102	// Add the "Click-through" check box
103	fAcceptFirstClickBox = new BCheckBox(
104		B_TRANSLATE("Accept first click"), new BMessage(kMsgAcceptFirstClick));
105
106	// Build the layout
107
108	// Layout is :
109	// A | B
110	// -----
111	//   C
112
113	BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING)
114		// Horizontal : A|B
115		.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
116
117			// Vertical block A: mouse type/view/test
118			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
119				.Add(fTypeMenu)
120				.AddGroup(B_HORIZONTAL, 0)
121					.AddGlue()
122					.Add(fMouseView)
123					.AddGlue()
124					.End()
125				.AddGlue()
126				.Add(doubleClickTextControl)
127				.End()
128			.Add(new BSeparatorView(B_VERTICAL))
129
130			// Vertical block B: speed settings
131			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 3)
132				.AddGroup(B_HORIZONTAL, 0)
133					.Add(fClickSpeedSlider)
134					.End()
135				.AddGroup(B_HORIZONTAL, 0)
136					.Add(fMouseSpeedSlider)
137					.End()
138				.AddGroup(B_HORIZONTAL, 0)
139					.Add(fAccelerationSlider)
140					.End()
141				.End()
142			.End()
143		.AddStrut(B_USE_DEFAULT_SPACING)
144
145		// Horizontal Block C: focus mode
146		.AddGroup(B_HORIZONTAL, B_USE_SMALL_SPACING)
147			.Add(fFocusMenu)
148			.AddGlue()
149			.AddGroup(B_VERTICAL, 0)
150				.Add(fAcceptFirstClickBox)
151				.End()
152			.End();
153
154	SetBorder(B_NO_BORDER);
155}
156
157
158SettingsView::~SettingsView()
159{
160}
161
162
163void
164SettingsView::AttachedToWindow()
165{
166	UpdateFromSettings();
167}
168
169
170void
171SettingsView::SetMouseType(int32 type)
172{
173	if (type > 6)
174		debugger("Mouse type is invalid");
175	fMouseView->SetMouseType(type);
176}
177
178
179void
180SettingsView::MouseMapUpdated()
181{
182	fMouseView->MouseMapUpdated();
183}
184
185
186void
187SettingsView::UpdateFromSettings()
188{
189	int32 value = int32(fSettings.ClickSpeed() / 1000);
190	// slow = 1000000, fast = 0
191	fClickSpeedSlider->SetValue(value);
192
193	value = int32((log(fSettings.MouseSpeed() / 8192.0) / log(2)) * 1000 / 6);
194	// slow = 8192, fast = 524287
195	fMouseSpeedSlider->SetValue(value);
196
197	value = int32(sqrt(fSettings.AccelerationFactor() / 16384.0) * 1000 / 4);
198	// slow = 0, fast = 262144
199	fAccelerationSlider->SetValue(value);
200
201	fTypeMenu->SelectOptionFor(fSettings.MouseType());
202	fMouseView->SetMouseType(fSettings.MouseType());
203
204	fFocusMenu->SelectOptionFor(fSettings.MouseMode());
205
206	fAcceptFirstClickBox->SetValue(
207		fSettings.AcceptFirstClick() ? B_CONTROL_ON : B_CONTROL_OFF);
208	fAcceptFirstClickBox->SetEnabled(
209		fSettings.MouseMode() != B_FOCUS_FOLLOWS_MOUSE);
210}
211