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 "InputTouchpadPrefView.h" 11 12 #include <stdio.h> 13 14 #include <Alert.h> 15 #include <Box.h> 16 #include <Catalog.h> 17 #include <CheckBox.h> 18 #include <ControlLook.h> 19 #include <File.h> 20 #include <FindDirectory.h> 21 #include <Input.h> 22 #include <LayoutBuilder.h> 23 #include <Locale.h> 24 #include <MenuField.h> 25 #include <MenuItem.h> 26 #include <Message.h> 27 #include <Path.h> 28 #include <Screen.h> 29 #include <SeparatorView.h> 30 #include <SpaceLayoutItem.h> 31 #include <Window.h> 32 33 #include <keyboard_mouse_driver.h> 34 35 36 const uint32 SCROLL_X_DRAG = 'sxdr'; 37 const uint32 SCROLL_Y_DRAG = 'sydr'; 38 39 #undef B_TRANSLATION_CONTEXT 40 #define B_TRANSLATION_CONTEXT "TouchpadPrefView" 41 42 43 TouchpadView::TouchpadView(BRect frame) 44 : 45 BView(frame, "TouchpadView", B_FOLLOW_NONE, B_WILL_DRAW) 46 { 47 fXTracking = false; 48 fYTracking = false; 49 fOffScreenView = NULL; 50 fOffScreenBitmap = NULL; 51 52 fPrefRect = frame; 53 fPadRect = fPrefRect; 54 fPadRect.InsetBy(10, 10); 55 fXScrollRange = fPadRect.Width(); 56 fYScrollRange = fPadRect.Height(); 57 58 } 59 60 61 TouchpadView::~TouchpadView() 62 { 63 delete fOffScreenBitmap; 64 } 65 66 67 void 68 TouchpadView::Draw(BRect updateRect) 69 { 70 DrawSliders(); 71 } 72 73 74 void 75 TouchpadView::MouseDown(BPoint point) 76 { 77 if (fXScrollDragZone.Contains(point)) { 78 fXTracking = true; 79 fOldXScrollRange = fXScrollRange; 80 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 81 } 82 83 if (fYScrollDragZone.Contains(point)) { 84 fYTracking = true; 85 fOldYScrollRange = fYScrollRange; 86 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 87 } 88 } 89 90 91 void 92 TouchpadView::MouseUp(BPoint point) 93 { 94 if (!fXTracking && !fYTracking) 95 return; 96 97 fXTracking = false; 98 fYTracking = false; 99 100 const float kSoftScrollLimit = 0.7; 101 102 int32 result = 0; 103 if (GetRightScrollRatio() > kSoftScrollLimit 104 || GetBottomScrollRatio() > kSoftScrollLimit) { 105 BAlert* alert = new BAlert(B_TRANSLATE("Please confirm"), 106 B_TRANSLATE("The new scroll area is very large and may impede " 107 "normal mouse operation. Do you really want to change it?"), 108 B_TRANSLATE("OK"), B_TRANSLATE("Cancel"), 109 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 110 alert->SetShortcut(1, B_ESCAPE); 111 result = alert->Go(); 112 } 113 114 if (result == 0) { 115 BMessage msg(SCROLL_AREA_CHANGED); 116 Invoke(&msg); 117 } else { 118 if (GetRightScrollRatio() > kSoftScrollLimit) 119 fXScrollRange = fOldXScrollRange; 120 if (GetBottomScrollRatio() > kSoftScrollLimit) 121 fYScrollRange = fOldYScrollRange; 122 DrawSliders(); 123 } 124 } 125 126 127 void 128 TouchpadView::AttachedToWindow() 129 { 130 if (!fOffScreenView) 131 fOffScreenView = new BView(Bounds(), "", B_FOLLOW_ALL, B_WILL_DRAW); 132 133 if (!fOffScreenBitmap) { 134 fOffScreenBitmap = new BBitmap(Bounds(), B_CMAP8, true, false); 135 136 if (fOffScreenBitmap && fOffScreenView) 137 fOffScreenBitmap->AddChild(fOffScreenView); 138 } 139 } 140 141 142 void 143 TouchpadView::SetValues(float rightRange, float bottomRange) 144 { 145 fXScrollRange = fPadRect.Width() * (1 - rightRange); 146 fYScrollRange = fPadRect.Height() * (1 - bottomRange); 147 Invalidate(); 148 } 149 150 151 void 152 TouchpadView::GetPreferredSize(float* width, float* height) 153 { 154 if (width != NULL) 155 *width = fPrefRect.Width(); 156 if (height != NULL) 157 *height = fPrefRect.Height(); 158 } 159 160 161 void 162 TouchpadView::MouseMoved(BPoint point, uint32 transit, const BMessage* message) 163 { 164 if (fXTracking) { 165 if (point.x > fPadRect.right) 166 fXScrollRange = fPadRect.Width(); 167 else if (point.x < fPadRect.left) 168 fXScrollRange = 0; 169 else 170 fXScrollRange = point.x - fPadRect.left; 171 172 DrawSliders(); 173 } 174 175 if (fYTracking) { 176 if (point.y > fPadRect.bottom) 177 fYScrollRange = fPadRect.Height(); 178 else if (point.y < fPadRect.top) 179 fYScrollRange = 0; 180 else 181 fYScrollRange = point.y - fPadRect.top; 182 183 DrawSliders(); 184 } 185 } 186 187 188 189 void 190 TouchpadView::DrawSliders() 191 { 192 BView* view = fOffScreenView != NULL ? fOffScreenView : this; 193 194 if (!LockLooper()) 195 return; 196 197 if (fOffScreenBitmap->Lock()) { 198 view->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 199 view->FillRect(Bounds()); 200 view->SetHighColor(100, 100, 100); 201 view->FillRoundRect(fPadRect, 4, 4); 202 203 int32 dragSize = 3; // half drag size 204 205 // scroll areas 206 view->SetHighColor(145, 100, 100); 207 BRect rightRect(fPadRect.left + fXScrollRange, fPadRect.top, 208 fPadRect.right, fPadRect.bottom); 209 view->FillRoundRect(rightRect, 4, 4); 210 211 BRect bottomRect(fPadRect.left, fPadRect.top + fYScrollRange, 212 fPadRect.right, fPadRect.bottom); 213 view->FillRoundRect(bottomRect, 4, 4); 214 215 // Stroke Rect 216 view->SetHighColor(100, 100, 100); 217 view->SetPenSize(2); 218 view->StrokeRoundRect(fPadRect, 4, 4); 219 220 // x scroll range line 221 view->SetHighColor(200, 0, 0); 222 view->StrokeLine(BPoint(fPadRect.left + fXScrollRange, fPadRect.top), 223 BPoint(fPadRect.left + fXScrollRange, fPadRect.bottom)); 224 225 fXScrollDragZone = BRect(fPadRect.left + fXScrollRange - dragSize, 226 fPadRect.top - dragSize, fPadRect.left + fXScrollRange + dragSize, 227 fPadRect.bottom + dragSize); 228 BRect xscrollDragZone1 = BRect(fPadRect.left + fXScrollRange - dragSize, 229 fPadRect.top - dragSize, fPadRect.left + fXScrollRange + dragSize, 230 fPadRect.top + dragSize); 231 view->FillRect(xscrollDragZone1); 232 BRect xscrollDragZone2 = BRect(fPadRect.left + fXScrollRange - dragSize, 233 fPadRect.bottom - dragSize, 234 fPadRect.left + fXScrollRange + dragSize, 235 fPadRect.bottom + dragSize); 236 view->FillRect(xscrollDragZone2); 237 238 // y scroll range line 239 view->StrokeLine(BPoint(fPadRect.left, fPadRect.top + fYScrollRange), 240 BPoint(fPadRect.right, fPadRect.top + fYScrollRange)); 241 242 fYScrollDragZone = BRect(fPadRect.left - dragSize, 243 fPadRect.top + fYScrollRange - dragSize, 244 fPadRect.right + dragSize, 245 fPadRect.top + fYScrollRange + dragSize); 246 BRect yscrollDragZone1 = BRect(fPadRect.left - dragSize, 247 fPadRect.top + fYScrollRange - dragSize, fPadRect.left + dragSize, 248 fPadRect.top + fYScrollRange + dragSize); 249 view->FillRect(yscrollDragZone1); 250 BRect yscrollDragZone2 = BRect(fPadRect.right - dragSize, 251 fPadRect.top + fYScrollRange - dragSize, fPadRect.right + dragSize, 252 fPadRect.top + fYScrollRange + dragSize); 253 view->FillRect(yscrollDragZone2); 254 255 view->Sync(); 256 fOffScreenBitmap->Unlock(); 257 DrawBitmap(fOffScreenBitmap, B_ORIGIN); 258 } 259 260 UnlockLooper(); 261 } 262 263 264 // #pragma mark - TouchpadPrefView 265 266 267 TouchpadPrefView::TouchpadPrefView(BInputDevice* dev) 268 : 269 BGroupView(), 270 fTouchpadPref(dev) 271 { 272 SetupView(); 273 // set view values 274 SetValues(&fTouchpadPref.Settings()); 275 } 276 277 278 TouchpadPrefView::~TouchpadPrefView() 279 { 280 } 281 282 283 void 284 TouchpadPrefView::MessageReceived(BMessage* message) 285 { 286 touchpad_settings& settings = fTouchpadPref.Settings(); 287 288 switch (message->what) { 289 case SCROLL_AREA_CHANGED: 290 settings.scroll_rightrange = fTouchpadView->GetRightScrollRatio(); 291 settings.scroll_bottomrange = fTouchpadView->GetBottomScrollRatio(); 292 fTouchpadPref.UpdateSettings(); 293 break; 294 295 case SCROLL_CONTROL_CHANGED: 296 settings.scroll_twofinger = fTwoFingerBox->Value() == B_CONTROL_ON; 297 settings.scroll_twofinger_horizontal 298 = fTwoFingerHorizontalBox->Value() == B_CONTROL_ON; 299 settings.scroll_acceleration = fScrollAccelSlider->Value(); 300 settings.scroll_xstepsize = (20 - fScrollStepXSlider->Value()) * 3; 301 settings.scroll_ystepsize = (20 - fScrollStepYSlider->Value()) * 3; 302 fTwoFingerHorizontalBox->SetEnabled(settings.scroll_twofinger); 303 fTouchpadPref.UpdateSettings(); 304 break; 305 306 case TAP_CONTROL_CHANGED: 307 settings.tapgesture_sensibility = fTapSlider->Value(); 308 fTouchpadPref.UpdateSettings(); 309 break; 310 311 case PADBLOCK_TIME_CHANGED: 312 settings.padblocker_threshold = fPadBlockerSlider->Value(); 313 // The maximum value means "disabled", but in the settings file that 314 // must be stored as 0 315 if (settings.padblocker_threshold == 1000) 316 settings.padblocker_threshold = 0; 317 fRevertButton->SetEnabled(true); 318 fTouchpadPref.UpdateSettings(); 319 break; 320 321 case DEFAULT_SETTINGS: 322 fTouchpadPref.Defaults(); 323 fRevertButton->SetEnabled(true); 324 fTouchpadPref.UpdateSettings(); 325 SetValues(&settings); 326 break; 327 328 case REVERT_SETTINGS: 329 fTouchpadPref.Revert(); 330 fTouchpadPref.UpdateSettings(); 331 fRevertButton->SetEnabled(false); 332 SetValues(&settings); 333 break; 334 335 default: 336 BView::MessageReceived(message); 337 } 338 } 339 340 341 void 342 TouchpadPrefView::AttachedToWindow() 343 { 344 fTouchpadView->SetTarget(this); 345 fTwoFingerBox->SetTarget(this); 346 fTwoFingerHorizontalBox->SetTarget(this); 347 fScrollStepXSlider->SetTarget(this); 348 fScrollStepYSlider->SetTarget(this); 349 fScrollAccelSlider->SetTarget(this); 350 fPadBlockerSlider->SetTarget(this); 351 fTapSlider->SetTarget(this); 352 fDefaultButton->SetTarget(this); 353 fRevertButton->SetTarget(this); 354 BSize size = PreferredSize(); 355 Window()->ResizeTo(size.width, size.height); 356 357 BPoint position = fTouchpadPref.WindowPosition(); 358 // center window on screen if it had a bad position 359 if (position.x < 0 && position.y < 0) 360 Window()->CenterOnScreen(); 361 else 362 Window()->MoveTo(position); 363 } 364 365 366 void 367 TouchpadPrefView::DetachedFromWindow() 368 { 369 fTouchpadPref.SetWindowPosition(Window()->Frame().LeftTop()); 370 } 371 372 373 void 374 TouchpadPrefView::SetupView() 375 { 376 SetLayout(new BGroupLayout(B_VERTICAL)); 377 BBox* scrollBox = new BBox("Touchpad"); 378 scrollBox->SetLabel(B_TRANSLATE("Scrolling")); 379 380 381 fTouchpadView = new TouchpadView(BRect(0, 0, 130, 120)); 382 fTouchpadView->SetExplicitMaxSize(BSize(130, 120)); 383 384 // Create the "Mouse Speed" slider... 385 fScrollAccelSlider = new BSlider("scroll_accel", 386 B_TRANSLATE("Acceleration"), 387 new BMessage(SCROLL_CONTROL_CHANGED), 0, 20, B_HORIZONTAL); 388 fScrollAccelSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 389 fScrollAccelSlider->SetHashMarkCount(7); 390 fScrollAccelSlider->SetLimitLabels(B_TRANSLATE("Slow"), 391 B_TRANSLATE("Fast")); 392 fScrollAccelSlider->SetExplicitMinSize(BSize(150, B_SIZE_UNSET)); 393 394 fScrollStepXSlider = new BSlider("scroll_stepX", 395 B_TRANSLATE("Horizontal"), 396 new BMessage(SCROLL_CONTROL_CHANGED), 397 0, 20, B_HORIZONTAL); 398 fScrollStepXSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 399 fScrollStepXSlider->SetHashMarkCount(7); 400 fScrollStepXSlider->SetLimitLabels(B_TRANSLATE("Slow"), 401 B_TRANSLATE("Fast")); 402 403 fScrollStepYSlider = new BSlider("scroll_stepY", 404 B_TRANSLATE("Vertical"), 405 new BMessage(SCROLL_CONTROL_CHANGED), 0, 20, B_HORIZONTAL); 406 fScrollStepYSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 407 fScrollStepYSlider->SetHashMarkCount(7); 408 fScrollStepYSlider->SetLimitLabels(B_TRANSLATE("Slow"), 409 B_TRANSLATE("Fast")); 410 411 fPadBlockerSlider = new BSlider("padblocker", 412 B_TRANSLATE("Keyboard Lock Delay"), 413 new BMessage(PADBLOCK_TIME_CHANGED), 5, 1000, B_HORIZONTAL); 414 fPadBlockerSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 415 fPadBlockerSlider->SetHashMarkCount(10); 416 fPadBlockerSlider->SetLimitLabels(B_TRANSLATE("Quick"), 417 B_TRANSLATE("Never")); 418 419 fTwoFingerBox = new BCheckBox(B_TRANSLATE("Two finger scrolling"), 420 new BMessage(SCROLL_CONTROL_CHANGED)); 421 fTwoFingerHorizontalBox = new BCheckBox( 422 B_TRANSLATE("Horizontal scrolling"), 423 new BMessage(SCROLL_CONTROL_CHANGED)); 424 425 float spacing = be_control_look->DefaultItemSpacing(); 426 427 BView* scrollPrefLeftLayout 428 = BLayoutBuilder::Group<>(B_VERTICAL, 0) 429 .Add(fTouchpadView) 430 .AddStrut(spacing) 431 .Add(fTwoFingerBox) 432 .AddGroup(B_HORIZONTAL, 0) 433 .AddStrut(spacing * 2) 434 .Add(fTwoFingerHorizontalBox) 435 .End() 436 .AddGlue() 437 .View(); 438 439 BGroupView* scrollPrefRightLayout = new BGroupView(B_VERTICAL); 440 scrollPrefRightLayout->AddChild(fScrollAccelSlider); 441 scrollPrefRightLayout->AddChild(fScrollStepXSlider); 442 scrollPrefRightLayout->AddChild(fScrollStepYSlider); 443 444 BGroupLayout* scrollPrefLayout = new BGroupLayout(B_HORIZONTAL); 445 scrollPrefLayout->SetSpacing(spacing); 446 scrollPrefLayout->SetInsets(spacing, 447 scrollBox->TopBorderOffset() * 2 + spacing, spacing, spacing); 448 scrollBox->SetLayout(scrollPrefLayout); 449 450 scrollPrefLayout->AddView(scrollPrefLeftLayout); 451 scrollPrefLayout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(spacing 452 * 1.5)); 453 scrollPrefLayout->AddView(scrollPrefRightLayout); 454 455 fTapSlider = new BSlider("tap_sens", B_TRANSLATE("Tapping sensitivity"), 456 new BMessage(TAP_CONTROL_CHANGED), 0, spacing * 2, B_HORIZONTAL); 457 fTapSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 458 fTapSlider->SetHashMarkCount(7); 459 fTapSlider->SetLimitLabels(B_TRANSLATE("Off"), B_TRANSLATE("High")); 460 461 fDefaultButton = new BButton(B_TRANSLATE("Defaults"), 462 new BMessage(DEFAULT_SETTINGS)); 463 464 fRevertButton = new BButton(B_TRANSLATE("Revert"), 465 new BMessage(REVERT_SETTINGS)); 466 fRevertButton->SetEnabled(false); 467 468 469 BLayoutBuilder::Group<>(this, B_VERTICAL) 470 .SetInsets(B_USE_WINDOW_SPACING) 471 .Add(scrollBox) 472 .Add(fTapSlider) 473 .Add(fPadBlockerSlider) 474 .Add(new BSeparatorView(B_HORIZONTAL)) 475 .AddGroup(B_HORIZONTAL) 476 .Add(fDefaultButton) 477 .Add(fRevertButton) 478 .AddGlue() 479 .End() 480 .End(); 481 } 482 483 484 void 485 TouchpadPrefView::SetValues(touchpad_settings* settings) 486 { 487 fTouchpadView->SetValues(settings->scroll_rightrange, 488 settings->scroll_bottomrange); 489 fTwoFingerBox->SetValue(settings->scroll_twofinger 490 ? B_CONTROL_ON : B_CONTROL_OFF); 491 fTwoFingerHorizontalBox->SetValue(settings->scroll_twofinger_horizontal 492 ? B_CONTROL_ON : B_CONTROL_OFF); 493 fTwoFingerHorizontalBox->SetEnabled(settings->scroll_twofinger); 494 fScrollStepXSlider->SetValue(20 - settings->scroll_xstepsize / 2); 495 fScrollStepYSlider->SetValue(20 - settings->scroll_ystepsize / 2); 496 fScrollAccelSlider->SetValue(settings->scroll_acceleration); 497 fTapSlider->SetValue(settings->tapgesture_sensibility); 498 fPadBlockerSlider->SetValue(settings->padblocker_threshold); 499 } 500