/*
 * Copyright 2003-2014 Haiku Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Jérôme Duval,
 *		Axel Dörfler (axeld@pinc-software.de)
 *		Andrew McCall (mccall@digitalparadise.co.uk)
 *		Brecht Machiels (brecht@mos6581.org)
 */
 
 
#include "SettingsView.h"
 
#include <Bitmap.h>
#include <Box.h>
#include <Button.h>
#include <Catalog.h>
#include <Debug.h>
#include <InterfaceDefs.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
#include <SeparatorView.h>
#include <Slider.h>
#include <TextControl.h>
#include <TranslationUtils.h>
#include <Window.h>
 
#include "MouseConstants.h"
#include "MouseSettings.h"
#include "MouseView.h"
 
 
static int32
mouse_mode_to_index(mode_mouse mode)
{
	switch (mode) {
		case B_NORMAL_MOUSE:
		default:
			return 0;
		case B_CLICK_TO_FOCUS_MOUSE:
			return 1;
		case B_FOCUS_FOLLOWS_MOUSE:
			return 2;
	}
}
 
 
static int32
focus_follows_mouse_mode_to_index(mode_focus_follows_mouse mode)
{
	switch (mode) {
		case B_NORMAL_FOCUS_FOLLOWS_MOUSE:
		default:
			return 0;
		case B_WARP_FOCUS_FOLLOWS_MOUSE:
			return 1;
		case B_INSTANT_WARP_FOCUS_FOLLOWS_MOUSE:
			return 2;
	}
}
 
 
//	#pragma mark -
 
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SettingsView"
 
SettingsView::SettingsView(MouseSettings& settings)
	: BBox("main_view"),
	fSettings(settings)
{
	// Add the "Mouse Type" pop up menu
	fTypeMenu = new BPopUpMenu("unknown");
	fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("1-Button"),
		new BMessage(kMsgMouseType)));
	fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("2-Button"),
		new BMessage(kMsgMouseType)));
	fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("3-Button"),
		new BMessage(kMsgMouseType)));
 
	BMenuField* typeField = new BMenuField(B_TRANSLATE("Mouse type:"),
		fTypeMenu);
	typeField->SetAlignment(B_ALIGN_LEFT);
 
	// 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);
 
	// Mouse image...
	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 BPopUpMenu(B_TRANSLATE("Click to focus and raise"));
 
	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 (int i = 0; i < 3; i++) {
		BMessage* message = new BMessage(kMsgMouseFocusMode);
		message->AddInt32("mode", focusModes[i]);
 
		fFocusMenu->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(focusLabels[i]),
			message));
	}
 
	BMenuField* focusField = new BMenuField(B_TRANSLATE("Focus mode:"),
		fFocusMenu);
	focusField->SetAlignment(B_ALIGN_LEFT);
 
	// Add the "Focus follows mouse mode" pop up menu
	fFocusFollowsMouseMenu = new BPopUpMenu(B_TRANSLATE("Normal"));
 
	const char *focusFollowsMouseLabels[] = {B_TRANSLATE_MARK("Normal"),
		B_TRANSLATE_MARK("Warp"), B_TRANSLATE_MARK("Instant warp")};
	const mode_focus_follows_mouse focusFollowsMouseModes[]
		= {B_NORMAL_FOCUS_FOLLOWS_MOUSE, B_WARP_FOCUS_FOLLOWS_MOUSE,
			B_INSTANT_WARP_FOCUS_FOLLOWS_MOUSE};
 
	for (int i = 0; i < 3; i++) {
		BMessage* message = new BMessage(kMsgFollowsMouseMode);
		message->AddInt32("mode_focus_follows_mouse",
			focusFollowsMouseModes[i]);
 
		fFocusFollowsMouseMenu->AddItem(new BMenuItem(
			B_TRANSLATE_NOCOLLECT(focusFollowsMouseLabels[i]), message));
	}
 
	BMenuField* focusFollowsMouseField = new BMenuField(
		"Focus follows mouse mode:", fFocusFollowsMouseMenu);
	focusFollowsMouseField->SetAlignment(B_ALIGN_RIGHT);
 
	// 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)
				.AddGroup(B_HORIZONTAL, 0)
					.AddGlue()
					.Add(typeField)
					.AddGlue()
					.End()
				.AddGlue()
				.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(focusField)
			.AddGlue()
			.AddGroup(B_VERTICAL, 0)
				.Add(fAcceptFirstClickBox)
				.End()
			.End();
 
	SetBorder(B_NO_BORDER);
}
 
 
SettingsView::~SettingsView()
{
 
}
 
 
void
SettingsView::AttachedToWindow()
{
	UpdateFromSettings();
 
 
}
 
 
void
SettingsView::SetMouseType(int32 type)
{
	fMouseView->SetMouseType(type);
}
 
 
void
SettingsView::MouseMapUpdated()
{
	fMouseView->MouseMapUpdated();
}
 
 
void
SettingsView::UpdateFromSettings()
{
	int32 value = int32(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);
 
	BMenuItem* item = fTypeMenu->ItemAt(fSettings.MouseType() - 1);
	if (item != NULL)
		item->SetMarked(true);
 
	fMouseView->SetMouseType(fSettings.MouseType());
 
	item = fFocusMenu->ItemAt(mouse_mode_to_index(fSettings.MouseMode()));
	if (item != NULL)
		item->SetMarked(true);
 
	item = fFocusFollowsMouseMenu->ItemAt(
		focus_follows_mouse_mode_to_index(fSettings.FocusFollowsMouseMode()));
	if (item != NULL)
		item->SetMarked(true);
 
	fFocusFollowsMouseMenu->SetEnabled(fSettings.MouseMode()
		== B_FOCUS_FOLLOWS_MOUSE);
 
	fAcceptFirstClickBox->SetValue(fSettings.AcceptFirstClick()
		? B_CONTROL_ON : B_CONTROL_OFF);
	fAcceptFirstClickBox->SetEnabled(fSettings.MouseMode()
		!= B_FOCUS_FOLLOWS_MOUSE);
}
 

V773 Visibility scope of the 'message' pointer was exited without releasing the memory. A memory leak is possible.

V773 Visibility scope of the 'message' pointer was exited without releasing the memory. A memory leak is possible.

V773 Visibility scope of the 'focusFollowsMouseField' pointer was exited without releasing the memory. A memory leak is possible.