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 19 MultipleManipulatorState::MultipleManipulatorState(StateView* view) 20 : ViewState(view), 21 fManipulators(24), 22 fCurrentManipulator(NULL), 23 fPreviousManipulator(NULL) 24 { 25 } 26 27 // destructor 28 MultipleManipulatorState::~MultipleManipulatorState() 29 { 30 DeleteManipulators(); 31 } 32 33 // #pragma mark - 34 35 // Init 36 void 37 MultipleManipulatorState::Init() 38 { 39 } 40 41 // Cleanup 42 void 43 MultipleManipulatorState::Cleanup() 44 { 45 } 46 47 // #pragma mark - 48 49 // Draw 50 void 51 MultipleManipulatorState::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 63 bool 64 MultipleManipulatorState::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 80 void 81 MultipleManipulatorState::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 114 void 115 MultipleManipulatorState::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 144 Command* 145 MultipleManipulatorState::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 159 void 160 MultipleManipulatorState::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 171 bool 172 MultipleManipulatorState::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 190 bool 191 MultipleManipulatorState::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 205 bool 206 MultipleManipulatorState::UpdateCursor() 207 { 208 if (fPreviousManipulator && fManipulators.HasItem(fPreviousManipulator)) 209 return fPreviousManipulator->UpdateCursor(); 210 return false; 211 } 212 213 // #pragma mark - 214 215 // AddManipulator 216 bool 217 MultipleManipulatorState::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 231 Manipulator* 232 MultipleManipulatorState::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 248 void 249 MultipleManipulatorState::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 269 int32 270 MultipleManipulatorState::CountManipulators() const 271 { 272 return fManipulators.CountItems(); 273 } 274 275 // ManipulatorAt 276 Manipulator* 277 MultipleManipulatorState::ManipulatorAt(int32 index) const 278 { 279 return (Manipulator*)fManipulators.ItemAt(index); 280 } 281 282 // ManipulatorAtFast 283 Manipulator* 284 MultipleManipulatorState::ManipulatorAtFast(int32 index) const 285 { 286 return (Manipulator*)fManipulators.ItemAtFast(index); 287 } 288 289 // #pragma mark - 290 291 // _UpdateViewCursor 292 void 293 MultipleManipulatorState::_UpdateCursor() 294 { 295 if (fCurrentManipulator) 296 fCurrentManipulator->UpdateCursor(); 297 else 298 fView->SetViewCursor(B_CURSOR_SYSTEM_DEFAULT); 299 } 300 301 // _ShowContextMenu 302 void 303 MultipleManipulatorState::_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