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

pixscroller.cc

/*
    Copyright (C) 2005 Paul 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: pixscroller.cc,v 1.5 2005/09/23 13:19:15 sampo Exp $
*/
#include <iostream>
#include <algorithm>
#include <cmath>

#include <gtk--/style.h>
#include <gtkmmext/pixscroller.h>

using namespace std;
using namespace Gtk;
using namespace Gtkmmext;

PixScroller::PixScroller (Adjustment& a, Pix& pix)
      : adj (a)
{
      dragging = false;
      add_events (GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|GDK_POINTER_MOTION_MASK);

      adj.value_changed.connect (slot (*this, &PixScroller::adjustment_changed));
      default_value = adj.get_value();

      pix.generate (0, 0);

      rail = pix.pixmap (0);
      rail_mask = pix.shape_mask (0);
      slider = pix.pixmap (1);
      slider_mask = pix.shape_mask (1);

      gint w, h;

      gdk_window_get_size (slider, &w, &h);
      sliderrect.width = w;
      sliderrect.height = h;
      gdk_window_get_size (rail, &w, &h);
      railrect.width = w;
      railrect.height = h;

      railrect.y = sliderrect.height / 2;
      sliderrect.x = 0;

      overall_height = railrect.height + sliderrect.height;

      sliderrect.y = (int) rint ((overall_height - sliderrect.height) * (adj.get_upper() - adj.get_value()));
      railrect.x = (sliderrect.width / 2) - 2;
}

void
PixScroller::size_request_impl (GtkRequisition* requisition)
{
      requisition->width = sliderrect.width;
      requisition->height = overall_height;
}

gint
PixScroller::expose_event_impl (GdkEventExpose* ev)
{
      GdkRectangle intersect;
      Gdk_Window win (get_window());

      win.draw_rectangle (get_style()->get_bg_gc(get_state()), TRUE, 
                      ev->area.x,
                      ev->area.y,
                      ev->area.width,
                      ev->area.height);

      if (gdk_rectangle_intersect (&railrect, &ev->area, &intersect)) {
            Gdk_GC gc = get_style()->get_bg_gc(get_state());
            win.draw_pixmap (gc, Gdk_Pixmap (rail), 
                         intersect.x - railrect.x,
                         intersect.y - railrect.y,
                         intersect.x, 
                         intersect.y, 
                         intersect.width,
                         intersect.height);
      }
      
      if (gdk_rectangle_intersect (&sliderrect, &ev->area, &intersect)) {
            Gdk_GC gc = get_style()->get_fg_gc(get_state());
            Gdk_Bitmap mask (slider_mask);
            GdkGCValues values;

            gc.get_values (values);

            gc.set_clip_origin (sliderrect.x, sliderrect.y);
            gc.set_clip_mask (mask);
            win.draw_pixmap (gc, Gdk_Pixmap (slider), 
                         intersect.x - sliderrect.x,
                         intersect.y - sliderrect.y,
                         intersect.x, 
                         intersect.y, 
                         intersect.width,
                         intersect.height);

            gc.set_clip_origin (values.clip_x_origin, values.clip_y_origin);
            Gdk_Bitmap i_hate_gdk (values.clip_mask);
            gc.set_clip_mask (i_hate_gdk);
      }
      
      return TRUE;
}

gint
PixScroller::button_press_event_impl (GdkEventButton* ev)
{
      switch (ev->button) {
      case 1:
            if (!(ev->state & GDK_SHIFT_MASK)) {
                  Gtk::Main::grab_add (*this);
                  grab_y = ev->y;
                  grab_start = ev->y;
                  grab_window = ev->window;
                  dragging = true;
            }
            break;
      default:
            break;
      } 
                         

      return FALSE;
}

gint
PixScroller::button_release_event_impl (GdkEventButton* ev)
{
      double scale;
      
      if (ev->state & GDK_CONTROL_MASK) {
            if (ev->state & GDK_MOD1_MASK) {
                  scale = 0.05;
            } else {
                  scale = 0.1;
            }
      } else {
            scale = 1.0;
      }

      switch (ev->button) {
      case 1:
            if (dragging) {
                  Gtk::Main::grab_remove (*this);
                  dragging = false;

                  if (ev->y == grab_start) {
                        /* no motion - just a click */
                        double fract;

                        if (ev->y < sliderrect.height/2) {
                              /* near the top */
                              fract = 1.0;
                        } else {
                              fract = 1.0 - (ev->y - sliderrect.height/2) / railrect.height;
                        }

                        fract = min (1.0, fract);
                        fract = max (0.0, fract);

                        adj.set_value (scale * fract * (adj.get_upper() - adj.get_lower()));
                  }
                        
            } else { 
                  if (ev->state & GDK_SHIFT_MASK) {
                        adj.set_value (default_value);
                        cerr << "default value = " << default_value << endl;
                  }
            }
            break;
      case 4:
            /* wheel up */
            adj.set_value (adj.get_value() + (adj.get_page_increment() * scale));
            break;
      case 5:
            /* wheel down */
            adj.set_value (adj.get_value() - (adj.get_page_increment() * scale));
            break;
      default:
            break;
      }
      return FALSE;
}

gint
PixScroller::motion_notify_event_impl (GdkEventMotion* ev)
{
      if (dragging) {
            double fract;
            double delta;
            double scale;

            if (ev->window != grab_window) {
                  grab_y = ev->y;
                  grab_window = ev->window;
                  return TRUE;
            }
            
            if (ev->state & GDK_CONTROL_MASK) {
                  if (ev->state & GDK_MOD1_MASK) {
                        scale = 0.05;
                  } else {
                        scale = 0.1;
                  }
            } else {
                  scale = 1.0;
            }

            delta = ev->y - grab_y;
            grab_y = ev->y;

            fract = (delta / railrect.height);

            fract = min (1.0, fract);
            fract = max (-1.0, fract);
            
            fract = -fract;

            adj.set_value (adj.get_value() + scale * fract * (adj.get_upper() - adj.get_lower()));
      }

      return TRUE;
}

void
PixScroller::adjustment_changed ()
{
      int y = (int) rint ((overall_height - sliderrect.height) * (adj.get_upper() - adj.get_value()));

      if (y != sliderrect.y) {
            sliderrect.y = y;
            queue_draw ();
      }
}

Generated by  Doxygen 1.6.0   Back to index