1/* 2 * Copyright 2006-2007, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan A��mus <superstippi@gmx.de> 7 */ 8 9#include "MultipleManipulatorState.h" 10 11#include <stdio.h> 12 13#include <AppDefs.h> 14 15#include "Manipulator.h" 16#include "StateView.h" 17 18// constructor 19MultipleManipulatorState::MultipleManipulatorState(StateView* view) 20 : ViewState(view), 21 fManipulators(24), 22 fCurrentManipulator(NULL), 23 fPreviousManipulator(NULL) 24{ 25} 26 27// destructor 28MultipleManipulatorState::~MultipleManipulatorState() 29{ 30 DeleteManipulators(); 31} 32 33// #pragma mark - 34 35// Init 36void 37MultipleManipulatorState::Init() 38{ 39} 40 41// Cleanup 42void 43MultipleManipulatorState::Cleanup() 44{ 45} 46 47// #pragma mark - 48 49// Draw 50void 51MultipleManipulatorState::Draw(BView* into, BRect updateRect) 52{ 53 int32 count = fManipulators.CountItems(); 54 for (int32 i = 0; i < count; i++) { 55 Manipulator* manipulator = 56 (Manipulator*)fManipulators.ItemAtFast(i); 57 if (manipulator->Bounds().Intersects(updateRect)) 58 manipulator->Draw(into, updateRect); 59 } 60} 61 62// MessageReceived 63bool 64MultipleManipulatorState::MessageReceived(BMessage* message, 65 Command** _command) 66{ 67 int32 count = fManipulators.CountItems(); 68 for (int32 i = 0; i < count; i++) { 69 Manipulator* manipulator = 70 (Manipulator*)fManipulators.ItemAtFast(i); 71 if (manipulator->MessageReceived(message, _command)) 72 return true; 73 } 74 return false; 75} 76 77// #pragma mark - 78 79// MouseDown 80void 81MultipleManipulatorState::MouseDown(BPoint where, uint32 buttons, uint32 clicks) 82{ 83 if (buttons & B_SECONDARY_MOUSE_BUTTON) { 84 _ShowContextMenu(where); 85 return; 86 } 87 88 if (clicks == 2 89 && fPreviousManipulator 90 && fManipulators.HasItem(fPreviousManipulator)) { 91 // valid double click (onto the same, still existing manipulator) 92 if (fPreviousManipulator->TrackingBounds(fView).Contains(where) 93 && fPreviousManipulator->DoubleClicked(where)) { 94 // TODO: eat the click here or wait for MouseUp? 95 fPreviousManipulator = NULL; 96 return; 97 } 98 } 99 100 int32 count = fManipulators.CountItems(); 101 for (int32 i = count - 1; i >= 0; i--) { 102 Manipulator* manipulator = 103 (Manipulator*)fManipulators.ItemAtFast(i); 104 if (manipulator->MouseDown(where)) { 105 fCurrentManipulator = manipulator; 106 break; 107 } 108 } 109 110 fView->SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 111} 112 113// MouseMoved 114void 115MultipleManipulatorState::MouseMoved(BPoint where, uint32 transit, 116 const BMessage* dragMessage) 117{ 118 if (fCurrentManipulator) { 119 // the mouse is currently pressed 120 fCurrentManipulator->MouseMoved(where); 121 122 } else { 123 // the mouse is currently NOT pressed 124 125 // call MouseOver on all manipulators 126 // until one feels responsible 127 int32 count = fManipulators.CountItems(); 128 bool updateCursor = true; 129 for (int32 i = 0; i < count; i++) { 130 Manipulator* manipulator = 131 (Manipulator*)fManipulators.ItemAtFast(i); 132 if (manipulator->TrackingBounds(fView).Contains(where) 133 && manipulator->MouseOver(where)) { 134 updateCursor = false; 135 break; 136 } 137 } 138 if (updateCursor) 139 _UpdateCursor(); 140 } 141} 142 143// MouseUp 144Command* 145MultipleManipulatorState::MouseUp() 146{ 147 Command* command = NULL; 148 if (fCurrentManipulator) { 149 command = fCurrentManipulator->MouseUp(); 150 fPreviousManipulator = fCurrentManipulator; 151 fCurrentManipulator = NULL; 152 } 153 return command; 154} 155 156// #pragma mark - 157 158// ModifiersChanged 159void 160MultipleManipulatorState::ModifiersChanged(uint32 modifiers) 161{ 162 int32 count = fManipulators.CountItems(); 163 for (int32 i = 0; i < count; i++) { 164 Manipulator* manipulator = 165 (Manipulator*)fManipulators.ItemAtFast(i); 166 manipulator->ModifiersChanged(modifiers); 167 } 168} 169 170// HandleKeyDown 171bool 172MultipleManipulatorState::HandleKeyDown(uint32 key, uint32 modifiers, 173 Command** _command) 174{ 175 // TODO: somehow this looks suspicious, because it doesn't 176 // seem guaranteed that the manipulator having indicated to 177 // handle the key down handles the matching key up event... 178 // maybe there should be the concept of the "focused manipulator" 179 int32 count = fManipulators.CountItems(); 180 for (int32 i = 0; i < count; i++) { 181 Manipulator* manipulator = 182 (Manipulator*)fManipulators.ItemAtFast(i); 183 if (manipulator->HandleKeyDown(key, modifiers, _command)) 184 return true; 185 } 186 return false; 187} 188 189// HandleKeyUp 190bool 191MultipleManipulatorState::HandleKeyUp(uint32 key, uint32 modifiers, 192 Command** _command) 193{ 194 int32 count = fManipulators.CountItems(); 195 for (int32 i = 0; i < count; i++) { 196 Manipulator* manipulator = 197 (Manipulator*)fManipulators.ItemAtFast(i); 198 if (manipulator->HandleKeyUp(key, modifiers, _command)) 199 return true; 200 } 201 return false; 202} 203 204// UpdateCursor 205bool 206MultipleManipulatorState::UpdateCursor() 207{ 208 if (fPreviousManipulator && fManipulators.HasItem(fPreviousManipulator)) 209 return fPreviousManipulator->UpdateCursor(); 210 return false; 211} 212 213// #pragma mark - 214 215// AddManipulator 216bool 217MultipleManipulatorState::AddManipulator(Manipulator* manipulator) 218{ 219 if (!manipulator) 220 return false; 221 222 if (fManipulators.AddItem((void*)manipulator)) { 223 manipulator->AttachedToView(fView); 224 fView->Invalidate(manipulator->Bounds()); 225 return true; 226 } 227 return false; 228} 229 230// RemoveManipulator 231Manipulator* 232MultipleManipulatorState::RemoveManipulator(int32 index) 233{ 234 Manipulator* manipulator = (Manipulator*)fManipulators.RemoveItem(index); 235 236 if (manipulator == fCurrentManipulator) 237 fCurrentManipulator = NULL; 238 239 if (manipulator) { 240 fView->Invalidate(manipulator->Bounds()); 241 manipulator->DetachedFromView(fView); 242 } 243 244 return manipulator; 245} 246 247// DeleteManipulators 248void 249MultipleManipulatorState::DeleteManipulators() 250{ 251 BRect dirty(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN); 252 253 int32 count = fManipulators.CountItems(); 254 for (int32 i = 0; i < count; i++) { 255 Manipulator* m = (Manipulator*)fManipulators.ItemAtFast(i); 256 dirty = dirty | m->Bounds(); 257 m->DetachedFromView(fView); 258 delete m; 259 } 260 fManipulators.MakeEmpty(); 261 fCurrentManipulator = NULL; 262 fPreviousManipulator = NULL; 263 264 fView->Invalidate(dirty); 265 _UpdateCursor(); 266} 267 268// CountManipulators 269int32 270MultipleManipulatorState::CountManipulators() const 271{ 272 return fManipulators.CountItems(); 273} 274 275// ManipulatorAt 276Manipulator* 277MultipleManipulatorState::ManipulatorAt(int32 index) const 278{ 279 return (Manipulator*)fManipulators.ItemAt(index); 280} 281 282// ManipulatorAtFast 283Manipulator* 284MultipleManipulatorState::ManipulatorAtFast(int32 index) const 285{ 286 return (Manipulator*)fManipulators.ItemAtFast(index); 287} 288 289// #pragma mark - 290 291// _UpdateViewCursor 292void 293MultipleManipulatorState::_UpdateCursor() 294{ 295 if (fCurrentManipulator) 296 fCurrentManipulator->UpdateCursor(); 297 else 298 fView->SetViewCursor(B_CURSOR_SYSTEM_DEFAULT); 299} 300 301// _ShowContextMenu 302void 303MultipleManipulatorState::_ShowContextMenu(BPoint where) 304{ 305 int32 count = fManipulators.CountItems(); 306 for (int32 i = 0; i < count; i++) { 307 Manipulator* manipulator = 308 (Manipulator*)fManipulators.ItemAtFast(i); 309 if (manipulator->ShowContextMenu(where)) 310 return; 311 } 312} 313 314 315