1 /* 2 * Copyright (c) 1999-2000, Eric Moon. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions, and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions, and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 32 // DiagramEndPoint.cpp 33 34 #include "DiagramEndPoint.h" 35 #include "DiagramDefs.h" 36 #include "DiagramWire.h" 37 #include "DiagramView.h" 38 39 #include <Message.h> 40 #include <Messenger.h> 41 __USE_CORTEX_NAMESPACE 42 43 #include <Debug.h> 44 #define D_METHOD(x) //PRINT (x) 45 #define D_MESSAGE(x) //PRINT (x) 46 #define D_MOUSE(x) //PRINT (x) 47 48 // -------------------------------------------------------- // 49 // *** ctor/dtor 50 // -------------------------------------------------------- // 51 52 DiagramEndPoint::DiagramEndPoint( 53 BRect frame) 54 : DiagramItem(DiagramItem::M_ENDPOINT), 55 m_frame(frame), 56 m_wire(0), 57 m_connected(false), 58 m_connecting(false) 59 { 60 D_METHOD(("DiagramEndPoint::DiagramEndPoint()\n")); 61 makeDraggable(true); 62 } 63 64 DiagramEndPoint::~DiagramEndPoint() 65 { 66 D_METHOD(("DiagramEndPoint::~DiagramEndPoint()\n")); 67 } 68 69 // -------------------------------------------------------- // 70 // *** hook functions 71 // -------------------------------------------------------- // 72 73 BPoint DiagramEndPoint::connectionPoint() const 74 { 75 D_METHOD(("DiagramEndPoint::connectionPoint()\n")); 76 return BPoint(Frame().left + Frame().Height() / 2.0, Frame().top + Frame().Width() / 2.0); 77 } 78 79 bool DiagramEndPoint::connectionRequested( 80 DiagramEndPoint *fromWhich) 81 { 82 D_METHOD(("DiagramEndPoint::connectionRequested()\n")); 83 if (!isConnected()) 84 { 85 return true; 86 } 87 return false; 88 } 89 90 // -------------------------------------------------------- // 91 // *** derived from DiagramItem 92 // -------------------------------------------------------- // 93 94 void DiagramEndPoint::Draw( 95 BRect updateRect) 96 { 97 D_METHOD(("DiagramEndPoint::Draw()\n")); 98 if (view()) 99 { 100 view()->PushState(); 101 { 102 BRegion region; 103 region.Include(Frame() & updateRect); 104 view()->ConstrainClippingRegion(®ion); 105 drawEndPoint(); 106 } 107 view()->PopState(); 108 } 109 } 110 111 void DiagramEndPoint::MouseDown( 112 BPoint point, 113 uint32 buttons, 114 uint32 clicks) 115 { 116 D_MOUSE(("DiagramEndPoint::MouseDown()\n")); 117 if (clicks == 1) 118 { 119 if (isSelectable()) 120 { 121 BMessage selectMsg(M_SELECTION_CHANGED); 122 if (modifiers() & B_SHIFT_KEY) 123 { 124 selectMsg.AddBool("replace", false); 125 } 126 else 127 { 128 selectMsg.AddBool("replace", true); 129 } 130 selectMsg.AddPointer("item", reinterpret_cast<void *>(this)); 131 DiagramView* v = view(); 132 BMessenger(v).SendMessage(&selectMsg); 133 } 134 if (isDraggable() && (buttons == B_PRIMARY_MOUSE_BUTTON)) 135 { 136 BMessage dragMsg(M_WIRE_DRAGGED); 137 dragMsg.AddPointer("from", static_cast<void *>(this)); 138 view()->DragMessage(&dragMsg, BRect(0.0, 0.0, -1.0, -1.0), view()); 139 view()->MessageDragged(point, B_INSIDE_VIEW, &dragMsg); 140 } 141 } 142 } 143 144 void DiagramEndPoint::MessageDragged( 145 BPoint point, 146 uint32 transit, 147 const BMessage *message) 148 { 149 D_MOUSE(("DiagramEndPoint::MessageDragged()\n")); 150 switch (message->what) 151 { 152 case M_WIRE_DRAGGED: 153 { 154 D_MESSAGE(("DiagramEndPoint::MessageDragged(M_WIRE_DRAGGED)\n")); 155 switch (transit) 156 { 157 case B_INSIDE_VIEW: 158 { 159 //PRINT((" -> transit: B_INSIDE_VIEW\n")); 160 // this is a WORK-AROUND caused by the unreliability 161 // of BViews DragMessage() routine !! 162 if (isConnecting()) 163 { 164 break; 165 } 166 else if (isConnected()) 167 { 168 view()->trackWire(point); 169 } 170 /* this should be enough in theory: 171 if (!isConnecting()) 172 { 173 view()->trackWire(point); 174 } 175 //break;*/ 176 } 177 case B_ENTERED_VIEW: 178 { 179 //PRINT((" -> transit: B_ENTERED_VIEW\n")); 180 DiagramEndPoint *endPoint; 181 if ((message->FindPointer("from", reinterpret_cast<void **>(&endPoint)) == B_OK) 182 && (endPoint != this)) 183 { 184 if (connectionRequested(endPoint)) 185 { 186 view()->trackWire(connectionPoint()); 187 if (!isConnecting()) 188 { 189 m_connecting = true; 190 connected(); 191 } 192 } 193 else 194 { 195 view()->trackWire(point); 196 if (isConnecting()) 197 { 198 m_connecting = false; 199 disconnected(); 200 } 201 } 202 } 203 break; 204 } 205 case B_EXITED_VIEW: 206 { 207 //PRINT((" -> transit: B_EXITED_VIEW\n")); 208 if (isConnecting()) 209 { 210 m_connecting = false; 211 disconnected(); 212 } 213 break; 214 } 215 } 216 break; 217 } 218 default: 219 { 220 DiagramItem::MessageDragged(point, transit, message); 221 } 222 } 223 } 224 225 void DiagramEndPoint::MessageDropped( 226 BPoint point, 227 BMessage *message) 228 { 229 D_MESSAGE(("DiagramEndPoint::MessageDropped()\n")); 230 switch (message->what) 231 { 232 case M_WIRE_DRAGGED: 233 { 234 D_MESSAGE(("DiagramEndPoint::MessageDropped(M_WIRE_DRAGGED)\n")); 235 DiagramEndPoint *endPoint; 236 if ((message->FindPointer("from", reinterpret_cast<void **>(&endPoint)) == B_OK) 237 && (endPoint != this)) 238 { 239 bool success = connectionRequested(endPoint); 240 BMessage dropMsg(M_WIRE_DROPPED); 241 dropMsg.AddPointer("from", reinterpret_cast<void *>(endPoint)); 242 dropMsg.AddPointer("to", reinterpret_cast<void *>(this)); 243 dropMsg.AddBool("success", success); 244 DiagramView* v = view(); 245 BMessenger(v).SendMessage(&dropMsg); 246 if (isConnecting()) 247 { 248 m_connecting = false; 249 disconnected(); 250 } 251 } 252 return; 253 } 254 default: 255 { 256 DiagramItem::MessageDropped(point, message); 257 } 258 } 259 } 260 261 // -------------------------------------------------------- // 262 // *** frame related operations 263 // -------------------------------------------------------- // 264 265 void DiagramEndPoint::MoveBy( 266 float x, 267 float y, 268 BRegion *updateRegion) 269 { 270 D_METHOD(("DiagramEndPoint::MoveBy()\n")); 271 if (isConnected() && m_wire && updateRegion) 272 { 273 updateRegion->Include(m_wire->Frame()); 274 m_frame.OffsetBy(x, y); 275 m_wire->endPointMoved(this); 276 updateRegion->Include(m_wire->Frame()); 277 } 278 else 279 { 280 m_frame.OffsetBy(x, y); 281 if (m_wire) 282 { 283 m_wire->endPointMoved(this); 284 } 285 } 286 } 287 288 void DiagramEndPoint::ResizeBy( 289 float horizontal, 290 float vertical) 291 { 292 D_METHOD(("DiagramEndPoint::ResizeBy()\n")); 293 m_frame.right += horizontal; 294 m_frame.bottom += vertical; 295 } 296 297 // -------------------------------------------------------- // 298 // *** connection methods 299 // -------------------------------------------------------- // 300 301 void DiagramEndPoint::connect( 302 DiagramWire *wire) 303 { 304 D_METHOD(("DiagramEndPoint::connect()\n")); 305 if (!m_connected && wire) 306 { 307 m_connected = true; 308 m_wire = wire; 309 makeDraggable(false); 310 connected(); 311 } 312 } 313 314 void DiagramEndPoint::disconnect() 315 { 316 D_METHOD(("DiagramEndPoint::disconnect()\n")); 317 if (m_connected) 318 { 319 m_connected = false; 320 m_wire = 0; 321 makeDraggable(true); 322 disconnected(); 323 } 324 } 325 326 // END -- DiagramEndPoint.cpp -- 327