diff --git a/src/preferences/Jamfile b/src/preferences/Jamfile index 7cc5f6c84b..caf06fac1a 100644 --- a/src/preferences/Jamfile +++ b/src/preferences/Jamfile @@ -6,6 +6,7 @@ SubInclude HAIKU_TOP src preferences bluetooth ; SubInclude HAIKU_TOP src preferences datatranslations ; SubInclude HAIKU_TOP src preferences deskbar ; SubInclude HAIKU_TOP src preferences filetypes ; +SubInclude HAIKU_TOP src preferences input ; SubInclude HAIKU_TOP src preferences joysticks ; SubInclude HAIKU_TOP src preferences keyboard ; SubInclude HAIKU_TOP src preferences keymap ; diff --git a/src/preferences/input/Input.cpp b/src/preferences/input/Input.cpp new file mode 100644 index 0000000000..19c808f167 --- /dev/null +++ b/src/preferences/input/Input.cpp @@ -0,0 +1,77 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur + */ + + +#include "Input.h" + +#include +#include + +#include "InputConstants.h" +#include "InputMouse.h" +#include "InputWindow.h" +#include "MouseSettings.h" +#include "MouseView.h" + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "InputApplication" + +const char* kSignature = "application/x-vnd.Haiku-Input"; + + +InputApplication::InputApplication() + : + BApplication(kSignature) +{ + BRect rect(0, 0, 600, 500); + InputWindow* window = new InputWindow(rect); + window->Show(); +} + +void +InputApplication::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMsgMouseType: + case kMsgMouseMap: + case kMsgMouseFocusMode: + case kMsgFollowsMouseMode: + case kMsgAcceptFirstClick: + case kMsgDoubleClickSpeed: + case kMsgMouseSpeed: + case kMsgAccelerationFactor: + case kMsgDefaults: + case kMsgRevert: + { + fWindow->PostMessage(message); + break; + } + case SCROLL_AREA_CHANGED: + case SCROLL_CONTROL_CHANGED: + case TAP_CONTROL_CHANGED: + case DEFAULT_SETTINGS: + case REVERT_SETTINGS: + { + fWindow->PostMessage(message); + break; + } + default: + BApplication::MessageReceived(message); + } +}; + + +int +main(int /*argc*/, char** /*argv*/) +{ + InputApplication app; + app.Run(); + + return 0; +} diff --git a/src/preferences/input/Input.h b/src/preferences/input/Input.h new file mode 100644 index 0000000000..0a64c3aed1 --- /dev/null +++ b/src/preferences/input/Input.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur + */ + + +#ifndef INPUT_H +#define INPUT_H + + +#include +#include +#include + + +#include "MouseSettings.h" +#include "InputMouse.h" +#include "InputWindow.h" + + +class SettingsView; +class MouseSettings; + +class InputApplication : public BApplication { +public: + InputApplication(); + void MessageReceived(BMessage* message); +private: + InputWindow* fWindow; +}; + +#endif /* INPUT_H */ \ No newline at end of file diff --git a/src/preferences/input/InputConstants.h b/src/preferences/input/InputConstants.h new file mode 100644 index 0000000000..e2c961e51d --- /dev/null +++ b/src/preferences/input/InputConstants.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur + */ + + +#ifndef INPUT_MOUSE_CONSTANTS_H +#define INPUT_MOUSE_CONSTANTS_H + +#include + + +const uint32 kMsgDefaults = 'BTde'; +const uint32 kMsgRevert = 'BTre'; +const uint32 kMsgUpdate = 'BTup'; +const uint32 kMsgDoubleClickSpeed = 'SLdc'; +const uint32 kMsgCursorSpeed = 'SLcs'; +const uint32 kMsgFollowsMouseMode = 'PUff'; +const uint32 kMsgMouseFocusMode = 'PUmf'; +const uint32 kMsgAcceptFirstClick = 'PUaf'; +const uint32 kMsgMouseType = 'PUmt'; +const uint32 kMsgMouseMap = 'PUmm'; +const uint32 kMsgMouseSpeed = 'SLms'; +const uint32 kMsgAccelerationFactor = 'SLma'; +const uint32 kMsgSelected = 'SMms'; +const uint32 kMsgAddToDeviceList = 'SAdl'; +const uint32 kMsgPointingDevices = 'MTss'; + +const uint32 kBorderSpace = 10; +const uint32 kItemSpace = 7; + +#endif /* INPUT_MOUSE_CONSTANTS_H */ diff --git a/src/preferences/input/InputMouse.cpp b/src/preferences/input/InputMouse.cpp new file mode 100644 index 0000000000..f76b56244e --- /dev/null +++ b/src/preferences/input/InputMouse.cpp @@ -0,0 +1,217 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur + */ + + +#include "InputMouse.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "InputConstants.h" +#include "InputWindow.h" +#include "MouseSettings.h" +#include "MouseView.h" + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "InputMouse" + +static const bigtime_t kDefaultClickSpeed = 500000; +static const int32 kDefaultMouseSpeed = 65536; +static const int32 kDefaultMouseType = 3; // 3 button mouse +static const int32 kDefaultAccelerationFactor = 65536; +static const bool kDefaultAcceptFirstClick = false; + + +InputMouse::InputMouse() + : BView("InputMouse", B_WILL_DRAW) +{ + fSettingsView = new SettingsView(fSettings); + + fDefaultsButton = new BButton(B_TRANSLATE("Defaults"), + new BMessage(kMsgDefaults)); + fDefaultsButton->SetEnabled(fSettings.IsDefaultable()); + + fRevertButton = new BButton(B_TRANSLATE("Revert"), + new BMessage(kMsgRevert)); + fRevertButton->SetEnabled(false); + + BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING) + .Add(fSettingsView) + .Add(new BSeparatorView(B_HORIZONTAL)) + .AddGroup(B_HORIZONTAL) + .Add(fDefaultsButton) + .Add(fRevertButton) + .AddGlue() + .End() + .End(); +} + +InputMouse::~InputMouse() +{ +} + +void +InputMouse::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMsgDefaults: { + fSettings.Defaults(); + fSettingsView->UpdateFromSettings(); + + fDefaultsButton->SetEnabled(false); + fRevertButton->SetEnabled(fSettings.IsRevertable()); + break; + } + + case kMsgRevert: { + fSettings.Revert(); + fSettingsView->UpdateFromSettings(); + + fDefaultsButton->SetEnabled(fSettings.IsDefaultable()); + fRevertButton->SetEnabled(false); + break; + + } + + case kMsgMouseType: + { + int32 type; + if (message->FindInt32("index", &type) == B_OK) { + fSettings.SetMouseType(++type); + fSettingsView->SetMouseType(type); + fDefaultsButton->SetEnabled(fSettings.IsDefaultable()); + fRevertButton->SetEnabled(fSettings.IsRevertable()); + } + break; + } + + case kMsgMouseFocusMode: + { + int32 mode; + if (message->FindInt32("mode", &mode) == B_OK) { + fSettings.SetMouseMode((mode_mouse)mode); + fDefaultsButton->SetEnabled(fSettings.IsDefaultable()); + fRevertButton->SetEnabled(fSettings.IsRevertable()); + fSettingsView->fFocusFollowsMouseMenu->SetEnabled( + mode == B_FOCUS_FOLLOWS_MOUSE); + fSettingsView->fAcceptFirstClickBox->SetEnabled( + mode != B_FOCUS_FOLLOWS_MOUSE); + } + break; + } + + case kMsgFollowsMouseMode: + { + int32 mode; + if (message->FindInt32("mode_focus_follows_mouse", &mode) + == B_OK) { + fSettings.SetFocusFollowsMouseMode( + (mode_focus_follows_mouse)mode); + fDefaultsButton->SetEnabled(fSettings.IsDefaultable()); + fRevertButton->SetEnabled(fSettings.IsRevertable()); + } + break; + } + + case kMsgAcceptFirstClick: + { + BHandler *handler; + if (message->FindPointer("source", + reinterpret_cast(&handler)) == B_OK) { + bool acceptFirstClick = false; + BCheckBox *acceptFirstClickBox = + dynamic_cast(handler); + if (acceptFirstClickBox) + acceptFirstClick = acceptFirstClickBox->Value() + == B_CONTROL_ON; + fSettings.SetAcceptFirstClick(acceptFirstClick); + fDefaultsButton->SetEnabled(fSettings.IsDefaultable()); + fRevertButton->SetEnabled(fSettings.IsRevertable()); + } + break; + } + + case kMsgDoubleClickSpeed: + { + int32 value; + if (message->FindInt32("be:value", &value) == B_OK) { + // slow = 1000000, fast = 0 + fSettings.SetClickSpeed(value * 1000); + fDefaultsButton->SetEnabled(fSettings.IsDefaultable()); + fRevertButton->SetEnabled(fSettings.IsRevertable()); + } + break; + } + + case kMsgMouseSpeed: + { + int32 value; + if (message->FindInt32("be:value", &value) == B_OK) { + // slow = 8192, fast = 524287 + fSettings.SetMouseSpeed((int32)pow(2, + value * 6.0 / 1000) * 8192); + fDefaultsButton->SetEnabled(fSettings.IsDefaultable()); + fRevertButton->SetEnabled(fSettings.IsRevertable()); + } + break; + } + + case kMsgAccelerationFactor: + { + int32 value; + if (message->FindInt32("be:value", &value) == B_OK) { + // slow = 0, fast = 262144 + fSettings.SetAccelerationFactor((int32)pow( + value * 4.0 / 1000, 2) * 16384); + fDefaultsButton->SetEnabled(fSettings.IsDefaultable()); + fRevertButton->SetEnabled(fSettings.IsRevertable()); + } + break; + } + + case kMsgMouseMap: + { + int32 index; + int32 button; + if (message->FindInt32("index", &index) == B_OK + && message->FindInt32("button", &button) == B_OK) { + int32 mapping = B_PRIMARY_MOUSE_BUTTON; + switch (index) { + case 1: + mapping = B_SECONDARY_MOUSE_BUTTON; + break; + case 2: + mapping = B_TERTIARY_MOUSE_BUTTON; + break; + } + + fSettings.SetMapping(button, mapping); + fDefaultsButton->SetEnabled(fSettings.IsDefaultable()); + fRevertButton->SetEnabled(fSettings.IsRevertable()); + fSettingsView->MouseMapUpdated(); + } + break; + } + } +} \ No newline at end of file diff --git a/src/preferences/input/InputMouse.h b/src/preferences/input/InputMouse.h new file mode 100644 index 0000000000..ba56a4a18b --- /dev/null +++ b/src/preferences/input/InputMouse.h @@ -0,0 +1,54 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur +*/ + + +#ifndef INPUT_MOUSE_H +#define INPUT_MOUSE_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "InputWindow.h" +#include "MouseSettings.h" +#include "MouseView.h" +#include "SettingsView.h" + +#define MOUSE_SETTINGS 'Mss' + + +class BTabView; + +class InputMouse : public BView { +public: + InputMouse(); + virtual ~InputMouse(); + void SetMouseType(int32 type); + void MessageReceived(BMessage* message); +private: + + typedef BBox inherited; + + SettingsView* fSettingsView; + MouseView* fMouseView; + BButton* fDefaultsButton; + BButton* fRevertButton; + MouseSettings fSettings; + + mouse_settings fMouseSettings, fOriginalSettings; +}; + +#endif /* INPUT_MOUSE_H */ \ No newline at end of file diff --git a/src/preferences/input/InputTouchpadPref.cpp b/src/preferences/input/InputTouchpadPref.cpp new file mode 100644 index 0000000000..94dcbf1281 --- /dev/null +++ b/src/preferences/input/InputTouchpadPref.cpp @@ -0,0 +1,186 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur +*/ + + +#include "InputTouchpadPref.h" + +#include +#include +#include +#include + +#include + + +TouchpadPref::TouchpadPref() +{ + fConnected = false; + // default center position + fWindowPosition.x = -1; + fWindowPosition.y = -1; + + ConnectToTouchPad(); + + if (LoadSettings() != B_OK) + Defaults(); + + fStartSettings = fSettings; +} + + +TouchpadPref::~TouchpadPref() +{ + if (fConnected) + delete fTouchPad; + + SaveSettings(); +} + + +void +TouchpadPref::Revert() +{ + fSettings = fStartSettings; +} + + +status_t +TouchpadPref::UpdateSettings() +{ + if (!fConnected) + return B_ERROR; + + LOG("UpdateSettings of device %s\n", fTouchPad->Name()); + + BMessage msg; + msg.AddBool("scroll_twofinger", fSettings.scroll_twofinger); + msg.AddBool("scroll_twofinger_horizontal", + fSettings.scroll_twofinger_horizontal); + msg.AddFloat("scroll_rightrange", fSettings.scroll_rightrange); + msg.AddFloat("scroll_bottomrange", fSettings.scroll_bottomrange); + msg.AddInt16("scroll_xstepsize", fSettings.scroll_xstepsize); + msg.AddInt16("scroll_ystepsize", fSettings.scroll_ystepsize); + msg.AddInt8("scroll_acceleration", fSettings.scroll_acceleration); + msg.AddInt8("tapgesture_sensibility", fSettings.tapgesture_sensibility); + + return fTouchPad->Control(MS_SET_TOUCHPAD_SETTINGS, &msg); +} + + +void +TouchpadPref::Defaults() +{ + fSettings = kDefaultTouchpadSettings; +} + + +status_t +TouchpadPref::GetSettingsPath(BPath &path) +{ + status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + if (status < B_OK) + return status; + + return path.Append(TOUCHPAD_SETTINGS_FILE); +} + + +status_t +TouchpadPref::LoadSettings() +{ + BPath path; + status_t status = GetSettingsPath(path); + if (status != B_OK) + return status; + + BFile settingsFile(path.Path(), B_READ_ONLY); + status = settingsFile.InitCheck(); + if (status != B_OK) + return status; + + if (settingsFile.Read(&fSettings, sizeof(touchpad_settings)) + != sizeof(touchpad_settings)) { + LOG("failed to load settings\n"); + return B_ERROR; + } + + if (settingsFile.Read(&fWindowPosition, sizeof(BPoint)) + != sizeof(BPoint)) { + LOG("failed to load settings\n"); + return B_ERROR; + } + + return B_OK; +} + + +status_t +TouchpadPref::SaveSettings() +{ + BPath path; + status_t status = GetSettingsPath(path); + if (status != B_OK) + return status; + + BFile settingsFile(path.Path(), B_READ_WRITE | B_CREATE_FILE); + status = settingsFile.InitCheck(); + if (status != B_OK) + return status; + + if (settingsFile.Write(&fSettings, sizeof(touchpad_settings)) + != sizeof(touchpad_settings)) { + LOG("can't save settings\n"); + return B_ERROR; + } + + if (settingsFile.Write(&fWindowPosition, sizeof(BPoint)) + != sizeof(BPoint)) { + LOG("can't save window position\n"); + return B_ERROR; + } + + return B_OK; +} + + +status_t +TouchpadPref::ConnectToTouchPad() +{ + BList devList; + status_t status = get_input_devices(&devList); + if (status != B_OK) + return status; + + int32 i = 0; + while (true) { + BInputDevice* dev = (BInputDevice*)devList.ItemAt(i); + if (dev == NULL) + break; + i++; + + LOG("input device %s\n", dev->Name()); + + BString name = dev->Name(); + + if (name.FindFirst("Touchpad") >= 0 + && dev->Type() == B_POINTING_DEVICE + && !fConnected) { + fConnected = true; + fTouchPad = dev; + // Don't bail out here, since we need to delete the other devices + // yet. + } else { + delete dev; + } + } + if (fConnected) + return B_OK; + + LOG("touchpad input device NOT found\n"); + return B_ENTRY_NOT_FOUND; +} \ No newline at end of file diff --git a/src/preferences/input/InputTouchpadPref.h b/src/preferences/input/InputTouchpadPref.h new file mode 100644 index 0000000000..fca25a44cd --- /dev/null +++ b/src/preferences/input/InputTouchpadPref.h @@ -0,0 +1,62 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur +*/ + + +#ifndef TOUCHPAD_PREF_H +#define TOUCHPAD_PREF_H + + +#include + +#include "touchpad_settings.h" +#include +#include + +#if DEBUG +# define LOG(text...) PRINT((text)) +#else +# define LOG(text...) +#endif + + +class TouchpadPref { +public: + TouchpadPref(); + ~TouchpadPref(); + + void Revert(); + void Defaults(); + + BPoint WindowPosition() + { return fWindowPosition; } + void SetWindowPosition(BPoint position) + { fWindowPosition = position; } + + touchpad_settings& Settings() + { return fSettings; } + bool IsTouchpadConnected() + { return fConnected; } + status_t UpdateSettings(); + +private: + status_t GetSettingsPath(BPath& path); + status_t LoadSettings(); + status_t SaveSettings(); + + status_t ConnectToTouchPad(); + + bool fConnected; + BInputDevice* fTouchPad; + + touchpad_settings fSettings; + touchpad_settings fStartSettings; + BPoint fWindowPosition; +}; + + +#endif // TOUCHPAD_PREF_H diff --git a/src/preferences/input/InputTouchpadPrefView.cpp b/src/preferences/input/InputTouchpadPrefView.cpp new file mode 100644 index 0000000000..80a66e2d34 --- /dev/null +++ b/src/preferences/input/InputTouchpadPrefView.cpp @@ -0,0 +1,507 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur + */ + + +#include "InputTouchpadPrefView.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +const uint32 SCROLL_X_DRAG = 'sxdr'; +const uint32 SCROLL_Y_DRAG = 'sydr'; + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "TouchpadPrefView" + + +TouchpadView::TouchpadView(BRect frame) + : + BView(frame, "TouchpadView", B_FOLLOW_NONE, B_WILL_DRAW) +{ + fXTracking = false; + fYTracking = false; + fOffScreenView = NULL; + fOffScreenBitmap = NULL; + + fPrefRect = frame; + fPadRect = fPrefRect; + fPadRect.InsetBy(10, 10); + fXScrollRange = fPadRect.Width(); + fYScrollRange = fPadRect.Height(); + +} + + +TouchpadView::~TouchpadView() +{ + delete fOffScreenBitmap; +} + + +void +TouchpadView::Draw(BRect updateRect) +{ + DrawSliders(); +} + + +void +TouchpadView::MouseDown(BPoint point) +{ + if (fXScrollDragZone.Contains(point)) { + fXTracking = true; + fOldXScrollRange = fXScrollRange; + SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); + } + + if (fYScrollDragZone.Contains(point)) { + fYTracking = true; + fOldYScrollRange = fYScrollRange; + SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); + } +} + + +void +TouchpadView::MouseUp(BPoint point) +{ + if (!fXTracking && !fYTracking) + return; + + fXTracking = false; + fYTracking = false; + + const float kSoftScrollLimit = 0.7; + + int32 result = 0; + if (GetRightScrollRatio() > kSoftScrollLimit + || GetBottomScrollRatio() > kSoftScrollLimit) { + BAlert* alert = new BAlert(B_TRANSLATE("Please confirm"), + B_TRANSLATE("The new scroll area is very large and may impede " + "normal mouse operation. Do you really want to change it?"), + B_TRANSLATE("OK"), B_TRANSLATE("Cancel"), + NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); + alert->SetShortcut(1, B_ESCAPE); + result = alert->Go(); + } + + if (result == 0) { + BMessage msg(SCROLL_AREA_CHANGED); + Invoke(&msg); + } else { + if (GetRightScrollRatio() > kSoftScrollLimit) + fXScrollRange = fOldXScrollRange; + if (GetBottomScrollRatio() > kSoftScrollLimit) + fYScrollRange = fOldYScrollRange; + DrawSliders(); + } +} + + +void +TouchpadView::AttachedToWindow() +{ + if (!fOffScreenView) + fOffScreenView = new BView(Bounds(), "", B_FOLLOW_ALL, B_WILL_DRAW); + + if (!fOffScreenBitmap) { + fOffScreenBitmap = new BBitmap(Bounds(), B_CMAP8, true, false); + + if (fOffScreenBitmap && fOffScreenView) + fOffScreenBitmap->AddChild(fOffScreenView); + } +} + + +void +TouchpadView::SetValues(float rightRange, float bottomRange) +{ + fXScrollRange = fPadRect.Width() * (1 - rightRange); + fYScrollRange = fPadRect.Height() * (1 - bottomRange); + Invalidate(); +} + + +void +TouchpadView::GetPreferredSize(float* width, float* height) +{ + if (width != NULL) + *width = fPrefRect.Width(); + if (height != NULL) + *height = fPrefRect.Height(); +} + + +void +TouchpadView::MouseMoved(BPoint point, uint32 transit, const BMessage* message) +{ + if (fXTracking) { + if (point.x > fPadRect.right) + fXScrollRange = fPadRect.Width(); + else if (point.x < fPadRect.left) + fXScrollRange = 0; + else + fXScrollRange = point.x - fPadRect.left; + + DrawSliders(); + } + + if (fYTracking) { + if (point.y > fPadRect.bottom) + fYScrollRange = fPadRect.Height(); + else if (point.y < fPadRect.top) + fYScrollRange = 0; + else + fYScrollRange = point.y - fPadRect.top; + + DrawSliders(); + } +} + + + +void +TouchpadView::DrawSliders() +{ + BView* view = fOffScreenView != NULL ? fOffScreenView : this; + + if (!LockLooper()) + return; + + if (fOffScreenBitmap->Lock()) { + view->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + view->FillRect(Bounds()); + view->SetHighColor(100, 100, 100); + view->FillRoundRect(fPadRect, 4, 4); + + int32 dragSize = 3; // half drag size + + // scroll areas + view->SetHighColor(145, 100, 100); + BRect rightRect(fPadRect.left + fXScrollRange, fPadRect.top, + fPadRect.right, fPadRect.bottom); + view->FillRoundRect(rightRect, 4, 4); + + BRect bottomRect(fPadRect.left, fPadRect.top + fYScrollRange, + fPadRect.right, fPadRect.bottom); + view->FillRoundRect(bottomRect, 4, 4); + + // Stroke Rect + view->SetHighColor(100, 100, 100); + view->SetPenSize(2); + view->StrokeRoundRect(fPadRect, 4, 4); + + // x scroll range line + view->SetHighColor(200, 0, 0); + view->StrokeLine(BPoint(fPadRect.left + fXScrollRange, fPadRect.top), + BPoint(fPadRect.left + fXScrollRange, fPadRect.bottom)); + + fXScrollDragZone = BRect(fPadRect.left + fXScrollRange - dragSize, + fPadRect.top - dragSize, fPadRect.left + fXScrollRange + dragSize, + fPadRect.bottom + dragSize); + BRect xscrollDragZone1 = BRect(fPadRect.left + fXScrollRange - dragSize, + fPadRect.top - dragSize, fPadRect.left + fXScrollRange + dragSize, + fPadRect.top + dragSize); + view->FillRect(xscrollDragZone1); + BRect xscrollDragZone2 = BRect(fPadRect.left + fXScrollRange - dragSize, + fPadRect.bottom - dragSize, + fPadRect.left + fXScrollRange + dragSize, + fPadRect.bottom + dragSize); + view->FillRect(xscrollDragZone2); + + // y scroll range line + view->StrokeLine(BPoint(fPadRect.left, fPadRect.top + fYScrollRange), + BPoint(fPadRect.right, fPadRect.top + fYScrollRange)); + + fYScrollDragZone = BRect(fPadRect.left - dragSize, + fPadRect.top + fYScrollRange - dragSize, + fPadRect.right + dragSize, + fPadRect.top + fYScrollRange + dragSize); + BRect yscrollDragZone1 = BRect(fPadRect.left - dragSize, + fPadRect.top + fYScrollRange - dragSize, fPadRect.left + dragSize, + fPadRect.top + fYScrollRange + dragSize); + view->FillRect(yscrollDragZone1); + BRect yscrollDragZone2 = BRect(fPadRect.right - dragSize, + fPadRect.top + fYScrollRange - dragSize, fPadRect.right + dragSize, + fPadRect.top + fYScrollRange + dragSize); + view->FillRect(yscrollDragZone2); + + view->Sync(); + fOffScreenBitmap->Unlock(); + DrawBitmap(fOffScreenBitmap, B_ORIGIN); + } + + UnlockLooper(); +} + + +// #pragma mark - TouchpadPrefView + + +TouchpadPrefView::TouchpadPrefView(const char* name) + : + BGroupView(name) +{ + SetupView(); + // set view values + SetValues(&fTouchpadPref.Settings()); + if (fTouchpadPref.IsTouchpadConnected() == false) { + DisablePref(); + fShowWarning->SetText(B_TRANSLATE("No touchpad found, the settings " + "will have no effect.")); + } + else + fShowWarning->Hide(); +} + + +TouchpadPrefView::~TouchpadPrefView() +{ +} + + +void +TouchpadPrefView::MessageReceived(BMessage* message) +{ + touchpad_settings& settings = fTouchpadPref.Settings(); + + switch (message->what) { + case SCROLL_AREA_CHANGED: + settings.scroll_rightrange = fTouchpadView->GetRightScrollRatio(); + settings.scroll_bottomrange = fTouchpadView->GetBottomScrollRatio(); + fTouchpadPref.UpdateSettings(); + break; + + case SCROLL_CONTROL_CHANGED: + settings.scroll_twofinger = fTwoFingerBox->Value() == B_CONTROL_ON; + settings.scroll_twofinger_horizontal + = fTwoFingerHorizontalBox->Value() == B_CONTROL_ON; + settings.scroll_acceleration = fScrollAccelSlider->Value(); + settings.scroll_xstepsize = (20 - fScrollStepXSlider->Value()) * 3; + settings.scroll_ystepsize = (20 - fScrollStepYSlider->Value()) * 3; + fTwoFingerHorizontalBox->SetEnabled(settings.scroll_twofinger); + fTouchpadPref.UpdateSettings(); + break; + + case TAP_CONTROL_CHANGED: + settings.tapgesture_sensibility = fTapSlider->Value(); + fTouchpadPref.UpdateSettings(); + break; + + case DEFAULT_SETTINGS: + fTouchpadPref.Defaults(); + fRevertButton->SetEnabled(true); + fTouchpadPref.UpdateSettings(); + SetValues(&settings); + break; + + case REVERT_SETTINGS: + fTouchpadPref.Revert(); + fTouchpadPref.UpdateSettings(); + fRevertButton->SetEnabled(false); + SetValues(&settings); + break; + + default: + BView::MessageReceived(message); + } +} + + +void +TouchpadPrefView::AttachedToWindow() +{ + fTouchpadView->SetTarget(this); + fTwoFingerBox->SetTarget(this); + fTwoFingerHorizontalBox->SetTarget(this); + fScrollStepXSlider->SetTarget(this); + fScrollStepYSlider->SetTarget(this); + fScrollAccelSlider->SetTarget(this); + fTapSlider->SetTarget(this); + fDefaultButton->SetTarget(this); + fRevertButton->SetTarget(this); + BSize size = PreferredSize(); + Window()->ResizeTo(size.width, size.height); + + BPoint position = fTouchpadPref.WindowPosition(); + // center window on screen if it had a bad position + if (position.x < 0 && position.y < 0) + Window()->CenterOnScreen(); + else + Window()->MoveTo(position); +} + + +void +TouchpadPrefView::DetachedFromWindow() +{ + fTouchpadPref.SetWindowPosition(Window()->Frame().LeftTop()); +} + + +void +TouchpadPrefView::SetupView() +{ + SetLayout(new BGroupLayout(B_VERTICAL)); + BBox* scrollBox = new BBox("Touchpad"); + scrollBox->SetLabel(B_TRANSLATE("Scrolling")); + + fTouchpadView = new TouchpadView(BRect(0, 0, 130, 120)); + fTouchpadView->SetExplicitMaxSize(BSize(130, 120)); + + // Create the "Mouse Speed" slider... + fScrollAccelSlider = new BSlider("scroll_accel", + B_TRANSLATE("Acceleration"), + new BMessage(SCROLL_CONTROL_CHANGED), 0, 20, B_HORIZONTAL); + fScrollAccelSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fScrollAccelSlider->SetHashMarkCount(7); + fScrollAccelSlider->SetLimitLabels(B_TRANSLATE("Slow"), + B_TRANSLATE("Fast")); + fScrollAccelSlider->SetExplicitMinSize(BSize(150, B_SIZE_UNSET)); + + fScrollStepXSlider = new BSlider("scroll_stepX", + B_TRANSLATE("Horizontal"), + new BMessage(SCROLL_CONTROL_CHANGED), + 0, 20, B_HORIZONTAL); + fScrollStepXSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fScrollStepXSlider->SetHashMarkCount(7); + fScrollStepXSlider->SetLimitLabels(B_TRANSLATE("Slow"), + B_TRANSLATE("Fast")); + + fScrollStepYSlider = new BSlider("scroll_stepY", + B_TRANSLATE("Vertical"), + new BMessage(SCROLL_CONTROL_CHANGED), 0, 20, B_HORIZONTAL); + fScrollStepYSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fScrollStepYSlider->SetHashMarkCount(7); + fScrollStepYSlider->SetLimitLabels(B_TRANSLATE("Slow"), + B_TRANSLATE("Fast")); + + fTwoFingerBox = new BCheckBox(B_TRANSLATE("Two finger scrolling"), + new BMessage(SCROLL_CONTROL_CHANGED)); + fTwoFingerHorizontalBox = new BCheckBox( + B_TRANSLATE("Horizontal scrolling"), + new BMessage(SCROLL_CONTROL_CHANGED)); + + float spacing = be_control_look->DefaultItemSpacing(); + + BView* scrollPrefLeftLayout + = BLayoutBuilder::Group<>(B_VERTICAL, 0) + .Add(fTouchpadView) + .AddStrut(spacing) + .Add(fTwoFingerBox) + .AddGroup(B_HORIZONTAL, 0) + .AddStrut(spacing * 2) + .Add(fTwoFingerHorizontalBox) + .End() + .AddGlue() + .View(); + + BGroupView* scrollPrefRightLayout = new BGroupView(B_VERTICAL); + scrollPrefRightLayout->AddChild(fScrollAccelSlider); + scrollPrefRightLayout->AddChild(fScrollStepXSlider); + scrollPrefRightLayout->AddChild(fScrollStepYSlider); + + BGroupLayout* scrollPrefLayout = new BGroupLayout(B_HORIZONTAL); + scrollPrefLayout->SetSpacing(spacing); + scrollPrefLayout->SetInsets(spacing, + scrollBox->TopBorderOffset() * 2 + spacing, spacing, spacing); + scrollBox->SetLayout(scrollPrefLayout); + + scrollPrefLayout->AddView(scrollPrefLeftLayout); + scrollPrefLayout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(spacing + * 1.5)); + scrollPrefLayout->AddView(scrollPrefRightLayout); + + BBox* tapBox = new BBox("tapbox"); + tapBox->SetLabel(B_TRANSLATE("Tapping")); + + BGroupLayout* tapPrefLayout = new BGroupLayout(B_HORIZONTAL); + tapPrefLayout->SetInsets(spacing, tapBox->TopBorderOffset() * 2 + spacing, + spacing, spacing); + tapBox->SetLayout(tapPrefLayout); + + fTapSlider = new BSlider("tap_sens", B_TRANSLATE("Sensitivity"), + new BMessage(TAP_CONTROL_CHANGED), 0, spacing * 2, B_HORIZONTAL); + fTapSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fTapSlider->SetHashMarkCount(7); + fTapSlider->SetLimitLabels(B_TRANSLATE("Off"), B_TRANSLATE("High")); + + tapPrefLayout->AddView(fTapSlider); + + fDefaultButton = new BButton(B_TRANSLATE("Defaults"), + new BMessage(DEFAULT_SETTINGS)); + + fRevertButton = new BButton(B_TRANSLATE("Revert"), + new BMessage(REVERT_SETTINGS)); + fRevertButton->SetEnabled(false); + + fShowWarning = new BStringView("warning", ""); + + BLayoutBuilder::Group<>(this, B_VERTICAL) + .SetInsets(B_USE_WINDOW_SPACING) + .Add(fShowWarning) + .Add(scrollBox) + .Add(tapBox) + .Add(new BSeparatorView(B_HORIZONTAL)) + .AddGroup(B_HORIZONTAL) + .Add(fDefaultButton) + .Add(fRevertButton) + .AddGlue() + .End() + .End(); +} + + +void +TouchpadPrefView::SetValues(touchpad_settings* settings) +{ + fTouchpadView->SetValues(settings->scroll_rightrange, + settings->scroll_bottomrange); + fTwoFingerBox->SetValue(settings->scroll_twofinger + ? B_CONTROL_ON : B_CONTROL_OFF); + fTwoFingerHorizontalBox->SetValue(settings->scroll_twofinger_horizontal + ? B_CONTROL_ON : B_CONTROL_OFF); + fTwoFingerHorizontalBox->SetEnabled(settings->scroll_twofinger); + fScrollStepXSlider->SetValue(20 - settings->scroll_xstepsize / 2); + fScrollStepYSlider->SetValue(20 - settings->scroll_ystepsize / 2); + fScrollAccelSlider->SetValue(settings->scroll_acceleration); + fTapSlider->SetValue(settings->tapgesture_sensibility); +} + + +void +TouchpadPrefView::DisablePref() +{ + fTwoFingerBox->SetEnabled(false); + fTwoFingerHorizontalBox->SetEnabled(false); + fTapSlider->SetEnabled(false); + fScrollAccelSlider->SetEnabled(false); + fScrollStepXSlider->SetEnabled(false); + fScrollStepYSlider->SetEnabled(false); +} \ No newline at end of file diff --git a/src/preferences/input/InputTouchpadPrefView.h b/src/preferences/input/InputTouchpadPrefView.h new file mode 100644 index 0000000000..18fe7d728b --- /dev/null +++ b/src/preferences/input/InputTouchpadPrefView.h @@ -0,0 +1,106 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur + */ + + +#ifndef TOUCHPAD_PREF_VIEW_H +#define TOUCHPAD_PREF_VIEW_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "InputTouchpadPref.h" +#include "touchpad_settings.h" + +#include + +#if DEBUG +# define LOG(text...) PRINT((text)) +#else +# define LOG(text...) +#endif + +const uint SCROLL_AREA_CHANGED = '&sac'; +const uint SCROLL_CONTROL_CHANGED = '&scc'; +const uint TAP_CONTROL_CHANGED = '&tcc'; +const uint DEFAULT_SETTINGS = '&dse'; +const uint REVERT_SETTINGS = '&rse'; + + +//! Shows a touchpad +class TouchpadView : public BView, public BInvoker { +public: + TouchpadView(BRect frame); + virtual ~TouchpadView(); + virtual void Draw(BRect updateRect); + virtual void MouseDown(BPoint point); + virtual void MouseUp(BPoint point); + virtual void MouseMoved(BPoint point, uint32 transit, + const BMessage* dragMessage); + + virtual void AttachedToWindow(); + virtual void GetPreferredSize(float* width, float* height); + + void SetValues(float rightRange, float bottomRange); + float GetRightScrollRatio() + { return 1 - fXScrollRange / fPadRect.Width(); } + float GetBottomScrollRatio() + { return 1 + - fYScrollRange / fPadRect.Height(); } +private: + virtual void DrawSliders(); + + BRect fPrefRect; + BRect fPadRect; + BRect fXScrollDragZone; + float fXScrollRange; + float fOldXScrollRange; + BRect fYScrollDragZone; + float fYScrollRange; + float fOldYScrollRange; + + bool fXTracking; + bool fYTracking; + BView* fOffScreenView; + BBitmap* fOffScreenBitmap; +}; + + +class TouchpadPrefView : public BGroupView { +public: + TouchpadPrefView(const char* name); + virtual ~TouchpadPrefView(); + virtual void MessageReceived(BMessage* message); + virtual void AttachedToWindow(); + virtual void DetachedFromWindow(); + void SetupView(); + + void SetValues(touchpad_settings *settings); + TouchpadPref fTouchpadPref; + +private: + void DisablePref(); + + TouchpadView* fTouchpadView; + BCheckBox* fTwoFingerBox; + BCheckBox* fTwoFingerHorizontalBox; + BSlider* fScrollStepXSlider; + BSlider* fScrollStepYSlider; + BSlider* fScrollAccelSlider; + BSlider* fTapSlider; + BButton* fDefaultButton; + BButton* fRevertButton; + BStringView* fShowWarning; +}; + +#endif // TOUCHPAD_PREF_VIEW_H \ No newline at end of file diff --git a/src/preferences/input/InputWindow.cpp b/src/preferences/input/InputWindow.cpp new file mode 100644 index 0000000000..d47f7f6196 --- /dev/null +++ b/src/preferences/input/InputWindow.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "InputWindow.h" +#include "InputDeviceView.h" +#include "MouseSettings.h" +#include "InputMouse.h" +#include "InputConstants.h" +#include "SettingsView.h" +#include "InputTouchpadPref.h" + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "InputWindow" + + +InputWindow::InputWindow(BRect _rect) + : + BWindow(_rect, B_TRANSLATE_SYSTEM_NAME("Input"), B_TITLED_WINDOW, + B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS + | B_AUTO_UPDATE_SIZE_LIMITS | B_QUIT_ON_WINDOW_CLOSE) +{ + fInputMouse = new InputMouse(); + fTouchpadPrefView = new TouchpadPrefView(B_TRANSLATE("Touchpad")); + fDeviceListView = new DeviceListView(B_TRANSLATE("Device List")); + + fCardView = new BCardView(); + fCardView->AddChild(fInputMouse); + fCardView->AddChild(fTouchpadPrefView); + + BLayoutBuilder::Group<>(this, B_HORIZONTAL, 10) + .Add(fDeviceListView) + .AddGroup(B_VERTICAL,0) + .Add(fCardView) + .End(); +} + +void +InputWindow::MessageReceived(BMessage* message) +{ + int32 name = message->GetInt32("index", 0); + + switch (message->what) { + + case ITEM_SELECTED: + { + fCardView->CardLayout()->SetVisibleItem(name); + } + case kMsgMouseType: + case kMsgMouseMap: + case kMsgMouseFocusMode: + case kMsgFollowsMouseMode: + case kMsgAcceptFirstClick: + case kMsgDoubleClickSpeed: + case kMsgMouseSpeed: + case kMsgAccelerationFactor: + case kMsgDefaults: + case kMsgRevert: + { + PostMessage(message, fInputMouse); + break; + } + case SCROLL_AREA_CHANGED: + case SCROLL_CONTROL_CHANGED: + case TAP_CONTROL_CHANGED: + case DEFAULT_SETTINGS: + case REVERT_SETTINGS: + { + PostMessage(message, fTouchpadPrefView); + break; + } + default: + BWindow::MessageReceived(message); + break; + } +} diff --git a/src/preferences/input/InputWindow.h b/src/preferences/input/InputWindow.h new file mode 100644 index 0000000000..e76f1144d8 --- /dev/null +++ b/src/preferences/input/InputWindow.h @@ -0,0 +1,59 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur + */ + + +#ifndef INPUT_WINDOW_H +#define INPUT_WINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MouseSettings.h" +#include "InputMouse.h" +#include "InputTouchpadPrefView.h" +#include "touchpad_settings.h" + + +class BSplitView; +class BCardView; +class BCardLayout; + +class DeviceListView; +class SettingsView; +class DeviceName; +class TouchpadPrefView; +class TouchpadPref; +class TouchpadView; +class InputDevices; +class InputMouse; + + +class InputWindow : public BWindow +{ +public: + InputWindow(BRect rect); + void MessageReceived(BMessage* message); +private: + DeviceListView* fDeviceListView; + BCardView* fCardView; + MouseSettings fSettings; + SettingsView* fSettingsView; + InputMouse* fInputMouse; + TouchpadPrefView* fTouchpadPrefView; + TouchpadPref* fTouchpadPref; +}; + +#endif /* INPUT_WINDOW_H */ diff --git a/src/preferences/input/Jamfile b/src/preferences/input/Jamfile new file mode 100644 index 0000000000..6c1025ed70 --- /dev/null +++ b/src/preferences/input/Jamfile @@ -0,0 +1,29 @@ +SubDir HAIKU_TOP src preferences input ; + +UsePrivateHeaders input ; + +Preference Input : + Input.cpp + InputWindow.cpp + InputDeviceView.cpp + InputTouchpadPref.cpp + InputTouchpadPrefView.cpp + InputMouse.cpp + MouseView.cpp + MouseSettings.cpp + SettingsView.cpp + : be [ TargetLibsupc++ ] localestub + ; +DoCatalogs Input : + x-vnd.Haiku-Input + : + Input.cpp + InputWindow.cpp + InputDeviceView.cpp + InputTouchpadPref.cpp + InputTouchpadPrefView.cpp + InputMouse.cpp + MouseView.cpp + MouseSettings.cpp + SettingsView.cpp +; diff --git a/src/preferences/input/MouseSettings.cpp b/src/preferences/input/MouseSettings.cpp new file mode 100644 index 0000000000..ddfaff4b24 --- /dev/null +++ b/src/preferences/input/MouseSettings.cpp @@ -0,0 +1,370 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur +*/ + + +#include +#include +#include +#include + +#include + +#include "MouseSettings.h" + +// The R5 settings file differs from that of OpenBeOS; +// the latter maps 16 different mouse buttons +#define R5_COMPATIBLE 1 + +static const bigtime_t kDefaultClickSpeed = 500000; +static const int32 kDefaultMouseSpeed = 65536; +static const int32 kDefaultMouseType = 3; // 3 button mouse +static const int32 kDefaultAccelerationFactor = 65536; +static const bool kDefaultAcceptFirstClick = false; + + +MouseSettings::MouseSettings() + : + fWindowPosition(-1, -1) +{ + _RetrieveSettings(); + + fOriginalSettings = fSettings; + fOriginalMode = fMode; + fOriginalFocusFollowsMouseMode = fFocusFollowsMouseMode; + fOriginalAcceptFirstClick = fAcceptFirstClick; +} + + +MouseSettings::~MouseSettings() +{ + _SaveSettings(); +} + + +status_t +MouseSettings::_GetSettingsPath(BPath &path) +{ + status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + if (status < B_OK) + return status; + + path.Append(mouse_settings_file); + return B_OK; +} + + +void +MouseSettings::_RetrieveSettings() +{ + // retrieve current values + + if (get_mouse_map(&fSettings.map) != B_OK) + fprintf(stderr, "error when get_mouse_map\n"); + if (get_click_speed(&fSettings.click_speed) != B_OK) + fprintf(stderr, "error when get_click_speed\n"); + if (get_mouse_speed(&fSettings.accel.speed) != B_OK) + fprintf(stderr, "error when get_mouse_speed\n"); + if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK) + fprintf(stderr, "error when get_mouse_acceleration\n"); + if (get_mouse_type(&fSettings.type) != B_OK) + fprintf(stderr, "error when get_mouse_type\n"); + + fMode = mouse_mode(); + fFocusFollowsMouseMode = focus_follows_mouse_mode(); + fAcceptFirstClick = accept_first_click(); + + // also try to load the window position from disk + + BPath path; + if (_GetSettingsPath(path) < B_OK) + return; + + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() < B_OK) + return; + +#if R5_COMPATIBLE + const off_t kOffset = sizeof(mouse_settings) - sizeof(mouse_map) + + sizeof(int32) * 3; + // we have to do this because mouse_map counts 16 buttons in OBOS +#else + const off_t kOffset = sizeof(mouse_settings); +#endif + + if (file.ReadAt(kOffset, &fWindowPosition, sizeof(BPoint)) + != sizeof(BPoint)) { + // set default window position (invalid positions will be + // corrected by the application; the window will be centered + // in this case) + fWindowPosition.x = -1; + fWindowPosition.y = -1; + } + +#ifdef DEBUG + Dump(); +#endif +} + + +status_t +MouseSettings::_SaveSettings() +{ + BPath path; + status_t status = _GetSettingsPath(path); + if (status < B_OK) + return status; + + BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE); + status = file.InitCheck(); + if (status < B_OK) + return status; + +#if R5_COMPATIBLE + const off_t kOffset = sizeof(mouse_settings) - sizeof(mouse_map) + + sizeof(int32) * 3; + // we have to do this because mouse_map counts 16 buttons in OBOS +#else + const off_t kOffset = sizeof(mouse_settings); +#endif + + file.WriteAt(kOffset, &fWindowPosition, sizeof(BPoint)); + + return B_OK; +} + + +#ifdef DEBUG +void +MouseSettings::Dump() +{ + printf("type:\t\t%" B_PRId32 " button mouse\n", fSettings.type); + printf("map:\t\tleft = %" B_PRIu32 " : middle = %" B_PRIu32 " : right = %" + B_PRIu32 "\n", fSettings.map.button[0], fSettings.map.button[2], + fSettings.map.button[1]); + printf("click speed:\t%" B_PRId64 "\n", fSettings.click_speed); + printf("accel:\t\t%s\n", fSettings.accel.enabled ? "enabled" : "disabled"); + printf("accel factor:\t%" B_PRId32 "\n", fSettings.accel.accel_factor); + printf("speed:\t\t%" B_PRId32 "\n", fSettings.accel.speed); + + const char *mode = "unknown"; + switch (fMode) { + case B_NORMAL_MOUSE: + mode = "click to focus and raise"; + break; + case B_CLICK_TO_FOCUS_MOUSE: + mode = "click to focus"; + break; + case B_FOCUS_FOLLOWS_MOUSE: + mode = "focus follows mouse"; + break; + } + printf("mouse mode:\t%s\n", mode); + + const char *focus_follows_mouse_mode = "unknown"; + switch (fFocusFollowsMouseMode) { + case B_NORMAL_FOCUS_FOLLOWS_MOUSE: + focus_follows_mouse_mode = "normal"; + break; + case B_WARP_FOCUS_FOLLOWS_MOUSE: + focus_follows_mouse_mode = "warp"; + break; + case B_INSTANT_WARP_FOCUS_FOLLOWS_MOUSE: + focus_follows_mouse_mode = "instant warp"; + break; + } + printf("focus follows mouse mode:\t%s\n", focus_follows_mouse_mode); + printf("accept first click:\t%s\n", + fAcceptFirstClick ? "enabled" : "disabled"); +} +#endif + + +// Resets the settings to the system defaults +void +MouseSettings::Defaults() +{ + SetClickSpeed(kDefaultClickSpeed); + SetMouseSpeed(kDefaultMouseSpeed); + SetMouseType(kDefaultMouseType); + SetAccelerationFactor(kDefaultAccelerationFactor); + SetMouseMode(B_NORMAL_MOUSE); + SetFocusFollowsMouseMode(B_NORMAL_FOCUS_FOLLOWS_MOUSE); + SetAcceptFirstClick(kDefaultAcceptFirstClick); + + mouse_map map; + if (get_mouse_map(&map) == B_OK) { + map.button[0] = B_PRIMARY_MOUSE_BUTTON; + map.button[1] = B_SECONDARY_MOUSE_BUTTON; + map.button[2] = B_TERTIARY_MOUSE_BUTTON; + SetMapping(map); + } +} + + +// Checks if the settings are different then the system defaults +bool +MouseSettings::IsDefaultable() +{ + return fSettings.click_speed != kDefaultClickSpeed + || fSettings.accel.speed != kDefaultMouseSpeed + || fSettings.type != kDefaultMouseType + || fSettings.accel.accel_factor != kDefaultAccelerationFactor + || fMode != B_NORMAL_MOUSE + || fFocusFollowsMouseMode != B_NORMAL_FOCUS_FOLLOWS_MOUSE + || fAcceptFirstClick != kDefaultAcceptFirstClick + || fSettings.map.button[0] != B_PRIMARY_MOUSE_BUTTON + || fSettings.map.button[1] != B_SECONDARY_MOUSE_BUTTON + || fSettings.map.button[2] != B_TERTIARY_MOUSE_BUTTON; +} + + +// Reverts to the active settings at program startup +void +MouseSettings::Revert() +{ + SetClickSpeed(fOriginalSettings.click_speed); + SetMouseSpeed(fOriginalSettings.accel.speed); + SetMouseType(fOriginalSettings.type); + SetAccelerationFactor(fOriginalSettings.accel.accel_factor); + SetMouseMode(fOriginalMode); + SetFocusFollowsMouseMode(fOriginalFocusFollowsMouseMode); + SetAcceptFirstClick(fOriginalAcceptFirstClick); + + SetMapping(fOriginalSettings.map); +} + + +// Checks if the settings are different then the original settings +bool +MouseSettings::IsRevertable() +{ + return fSettings.click_speed != fOriginalSettings.click_speed + || fSettings.accel.speed != fOriginalSettings.accel.speed + || fSettings.type != fOriginalSettings.type + || fSettings.accel.accel_factor != fOriginalSettings.accel.accel_factor + || fMode != fOriginalMode + || fFocusFollowsMouseMode != fOriginalFocusFollowsMouseMode + || fAcceptFirstClick != fOriginalAcceptFirstClick + || fSettings.map.button[0] != fOriginalSettings.map.button[0] + || fSettings.map.button[1] != fOriginalSettings.map.button[1] + || fSettings.map.button[2] != fOriginalSettings.map.button[2]; +} + + +void +MouseSettings::SetWindowPosition(BPoint corner) +{ + fWindowPosition = corner; +} + + +void +MouseSettings::SetMouseType(int32 type) +{ + if (set_mouse_type(type) == B_OK) + fSettings.type = type; + else + fprintf(stderr, "error when set_mouse_type\n"); +} + + +bigtime_t +MouseSettings::ClickSpeed() const +{ + return 1000000LL - fSettings.click_speed; + // to correct the Sliders 0-100000 scale +} + + +void +MouseSettings::SetClickSpeed(bigtime_t clickSpeed) +{ + clickSpeed = 1000000LL - clickSpeed; + + if (set_click_speed(clickSpeed) == B_OK) + fSettings.click_speed = clickSpeed; + else + fprintf(stderr, "error when set_click_speed\n"); +} + + +void +MouseSettings::SetMouseSpeed(int32 speed) +{ + if (set_mouse_speed(speed) == B_OK) + fSettings.accel.speed = speed; + else + fprintf(stderr, "error when set_mouse_speed\n"); +} + + +void +MouseSettings::SetAccelerationFactor(int32 factor) +{ + if (set_mouse_acceleration(factor) == B_OK) + fSettings.accel.accel_factor = factor; + else + fprintf(stderr, "error when set_mouse_acceleration\n"); +} + + +uint32 +MouseSettings::Mapping(int32 index) const +{ + return fSettings.map.button[index]; +} + + +void +MouseSettings::Mapping(mouse_map &map) const +{ + map = fSettings.map; +} + + +void +MouseSettings::SetMapping(int32 index, uint32 button) +{ + fSettings.map.button[index] = button; + if (set_mouse_map(&fSettings.map) != B_OK) + fprintf(stderr, "error when set_mouse_map\n"); +} + + +void +MouseSettings::SetMapping(mouse_map &map) +{ + if (set_mouse_map(&map) == B_OK) + fSettings.map = map; + else + fprintf(stderr, "error when set_mouse_map\n"); +} + + +void +MouseSettings::SetMouseMode(mode_mouse mode) +{ + set_mouse_mode(mode); + fMode = mode; +} + + +void +MouseSettings::SetFocusFollowsMouseMode(mode_focus_follows_mouse mode) +{ + set_focus_follows_mouse_mode(mode); + fFocusFollowsMouseMode = mode; +} + + +void +MouseSettings::SetAcceptFirstClick(bool accept_first_click) +{ + set_accept_first_click(accept_first_click); + fAcceptFirstClick = accept_first_click; +} \ No newline at end of file diff --git a/src/preferences/input/MouseSettings.h b/src/preferences/input/MouseSettings.h new file mode 100644 index 0000000000..ef3e6711ca --- /dev/null +++ b/src/preferences/input/MouseSettings.h @@ -0,0 +1,78 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur + */ + + +#ifndef MOUSE_SETTINGS_H +#define MOUSE_SETTINGS_H + + +#include +#include +#include + +#include "kb_mouse_settings.h" + + +class BPath; + +class MouseSettings { +public: + MouseSettings(); + ~MouseSettings(); + + void Revert(); + bool IsRevertable(); + void Defaults(); + bool IsDefaultable(); + void Dump(); + + BPoint WindowPosition() const { return fWindowPosition; } + void SetWindowPosition(BPoint corner); + + int32 MouseType() const { return fSettings.type; } + void SetMouseType(int32 type); + + bigtime_t ClickSpeed() const; + void SetClickSpeed(bigtime_t click_speed); + + int32 MouseSpeed() const { return fSettings.accel.speed; } + void SetMouseSpeed(int32 speed); + + int32 AccelerationFactor() const { return fSettings.accel.accel_factor; } + void SetAccelerationFactor(int32 factor); + + uint32 Mapping(int32 index) const; + void Mapping(mouse_map &map) const; + void SetMapping(int32 index, uint32 button); + void SetMapping(mouse_map &map); + + mode_mouse MouseMode() const { return fMode; } + void SetMouseMode(mode_mouse mode); + + mode_focus_follows_mouse FocusFollowsMouseMode() const { + return fFocusFollowsMouseMode; + } + void SetFocusFollowsMouseMode(mode_focus_follows_mouse mode); + + bool AcceptFirstClick() const { return fAcceptFirstClick; } + void SetAcceptFirstClick(bool accept_first_click); + +private: + static status_t _GetSettingsPath(BPath &path); + void _RetrieveSettings(); + status_t _SaveSettings(); + + mouse_settings fSettings, fOriginalSettings; + mode_mouse fMode, fOriginalMode; + mode_focus_follows_mouse fFocusFollowsMouseMode; + mode_focus_follows_mouse fOriginalFocusFollowsMouseMode; + bool fAcceptFirstClick, fOriginalAcceptFirstClick; + BPoint fWindowPosition; +}; + +#endif // MOUSE_SETTINGS_H \ No newline at end of file diff --git a/src/preferences/input/MouseView.cpp b/src/preferences/input/MouseView.cpp new file mode 100644 index 0000000000..ebf37ca1c7 --- /dev/null +++ b/src/preferences/input/MouseView.cpp @@ -0,0 +1,380 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur +*/ + + +#include "MouseView.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "InputConstants.h" +#include "MouseSettings.h" +#include "InputWindow.h" + + +static const int32 kButtonTop = 3; +static const int32 kMouseDownWidth = 72; +static const int32 kMouseDownHeight = 35; + +static const int32 kOneButtonOffsets[4] + = { 0, kMouseDownWidth }; +static const int32 kTwoButtonOffsets[4] + = { 0, kMouseDownWidth / 2, kMouseDownWidth }; +static const int32 kThreeButtonOffsets[4] + = { 0, kMouseDownWidth / 3 + 1, kMouseDownWidth / 3 * 2, kMouseDownWidth }; + +static const rgb_color kButtonTextColor = { 0, 0, 0, 255 }; +static const rgb_color kMouseShadowColor = { 100, 100, 100, 128 }; +static const rgb_color kMouseBodyTopColor = { 0xed, 0xed, 0xed, 255 }; +static const rgb_color kMouseBodyBottomColor = { 0x85, 0x85, 0x85, 255 }; +static const rgb_color kMouseOutlineColor = { 0x51, 0x51, 0x51, 255 }; +static const rgb_color kMouseButtonOutlineColor = { 0xa0, 0xa0, 0xa0, 255 }; +static const rgb_color kButtonPressedColor = { 110, 110, 110, 110 }; + + +static const int32* +getButtonOffsets(int32 type) +{ + switch (type) { + case 1: + return kOneButtonOffsets; + case 2: + return kTwoButtonOffsets; + case 3: + default: + return kThreeButtonOffsets; + } +} + + +static uint32 +getMappingNumber(int32 mapping) +{ + switch (mapping) { + case B_PRIMARY_MOUSE_BUTTON: + return 0; + case B_SECONDARY_MOUSE_BUTTON: + return 1; + case B_TERTIARY_MOUSE_BUTTON: + return 2; + } + return 0; +} + +MouseView::MouseView(const MouseSettings &settings) + : + BView("Mouse", B_PULSE_NEEDED | B_WILL_DRAW), + fSettings(settings), + fType(-1), + fButtons(0), + fOldButtons(0) +{ + SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); + fScaling = std::max(1.0f, be_plain_font->Size() / 12.0f); +} + + +MouseView::~MouseView() +{ +} + + +void +MouseView::SetMouseType(int32 type) +{ + fType = type; + Invalidate(); +} + + +void +MouseView::MouseMapUpdated() +{ + Invalidate(); +} + + +void +MouseView::UpdateFromSettings() +{ + SetMouseType(fSettings.MouseType()); +} + + +void +MouseView::GetPreferredSize(float* _width, float* _height) +{ + if (_width != NULL) + *_width = fScaling * (kMouseDownWidth + 2); + if (_height != NULL) + *_height = fScaling * 104; +} + + +void +MouseView::AttachedToWindow() +{ + AdoptParentColors(); + + UpdateFromSettings(); + _CreateButtonsPicture(); + + font_height fontHeight; + GetFontHeight(&fontHeight); + fDigitHeight = int32(ceilf(fontHeight.ascent) + ceilf(fontHeight.descent)); + fDigitBaseline = int32(ceilf(fontHeight.ascent)); +} + + +void +MouseView::MouseUp(BPoint) +{ + fButtons = 0; + Invalidate(_ButtonsRect()); + fOldButtons = fButtons; +} + + +void +MouseView::MouseDown(BPoint where) +{ + BMessage *mouseMsg = Window()->CurrentMessage(); + fButtons = mouseMsg->FindInt32("buttons"); + int32 modifiers = mouseMsg->FindInt32("modifiers"); + if (modifiers & B_CONTROL_KEY) { + if (modifiers & B_COMMAND_KEY) + fButtons = B_TERTIARY_MOUSE_BUTTON; + else + fButtons = B_SECONDARY_MOUSE_BUTTON; + } + + // Get the current clipping region before requesting any updates. + // Otherwise those parts would be excluded from the region. + BRegion clipping; + GetClippingRegion(&clipping); + + if (fOldButtons != fButtons) { + Invalidate(_ButtonsRect()); + fOldButtons = fButtons; + } + + const int32* offset = getButtonOffsets(fType); + int32 button = -1; + for (int32 i = 0; i <= fType; i++) { + if (_ButtonRect(offset, i).Contains(where)) { + button = i; + break; + } + } + if (button < 0) + return; + + if (clipping.Contains(where)) { + button = _ConvertFromVisualOrder(button); + + BPopUpMenu menu("Mouse Map Menu"); + BMessage message(kMsgMouseMap); + message.AddInt32("button", button); + + menu.AddItem(new BMenuItem("1", new BMessage(message))); + menu.AddItem(new BMenuItem("2", new BMessage(message))); + menu.AddItem(new BMenuItem("3", new BMessage(message))); + + menu.ItemAt(getMappingNumber(fSettings.Mapping(button))) + ->SetMarked(true); + menu.SetTargetForItems(Window()); + + ConvertToScreen(&where); + menu.Go(where, true); + } +} + + +void +MouseView::Draw(BRect updateFrame) +{ + SetDrawingMode(B_OP_ALPHA); + SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + SetScale(fScaling * 1.8); + + BShape mouseShape; + mouseShape.MoveTo(BPoint(16, 12)); + // left + BPoint control[3] = { BPoint(12, 16), BPoint(8, 64), BPoint(32, 64) }; + mouseShape.BezierTo(control); + // right + BPoint control2[3] = { BPoint(56, 64), BPoint(52, 16), BPoint(48, 12) }; + mouseShape.BezierTo(control2); + // top + BPoint control3[3] = { BPoint(44, 8), BPoint(20, 8), BPoint(16, 12) }; + mouseShape.BezierTo(control3); + mouseShape.Close(); + + // Draw the shadow + SetOrigin(-17 * fScaling, -11 * fScaling); + SetHighColor(kMouseShadowColor); + FillShape(&mouseShape, B_SOLID_HIGH); + + // Draw the body + SetOrigin(-21 * fScaling, -14 * fScaling); + BGradientRadial bodyGradient(28, 24, 128); + bodyGradient.AddColor(kMouseBodyTopColor, 0); + bodyGradient.AddColor(kMouseBodyBottomColor, 255); + + FillShape(&mouseShape, bodyGradient); + + // Draw the outline + SetPenSize(1 / 1.8 / fScaling); + SetDrawingMode(B_OP_OVER); + SetHighColor(kMouseOutlineColor); + + StrokeShape(&mouseShape, B_SOLID_HIGH); + + // bottom button border + BShape buttonsOutline; + buttonsOutline.MoveTo(BPoint(13, 27)); + BPoint control4[] = { BPoint(18, 30), BPoint(46, 30), BPoint(51, 27) }; + buttonsOutline.BezierTo(control4); + + SetHighColor(kMouseButtonOutlineColor); + StrokeShape(&buttonsOutline, B_SOLID_HIGH); + + SetScale(1); + SetOrigin(0, 0); + + // Separator between the buttons + const int32* offset = getButtonOffsets(fType); + for (int32 i = 1; i < fType; i++) { + BRect buttonRect = _ButtonRect(offset, i); + StrokeLine(buttonRect.LeftTop(), buttonRect.LeftBottom()); + } + + mouse_map map; + fSettings.Mapping(map); + + SetDrawingMode(B_OP_OVER); + + if (fButtons != 0) + ClipToPicture(&fButtonsPicture, B_ORIGIN, false); + + for (int32 i = 0; i < fType; i++) { + // draw mapping number centered over the button + + bool pressed = (fButtons & map.button[_ConvertFromVisualOrder(i)]) != 0; + // is button currently pressed? + if (pressed) { + SetDrawingMode(B_OP_ALPHA); + SetHighColor(kButtonPressedColor); + FillRect(_ButtonRect(offset, i)); + } + + BRect border(fScaling * (offset[i] + 1), fScaling * (kButtonTop + 5), + fScaling * offset[i + 1] - 1, + fScaling * (kButtonTop + kMouseDownHeight - 4)); + if (i == 0) + border.left += fScaling * 5; + if (i == fType - 1) + border.right -= fScaling * 4; + + char number[2] = {0}; + number[0] = getMappingNumber(map.button[_ConvertFromVisualOrder(i)]) + + '1'; + + SetDrawingMode(B_OP_OVER); + SetHighColor(kButtonTextColor); + DrawString(number, BPoint( + border.left + (border.Width() - StringWidth(number)) / 2, + border.top + fDigitBaseline + + (border.IntegerHeight() - fDigitHeight) / 2)); + } + + if (fButtons != 0) + ClipToPicture(NULL); +} + + +BRect +MouseView::_ButtonsRect() const +{ + return BRect(0, fScaling * kButtonTop, fScaling * kMouseDownWidth, + fScaling * (kButtonTop + kMouseDownHeight)); +} + + +BRect +MouseView::_ButtonRect(const int32* offsets, int index) const +{ + return BRect(fScaling * offsets[index], fScaling * kButtonTop, + fScaling * offsets[index + 1] - 1, + fScaling * (kButtonTop + kMouseDownHeight)); +} + + +int32 +MouseView::_ConvertFromVisualOrder(int32 i) +{ + if (fType < 3) + return i; + + switch (i) { + case 0: + default: + return 0; + case 1: + return 2; + case 2: + return 1; + } +} + + +void +MouseView::_CreateButtonsPicture() +{ + BeginPicture(&fButtonsPicture); + SetScale(1.8 * fScaling); + SetOrigin(-21 * fScaling, -14 * fScaling); + + BShape mouseShape; + mouseShape.MoveTo(BPoint(48, 12)); + // top + BPoint control3[3] = { BPoint(44, 8), BPoint(20, 8), BPoint(16, 12) }; + mouseShape.BezierTo(control3); + // left + BPoint control[3] = { BPoint(12, 16), BPoint(13, 27), BPoint(13, 27) }; + mouseShape.BezierTo(control); + // bottom + BPoint control4[3] = { BPoint(18, 30), BPoint(46, 30), BPoint(51, 27) }; + mouseShape.BezierTo(control4); + // right + BPoint control2[3] = { BPoint(51, 27), BPoint(50, 14), BPoint(48, 12) }; + mouseShape.BezierTo(control2); + + mouseShape.Close(); + + SetHighColor(255, 0, 0, 255); + FillShape(&mouseShape, B_SOLID_HIGH); + + EndPicture(); + SetScale(1); +} \ No newline at end of file diff --git a/src/preferences/input/MouseView.h b/src/preferences/input/MouseView.h new file mode 100644 index 0000000000..2a92a79d03 --- /dev/null +++ b/src/preferences/input/MouseView.h @@ -0,0 +1,63 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur +*/ + + +#ifndef MOUSE_VIEW_H +#define MOUSE_VIEW_H + + +#include +#include +#include +#include + + +class MouseSettings; + +class MouseView : public BView { +public: + MouseView(const MouseSettings& settings); + virtual ~MouseView(); + + void SetMouseType(int32 type); + void MouseMapUpdated(); + void UpdateFromSettings(); + + virtual void GetPreferredSize(float* _width, float* _height); + virtual void AttachedToWindow(); + virtual void MouseUp(BPoint where); + virtual void MouseDown(BPoint where); + virtual void Draw(BRect frame); + bool IsMouseConnected() + { return fConnected; } + +private: + BRect _ButtonsRect() const; + BRect _ButtonRect(const int32* offsets, + int index) const; + int32 _ConvertFromVisualOrder(int32 button); + void _CreateButtonsPicture(); + +private: + typedef BView inherited; + + const MouseSettings& fSettings; + + BPicture fButtonsPicture; + int32 fDigitBaseline; + int32 fDigitHeight; + float fScaling; + + int32 fType; + uint32 fButtons; + uint32 fOldButtons; + bool fConnected; +}; + + +#endif /* MOUSE_VIEW_H */ diff --git a/src/preferences/input/SettingsView.cpp b/src/preferences/input/SettingsView.cpp new file mode 100644 index 0000000000..f0cc6ab84a --- /dev/null +++ b/src/preferences/input/SettingsView.cpp @@ -0,0 +1,285 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur + */ + + +#include "InputMouse.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "InputConstants.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); + + 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); +} \ No newline at end of file diff --git a/src/preferences/input/SettingsView.h b/src/preferences/input/SettingsView.h new file mode 100644 index 0000000000..33741d0e20 --- /dev/null +++ b/src/preferences/input/SettingsView.h @@ -0,0 +1,54 @@ +/* + * Copyright 2019, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Author: + * Preetpal Kaur +*/ + + +#ifndef SETTINGS_VIEW_H +#define SETTINGS_VIEW_H + + +#include +#include +#include +#include +#include +#include + + +class MouseSettings; +class MouseView; + + +class SettingsView : public BBox { + public: + SettingsView(MouseSettings &settings); + virtual ~SettingsView(); + + virtual void AttachedToWindow(); + + void SetMouseType(int32 type); + void MouseMapUpdated(); + void UpdateFromSettings(); + + BPopUpMenu* fFocusFollowsMouseMenu; + BCheckBox* fAcceptFirstClickBox; + + private: + + typedef BBox inherited; + + const MouseSettings &fSettings; + + BPopUpMenu* fTypeMenu; + BPopUpMenu* fFocusMenu; + MouseView* fMouseView; + BSlider* fClickSpeedSlider; + BSlider* fMouseSpeedSlider; + BSlider* fAccelerationSlider; +}; + +#endif /* SETTINGS_VIEW_H */