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