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 BPopUpMenu("unknown"); 76 fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("1-Button"), 77 new BMessage(kMsgMouseType))); 78 fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("2-Button"), 79 new BMessage(kMsgMouseType))); 80 fTypeMenu->AddItem(new BMenuItem(B_TRANSLATE("3-Button"), 81 new BMessage(kMsgMouseType))); 82 83 BMenuField* typeField = new BMenuField(B_TRANSLATE("Mouse type:"), 84 fTypeMenu); 85 typeField->SetAlignment(B_ALIGN_LEFT); 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 .AddGroup(B_HORIZONTAL, 0) 178 .AddGlue() 179 .Add(typeField) 180 .AddGlue() 181 .End() 182 .AddGlue() 183 .AddGroup(B_HORIZONTAL, 0) 184 .AddGlue() 185 .Add(fMouseView) 186 .AddGlue() 187 .End() 188 .AddGlue() 189 .Add(doubleClickTextControl) 190 .End() 191 .Add(new BSeparatorView(B_VERTICAL)) 192 193 // Vertical block B: speed settings 194 .AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING, 3) 195 .AddGroup(B_HORIZONTAL, 0) 196 .Add(fClickSpeedSlider) 197 .End() 198 .AddGroup(B_HORIZONTAL, 0) 199 .Add(fMouseSpeedSlider) 200 .End() 201 .AddGroup(B_HORIZONTAL, 0) 202 .Add(fAccelerationSlider) 203 .End() 204 .End() 205 .End() 206 .AddStrut(B_USE_DEFAULT_SPACING) 207 208 // Horizontal Block C: focus mode 209 .AddGroup(B_HORIZONTAL, B_USE_SMALL_SPACING) 210 .Add(focusField) 211 .AddGlue() 212 .AddGroup(B_VERTICAL, 0) 213 .Add(fAcceptFirstClickBox) 214 .End() 215 .End(); 216 217 SetBorder(B_NO_BORDER); 218 } 219 220 221 SettingsView::~SettingsView() 222 { 223 224 } 225 226 227 void 228 SettingsView::AttachedToWindow() 229 { 230 UpdateFromSettings(); 231 } 232 233 234 void 235 SettingsView::SetMouseType(int32 type) 236 { 237 fMouseView->SetMouseType(type); 238 } 239 240 241 void 242 SettingsView::MouseMapUpdated() 243 { 244 fMouseView->MouseMapUpdated(); 245 } 246 247 248 void 249 SettingsView::UpdateFromSettings() 250 { 251 int32 value = int32(fSettings.ClickSpeed() / 1000); 252 // slow = 1000000, fast = 0 253 fClickSpeedSlider->SetValue(value); 254 255 value = int32((log(fSettings.MouseSpeed() / 8192.0) / log(2)) * 1000 / 6); 256 // slow = 8192, fast = 524287 257 fMouseSpeedSlider->SetValue(value); 258 259 value = int32(sqrt(fSettings.AccelerationFactor() / 16384.0) * 1000 / 4); 260 // slow = 0, fast = 262144 261 fAccelerationSlider->SetValue(value); 262 263 BMenuItem* item = fTypeMenu->ItemAt(fSettings.MouseType() - 1); 264 if (item != NULL) 265 item->SetMarked(true); 266 267 fMouseView->SetMouseType(fSettings.MouseType()); 268 269 item = fFocusMenu->ItemAt(mouse_mode_to_index(fSettings.MouseMode())); 270 if (item != NULL) 271 item->SetMarked(true); 272 273 item = fFocusFollowsMouseMenu->ItemAt( 274 focus_follows_mouse_mode_to_index(fSettings.FocusFollowsMouseMode())); 275 if (item != NULL) 276 item->SetMarked(true); 277 278 fFocusFollowsMouseMenu->SetEnabled(fSettings.MouseMode() 279 == B_FOCUS_FOLLOWS_MOUSE); 280 281 fAcceptFirstClickBox->SetValue(fSettings.AcceptFirstClick() 282 ? B_CONTROL_ON : B_CONTROL_OFF); 283 fAcceptFirstClickBox->SetEnabled(fSettings.MouseMode() 284 != B_FOCUS_FOLLOWS_MOUSE); 285 }