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 25 extern const float ROW_LEFT = 50.0f; 26 extern const float ROW_TOP = 50.0f; 27 extern const float ROW_HEIGHT = 40.0f; 28 extern const float COLUMN_WIDTH = 40.0f; 29 extern const float METER_PADDING = 15.0f; 30 extern const uint32 MSG_CONNECT_REQUEST = 'mCRQ'; 31 32 static const BPoint kBoxOffset(8, 7); 33 34 // PatchCheckBox is the check box that describes a connection 35 // between a producer and a consumer. 36 class PatchCheckBox : public BCheckBox 37 { 38 public: 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 57 private: 58 int32 fProducerID; 59 int32 fConsumerID; 60 }; 61 62 63 PatchRow::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 74 PatchRow::~PatchRow() 75 { 76 delete fEventMeter; 77 } 78 79 80 int32 81 PatchRow::ID() const 82 { 83 return fProducerID; 84 } 85 86 87 void 88 PatchRow::Pulse() 89 { 90 if (fEventMeter != NULL) 91 fEventMeter->Pulse(this); 92 } 93 94 95 void 96 PatchRow::Draw(BRect) 97 { 98 if (fEventMeter != NULL) 99 fEventMeter->Draw(this); 100 } 101 102 103 void 104 PatchRow::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 119 void 120 PatchRow::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 139 void 140 PatchRow::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 151 void 152 PatchRow::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 163 void 164 PatchRow::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 177 void 178 PatchRow::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 198 void 199 PatchCheckBox::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