btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / cortex / DiagramView / DiagramView.cpp
blob6503a5d25aa1b02fa6fee0e06c886c7f64135521
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
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.
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.
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.
32 // DiagramView.cpp
34 #include "DiagramView.h"
35 #include "DiagramDefs.h"
36 #include "DiagramBox.h"
37 #include "DiagramEndPoint.h"
38 #include "DiagramWire.h"
40 #include <Bitmap.h>
41 #include <Message.h>
42 #include <ScrollBar.h>
44 __USE_CORTEX_NAMESPACE
46 #include <Debug.h>
47 #define D_METHOD(x) //PRINT (x)
48 #define D_HOOK(x) //PRINT (x)
49 #define D_MESSAGE(x) //PRINT (x)
50 #define D_MOUSE(x) //PRINT (x)
51 #define D_DRAW(x) //PRINT (x)
53 // -------------------------------------------------------- //
54 // *** ctor/dtor
55 // -------------------------------------------------------- //
57 DiagramView::DiagramView(
58 BRect frame,
59 const char *name,
60 bool multiSelection,
61 uint32 resizingMode,
62 uint32 flags)
63 : BView(frame, name, resizingMode, B_WILL_DRAW | B_FRAME_EVENTS | flags),
64 DiagramItemGroup(DiagramItem::M_BOX | DiagramItem::M_WIRE),
65 m_lastButton(0),
66 m_clickCount(0),
67 m_lastClickPoint(-1.0, -1.0),
68 m_pressedButton(0),
69 m_draggedWire(0),
70 m_useBackgroundBitmap(false),
71 m_backgroundBitmap(0)
73 D_METHOD(("DiagramView::DiagramView()\n"));
74 SetViewColor(B_TRANSPARENT_COLOR);
75 m_dataRect = Bounds();
78 DiagramView::~DiagramView()
80 D_METHOD(("DiagramView::~DiagramView()\n"));
83 // -------------------------------------------------------- //
84 // *** hook functions
85 // -------------------------------------------------------- //
87 void DiagramView::MessageDragged(
88 BPoint point,
89 uint32 transit,
90 const BMessage *message)
92 D_METHOD(("DiagramView::MessageDragged()\n"));
93 switch (message->what)
95 case M_WIRE_DRAGGED:
97 D_MESSAGE(("DiagramView::MessageDragged(M_WIRE_DROPPED)\n"));
98 if (!m_draggedWire)
100 DiagramEndPoint *fromEndPoint;
101 if (message->FindPointer("from", reinterpret_cast<void **>(&fromEndPoint)) == B_OK)
103 _beginWireTracking(fromEndPoint);
106 trackWire(point);
107 break;
112 void DiagramView::MessageDropped(
113 BPoint point,
114 BMessage *message)
116 D_METHOD(("DiagramView::MessageDropped()\n"));
117 switch (message->what)
119 case M_WIRE_DRAGGED:
121 D_MESSAGE(("DiagramView::MessageDropped(M_WIRE_DROPPED)\n"));
122 DiagramEndPoint *fromWhich = 0;
123 if (message->FindPointer("from", reinterpret_cast<void **>(&fromWhich)) == B_OK)
125 connectionAborted(fromWhich);
127 break;
132 // -------------------------------------------------------- //
133 // *** derived from BView
134 // -------------------------------------------------------- //
136 // initial scrollbar update [e.moon 16nov99]
137 void DiagramView::AttachedToWindow()
139 D_METHOD(("DiagramView::AttachedToWindow()\n"));
140 _updateScrollBars();
143 void DiagramView::Draw(
144 BRect updateRect)
146 D_METHOD(("DiagramView::Draw()\n"));
147 drawBackground(updateRect);
148 DrawItems(updateRect, DiagramItem::M_WIRE);
149 DrawItems(updateRect, DiagramItem::M_BOX);
152 void DiagramView::FrameResized(
153 float width,
154 float height)
156 D_METHOD(("DiagramView::FrameResized()\n"));
157 _updateScrollBars();
160 void DiagramView::GetPreferredSize(
161 float *width,
162 float *height) {
163 D_HOOK(("DiagramView::GetPreferredSize()\n"));
165 *width = m_dataRect.Width() + 10.0;
166 *height = m_dataRect.Height() + 10.0;
169 void DiagramView::MessageReceived(
170 BMessage *message)
172 D_METHOD(("DiagramView::MessageReceived()\n"));
173 switch (message->what)
175 case M_SELECTION_CHANGED:
177 D_MESSAGE(("DiagramView::MessageReceived(M_SELECTION_CHANGED)\n"));
178 DiagramItem *item;
179 if (message->FindPointer("item", reinterpret_cast<void **>(&item)) == B_OK)
181 bool deselectOthers = true;
182 message->FindBool("replace", &deselectOthers);
183 if (item->isSelected() && !deselectOthers && MultipleSelection())
185 if (DeselectItem(item))
187 SelectionChanged();
190 else if (SelectItem(item, deselectOthers))
192 SortItems(item->type(), &compareSelectionTime);
193 SelectionChanged();
196 break;
198 case M_WIRE_DROPPED:
200 D_MESSAGE(("DiagramView::MessageReceived(M_WIRE_DROPPED)\n"));
201 DiagramEndPoint *fromWhich = 0;
202 DiagramEndPoint *toWhich = 0;
203 bool success = false;
204 if (message->FindPointer("from", reinterpret_cast<void **>(&fromWhich)) == B_OK)
206 if ((message->FindPointer("to", reinterpret_cast<void **>(&toWhich)) == B_OK)
207 && (message->FindBool("success", &success) == B_OK))
209 if (success && fromWhich && toWhich)
211 _endWireTracking();
212 DiagramWire *wire = createWire(fromWhich, toWhich);
213 if (wire && AddItem(wire))
215 connectionEstablished(fromWhich, toWhich);
216 break;
221 connectionAborted(fromWhich);
222 break;
224 default:
226 if (message->WasDropped())
228 BPoint point = ConvertFromScreen(message->DropPoint());
229 DiagramItem *item = ItemUnder(point);
230 if (item)
232 item->MessageDropped(point, message);
233 return;
235 else
237 MessageDropped(point, message);
240 else
242 BView::MessageReceived(message);
248 void DiagramView::KeyDown(
249 const char *bytes,
250 int32 numBytes)
252 D_METHOD(("DiagramView::KeyDown()\n"));
253 switch (bytes[0])
255 case B_LEFT_ARROW:
257 float x;
258 GetItemAlignment(&x, 0);
259 BRegion updateRegion;
260 DragSelectionBy(-x, 0.0, &updateRegion);
261 for (int32 i = 0; i < updateRegion.CountRects(); i++)
262 Invalidate(updateRegion.RectAt(i));
263 updateDataRect();
264 break;
266 case B_RIGHT_ARROW:
268 float x;
269 GetItemAlignment(&x, 0);
270 BRegion updateRegion;
271 DragSelectionBy(x, 0.0, &updateRegion);
272 for (int32 i = 0; i < updateRegion.CountRects(); i++)
273 Invalidate(updateRegion.RectAt(i));
274 updateDataRect();
275 break;
277 case B_UP_ARROW:
279 float y;
280 GetItemAlignment(0, &y);
281 BRegion updateRegion;
282 DragSelectionBy(0.0, -y, &updateRegion);
283 for (int32 i = 0; i < updateRegion.CountRects(); i++)
284 Invalidate(updateRegion.RectAt(i));
285 updateDataRect();
286 break;
288 case B_DOWN_ARROW:
290 float y;
291 GetItemAlignment(0, &y);
292 BRegion updateRegion;
293 DragSelectionBy(0.0, y, &updateRegion);
294 for (int32 i = 0; i < updateRegion.CountRects(); i++)
295 Invalidate(updateRegion.RectAt(i));
296 updateDataRect();
297 break;
299 default:
301 BView::KeyDown(bytes, numBytes);
302 break;
307 void DiagramView::MouseDown(
308 BPoint point)
310 D_METHOD(("DiagramView::MouseDown()\n"));
312 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
314 // update click count
315 BMessage* message = Window()->CurrentMessage();
316 int32 clicks = message->FindInt32("clicks");
317 int32 buttons = message->FindInt32("buttons");
319 bool moved = (fabs(point.x - m_lastClickPoint.x) > 2.0 || fabs(point.y - m_lastClickPoint.y) > 2.0);
320 if (!moved && (buttons == m_lastButton) && (clicks > 1))
322 m_clickCount++;
324 else
326 m_clickCount = 1;
328 m_lastButton = buttons;
329 m_lastClickPoint = point;
330 m_lastDragPoint = ConvertToScreen(point);
332 // [e.moon 16nov99] scroll on 3rd button
333 m_pressedButton = buttons;
334 if(m_pressedButton == B_TERTIARY_MOUSE_BUTTON) {
335 return;
338 // was an item clicked ?
339 DiagramItem *item = ItemUnder(point);
340 if (item)
342 item->MouseDown(point, m_lastButton, m_clickCount);
344 else // no, the background was clicked
346 if (!(modifiers() & B_SHIFT_KEY) && DeselectAll(DiagramItem::M_ANY))
347 SelectionChanged();
348 if (MultipleSelection() && (m_lastButton == B_PRIMARY_MOUSE_BUTTON) && !(modifiers() & B_CONTROL_KEY))
349 _beginRectTracking(point);
350 BackgroundMouseDown(point, m_lastButton, m_clickCount);
354 void DiagramView::MouseMoved(
355 BPoint point,
356 uint32 transit,
357 const BMessage *message)
359 D_METHOD(("DiagramView::MouseMoved()\n"));
362 // [e.moon 16nov99] 3rd-button scrolling
363 if(m_pressedButton == B_TERTIARY_MOUSE_BUTTON) {
365 // fetch/store screen point; calculate distance travelled
366 ConvertToScreen(&point);
367 float xDelta = m_lastDragPoint.x - point.x;
368 float yDelta = m_lastDragPoint.y - point.y;
369 m_lastDragPoint = point;
371 // constrain to scrollbar limits
372 BScrollBar* hScroll = ScrollBar(B_HORIZONTAL);
373 if(xDelta && hScroll) {
374 float val = hScroll->Value();
375 float min, max;
376 hScroll->GetRange(&min, &max);
378 if(val + xDelta < min)
379 xDelta = 0;
381 if(val + xDelta > max)
382 xDelta = 0;
385 BScrollBar* vScroll = ScrollBar(B_VERTICAL);
386 if(yDelta && vScroll) {
387 float val = vScroll->Value();
388 float min, max;
389 vScroll->GetRange(&min, &max);
391 if(val + yDelta < min)
392 yDelta = 0;
394 if(val + yDelta > max)
395 yDelta = 0;
398 // scroll
399 if(xDelta == 0.0 && yDelta == 0.0)
400 return;
402 ScrollBy(xDelta, yDelta);
403 return;
406 if (message)
408 switch (message->what)
410 case M_RECT_TRACKING:
412 BPoint origin;
413 if (message->FindPoint("origin", &origin) == B_OK)
415 _trackRect(origin, point);
417 break;
419 case M_BOX_DRAGGED:
421 DiagramBox *box;
422 BPoint offset;
423 if ((message->FindPointer("item", reinterpret_cast<void **>(&box)) == B_OK)
424 && (message->FindPoint("offset", &offset) == B_OK))
426 if (box)
428 BRegion updateRegion;
429 DragSelectionBy(point.x - box->Frame().left - offset.x,
430 point.y - box->Frame().top - offset.y,
431 &updateRegion);
432 updateDataRect();
433 for (int32 i = 0; i < updateRegion.CountRects(); i++)
435 Invalidate(updateRegion.RectAt(i));
439 break;
441 default: // unkwown message -> redirect to MessageDragged()
443 DiagramItem *last = _LastItemUnder();
444 if (transit == B_EXITED_VIEW)
446 if (last)
448 last->MessageDragged(point, B_EXITED_VIEW, message);
449 MessageDragged(point, B_EXITED_VIEW, message);
452 else
454 DiagramItem *item = ItemUnder(point);
455 if (item)
457 if (item != last)
459 if (last)
460 last->MessageDragged(point, B_EXITED_VIEW, message);
461 item->MessageDragged(point, B_ENTERED_VIEW, message);
463 else
465 item->MessageDragged(point, B_INSIDE_VIEW, message);
468 else if (last)
470 last->MessageDragged(point, B_EXITED_VIEW, message);
471 MessageDragged(point, B_ENTERED_VIEW, message);
473 else
475 MessageDragged(point, transit, message);
478 break;
482 else // no message at all -> redirect to MouseOver()
484 DiagramItem *last = _LastItemUnder();
485 if ((transit == B_EXITED_VIEW) || (transit == B_OUTSIDE_VIEW))
487 if (last)
489 last->MouseOver(point, B_EXITED_VIEW);
490 _ResetItemUnder();
491 MouseOver(point, B_EXITED_VIEW);
494 else
496 DiagramItem *item = ItemUnder(point);
497 if (item)
499 if (item != last)
501 if (last)
502 last->MouseOver(point, B_EXITED_VIEW);
503 item->MouseOver(point, B_ENTERED_VIEW);
505 else
507 item->MouseOver(point, B_INSIDE_VIEW);
510 else if (last)
512 last->MouseOver(point, B_EXITED_VIEW);
513 MouseOver(point, B_ENTERED_VIEW);
519 void DiagramView::MouseUp(
520 BPoint point)
522 D_METHOD(("DiagramView::MouseUp()\n"));
523 if (MultipleSelection())
524 EndRectTracking();
525 _endWireTracking();
527 // [e.moon 16nov99] mark no button as down
528 m_pressedButton = 0;
531 // -------------------------------------------------------- //
532 // *** derived from DiagramItemGroup (public)
533 // -------------------------------------------------------- //
535 bool DiagramView::AddItem(
536 DiagramItem *item)
538 D_METHOD(("DiagramBox::AddItem()\n"));
539 if (item)
541 if (DiagramItemGroup::AddItem(item))
543 item->_SetOwner(this);
544 item->attachedToDiagram();
545 if (item->type() == DiagramItem::M_BOX)
547 updateDataRect();
549 return true;
552 return false;
555 bool DiagramView::RemoveItem(
556 DiagramItem *item)
558 D_METHOD(("DiagramBox::RemoveItem()\n"));
559 if (item)
561 item->detachedFromDiagram();
562 if (DiagramItemGroup::RemoveItem(item))
564 item->_SetOwner(0);
565 if (item->type() == DiagramItem::M_BOX)
567 updateDataRect();
569 return true;
572 return false;
575 // -------------------------------------------------------- //
576 // *** operations (public)
577 // -------------------------------------------------------- //
579 void DiagramView::trackWire(
580 BPoint point)
582 D_MOUSE(("DiagramView::trackWire()\n"));
583 if (m_draggedWire)
585 BRegion region;
586 region.Include(m_draggedWire->Frame());
587 m_draggedWire->m_dragEndPoint = point;
588 m_draggedWire->endPointMoved();
589 region.Include(m_draggedWire->Frame());
590 region.Exclude(&m_boxRegion);
591 for (int32 i = 0; i < region.CountRects(); i++)
593 Invalidate(region.RectAt(i));
598 // -------------------------------------------------------- //
599 // *** internal operations (protected)
600 // -------------------------------------------------------- //
602 void DiagramView::drawBackground(
603 BRect updateRect)
605 D_METHOD(("DiagramView::drawBackground()\n"));
606 if (m_useBackgroundBitmap)
608 BRegion region;
609 region.Include(updateRect);
610 region.Exclude(&m_boxRegion);
611 BRect bounds = Bounds();
612 PushState();
614 ConstrainClippingRegion(&region);
615 for (float y = 0; y < bounds.bottom; y += m_backgroundBitmap->Bounds().Height())
617 for (float x = 0; x < bounds.right; x += m_backgroundBitmap->Bounds().Width())
619 DrawBitmapAsync(m_backgroundBitmap, BPoint(x, y));
623 PopState();
625 else
627 BRegion region;
628 region.Include(updateRect);
629 region.Exclude(&m_boxRegion);
630 PushState();
632 SetLowColor(m_backgroundColor);
633 FillRegion(&region, B_SOLID_LOW);
635 PopState();
639 void DiagramView::setBackgroundColor(
640 rgb_color color)
642 D_METHOD(("DiagramView::setBackgroundColor()\n"));
643 m_backgroundColor = color;
644 m_useBackgroundBitmap = false;
648 void
649 DiagramView::setBackgroundBitmap(BBitmap* bitmap)
651 D_METHOD(("DiagramView::setBackgroundBitmap()\n"));
652 if (m_backgroundBitmap)
653 delete m_backgroundBitmap;
655 m_backgroundBitmap = new BBitmap(bitmap);
656 m_useBackgroundBitmap = true;
660 void
661 DiagramView::updateDataRect()
663 D_METHOD(("DiagramView::updateDataRect()\n"));
664 // calculate the area in which boxes display
665 m_boxRegion.MakeEmpty();
666 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) {
667 m_boxRegion.Include(ItemAt(i, DiagramItem::M_BOX)->Frame());
669 // adapt the data rect to the new region of boxes
670 BRect boxRect = m_boxRegion.Frame();
671 m_dataRect.right = boxRect.right;
672 m_dataRect.bottom = boxRect.bottom;
673 // update the scroll bars
674 _updateScrollBars();
678 // #pragma mark - internal operations (private)
681 void
682 DiagramView::_beginWireTracking(DiagramEndPoint *startPoint)
684 D_METHOD(("DiagramView::beginWireTracking()\n"));
685 m_draggedWire = createWire(startPoint);
686 AddItem(m_draggedWire);
687 SelectItem(m_draggedWire, true);
688 Invalidate(startPoint->Frame());
691 void DiagramView::_endWireTracking()
693 D_METHOD(("DiagramView::endWireTracking()\n"));
694 if (m_draggedWire)
696 RemoveItem(m_draggedWire);
697 Invalidate(m_draggedWire->Frame());
698 DiagramEndPoint *endPoint = m_draggedWire->startPoint();
699 if (!endPoint)
701 endPoint = m_draggedWire->endPoint();
703 if (endPoint)
705 Invalidate(endPoint->Frame());
707 delete m_draggedWire;
708 m_draggedWire = 0;
712 void DiagramView::_beginRectTracking(
713 BPoint origin)
715 D_METHOD(("DiagramView::beginRectTracking()\n"));
716 BMessage message(M_RECT_TRACKING);
717 message.AddPoint("origin", origin);
718 DragMessage(&message, BRect(0.0, 0.0, -1.0, -1.0));
719 BView::BeginRectTracking(BRect(origin, origin), B_TRACK_RECT_CORNER);
723 void
724 DiagramView::_trackRect(BPoint origin, BPoint current)
726 D_METHOD(("DiagramView::trackRect()\n"));
727 bool changed = false;
728 BRect rect;
729 rect.left = origin.x < current.x ? origin.x : current.x;
730 rect.top = origin.y < current.y ? origin.y : current.y;
731 rect.right = origin.x < current.x ? current.x : origin.x;
732 rect.bottom = origin.y < current.y ? current.y : origin.y;
733 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) {
734 DiagramBox *box = dynamic_cast<DiagramBox *>(ItemAt(i, DiagramItem::M_BOX));
735 if (box) {
736 if (rect.Intersects(box->Frame()))
737 changed |= SelectItem(box, false);
738 else
739 changed |= DeselectItem(box);
743 if (changed) {
744 SortItems(DiagramItem::M_BOX, &compareSelectionTime);
745 SelectionChanged();
750 void
751 DiagramView::_updateScrollBars()
753 D_METHOD(("DiagramView::_updateScrollBars()\n"));
754 // fetch the vertical ScrollBar
755 BScrollBar *scrollBar = ScrollBar(B_VERTICAL);
756 if (scrollBar)
758 // Disable the ScrollBar if the view is large enough to display
759 // the entire data-rect
760 if (Bounds().Height() > m_dataRect.Height())
762 scrollBar->SetRange(0.0, 0.0);
763 scrollBar->SetProportion(1.0);
765 else
767 scrollBar->SetRange(m_dataRect.top, m_dataRect.bottom - Bounds().Height());
768 scrollBar->SetProportion(Bounds().Height() / m_dataRect.Height());
771 scrollBar = ScrollBar(B_HORIZONTAL);
772 if (scrollBar)
774 // Disable the ScrollBar if the view is large enough to display
775 // the entire data-rect
776 if (Bounds().Width() > m_dataRect.Width())
778 scrollBar->SetRange(0.0, 0.0);
779 scrollBar->SetProportion(1.0);
781 else
783 scrollBar->SetRange(m_dataRect.left, m_dataRect.right - Bounds().Width());
784 scrollBar->SetProportion(Bounds().Width() / m_dataRect.Width());
789 // END -- DiagramView.cpp --