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

motionfeedback.cc

/*
    Copyright (C) 1998-99 Paul Barton-Davis
    This program 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.

    This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA.

    $Id: motionfeedback.cc,v 1.5 2004/03/01 03:44:19 pauld Exp $
*/

#include <cmath>
#include <unistd.h>
#include <stdio.h> /* for snprintf, grrr */

#include <gdk/gdkkeysyms.h>
#include <gtk--.h>
#include <gtkmmext/pix.h>
#include <gtkmmext/shaped_window.h>
#include <gtkmmext/motionfeedback.h>

using namespace Gtkmmext;

MotionFeedback::MotionFeedback (Pix *pixset, 
                        const char *widget_name, 
                        Gtk::Adjustment *adj,
                        bool with_numeric_display) :
        pixwin (pixset)

{
      char value_name[1024];

      set_homogeneous (false);

      max_pixmap = pixset->max_pixmap ();

      value = NULL;

      if (adj == NULL) {
          i_own_my_adjustment = true;
          set_adjustment (new Gtk::Adjustment (0, 0, 10000, 1, 10, 0));
      } else {
          i_own_my_adjustment = false;
          set_adjustment (adj);
      }

      set_spacing (3);
      pack_start (pixwin, false, true);

      current_step = adjustment->gtkobj()->value;
      current_pix_index = value_to_pix_index (current_step);

      pixwin.set_current_pix (current_pix_index);
      pixwin.show ();

      if (with_numeric_display) {

            value = new Gtk::SpinButton (*adjustment);

            if (step_inc < 1) {
                  value->set_digits (abs ((int) ceil (log10 (step_inc))));
            }
            
            pack_start (*value, false, false);

            if (widget_name) {
                  snprintf (value_name, sizeof(value_name), "%sValue", widget_name);
                  value->set_name (value_name);
            }

            value->show ();
      }

      adjustment->value_changed.connect(SigC::slot(this,&MotionFeedback::adjustment_changed));

      pixwin.set_events (GDK_BUTTON_PRESS_MASK|
                     GDK_BUTTON_RELEASE_MASK|
                     GDK_POINTER_MOTION_MASK|
                     GDK_ENTER_NOTIFY_MASK|
                     GDK_LEAVE_NOTIFY_MASK|
                     GDK_KEY_PRESS_MASK|
                     GDK_KEY_RELEASE_MASK);

      pixwin.set_flags (GTK_CAN_FOCUS);

      /* Proxy all important events on the pixwin to ourselves */

      pixwin.button_press_event.connect(SigC::slot(this,&MotionFeedback::pixwin_button_press_event));
      pixwin.button_release_event.connect(SigC::slot(this,&MotionFeedback::pixwin_button_release_event));
      pixwin.motion_notify_event.connect(SigC::slot(this,&MotionFeedback::pixwin_motion_notify_event));
      pixwin.enter_notify_event.connect(SigC::slot(this,&MotionFeedback::pixwin_enter_notify_event));
      pixwin.leave_notify_event.connect(SigC::slot(this,&MotionFeedback::pixwin_leave_notify_event));
      pixwin.key_press_event.connect(SigC::slot(this,&MotionFeedback::pixwin_key_press_event));
}

MotionFeedback::~MotionFeedback()

{
      if (i_own_my_adjustment) {
            delete adjustment;
      }
      delete value;
}

void
MotionFeedback::set_adjustment (Gtk::Adjustment *adj)

{
      adjustment = adj;

      if (value) {
            value->set_adjustment (*adj);
      }

      _lower = adj->gtkobj()->lower;
      _upper = adj->gtkobj()->upper;
      _range = _upper - _lower;
      step_inc = adj->gtkobj()->step_increment;
      page_inc = adj->gtkobj()->page_increment;
}

gint 
MotionFeedback::pixwin_button_press_event (GdkEventButton *ev) 
{ 
      switch (ev->button) {
      case 2:
            return FALSE;  /* XXX why ? */

      case 1:
            grab_is_fine = false;
            break;
      case 3:
            grab_is_fine = true;
            break;
      }

      gtk_grab_add(GTK_WIDGET(pixwin.gtkobj()));
      grabbed_y = ev->y_root;
      grabbed_x = ev->x_root;

      /* XXX should we return TRUE ? */

      return FALSE;
}

