xref: /haiku/src/apps/cortex/DiagramView/DiagramView.cpp (revision 2600324b57fa31cdea1627d584d314f2a579c4a8)
1 // DiagramView.cpp
2 
3 #include "DiagramView.h"
4 #include "DiagramDefs.h"
5 #include "DiagramBox.h"
6 #include "DiagramEndPoint.h"
7 #include "DiagramWire.h"
8 
9 #include <Bitmap.h>
10 #include <Message.h>
11 #include <ScrollBar.h>
12 
13 __USE_CORTEX_NAMESPACE
14 
15 #include <Debug.h>
16 #define D_METHOD(x) //PRINT (x)
17 #define D_HOOK(x) //PRINT (x)
18 #define D_MESSAGE(x) //PRINT (x)
19 #define D_MOUSE(x) //PRINT (x)
20 #define D_DRAW(x) //PRINT (x)
21 
22 // -------------------------------------------------------- //
23 // *** ctor/dtor
24 // -------------------------------------------------------- //
25 
26 DiagramView::DiagramView(
27 	BRect frame,
28 	const char *name,
29 	bool multiSelection,
30 	uint32 resizingMode,
31 	uint32 flags)
32 	: BView(frame, name, resizingMode, B_WILL_DRAW | B_FRAME_EVENTS | flags),
33 	  DiagramItemGroup(DiagramItem::M_BOX | DiagramItem::M_WIRE),
34 	  m_lastButton(0),
35 	  m_clickCount(0),
36 	  m_lastClickPoint(-1.0, -1.0),
37 	  m_pressedButton(0),
38 	  m_draggedWire(0),
39 	  m_useBackgroundBitmap(false),
40 	  m_backgroundBitmap(0)
41 {
42 	D_METHOD(("DiagramView::DiagramView()\n"));
43 	SetViewColor(B_TRANSPARENT_COLOR);
44 	m_dataRect = Bounds();
45 }
46 
47 DiagramView::~DiagramView()
48 {
49 	D_METHOD(("DiagramView::~DiagramView()\n"));
50 }
51 
52 // -------------------------------------------------------- //
53 // *** hook functions
54 // -------------------------------------------------------- //
55 
56 void DiagramView::MessageDragged(
57 	BPoint point,
58 	uint32 transit,
59 	const BMessage *message)
60 {
61 	D_METHOD(("DiagramView::MessageDragged()\n"));
62 	switch (message->what)
63 	{
64 		case M_WIRE_DRAGGED:
65 		{
66 			D_MESSAGE(("DiagramView::MessageDragged(M_WIRE_DROPPED)\n"));
67 			if (!m_draggedWire)
68 			{
69 				DiagramEndPoint *fromEndPoint;
70 				if (message->FindPointer("from", reinterpret_cast<void **>(&fromEndPoint)) == B_OK)
71 				{
72 					_beginWireTracking(fromEndPoint);
73 				}
74 			}
75 			trackWire(point);
76 			break;
77 		}
78 	}
79 }
80 
81 void DiagramView::MessageDropped(
82 	BPoint point,
83 	BMessage *message)
84 {
85 	D_METHOD(("DiagramView::MessageDropped()\n"));
86 	switch (message->what)
87 	{
88 		case M_WIRE_DRAGGED:
89 		{
90 			D_MESSAGE(("DiagramView::MessageDropped(M_WIRE_DROPPED)\n"));
91 			DiagramEndPoint *fromWhich = 0;
92 			if (message->FindPointer("from", reinterpret_cast<void **>(&fromWhich)) == B_OK)
93 			{
94 				connectionAborted(fromWhich);
95 			}
96 			break;
97 		}
98 	}
99 }
100 
101 // -------------------------------------------------------- //
102 // *** derived from BView
103 // -------------------------------------------------------- //
104 
105 // initial scrollbar update [e.moon 16nov99]
106 void DiagramView::AttachedToWindow()
107 {
108 	D_METHOD(("DiagramView::AttachedToWindow()\n"));
109 	_updateScrollBars();
110 }
111 
112 void DiagramView::Draw(
113 	BRect updateRect)
114 {
115 	D_METHOD(("DiagramView::Draw()\n"));
116 	drawBackground(updateRect);
117 	DrawItems(updateRect, DiagramItem::M_WIRE);
118 	DrawItems(updateRect, DiagramItem::M_BOX);
119 }
120 
121 void DiagramView::FrameResized(
122 	float width,
123 	float height)
124 {
125 	D_METHOD(("DiagramView::FrameResized()\n"));
126 	_updateScrollBars();
127 }
128 
129 void DiagramView::GetPreferredSize(
130 	float *width,
131 	float *height) {
132 	D_HOOK(("DiagramView::GetPreferredSize()\n"));
133 
134 	*width = m_dataRect.Width() + 10.0;
135 	*height = m_dataRect.Height() + 10.0;
136 }
137 
138 void DiagramView::MessageReceived(
139 	BMessage *message)
140 {
141 	D_METHOD(("DiagramView::MessageReceived()\n"));
142 	switch (message->what)
143 	{
144 		case M_SELECTION_CHANGED:
145 		{
146 			D_MESSAGE(("DiagramView::MessageReceived(M_SELECTION_CHANGED)\n"));
147 			DiagramItem *item;
148 			if (message->FindPointer("item", reinterpret_cast<void **>(&item)) == B_OK)
149 			{
150 				bool deselectOthers = true;
151 				message->FindBool("replace", &deselectOthers);
152 				if (item->isSelected() && !deselectOthers && MultipleSelection())
153 				{
154 					if (DeselectItem(item))
155 					{
156 						SelectionChanged();
157 					}
158 				}
159 				else if (SelectItem(item, deselectOthers))
160 				{
161 					SortItems(item->type(), &compareSelectionTime);
162 					SelectionChanged();
163 				}
164 			}
165 			break;
166 		}
167 		case M_WIRE_DROPPED:
168 		{
169 			D_MESSAGE(("DiagramView::MessageReceived(M_WIRE_DROPPED)\n"));
170 			DiagramEndPoint *fromWhich = 0;
171 			DiagramEndPoint *toWhich = 0;
172 			bool success = false;
173 			if (message->FindPointer("from", reinterpret_cast<void **>(&fromWhich)) == B_OK)
174 			{
175 				if ((message->FindPointer("to", reinterpret_cast<void **>(&toWhich)) == B_OK)
176 				 && (message->FindBool("success", &success) == B_OK))
177 				{
178 					if (success && fromWhich && toWhich)
179 					{
180 						_endWireTracking();
181 						DiagramWire *wire = createWire(fromWhich, toWhich);
182 						if (wire && AddItem(wire))
183 						{
184 							connectionEstablished(fromWhich, toWhich);
185 							break;
186 						}
187 					}
188 				}
189 			}
190 			connectionAborted(fromWhich);
191 			break;
192 		}
193 		default:
194 		{
195 			if (message->WasDropped())
196 			{
197 				BPoint point = ConvertFromScreen(message->DropPoint());
198 				DiagramItem *item = ItemUnder(point);
199 				if (item)
200 				{
201 					item->MessageDropped(point, message);
202 					return;
203 				}
204 				else
205 				{
206 					MessageDropped(point, message);
207 				}
208 			}
209 			else
210 			{
211 				BView::MessageReceived(message);
212 			}
213 		}
214 	}
215 }
216 
217 void DiagramView::KeyDown(
218 	const char *bytes,
219 	int32 numBytes)
220 {
221 	D_METHOD(("DiagramView::KeyDown()\n"));
222 	switch (bytes[0])
223 	{
224 		case B_LEFT_ARROW:
225 		{
226 			float x;
227 			GetItemAlignment(&x, 0);
228 			BRegion updateRegion;
229 			DragSelectionBy(-x, 0.0, &updateRegion);
230 			for (int32 i = 0; i < updateRegion.CountRects(); i++)
231 				Invalidate(updateRegion.RectAt(i));
232 			updateDataRect();
233 			break;
234 		}
235 		case B_RIGHT_ARROW:
236 		{
237 			float x;
238 			GetItemAlignment(&x, 0);
239 			BRegion updateRegion;
240 			DragSelectionBy(x, 0.0, &updateRegion);
241 			for (int32 i = 0; i < updateRegion.CountRects(); i++)
242 				Invalidate(updateRegion.RectAt(i));
243 			updateDataRect();
244 			break;
245 		}
246 		case B_UP_ARROW:
247 		{
248 			float y;
249 			GetItemAlignment(0, &y);
250 			BRegion updateRegion;
251 			DragSelectionBy(0.0, -y, &updateRegion);
252 			for (int32 i = 0; i < updateRegion.CountRects(); i++)
253 				Invalidate(updateRegion.RectAt(i));
254 			updateDataRect();
255 			break;
256 		}
257 		case B_DOWN_ARROW:
258 		{
259 			float y;
260 			GetItemAlignment(0, &y);
261 			BRegion updateRegion;
262 			DragSelectionBy(0.0, y, &updateRegion);
263 			for (int32 i = 0; i < updateRegion.CountRects(); i++)
264 				Invalidate(updateRegion.RectAt(i));
265 			updateDataRect();
266 			break;
267 		}
268 		default:
269 		{
270 			BView::KeyDown(bytes, numBytes);
271 			break;
272 		}
273 	}
274 }
275 
276 void DiagramView::MouseDown(
277 	BPoint point)
278 {
279 	D_METHOD(("DiagramView::MouseDown()\n"));
280 
281 	SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
282 
283 	// update click count
284 	BMessage* message = Window()->CurrentMessage();
285 	int32 clicks = message->FindInt32("clicks");
286 	int32 buttons = message->FindInt32("buttons");
287 
288 	bool moved = (fabs(point.x - m_lastClickPoint.x) > 2.0 || fabs(point.y - m_lastClickPoint.y) > 2.0);
289 	if (!moved && (buttons == m_lastButton) && (clicks > 1))
290 	{
291 		m_clickCount++;
292 	}
293 	else
294 	{
295 		m_clickCount = 1;
296 	}
297 	m_lastButton = buttons;
298 	m_lastClickPoint = point;
299 	m_lastDragPoint = ConvertToScreen(point);
300 
301 	// [e.moon 16nov99] scroll on 3rd button
302 	m_pressedButton = buttons;
303 	if(m_pressedButton == B_TERTIARY_MOUSE_BUTTON) {
304 		return;
305 	}
306 
307 	// was an item clicked ?
308  	DiagramItem *item = ItemUnder(point);
309 	if (item)
310 	{
311 		item->MouseDown(point, m_lastButton, m_clickCount);
312 	}
313 	else // no, the background was clicked
314 	{
315 		if (!(modifiers() & B_SHIFT_KEY) && DeselectAll(DiagramItem::M_ANY))
316 			SelectionChanged();
317 		if (MultipleSelection() && (m_lastButton == B_PRIMARY_MOUSE_BUTTON) && !(modifiers() & B_CONTROL_KEY))
318 			_beginRectTracking(point);
319 		BackgroundMouseDown(point, m_lastButton, m_clickCount);
320 	}
321 }
322 
323 void DiagramView::MouseMoved(
324 	BPoint point,
325 	uint32 transit,
326 	const BMessage *message)
327 {
328 	D_METHOD(("DiagramView::MouseMoved()\n"));
329 
330 
331 	// [e.moon 16nov99] 3rd-button scrolling
332 	if(m_pressedButton == B_TERTIARY_MOUSE_BUTTON) {
333 
334 		// fetch/store screen point; calculate distance travelled
335 		ConvertToScreen(&point);
336 		float xDelta = m_lastDragPoint.x - point.x;
337 		float yDelta = m_lastDragPoint.y - point.y;
338 		m_lastDragPoint = point;
339 
340 		// constrain to scrollbar limits
341 		BScrollBar* hScroll = ScrollBar(B_HORIZONTAL);
342 		if(xDelta && hScroll) {
343 			float val = hScroll->Value();
344 			float min, max;
345 			hScroll->GetRange(&min, &max);
346 
347 			if(val + xDelta < min)
348 				xDelta = 0;
349 
350 			if(val + xDelta > max)
351 				xDelta = 0;
352 		}
353 
354 		BScrollBar* vScroll = ScrollBar(B_VERTICAL);
355 		if(yDelta && vScroll) {
356 			float val = vScroll->Value();
357 			float min, max;
358 			vScroll->GetRange(&min, &max);
359 
360 			if(val + yDelta < min)
361 				yDelta = 0;
362 
363 			if(val + yDelta > max)
364 				yDelta = 0;
365 		}
366 
367 		// scroll
368 		if(xDelta == 0.0 && yDelta == 0.0)
369 			return;
370 
371 		ScrollBy(xDelta, yDelta);
372 		 return;
373 	}
374 
375 	if (message)
376 	{
377 		switch (message->what)
378 		{
379 			case M_RECT_TRACKING:
380 			{
381 				BPoint origin;
382 				if (message->FindPoint("origin", &origin) == B_OK)
383 				{
384 					_trackRect(origin, point);
385 				}
386 				break;
387 			}
388 			case M_BOX_DRAGGED:
389 			{
390 				DiagramBox *box;
391 				BPoint offset;
392 				if ((message->FindPointer("item", reinterpret_cast<void **>(&box)) == B_OK)
393 				 && (message->FindPoint("offset", &offset) == B_OK))
394 				{
395 					if (box)
396 					{
397 						BRegion updateRegion;
398 						DragSelectionBy(point.x - box->Frame().left - offset.x,
399 										point.y - box->Frame().top - offset.y,
400 										&updateRegion);
401 						updateDataRect();
402 						for (int32 i = 0; i < updateRegion.CountRects(); i++)
403 						{
404 							Invalidate(updateRegion.RectAt(i));
405 						}
406 					}
407 				}
408 				break;
409 			}
410 			default: // unkwown message -> redirect to MessageDragged()
411 			{
412 				DiagramItem *last = _LastItemUnder();
413 				if (transit == B_EXITED_VIEW)
414 				{
415 					if (last)
416 					{
417 						last->MessageDragged(point, B_EXITED_VIEW, message);
418 						MessageDragged(point, B_EXITED_VIEW, message);
419 					}
420 				}
421 				else
422 				{
423 					DiagramItem *item = ItemUnder(point);
424 					if (item)
425 					{
426 						if (item != last)
427 						{
428 							if (last)
429 								last->MessageDragged(point, B_EXITED_VIEW, message);
430 							item->MessageDragged(point, B_ENTERED_VIEW, message);
431 						}
432 						else
433 						{
434 							item->MessageDragged(point, B_INSIDE_VIEW, message);
435 						}
436 					}
437 					else if (last)
438 					{
439 						last->MessageDragged(point, B_EXITED_VIEW, message);
440 						MessageDragged(point, B_ENTERED_VIEW, message);
441 					}
442 					else
443 					{
444 						MessageDragged(point, transit, message);
445 					}
446 				}
447 				break;
448 			}
449 		}
450 	}
451 	else // no message at all -> redirect to MouseOver()
452 	{
453 		DiagramItem *last = _LastItemUnder();
454 		if ((transit == B_EXITED_VIEW) || (transit == B_OUTSIDE_VIEW))
455 		{
456 			if (last)
457 			{
458 				last->MouseOver(point, B_EXITED_VIEW);
459 				_ResetItemUnder();
460 				MouseOver(point, B_EXITED_VIEW);
461 			}
462 		}
463 		else
464 		{
465 			DiagramItem *item = ItemUnder(point);
466 			if (item)
467 			{
468 				if (item != last)
469 				{
470 					if (last)
471 						last->MouseOver(point, B_EXITED_VIEW);
472 					item->MouseOver(point, B_ENTERED_VIEW);
473 				}
474 				else
475 				{
476 					item->MouseOver(point, B_INSIDE_VIEW);
477 				}
478 			}
479 			else if (last)
480 			{
481 				last->MouseOver(point, B_EXITED_VIEW);
482 				MouseOver(point, B_ENTERED_VIEW);
483 			}
484 		}
485 	}
486 }
487 
488 void DiagramView::MouseUp(
489 	BPoint point)
490 {
491 	D_METHOD(("DiagramView::MouseUp()\n"));
492 	if (MultipleSelection())
493 		EndRectTracking();
494 	_endWireTracking();
495 
496 	// [e.moon 16nov99] mark no button as down
497 	m_pressedButton = 0;
498 }
499 
500 // -------------------------------------------------------- //
501 // *** derived from DiagramItemGroup (public)
502 // -------------------------------------------------------- //
503 
504 bool DiagramView::AddItem(
505 	DiagramItem *item)
506 {
507 	D_METHOD(("DiagramBox::AddItem()\n"));
508 	if (item)
509 	{
510 		if (DiagramItemGroup::AddItem(item))
511 		{
512 			item->_SetOwner(this);
513 			item->attachedToDiagram();
514 			if (item->type() == DiagramItem::M_BOX)
515 			{
516 				updateDataRect();
517 			}
518 			return true;
519 		}
520 	}
521 	return false;
522 }
523 
524 bool DiagramView::RemoveItem(
525 	DiagramItem *item)
526 {
527 	D_METHOD(("DiagramBox::RemoveItem()\n"));
528 	if (item)
529 	{
530 		item->detachedFromDiagram();
531 		if (DiagramItemGroup::RemoveItem(item))
532 		{
533 			item->_SetOwner(0);
534 			if (item->type() == DiagramItem::M_BOX)
535 			{
536 				updateDataRect();
537 			}
538 			return true;
539 		}
540 	}
541 	return false;
542 }
543 
544 // -------------------------------------------------------- //
545 // *** operations (public)
546 // -------------------------------------------------------- //
547 
548 void DiagramView::trackWire(
549 	BPoint point)
550 {
551 	D_MOUSE(("DiagramView::trackWire()\n"));
552 	if (m_draggedWire)
553 	{
554 		BRegion region;
555 		region.Include(m_draggedWire->Frame());
556 		m_draggedWire->m_dragEndPoint = point;
557 		m_draggedWire->endPointMoved();
558 		region.Include(m_draggedWire->Frame());
559 		region.Exclude(&m_boxRegion);
560 		for (int32 i = 0; i < region.CountRects(); i++)
561 		{
562 			Invalidate(region.RectAt(i));
563 		}
564 	}
565 }
566 
567 // -------------------------------------------------------- //
568 // *** internal operations (protected)
569 // -------------------------------------------------------- //
570 
571 void DiagramView::drawBackground(
572 	BRect updateRect)
573 {
574 	D_METHOD(("DiagramView::drawBackground()\n"));
575 	if (m_useBackgroundBitmap)
576 	{
577 		BRegion region;
578 		region.Include(updateRect);
579 		region.Exclude(&m_boxRegion);
580 		BRect bounds = Bounds();
581 		PushState();
582 		{
583 			ConstrainClippingRegion(&region);
584 			for (float y = 0; y < bounds.bottom; y += m_backgroundBitmap->Bounds().Height())
585 			{
586 				for (float x = 0; x < bounds.right; x += m_backgroundBitmap->Bounds().Width())
587 				{
588 					DrawBitmapAsync(m_backgroundBitmap, BPoint(x, y));
589 				}
590 			}
591 		}
592 		PopState();
593 	}
594 	else
595 	{
596 		BRegion region;
597 		region.Include(updateRect);
598 		region.Exclude(&m_boxRegion);
599 		PushState();
600 		{
601 			SetLowColor(m_backgroundColor);
602 			FillRegion(&region, B_SOLID_LOW);
603 		}
604 		PopState();
605 	}
606 }
607 
608 void DiagramView::setBackgroundColor(
609 	rgb_color color)
610 {
611 	D_METHOD(("DiagramView::setBackgroundColor()\n"));
612 	m_backgroundColor = color;
613 	m_useBackgroundBitmap = false;
614 }
615 
616 
617 void
618 DiagramView::setBackgroundBitmap(BBitmap* bitmap)
619 {
620 	D_METHOD(("DiagramView::setBackgroundBitmap()\n"));
621 	if (m_backgroundBitmap)
622 		delete m_backgroundBitmap;
623 
624 	m_backgroundBitmap = new BBitmap(bitmap);
625 	m_useBackgroundBitmap = true;
626 }
627 
628 
629 void
630 DiagramView::updateDataRect()
631 {
632 	D_METHOD(("DiagramView::updateDataRect()\n"));
633 	// calculate the area in which boxes display
634 	m_boxRegion.MakeEmpty();
635 	for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) {
636 		m_boxRegion.Include(ItemAt(i, DiagramItem::M_BOX)->Frame());
637 	}
638 	// adapt the data rect to the new region of boxes
639 	BRect boxRect = m_boxRegion.Frame();
640 	m_dataRect.right = boxRect.right;
641 	m_dataRect.bottom = boxRect.bottom;
642 	// update the scroll bars
643 	_updateScrollBars();
644 }
645 
646 
647 //	#pragma mark - internal operations (private)
648 
649 
650 void
651 DiagramView::_beginWireTracking(DiagramEndPoint *startPoint)
652 {
653 	D_METHOD(("DiagramView::beginWireTracking()\n"));
654 	m_draggedWire = createWire(startPoint);
655 	AddItem(m_draggedWire);
656 	SelectItem(m_draggedWire, true);
657 	Invalidate(startPoint->Frame());
658 }
659 
660 void DiagramView::_endWireTracking()
661 {
662 	D_METHOD(("DiagramView::endWireTracking()\n"));
663 	if (m_draggedWire)
664 	{
665 		RemoveItem(m_draggedWire);
666 		Invalidate(m_draggedWire->Frame());
667 		DiagramEndPoint *endPoint = m_draggedWire->startPoint();
668 		if (!endPoint)
669 		{
670 			endPoint = m_draggedWire->endPoint();
671 		}
672 		if (endPoint)
673 		{
674 			Invalidate(endPoint->Frame());
675 		}
676 		delete m_draggedWire;
677 		m_draggedWire = 0;
678 	}
679 }
680 
681 void DiagramView::_beginRectTracking(
682 	BPoint origin)
683 {
684 	D_METHOD(("DiagramView::beginRectTracking()\n"));
685 	BMessage message(M_RECT_TRACKING);
686 	message.AddPoint("origin", origin);
687 	DragMessage(&message, BRect(0.0, 0.0, -1.0, -1.0));
688 	BView::BeginRectTracking(BRect(origin, origin), B_TRACK_RECT_CORNER);
689 }
690 
691 
692 void
693 DiagramView::_trackRect(BPoint origin, BPoint current)
694 {
695 	D_METHOD(("DiagramView::trackRect()\n"));
696 	bool changed = false;
697 	BRect rect;
698 	rect.left = origin.x < current.x ? origin.x : current.x;
699 	rect.top = origin.y < current.y ? origin.y : current.y;
700 	rect.right = origin.x < current.x ? current.x : origin.x;
701 	rect.bottom = origin.y < current.y ? current.y : origin.y;
702 	for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++) {
703 		DiagramBox *box = dynamic_cast<DiagramBox *>(ItemAt(i, DiagramItem::M_BOX));
704 		if (box) {
705 			if (rect.Intersects(box->Frame()))
706 				changed  |= SelectItem(box, false);
707 			else
708 				changed |= DeselectItem(box);
709 		}
710 	}
711 
712 	if (changed) {
713 		SortItems(DiagramItem::M_BOX, &compareSelectionTime);
714 		SelectionChanged();
715 	}
716 }
717 
718 
719 void
720 DiagramView::_updateScrollBars()
721 {
722 	D_METHOD(("DiagramView::_updateScrollBars()\n"));
723 	// fetch the vertical ScrollBar
724 	BScrollBar *scrollBar = ScrollBar(B_VERTICAL);
725 	if (scrollBar)
726 	{
727 		 // Disable the ScrollBar if the view is large enough to display
728 		 // the entire data-rect
729 		if (Bounds().Height() > m_dataRect.Height())
730 		{
731 			scrollBar->SetRange(0.0, 0.0);
732 			scrollBar->SetProportion(1.0);
733 		}
734 		else
735 		{
736 			scrollBar->SetRange(m_dataRect.top, m_dataRect.bottom - Bounds().Height());
737 			scrollBar->SetProportion(Bounds().Height() / m_dataRect.Height());
738 		}
739 	}
740 	scrollBar = ScrollBar(B_HORIZONTAL);
741 	if (scrollBar)
742 	{
743 		 // Disable the ScrollBar if the view is large enough to display
744 		 // the entire data-rect
745 		if (Bounds().Width() > m_dataRect.Width())
746 		{
747 			scrollBar->SetRange(0.0, 0.0);
748 			scrollBar->SetProportion(1.0);
749 		}
750 		else
751 		{
752 			scrollBar->SetRange(m_dataRect.left, m_dataRect.right - Bounds().Width());
753 			scrollBar->SetProportion(Bounds().Width() / m_dataRect.Width());
754 		}
755 	}
756 }
757 
758 // END -- DiagramView.cpp --
759