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 TouchpadView::~TouchpadView() 61 { 62 delete fOffScreenBitmap; 63 } 64 65 66 void 67 TouchpadView::Draw(BRect updateRect) 68 { 69 DrawSliders(); 70 } 71 72 73 void 74 TouchpadView::MouseDown(BPoint point) 75 { 76 if (fXScrollDragZone.Contains(point)) { 77 fXTracking = true; 78 fOldXScrollRange = fXScrollRange; 79 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 80 } 81 82 if (fYScrollDragZone.Contains(point)) { 83 fYTracking = true; 84 fOldYScrollRange = fYScrollRange; 85 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 86 } 87 } 88 89 90 void 91 TouchpadView::MouseUp(BPoint point) 92 { 93 if (!fXTracking && !fYTracking) 94 return; 95 96 fXTracking = false; 97 fYTracking = false; 98 99 const float kSoftScrollLimit = 0.7; 100 101 int32 result = 0; 102 if (GetRightScrollRatio() > kSoftScrollLimit 103 || GetBottomScrollRatio() > kSoftScrollLimit) { 104 BAlert* alert = new BAlert(B_TRANSLATE("Please confirm"), 105 B_TRANSLATE( 106 "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"), NULL, B_WIDTH_AS_USUAL, 109 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 void 189 TouchpadView::DrawSliders() 190 { 191 BView* view = fOffScreenView != NULL ? fOffScreenView : this; 192 193 if (!LockLooper()) 194 return; 195 196 if (fOffScreenBitmap->Lock()) { 197 view->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 198 view->FillRect(Bounds()); 199 view->SetHighColor(100, 100, 100); 200 view->FillRoundRect(fPadRect, 4, 4); 201 202 int32 dragSize = 3; // half drag size 203 204 // scroll areas 205 view->SetHighColor(145, 100, 100); 206 BRect rightRect(fPadRect.left + fXScrollRange, fPadRect.top, 207 fPadRect.right, fPadRect.bottom); 208 view->FillRoundRect(rightRect, 4, 4); 209 210 BRect bottomRect(fPadRect.left, fPadRect.top + fYScrollRange, 211 fPadRect.right, fPadRect.bottom); 212 view->FillRoundRect(bottomRect, 4, 4); 213 214 // Stroke Rect 215 view->SetHighColor(100, 100, 100); 216 view->SetPenSize(2); 217 view->StrokeRoundRect(fPadRect, 4, 4); 218 219 // x scroll range line 220 view->SetHighColor(200, 0, 0); 221 view->StrokeLine(BPoint(fPadRect.left + fXScrollRange, fPadRect.top), 222 BPoint(fPadRect.left + fXScrollRange, fPadRect.bottom)); 223 224 fXScrollDragZone = BRect(fPadRect.left + fXScrollRange - dragSize, 225 fPadRect.top - dragSize, fPadRect.left + fXScrollRange + dragSize, 226 fPadRect.bottom + dragSize); 227 BRect xscrollDragZone1 = BRect(fPadRect.left + fXScrollRange - dragSize, 228 fPadRect.top - dragSize, fPadRect.left + fXScrollRange + dragSize, 229 fPadRect.top + dragSize); 230 view->FillRect(xscrollDragZone1); 231 BRect xscrollDragZone2 = BRect(fPadRect.left + fXScrollRange - dragSize, 232 fPadRect.bottom - dragSize, 233 fPadRect.left + fXScrollRange + dragSize, 234 fPadRect.bottom + dragSize); 235 view->FillRect(xscrollDragZone2); 236 237 // y scroll range line 238 view->StrokeLine(BPoint(fPadRect.left, fPadRect.top + fYScrollRange), 239 BPoint(fPadRect.right, fPadRect.top + fYScrollRange)); 240 241 fYScrollDragZone = BRect(fPadRect.left - dragSize, 242 fPadRect.top + fYScrollRange - dragSize, fPadRect.right + dragSize, 243 fPadRect.top + fYScrollRange + dragSize); 244 BRect yscrollDragZone1 = BRect(fPadRect.left - dragSize, 245 fPadRect.top + fYScrollRange - dragSize, fPadRect.left + dragSize, 246 fPadRect.top + fYScrollRange + dragSize); 247 view->FillRect(yscrollDragZone1); 248 BRect yscrollDragZone2 = BRect(fPadRect.right - dragSize, 249 fPadRect.top + fYScrollRange - dragSize, fPadRect.right + dragSize, 250 fPadRect.top + fYScrollRange + dragSize); 251 view->FillRect(yscrollDragZone2); 252 253 view->Sync(); 254 fOffScreenBitmap->Unlock(); 255 DrawBitmap(fOffScreenBitmap, B_ORIGIN); 256 } 257 258 UnlockLooper(); 259 } 260 261 262 // #pragma mark - TouchpadPrefView 263 264 265 TouchpadPrefView::TouchpadPrefView(BInputDevice* dev) 266 : 267 BGroupView(), 268 fTouchpadPref(dev) 269 { 270 SetupView(); 271 // set view values 272 SetValues(&fTouchpadPref.Settings()); 273 } 274 275 276 TouchpadPrefView::~TouchpadPrefView() 277 { 278 } 279 280 281 void 282 TouchpadPrefView::MessageReceived(BMessage* message) 283 { 284 touchpad_settings& settings = fTouchpadPref.Settings(); 285 286 switch (message->what) { 287 case SCROLL_AREA_CHANGED: 288 settings.scroll_rightrange = fTouchpadView->GetRightScrollRatio(); 289 settings.scroll_bottomrange = fTouchpadView->GetBottomScrollRatio(); 290 fTouchpadPref.UpdateSettings(); 291 break; 292 293 case SCROLL_CONTROL_CHANGED: 294 settings.scroll_twofinger = fTwoFingerBox->Value() == B_CONTROL_ON; 295 settings.scroll_twofinger_horizontal 296 = fTwoFingerHorizontalBox->Value() == B_CONTROL_ON; 297 settings.scroll_acceleration = fScrollAccelSlider->Value(); 298 settings.scroll_xstepsize = (20 - fScrollStepXSlider->Value()) * 3; 299 settings.scroll_ystepsize = (20 - fScrollStepYSlider->Value()) * 3; 300 fTwoFingerHorizontalBox->SetEnabled(settings.scroll_twofinger); 301 fTouchpadPref.UpdateSettings(); 302 break; 303 304 case TAP_CONTROL_CHANGED: 305 settings.tapgesture_sensibility = fTapSlider->Value(); 306 fTouchpadPref.UpdateSettings(); 307 break; 308 309 case PADBLOCK_TIME_CHANGED: 310 settings.padblocker_threshold = fPadBlockerSlider->Value(); 311 // The maximum value means "disabled", but in the settings file that 312 // must be stored as 0 313 if (settings.padblocker_threshold == 1000) 314 settings.padblocker_threshold = 0; 315 fRevertButton->SetEnabled(true); 316 fTouchpadPref.UpdateSettings(); 317 break; 318 319 case DEFAULT_SETTINGS: 320 fTouchpadPref.Defaults(); 321 fRevertButton->SetEnabled(true); 322 fTouchpadPref.UpdateSettings(); 323 SetValues(&settings); 324 break; 325 326 case REVERT_SETTINGS: 327 fTouchpadPref.Revert(); 328 fTouchpadPref.UpdateSettings(); 329 fRevertButton->SetEnabled(false); 330 SetValues(&settings); 331 break; 332 333 default: 334 BView::MessageReceived(message); 335 } 336 } 337 338 339 void 340 TouchpadPrefView::AttachedToWindow() 341 { 342 fTouchpadView->SetTarget(this); 343 fTwoFingerBox->SetTarget(this); 344 fTwoFingerHorizontalBox->SetTarget(this); 345 fScrollStepXSlider->SetTarget(this); 346 fScrollStepYSlider->SetTarget(this); 347 fScrollAccelSlider->SetTarget(this); 348 fPadBlockerSlider->SetTarget(this); 349 fTapSlider->SetTarget(this); 350 fDefaultButton->SetTarget(this); 351 fRevertButton->SetTarget(this); 352 BSize size = PreferredSize(); 353 Window()->ResizeTo(size.width, size.height); 354 355 BPoint position = fTouchpadPref.WindowPosition(); 356 // center window on screen if it had a bad position 357 if (position.x < 0 && position.y < 0) 358 Window()->CenterOnScreen(); 359 else 360 Window()->MoveTo(position); 361 } 362 363 364 void 365 TouchpadPrefView::DetachedFromWindow() 366 { 367 fTouchpadPref.SetWindowPosition(Window()->Frame().LeftTop()); 368 } 369 370 371 void 372 TouchpadPrefView::SetupView() 373 { 374 SetLayout(new BGroupLayout(B_VERTICAL)); 375 BBox* scrollBox = new BBox("Touchpad"); 376 scrollBox->SetLabel(B_TRANSLATE("Scrolling")); 377 378 379 fTouchpadView = new TouchpadView(BRect(0, 0, 130, 120)); 380 fTouchpadView->SetExplicitMaxSize(BSize(130, 120)); 381 382 // Create the "Mouse Speed" slider... 383 fScrollAccelSlider = new BSlider("scroll_accel", 384 B_TRANSLATE("Acceleration"), 385 new BMessage(SCROLL_CONTROL_CHANGED), 0, 20, B_HORIZONTAL); 386 fScrollAccelSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 387 fScrollAccelSlider->SetHashMarkCount(7); 388 fScrollAccelSlider->SetLimitLabels( 389 B_TRANSLATE("Slow"), B_TRANSLATE("Fast")); 390 fScrollAccelSlider->SetExplicitMinSize(BSize(150, B_SIZE_UNSET)); 391 392 fScrollStepXSlider = new BSlider("scroll_stepX", B_TRANSLATE("Horizontal"), 393 new BMessage(SCROLL_CONTROL_CHANGED), 0, 20, B_HORIZONTAL); 394 fScrollStepXSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 395 fScrollStepXSlider->SetHashMarkCount(7); 396 fScrollStepXSlider->SetLimitLabels( 397 B_TRANSLATE("Slow"), B_TRANSLATE("Fast")); 398 399 fScrollStepYSlider = new BSlider("scroll_stepY", B_TRANSLATE("Vertical"), 400 new BMessage(SCROLL_CONTROL_CHANGED), 0, 20, B_HORIZONTAL); 401 fScrollStepYSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 402 fScrollStepYSlider->SetHashMarkCount(7); 403 fScrollStepYSlider->SetLimitLabels( 404 B_TRANSLATE("Slow"), B_TRANSLATE("Fast")); 405 406 fPadBlockerSlider 407 = new BSlider("padblocker", B_TRANSLATE("Keyboard lock delay"), 408 new BMessage(PADBLOCK_TIME_CHANGED), 5, 1000, B_HORIZONTAL); 409 fPadBlockerSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 410 fPadBlockerSlider->SetHashMarkCount(10); 411 fPadBlockerSlider->SetLimitLabels( 412 B_TRANSLATE("Quick"), B_TRANSLATE("Never")); 413 414 fTwoFingerBox = new BCheckBox(B_TRANSLATE("Two finger scrolling"), 415 new BMessage(SCROLL_CONTROL_CHANGED)); 416 fTwoFingerHorizontalBox = new BCheckBox(B_TRANSLATE("Horizontal scrolling"), 417 new BMessage(SCROLL_CONTROL_CHANGED)); 418 419 float spacing = be_control_look->DefaultItemSpacing(); 420 421 BView* scrollPrefLeftLayout 422 = BLayoutBuilder::Group<>(B_VERTICAL, 0) 423 .Add(fTouchpadView) 424 .AddStrut(spacing) 425 .Add(fTwoFingerBox) 426 .AddGroup(B_HORIZONTAL, 0) 427 .AddStrut(spacing * 2) 428 .Add(fTwoFingerHorizontalBox) 429 .End() 430 .AddGlue() 431 .View(); 432 433 BGroupView* scrollPrefRightLayout = new BGroupView(B_VERTICAL); 434 scrollPrefRightLayout->AddChild(fScrollAccelSlider); 435 scrollPrefRightLayout->AddChild(fScrollStepXSlider); 436 scrollPrefRightLayout->AddChild(fScrollStepYSlider); 437 438 BGroupLayout* scrollPrefLayout = new BGroupLayout(B_HORIZONTAL); 439 scrollPrefLayout->SetSpacing(spacing); 440 scrollPrefLayout->SetInsets( 441 spacing, scrollBox->TopBorderOffset() * 2 + spacing, spacing, spacing); 442 scrollBox->SetLayout(scrollPrefLayout); 443 444 scrollPrefLayout->AddView(scrollPrefLeftLayout); 445 scrollPrefLayout->AddItem( 446 BSpaceLayoutItem::CreateVerticalStrut(spacing * 1.5)); 447 scrollPrefLayout->AddView(scrollPrefRightLayout); 448 449 fTapSlider = new BSlider("tap_sens", B_TRANSLATE("Tapping sensitivity"), 450 new BMessage(TAP_CONTROL_CHANGED), 0, spacing * 2, B_HORIZONTAL); 451 fTapSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); 452 fTapSlider->SetHashMarkCount(7); 453 fTapSlider->SetLimitLabels(B_TRANSLATE("Off"), B_TRANSLATE("High")); 454 455 fDefaultButton 456 = new BButton(B_TRANSLATE("Defaults"), new BMessage(DEFAULT_SETTINGS)); 457 458 fRevertButton 459 = new BButton(B_TRANSLATE("Revert"), new BMessage(REVERT_SETTINGS)); 460 fRevertButton->SetEnabled(false); 461 462 463 BLayoutBuilder::Group<>(this, B_VERTICAL) 464 .SetInsets(B_USE_WINDOW_SPACING) 465 .Add(scrollBox) 466 .Add(fTapSlider) 467 .Add(fPadBlockerSlider) 468 .Add(new BSeparatorView(B_HORIZONTAL)) 469 .AddGroup(B_HORIZONTAL) 470 .Add(fDefaultButton) 471 .Add(fRevertButton) 472 .AddGlue() 473 .End() 474 .End(); 475 } 476 477 478 void 479 TouchpadPrefView::SetValues(touchpad_settings* settings) 480 { 481 fTouchpadView->SetValues( 482 settings->scroll_rightrange, settings->scroll_bottomrange); 483 fTwoFingerBox->SetValue( 484 settings->scroll_twofinger ? B_CONTROL_ON : B_CONTROL_OFF); 485 fTwoFingerHorizontalBox->SetValue( 486 settings->scroll_twofinger_horizontal ? B_CONTROL_ON : B_CONTROL_OFF); 487 fTwoFingerHorizontalBox->SetEnabled(settings->scroll_twofinger); 488 fScrollStepXSlider->SetValue(20 - settings->scroll_xstepsize / 2); 489 fScrollStepYSlider->SetValue(20 - settings->scroll_ystepsize / 2); 490 fScrollAccelSlider->SetValue(settings->scroll_acceleration); 491 fTapSlider->SetValue(settings->tapgesture_sensibility); 492 fPadBlockerSlider->SetValue(settings->padblocker_threshold); 493 } 494