1 /* 2 * Copyright 2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include "StateView.h" 10 11 #include <Message.h> 12 #include <MessageFilter.h> 13 #include <TextView.h> 14 #include <Window.h> 15 16 #include "Command.h" 17 #include "CommandStack.h" 18 // TODO: hack - somehow figure out of catching 19 // key events for a given control is ok 20 #include "GradientControl.h" 21 #include "ListViews.h" 22 // 23 #include "RWLocker.h" 24 25 using std::nothrow; 26 27 class EventFilter : public BMessageFilter { 28 public: 29 EventFilter(StateView* target) 30 : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), 31 fTarget(target) 32 { 33 } 34 virtual ~EventFilter() 35 { 36 } 37 virtual filter_result Filter(BMessage* message, BHandler** target) 38 { 39 filter_result result = B_DISPATCH_MESSAGE; 40 switch (message->what) { 41 case B_KEY_DOWN: { 42 if (dynamic_cast<BTextView*>(*target)) 43 break; 44 if (dynamic_cast<SimpleListView*>(*target)) 45 break; 46 if (dynamic_cast<GradientControl*>(*target)) 47 break; 48 uint32 key; 49 uint32 modifiers; 50 if (message->FindInt32("raw_char", (int32*)&key) >= B_OK 51 && message->FindInt32("modifiers", (int32*)&modifiers) >= B_OK) 52 if (fTarget->HandleKeyDown(key, modifiers)) 53 result = B_SKIP_MESSAGE; 54 break; 55 } 56 case B_KEY_UP: { 57 if (dynamic_cast<BTextView*>(*target)) 58 break; 59 if (dynamic_cast<SimpleListView*>(*target)) 60 break; 61 if (dynamic_cast<GradientControl*>(*target)) 62 break; 63 uint32 key; 64 uint32 modifiers; 65 if (message->FindInt32("raw_char", (int32*)&key) >= B_OK 66 && message->FindInt32("modifiers", (int32*)&modifiers) >= B_OK) 67 if (fTarget->HandleKeyUp(key, modifiers)) 68 result = B_SKIP_MESSAGE; 69 break; 70 71 } 72 case B_MODIFIERS_CHANGED: 73 *target = fTarget; 74 break; 75 76 case B_MOUSE_WHEEL_CHANGED: { 77 float x; 78 float y; 79 if (message->FindFloat("be:wheel_delta_x", &x) >= B_OK 80 && message->FindFloat("be:wheel_delta_y", &y) >= B_OK) { 81 if (fTarget->MouseWheelChanged(x, y)) 82 result = B_SKIP_MESSAGE; 83 } 84 break; 85 } 86 default: 87 break; 88 } 89 return result; 90 } 91 private: 92 StateView* fTarget; 93 }; 94 95 // #pragma mark - 96 97 // constructor 98 StateView::StateView(BRect frame, const char* name, 99 uint32 resizingMode, uint32 flags) 100 : BView(frame, name, resizingMode, flags), 101 fCurrentState(NULL), 102 fDropAnticipatingState(NULL), 103 104 fMouseInfo(), 105 106 fCommandStack(NULL), 107 fLocker(NULL), 108 109 fEventFilter(NULL), 110 fCatchAllEvents(false), 111 112 fUpdateTarget(NULL), 113 fUpdateCommand(0) 114 { 115 } 116 117 // destructor 118 StateView::~StateView() 119 { 120 delete fEventFilter; 121 } 122 123 // #pragma mark - 124 125 // AttachedToWindow 126 void 127 StateView::AttachedToWindow() 128 { 129 _InstallEventFilter(); 130 131 BView::AttachedToWindow(); 132 } 133 134 // DetachedFromWindow 135 void 136 StateView::DetachedFromWindow() 137 { 138 _RemoveEventFilter(); 139 140 BView::DetachedFromWindow(); 141 } 142 143 // Draw 144 void 145 StateView::Draw(BRect updateRect) 146 { 147 Draw(this, updateRect); 148 } 149 150 // MessageReceived 151 void 152 StateView::MessageReceived(BMessage* message) 153 { 154 // let the state handle the message if it wants 155 if (fCurrentState) { 156 AutoWriteLocker locker(fLocker); 157 if (fLocker && !locker.IsLocked()) 158 return; 159 160 Command* command = NULL; 161 if (fCurrentState->MessageReceived(message, &command)) { 162 Perform(command); 163 return; 164 } 165 } 166 167 switch (message->what) { 168 case B_MODIFIERS_CHANGED: 169 // NOTE: received only if the view has focus!! 170 if (fCurrentState) { 171 uint32 mods; 172 if (message->FindInt32("modifiers", (int32*)&mods) != B_OK) 173 mods = modifiers(); 174 fCurrentState->ModifiersChanged(mods); 175 fMouseInfo.modifiers = mods; 176 } 177 break; 178 default: 179 BView::MessageReceived(message); 180 } 181 } 182 183 // #pragma mark - 184 185 // MouseDown 186 void 187 StateView::MouseDown(BPoint where) 188 { 189 if (fLocker && !fLocker->WriteLock()) 190 return; 191 192 // query more info from the windows current message if available 193 uint32 buttons; 194 uint32 clicks; 195 BMessage* message = Window() ? Window()->CurrentMessage() : NULL; 196 if (!message || message->FindInt32("buttons", (int32*)&buttons) != B_OK) 197 buttons = B_PRIMARY_MOUSE_BUTTON; 198 if (!message || message->FindInt32("clicks", (int32*)&clicks) != B_OK) 199 clicks = 1; 200 201 if (fCurrentState) 202 fCurrentState->MouseDown(where, buttons, clicks); 203 204 // update mouse info *after* having called the ViewState hook 205 fMouseInfo.buttons = buttons; 206 fMouseInfo.position = where; 207 208 if (fLocker) 209 fLocker->WriteUnlock(); 210 } 211 212 // MouseMoved 213 void 214 StateView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) 215 { 216 if (fLocker && !fLocker->WriteLock()) 217 return; 218 219 if (dragMessage && !fDropAnticipatingState) { 220 // switch to a drop anticipating state if there is one available 221 fDropAnticipatingState = StateForDragMessage(dragMessage); 222 if (fDropAnticipatingState) 223 fDropAnticipatingState->Init(); 224 } 225 226 // TODO: I don't like this too much 227 if (!dragMessage && fDropAnticipatingState) { 228 fDropAnticipatingState->Cleanup(); 229 fDropAnticipatingState = NULL; 230 } 231 232 if (fDropAnticipatingState) 233 fDropAnticipatingState->MouseMoved(where, transit, dragMessage); 234 else { 235 if (fCurrentState) { 236 fCurrentState->MouseMoved(where, transit, dragMessage); 237 if (fMouseInfo.buttons != 0) 238 _TriggerUpdate(); 239 } 240 } 241 242 // update mouse info *after* having called the ViewState hook 243 fMouseInfo.position = where; 244 fMouseInfo.transit = transit; 245 246 if (fLocker) 247 fLocker->WriteUnlock(); 248 } 249 250 // MouseUp 251 void 252 StateView::MouseUp(BPoint where) 253 { 254 if (fLocker && !fLocker->WriteLock()) 255 return; 256 257 if (fDropAnticipatingState) { 258 Perform(fDropAnticipatingState->MouseUp()); 259 fDropAnticipatingState->Cleanup(); 260 fDropAnticipatingState = NULL; 261 262 if (fCurrentState) { 263 fCurrentState->MouseMoved(fMouseInfo.position, fMouseInfo.transit, 264 NULL); 265 } 266 } else { 267 if (fCurrentState) { 268 Perform(fCurrentState->MouseUp()); 269 _TriggerUpdate(); 270 } 271 } 272 273 // update mouse info *after* having called the ViewState hook 274 fMouseInfo.buttons = 0; 275 276 if (fLocker) 277 fLocker->WriteUnlock(); 278 } 279 280 // #pragma mark - 281 282 // KeyDown 283 void 284 StateView::KeyDown(const char* bytes, int32 numBytes) 285 { 286 uint32 key; 287 uint32 modifiers; 288 BMessage* message = Window() ? Window()->CurrentMessage() : NULL; 289 if (message 290 && message->FindInt32("raw_char", (int32*)&key) >= B_OK 291 && message->FindInt32("modifiers", (int32*)&modifiers) >= B_OK) { 292 if (HandleKeyDown(key, modifiers)) 293 return; 294 } 295 BView::KeyDown(bytes, numBytes); 296 } 297 298 // KeyUp 299 void 300 StateView::KeyUp(const char* bytes, int32 numBytes) 301 { 302 uint32 key; 303 uint32 modifiers; 304 BMessage* message = Window() ? Window()->CurrentMessage() : NULL; 305 if (message 306 && message->FindInt32("raw_char", (int32*)&key) >= B_OK 307 && message->FindInt32("modifiers", (int32*)&modifiers) >= B_OK) { 308 if (HandleKeyUp(key, modifiers)) 309 return; 310 } 311 BView::KeyUp(bytes, numBytes); 312 } 313 314 // #pragma mark - 315 316 // SetState 317 void 318 StateView::SetState(ViewState* state) 319 { 320 if (fCurrentState == state) 321 return; 322 323 // switch states as appropriate 324 if (fCurrentState) 325 fCurrentState->Cleanup(); 326 327 fCurrentState = state; 328 329 if (fCurrentState) 330 fCurrentState->Init(); 331 } 332 333 // Draw 334 void 335 StateView::Draw(BView* into, BRect updateRect) 336 { 337 if (fLocker && !fLocker->ReadLock()) { 338 return; 339 } 340 341 if (fCurrentState) 342 fCurrentState->Draw(into, updateRect); 343 344 if (fDropAnticipatingState) 345 fDropAnticipatingState->Draw(into, updateRect); 346 347 if (fLocker) 348 fLocker->ReadUnlock(); 349 } 350 351 // MouseWheelChanged 352 bool 353 StateView::MouseWheelChanged(float x, float y) 354 { 355 return false; 356 } 357 358 // HandleKeyDown 359 bool 360 StateView::HandleKeyDown(uint32 key, uint32 modifiers) 361 { 362 AutoWriteLocker locker(fLocker); 363 if (fLocker && !locker.IsLocked()) 364 return false; 365 366 if (_HandleKeyDown(key, modifiers)) 367 return true; 368 369 if (fCurrentState) { 370 Command* command = NULL; 371 if (fCurrentState->HandleKeyDown(key, modifiers, &command)) { 372 Perform(command); 373 return true; 374 } 375 } 376 return false; 377 } 378 379 // HandleKeyUp 380 bool 381 StateView::HandleKeyUp(uint32 key, uint32 modifiers) 382 { 383 AutoWriteLocker locker(fLocker); 384 if (fLocker && !locker.IsLocked()) 385 return false; 386 387 if (_HandleKeyUp(key, modifiers)) 388 return true; 389 390 if (fCurrentState) { 391 Command* command = NULL; 392 if (fCurrentState->HandleKeyUp(key, modifiers, &command)) { 393 Perform(command); 394 return true; 395 } 396 } 397 return false; 398 } 399 400 // FilterMouse 401 void 402 StateView::FilterMouse(BPoint* where) const 403 { 404 } 405 406 // StateForDragMessage 407 ViewState* 408 StateView::StateForDragMessage(const BMessage* message) 409 { 410 return NULL; 411 } 412 413 // SetCommandStack 414 void 415 StateView::SetCommandStack(::CommandStack* stack) 416 { 417 fCommandStack = stack; 418 } 419 420 // SetLocker 421 void 422 StateView::SetLocker(RWLocker* locker) 423 { 424 fLocker = locker; 425 } 426 427 // SetUpdateTarget 428 void 429 StateView::SetUpdateTarget(BHandler* target, uint32 command) 430 { 431 fUpdateTarget = target; 432 fUpdateCommand = command; 433 } 434 435 // SetCatchAllEvents 436 void 437 StateView::SetCatchAllEvents(bool catchAll) 438 { 439 if (fCatchAllEvents == catchAll) 440 return; 441 442 fCatchAllEvents = catchAll; 443 444 if (fCatchAllEvents) 445 _InstallEventFilter(); 446 else 447 _RemoveEventFilter(); 448 } 449 450 // Perform 451 status_t 452 StateView::Perform(Command* command) 453 { 454 if (fCommandStack) 455 return fCommandStack->Perform(command); 456 457 // if there is no command stack, then nobody 458 // else feels responsible... 459 delete command; 460 461 return B_NO_INIT; 462 } 463 464 // #pragma mark - 465 466 // _HandleKeyDown 467 bool 468 StateView::_HandleKeyDown(uint32 key, uint32 modifiers) 469 { 470 return false; 471 } 472 473 // _HandleKeyUp 474 bool 475 StateView::_HandleKeyUp(uint32 key, uint32 modifiers) 476 { 477 return false; 478 } 479 480 // _InstallEventFilter 481 void 482 StateView::_InstallEventFilter() 483 { 484 if (!fCatchAllEvents) 485 return; 486 487 if (!fEventFilter) 488 fEventFilter = new (nothrow) EventFilter(this); 489 490 if (!fEventFilter || !Window()) 491 return; 492 493 Window()->AddCommonFilter(fEventFilter); 494 } 495 496 void 497 StateView::_RemoveEventFilter() 498 { 499 if (!fEventFilter || !Window()) 500 return; 501 502 Window()->RemoveCommonFilter(fEventFilter); 503 } 504 505 // _TriggerUpdate 506 void 507 StateView::_TriggerUpdate() 508 { 509 if (fUpdateTarget && fUpdateTarget->Looper()) { 510 fUpdateTarget->Looper()->PostMessage(fUpdateCommand); 511 } 512 } 513