Logo Search packages:      
Sourcecode: patchage version File versions  Download package

Module.cpp

/* This file is part of Om.  Copyright (C) 2005 Dave Robillard.
 * 
 * Om is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 * 
 * Om is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#include "Module.h"
#include "PatchBayArea.h"
#include <functional>
#include <cstdlib>

using std::string;

namespace PatchBay {
      

Module::Module(PatchBayArea* patch_bay, const string& name, double x, double y)
: Gnome::Canvas::Group(*patch_bay->root(), x, y),
  m_name(name),
  m_patch_bay(patch_bay),
  m_module_box(*this, 0, 0, 0, 0), // w, h set later
  m_canvas_title(*this, 0, 6, name) // x set later
{
      m_module_box.property_fill_color_rgba() = 0x1F2A3CFF;

      m_module_box.property_outline_color_rgba() = 0x8899AAFF;
      m_module_box.property_join_style() = Gdk::JOIN_ROUND;
      m_module_box.property_width_units() = 1.0;

      m_canvas_title.property_size_set() = true;
      m_canvas_title.property_size() = 10000;
      m_canvas_title.property_weight_set() = true;
      m_canvas_title.property_weight() = 400;
      m_canvas_title.property_fill_color_rgba() = 0xDDEEFFFF;

      width(m_canvas_title.property_text_width() + 6.0);
      height(m_canvas_title.property_text_height() + 2.0);
      m_canvas_title.property_x() = m_width/2.0;

      signal_event().connect(sigc::mem_fun(this, &Module::module_event));
}


Module::~Module()
{
      for (PortList::iterator p = m_ports.begin(); p != m_ports.end(); ++p)
            delete (*p);
}


bool
Module::module_event(GdkEvent* event)
{
      static double x, y;
      double module_x, module_y;
      static bool dragging = false;
      bool handled = true;
      
      module_x = event->button.x;
      module_y = event->button.y;

      property_parent().get_value()->w2i(module_x, module_y);
      
      switch (event->type) {

      case GDK_2BUTTON_PRESS:
            on_double_click();
            handled = true;
            break;

      case GDK_BUTTON_PRESS:
            if (event->button.button == 1) {
                  x = module_x;
                  y = module_y;
                  grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK,
                             Gdk::Cursor(Gdk::FLEUR),
                             event->button.time);
                  dragging = true;
            } else if (event->button.button == 2) {
                  on_double_click();
                  handled = true;
            } else if (event->button.button == 3) {
                  show_menu(event);
            } else {
                  handled = false;
            }
            break;
      
      case GDK_MOTION_NOTIFY:
            if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
                  double new_x = module_x;
                  double new_y = module_y;

                  move(new_x - x, new_y - y);
                  x = new_x;
                  y = new_y;

                  // Deal with moving the connection lines
                  for (PortList::iterator p = ports().begin(); p != ports().end(); ++p)
                        (*p)->move_connections();
            } else {
                  handled = false;
            }
            break;

      case GDK_BUTTON_RELEASE:
            if (dragging) {
                  ungrab(event->button.time);
                  dragging = false;
                  store_location();
            } else {
                  handled = false;
            }
            break;

      case GDK_ENTER_NOTIFY:
            raise_to_top();
            for (PortList::iterator p = m_ports.begin(); p != m_ports.end(); ++p)
                  (*p)->raise_connections();

      default:
            handled = false;
      }

      return handled;
}


void
Module::zoom(float z)
{
      m_canvas_title.property_size() = static_cast<int>(10000.0f * z);
      for (PortList::iterator p = m_ports.begin(); p != m_ports.end(); ++p)
            (*p)->zoom(z);
}


void
Module::remove_port(const string& port_name, bool resize_to_fit)
{
      for (PortList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) {
            if ((*i)->name() == port_name) {
                  delete (*i);
                  i = m_ports.erase(i);
            }
      }

      if (resize_to_fit)
            resize();
}


void
Module::width(double w)
{
      m_width = w;
      m_module_box.property_x2() = m_module_box.property_x1() + w;
}


void
Module::height(double h)
{
      m_height = h;
      m_module_box.property_y2() = m_module_box.property_y1() + h;
}


void
Module::move_to(double x, double y)
{
      // Man, not many things left to try to get the damn things to move! :)
      property_x() = x;
      property_y() = y;
      move(0, 0);
      // Deal with moving the connection lines
      for (PortList::iterator p = ports().begin(); p != ports().end(); ++p)
            (*p)->move_connections();
}


void
Module::add_port(const string& port_name, bool is_input, int color, bool resize_to_fit)
{
      Port* port = new Port(this, port_name, is_input, color);

      port->signal_event().connect(
            sigc::bind<Port*>(sigc::mem_fun(m_patch_bay, &PatchBayArea::port_event), port));

      add_port(port, resize_to_fit);
}


void
Module::add_port(Port* port, bool resize_to_fit)
{
      m_ports.push_back(port);
      
      if (resize_to_fit)
            resize();
}


/** Resize the module to fit its contents best.
 */
void
00218 Module::resize()
{
      double widest_in = 0.0;
      double widest_out = 0.0;
      
      Port* p = NULL;
      
      // Find widest in/out ports
      for (PortList::iterator i = m_ports.begin(); i != m_ports.end(); ++i) {
            p = (*i);
            if (p->is_input() && p->width() > widest_in)
                  widest_in = p->width();
            else if (p->is_output() && p->width() > widest_out)
                  widest_out = p->width();
      }
      
      // Make sure module is wide enough for ports
      if (widest_in > widest_out)
            width(widest_in + 5.0);
      else
            width(widest_out + 5.0);
      
      // Make sure module is wide enough for title
      if (m_canvas_title.property_text_width() + 6.0 > m_width)
            width(m_canvas_title.property_text_width() + 6.0);

      // Set height to contain ports and title
      double height_base = m_canvas_title.property_text_height() + 2;
      double h = height_base;
      if (m_ports.size() > 0)
            h += m_ports.size() * ((*m_ports.begin())->height()+2.0);
      height(h);
      
      // Move ports to appropriate locations
      
      double y;
      int i = 0;
      for (PortList::iterator pi = m_ports.begin(); pi != m_ports.end(); ++pi, ++i) {
            Port* p = (*pi);

            y = height_base + (i * (p->height() + 2.0));
            if (p->is_input()) {
                  p->width(widest_in);
                  p->property_x() = 0.0;
                  p->property_y() = y;
            } else {
                  p->width(widest_out);
                  p->property_x() = m_width - p->width();
                  p->property_y() = y;
            }
      }
}


} // namespace PatchBay

Generated by  Doxygen 1.6.0   Back to index