1// PatchRow.cpp 2// ------------ 3// Implements the PatchRow class. 4// 5// Copyright 1999, Be Incorporated. All Rights Reserved. 6// This file may be used under the terms of the Be Sample Code License. 7 8#include <stdio.h> 9#include <CheckBox.h> 10#include <Debug.h> 11#include <MidiRoster.h> 12#include <MidiConsumer.h> 13#include <MidiProducer.h> 14#include <Window.h> 15#include "MidiEventMeter.h" 16#include "PatchRow.h" 17 18extern const float ROW_LEFT = 50.0f; 19extern const float ROW_TOP = 50.0f; 20extern const float ROW_HEIGHT = 40.0f; 21extern const float COLUMN_WIDTH = 40.0f; 22extern const float METER_PADDING = 15.0f; 23extern const uint32 MSG_CONNECT_REQUEST = 'mCRQ'; 24 25static const BPoint kBoxOffset(8,7); 26 27// PatchCheckBox is the check box that describes a connection 28// between a producer and a consumer. 29class PatchCheckBox : public BCheckBox 30{ 31public: 32 PatchCheckBox(BRect r, int32 producerID, int32 consumerID) 33 : BCheckBox(r, "", "", new BMessage(MSG_CONNECT_REQUEST)) 34 { 35 m_producerID = producerID; 36 m_consumerID = consumerID; 37 } 38 39 int32 ProducerID() const { return m_producerID; } 40 int32 ConsumerID() const { return m_consumerID; } 41 42 void DoConnect(); 43 44private: 45 int32 m_producerID; 46 int32 m_consumerID; 47}; 48 49PatchRow::PatchRow(int32 producerID) 50 : BView(BRect(0,0,0,0), "PatchRow", B_FOLLOW_NONE, 51 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_PULSE_NEEDED), 52 m_producerID(producerID), m_eventMeter(NULL) 53{ 54 m_eventMeter = new MidiEventMeter(m_producerID); 55} 56 57PatchRow::~PatchRow() 58{ 59 delete m_eventMeter; 60} 61 62int32 PatchRow::ID() const 63{ 64 return m_producerID; 65} 66 67void PatchRow::Pulse() 68{ 69 if (m_eventMeter) m_eventMeter->Pulse(this); 70} 71 72void PatchRow::Draw(BRect) 73{ 74 if (m_eventMeter) m_eventMeter->Draw(this); 75} 76 77void PatchRow::AddColumn(int32 consumerID) 78{ 79 BRect r; 80 int32 numColumns = CountChildren(); 81 r.left = numColumns*COLUMN_WIDTH + METER_PADDING + kBoxOffset.x; 82 r.top = kBoxOffset.y; 83 r.right = r.left + 20; 84 r.bottom = r.top + 20; 85 86 PatchCheckBox* box = new PatchCheckBox(r, m_producerID, consumerID); 87 AddChild(box); 88 box->SetTarget(this); 89} 90 91void PatchRow::RemoveColumn(int32 consumerID) 92{ 93 int32 numChildren = CountChildren(); 94 for (int32 i=0; i<numChildren; i++) { 95 PatchCheckBox* box = dynamic_cast<PatchCheckBox*>(ChildAt(i)); 96 if (box && box->ConsumerID() == consumerID) { 97 RemoveChild(box); 98 delete box; 99 while (i < numChildren) { 100 box = dynamic_cast<PatchCheckBox*>(ChildAt(i++)); 101 if (box) { 102 box->MoveBy(-COLUMN_WIDTH, 0); 103 } 104 } 105 break; 106 } 107 } 108} 109 110void PatchRow::Connect(int32 consumerID) 111{ 112 int32 numChildren = CountChildren(); 113 for (int32 i=0; i<numChildren; i++) { 114 PatchCheckBox* box = dynamic_cast<PatchCheckBox*>(ChildAt(i)); 115 if (box && box->ConsumerID() == consumerID) { 116 box->SetValue(1); 117 } 118 } 119} 120 121void PatchRow::Disconnect(int32 consumerID) 122{ 123 int32 numChildren = CountChildren(); 124 for (int32 i=0; i<numChildren; i++) { 125 PatchCheckBox* box = dynamic_cast<PatchCheckBox*>(ChildAt(i)); 126 if (box && box->ConsumerID() == consumerID) { 127 box->SetValue(0); 128 } 129 } 130} 131 132void PatchRow::AttachedToWindow() 133{ 134 Window()->SetPulseRate(200000); 135 SetViewColor(Parent()->ViewColor()); 136 int32 numChildren = CountChildren(); 137 for (int32 i=0; i<numChildren; i++) { 138 PatchCheckBox* box = dynamic_cast<PatchCheckBox*>(ChildAt(i)); 139 if (box) { 140 box->SetTarget(this); 141 } 142 } 143} 144 145void PatchRow::MessageReceived(BMessage* msg) 146{ 147 switch (msg->what) { 148 case MSG_CONNECT_REQUEST: 149 { 150 BControl* ctrl; 151 if (msg->FindPointer("source", (void**) &ctrl) == B_OK) { 152 PatchCheckBox* box = dynamic_cast<PatchCheckBox*>(ctrl); 153 if (box) { 154 box->DoConnect(); 155 } 156 } 157 } 158 break; 159 default: 160 BView::MessageReceived(msg); 161 break; 162 } 163} 164 165void PatchCheckBox::DoConnect() 166{ 167 int32 value = Value(); 168 int32 inverseValue = (value + 1) % 2; 169 170 BMidiRoster* roster = BMidiRoster::MidiRoster(); 171 if (! roster) { 172 SetValue(inverseValue); 173 return; 174 } 175 176 BMidiProducer* producer = roster->FindProducer(m_producerID); 177 BMidiConsumer* consumer = roster->FindConsumer(m_consumerID); 178 if (producer && consumer) { 179 status_t err; 180 if (value) { 181 err = producer->Connect(consumer); 182 } else { 183 err = producer->Disconnect(consumer); 184 } 185 186 if (err != B_OK) { 187 SetValue(inverseValue); 188 } 189 } else { 190 SetValue(inverseValue); 191 } 192 if (producer) producer->Release(); 193 if (consumer) consumer->Release(); 194} 195