2 * Copyright (c) 1999-2000, Eric Moon.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
36 #include "RouteWindow.h"
37 #include "MediaRoutingView.h"
38 #include "StatusView.h"
40 #include "DormantNodeWindow.h"
41 #include "TransportWindow.h"
43 #include "RouteAppNodeManager.h"
44 #include "NodeGroup.h"
45 #include "TipManager.h"
55 #include <Messenger.h>
58 #include <ScrollView.h>
59 #include <StringView.h>
63 #include "debug_tools.h"
64 #define D_HOOK(x) //PRINT (x)
65 #define D_INTERNAL(x) //PRINT (x)
67 __USE_CORTEX_NAMESPACE
70 const char* const RouteWindow::s_windowName
= "Cortex";
72 const BRect
RouteWindow::s_initFrame(100,100,700,550);
74 const char* const g_aboutText
=
75 "Cortex/Route 2.1.2\n\n"
76 "Copyright 1999-2000 Eric Moon\n"
77 "All rights reserved.\n\n"
78 "The Cortex Team:\n\n"
79 "Christopher Lenz: UI\n"
80 "Eric Moon: UI, back-end\n\n"
81 "Thanks to:\nJohn Ashmun\nJon Watte\nDoug Wright\n<your name here>\n\n"
82 "Certain icons used herein are the property of\n"
83 "Be, Inc. and are used by permission.";
86 RouteWindow::~RouteWindow()
91 RouteWindow::RouteWindow(RouteAppNodeManager
* manager
)
93 BWindow(s_initFrame
, s_windowName
, B_DOCUMENT_WINDOW
, 0),
97 m_dormantNodeWindow(0),
104 // initialize the menu bar: add all menus that target this window
105 BMenuBar
* pMenuBar
= new BMenuBar(b
, "menuBar");
106 BMenu
* pFileMenu
= new BMenu("File");
107 BMenuItem
* item
= new BMenuItem("Open" B_UTF8_ELLIPSIS
,
108 new BMessage(RouteApp::M_SHOW_OPEN_PANEL
), 'O');
109 item
->SetTarget(be_app
);
110 pFileMenu
->AddItem(item
);
111 pFileMenu
->AddItem(new BSeparatorItem());
112 item
= new BMenuItem("Save nodes" B_UTF8_ELLIPSIS
,
113 new BMessage(RouteApp::M_SHOW_SAVE_PANEL
), 'S');
114 item
->SetTarget(be_app
);
115 pFileMenu
->AddItem(item
);
116 pFileMenu
->AddItem(new BSeparatorItem());
117 pFileMenu
->AddItem(new BMenuItem("About Cortex/Route" B_UTF8_ELLIPSIS
,
118 new BMessage(B_ABOUT_REQUESTED
)));
119 pFileMenu
->AddItem(new BSeparatorItem());
120 pFileMenu
->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED
)));
121 pMenuBar
->AddItem(pFileMenu
);
124 // build the routing view
126 rvBounds
.top
= pMenuBar
->Frame().bottom
+1;
127 rvBounds
.right
-= B_V_SCROLL_BAR_WIDTH
;
128 rvBounds
.bottom
-= B_H_SCROLL_BAR_HEIGHT
;
129 m_routingView
= new MediaRoutingView(manager
, rvBounds
, "routingView");
131 BRect hsBounds
= rvBounds
;
132 hsBounds
.left
= rvBounds
.left
+ 199;
133 hsBounds
.top
= hsBounds
.bottom
+ 1;
135 hsBounds
.bottom
= b
.bottom
+ 1;
137 m_hScrollBar
= new BScrollBar(hsBounds
, "hScrollBar", m_routingView
,
139 AddChild(m_hScrollBar
);
141 BRect vsBounds
= rvBounds
;
142 vsBounds
.left
= vsBounds
.right
+ 1;
144 vsBounds
.right
= b
.right
+ 1;
147 m_vScrollBar
= new BScrollBar(vsBounds
, "vScrollBar", m_routingView
,
149 AddChild(m_vScrollBar
);
151 BRect svBounds
= rvBounds
;
153 svBounds
.right
= hsBounds
.left
- 1;
154 svBounds
.top
= svBounds
.bottom
+ 1;
155 svBounds
.bottom
= b
.bottom
+ 1;
157 m_statusView
= new StatusView(svBounds
, manager
, m_hScrollBar
);
158 AddChild(m_statusView
);
160 AddChild(m_routingView
);
162 float minWidth
, maxWidth
, minHeight
, maxHeight
;
163 GetSizeLimits(&minWidth
, &maxWidth
, &minHeight
, &maxHeight
);
164 minWidth
= m_statusView
->Frame().Width() + 6 * B_V_SCROLL_BAR_WIDTH
;
165 minHeight
= 6 * B_H_SCROLL_BAR_HEIGHT
;
166 SetSizeLimits(minWidth
, maxWidth
, minHeight
, maxHeight
);
168 // construct the Window menu
169 BMenu
* windowMenu
= new BMenu("Window");
170 m_transportWindowItem
= new BMenuItem(
172 new BMessage(M_TOGGLE_TRANSPORT_WINDOW
));
173 windowMenu
->AddItem(m_transportWindowItem
);
175 m_dormantNodeWindowItem
= new BMenuItem(
177 new BMessage(M_TOGGLE_DORMANT_NODE_WINDOW
));
178 windowMenu
->AddItem(m_dormantNodeWindowItem
);
180 windowMenu
->AddItem(new BSeparatorItem());
182 m_pullPalettesItem
= new BMenuItem(
184 new BMessage(M_TOGGLE_PULLING_PALETTES
));
185 windowMenu
->AddItem(m_pullPalettesItem
);
187 pMenuBar
->AddItem(windowMenu
);
189 // create the dormant-nodes palette
190 _toggleDormantNodeWindow();
192 // display group inspector
193 _toggleTransportWindow();
197 // #pragma mark - operations
200 /*! Enable/disable palette position-locking (when the main
201 window is moved, all palettes follow).
204 RouteWindow::isPullPalettes() const
206 return m_pullPalettesItem
->IsMarked();
211 RouteWindow::setPullPalettes(bool enabled
)
213 m_pullPalettesItem
->SetMarked(enabled
);
218 RouteWindow::constrainToScreen()
220 BScreen
screen(this);
222 const BRect sr
= screen
.Frame();
224 // [c.lenz 1mar2000] this should be handled by every window
225 // itself. will probably change soon ;-)
226 _constrainToScreen();
229 BPoint offset(0.0, 0.0);
234 if(r.left >= (sr.right - 20.0))
235 offset.x -= (r.left - (sr.Width()/2));
236 if(r.top >= (sr.bottom - 20.0))
237 offset.y -= (r.top - (sr.Height()/2));
238 if(offset.x != 0.0 || offset.y != 0.0) {
239 setPullPalettes(false);
240 MoveBy(offset.x, offset.y);
244 BPoint offset
= BPoint(0.0, 0.0);
245 BRect r
= (m_transportWindow
) ?
246 m_transportWindow
->Frame() :
247 m_transportWindowFrame
;
249 offset
.x
= (sr
.Width()*.75) - r
.left
;
251 offset
.y
= (sr
.Height()*.25) - r
.top
;
252 if(r
.left
>= (sr
.right
- 20.0))
253 offset
.x
-= (r
.left
- (sr
.Width()/2));
254 if(r
.top
>= (sr
.bottom
- 20.0))
255 offset
.y
-= (r
.top
- (sr
.Height()/2));
257 if(offset
.x
!= 0.0 || offset
.y
!= 0.0) {
258 if(m_transportWindow
)
259 m_transportWindow
->MoveBy(offset
.x
, offset
.y
);
261 m_transportWindowFrame
.OffsetBy(offset
.x
, offset
.y
);
265 offset
= BPoint(0.0, 0.0);
266 r
= (m_dormantNodeWindow
) ?
267 m_dormantNodeWindow
->Frame() :
268 m_dormantNodeWindowFrame
;
270 offset
.x
= (sr
.Width()*.25) - r
.left
;
272 offset
.y
= (sr
.Height()*.125) - r
.top
;
273 if(r
.left
>= (sr
.right
- 20.0))
274 offset
.x
-= (r
.left
- (sr
.Width()/2));
275 if(r
.top
>= (sr
.bottom
- 20.0))
276 offset
.y
-= (r
.top
- (sr
.Height()/2));
278 if(offset
.x
!= 0.0 || offset
.y
!= 0.0) {
279 if(m_dormantNodeWindow
)
280 m_dormantNodeWindow
->MoveBy(offset
.x
, offset
.y
);
282 m_dormantNodeWindowFrame
.OffsetBy(offset
.x
, offset
.y
);
288 // #pragma mark - BWindow implementation
292 RouteWindow::FrameMoved(BPoint point
)
294 // ignore notification if the window isn't yet visible
298 BPoint delta
= point
- m_lastFramePosition
;
299 m_lastFramePosition
= point
;
302 if (m_pullPalettesItem
->IsMarked())
303 _movePalettesBy(delta
.x
, delta
.y
);
308 RouteWindow::FrameResized(float width
, float height
)
310 D_HOOK(("RouteWindow::FrameResized()\n"));
322 RouteWindow::QuitRequested()
324 be_app
->PostMessage(B_QUIT_REQUESTED
);
325 return false; // [e.moon 20oct99] app now quits window
330 RouteWindow::Zoom(BPoint origin
, float width
, float height
)
332 D_HOOK(("RouteWindow::Zoom()\n"));
336 BScreen
screen(this);
337 if (!screen
.Frame().Contains(Frame())) {
342 // resize to the ideal size
343 m_manualSize
= Bounds();
345 m_routingView
->GetPreferredSize(&width
, &height
);
346 width
+= B_V_SCROLL_BAR_WIDTH
;
347 height
+= B_H_SCROLL_BAR_HEIGHT
;
349 height
+= KeyMenuBar()->Frame().Height();
351 ResizeTo(width
, height
);
352 _constrainToScreen();
356 // resize to the most recent manual size
357 ResizeTo(m_manualSize
.Width(), m_manualSize
.Height());
363 // #pragma mark - BHandler implemenation
367 RouteWindow::MessageReceived(BMessage
* pMsg
)
370 // "RouteWindow::MessageReceived()\n"));
371 // pMsg->PrintToStream();
373 switch (pMsg
->what
) {
374 case B_ABOUT_REQUESTED
:
376 BAlert
* alert
= new BAlert("About", g_aboutText
, "OK");
377 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
381 case MediaRoutingView::M_GROUP_SELECTED
:
382 _handleGroupSelected(pMsg
);
385 case MediaRoutingView::M_SHOW_ERROR_MESSAGE
:
386 _handleShowErrorMessage(pMsg
);
389 case M_TOGGLE_TRANSPORT_WINDOW
:
390 _toggleTransportWindow();
393 case M_REFRESH_TRANSPORT_SETTINGS
:
394 _refreshTransportSettings(pMsg
);
397 case M_TOGGLE_PULLING_PALETTES
:
398 _togglePullPalettes();
401 case M_TOGGLE_DORMANT_NODE_WINDOW
:
402 _toggleDormantNodeWindow();
405 case M_TOGGLE_GROUP_ROLLING
:
406 _toggleGroupRolling();
410 _inherited::MessageReceived(pMsg
);
416 // #pragma mark - IStateArchivable
420 RouteWindow::importState(const BMessage
* archive
)
426 err
= archive
->FindRect("frame", &r
);
429 ResizeTo(r
.Width(), r
.Height());
430 m_lastFramePosition
= r
.LeftTop();
435 err
= archive
->FindInt32("statusViewWidth", &i
);
437 float diff
= i
- m_statusView
->Bounds().IntegerWidth();
438 m_statusView
->ResizeBy(diff
, 0.0);
439 m_hScrollBar
->ResizeBy(-diff
, 0.0);
440 m_hScrollBar
->MoveBy(diff
, 0.0);
445 err
= archive
->FindBool("pullPalettes", &b
);
447 m_pullPalettesItem
->SetMarked(b
);
450 // err = archive->FindString("saveDir", &p);
452 // m_openPanel.SetPanelDirectory(p);
453 // m_savePanel.SetPanelDirectory(p);
456 // dormant-node window
457 err
= archive
->FindRect("addonPaletteFrame", &r
);
459 m_dormantNodeWindowFrame
= r
;
460 err
= archive
->FindBool("addonPaletteVisible", &b
);
461 if (err
== B_OK
&& (b
!= (m_dormantNodeWindow
!= 0))) {
462 _toggleDormantNodeWindow();
463 if(!m_dormantNodeWindow
)
464 m_dormantNodeWindowFrame
= r
;
467 if (m_dormantNodeWindow
) {
468 m_dormantNodeWindow
->MoveTo(m_dormantNodeWindowFrame
.LeftTop());
469 m_dormantNodeWindow
->ResizeTo(
470 m_dormantNodeWindowFrame
.Width(),
471 m_dormantNodeWindowFrame
.Height());
475 err
= archive
->FindRect("transportFrame", &r
);
477 m_transportWindowFrame
= r
;
478 err
= archive
->FindBool("transportVisible", &b
);
479 if (err
== B_OK
&& (b
!= (m_transportWindow
!= 0))) {
480 _toggleTransportWindow();
481 if (!m_transportWindow
)
482 m_transportWindowFrame
= r
;
485 if (m_transportWindow
) {
486 m_transportWindow
->MoveTo(m_transportWindowFrame
.LeftTop());
487 m_transportWindow
->ResizeTo(
488 m_transportWindowFrame
.Width(),
489 m_transportWindowFrame
.Height());
497 RouteWindow::exportState(BMessage
* archive
) const
500 archive
->AddRect("frame", r
);
501 archive
->AddBool("pullPalettes", m_pullPalettesItem
->IsMarked());
503 bool b
= (m_dormantNodeWindow
!= 0);
504 r
= b
? m_dormantNodeWindow
->Frame() : m_dormantNodeWindowFrame
;
505 archive
->AddRect("addonPaletteFrame", r
);
506 archive
->AddBool("addonPaletteVisible", b
);
508 b
= (m_transportWindow
!= 0);
509 r
= b
? m_transportWindow
->Frame() : m_transportWindowFrame
;
511 archive
->AddRect("transportFrame", r
);
512 archive
->AddBool("transportVisible", b
);
514 // [c.lenz 23may00] remember status view width
515 int i
= m_statusView
->Bounds().IntegerWidth();
516 archive
->AddInt32("statusViewWidth", i
);
518 // entry_ref saveRef;
519 // m_savePanel.GetPanelDirectory(&saveRef);
520 // BEntry saveEntry(&saveRef);
521 // if(saveEntry.InitCheck() == B_OK) {
523 // saveEntry.GetPath(&p);
524 // archive->AddString("saveDir", p.Path());
531 // #pragma mark - implementation
535 RouteWindow::_constrainToScreen()
537 D_INTERNAL(("RouteWindow::_constrainToScreen()\n"));
539 BScreen
screen(this);
540 BRect screenRect
= screen
.Frame();
541 BRect windowRect
= Frame();
543 // if the window is outside the screen rect
544 // move it to the default position
545 if (!screenRect
.Intersects(windowRect
)) {
546 windowRect
.OffsetTo(screenRect
.LeftTop());
547 MoveTo(windowRect
.LeftTop());
548 windowRect
= Frame();
551 // if the window is larger than the screen rect
552 // resize it to fit at each side
553 if (!screenRect
.Contains(windowRect
)) {
554 if (windowRect
.left
< screenRect
.left
) {
555 windowRect
.left
= screenRect
.left
+ 5.0;
556 MoveTo(windowRect
.LeftTop());
557 windowRect
= Frame();
559 if (windowRect
.top
< screenRect
.top
) {
560 windowRect
.top
= screenRect
.top
+ 5.0;
561 MoveTo(windowRect
.LeftTop());
562 windowRect
= Frame();
564 if (windowRect
.right
> screenRect
.right
) {
565 windowRect
.right
= screenRect
.right
- 5.0;
567 if (windowRect
.bottom
> screenRect
.bottom
) {
568 windowRect
.bottom
= screenRect
.bottom
- 5.0;
570 ResizeTo(windowRect
.Width(), windowRect
.Height());
576 RouteWindow::_toggleTransportWindow()
578 if (m_transportWindow
) {
579 m_transportWindowFrame
= m_transportWindow
->Frame();
580 m_transportWindow
->Lock();
581 m_transportWindow
->Quit();
582 m_transportWindow
= 0;
583 m_transportWindowItem
->SetMarked(false);
585 m_transportWindow
= new TransportWindow(m_routingView
->manager
,
588 // ask for a selection update
589 BMessenger(m_routingView
).SendMessage(
590 MediaRoutingView::M_BROADCAST_SELECTION
);
592 // place & display the window
593 if (m_transportWindowFrame
.IsValid()) {
594 m_transportWindow
->MoveTo(m_transportWindowFrame
.LeftTop());
595 m_transportWindow
->ResizeTo(m_transportWindowFrame
.Width(),
596 m_transportWindowFrame
.Height());
599 m_transportWindow
->Show();
600 m_transportWindowItem
->SetMarked(true);
606 RouteWindow::_togglePullPalettes()
608 m_pullPalettesItem
->SetMarked(!m_pullPalettesItem
->IsMarked());
613 RouteWindow::_toggleDormantNodeWindow()
615 if (m_dormantNodeWindow
) {
616 m_dormantNodeWindowFrame
= m_dormantNodeWindow
->Frame();
617 m_dormantNodeWindow
->Lock();
618 m_dormantNodeWindow
->Quit();
619 m_dormantNodeWindow
= 0;
620 m_dormantNodeWindowItem
->SetMarked(false);
622 m_dormantNodeWindow
= new DormantNodeWindow(this);
623 if (m_dormantNodeWindowFrame
.IsValid()) {
624 m_dormantNodeWindow
->MoveTo(m_dormantNodeWindowFrame
.LeftTop());
625 m_dormantNodeWindow
->ResizeTo(m_dormantNodeWindowFrame
.Width(),
626 m_dormantNodeWindowFrame
.Height());
628 m_dormantNodeWindow
->Show();
629 m_dormantNodeWindowItem
->SetMarked(true);
635 RouteWindow::_handleGroupSelected(BMessage
* message
)
640 err
= message
->FindInt32("groupID", (int32
*)&groupID
);
643 "! RouteWindow::_handleGroupSelected(): no groupID in message!\n"));
647 if (!m_transportWindow
)
650 BMessage
m(TransportWindow::M_SELECT_GROUP
);
651 m
.AddInt32("groupID", groupID
);
652 BMessenger(m_transportWindow
).SendMessage(&m
);
654 m_selectedGroupID
= groupID
;
659 RouteWindow::_handleShowErrorMessage(BMessage
* message
)
664 err
= message
->FindString("text", &text
);
667 "! RouteWindow::_handleShowErrorMessage(): no text in message!\n"));
671 m_statusView
->setErrorMessage(text
.String(), message
->HasBool("error"));
675 //! Refresh the transport window for the given group, if any
677 RouteWindow::_refreshTransportSettings(BMessage
* message
)
682 err
= message
->FindInt32("groupID", (int32
*)&groupID
);
685 "! RouteWindow::_refreshTransportSettings(): no groupID in message!\n"));
689 if(m_transportWindow
) {
691 BMessenger(m_transportWindow
).SendMessage(message
);
697 RouteWindow::_closePalettes()
701 if (m_transportWindow
) {
702 m_transportWindow
->Lock();
703 m_transportWindow
->Quit();
704 m_transportWindow
= 0;
709 //! Move all palette windows by the specified amounts
710 void RouteWindow::_movePalettesBy(float xDelta
, float yDelta
)
712 if (m_transportWindow
)
713 m_transportWindow
->MoveBy(xDelta
, yDelta
);
715 if (m_dormantNodeWindow
)
716 m_dormantNodeWindow
->MoveBy(xDelta
, yDelta
);
720 //! Toggle group playback
722 RouteWindow::_toggleGroupRolling()
724 if (!m_selectedGroupID
)
728 status_t err
= m_routingView
->manager
->findGroup(m_selectedGroupID
, &g
);
733 uint32 startAction
= (g
->runMode() == BMediaNode::B_OFFLINE
)
734 ? NodeGroup::M_ROLL
: NodeGroup::M_START
;
737 switch (g
->transportState()) {
738 case NodeGroup::TRANSPORT_STOPPED
:
739 m
.SendMessage(startAction
);
742 case NodeGroup::TRANSPORT_RUNNING
:
743 case NodeGroup::TRANSPORT_ROLLING
:
744 m
.SendMessage(NodeGroup::M_STOP
);