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 // MediaRoutingView.cpp
33
34 #include "MediaRoutingView.h"
35
36 // RouteApp
37 #include "RouteApp.h"
38 #include "RouteAppNodeManager.h"
39 #include "RouteWindow.h"
40 #include "NodeSetIOContext.h"
41 // DormantNodeView
42 #include "DormantNodeView.h"
43 // InfoWindow
44 #include "InfoWindowManager.h"
45 // TransportWindow
46 #include "TransportWindow.h"
47 // MediaRoutingView
48 #include "MediaNodePanel.h"
49 #include "MediaWire.h"
50 // NodeManager
51 #include "NodeGroup.h"
52 #include "NodeRef.h"
53 #include "Connection.h"
54 // ParameterWindow
55 #include "ParameterWindowManager.h"
56
57 // Application Kit
58 #include <Application.h>
59 // Interface Kit
60 #include <Alert.h>
61 #include <Bitmap.h>
62 #include <MenuItem.h>
63 #include <PopUpMenu.h>
64 #include <Window.h>
65 // Locale Kit
66 #undef B_CATALOG
67 #define B_CATALOG (&sCatalog)
68 #include <Catalog.h>
69 // Media Kit
70 #include <MediaRoster.h>
71 // Storage Kit
72 #include <File.h>
73 #include <NodeInfo.h>
74 #include <Path.h>
75 // Translation Kit
76 #include <BitmapStream.h>
77 #include <TranslatorRoster.h>
78
79 #undef B_TRANSLATION_CONTEXT
80 #define B_TRANSLATION_CONTEXT "MediaRoutingView"
81
82 __USE_CORTEX_NAMESPACE
83
84 #include <Debug.h>
85 #define D_METHOD(x) //PRINT (x)
86 #define D_MESSAGE(x) //PRINT (x)
87 #define D_MOUSE(x) //PRINT (x)
88 #define D_KEY(x) //PRINT (x)
89
90 static BCatalog sCatalog("x-vnd.Cortex.MediaRoutingView");
91
92 // ---------------------------------------------------------------- //
93 // constants
94 // ---------------------------------------------------------------- //
95
96 float MediaRoutingView::M_CLEANUP_H_GAP = 25.0;
97 float MediaRoutingView::M_CLEANUP_V_GAP = 10.0;
98 float MediaRoutingView::M_CLEANUP_H_MARGIN = 15.0;
99 float MediaRoutingView::M_CLEANUP_V_MARGIN = 10.0;
100
101 // ---------------------------------------------------------------- //
102 // m_inactiveNodeState content
103 // ---------------------------------------------------------------- //
104
105 struct _inactive_node_state_entry {
_inactive_node_state_entry_inactive_node_state_entry106 _inactive_node_state_entry(
107 const char* _name, int32 _kind, const BMessage& _state) :
108 name(_name), kind(_kind), state(_state) {}
109
110 BString name;
111 uint32 kind;
112 BMessage state;
113 };
114
115 // ---------------------------------------------------------------- //
116 // ctor/dtor
117 // ---------------------------------------------------------------- //
118
MediaRoutingView(RouteAppNodeManager * nodeManager,BRect frame,const char * name,uint32 resizeMode)119 MediaRoutingView::MediaRoutingView(
120 RouteAppNodeManager *nodeManager,
121 BRect frame,
122 const char *name,
123 uint32 resizeMode)
124 : DiagramView(frame, "MediaRoutingView", true, B_FOLLOW_ALL_SIDES),
125 manager(nodeManager),
126 m_layout(M_ICON_VIEW),
127 m_nextGroupNumber(1),
128 m_lastDroppedNode(0),
129 m_draggedWire(0)
130 {
131 D_METHOD(("MediaRoutingView::MediaRoutingView()\n"));
132 ASSERT(manager);
133
134 setBackgroundColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_DARKEN_2_TINT));
135 SetItemAlignment(5.0, 5.0);
136 _initLayout();
137 }
138
~MediaRoutingView()139 MediaRoutingView::~MediaRoutingView() {
140 D_METHOD(("MediaRoutingView::~MediaRoutingView()\n"));
141
142 _emptyInactiveNodeState();
143
144 // quit ParameterWindowManager if necessary
145 ParameterWindowManager::shutDown();
146
147 // quit InfoWindowManager if necessary
148 InfoWindowManager::shutDown();
149 }
150
151 // -------------------------------------------------------- //
152 // *** derived from DiagramView
153 // -------------------------------------------------------- //
154
connectionAborted(DiagramEndPoint * fromWhich)155 void MediaRoutingView::connectionAborted(
156 DiagramEndPoint *fromWhich)
157 {
158 D_METHOD(("MediaRoutingView::connectionAborted()\n"));
159
160 be_app->SetCursor(B_HAND_CURSOR);
161 }
162
connectionEstablished(DiagramEndPoint * fromWhich,DiagramEndPoint * toWhich)163 void MediaRoutingView::connectionEstablished(
164 DiagramEndPoint *fromWhich,
165 DiagramEndPoint *toWhich)
166 {
167 D_METHOD(("MediaRoutingView::connectionEstablished()\n"));
168
169 be_app->SetCursor(B_HAND_CURSOR);
170 }
171
createWire(DiagramEndPoint * fromWhich,DiagramEndPoint * toWhich)172 DiagramWire *MediaRoutingView::createWire(
173 DiagramEndPoint *fromWhich,
174 DiagramEndPoint *toWhich)
175 {
176 D_METHOD(("MediaRoutingView::createWire()\n"));
177
178 MediaJack *outputJack, *inputJack;
179 MediaJack *jack = dynamic_cast<MediaJack *>(fromWhich);
180
181 if (jack == NULL)
182 return 0;
183
184 if (jack->isOutput())
185 {
186 outputJack = jack;
187 inputJack = dynamic_cast<MediaJack *>(toWhich);
188 if (!inputJack || !inputJack->isInput())
189 {
190 return 0;
191 }
192 }
193 else
194 {
195 inputJack = jack;
196 outputJack = dynamic_cast<MediaJack *>(toWhich);
197 if (!outputJack || !outputJack->isOutput())
198 {
199 return 0;
200 }
201 }
202 if (!outputJack->isConnected() && !inputJack->isConnected())
203 {
204 media_output output;
205 media_input input;
206 if ((outputJack->getOutput(&output) == B_OK)
207 && (inputJack->getInput(&input) == B_OK))
208 {
209 status_t error;
210 Connection connection;
211 error = manager->connect(output, input, &connection);
212 if (error)
213 {
214 showErrorMessage(B_TRANSLATE("Could not connect"), error);
215 }
216 }
217 }
218 return 0;
219 }
220
createWire(DiagramEndPoint * fromWhich)221 DiagramWire *MediaRoutingView::createWire(
222 DiagramEndPoint *fromWhich)
223 {
224 D_METHOD(("MediaRoutingView::createWire(temp)\n"));
225
226 MediaJack *jack = dynamic_cast<MediaJack *>(fromWhich);
227 if (jack)
228 {
229 if (jack->isOutput()) // this is the start point
230 {
231 return new MediaWire(jack, true);
232 }
233 else
234 {
235 return new MediaWire(jack, false);
236 }
237 }
238 return 0;
239 }
240
241
242 void
BackgroundMouseDown(BPoint point,uint32 buttons,uint32 clicks)243 MediaRoutingView::BackgroundMouseDown(BPoint point, uint32 buttons,
244 uint32 clicks)
245 {
246 D_MOUSE(("MediaRoutingView::BackgroundMouseDown()\n"));
247
248 if ((buttons == B_SECONDARY_MOUSE_BUTTON)
249 || (modifiers() & B_CONTROL_KEY)) {
250 EndRectTracking();
251 showContextMenu(point);
252 }
253 }
254
255
256 void
MessageDropped(BPoint point,BMessage * message)257 MediaRoutingView::MessageDropped(BPoint point, BMessage *message)
258 {
259 D_METHOD(("MediaRoutingView::MessageDropped()\n"));
260
261 switch (message->what) {
262 case DormantNodeView::M_INSTANTIATE_NODE:
263 {
264 D_MESSAGE(("MediaRoutingView::MessageDropped(DormantNodeView::M_INSTANTIATE_NODE)\n"));
265 type_code type;
266 int32 count;
267 if (message->GetInfo("which", &type, &count) == B_OK) {
268 for (int32 n = 0; n < count; n++) {
269 dormant_node_info info;
270 const void *data;
271 ssize_t dataSize;
272 if (message->FindData("which", B_RAW_TYPE, &data, &dataSize) == B_OK) {
273 memcpy(reinterpret_cast<void *>(&info), data, dataSize);
274 NodeRef* droppedNode;
275 status_t error;
276 error = manager->instantiate(info, &droppedNode);
277 if (!error) {
278 m_lastDroppedNode = droppedNode->id();
279 BPoint dropPoint, dropOffset;
280 dropPoint = message->DropPoint(&dropOffset);
281 m_lastDropPoint = Align(ConvertFromScreen(dropPoint - dropOffset));
282 } else {
283 BString s = B_TRANSLATE(
284 "Could not instantiate '%infoname%'");
285 s.ReplaceFirst("%infoname%", info.name);
286 showErrorMessage(s, error);
287 }
288 }
289 }
290 }
291 break;
292 }
293
294 case B_SIMPLE_DATA:
295 {
296 D_MESSAGE(("MediaRoutingView::MessageDropped(B_SIMPLE_DATA)\n"));
297 entry_ref fileRef;
298 if (message->FindRef("refs", &fileRef) == B_OK)
299 _checkDroppedFile(&fileRef, ConvertFromScreen(message->DropPoint()));
300 break;
301 }
302
303 case B_PASTE:
304 {
305 D_MESSAGE(("MediaRoutingView::MessageDropped(B_PASTE)\n"));
306 ssize_t size;
307 const rgb_color *color; // [e.moon 21nov99] fixed const error
308 if (message->FindData("RGBColor", B_RGB_COLOR_TYPE,
309 reinterpret_cast<const void **>(&color), &size) == B_OK)
310 _changeBackground(*color);
311 break;
312 }
313
314 default:
315 DiagramView::MessageDropped(point, message);
316 }
317 }
318
319
320 void
SelectionChanged()321 MediaRoutingView::SelectionChanged()
322 {
323 D_METHOD(("MediaRoutingView::selectionChanged()\n"));
324 _broadcastSelection();
325 }
326
327 // ---------------------------------------------------------------- //
328 // *** BView impl.
329 // ---------------------------------------------------------------- //
330
AttachedToWindow()331 void MediaRoutingView::AttachedToWindow()
332 {
333 D_METHOD(("MediaRoutingView::AttachedToWindow()\n"));
334 _inherited::AttachedToWindow();
335
336 // attach to manager
337 ASSERT(manager);
338 add_observer(this, manager);
339
340 // add the context-menu shortcuts to the window
341 _addShortcuts();
342
343 // populate with existing nodes & connections
344 _initContent();
345
346 // [e.moon 29nov99] moved from AllAttached()
347 cleanUp();
348 }
349
AllAttached()350 void MediaRoutingView::AllAttached()
351 {
352 D_METHOD(("MediaRoutingView::AllAttached()\n"));
353 _inherited::AllAttached();
354
355 _adjustScrollBars();
356
357 // grab keyboard events
358 MakeFocus();
359 }
360
DetachedFromWindow()361 void MediaRoutingView::DetachedFromWindow()
362 {
363 D_METHOD(("MediaRoutingView::DetachedFromWindow()\n"));
364 _inherited::DetachedFromWindow();
365
366 // detach from manager
367 if (manager)
368 {
369 Autolock lock(manager);
370 void *cookie = 0;
371 NodeRef *ref;
372 while (manager->getNextRef(&ref, &cookie) == B_OK)
373 {
374 remove_observer(this, ref);
375 }
376 remove_observer(this, manager);
377 const_cast<RouteAppNodeManager *&>(manager) = 0;
378 }
379 }
380
KeyDown(const char * bytes,int32 numBytes)381 void MediaRoutingView::KeyDown(
382 const char *bytes,
383 int32 numBytes)
384 {
385 D_METHOD(("MediaRoutingView::KeyDown()\n"));
386
387 switch (bytes[0])
388 {
389 case B_ENTER:
390 {
391 D_KEY(("MediaRoutingView::KeyDown(B_ENTER)\n"));
392 _openParameterWindowsForSelection();
393 break;
394 }
395 case B_DELETE:
396 {
397 D_KEY(("MediaRoutingView::KeyDown(B_DELETE)\n"));
398 _deleteSelection();
399 break;
400 }
401 case B_SPACE:
402 {
403 // [e.moon 1dec99]
404 BWindow* w = Window();
405 ASSERT(w);
406 BMessenger(w).SendMessage(RouteWindow::M_TOGGLE_GROUP_ROLLING);
407 break;
408 }
409 default:
410 {
411 DiagramView::KeyDown(bytes, numBytes);
412 break;
413 }
414 }
415 }
416
Pulse()417 void MediaRoutingView::Pulse()
418 {
419 // do the animation
420 }
421
422 // ---------------------------------------------------------------- //
423 // BHandler impl
424 // ---------------------------------------------------------------- //
425
MessageReceived(BMessage * message)426 void MediaRoutingView::MessageReceived(
427 BMessage* message)
428 {
429 D_METHOD(("MediaRoutingView::MessageReceived()\n"));
430
431 switch (message->what)
432 {
433 case B_MEDIA_NODE_CREATED:
434 {
435 D_MESSAGE(("MediaRoutingView::MessageReceived(B_MEDIA_NODE_CREATED)\n"));
436 type_code type;
437 int32 count;
438 if (message->GetInfo("media_node_id", &type, &count) == B_OK)
439 {
440 for(int32 n = 0; n < count; n++)
441 {
442 int32 id;
443 if (message->FindInt32("media_node_id", n, &id) == B_OK)
444 {
445 // [e.moon 8dec99] allow for existing panel
446 MediaNodePanel* panel;
447 if(_findPanelFor(id, &panel) < B_OK)
448 _addPanelFor(id, BPoint(5.0, 5.0));
449 }
450 }
451 }
452 break;
453 }
454 case B_MEDIA_NODE_DELETED:
455 {
456 D_MESSAGE(("MediaRoutingView::MessageReceived(B_MEDIA_NODE_DELETED)\n"));
457 type_code type;
458 int32 count;
459 if (message->GetInfo("media_node_id", &type, &count) == B_OK)
460 {
461 for (int32 n = 0; n < count; n++)
462 {
463 int32 id;
464 if (message->FindInt32("media_node_id", n, &id) == B_OK)
465 {
466 _removePanelFor(id);
467 }
468 }
469 }
470 break;
471 }
472 case B_MEDIA_CONNECTION_MADE:
473 {
474 D_MESSAGE(("MediaRoutingView::MessageReceived(B_MEDIA_CONNECTION_MADE)\n"));
475 type_code type;
476 int32 count;
477 if (message->GetInfo("output", &type, &count) == B_OK)
478 {
479 for (int32 n = 0; n < count; n++)
480 {
481 media_output output;
482 const void *data;
483 ssize_t dataSize;
484 if (message->FindData("output", B_RAW_TYPE, n, &data, &dataSize) == B_OK)
485 {
486 output = *reinterpret_cast<const media_output *>(data);
487 Connection connection;
488 if (manager->findConnection(output.node.node, output.source, &connection) == B_OK)
489 {
490 _addWireFor(connection);
491 }
492 }
493 }
494 }
495 break;
496 }
497 case B_MEDIA_CONNECTION_BROKEN:
498 {
499 D_MESSAGE(("MediaRoutingView::MessageReceived(B_MEDIA_CONNECTION_BROKEN)\n"));
500 type_code type;
501 int32 count;
502 if (message->GetInfo("__connection_id", &type, &count) == B_OK)
503 {
504 for (int32 n = 0; n < count; n++)
505 {
506 int32 id;
507 if (message->FindInt32("__connection_id", n, &id) == B_OK)
508 {
509 _removeWireFor(id);
510 }
511 }
512 }
513 break;
514 }
515 case B_MEDIA_FORMAT_CHANGED:
516 {
517 D_MESSAGE(("MediaRoutingView::MessageReceived(B_MEDIA_FORMAT_CHANGED)\n"));
518
519 media_node_id nodeID;
520 if(message->FindInt32("__source_node_id", &nodeID) < B_OK)
521 break;
522
523 uint32 connectionID;
524 if(message->FindInt32("__connection_id", (int32*)&connectionID) < B_OK)
525 break;
526
527 media_source* source;
528 ssize_t dataSize;
529 if(message->FindData("be:source", B_RAW_TYPE, (const void**)&source, &dataSize) < B_OK)
530 break;
531
532 MediaWire* wire;
533 if(_findWireFor(connectionID, &wire) == B_OK) {
534 // copy new connection data
535 manager->findConnection(nodeID, *source, &wire->connection);
536 }
537 break;
538 }
539 case M_CLEANUP_REQUESTED:
540 {
541 D_MESSAGE(("MediaRoutingView::MessageReceived(M_M_CLEANUP_REQUESTED)\n"));
542 cleanUp();
543 break;
544 }
545 case M_SELECT_ALL:
546 {
547 D_MESSAGE(("MediaRoutingView::MessageReceived(M_SELECT_ALL)\n"));
548 SelectAll(DiagramItem::M_BOX);
549 break;
550 }
551 case M_DELETE_SELECTION:
552 {
553 D_MESSAGE(("MediaRoutingView::MessageReceived(M_DELETE_SELECTION)\n"));
554 _deleteSelection();
555 break;
556 }
557 case M_NODE_CHANGE_CYCLING:
558 {
559 D_MESSAGE(("MediaRoutingView::MessageReceived(M_NODE_CYCLING_CHANGED)\n"));
560 bool cycle;
561 if (message->FindBool("cycle", &cycle) == B_OK)
562 {
563 _changeCyclingForSelection(cycle);
564 }
565 break;
566 }
567 case M_NODE_CHANGE_RUN_MODE:
568 {
569 D_MESSAGE(("MediaRoutingView::MessageReceived(M_NODE_RUNMODE_CHANGED)\n"));
570 int32 mode;
571 if (message->FindInt32("run_mode", &mode) == B_OK)
572 {
573 _changeRunModeForSelection(static_cast<uint32>(mode));
574 }
575 break;
576 }
577 case M_LAYOUT_CHANGED:
578 {
579 D_MESSAGE(("MediaRoutingView::MessageReceived(M_LAYOUT_CHANGED)\n"));
580 layout_t layout;
581 if (message->FindInt32("layout", (int32*)&layout) == B_OK)
582 {
583 if (layout != m_layout)
584 {
585 layoutChanged(layout);
586 updateDataRect();
587 Invalidate();
588 }
589 }
590 break;
591 }
592 case M_NODE_START_TIME_SOURCE:
593 {
594 D_MESSAGE(("MediaRoutingView::MessageReceived(M_NODE_START_TIME_SOURCE)\n"));
595 int32 id;
596 if(message->FindInt32("nodeID", &id) < B_OK)
597 break;
598 NodeRef* ref;
599 if(manager->getNodeRef(id, &ref) < B_OK)
600 break;
601
602 bigtime_t when = system_time();
603 status_t err = manager->roster->StartTimeSource(ref->node(), when);
604 if(err < B_OK) {
605 PRINT((
606 "! StartTimeSource(%" B_PRId32 "): '%s'\n",
607 ref->id(), strerror(err)));
608 }
609 break;
610 }
611 case M_NODE_STOP_TIME_SOURCE:
612 {
613 D_MESSAGE(("MediaRoutingView::MessageReceived(M_NODE_STOP_TIME_SOURCE)\n"));
614 int32 id;
615 if(message->FindInt32("nodeID", &id) < B_OK)
616 break;
617 NodeRef* ref;
618 if(manager->getNodeRef(id, &ref) < B_OK)
619 break;
620
621 bigtime_t when = system_time();
622 status_t err = manager->roster->StopTimeSource(ref->node(), when);
623 if(err < B_OK) {
624 PRINT((
625 "! StopTimeSource(%" B_PRId32 "): '%s'\n",
626 ref->id(), strerror(err)));
627 }
628 break;
629 }
630 case M_NODE_TWEAK_PARAMETERS: {
631 D_MESSAGE((" -> M_NODE_TWEAK_PARAMETERS\n"));
632 _openParameterWindowsForSelection();
633 break;
634 }
635 case M_NODE_START_CONTROL_PANEL: {
636 D_MESSAGE((" -> M_NODE_START_CONTROL_PANEL\n"));
637 _startControlPanelsForSelection();
638 break;
639 }
640 case M_GROUP_SET_LOCKED:
641 {
642 D_MESSAGE(("MediaRoutingView::MessageReceived(M_GROUP_SET_LOCKED)\n"));
643 int32 groupID;
644 if(message->FindInt32("groupID", &groupID) < B_OK)
645 break;
646 bool locked;
647 if(message->FindBool("locked", &locked) < B_OK)
648 break;
649 NodeGroup* group;
650 if(manager->findGroup(groupID, &group) < B_OK)
651 break;
652 uint32 f = locked ?
653 group->groupFlags() | NodeGroup::GROUP_LOCKED :
654 group->groupFlags() & ~NodeGroup::GROUP_LOCKED;
655 group->setGroupFlags(f);
656 break;
657 }
658 case M_BROADCAST_SELECTION: {
659 D_MESSAGE((" -> M_BROADCAST_SELECTION\n"));
660 _broadcastSelection();
661 break;
662 }
663 case InfoWindowManager::M_INFO_WINDOW_REQUESTED:
664 {
665 D_MESSAGE(("MediaRoutingView::MessageReceived(InfoView::M_INFO_WINDOW_REQUESTED)\n"));
666 type_code type;
667 int32 count;
668 if (message->GetInfo("input", &type, &count) == B_OK)
669 {
670 for (int32 i = 0; i < count; i++)
671 {
672 media_input input;
673 const void *data;
674 ssize_t dataSize;
675 if (message->FindData("input", B_RAW_TYPE, i, &data, &dataSize) == B_OK)
676 {
677 input = *reinterpret_cast<const media_input *>(data);
678 InfoWindowManager *manager = InfoWindowManager::Instance();
679 if (manager && manager->Lock()) {
680 manager->openWindowFor(input);
681 manager->Unlock();
682 }
683 }
684 }
685 }
686 else if (message->GetInfo("output", &type, &count) == B_OK)
687 {
688 for (int32 i = 0; i < count; i++)
689 {
690 media_output output;
691 const void *data;
692 ssize_t dataSize;
693 if (message->FindData("output", B_RAW_TYPE, i, &data, &dataSize) == B_OK)
694 {
695 output = *reinterpret_cast<const media_output *>(data);
696 InfoWindowManager *manager = InfoWindowManager::Instance();
697 if (manager && manager->Lock()) {
698 manager->openWindowFor(output);
699 manager->Unlock();
700 }
701 }
702 }
703 }
704 else
705 {
706 _openInfoWindowsForSelection();
707 }
708 break;
709 }
710 case NodeManager::M_RELEASED:
711 {
712 D_MESSAGE(("MediaRoutingView::MessageReceived(NodeManager::M_RELEASED)\n"));
713 remove_observer(this, manager);
714 const_cast<RouteAppNodeManager*&>(manager) = 0;
715 // +++++ disable view!
716 break;
717 }
718 case NodeRef::M_RELEASED:
719 {
720 D_MESSAGE(("MediaRoutingView::MessageReceived(NodeRef::M_RELEASED)\n"));
721 // only relevant on shutdown; do nothing
722 break;
723 }
724 default:
725 {
726 DiagramView::MessageReceived(message);
727 }
728 }
729 }
730
731 // ---------------------------------------------------------------- //
732 // *** operations (public)
733 // ---------------------------------------------------------------- //
734
findFreePositionFor(const MediaNodePanel * panel) const735 BPoint MediaRoutingView::findFreePositionFor(
736 const MediaNodePanel* panel) const
737 {
738 D_METHOD(("MediaRoutingView::_findFreeSpotFor()\n"));
739
740 BPoint p(M_CLEANUP_H_MARGIN, M_CLEANUP_V_MARGIN);
741 if (panel)
742 {
743 switch (m_layout)
744 {
745 case M_ICON_VIEW:
746 {
747 // find the target column by node_kind
748 p.x += M_CLEANUP_H_GAP + MediaNodePanel::M_DEFAULT_WIDTH;
749 if (panel->ref->kind() & B_BUFFER_PRODUCER)
750 {
751 p.x -= M_CLEANUP_H_GAP + MediaNodePanel::M_DEFAULT_WIDTH;
752 }
753 if (panel->ref->kind() & B_BUFFER_CONSUMER)
754 {
755 p.x += M_CLEANUP_H_GAP + MediaNodePanel::M_DEFAULT_WIDTH;
756 }
757 // find the bottom item in the column
758 float bottom = 0.0;
759 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++)
760 {
761 BRect r = ItemAt(i, DiagramItem::M_BOX)->Frame();
762 if ((r.left >= p.x)
763 && (r.left <= p.x + MediaNodePanel::M_DEFAULT_WIDTH))
764 {
765 bottom = (r.bottom > bottom) ? r.bottom : bottom;
766 }
767 }
768 if (bottom >= p.y)
769 {
770 p.y = bottom + M_CLEANUP_V_GAP;
771 }
772 break;
773 }
774 case M_MINI_ICON_VIEW:
775 {
776 // find the target row by node_kind
777 p.y += M_CLEANUP_V_GAP + MediaNodePanel::M_DEFAULT_HEIGHT;
778 if (panel->ref->kind() & B_BUFFER_PRODUCER)
779 {
780 p.y -= M_CLEANUP_V_GAP + MediaNodePanel::M_DEFAULT_HEIGHT;
781 }
782 if (panel->ref->kind() & B_BUFFER_CONSUMER)
783 {
784 p.y += M_CLEANUP_V_GAP + MediaNodePanel::M_DEFAULT_HEIGHT;
785 }
786 // find the right-most item in the row
787 float right = 0.0;
788 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++)
789 {
790 BRect r = ItemAt(i, DiagramItem::M_BOX)->Frame();
791 if ((r.top >= p.y)
792 && (r.top <= p.y + MediaNodePanel::M_DEFAULT_HEIGHT))
793 {
794 right = (r.right > right) ? r.right : right;
795 }
796 }
797 if (right >= p.x)
798 {
799 p.x = right + M_CLEANUP_H_GAP;
800 }
801 break;
802 }
803 }
804 }
805 return p;
806 }
807
808 // ---------------------------------------------------------------- //
809 // *** operations (protected)
810 // ---------------------------------------------------------------- //
811
layoutChanged(layout_t layout)812 void MediaRoutingView::layoutChanged(
813 layout_t layout)
814 {
815 D_METHOD(("MediaRoutingView::layoutChanged()\n"));
816
817 switch (layout)
818 {
819 case M_ICON_VIEW:
820 {
821 float temp;
822
823 // swap the cleanup defaults
824 temp = M_CLEANUP_H_GAP;
825 M_CLEANUP_H_GAP = M_CLEANUP_V_GAP;
826 M_CLEANUP_V_GAP = temp;
827 temp = M_CLEANUP_H_MARGIN;
828 M_CLEANUP_H_MARGIN = M_CLEANUP_V_MARGIN;
829 M_CLEANUP_V_MARGIN = temp;
830
831 // swap the default dimensions for MediaJacks
832 temp = MediaJack::M_DEFAULT_WIDTH;
833 MediaJack::M_DEFAULT_WIDTH = MediaJack::M_DEFAULT_HEIGHT;
834 MediaJack::M_DEFAULT_HEIGHT = temp;
835
836 // Add space for the 3-letter i/o-abbreviation
837 BFont font(be_plain_font);
838 font.SetSize(font.Size() - 2.0);
839 for (int i = 0; i < MediaJack::M_MAX_ABBR_LENGTH; i++)
840 {
841 MediaJack::M_DEFAULT_WIDTH += font.StringWidth("M");
842 }
843 MediaJack::M_DEFAULT_WIDTH += 2.0; // add some padding
844
845 // Adjust the default size for MediaNodePanels
846 float labelWidth, bodyWidth;
847 float labelHeight, bodyHeight;
848 font_height fh;
849 be_plain_font->GetHeight(&fh);
850 labelWidth = 4 * MediaNodePanel::M_LABEL_H_MARGIN
851 + be_plain_font->StringWidth(" Be Audio Mixer ");
852 bodyWidth = 2 * MediaNodePanel::M_BODY_H_MARGIN + B_LARGE_ICON
853 + 2 * MediaJack::M_DEFAULT_WIDTH;
854 labelHeight = 2 * MediaNodePanel::M_LABEL_V_MARGIN
855 + fh.ascent + fh.descent + fh.leading + 1.0;
856 bodyHeight = 2 * MediaNodePanel::M_BODY_V_MARGIN + B_LARGE_ICON;
857 MediaNodePanel::M_DEFAULT_WIDTH = labelWidth > bodyWidth ? labelWidth : bodyWidth;
858 MediaNodePanel::M_DEFAULT_HEIGHT = labelHeight + bodyHeight;
859 Align(&MediaNodePanel::M_DEFAULT_WIDTH, &MediaNodePanel::M_DEFAULT_HEIGHT);
860 break;
861 }
862 case M_MINI_ICON_VIEW:
863 {
864 float temp;
865
866 // Swap the cleanup defaults
867 temp = M_CLEANUP_H_GAP;
868 M_CLEANUP_H_GAP = M_CLEANUP_V_GAP;
869 M_CLEANUP_V_GAP = temp;
870 temp = M_CLEANUP_H_MARGIN;
871 M_CLEANUP_H_MARGIN = M_CLEANUP_V_MARGIN;
872 M_CLEANUP_V_MARGIN = temp;
873
874 // Subtract space for the 3-letter i/o-abbreviation
875 BFont font(be_plain_font);
876 font.SetSize(font.Size() - 2.0);
877 for (int i = 0; i < MediaJack::M_MAX_ABBR_LENGTH; i++)
878 {
879 MediaJack::M_DEFAULT_WIDTH -= font.StringWidth("M");
880 }
881 MediaJack::M_DEFAULT_WIDTH -= 2.0; // substract the padding
882
883 // Swap the default dimensions for MediaJacks
884 temp = MediaJack::M_DEFAULT_WIDTH;
885 MediaJack::M_DEFAULT_WIDTH = MediaJack::M_DEFAULT_HEIGHT;
886 MediaJack::M_DEFAULT_HEIGHT = temp;
887
888 // Adjust the default size for MediaNodePanels
889 float labelWidth, bodyWidth;
890 float labelHeight, bodyHeight;
891 font_height fh;
892 be_plain_font->GetHeight(&fh);
893 labelWidth = 4 * MediaNodePanel::M_LABEL_H_MARGIN
894 + be_plain_font->StringWidth(" Be Audio Mixer ");
895 bodyWidth = 2 * MediaNodePanel::M_BODY_H_MARGIN + B_MINI_ICON;
896 labelHeight = 3 * MediaNodePanel::M_LABEL_V_MARGIN
897 + fh.ascent + fh.descent + fh.leading
898 + 2 * MediaJack::M_DEFAULT_HEIGHT;
899 bodyHeight = 2 * MediaNodePanel::M_BODY_V_MARGIN + B_MINI_ICON;
900 MediaNodePanel::M_DEFAULT_WIDTH = labelWidth + bodyWidth;
901 MediaNodePanel::M_DEFAULT_HEIGHT = labelHeight > bodyHeight ? labelHeight : bodyHeight;
902 Align(&MediaNodePanel::M_DEFAULT_WIDTH, &MediaNodePanel::M_DEFAULT_HEIGHT);
903 break;
904 }
905 }
906 m_layout = layout;
907 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++)
908 {
909 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(ItemAt(i, DiagramItem::M_BOX));
910 if (panel)
911 {
912 panel->layoutChanged(layout);
913 }
914 }
915
916 _adjustScrollBars();
917 }
918
cleanUp()919 void MediaRoutingView::cleanUp()
920 {
921 D_METHOD(("MediaRoutingView::cleanUp()\n"));
922
923 SortItems(DiagramItem::M_BOX, compareID);
924
925 // move all the panels offscreen
926 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++)
927 {
928 ItemAt(i, DiagramItem::M_BOX)->moveTo(BPoint(-200.0, -200.0));
929 }
930
931 // move all panels to their 'ideal' position
932 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++)
933 {
934 MediaNodePanel *panel;
935 panel = dynamic_cast<MediaNodePanel *>(ItemAt(i, DiagramItem::M_BOX));
936 BPoint p = findFreePositionFor(panel);
937 panel->moveTo(p);
938 }
939
940 SortItems(DiagramItem::M_BOX, compareSelectionTime);
941 Invalidate();
942 updateDataRect();
943 }
944
showContextMenu(BPoint point)945 void MediaRoutingView::showContextMenu(
946 BPoint point)
947 {
948 D_METHOD(("MediaRoutingView::showContextMenu()\n"));
949
950 BPopUpMenu *menu = new BPopUpMenu("MediaRoutingView PopUp", false, false, B_ITEMS_IN_COLUMN);
951 menu->SetFont(be_plain_font);
952
953 // add layout options
954 BMenuItem *item;
955 BMessage *message = new BMessage(M_LAYOUT_CHANGED);
956 message->AddInt32("layout", M_ICON_VIEW);
957 menu->AddItem(item = new BMenuItem(B_TRANSLATE("Icon view"), message));
958 if (m_layout == M_ICON_VIEW)
959 {
960 item->SetMarked(true);
961 }
962 message = new BMessage(M_LAYOUT_CHANGED);
963 message->AddInt32("layout", M_MINI_ICON_VIEW);
964 menu->AddItem(item = new BMenuItem(B_TRANSLATE("Mini icon view"), message));
965 if (m_layout == M_MINI_ICON_VIEW)
966 {
967 item->SetMarked(true);
968 }
969 menu->AddSeparatorItem();
970
971 // add 'CleanUp' command
972 menu->AddItem(new BMenuItem(B_TRANSLATE("Clean up"),
973 new BMessage(M_CLEANUP_REQUESTED), 'K'));
974
975 // add 'Select All' command
976 menu->AddItem(new BMenuItem(B_TRANSLATE("Select all"),
977 new BMessage(M_SELECT_ALL), 'A'));
978
979 menu->SetTargetForItems(this);
980 ConvertToScreen(&point);
981 point -= BPoint(1.0, 1.0);
982 menu->Go(point, true, true, true);
983 }
984
showErrorMessage(BString text,status_t error)985 void MediaRoutingView::showErrorMessage(
986 BString text,
987 status_t error)
988 {
989 D_METHOD(("MediaRoutingView::showErrorMessage()\n"));
990
991 if (error) {
992 text << " (" << strerror(error) << ")";
993 }
994
995 BMessage message(M_SHOW_ERROR_MESSAGE);
996 message.AddString("text", text.String());
997 if (error) {
998 message.AddBool("error", true);
999 }
1000 BMessenger messenger(0, Window());
1001 if (!messenger.IsValid()
1002 || (messenger.SendMessage(&message) != B_OK)) {
1003 BAlert *alert = new BAlert(B_TRANSLATE("Error"), text.String(),
1004 B_TRANSLATE("OK"), 0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
1005 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
1006 alert->Go();
1007 }
1008 }
1009
1010 // -------------------------------------------------------- //
1011 // *** IStateArchivable
1012 // -------------------------------------------------------- //
1013
importState(const BMessage * archive)1014 status_t MediaRoutingView::importState(
1015 const BMessage* archive) {
1016
1017 status_t err;
1018
1019 _emptyInactiveNodeState();
1020
1021 layout_t layout;
1022 err = archive->FindInt32("layout", (int32*)&layout);
1023 if(err == B_OK && layout != m_layout) {
1024 layoutChanged(layout);
1025 }
1026
1027 const char* path;
1028 err = archive->FindString("bgBitmap", &path);
1029 if(err == B_OK) {
1030 BEntry entry(path);
1031 entry_ref ref;
1032 err = entry.GetRef(&ref);
1033 if(err == B_OK)
1034 _changeBackground(&ref);
1035 }
1036 else {
1037 rgb_color color;
1038 color.alpha = 255;
1039 if(
1040 archive->FindInt8("bgRed", (int8*)&color.red) == B_OK &&
1041 archive->FindInt8("bgGreen", (int8*)&color.green) == B_OK &&
1042 archive->FindInt8("bgBlue", (int8*)&color.blue) == B_OK)
1043 _changeBackground(color);
1044 }
1045
1046 for(int32 n = 0; ; ++n) {
1047
1048 // find panel state info; stop when exhausted
1049 BMessage m;
1050 err = archive->FindMessage("panel", n, &m);
1051 if(err < B_OK)
1052 break;
1053
1054 const char* nodeName;
1055 err = archive->FindString("nodeName", n, &nodeName);
1056 if(err < B_OK)
1057 break;
1058
1059 uint32 nodeKind;
1060 err = archive->FindInt32("nodeKind", n, (int32*)&nodeKind);
1061 if(err < B_OK)
1062 break;
1063
1064 // look up matching panel +++++ SLOW +++++
1065 uint32 panelIndex;
1066 uint32 items = CountItems(DiagramItem::M_BOX);
1067 for(
1068 panelIndex = 0;
1069 panelIndex < items;
1070 ++panelIndex) {
1071
1072 MediaNodePanel* panel = dynamic_cast<MediaNodePanel*>(
1073 ItemAt(panelIndex, DiagramItem::M_BOX));
1074
1075 if(panel &&
1076 !strcmp(panel->ref->name(), nodeName) &&
1077 panel->ref->kind() == nodeKind) {
1078
1079 // found match; hand message to panel
1080 panel->importState(&m);
1081 break;
1082 }
1083 }
1084 if(panelIndex == items) {
1085 // no panel found
1086 // if a "system node" hang onto (and re-export) state info
1087 bool sysOwned;
1088 if(m.FindBool("sysOwned", &sysOwned) == B_OK && sysOwned) {
1089 m_inactiveNodeState.AddItem(
1090 new _inactive_node_state_entry(
1091 nodeName, nodeKind, m));
1092 }
1093 }
1094 }
1095
1096 updateDataRect();
1097
1098 return B_OK;
1099 }
1100
1101 // +++++ export state info for currently inactive system nodes +++++
exportState(BMessage * archive) const1102 status_t MediaRoutingView::exportState(
1103 BMessage* archive) const {
1104
1105 // store layout mode
1106 archive->AddInt32("layout", m_layout);
1107
1108 // store background settings
1109 if(m_backgroundBitmapEntry.InitCheck() == B_OK) {
1110 BPath path;
1111 m_backgroundBitmapEntry.GetPath(&path);
1112 archive->AddString("bgBitmap", path.Path());
1113 } else {
1114 rgb_color c = backgroundColor();
1115 archive->AddInt8("bgRed", c.red);
1116 archive->AddInt8("bgGreen", c.green);
1117 archive->AddInt8("bgBlue", c.blue);
1118 }
1119
1120 // store panel positions w/ node names & signatures
1121 for(uint32 n = 0; n < CountItems(DiagramItem::M_BOX); ++n) {
1122 MediaNodePanel* panel = dynamic_cast<MediaNodePanel*>(
1123 ItemAt(n, DiagramItem::M_BOX));
1124 if(!panel)
1125 continue;
1126
1127 if(panel->ref->isInternal())
1128 // skip internal nodes
1129 continue;
1130
1131 BMessage m;
1132 panel->exportState(&m);
1133 archive->AddString("nodeName", panel->ref->name());
1134 archive->AddInt32("nodeKind", panel->ref->kind());
1135 archive->AddMessage("panel", &m);
1136 }
1137
1138 // copy inactive node state info
1139 for(int32 n = 0; n < m_inactiveNodeState.CountItems(); ++n) {
1140 _inactive_node_state_entry* e = reinterpret_cast<_inactive_node_state_entry*>(
1141 m_inactiveNodeState.ItemAt(n));
1142
1143 archive->AddString("nodeName", e->name.String());
1144 archive->AddInt32("nodeKind", e->kind);
1145 archive->AddMessage("panel", &e->state);
1146 }
1147
1148 return B_OK;
1149 }
1150
1151 // [e.moon 8dec99] subset support
1152
importStateFor(const NodeSetIOContext * context,const BMessage * archive)1153 status_t MediaRoutingView::importStateFor(
1154 const NodeSetIOContext* context,
1155 const BMessage* archive) {
1156
1157 status_t err;
1158
1159 for(int32 archiveIndex = 0;; ++archiveIndex) {
1160
1161 // fetch archived key & panel data
1162 const char* key;
1163 err = archive->FindString("nodeKey", archiveIndex, &key);
1164 if(err < B_OK)
1165 break;
1166
1167 BMessage m;
1168 err = archive->FindMessage("panel", archiveIndex, &m);
1169 if(err < B_OK) {
1170 PRINT((
1171 "!!! MediaRoutingView::importStateFor(): missing panel %"
1172 B_PRId32 "\n", archiveIndex));
1173 continue;
1174 }
1175
1176 // find corresponding node
1177 media_node_id id;
1178 err = context->getNodeFor(key, &id);
1179 if(err < B_OK) {
1180 PRINT((
1181 "!!! MediaRoutingView::importStateFor(): missing node '%s'\n",
1182 key));
1183 continue;
1184 }
1185
1186 // look for panel, create it if necessary
1187 MediaNodePanel* panel;
1188 err = _findPanelFor(id, &panel);
1189 if(err < B_OK) {
1190 // create it
1191 err = _addPanelFor(
1192 id,
1193 BPoint(5.0, 5.0));
1194 if(err < B_OK) {
1195 PRINT((
1196 "!!! MediaRoutingView::importStateFor(): _addPanelFor():\n"
1197 " %s\n", strerror(err)));
1198 continue;
1199 }
1200
1201 err = _findPanelFor(id, &panel);
1202 if(err < B_OK) {
1203 PRINT((
1204 "!!! MediaRoutingView::importStateFor(): _findPanelFor():\n"
1205 " %s\n", strerror(err)));
1206 continue;
1207 }
1208 }
1209
1210 // pass state data along
1211 panel->importState(&m);
1212
1213 // select the panel
1214 SelectItem(panel, false);
1215 }
1216
1217 return B_OK;
1218 }
1219
exportStateFor(const NodeSetIOContext * context,BMessage * archive) const1220 status_t MediaRoutingView::exportStateFor(
1221 const NodeSetIOContext* context,
1222 BMessage* archive) const {
1223
1224 status_t err;
1225
1226 for(uint32 n = 0; n < context->countNodes(); ++n) {
1227 MediaNodePanel* panel;
1228 err = _findPanelFor(
1229 context->nodeAt(n),
1230 &panel);
1231 if(err < B_OK) {
1232 PRINT((
1233 "!!! MediaRoutingView::exportStateFor():\n"
1234 " no panel for node %" B_PRId32 "\n",
1235 context->nodeAt(n)));
1236 return B_BAD_VALUE;
1237 }
1238
1239 const char* key = context->keyAt(n);
1240
1241 archive->AddString("nodeKey", key);
1242 BMessage m;
1243 panel->exportState(&m);
1244 archive->AddMessage("panel", &m);
1245 }
1246
1247 return B_OK;
1248 }
1249
1250 // -------------------------------------------------------- //
1251 // *** children management
1252 // -------------------------------------------------------- //
1253
_addPanelFor(media_node_id id,BPoint atPoint)1254 status_t MediaRoutingView::_addPanelFor(
1255 media_node_id id,
1256 BPoint atPoint)
1257 {
1258 D_METHOD(("MediaRoutingView::_addPanelFor()\n"));
1259
1260 manager->lock();
1261 NodeRef *ref;
1262 status_t error = manager->getNodeRef(id, &ref);
1263 manager->unlock();
1264 if (!error)
1265 {
1266 add_observer(this, ref);
1267 MediaNodePanel *panel = 0;
1268 if (id == m_lastDroppedNode) // this was instantiated thru drag & drop
1269 {
1270 AddItem(panel = new MediaNodePanel(m_lastDropPoint, ref));
1271 SelectItem(panel, true);
1272 m_lastDroppedNode = 0;
1273 }
1274 else // this was an externally created node, must find a nice position first
1275 {
1276 panel = new MediaNodePanel(BPoint(0.0, 0.0), ref);
1277 AddItem(panel);
1278 BMessage state;
1279 if(_fetchInactiveNodeState(panel, &state) == B_OK)
1280 panel->importState(&state);
1281 else {
1282 BPoint p = findFreePositionFor(panel);
1283 panel->moveTo(p);
1284 }
1285 Invalidate(panel->Frame());
1286 }
1287 }
1288 updateDataRect();
1289 return error;
1290 }
1291
_findPanelFor(media_node_id id,MediaNodePanel ** outPanel) const1292 status_t MediaRoutingView::_findPanelFor(
1293 media_node_id id,
1294 MediaNodePanel **outPanel) const
1295 {
1296 D_METHOD(("MediaRoutingView::_findPanelFor()\n"));
1297
1298 for (uint32 i = 0; i < CountItems(DiagramItem::M_BOX); i++)
1299 {
1300 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(ItemAt(i, DiagramItem::M_BOX));
1301 if (panel)
1302 {
1303 if (panel->ref->id() == id)
1304 {
1305 *outPanel = panel;
1306 return B_OK;
1307 }
1308 }
1309 }
1310 return B_ERROR;
1311 }
1312
_removePanelFor(media_node_id id)1313 status_t MediaRoutingView::_removePanelFor(
1314 media_node_id id)
1315 {
1316 D_METHOD(("MediaRoutingView::_removePanelFor()\n"));
1317
1318 MediaNodePanel *panel;
1319 if (_findPanelFor(id, &panel) == B_OK)
1320 {
1321 if (RemoveItem(panel))
1322 {
1323 remove_observer(this, panel->ref);
1324 Invalidate(panel->Frame());
1325 delete panel;
1326 return B_OK;
1327 }
1328 }
1329 return B_ERROR;
1330 }
1331
_addWireFor(Connection & connection)1332 status_t MediaRoutingView::_addWireFor(
1333 Connection& connection)
1334 {
1335 D_METHOD(("MediaRoutingView::_addWireFor()\n"));
1336
1337 MediaNodePanel *source, *destination;
1338 if ((_findPanelFor(connection.sourceNode(), &source) == B_OK)
1339 && (_findPanelFor(connection.destinationNode(), &destination) == B_OK))
1340 {
1341 status_t error;
1342
1343 media_output output;
1344 error = connection.getOutput(&output);
1345 if (error)
1346 {
1347 return error;
1348 }
1349 MediaJack *outputJack = new MediaJack(output);
1350 source->AddItem(outputJack);
1351
1352 media_input input;
1353 error = connection.getInput(&input);
1354 if (error)
1355 {
1356 return error;
1357 }
1358 MediaJack *inputJack = new MediaJack(input);
1359 destination->AddItem(inputJack);
1360
1361 MediaWire *wire = new MediaWire(connection, outputJack, inputJack);
1362 AddItem(wire);
1363 source->updateIOJacks();
1364 source->arrangeIOJacks();
1365 destination->updateIOJacks();
1366 destination->arrangeIOJacks();
1367 updateDataRect();
1368
1369 // [e.moon 21nov99] group creation/merging now performed by
1370 // RouteAppNodeManager
1371
1372 Invalidate(source->Frame());
1373 Invalidate(destination->Frame());
1374 Invalidate(wire->Frame());
1375 return B_OK;
1376 }
1377 else
1378 {
1379 return B_ERROR;
1380 }
1381 }
1382
_findWireFor(uint32 connectionID,MediaWire ** outWire) const1383 status_t MediaRoutingView::_findWireFor(
1384 uint32 connectionID,
1385 MediaWire **outWire) const
1386 {
1387 D_METHOD(("MediaRoutingView::_findWireFor()\n"));
1388
1389 for (uint32 i = 0; i < CountItems(DiagramItem::M_WIRE); i++)
1390 {
1391 MediaWire *wire = dynamic_cast<MediaWire *>(ItemAt(i, DiagramItem::M_WIRE));
1392 if (wire && wire->connection.id() == connectionID)
1393 {
1394 *outWire = wire;
1395 return B_OK;
1396 }
1397 }
1398 return B_ERROR;
1399 }
1400
_removeWireFor(uint32 connectionID)1401 status_t MediaRoutingView::_removeWireFor(
1402 uint32 connectionID)
1403 {
1404 D_METHOD(("MediaRoutingView::_removeWireFor()\n"));
1405
1406 MediaWire *wire;
1407 if (_findWireFor(connectionID, &wire) == B_OK)
1408 {
1409 MediaNodePanel *source, *destination;
1410 _findPanelFor(wire->connection.sourceNode(), &source);
1411 _findPanelFor(wire->connection.destinationNode(), &destination);
1412 RemoveItem(wire);
1413 Invalidate(wire->Frame());
1414 delete wire;
1415 if (source)
1416 {
1417 source->updateIOJacks();
1418 source->arrangeIOJacks();
1419 Invalidate(source->Frame());
1420 }
1421 if (destination)
1422 {
1423 destination->updateIOJacks();
1424 destination->arrangeIOJacks();
1425 Invalidate(destination->Frame());
1426 }
1427
1428 // [e.moon 21nov99] group split/remove now performed by
1429 // RouteAppNodeManager
1430
1431 updateDataRect();
1432 return B_OK;
1433 }
1434 return B_ERROR;
1435 }
1436
1437 // -------------------------------------------------------- //
1438 // *** internal methods
1439 // -------------------------------------------------------- //
1440
_addShortcuts()1441 void MediaRoutingView::_addShortcuts()
1442 {
1443 Window()->AddShortcut('A', B_COMMAND_KEY,
1444 new BMessage(M_SELECT_ALL), this);
1445 Window()->AddShortcut('K', B_COMMAND_KEY,
1446 new BMessage(M_CLEANUP_REQUESTED), this);
1447 Window()->AddShortcut('T', B_COMMAND_KEY,
1448 new BMessage(M_DELETE_SELECTION), this);
1449 Window()->AddShortcut('P', B_COMMAND_KEY,
1450 new BMessage(M_NODE_TWEAK_PARAMETERS), this);
1451 Window()->AddShortcut('P', B_COMMAND_KEY | B_SHIFT_KEY,
1452 new BMessage(M_NODE_START_CONTROL_PANEL), this);
1453 Window()->AddShortcut('I', B_COMMAND_KEY,
1454 new BMessage(InfoWindowManager::M_INFO_WINDOW_REQUESTED), this);
1455 }
1456
_initLayout()1457 void MediaRoutingView::_initLayout()
1458 {
1459 D_METHOD(("MediaRoutingView::_initLayout()\n"));
1460
1461 BString measure;
1462 measure << " " << B_TRANSLATE("Be Audio Mixer") << " ";
1463
1464 switch (m_layout)
1465 {
1466 case M_ICON_VIEW:
1467 {
1468 // Adjust the jack width for displaying the abbreviated
1469 // input/output name
1470 BFont font(be_plain_font);
1471 font.SetSize(font.Size() - 2.0);
1472 for (int i = 0; i < MediaJack::M_MAX_ABBR_LENGTH; i++)
1473 {
1474 MediaJack::M_DEFAULT_WIDTH += font.StringWidth("M");
1475 }
1476 MediaJack::M_DEFAULT_WIDTH += 2.0; // add some padding
1477
1478 // Adjust the default size for MediaNodePanels to fit the
1479 // size of be_plain_font
1480 float labelWidth, bodyWidth;
1481 float labelHeight, bodyHeight;
1482 font_height fh;
1483 be_plain_font->GetHeight(&fh);
1484 labelWidth = 4 * MediaNodePanel::M_LABEL_H_MARGIN
1485 + be_plain_font->StringWidth(measure.String());
1486 bodyWidth = 2 * MediaNodePanel::M_BODY_H_MARGIN + B_LARGE_ICON
1487 + 2 * MediaJack::M_DEFAULT_WIDTH;
1488 labelHeight = 2 * MediaNodePanel::M_LABEL_V_MARGIN
1489 + fh.ascent + fh.descent + fh.leading + 1.0;
1490 bodyHeight = 2 * MediaNodePanel::M_BODY_V_MARGIN + B_LARGE_ICON;
1491 MediaNodePanel::M_DEFAULT_WIDTH = labelWidth > bodyWidth ? labelWidth : bodyWidth;
1492 MediaNodePanel::M_DEFAULT_HEIGHT = labelHeight + bodyHeight;
1493 Align(&MediaNodePanel::M_DEFAULT_WIDTH, &MediaNodePanel::M_DEFAULT_HEIGHT);
1494
1495 // Adjust the cleanup settings
1496 M_CLEANUP_H_GAP += MediaNodePanel::M_DEFAULT_WIDTH;
1497 break;
1498 }
1499 case M_MINI_ICON_VIEW:
1500 {
1501 // Adjust the default size for MediaNodePanels to fit the
1502 // size of be_plain_font
1503 float labelWidth, bodyWidth;
1504 float labelHeight, bodyHeight;
1505 font_height fh;
1506 be_plain_font->GetHeight(&fh);
1507 labelWidth = 4 * MediaNodePanel::M_LABEL_H_MARGIN
1508 + be_plain_font->StringWidth(measure.String());
1509 bodyWidth = 2 * MediaNodePanel::M_BODY_H_MARGIN + B_MINI_ICON;
1510 labelHeight = 3 * MediaNodePanel::M_LABEL_V_MARGIN
1511 + fh.ascent + fh.descent + fh.leading
1512 + 2 * MediaJack::M_DEFAULT_HEIGHT;
1513 bodyHeight = 2 * MediaNodePanel::M_BODY_V_MARGIN + B_MINI_ICON;
1514 MediaNodePanel::M_DEFAULT_WIDTH = labelWidth + bodyWidth;
1515 MediaNodePanel::M_DEFAULT_HEIGHT = labelHeight > bodyHeight ? labelHeight : bodyHeight;
1516 Align(&MediaNodePanel::M_DEFAULT_WIDTH, &MediaNodePanel::M_DEFAULT_HEIGHT);
1517
1518 // Adjust the cleanup settings
1519 M_CLEANUP_V_GAP += MediaNodePanel::M_DEFAULT_HEIGHT;
1520 break;
1521 }
1522 }
1523 }
1524
_initContent()1525 void MediaRoutingView::_initContent()
1526 {
1527 D_METHOD(("MediaRoutingView::_initContent()\n"));
1528
1529 Autolock lock(manager);
1530
1531 void *cookie = 0;
1532 NodeRef *ref;
1533 while (manager->getNextRef(&ref, &cookie) == B_OK)
1534 {
1535 // add self as observer
1536 add_observer(this, ref);
1537 // create & place node view (+++++ defer until observer status confirmed!)
1538 _addPanelFor(ref->id(), BPoint(M_CLEANUP_H_MARGIN, M_CLEANUP_V_MARGIN));
1539 }
1540 cookie = 0;
1541 Connection connection;
1542 while (manager->getNextConnection(&connection, &cookie) == B_OK)
1543 {
1544 _addWireFor(connection);
1545 }
1546
1547 // create default groups
1548 NodeGroup* group;
1549 NodeRef* videoIn = manager->videoInputNode();
1550 if (videoIn)
1551 {
1552 group = manager->createGroup(B_TRANSLATE("Video input"));
1553 group->setRunMode(BMediaNode::B_RECORDING);
1554 group->addNode(videoIn);
1555 }
1556 NodeRef* audioIn = manager->audioInputNode();
1557 if (audioIn)
1558 {
1559 group = manager->createGroup(B_TRANSLATE("Audio input"));
1560 group->setRunMode(BMediaNode::B_RECORDING);
1561 group->addNode(audioIn);
1562 }
1563 NodeRef* videoOut = manager->videoOutputNode();
1564 if (videoOut)
1565 {
1566 group = manager->createGroup(B_TRANSLATE("Video output"));
1567 group->addNode(videoOut);
1568 }
1569 }
1570
_changeCyclingForSelection(bool cycle)1571 void MediaRoutingView::_changeCyclingForSelection(
1572 bool cycle)
1573 {
1574 D_METHOD(("MediaRoutingView::_changeCyclingForSelection()\n"));
1575
1576 if (SelectedType() == DiagramItem::M_BOX)
1577 {
1578 manager->lock();
1579 for (uint32 i = 0; i < CountSelectedItems(); i++)
1580 {
1581 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i));
1582 if (panel && (panel->ref->isCycling() != cycle))
1583 {
1584 panel->ref->setCycling(cycle);
1585 }
1586 }
1587 manager->unlock();
1588 }
1589 }
1590
_changeRunModeForSelection(uint32 mode)1591 void MediaRoutingView::_changeRunModeForSelection(
1592 uint32 mode)
1593 {
1594 D_METHOD(("MediaRoutingView::_changeRunModeForSelection()\n"));
1595
1596 if (SelectedType() == DiagramItem::M_BOX)
1597 {
1598 manager->lock();
1599 for (uint32 i = 0; i < CountSelectedItems(); i++)
1600 {
1601 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i));
1602 if (panel && (panel->ref->runMode() != mode))
1603 {
1604 panel->ref->setRunMode(mode);
1605 }
1606 }
1607 manager->unlock();
1608 }
1609 }
1610
_openInfoWindowsForSelection()1611 void MediaRoutingView::_openInfoWindowsForSelection() {
1612 D_METHOD(("MediaRoutingView::_openInfoWindowsForSelection()\n"));
1613
1614 InfoWindowManager *manager = InfoWindowManager::Instance();
1615 if (!manager) {
1616 return;
1617 }
1618
1619 if (SelectedType() == DiagramItem::M_BOX) {
1620 for (uint32 i = 0; i < CountSelectedItems(); i++) {
1621 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i));
1622 if (panel && manager->Lock()) {
1623 manager->openWindowFor(panel->ref);
1624 manager->Unlock();
1625 }
1626 }
1627 }
1628 else if (SelectedType() == DiagramItem::M_WIRE) {
1629 for (uint32 i = 0; i < CountSelectedItems(); i++) {
1630 MediaWire *wire = dynamic_cast<MediaWire *>(SelectedItemAt(i));
1631 if (wire && manager->Lock()) {
1632 manager->openWindowFor(wire->connection);
1633 manager->Unlock();
1634 }
1635 }
1636 }
1637 }
1638
_openParameterWindowsForSelection()1639 void MediaRoutingView::_openParameterWindowsForSelection() {
1640 D_METHOD(("MediaRoutingView::_openParameterWindowsForSelection()\n"));
1641
1642 if (SelectedType() != DiagramItem::M_BOX) {
1643 // can only open parameter window for nodes
1644 return;
1645 }
1646
1647 for (uint32 i = 0; i < CountSelectedItems(); i++) {
1648 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i));
1649 if (panel && (panel->ref->kind() & B_CONTROLLABLE)) {
1650 ParameterWindowManager *paramMgr= ParameterWindowManager::Instance();
1651 if (paramMgr && paramMgr->Lock()) {
1652 paramMgr->openWindowFor(panel->ref);
1653 paramMgr->Unlock();
1654 }
1655 }
1656 }
1657 }
1658
_startControlPanelsForSelection()1659 void MediaRoutingView::_startControlPanelsForSelection() {
1660 D_METHOD(("MediaRoutingView::_startControlPanelsForSelection()\n"));
1661
1662 if (SelectedType() != DiagramItem::M_BOX) {
1663 // can only start control panel for nodes
1664 return;
1665 }
1666
1667 for (uint32 i = 0; i < CountSelectedItems(); i++) {
1668 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i));
1669 if (panel && (panel->ref->kind() & B_CONTROLLABLE)) {
1670 ParameterWindowManager *paramMgr= ParameterWindowManager::Instance();
1671 if (paramMgr && paramMgr->Lock()) {
1672 paramMgr->startControlPanelFor(panel->ref);
1673 paramMgr->Unlock();
1674 }
1675 }
1676 }
1677 }
1678
_deleteSelection()1679 void MediaRoutingView::_deleteSelection()
1680 {
1681 D_METHOD(("MediaRoutingView::_deleteSelection()\n"));
1682 if (SelectedType() == DiagramItem::M_BOX)
1683 {
1684 for (uint32 i = 0; i < CountSelectedItems(); i++)
1685 {
1686 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i));
1687 if (panel && panel->ref->isInternal())
1688 {
1689 status_t error = panel->ref->releaseNode();
1690 if (error)
1691 {
1692 BString s = B_TRANSLATE("Could not release '%refname%'");
1693 s.ReplaceFirst("%rename%", panel->ref->name());
1694 showErrorMessage(s, error);
1695 }
1696 }
1697 }
1698 }
1699 else if (SelectedType() == DiagramItem::M_WIRE)
1700 {
1701 for (uint32 i = 0; i < CountSelectedItems(); i++)
1702 {
1703 MediaWire *wire = dynamic_cast<MediaWire *>(SelectedItemAt(i));
1704 if (wire && !(wire->connection.flags() & Connection::LOCKED))
1705 {
1706 status_t error = manager->disconnect(wire->connection);
1707 if (error)
1708 {
1709 showErrorMessage(
1710 B_TRANSLATE("Could not disconnect"), error);
1711 }
1712 }
1713 }
1714 }
1715 // make sure none of the deleted items is still displaying its mouse cursor !
1716 be_app->SetCursor(B_HAND_CURSOR);
1717 }
1718
_checkDroppedFile(entry_ref * ref,BPoint dropPoint)1719 void MediaRoutingView::_checkDroppedFile(
1720 entry_ref *ref,
1721 BPoint dropPoint)
1722 {
1723 D_METHOD(("MediaRoutingView::_checkDroppedFile()\n"));
1724
1725 // [cell 26apr00] traverse links
1726 BEntry entry(ref, true);
1727 entry.GetRef(ref);
1728
1729 BNode node(ref);
1730 if (node.InitCheck() == B_OK)
1731 {
1732 BNodeInfo nodeInfo(&node);
1733 if (nodeInfo.InitCheck() == B_OK)
1734 {
1735 char mimeString[B_MIME_TYPE_LENGTH];
1736 if (nodeInfo.GetType(mimeString) == B_OK)
1737 {
1738 BMimeType mimeType(mimeString);
1739 BMimeType superType;
1740
1741 // [e.moon 22dec99] handle dropped node-set files
1742 if(mimeType == RouteApp::s_nodeSetType) {
1743 BMessage m(B_REFS_RECEIVED);
1744 m.AddRef("refs", ref);
1745 be_app_messenger.SendMessage(&m);
1746 }
1747 else if (mimeType.GetSupertype(&superType) == B_OK)
1748 {
1749 if (superType == "image")
1750 {
1751 _changeBackground(ref);
1752 }
1753 else if ((superType == "audio") || (superType == "video"))
1754 {
1755 NodeRef* droppedNode;
1756 status_t error;
1757 error = manager->instantiate(*ref, B_BUFFER_PRODUCER, &droppedNode);
1758 if (!error)
1759 {
1760 media_output encVideoOutput;
1761 if (droppedNode->findFreeOutput(&encVideoOutput, B_MEDIA_ENCODED_VIDEO) == B_OK)
1762 {
1763 droppedNode->setFlags(droppedNode->flags() | NodeRef::NO_POSITION_REPORTING);
1764 }
1765 m_lastDroppedNode = droppedNode->id();
1766 m_lastDropPoint = Align(dropPoint);
1767 }
1768 else
1769 {
1770 char fileName[B_FILE_NAME_LENGTH];
1771 BEntry entry(ref);
1772 entry.GetName(fileName);
1773 BString s = B_TRANSLATE(
1774 "Could not load '%filename%'");
1775 s.ReplaceFirst("%filename%", fileName);
1776 showErrorMessage(s, error);
1777 }
1778 }
1779 }
1780 }
1781 }
1782 }
1783 }
1784
_changeBackground(entry_ref * ref)1785 void MediaRoutingView::_changeBackground(
1786 entry_ref *ref)
1787 {
1788 D_METHOD(("MediaRoutingView::_changeBackground()\n"));
1789
1790 status_t error;
1791 BBitmap *background = 0;
1792 BFile file(ref, B_READ_ONLY);
1793 error = file.InitCheck();
1794 if (!error)
1795 {
1796 BTranslatorRoster *roster = BTranslatorRoster::Default();
1797 BBitmapStream stream;
1798 error = roster->Translate(&file, NULL, NULL, &stream, B_TRANSLATOR_BITMAP);
1799 if (!error)
1800 {
1801 stream.DetachBitmap(&background);
1802 setBackgroundBitmap(background);
1803 Invalidate();
1804
1805 // [e.moon 1dec99] persistence, yay
1806 m_backgroundBitmapEntry.SetTo(ref);
1807 }
1808 }
1809 delete background;
1810 }
1811
_changeBackground(rgb_color color)1812 void MediaRoutingView::_changeBackground(
1813 rgb_color color)
1814 {
1815 D_METHOD(("MediaRoutingView::_changeBackground()\n"));
1816 setBackgroundColor(color);
1817 Invalidate();
1818
1819 // [e.moon 1dec99] persistence, yay
1820 m_backgroundBitmapEntry.Unset();
1821 }
1822
1823 void
_adjustScrollBars()1824 MediaRoutingView::_adjustScrollBars()
1825 {
1826 D_METHOD(("MediaRoutingView::_adjustScrollBars()\n"));
1827
1828 BScrollBar *scrollBar;
1829
1830 // adjust horizontal scroll bar
1831 scrollBar = ScrollBar(B_HORIZONTAL);
1832 if (scrollBar) {
1833 float bigStep = floor(MediaNodePanel::M_DEFAULT_WIDTH + M_CLEANUP_H_GAP);
1834 scrollBar->SetSteps(floor(bigStep / 10.0), bigStep);
1835 }
1836
1837 // adjust vertical scroll bar
1838 scrollBar = ScrollBar(B_VERTICAL);
1839 if (scrollBar) {
1840 float bigStep = floor(MediaNodePanel::M_DEFAULT_HEIGHT + M_CLEANUP_V_GAP);
1841 scrollBar->SetSteps(floor(bigStep / 10.0), bigStep);
1842 }
1843 }
1844
1845 void
_broadcastSelection() const1846 MediaRoutingView::_broadcastSelection() const
1847 {
1848 int32 selectedGroup = 0;
1849
1850 if (SelectedType() == DiagramItem::M_BOX) {
1851 // iterate thru the list of selected node panels and make the
1852 // first group we find the selected group
1853 for (uint32 i = 0; i < CountSelectedItems(); i++) {
1854 MediaNodePanel *panel = dynamic_cast<MediaNodePanel *>(SelectedItemAt(i));
1855 if (panel && panel->ref->group()) {
1856 selectedGroup = panel->ref->group()->id();
1857 BMessenger messenger(Window());
1858 BMessage groupMsg(M_GROUP_SELECTED);
1859 groupMsg.AddInt32("groupID", selectedGroup);
1860 messenger.SendMessage(&groupMsg);
1861 return;
1862 }
1863 }
1864 }
1865
1866 // currently no group is selected
1867 BMessenger messenger(Window());
1868 BMessage groupMsg(M_GROUP_SELECTED);
1869 groupMsg.AddInt32("groupID", selectedGroup);
1870 messenger.SendMessage(&groupMsg);
1871 }
1872
1873 status_t
_fetchInactiveNodeState(MediaNodePanel * forPanel,BMessage * outMessage)1874 MediaRoutingView::_fetchInactiveNodeState(MediaNodePanel *forPanel, BMessage *outMessage)
1875 {
1876 // copy inactive node state info
1877 int32 c = m_inactiveNodeState.CountItems();
1878 for(int32 n = 0; n < c; n++) {
1879 _inactive_node_state_entry* e = reinterpret_cast<_inactive_node_state_entry*>(
1880 m_inactiveNodeState.ItemAt(n));
1881 ASSERT(e);
1882 if(e->name != forPanel->ref->name())
1883 continue;
1884
1885 if(e->kind != forPanel->ref->kind())
1886 continue;
1887
1888 // found match; extract message & remove entry
1889 *outMessage = e->state;
1890 m_inactiveNodeState.RemoveItem(n);
1891 return B_OK;
1892 }
1893
1894 return B_BAD_VALUE;
1895 }
1896
1897 void
_emptyInactiveNodeState()1898 MediaRoutingView::_emptyInactiveNodeState()
1899 {
1900 int32 c = m_inactiveNodeState.CountItems();
1901 for(int32 n = 0; n < c; n++) {
1902 _inactive_node_state_entry* e = reinterpret_cast<_inactive_node_state_entry*>(
1903 m_inactiveNodeState.ItemAt(n));
1904 ASSERT(e);
1905 delete e;
1906 }
1907 m_inactiveNodeState.MakeEmpty();
1908 }
1909
1910
1911 // END -- MediaRoutingView.cpp --
1912