#include #include #include #include "jack.h" #include "portmanager.h" #include "gui.h" const Rect Rect::None = Rect(0, 0, -1, -1); Matrix::Matrix() : m_client_width(0), m_client_height(0), m_port_width(0), m_port_height(0), m_separation(0), m_padding(3), m_font_size(10), m_typeface("Liberation Sans Bold") { set_size_request(0, 0); show(); add_events(Gdk::BUTTON_PRESS_MASK); } Matrix::~Matrix() { } void Matrix::Refresh() { Glib::RefPtr window = get_window(); if (!window) return; m_client_width = 0; m_client_height = 0; m_port_width = 0; m_port_height = 0; m_separation = 0; pm.Sort(); int cols = 0; int rows = 0; Cairo::RefPtr cr = window->create_cairo_context(); cr->select_font_face(m_typeface, Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL); cr->set_font_size(m_font_size); PortList::iterator plit; for (plit = pm.m_ports.begin(); plit != pm.m_ports.end(); ++plit) { Port *p = *plit; p->rect = Rect::None; } ClientList::iterator clit; for (clit = pm.m_clients.begin(); clit != pm.m_clients.end(); ++clit) { Client *c = *clit; cr->get_text_extents(c->m_name, c->extents); int width = c->extents.width + m_padding * 2; if (c->m_is_input) { if (width > m_client_height) m_client_height = width; } else { if (width > m_client_width) m_client_width = width; } if (c->extents.height > m_separation) m_separation = c->extents.height; if (!c->m_expanded) { if (c->m_is_input) { cols++; } else { rows++; } PortGroupList::iterator pglit; for (pglit = c->m_groups.begin(); pglit != c->m_groups.end(); ++pglit) { PortGroup *pg = *pglit; pg->rect = Rect::None; } continue; } PortGroupList::iterator pglit; for (pglit = c->m_groups.begin(); pglit != c->m_groups.end(); ++pglit) { PortGroup *pg = *pglit; cr->get_text_extents(pg->m_name, pg->extents); if (pg->extents.height > m_separation) m_separation = pg->extents.height; if (!pg->m_expanded && pg->m_name != "") { int width = pg->extents.width + m_padding * 2; if (c->m_is_input) { if (width > m_port_height) m_port_height = width; cols++; } else { if (width > m_port_width) m_port_width = width; rows++; } continue; } PortList::iterator plit; for (plit = pg->m_ports.begin(); plit != pg->m_ports.end(); ++plit) { Port *p = *plit; cr->get_text_extents(p->m_name, p->extents); int width = pg->extents.width + p->extents.width + m_padding * (pg->extents.width > 0 ? 4 : 2); if (p->m_flags & JackPortIsInput) { if (width > m_port_height) m_port_height = width; cols++; } else { if (width > m_port_width) m_port_width = width; rows++; } if (p->extents.height > m_separation) m_separation = p->extents.height; } } } /* PortList::iterator plit; for (plit = pm.m_ports.begin(); plit != pm.m_ports.end(); ++plit) { Port *p = *plit; cr->get_text_extents(p->m_name, p->extents); if (p->m_flags & JackPortIsInput) { if (p->extents.width > m_port_height) m_port_height = p->extents.width; } else { if (p->extents.width > m_port_width) m_port_width = p->extents.width; } if (p->extents.height > m_separation) m_separation = p->extents.height; } */ m_separation += m_padding * 2; // if (m_port_width > m_separation * 5) m_port_width = m_separation * 5; // if (m_port_height > m_separation * 5) m_port_height = m_separation * 5; int y = m_client_height + m_port_height + m_padding; int x = m_client_width + m_port_width + m_padding; across.clear(); down.clear(); Rect r; // ClientList::iterator clit; for (clit = pm.m_clients.begin(); clit != pm.m_clients.end(); ++clit) { Client *c = *clit; if (c->m_is_input) { r.left = x; r.top = m_padding; r.width = -1; r.height = m_client_height; c->rect = r; if (!c->m_expanded) { c->rect.width = m_separation; c->rect.height = m_client_height + m_port_height; across.push_back(c); x += m_separation; continue; } PortGroupList::iterator pglit; for (pglit = c->m_groups.begin(); pglit != c->m_groups.end(); ++pglit) { PortGroup *pg = *pglit; if (pg->m_name != "") { r.left = x; r.top = m_padding + m_client_height; r.width = pg->m_expanded ? m_separation * pg->m_ports.size() : m_separation; r.height = pg->m_expanded ? pg->extents.width + m_padding * 2 : m_port_height; pg->rect = r; if (!pg->m_expanded) { c->rect.width = pg->rect.left - c->rect.left + m_separation; across.push_back(pg); x += m_separation; continue; } r.top += r.height; r.width = m_separation; r.height = m_port_height - r.height; } else { pg->rect = Rect::None; r.top = m_padding + m_client_height; r.width = m_separation; r.height = m_port_height; } PortList::iterator plit; for (plit = pg->m_ports.begin(); plit != pg->m_ports.end(); ++plit) { Port *p = *plit; r.left = x; p->rect = r; c->rect.width = p->rect.left - c->rect.left + m_separation; if (pg->rect != Rect::None) { pg->rect.width = p->rect.left - pg->rect.left + m_separation; } across.push_back(p); x += m_separation; } } } else { r.left = m_padding; r.top = y; r.width = m_client_width; r.height = -1; c->rect = r; if (!c->m_expanded) { c->rect.width = m_client_width + m_port_width; c->rect.height = m_separation; down.push_back(c); y += m_separation; continue; } PortGroupList::iterator pglit; for (pglit = c->m_groups.begin(); pglit != c->m_groups.end(); ++pglit) { PortGroup *pg = *pglit; if (pg->m_name != "") { r.left = m_padding + m_client_width; r.top = y; r.width = pg->m_expanded ? pg->extents.width + m_padding * 2 : m_port_width; r.height = pg->m_expanded ? m_separation * pg->m_ports.size() : m_separation; pg->rect = r; if (!pg->m_expanded) { c->rect.height = pg->rect.top - c->rect.top + m_separation; down.push_back(pg); y += m_separation; continue; } r.left += r.width; r.width = m_port_width - r.width; r.height = m_separation; } else { pg->rect = Rect::None; r.left = m_padding + m_client_width; r.width = m_port_width; r.height = m_separation; } PortList::iterator plit; for (plit = pg->m_ports.begin(); plit != pg->m_ports.end(); ++plit) { Port *p = *plit; r.top = y; p->rect = r; c->rect.height = p->rect.top - c->rect.top + m_separation; if (pg->rect != Rect::None) { pg->rect.height = p->rect.top - pg->rect.top + m_separation; } down.push_back(p); y += m_separation; } } } } int w = m_padding * 2 + m_client_width + m_port_width; int h = m_padding * 2 + m_client_height + m_port_height; w += cols * m_separation; h += rows * m_separation; m_width = w; m_height = h; set_size_request(w, h); parent->set_size_request(w + 20, h + 20); } void Matrix::Box(Cairo::RefPtr cr, float r, float g, float b, Rect &rect) { cr->set_source_rgb(r, g, b); cr->rectangle(rect.left, rect.top, rect.width, rect.height); cr->fill(); cr->set_source_rgb(0.75, 0.75, 0.75); cr->rectangle(rect.left, rect.top, rect.width, rect.height); cr->stroke(); cr->set_source_rgb(1, 1, 1); } bool Matrix::on_expose_event(GdkEventExpose *event) { Glib::RefPtr window = get_window(); if (!window) return true; if (m_client_width == 0) Refresh(); Gtk::Allocation allocation = get_allocation(); const int alloc_width = allocation.get_width(); const int alloc_height = allocation.get_height(); Cairo::RefPtr cr = window->create_cairo_context(); cr->set_line_width(1.0); cr->set_antialias(Cairo::ANTIALIAS_NONE); // Set clipping area cr->rectangle(event->area.x, event->area.y, event->area.width, event->area.height); cr->clip(); // Clear background cr->set_source_rgb(0.25, 0.25, 0.25); cr->rectangle(0, 0, alloc_width, alloc_height); cr->fill(); cr->set_source_rgb(1, 1, 1); cr->select_font_face(m_typeface, Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL); cr->set_font_size(m_font_size); Rect tr; Rect &r = tr; ClientList::iterator clit; for (clit = pm.m_clients.begin(); clit != pm.m_clients.end(); ++clit) { Client *c = *clit; r = c->rect; if (c->m_is_input) { Box(cr, BACK_COLOUR, r); cr->save(); cr->move_to(r.left + m_padding - c->extents.y_bearing, r.top + r.height - m_padding - c->extents.x_bearing); cr->rotate(2 * M_PI * 0.75); cr->show_text(c->m_name); cr->restore(); if (!c->m_expanded) { cr->set_source_rgb(GRID_CLIENT); cr->move_to(r.left + r.width, r.top + r.height); cr->line_to(r.left + r.width, m_height - m_padding); cr->stroke(); continue; } PortGroupList::iterator pglast = c->m_groups.end(); --pglast; PortGroupList::iterator pglit; for (pglit = c->m_groups.begin(); pglit != c->m_groups.end(); ++pglit) { PortGroup *pg = *pglit; r = pg->rect; if (pg->m_name != "") { Box(cr, GROUP_COLOUR, r); cr->save(); cr->move_to(r.left + m_padding - pg->extents.y_bearing, r.top + r.height - m_padding - pg->extents.x_bearing); cr->rotate(2 * M_PI * 0.75); cr->show_text(pg->m_name); cr->restore(); if (!pg->m_expanded) { if (pglit == pglast) { cr->set_source_rgb(GRID_CLIENT); } else { cr->set_source_rgb(GRID_GROUP); } cr->move_to(r.left + r.width, r.top + r.height); cr->line_to(r.left + r.width, m_height - m_padding); cr->stroke(); continue; } } PortList::iterator plast = pg->m_ports.end(); --plast; PortList::iterator plit; for (plit = pg->m_ports.begin(); plit != pg->m_ports.end(); ++plit) { Port *p = *plit; r = p->rect; if (p->m_is_midi) { Box(cr, MIDI_COLOUR, r); } else { Box(cr, AUDIO_COLOUR, r); } cr->save(); cr->move_to(r.left + m_padding - p->extents.y_bearing, r.top + r.height - m_padding - p->extents.x_bearing); cr->rotate(2 * M_PI * 0.75); cr->show_text(p->m_name); cr->restore(); if (pglit == pglast && plit == plast) { cr->set_source_rgb(GRID_CLIENT); } else if (plit == plast) { cr->set_source_rgb(GRID_GROUP); } else { cr->set_source_rgb(GRID_PORT); } cr->move_to(r.left + r.width, r.top + r.height); cr->line_to(r.left + r.width, m_height - m_padding); cr->stroke(); } } } else { Box(cr, BACK_COLOUR, r); cr->move_to(r.left + m_padding - c->extents.x_bearing, r.top + m_padding - c->extents.y_bearing); cr->show_text(c->m_name); if (!c->m_expanded) { cr->set_source_rgb(GRID_CLIENT); cr->move_to(r.left + r.width, r.top + r.height); cr->line_to(m_width - m_padding, r.top + r.height); cr->stroke(); continue; } PortGroupList::iterator pglast = c->m_groups.end(); --pglast; PortGroupList::iterator pglit; for (pglit = c->m_groups.begin(); pglit != c->m_groups.end(); ++pglit) { PortGroup *pg = *pglit; r = pg->rect; if (pg->m_name != "") { Box(cr, GROUP_COLOUR, r); cr->move_to(r.left + m_padding - pg->extents.x_bearing, r.top + m_padding - pg->extents.y_bearing); cr->show_text(pg->m_name); if (!pg->m_expanded) { if (pglit == pglast) { cr->set_source_rgb(GRID_CLIENT); } else { cr->set_source_rgb(GRID_GROUP); } cr->move_to(r.left + r.width, r.top + r.height); cr->line_to(m_width - m_padding, r.top + r.height); cr->stroke(); continue; } } PortList::iterator plast = pg->m_ports.end(); --plast; PortList::iterator plit; for (plit = pg->m_ports.begin(); plit != pg->m_ports.end(); ++plit) { Port *p = *plit; r = p->rect; if (p->m_is_midi) { Box(cr, MIDI_COLOUR, r); } else { Box(cr, AUDIO_COLOUR, r); } cr->move_to(r.left + m_padding - p->extents.x_bearing, r.top + m_padding - p->extents.y_bearing); cr->show_text(p->m_name); if (pglit == pglast && plit == plast) { cr->set_source_rgb(GRID_CLIENT); } else if (plit == plast) { cr->set_source_rgb(GRID_GROUP); } else { cr->set_source_rgb(GRID_PORT); } cr->move_to(r.left + r.width, r.top + r.height); cr->line_to(m_width - m_padding, r.top + r.height); cr->stroke(); } } } } int x = m_client_width + m_port_width + m_padding; BaseList::iterator bit1; for (bit1 = across.begin(); bit1 != across.end(); ++bit1) { BaseList::iterator bit2; Base *b1 = *bit1; int y = m_client_height + m_port_height + m_padding; for (bit2 = down.begin(); bit2 != down.end(); ++bit2) { Base *b2 = *bit2; ConnectionMode cm = b1->ConnectedTo(b2); if (cm != CM_NONE) { // if (p1->m_is_midi) { // cr->set_source_rgb(MIDI_COLOUR); // } else { cr->set_source_rgb(AUDIO_COLOUR); // } cr->rectangle(x + 1, y + 1, m_separation - 1, m_separation - 1); cr->fill(); } y += m_separation; } x += m_separation; } /* PortList::iterator plit1; for (plit1 = pm.m_ports.begin(); plit1 != pm.m_ports.end(); ++plit1) { Port *p1 = *plit1; if (p1->pos == 0) continue; PortList::iterator plit2; for (plit2 = p1->m_connections.begin(); plit2 != p1->m_connections.end(); ++plit2) { Port *p2 = *plit2; if (p2->pos == 0) continue; // cr->imove_to(p2->pos, p1->pos); // cr->arc(p1->pos, p2->pos, (m_separation - m_padding * 2) / 2.0, 0, 2 * M_PI); if (p1->m_is_midi) { cr->set_source_rgb(MIDI_COLOUR); } else { cr->set_source_rgb(AUDIO_COLOUR); } cr->rectangle(p1->pos + 1, p2->pos + 1, m_separation - 1, m_separation - 1); cr->fill(); } } */ return true; } bool Matrix::on_button_press_event(GdkEventButton *event) { // Check expandable boxes ClientList::iterator clit; for (clit = pm.m_clients.begin(); clit != pm.m_clients.end(); ++clit) { Client *c = *clit; if (c->rect.Hit(event->x, event->y)) { c->m_expanded = !c->m_expanded; Refresh(); queue_draw(); return true; } PortGroupList::iterator pglit; for (pglit = c->m_groups.begin(); pglit != c->m_groups.end(); ++pglit) { PortGroup *pg = *pglit; if (pg->rect.Hit(event->x, event->y)) { pg->m_expanded = !pg->m_expanded; Refresh(); queue_draw(); return true; } } } Port *p1 = NULL; Port *p2 = NULL; // Check port hit PortList::iterator plit; for (plit = pm.m_ports.begin(); plit != pm.m_ports.end(); ++plit) { Port *p = *plit; if (p->rect.HitX(event->x)) p1 = p; if (p->rect.HitY(event->y)) p2 = p; if (p1 != NULL && p2 != NULL) { pm.ToggleConnect(p1, p2); return true; } } PortGroup *pg1 = NULL; PortGroup *pg2 = NULL; for (clit = pm.m_clients.begin(); clit != pm.m_clients.end(); ++clit) { Client *c = *clit; PortGroupList::iterator pglit; for (pglit = c->m_groups.begin(); pglit != c->m_groups.end(); ++pglit) { PortGroup *pg = *pglit; if (pg->rect.HitX(event->x)) pg1 = pg; if (pg->rect.HitY(event->y)) pg2 = pg; if (p1 != NULL && pg2 != NULL) { pm.ToggleConnect(p1, pg2); return true; } if (pg1 != NULL && p2 != NULL) { pm.ToggleConnect(pg1, p2); return true; } if (pg1 != NULL && pg2 != NULL) { pm.ToggleConnect(pg1, pg2); return true; } } } std::cout << event->x << ", " << event->y << std::endl; return true; } Gui::Gui() { set_title("JACK Sweeper"); set_border_width(0); set_size_request(100, 100); add(m_box); m_scrolledwindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); m_scrolledwindow.set_border_width(0); m_scrolledwindow.add(m_matrix); m_matrix.parent = this; Refresh(); Glib::signal_idle().connect(sigc::mem_fun(*this, &Gui::on_idle)); m_actiongroup = Gtk::ActionGroup::create(); m_actiongroup->add(Gtk::Action::create("MenuFile", "_File")); m_actiongroup->add(Gtk::Action::create("Connect", "Connect")); m_actiongroup->add(Gtk::Action::create("Disconnect", "Disconnect")); m_actiongroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT)); m_uimanager = Gtk::UIManager::create(); m_uimanager->insert_action_group(m_actiongroup); add_accel_group(m_uimanager->get_accel_group()); std::string ui_info = "" " " " " " " " " " " " " " " " " ""; m_uimanager->add_ui_from_string(ui_info); Gtk::Widget *menubar = m_uimanager->get_widget("/MenuBar"); m_box.pack_start(*menubar, Gtk::PACK_SHRINK); m_box.pack_start(m_scrolledwindow); show_all_children(); } Gui::~Gui() { } void Gui::Refresh() { m_matrix.Refresh(); } bool Gui::on_idle() { if (jack.ProcessEvents()) { Refresh(); queue_draw(); } usleep(1000); return true; }