libroot/posix/stdio: Remove unused portions.
[haiku.git] / src / apps / patchbay / PatchView.cpp
blobcf0f036ca91daa5890e1da9c867a88a57bde3d2e
1 /* PatchView.cpp
2 * -------------
3 * Implements the main PatchBay view class.
5 * Copyright 2013, Haiku, Inc. All rights reserved.
6 * Distributed under the terms of the MIT License.
8 * Revisions by Pete Goodeve
10 * Copyright 1999, Be Incorporated. All Rights Reserved.
11 * This file may be used under the terms of the Be Sample Code License.
14 #include "PatchView.h"
16 #include <Application.h>
17 #include <Bitmap.h>
18 #include <Catalog.h>
19 #include <Debug.h>
20 #include <IconUtils.h>
21 #include <InterfaceDefs.h>
22 #include <Message.h>
23 #include <Messenger.h>
24 #include <MidiRoster.h>
25 #include <Window.h>
27 #include "EndpointInfo.h"
28 #include "PatchRow.h"
29 #include "UnknownDeviceIcons.h"
32 #define B_TRANSLATION_CONTEXT "Patch Bay"
35 PatchView::PatchView(BRect rect)
37 BView(rect, "PatchView", B_FOLLOW_ALL, B_WILL_DRAW),
38 fUnknownDeviceIcon(NULL)
40 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
42 BRect iconRect(0, 0, LARGE_ICON_SIZE - 1, LARGE_ICON_SIZE - 1);
43 fUnknownDeviceIcon = new BBitmap(iconRect, B_RGBA32);
44 if (BIconUtils::GetVectorIcon(
45 UnknownDevice::kVectorIcon,
46 sizeof(UnknownDevice::kVectorIcon),
47 fUnknownDeviceIcon) == B_OK)
48 return;
49 delete fUnknownDeviceIcon;
53 PatchView::~PatchView()
55 delete fUnknownDeviceIcon;
59 void
60 PatchView::AttachedToWindow()
62 BMidiRoster* roster = BMidiRoster::MidiRoster();
63 if (roster == NULL) {
64 PRINT(("Couldn't get MIDI roster\n"));
65 be_app->PostMessage(B_QUIT_REQUESTED);
66 return;
69 BMessenger msgr(this);
70 roster->StartWatching(&msgr);
71 SetHighUIColor(B_PANEL_TEXT_COLOR);
75 void
76 PatchView::MessageReceived(BMessage* msg)
78 switch (msg->what) {
79 case B_MIDI_EVENT:
80 HandleMidiEvent(msg);
81 break;
82 default:
83 BView::MessageReceived(msg);
84 break;
89 bool
90 PatchView::GetToolTipAt(BPoint point, BToolTip** tip)
92 bool found = false;
93 int32 index = 0;
94 endpoint_itor begin, end;
95 int32 size = fConsumers.size();
96 for (int32 i = 0; !found && i < size; i++) {
97 BRect r = ColumnIconFrameAt(i);
98 if (r.Contains(point)) {
99 begin = fConsumers.begin();
100 end = fConsumers.end();
101 found = true;
102 index = i;
105 size = fProducers.size();
106 for (int32 i = 0; !found && i < size; i++) {
107 BRect r = RowIconFrameAt(i);
108 if (r.Contains(point)) {
109 begin = fProducers.begin();
110 end = fProducers.end();
111 found = true;
112 index = i;
116 if (!found)
117 return false;
119 endpoint_itor itor;
120 for (itor = begin; itor != end; itor++, index--)
121 if (index <= 0)
122 break;
124 if (itor == end)
125 return false;
127 BMidiRoster* roster = BMidiRoster::MidiRoster();
128 if (roster == NULL)
129 return false;
130 BMidiEndpoint* obj = roster->FindEndpoint(itor->ID());
131 if (obj == NULL)
132 return false;
134 BString str;
135 str << "<" << obj->ID() << ">: " << obj->Name();
136 obj->Release();
138 SetToolTip(str.String());
140 *tip = ToolTip();
142 return true;
146 void
147 PatchView::Draw(BRect /* updateRect */)
149 // draw producer icons
150 SetDrawingMode(B_OP_OVER);
151 int32 index = 0;
152 for (list<EndpointInfo>::const_iterator i = fProducers.begin();
153 i != fProducers.end(); i++) {
154 const BBitmap* bitmap = (i->Icon()) ? i->Icon() : fUnknownDeviceIcon;
155 DrawBitmapAsync(bitmap, RowIconFrameAt(index++).LeftTop());
158 // draw consumer icons
159 int32 index2 = 0;
160 for (list<EndpointInfo>::const_iterator i = fConsumers.begin();
161 i != fConsumers.end(); i++) {
162 const BBitmap* bitmap = (i->Icon()) ? i->Icon() : fUnknownDeviceIcon;
163 DrawBitmapAsync(bitmap, ColumnIconFrameAt(index2++).LeftTop());
166 if (index == 0 && index2 == 0) {
167 const char* message = B_TRANSLATE("No MIDI devices found!");
168 float width = StringWidth(message);
169 BRect rect = Bounds();
171 rect.top = rect.top + rect.bottom / 2;
172 rect.left = rect.left + rect.right / 2;
173 rect.left -= width / 2;
175 DrawString(message, rect.LeftTop());
177 // Since the message is centered, we need to redraw the whole view in
178 // this case.
179 SetFlags(Flags() | B_FULL_UPDATE_ON_RESIZE);
180 } else
181 SetFlags(Flags() & ~B_FULL_UPDATE_ON_RESIZE);
185 BRect
186 PatchView::ColumnIconFrameAt(int32 index) const
188 BRect rect;
189 rect.left = ROW_LEFT + METER_PADDING + index * COLUMN_WIDTH;
190 rect.top = 10;
191 rect.right = rect.left + 31;
192 rect.bottom = rect.top + 31;
193 return rect;
197 BRect
198 PatchView::RowIconFrameAt(int32 index) const
200 BRect rect;
201 rect.left = 10;
202 rect.top = ROW_TOP + index * ROW_HEIGHT;
203 rect.right = rect.left + 31;
204 rect.bottom = rect.top + 31;
205 return rect;
209 void
210 PatchView::HandleMidiEvent(BMessage* msg)
212 SET_DEBUG_ENABLED(true);
214 int32 op;
215 if (msg->FindInt32("be:op", &op) != B_OK) {
216 PRINT(("PatchView::HandleMidiEvent: \"op\" field not found\n"));
217 return;
220 switch (op) {
221 case B_MIDI_REGISTERED:
223 int32 id;
224 if (msg->FindInt32("be:id", &id) != B_OK) {
225 PRINT(("PatchView::HandleMidiEvent: \"be:id\""
226 " field not found in B_MIDI_REGISTERED event\n"));
227 break;
230 const char* type;
231 if (msg->FindString("be:type", &type) != B_OK) {
232 PRINT(("PatchView::HandleMidiEvent: \"be:type\""
233 " field not found in B_MIDI_REGISTERED event\n"));
234 break;
237 PRINT(("MIDI Roster Event B_MIDI_REGISTERED: id=%" B_PRId32
238 ", type=%s\n", id, type));
239 if (strcmp(type, "producer") == 0)
240 AddProducer(id);
241 else if (strcmp(type, "consumer") == 0)
242 AddConsumer(id);
244 break;
245 case B_MIDI_UNREGISTERED:
247 int32 id;
248 if (msg->FindInt32("be:id", &id) != B_OK) {
249 PRINT(("PatchView::HandleMidiEvent: \"be:id\""
250 " field not found in B_MIDI_UNREGISTERED\n"));
251 break;
254 const char* type;
255 if (msg->FindString("be:type", &type) != B_OK) {
256 PRINT(("PatchView::HandleMidiEvent: \"be:type\""
257 " field not found in B_MIDI_UNREGISTERED\n"));
258 break;
261 PRINT(("MIDI Roster Event B_MIDI_UNREGISTERED: id=%" B_PRId32
262 ", type=%s\n", id, type));
263 if (strcmp(type, "producer") == 0)
264 RemoveProducer(id);
265 else if (strcmp(type, "consumer") == 0)
266 RemoveConsumer(id);
268 break;
269 case B_MIDI_CHANGED_PROPERTIES:
271 int32 id;
272 if (msg->FindInt32("be:id", &id) != B_OK) {
273 PRINT(("PatchView::HandleMidiEvent: \"be:id\""
274 " field not found in B_MIDI_CHANGED_PROPERTIES\n"));
275 break;
278 const char* type;
279 if (msg->FindString("be:type", &type) != B_OK) {
280 PRINT(("PatchView::HandleMidiEvent: \"be:type\""
281 " field not found in B_MIDI_CHANGED_PROPERTIES\n"));
282 break;
285 BMessage props;
286 if (msg->FindMessage("be:properties", &props) != B_OK) {
287 PRINT(("PatchView::HandleMidiEvent: \"be:properties\""
288 " field not found in B_MIDI_CHANGED_PROPERTIES\n"));
289 break;
292 PRINT(("MIDI Roster Event B_MIDI_CHANGED_PROPERTIES: id=%" B_PRId32
293 ", type=%s\n", id, type));
294 if (strcmp(type, "producer") == 0)
295 UpdateProducerProps(id, &props);
296 else if (strcmp(type, "consumer") == 0)
297 UpdateConsumerProps(id, &props);
300 break;
301 case B_MIDI_CHANGED_NAME:
302 case B_MIDI_CHANGED_LATENCY:
303 // we don't care about these
304 break;
305 case B_MIDI_CONNECTED:
307 int32 prod;
308 if (msg->FindInt32("be:producer", &prod) != B_OK) {
309 PRINT(("PatchView::HandleMidiEvent: \"be:producer\""
310 " field not found in B_MIDI_CONNECTED\n"));
311 break;
314 int32 cons;
315 if (msg->FindInt32("be:consumer", &cons) != B_OK) {
316 PRINT(("PatchView::HandleMidiEvent: \"be:consumer\""
317 " field not found in B_MIDI_CONNECTED\n"));
318 break;
320 PRINT(("MIDI Roster Event B_MIDI_CONNECTED: producer=%" B_PRId32
321 ", consumer=%" B_PRId32 "\n", prod, cons));
322 Connect(prod, cons);
324 break;
325 case B_MIDI_DISCONNECTED:
327 int32 prod;
328 if (msg->FindInt32("be:producer", &prod) != B_OK) {
329 PRINT(("PatchView::HandleMidiEvent: \"be:producer\""
330 " field not found in B_MIDI_DISCONNECTED\n"));
331 break;
334 int32 cons;
335 if (msg->FindInt32("be:consumer", &cons) != B_OK) {
336 PRINT(("PatchView::HandleMidiEvent: \"be:consumer\""
337 " field not found in B_MIDI_DISCONNECTED\n"));
338 break;
340 PRINT(("MIDI Roster Event B_MIDI_DISCONNECTED: producer=%" B_PRId32
341 ", consumer=%" B_PRId32 "\n", prod, cons));
342 Disconnect(prod, cons);
344 break;
345 default:
346 PRINT(("PatchView::HandleMidiEvent: unknown opcode %" B_PRId32 "\n",
347 op));
348 break;
353 void
354 PatchView::AddProducer(int32 id)
356 EndpointInfo info(id);
357 fProducers.push_back(info);
359 Window()->BeginViewTransaction();
360 PatchRow* row = new PatchRow(id);
361 fPatchRows.push_back(row);
362 BPoint p1 = CalcRowOrigin(fPatchRows.size() - 1);
363 BPoint p2 = CalcRowSize();
364 row->MoveTo(p1);
365 row->ResizeTo(p2.x, p2.y);
366 for (list<EndpointInfo>::const_iterator i = fConsumers.begin();
367 i != fConsumers.end(); i++)
368 row->AddColumn(i->ID());
369 AddChild(row);
370 Invalidate();
371 Window()->EndViewTransaction();
375 void
376 PatchView::AddConsumer(int32 id)
378 EndpointInfo info(id);
379 fConsumers.push_back(info);
381 Window()->BeginViewTransaction();
382 BPoint newSize = CalcRowSize();
383 for (row_itor i = fPatchRows.begin(); i != fPatchRows.end(); i++) {
384 (*i)->AddColumn(id);
385 (*i)->ResizeTo(newSize.x, newSize.y - 1);
387 Invalidate();
388 Window()->EndViewTransaction();
392 void
393 PatchView::RemoveProducer(int32 id)
395 for (endpoint_itor i = fProducers.begin(); i != fProducers.end(); i++) {
396 if (i->ID() == id) {
397 fProducers.erase(i);
398 break;
402 Window()->BeginViewTransaction();
403 for (row_itor i = fPatchRows.begin(); i != fPatchRows.end(); i++) {
404 if ((*i)->ID() == id) {
405 PatchRow* row = *i;
406 i = fPatchRows.erase(i);
407 RemoveChild(row);
408 delete row;
409 float moveBy = -1 * CalcRowSize().y;
410 while (i != fPatchRows.end()) {
411 (*i++)->MoveBy(0, moveBy);
413 break;
416 Invalidate();
417 Window()->EndViewTransaction();
421 void
422 PatchView::RemoveConsumer(int32 id)
424 Window()->BeginViewTransaction();
425 for (endpoint_itor i = fConsumers.begin(); i != fConsumers.end(); i++) {
426 if (i->ID() == id) {
427 fConsumers.erase(i);
428 break;
432 BPoint newSize = CalcRowSize();
433 for (row_itor i = fPatchRows.begin(); i != fPatchRows.end(); i++) {
434 (*i)->RemoveColumn(id);
435 (*i)->ResizeTo(newSize.x, newSize.y - 1);
437 Invalidate();
438 Window()->EndViewTransaction();
442 void
443 PatchView::UpdateProducerProps(int32 id, const BMessage* props)
445 for (endpoint_itor i = fProducers.begin(); i != fProducers.end(); i++) {
446 if (i->ID() == id) {
447 i->UpdateProperties(props);
448 Invalidate();
449 break;
455 void
456 PatchView::UpdateConsumerProps(int32 id, const BMessage* props)
458 for (endpoint_itor i = fConsumers.begin(); i != fConsumers.end(); i++) {
459 if (i->ID() == id) {
460 i->UpdateProperties(props);
461 Invalidate();
462 break;
468 void
469 PatchView::Connect(int32 prod, int32 cons)
471 for (row_itor i = fPatchRows.begin(); i != fPatchRows.end(); i++) {
472 if ((*i)->ID() == prod) {
473 (*i)->Connect(cons);
474 break;
480 void
481 PatchView::Disconnect(int32 prod, int32 cons)
483 for (row_itor i = fPatchRows.begin(); i != fPatchRows.end(); i++) {
484 if ((*i)->ID() == prod) {
485 (*i)->Disconnect(cons);
486 break;
492 BPoint
493 PatchView::CalcRowOrigin(int32 rowIndex) const
495 BPoint point;
496 point.x = ROW_LEFT;
497 point.y = ROW_TOP + rowIndex * ROW_HEIGHT;
498 return point;
502 BPoint
503 PatchView::CalcRowSize() const
505 BPoint point;
506 point.x = METER_PADDING + fConsumers.size()*COLUMN_WIDTH;
507 point.y = ROW_HEIGHT - 1;
508 return point;