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