btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / cortex / TransportView / TransportView.cpp
blob925cec47ab0350b6cba9d33c9a38d5aee2048d6c
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions, and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 // TransportView.cpp
34 #include "TransportView.h"
36 #include "RouteApp.h"
37 #include "RouteWindow.h"
39 #include "RouteAppNodeManager.h"
40 #include "NodeGroup.h"
42 #include "NumericValControl.h"
43 #include "TextControlFloater.h"
45 #include <Button.h>
46 #include <Debug.h>
47 #include <Font.h>
48 #include <Invoker.h>
49 #include <StringView.h>
50 #include <MediaRoster.h>
51 #include <MenuField.h>
52 #include <MenuItem.h>
53 #include <PopUpMenu.h>
54 #include <String.h>
55 #include <TextControl.h>
57 #include <algorithm>
58 #include <functional>
60 using namespace std;
62 __USE_CORTEX_NAMESPACE
64 // -------------------------------------------------------- //
65 // _GroupInfoView
66 // -------------------------------------------------------- //
68 __BEGIN_CORTEX_NAMESPACE
69 class _GroupInfoView :
70 public BView {
71 typedef BView _inherited;
73 public: // ctor/dtor
74 _GroupInfoView(
75 BRect frame,
76 TransportView* parent,
77 const char* name,
78 uint32 resizeMode =B_FOLLOW_LEFT|B_FOLLOW_TOP,
79 uint32 flags =B_WILL_DRAW|B_FRAME_EVENTS) :
81 BView(frame, name, resizeMode, flags),
82 m_parent(parent),
83 m_plainFont(be_plain_font),
84 m_boldFont(be_bold_font) {
86 _initViews();
87 _initColors();
88 _updateLayout();
91 public: // BView
92 virtual void FrameResized(
93 float width,
94 float height) {
96 _inherited::FrameResized(width, height);
97 _updateLayout();
98 Invalidate();
101 virtual void GetPreferredSize(
102 float* width,
103 float* height) {
104 font_height fh;
105 m_plainFont.GetHeight(&fh);
107 *width = 0.0;
108 *height = (fh.ascent+fh.descent+fh.leading) * 2;
109 *height += 4.0; //+++++
113 virtual void Draw(
114 BRect updateRect) {
116 NodeGroup* g = m_parent->m_group;
117 BRect b = Bounds();
119 // border
120 rgb_color hi = tint_color(ViewColor(), B_LIGHTEN_2_TINT);
121 rgb_color lo = tint_color(ViewColor(), B_DARKEN_2_TINT);
122 SetHighColor(lo);
123 StrokeLine(
124 b.LeftTop(), b.RightTop());
125 StrokeLine(
126 b.LeftTop(), b.LeftBottom());
128 SetHighColor(hi);
129 StrokeLine(
130 b.LeftBottom(), b.RightBottom());
131 StrokeLine(
132 b.RightTop(), b.RightBottom());
134 SetHighColor(255,255,255,255);
136 // background +++++
138 // name
139 BString name = g ? g->name() : "(no group)";
140 // +++++ constrain width
141 SetFont(&m_boldFont);
142 DrawString(name.String(), m_namePosition);
144 SetFont(&m_plainFont);
146 // node count
147 BString nodeCount;
148 if(g)
149 nodeCount << g->countNodes();
150 else
151 nodeCount << '0';
152 nodeCount << ((nodeCount == "1") ? " node." : " nodes.");
153 // +++++ constrain width
154 DrawString(nodeCount.String(), m_nodeCountPosition);
156 // status
157 BString status = "No errors.";
158 // +++++ constrain width
159 DrawString(status.String(), m_statusPosition);
162 virtual void MouseDown(
163 BPoint point) {
165 NodeGroup* g = m_parent->m_group;
166 if(!g)
167 return;
169 font_height fh;
170 m_boldFont.GetHeight(&fh);
172 BRect nameBounds(
173 m_namePosition.x,
174 m_namePosition.y - fh.ascent,
175 m_namePosition.x + m_maxNameWidth,
176 m_namePosition.y + (fh.ascent+fh.leading-4.0));
177 if(nameBounds.Contains(point)) {
178 ConvertToScreen(&nameBounds);
179 nameBounds.OffsetBy(-7.0, -3.0);
180 new TextControlFloater(
181 nameBounds,
182 B_ALIGN_LEFT,
183 &m_boldFont,
184 g->name(),
185 m_parent,
186 new BMessage(TransportView::M_SET_NAME));
190 public: // implementation
191 void _initViews() {
192 // +++++
195 void _initColors() {
196 // +++++ these colors need to be centrally defined
197 SetViewColor(16, 64, 96, 255);
198 SetLowColor(16, 64, 96, 255);
199 SetHighColor(255,255,255,255);
202 void _updateLayout() {
203 float _edge_pad_x = 3.0;
204 float _edge_pad_y = 1.0;
206 BRect b = Bounds();
207 font_height fh;
208 m_plainFont.GetHeight(&fh);
210 float realWidth = b.Width() - (_edge_pad_x * 2);
212 m_maxNameWidth = realWidth * 0.7;
213 m_maxNodeCountWidth = realWidth - m_maxNameWidth;
214 m_namePosition.x = _edge_pad_x;
215 m_namePosition.y = _edge_pad_x + fh.ascent - 2.0;
216 m_nodeCountPosition = m_namePosition;
217 m_nodeCountPosition.x = m_maxNameWidth;
219 m_maxStatusWidth = realWidth;
220 m_statusPosition.x = _edge_pad_x;
221 m_statusPosition.y = b.Height() - (fh.descent + fh.leading + _edge_pad_y);
224 private:
225 TransportView* m_parent;
227 BFont m_plainFont;
228 BFont m_boldFont;
230 BPoint m_namePosition;
231 float m_maxNameWidth;
233 BPoint m_nodeCountPosition;
234 float m_maxNodeCountWidth;
236 BPoint m_statusPosition;
237 float m_maxStatusWidth;
239 __END_CORTEX_NAMESPACE
241 // -------------------------------------------------------- //
242 // *** ctors
243 // -------------------------------------------------------- //
245 TransportView::TransportView(
246 NodeManager* manager,
247 const char* name) :
249 BView(
250 BRect(),
251 name,
252 B_FOLLOW_ALL_SIDES,
253 B_WILL_DRAW|B_FRAME_EVENTS),
254 m_manager(manager),
255 m_group(0) {
257 // initialize
258 _initLayout();
259 _constructControls();
260 // _updateLayout(); deferred until AttachedToWindow(): 24aug99
261 _disableControls();
263 SetViewColor(
264 tint_color(
265 ui_color(B_PANEL_BACKGROUND_COLOR),
266 B_LIGHTEN_1_TINT));
269 // -------------------------------------------------------- //
270 // *** BView
271 // -------------------------------------------------------- //
273 void TransportView::AttachedToWindow() {
274 _inherited::AttachedToWindow();
276 // finish layout
277 _updateLayout();
279 // watch the node manager (for time-source create/delete notification)
280 RouteApp* app = dynamic_cast<RouteApp*>(be_app);
281 ASSERT(app);
282 add_observer(this, app->manager);
285 void TransportView::AllAttached() {
286 _inherited::AllAttached();
288 // set message targets for view-configuation controls
289 for(target_set::iterator it = m_localTargets.begin();
290 it != m_localTargets.end(); ++it) {
291 ASSERT(*it);
292 (*it)->SetTarget(this);
296 void TransportView::DetachedFromWindow() {
297 _inherited::DetachedFromWindow();
299 RouteApp* app = dynamic_cast<RouteApp*>(be_app);
300 ASSERT(app);
301 remove_observer(this, app->manager);
304 void TransportView::FrameResized(
305 float width,
306 float height) {
308 _inherited::FrameResized(width, height);
309 // _updateLayout();
312 void TransportView::KeyDown(
313 const char* bytes,
314 int32 count) {
316 switch(bytes[0]) {
317 case B_SPACE: {
318 RouteApp* app = dynamic_cast<RouteApp*>(be_app);
319 ASSERT(app);
320 BMessenger(app->routeWindow).SendMessage(
321 RouteWindow::M_TOGGLE_GROUP_ROLLING);
322 break;
325 default:
326 _inherited::KeyDown(bytes, count);
331 void TransportView::MouseDown(
332 BPoint where) {
334 MakeFocus(true);
338 // -------------------------------------------------------- //
339 // *** BHandler
340 // -------------------------------------------------------- //
342 void TransportView::MessageReceived(
343 BMessage* message) {
344 status_t err;
345 uint32 groupID;
347 // PRINT((
348 // "TransportView::MessageReceived()\n"));
349 // message->PrintToStream();
351 switch(message->what) {
353 case NodeGroup::M_RELEASED:
355 err = message->FindInt32("groupID", (int32*)&groupID);
356 if(err < B_OK) {
357 PRINT((
358 "* TransportView::MessageReceived(NodeGroup::M_RELEASED)\n"
359 " no groupID!\n"));
361 if(!m_group || groupID != m_group->id()) {
362 PRINT((
363 "* TransportView::MessageReceived(NodeGroup::M_RELEASED)\n"
364 " mismatched groupID.\n"));
365 break;
368 _releaseGroup();
370 // BMessage m(M_REMOVE_OBSERVER);
371 // m.AddMessenger("observer", BMessenger(this));
372 // message->SendReply(&m);
374 break;
376 case NodeGroup::M_OBSERVER_ADDED:
377 err = message->FindInt32("groupID", (int32*)&groupID);
378 if(err < B_OK) {
379 PRINT((
380 "* TransportView::MessageReceived(NodeGroup::M_OBSERVER_ADDED)\n"
381 " no groupID!\n"));
382 break;
384 if(!m_group || groupID != m_group->id()) {
385 PRINT((
386 "* TransportView::MessageReceived(NodeGroup::M_OBSERVER_ADDED)\n"
387 " mismatched groupID; ignoring.\n"));
388 break;
391 _enableControls();
392 break;
394 case NodeGroup::M_TRANSPORT_STATE_CHANGED:
395 uint32 groupID;
396 err = message->FindInt32("groupID", (int32*)&groupID);
397 if(err < B_OK) {
398 PRINT((
399 "* TransportView::MessageReceived(NodeGroup::M_TRANSPORT_STATE_CHANGED)\n"
400 " no groupID!\n"));
401 break;
403 if(!m_group || groupID != m_group->id()) {
404 PRINT((
405 "* TransportView::MessageReceived(NodeGroup::M_TRANSPORT_STATE_CHANGED)\n"
406 " mismatched groupID; ignoring.\n"));
407 break;
410 _updateTransportButtons();
411 break;
413 case NodeGroup::M_TIME_SOURCE_CHANGED:
414 //_updateTimeSource(); +++++ check group?
415 break;
417 case NodeGroup::M_RUN_MODE_CHANGED:
418 //_updateRunMode(); +++++ check group?
419 break;
421 // * CONTROL PROCESSING
423 case NodeGroup::M_SET_START_POSITION: {
425 if(!m_group)
426 break;
428 bigtime_t position = _scalePosition(
429 m_regionStartView->value());
430 message->AddInt64("position", position);
431 BMessenger(m_group).SendMessage(message);
433 // update start-button duty/label [e.moon 11oct99]
434 if(m_group->transportState() == NodeGroup::TRANSPORT_STOPPED)
435 _updateTransportButtons();
437 break;
440 case NodeGroup::M_SET_END_POSITION: {
442 if(!m_group)
443 break;
445 bigtime_t position = _scalePosition(
446 m_regionEndView->value());
447 message->AddInt64("position", position);
448 BMessenger(m_group).SendMessage(message);
450 // update start-button duty/label [e.moon 11oct99]
451 if(m_group->transportState() == NodeGroup::TRANSPORT_STOPPED)
452 _updateTransportButtons();
454 break;
457 case M_SET_NAME:
459 const char* name;
460 err = message->FindString("_value", &name);
461 if(err < B_OK) {
462 PRINT((
463 "! TransportView::MessageReceived(M_SET_NAME): no _value!\n"));
464 break;
466 if(m_group) {
467 m_group->setName(name);
468 m_infoView->Invalidate();
471 break;
473 case RouteAppNodeManager::M_TIME_SOURCE_CREATED:
474 _timeSourceCreated(message);
475 break;
477 case RouteAppNodeManager::M_TIME_SOURCE_DELETED:
478 _timeSourceDeleted(message);
479 break;
481 default:
482 _inherited::MessageReceived(message);
483 break;
487 // -------------------------------------------------------- //
488 // *** BHandler impl.
489 // -------------------------------------------------------- //
491 void TransportView::_handleSelectGroup(
492 BMessage* message) {
494 uint32 groupID;
495 status_t err = message->FindInt32("groupID", (int32*)&groupID);
496 if(err < B_OK) {
497 PRINT((
498 "* TransportView::_handleSelectGroup(): no groupID\n"));
499 return;
502 if(m_group && groupID != m_group->id())
503 _releaseGroup();
505 _selectGroup(groupID);
507 Invalidate();
510 // -------------------------------------------------------- //
511 // *** internal operations
512 // -------------------------------------------------------- //
514 // select the given group; initialize controls
515 // (if 0, gray out all controls)
516 void TransportView::_selectGroup(
517 uint32 groupID) {
518 status_t err;
520 if(m_group)
521 _releaseGroup();
523 if(!groupID) {
524 _disableControls();
525 return;
528 err = m_manager->findGroup(groupID, &m_group);
529 if(err < B_OK) {
530 PRINT((
531 "* TransportView::_selectGroup(%" B_PRId32 "): findGroup() failed:\n"
532 " %s\n",
533 groupID,
534 strerror(err)));
535 return;
538 _observeGroup();
541 void TransportView::_observeGroup() {
542 ASSERT(m_group);
544 add_observer(this, m_group);
547 void TransportView::_releaseGroup() {
548 ASSERT(m_group);
550 remove_observer(this, m_group);
551 m_group = 0;
553 // -------------------------------------------------------- //
554 // *** CONTROLS
555 // -------------------------------------------------------- //
557 const char _run_mode_strings[][20] = {
558 "Offline",
559 "Decrease precision",
560 "Increase latency",
561 "Drop data",
562 "Recording"
564 const int _run_modes = 5;
566 //const char _time_source_strings[][20] = {
567 // "DAC time source",
568 // "System clock"
569 //};
570 //const int _time_sources = 2;
572 const char* _region_start_label = "From:";
573 const char* _region_end_label = "To:";
575 void TransportView::_constructControls() {
577 BMessage* m;
579 // * create and populate, but don't position, the views:
581 // // create and populate, but don't position, the views:
582 // m_nameView = new BStringView(
583 // BRect(),
584 // "nameView",
585 // "Group Name",
586 // B_FOLLOW_NONE);
587 // AddChild(m_nameView);
589 m_infoView = new _GroupInfoView(
590 BRect(),
591 this,
592 "infoView");
593 AddChild(m_infoView);
595 m_runModeView = new BMenuField(
596 BRect(),
597 "runModeView",
598 "Run mode:",
599 new BPopUpMenu("runModeMenu"));
600 _populateRunModeMenu(
601 m_runModeView->Menu());
602 AddChild(m_runModeView);
604 m_timeSourceView = new BMenuField(
605 BRect(),
606 "timeSourceView",
607 "Time source:",
608 new BPopUpMenu("timeSourceMenu"));
609 _populateTimeSourceMenu(
610 m_timeSourceView->Menu());
611 AddChild(m_timeSourceView);
614 m_fromLabel = new BStringView(BRect(), 0, "Roll from");
615 AddChild(m_fromLabel);
618 m = new BMessage(NodeGroup::M_SET_START_POSITION);
619 m_regionStartView = new NumericValControl(
620 BRect(),
621 "regionStartView",
623 2, 4, // * DIGITS
624 false, ValControl::ALIGN_FLUSH_LEFT);
626 // redirect view back to self. this gives me the chance to
627 // augment the message with the position before sending
628 _addLocalTarget(m_regionStartView);
629 AddChild(m_regionStartView);
631 m_toLabel = new BStringView(BRect(), 0, "to");
632 AddChild(m_toLabel);
634 m = new BMessage(NodeGroup::M_SET_END_POSITION);
635 m_regionEndView = new NumericValControl(
636 BRect(),
637 "regionEndView",
639 2, 4, // * DIGITS
640 false, ValControl::ALIGN_FLUSH_LEFT);
642 // redirect view back to self. this gives me the chance to
643 // augment the message with the position before sending
644 _addLocalTarget(m_regionEndView);
645 AddChild(m_regionEndView);
647 // m = new BMessage(NodeGroup::M_SET_START_POSITION);
648 // m_regionStartView = new BTextControl(
649 // BRect(),
650 // "regionStartView",
651 // _region_start_label,
652 // "0",
653 // m);
655 // _addGroupTarget(m_regionStartView);
656 //// m_regionStartView->TextView()->SetAlignment(B_ALIGN_RIGHT);
658 // AddChild(m_regionStartView);
660 // m = new BMessage(NodeGroup::M_SET_END_POSITION);
661 // m_regionEndView = new BTextControl(
662 // BRect(),
663 // "regionEndView",
664 // _region_end_label,
665 // "0",
666 // m);
668 // _addGroupTarget(m_regionEndView);
669 //// m_regionEndView->TextView()->SetAlignment(B_ALIGN_RIGHT);
670 // AddChild(m_regionEndView);
672 m = new BMessage(NodeGroup::M_START);
673 m_startButton = new BButton(
674 BRect(),
675 "startButton",
676 "Start",
678 _addGroupTarget(m_startButton);
679 AddChild(m_startButton);
681 m = new BMessage(NodeGroup::M_STOP);
682 m_stopButton = new BButton(
683 BRect(),
684 "stopButton",
685 "Stop",
687 _addGroupTarget(m_stopButton);
688 AddChild(m_stopButton);
690 m = new BMessage(NodeGroup::M_PREROLL);
691 m_prerollButton = new BButton(
692 BRect(),
693 "prerollButton",
694 "Preroll",
696 _addGroupTarget(m_prerollButton);
697 AddChild(m_prerollButton);
700 // convert a position control's value to bigtime_t
701 // [e.moon 11oct99]
702 bigtime_t TransportView::_scalePosition(
703 double value) {
705 return bigtime_t(value * 1000000.0);
708 void TransportView::_populateRunModeMenu(
709 BMenu* menu) {
711 BMessage* m;
712 for(int n = 0; n < _run_modes; ++n) {
713 m = new BMessage(NodeGroup::M_SET_RUN_MODE);
714 m->AddInt32("runMode", n+1);
716 BMenuItem* i = new BMenuItem(
717 _run_mode_strings[n], m);
718 menu->AddItem(i);
719 _addGroupTarget(i);
723 void TransportView::_populateTimeSourceMenu(
724 BMenu* menu) {
726 // find the standard time sources
727 status_t err;
728 media_node dacTimeSource, systemTimeSource;
729 BMessage* m;
730 BMenuItem* i;
731 err = m_manager->roster->GetTimeSource(&dacTimeSource);
732 if(err == B_OK) {
733 m = new BMessage(NodeGroup::M_SET_TIME_SOURCE);
734 m->AddData(
735 "timeSourceNode",
736 B_RAW_TYPE,
737 &dacTimeSource,
738 sizeof(media_node));
739 i = new BMenuItem(
740 "DAC time source",
742 menu->AddItem(i);
743 _addGroupTarget(i);
746 err = m_manager->roster->GetSystemTimeSource(&systemTimeSource);
747 if(err == B_OK) {
748 m = new BMessage(NodeGroup::M_SET_TIME_SOURCE);
749 m->AddData(
750 "timeSourceNode",
751 B_RAW_TYPE,
752 &systemTimeSource,
753 sizeof(media_node));
754 i = new BMenuItem(
755 "System clock",
757 menu->AddItem(i);
758 _addGroupTarget(i);
761 // find other time source nodes
763 Autolock _l(m_manager);
764 void* cookie = 0;
765 NodeRef* r;
766 char nameBuffer[B_MEDIA_NAME_LENGTH+16];
767 bool needSeparator = (menu->CountItems() > 0);
768 while(m_manager->getNextRef(&r, &cookie) == B_OK) {
769 if(!(r->kind() & B_TIME_SOURCE))
770 continue;
771 if(r->id() == dacTimeSource.node)
772 continue;
773 if(r->id() == systemTimeSource.node)
774 continue;
776 if(needSeparator) {
777 needSeparator = false;
778 menu->AddItem(new BSeparatorItem());
781 m = new BMessage(NodeGroup::M_SET_TIME_SOURCE);
782 m->AddData(
783 "timeSourceNode",
784 B_RAW_TYPE,
785 &r->node(),
786 sizeof(media_node));
787 sprintf(nameBuffer, "%s: %" B_PRId32,
788 r->name(),
789 r->id());
790 i = new BMenuItem(
791 nameBuffer,
793 menu->AddItem(i);
794 _addGroupTarget(i);
797 // BMessage* m;
798 // for(int n = 0; n < _time_sources; ++n) {
799 // m = new BMessage(NodeGroup::M_SET_TIME_SOURCE);
800 // m->AddData(
801 // "timeSourceNode",
802 // B_RAW_TYPE,
803 // &m_timeSourcePresets[n],
804 // sizeof(media_node));
805 // // +++++ copy media_node of associated time source!
806 //// m->AddInt32("timeSource", n);
808 // BMenuItem* i = new BMenuItem(
809 // _time_source_strings[n], m);
810 // menu->AddItem(i);
811 // _addGroupTarget(i);
812 // }
815 // add the given invoker to be retargeted to this
816 // view (used for controls whose messages need a bit more
817 // processing before being forwarded to the NodeManager.)
819 void TransportView::_addLocalTarget(
820 BInvoker* invoker) {
822 m_localTargets.push_back(invoker);
823 if(Window())
824 invoker->SetTarget(this);
827 void TransportView::_addGroupTarget(
828 BInvoker* invoker) {
830 m_groupTargets.push_back(invoker);
831 if(m_group)
832 invoker->SetTarget(m_group);
835 void TransportView::_refreshTransportSettings() {
836 if(m_group)
837 _updateTransportButtons();
841 void TransportView::_disableControls() {
843 // PRINT((
844 // "*** _disableControls()\n"));
846 BWindow* w = Window();
847 if(w)
848 w->BeginViewTransaction();
850 // m_nameView->SetText("(no group)");
851 m_infoView->Invalidate();
853 m_runModeView->SetEnabled(false);
854 m_runModeView->Menu()->Superitem()->SetLabel("(none)");
856 m_timeSourceView->SetEnabled(false);
857 m_timeSourceView->Menu()->Superitem()->SetLabel("(none)");
859 m_regionStartView->SetEnabled(false);
860 m_regionStartView->setValue(0);
862 m_regionEndView->SetEnabled(false);
863 m_regionEndView->setValue(0);
865 m_startButton->SetEnabled(false);
866 m_stopButton->SetEnabled(false);
867 m_prerollButton->SetEnabled(false);
869 if(w)
870 w->EndViewTransaction();
873 // PRINT((
874 // "*** DONE: _disableControls()\n"));
877 void TransportView::_enableControls() {
879 // PRINT((
880 // "*** _enableControls()\n"));
882 ASSERT(m_group);
883 Autolock _l(m_group); // +++++ why?
884 BWindow* w = Window();
885 if(w) {
886 w->BeginViewTransaction();
888 // clear focused view
889 // 19sep99: TransportWindow is currently a B_AVOID_FOCUS window; the
890 // only way views get focused is if they ask to be (which ValControl
891 // currently does.)
892 BView* focused = w->CurrentFocus();
893 if(focused)
894 focused->MakeFocus(false);
897 // BString nameViewText = m_group->name();
898 // nameViewText << ": " << m_group->countNodes() << " nodes.";
899 // m_nameView->SetText(nameViewText.String());
901 m_infoView->Invalidate();
903 m_runModeView->SetEnabled(true);
904 _updateRunMode();
906 m_timeSourceView->SetEnabled(true);
907 _updateTimeSource();
909 _updateTransportButtons();
912 // +++++ ick. hard-coded scaling factors make me queasy
914 m_regionStartView->SetEnabled(true);
915 m_regionStartView->setValue(
916 ((double)m_group->startPosition()) / 1000000.0);
918 m_regionEndView->SetEnabled(true);
919 m_regionEndView->setValue(
920 ((double)m_group->endPosition()) / 1000000.0);
922 // target controls on group
923 for(target_set::iterator it = m_groupTargets.begin();
924 it != m_groupTargets.end(); ++it) {
925 ASSERT(*it);
926 (*it)->SetTarget(m_group);
929 if(w) {
930 w->EndViewTransaction();
933 // PRINT((
934 // "*** DONE: _enableControls()\n"));
937 void TransportView::_updateTransportButtons() {
939 ASSERT(m_group);
941 switch(m_group->transportState()) {
942 case NodeGroup::TRANSPORT_INVALID:
943 case NodeGroup::TRANSPORT_STARTING:
944 case NodeGroup::TRANSPORT_STOPPING:
945 m_startButton->SetEnabled(false);
946 m_stopButton->SetEnabled(false);
947 m_prerollButton->SetEnabled(false);
948 break;
950 case NodeGroup::TRANSPORT_STOPPED:
951 m_startButton->SetEnabled(true);
952 m_stopButton->SetEnabled(false);
953 m_prerollButton->SetEnabled(true);
954 break;
956 case NodeGroup::TRANSPORT_RUNNING:
957 case NodeGroup::TRANSPORT_ROLLING:
958 m_startButton->SetEnabled(false);
959 m_stopButton->SetEnabled(true);
960 m_prerollButton->SetEnabled(false);
961 break;
964 // based on group settings, set the start button to do either
965 // a simple start or a roll (atomic start/stop.) [e.moon 11oct99]
966 ASSERT(m_startButton->Message());
968 // get current region settings
969 bigtime_t startPosition = _scalePosition(m_regionStartView->value());
970 bigtime_t endPosition = _scalePosition(m_regionEndView->value());
972 // get current run-mode setting
973 uint32 runMode = 0;
974 BMenuItem* i = m_runModeView->Menu()->FindMarked();
975 ASSERT(i);
976 runMode = m_runModeView->Menu()->IndexOf(i) + 1;
979 endPosition > startPosition &&
980 (runMode == BMediaNode::B_OFFLINE ||
981 !m_group->canCycle())) {
983 m_startButton->SetLabel("Roll");
984 m_startButton->Message()->what = NodeGroup::M_ROLL;
986 } else {
987 m_startButton->SetLabel("Start");
988 m_startButton->Message()->what = NodeGroup::M_START;
992 void TransportView::_updateTimeSource() {
993 ASSERT(m_group);
995 media_node tsNode;
996 status_t err = m_group->getTimeSource(&tsNode);
997 if(err < B_OK) {
998 PRINT((
999 "! TransportView::_updateTimeSource(): m_group->getTimeSource():\n"
1000 " %s\n",
1001 strerror(err)));
1002 return;
1005 BMenu* menu = m_timeSourceView->Menu();
1006 ASSERT(menu);
1007 if(tsNode == media_node::null) {
1008 menu->Superitem()->SetLabel("(none)");
1009 return;
1012 // find menu item
1013 int32 n;
1014 for(n = menu->CountItems()-1; n >= 0; --n) {
1015 const void* data;
1016 media_node itemNode;
1017 BMessage* message = menu->ItemAt(n)->Message();
1018 if(!message)
1019 continue;
1021 ssize_t size = sizeof(media_node);
1022 err = message->FindData(
1023 "timeSourceNode",
1024 B_RAW_TYPE,
1025 &data,
1026 &size);
1027 if(err < B_OK)
1028 continue;
1030 memcpy(&itemNode, data, sizeof(media_node));
1031 if(itemNode != tsNode)
1032 continue;
1034 // found it
1035 PRINT((
1036 "### _updateTimeSource: %s\n",
1037 menu->ItemAt(n)->Label()));
1038 menu->ItemAt(n)->SetMarked(true);
1039 break;
1041 // ASSERT(m_timeSourcePresets);
1042 // int n;
1043 // for(n = 0; n < _time_sources; ++n) {
1044 // if(m_timeSourcePresets[n] == tsNode) {
1045 // BMenuItem* i = m_timeSourceView->Menu()->ItemAt(n);
1046 // ASSERT(i);
1047 // i->SetMarked(true);
1048 // break;
1049 // }
1050 // }
1051 if(n < 0)
1052 menu->Superitem()->SetLabel("(???)");
1055 void TransportView::_updateRunMode() {
1056 ASSERT(m_group);
1058 BMenu* menu = m_runModeView->Menu();
1059 uint32 runMode = m_group->runMode() - 1; // real run mode starts at 1
1060 ASSERT((uint32)menu->CountItems() > runMode);
1061 menu->ItemAt(runMode)->SetMarked(true);
1064 //void TransportView::_initTimeSources() {
1066 // status_t err;
1067 // media_node node;
1068 // err = m_manager->roster->GetTimeSource(&node);
1069 // if(err == B_OK) {
1070 // m_timeSources.push_back(node.node);
1071 // }
1073 // err = m_manager->roster->GetSystemTimeSource(&m_timeSourcePresets[1]);
1074 // if(err < B_OK) {
1075 // PRINT((
1076 // "* TransportView::_initTimeSources():\n"
1077 // " GetSystemTimeSource() failed: %s\n", strerror(err)));
1078 // }
1081 // [e.moon 2dec99]
1082 void TransportView::_timeSourceCreated(
1083 BMessage* message) {
1085 status_t err;
1086 media_node_id id;
1087 err = message->FindInt32("nodeID", &id);
1088 if(err < B_OK)
1089 return;
1091 // PRINT(("### _timeSourceCreated(): %" B_PRId32 "\n", id));
1092 NodeRef* ref;
1093 err = m_manager->getNodeRef(id, &ref);
1094 if(err < B_OK) {
1095 PRINT((
1096 "!!! TransportView::_timeSourceCreated(): node %" B_PRId32 " doesn't exist\n",
1097 id));
1098 return;
1101 char nameBuffer[B_MEDIA_NAME_LENGTH+16];
1102 BMessage* m = new BMessage(NodeGroup::M_SET_TIME_SOURCE);
1103 m->AddData(
1104 "timeSourceNode",
1105 B_RAW_TYPE,
1106 &ref->node(),
1107 sizeof(media_node));
1108 sprintf(nameBuffer, "%s: %" B_PRId32,
1109 ref->name(),
1110 ref->id());
1111 BMenuItem* i = new BMenuItem(
1112 nameBuffer,
1114 BMenu* menu = m_timeSourceView->Menu();
1115 menu->AddItem(i);
1116 _addGroupTarget(i);
1119 // +++++
1120 void TransportView::_timeSourceDeleted(
1121 BMessage* message) {
1123 status_t err;
1124 media_node_id id;
1125 err = message->FindInt32("nodeID", &id);
1126 if(err < B_OK)
1127 return;
1129 // PRINT(("### _timeSourceDeleted(): %" B_PRId32 "\n", id));
1131 BMenu* menu = m_timeSourceView->Menu();
1132 ASSERT(menu);
1134 // find menu item
1135 int32 n;
1136 for(n = menu->CountItems()-1; n >= 0; --n) {
1137 const void* data;
1138 media_node itemNode;
1139 BMessage* message = menu->ItemAt(n)->Message();
1140 if(!message)
1141 continue;
1143 ssize_t size = sizeof(media_node);
1144 err = message->FindData(
1145 "timeSourceNode",
1146 B_RAW_TYPE,
1147 &data,
1148 &size);
1149 if(err < B_OK)
1150 continue;
1152 memcpy(&itemNode, data, sizeof(media_node));
1153 if(itemNode.node != id)
1154 continue;
1156 // found it; remove the item
1157 menu->RemoveItem(n);
1158 break;
1162 // -------------------------------------------------------- //
1163 // *** LAYOUT ***
1164 // -------------------------------------------------------- //
1166 const float _edge_pad_x = 3.0;
1167 const float _edge_pad_y = 3.0;
1169 const float _column_pad_x = 4.0;
1171 const float _field_pad_x = 20.0;
1173 const float _text_view_pad_x = 10.0;
1175 const float _control_pad_x = 5.0;
1176 const float _control_pad_y = 10.0;
1177 const float _menu_field_pad_x = 30.0;
1179 const float _label_pad_x = 8.0;
1181 const float _transport_pad_y = 4.0;
1182 const float _transport_button_width = 60.0;
1183 const float _transport_button_height = 22.0;
1184 const float _transport_button_pad_x = 4.0;
1186 const float _lock_button_width = 42.0;
1187 const float _lock_button_height = 16.0;
1189 class TransportView::_layout_state {
1190 public:
1191 _layout_state() {}
1193 // +++++
1196 inline float _menu_width(
1197 const BMenu* menu,
1198 const BFont* font) {
1200 float max = 0.0;
1202 int total = menu->CountItems();
1203 for(int n = 0; n < total; ++n) {
1204 float w = font->StringWidth(
1205 menu->ItemAt(n)->Label());
1206 if(w > max)
1207 max = w;
1210 return max;
1213 // -------------------------------------------------------- //
1215 void TransportView::_initLayout() {
1216 m_layout = new _layout_state();
1220 void TransportView::_updateLayout() // +++++
1222 BWindow* window = Window();
1223 if(window)
1224 window->BeginViewTransaction();
1226 // calculate the ideal size of the view
1227 // * max label width
1228 float maxLabelWidth = 0.0;
1229 float w;
1231 maxLabelWidth = be_bold_font->StringWidth(
1232 m_runModeView->Label());
1234 w = be_bold_font->StringWidth(
1235 m_timeSourceView->Label());
1236 if(w > maxLabelWidth)
1237 maxLabelWidth = w;
1239 // w = be_bold_font->StringWidth(
1240 // m_regionStartView->Label());
1241 // if(w > maxLabelWidth)
1242 // maxLabelWidth = w;
1244 // w = be_bold_font->StringWidth(
1245 // m_regionEndView->Label());
1246 // if(w > maxLabelWidth)
1247 // maxLabelWidth = w;
1249 // * max field width
1250 float maxFieldWidth = 0.0;
1251 maxFieldWidth = _menu_width(
1252 m_runModeView->Menu(), be_plain_font);
1254 w = _menu_width(
1255 m_timeSourceView->Menu(), be_plain_font);
1256 if(w > maxFieldWidth)
1257 maxFieldWidth = w;
1259 // * column width
1260 float columnWidth =
1261 maxLabelWidth +
1262 maxFieldWidth + _label_pad_x + _field_pad_x;
1264 // figure columns
1265 float column1_x = _edge_pad_x;
1266 float column2_x = column1_x + columnWidth + _column_pad_x;
1268 // * sum to figure view width
1269 float viewWidth =
1270 column2_x + columnWidth + _edge_pad_x;
1272 // make room for buttons
1273 float buttonSpan =
1274 (_transport_button_width*3) +
1275 (_transport_button_pad_x*2);
1276 if(columnWidth < buttonSpan)
1277 viewWidth += (buttonSpan - columnWidth);
1279 // float insideWidth = viewWidth - (_edge_pad_x*2);
1281 // * figure view height a row at a time
1282 font_height fh;
1283 be_plain_font->GetHeight(&fh);
1284 float lineHeight = fh.ascent + fh.descent + fh.leading;
1286 float prefInfoWidth, prefInfoHeight;
1287 m_infoView->GetPreferredSize(&prefInfoWidth, &prefInfoHeight);
1288 float row_1_height = max(prefInfoHeight, _transport_button_height);
1290 float row1_y = _edge_pad_y;
1291 float row2_y = row1_y + row_1_height + _transport_pad_y;
1292 float row3_y = row2_y + lineHeight + _control_pad_y;
1293 // float row4_y = row3_y + lineHeight + _control_pad_y + _transport_pad_y;
1294 // float row5_y = row4_y + lineHeight + _control_pad_y;
1295 float viewHeight = row3_y + lineHeight + _control_pad_y + _edge_pad_y;
1297 // Place controls
1298 m_infoView->MoveTo(
1299 column1_x+1.0, row1_y+1.0);
1300 m_infoView->ResizeTo(
1301 columnWidth, prefInfoHeight);
1303 BRect br(
1304 column2_x, row1_y,
1305 column2_x+_transport_button_width,
1306 row1_y+_transport_button_height);
1307 if(prefInfoHeight > _transport_button_height)
1308 br.OffsetBy(0.0, (prefInfoHeight - _transport_button_height)/2);
1310 m_startButton->MoveTo(br.LeftTop());
1311 m_startButton->ResizeTo(br.Width(), br.Height());
1312 br.OffsetBy(_transport_button_width + _transport_button_pad_x, 0.0);
1314 m_stopButton->MoveTo(br.LeftTop());
1315 m_stopButton->ResizeTo(br.Width(), br.Height());
1316 br.OffsetBy(_transport_button_width + _transport_button_pad_x, 0.0);
1318 m_prerollButton->MoveTo(br.LeftTop());
1319 m_prerollButton->ResizeTo(br.Width(), br.Height());
1321 m_runModeView->MoveTo(
1322 column2_x, row2_y);
1323 m_runModeView->ResizeTo(
1324 columnWidth, lineHeight);
1325 m_runModeView->SetDivider(
1326 maxLabelWidth+_label_pad_x);
1327 m_runModeView->SetAlignment(
1328 B_ALIGN_LEFT);
1330 m_timeSourceView->MoveTo(
1331 column2_x, row3_y);
1332 m_timeSourceView->ResizeTo(
1333 columnWidth, lineHeight);
1334 m_timeSourceView->SetDivider(
1335 maxLabelWidth+_label_pad_x);
1336 m_timeSourceView->SetAlignment(
1337 B_ALIGN_LEFT);
1339 // float regionControlWidth = columnWidth;
1340 // float regionControlHeight = lineHeight + 4.0;
1342 // m_regionStartView->TextView()->SetResizingMode(
1343 // B_FOLLOW_LEFT_RIGHT|B_FOLLOW_TOP);
1345 // "FROM"
1347 BPoint rtLeftTop(column1_x, row2_y + 5.0);
1348 BPoint rtRightBottom;
1350 m_fromLabel->MoveTo(rtLeftTop);
1351 m_fromLabel->ResizeToPreferred();
1352 rtRightBottom = rtLeftTop + BPoint(
1353 m_fromLabel->Bounds().Width(),
1354 m_fromLabel->Bounds().Height());
1357 // (region-start)
1359 rtLeftTop.x = rtRightBottom.x+4;
1361 m_regionStartView->MoveTo(rtLeftTop + BPoint(0.0, 2.0));
1362 m_regionStartView->ResizeToPreferred();
1363 rtRightBottom = rtLeftTop + BPoint(
1364 m_regionStartView->Bounds().Width(),
1365 m_regionStartView->Bounds().Height());
1367 // m_regionStartView->SetDivider(
1368 // maxLabelWidth);
1369 // m_regionStartView->TextView()->ResizeTo(
1370 // regionControlWidth-(maxLabelWidth+_text_view_pad_x),
1371 // regionControlHeight-4.0);
1373 // "TO"
1375 rtLeftTop.x = rtRightBottom.x + 6;
1377 m_toLabel->MoveTo(rtLeftTop);
1378 m_toLabel->ResizeToPreferred();
1379 rtRightBottom = rtLeftTop + BPoint(
1380 m_toLabel->Bounds().Width(),
1381 m_toLabel->Bounds().Height());
1383 // (region-end)
1385 rtLeftTop.x = rtRightBottom.x + 4;
1387 m_regionEndView->MoveTo(rtLeftTop + BPoint(0.0, 2.0));
1388 m_regionEndView->ResizeToPreferred();
1389 // m_regionEndView->SetDivider(
1390 // maxLabelWidth);
1391 // m_regionEndView->TextView()->ResizeTo(
1392 // regionControlWidth-(maxLabelWidth+_text_view_pad_x),
1393 // regionControlHeight-4.0);
1396 BRect b = Bounds();
1397 float targetWidth = (b.Width() < viewWidth) ?
1398 viewWidth :
1399 b.Width();
1400 float targetHeight = (b.Height() < viewHeight) ?
1401 viewHeight :
1402 b.Height();
1404 // Resize view to fit contents
1405 ResizeTo(targetWidth, targetHeight);
1407 if(window) {
1408 window->ResizeTo(targetWidth, targetHeight);
1411 // // +++++ testing NumericValControl [23aug99]
1412 // float valWidth, valHeight;
1413 // m_valView->GetPreferredSize(&valWidth, &valHeight);
1414 // PRINT((
1415 // "\n\nm_valView preferred size: %.1f x %.1f\n\n",
1416 // valWidth, valHeight));
1418 if(window)
1419 window->EndViewTransaction();
1422 // -------------------------------------------------------- //
1423 // *** dtor
1424 // -------------------------------------------------------- //
1426 TransportView::~TransportView() {
1427 if(m_group)
1428 _releaseGroup();
1429 if(m_layout)
1430 delete m_layout;
1434 // END -- TransportView.cpp --