gint 
MotionFeedback::pixwin_button_release_event (GdkEventButton *ev) 
{ 
      switch (ev->button) {
      case 1:
            if (pixwin.has_grab()) {
                  if (!grab_is_fine) {
                        gtk_grab_remove
                              (GTK_WIDGET(pixwin.gtkobj()));
                  }
            }
            break;
            
      case 3:
            if (pixwin.has_grab()) {
                  if (grab_is_fine) {
                        gtk_grab_remove
                              (GTK_WIDGET(pixwin.gtkobj()));
                  }
            }
            break;
      }

      return Gtk::VBox::button_release_event_impl(ev); 
}

gint 
MotionFeedback::pixwin_motion_notify_event (GdkEventMotion *ev) 
{ 
      gfloat multiplier;
      gfloat x_delta;
      gfloat y_delta;

      if(!pixwin.has_grab()) return Gtk::VBox::motion_notify_event_impl(ev); 

      multiplier = (ev->state & GDK_SHIFT_MASK ? 100 : 1) *
          (ev->state & GDK_CONTROL_MASK ? 10 : 1) * 
          (ev->state & GDK_MOD1_MASK ? 2 : 1);

      y_delta = grabbed_y - ev->y_root;
      grabbed_y = ev->y_root;

      x_delta = ev->x_root - grabbed_x;

      if (y_delta == 0) return TRUE;

      y_delta *= 1 + (x_delta/100);
      y_delta *= multiplier;
      y_delta /= 10;

      adjustment->set_value (adjustment->get_value() + 
                         ((grab_is_fine ? step_inc : page_inc) * y_delta));

      return TRUE;
}

gint 
MotionFeedback::pixwin_enter_notify_event (GdkEventCrossing *ev) 

{
      pixwin.grab_focus();
      return FALSE;
}

gint 
MotionFeedback::pixwin_leave_notify_event (GdkEventCrossing *ev) 

{
      pixwin.unset_flags (GTK_HAS_FOCUS);
      return FALSE;
}

gint 
MotionFeedback::pixwin_key_press_event (GdkEventKey *ev) 

{
        gint retval = FALSE;
      gfloat curval;
      gfloat multiplier;

      multiplier = (ev->state & GDK_SHIFT_MASK ? 100 : 1) *
          (ev->state & GDK_CONTROL_MASK ? 10 : 1) * 
          (ev->state & GDK_MOD1_MASK ? 2 : 1);

      switch (ev->keyval) {
      case GDK_Page_Up:
              retval = TRUE;
            curval = adjustment->get_value();
            adjustment->set_value (curval + (multiplier * page_inc));
            break;

      case GDK_Page_Down:
              retval = TRUE;
            curval = adjustment->get_value();
            adjustment->set_value (curval - (multiplier * page_inc));
            break;

      case GDK_Up:
              retval = TRUE;
            curval = adjustment->get_value();
            adjustment->set_value (curval + (multiplier * step_inc));
            break;

      case GDK_Down:
              retval = TRUE;
            curval = adjustment->get_value();
            adjustment->set_value (curval - (multiplier * step_inc));
            break;

      case GDK_Home:
              retval = TRUE;
            adjustment->set_value (_lower);
            break;

      case GDK_End:
              retval = TRUE;
            adjustment->set_value (_upper);
            break;
      }
      
      if (retval) {
            gtk_signal_emit_stop_by_name (GTK_OBJECT(pixwin.gtkobj()),
                                    "key_press_event");
      }

      return retval;
}

void
MotionFeedback::adjustment_changed ()

{
      pixwin.set_current_pix (value_to_pix_index (adjustment->get_value()));
}

int
MotionFeedback::value_to_pix_index (gfloat value)

{
      current_step = fabs (_lower + value);
      return (int) floor ((current_step/_range) * max_pixmap);
}


Generated by  Doxygen 1.6.0   Back to index