xref: /haiku/src/apps/patchbay/PatchRow.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
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