⛏️ index : haiku.git

/*
 * Copyright 2019, Haiku, Inc.
 * Distributed under the terms of the MIT License.
 *
 * Author:
 *		Preetpal Kaur <preetpalok123@gmail.com>
 */


#include "SettingsView.h"

#include <Box.h>
#include <Catalog.h>
#include <Debug.h>
#include <InterfaceDefs.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <SeparatorView.h>
#include <Slider.h>
#include <TextControl.h>

#include "InputConstants.h"
#include "MouseSettings.h"
#include "MouseView.h"


//	#pragma mark -

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SettingsView"


SettingsView::SettingsView(MouseSettings& settings)
	:
	BBox("main_view"),
	fSettings(settings)
{
	if (fSettings.MouseType() > 6)
		debugger("Mouse type is invalid");

	// Add the "Mouse Type" pop up menu
	fTypeMenu = new BOptionPopUp(
		"type", B_TRANSLATE("Mouse type:"), new BMessage(kMsgMouseType));
	fTypeMenu->AddOption(B_TRANSLATE("1-Button"), 1);
	fTypeMenu->AddOption(B_TRANSLATE("2-Button"), 2);
	fTypeMenu->AddOption(B_TRANSLATE("3-Button"), 3);
	fTypeMenu->AddOption(B_TRANSLATE("4-Button"), 4);
	fTypeMenu->AddOption(B_TRANSLATE("5-Button"), 5);
	fTypeMenu->AddOption(B_TRANSLATE("6-Button"), 6);

	// Create the "Double-click speed slider...
	fClickSpeedSlider
		= new BSlider("double_click_speed", B_TRANSLATE("Double-click speed"),
			new BMessage(kMsgDoubleClickSpeed), 0, 1000, B_HORIZONTAL);
	fClickSpeedSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
	fClickSpeedSlider->SetHashMarkCount(7);

	// Create the "Mouse Speed" slider...
	fMouseSpeedSlider = new BSlider("mouse_speed", B_TRANSLATE("Mouse speed"),
		new BMessage(kMsgMouseSpeed), 0, 1000, B_HORIZONTAL);
	fMouseSpeedSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
	fMouseSpeedSlider->SetHashMarkCount(7);

	// Create the "Mouse Acceleration" slider...
	fAccelerationSlider
		= new BSlider("mouse_acceleration", B_TRANSLATE("Mouse acceleration"),
			new BMessage(kMsgAccelerationFactor), 0, 1000, B_HORIZONTAL);
	fAccelerationSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
	fAccelerationSlider->SetHashMarkCount(7);

	fMouseView = new MouseView(fSettings);

	// Create the "Double-click test area" text box...
	const char* label = B_TRANSLATE("Double-click test area");
	BTextControl* doubleClickTextControl = new BTextControl(NULL, label, NULL);
	doubleClickTextControl->SetAlignment(B_ALIGN_LEFT, B_ALIGN_CENTER);
	doubleClickTextControl->SetExplicitMinSize(
		BSize(StringWidth(label), B_SIZE_UNSET));

	// Add the "Mouse focus mode" pop up menu
	fFocusMenu = new BOptionPopUp("focus_mode", B_TRANSLATE("Focus mode:"),
		new BMessage(kMsgMouseFocusMode));

	const char* focusLabels[] = {B_TRANSLATE_MARK("Click to focus and raise"),
		B_TRANSLATE_MARK("Click to focus"),
		B_TRANSLATE_MARK("Focus follows mouse")};
	const mode_mouse focusModes[]
		= {B_NORMAL_MOUSE, B_CLICK_TO_FOCUS_MOUSE, B_FOCUS_FOLLOWS_MOUSE};

	for (size_t i = 0; i < B_COUNT_OF(focusModes); i++)
		fFocusMenu->AddOption(
			B_TRANSLATE_NOCOLLECT(focusLabels[i]), focusModes[i]);

	// Add the "Click-through" check box
	fAcceptFirstClickBox = new BCheckBox(
		B_TRANSLATE("Accept first click"), new BMessage(kMsgAcceptFirstClick));

	// Build the layout

	// Layout is :
	// A | B
	// -----
	//   C

	BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING)
		// Horizontal : A|B
		.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)

			// Vertical block A: mouse type/view/test
			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
				.Add(fTypeMenu)
				.AddGroup(B_HORIZONTAL, 0)
					.AddGlue()
					.Add(fMouseView)
					.AddGlue()
					.End()
				.AddGlue()
				.Add(doubleClickTextControl)
				.End()
			.Add(new BSeparatorView(B_VERTICAL))

			// Vertical block B: speed settings
			.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 3)
				.AddGroup(B_HORIZONTAL, 0)
					.Add(fClickSpeedSlider)
					.End()
				.AddGroup(B_HORIZONTAL, 0)
					.Add(fMouseSpeedSlider)
					.End()
				.AddGroup(B_HORIZONTAL, 0)
					.Add(fAccelerationSlider)
					.End()
				.End()
			.End()
		.AddStrut(B_USE_DEFAULT_SPACING)

		// Horizontal Block C: focus mode
		.AddGroup(B_HORIZONTAL, B_USE_SMALL_SPACING)
			.Add(fFocusMenu)
			.AddGlue()
			.AddGroup(B_VERTICAL, 0)
				.Add(fAcceptFirstClickBox)
				.End()
			.End();

	SetBorder(B_NO_BORDER);
}


SettingsView::~SettingsView()
{
}


void
SettingsView::AttachedToWindow()
{
	UpdateFromSettings();
}


void
SettingsView::SetMouseType(int32 type)
{
	if (type > 6)
		debugger("Mouse type is invalid");
	fMouseView->SetMouseType(type);
}


void
SettingsView::MouseMapUpdated()
{
	fMouseView->MouseMapUpdated();
}


void
SettingsView::UpdateFromSettings()
{
	int32 value = int32((1000000LL - fSettings.ClickSpeed()) / 1000);
	// slow = 1000000, fast = 0
	fClickSpeedSlider->SetValue(value);

	value = int32((log(fSettings.MouseSpeed() / 8192.0) / log(2)) * 1000 / 6);
	// slow = 8192, fast = 524287
	fMouseSpeedSlider->SetValue(value);

	value = int32(sqrt(fSettings.AccelerationFactor() / 16384.0) * 1000 / 4);
	// slow = 0, fast = 262144
	fAccelerationSlider->SetValue(value);

	fTypeMenu->SelectOptionFor(fSettings.MouseType());
	fMouseView->SetMouseType(fSettings.MouseType());

	fFocusMenu->SelectOptionFor(fSettings.MouseMode());

	fAcceptFirstClickBox->SetValue(
		fSettings.AcceptFirstClick() ? B_CONTROL_ON : B_CONTROL_OFF);
	fAcceptFirstClickBox->SetEnabled(
		fSettings.MouseMode() != B_FOCUS_FOLLOWS_MOUSE);
}