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