Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gimpnavigationview.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * GimpNavigationView Widget
 * Copyright (C) 2001-2002 Michael Natterer <mitch@gimp.org>
 *
 * partly based on app/nav_window
 * Copyright (C) 1999 Andy Thomas <alt@gimp.org>
 *
 * 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 3 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, see <https://www.gnu.org/licenses/>.
 */


#include "config.h"

#include <math.h>

#include <gegl.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

#include "libgimpmath/gimpmath.h"

#include "widgets-types.h"

#include "core/gimpimage.h"
#include "core/gimpmarshal.h"

#include "display/gimpcanvas-style.h"

#include "gimpnavigationview.h"
#include "gimpviewrenderer.h"
#include "gimpwidgets-utils.h"


#define BORDER_WIDTH 2


enum
{
  MARKER_CHANGED,
  ZOOM,
  SCROLL,
  LAST_SIGNAL
};


struct _GimpNavigationView
{
  GimpView     parent_instance;

  /*  values in image coordinates  */
  gdouble      center_x;
  gdouble      center_y;
  gdouble      width;
  gdouble      height;
  gboolean     flip_horizontally;
  gboolean     flip_vertically;
  gdouble      rotate_angle;

  gboolean     canvas_visible;
  gdouble      canvas_x;
  gdouble      canvas_y;
  gdouble      canvas_width;
  gdouble      canvas_height;

  /*  values in view coordinates  */
  gint         p_center_x;
  gint         p_center_y;
  gint         p_width;
  gint         p_height;

  gint         p_canvas_x;
  gint         p_canvas_y;
  gint         p_canvas_width;
  gint         p_canvas_height;

  gint         motion_offset_x;
  gint         motion_offset_y;
  gboolean     has_grab;
};


static void     gimp_navigation_view_size_allocate   (GtkWidget      *widget,
                                                      GtkAllocation  *allocation);
static gboolean gimp_navigation_view_draw            (GtkWidget      *widget,
                                                      cairo_t        *cr);
static gboolean gimp_navigation_view_button_press    (GtkWidget      *widget,
                                                      GdkEventButton *bevent);
static gboolean gimp_navigation_view_button_release  (GtkWidget      *widget,
                                                      GdkEventButton *bevent);
static gboolean gimp_navigation_view_scroll          (GtkWidget      *widget,
                                                      GdkEventScroll *sevent);
static gboolean gimp_navigation_view_motion_notify   (GtkWidget      *widget,
                                                      GdkEventMotion *mevent);
static gboolean gimp_navigation_view_key_press       (GtkWidget      *widget,
                                                      GdkEventKey    *kevent);

static void     gimp_navigation_view_transform       (GimpNavigationView *nav_view);
static void     gimp_navigation_view_draw_marker     (GimpNavigationView *nav_view,
                                                      cairo_t            *cr);
static void     gimp_navigation_view_move_to         (GimpNavigationView *nav_view,
                                                      gint                tx,
                                                      gint                ty);
static void     gimp_navigation_view_get_ratio       (GimpNavigationView *nav_view,
                                                      gdouble            *ratiox,
                                                      gdouble            *ratioy);
static gboolean gimp_navigation_view_point_in_marker (GimpNavigationView *nav_view,
                                                      gint                x,
                                                      gint                y);


G_DEFINE_TYPE (GimpNavigationView, gimp_navigation_view, GIMP_TYPE_VIEW)

#define parent_class gimp_navigation_view_parent_class

static guint view_signals[LAST_SIGNAL] = { 0 };


static void
gimp_navigation_view_class_init (GimpNavigationViewClass *klass)
{
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  view_signals[MARKER_CHANGED] =
    g_signal_new ("marker-changed",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpNavigationViewClass, marker_changed),
                  NULL, NULL,
                  gimp_marshal_VOID__DOUBLE_DOUBLE_DOUBLE_DOUBLE,
                  G_TYPE_NONE, 4,
                  G_TYPE_DOUBLE,
                  G_TYPE_DOUBLE,
                  G_TYPE_DOUBLE,
                  G_TYPE_DOUBLE);

  view_signals[ZOOM] =
    g_signal_new ("zoom",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpNavigationViewClass, zoom),
                  NULL, NULL,
                  gimp_marshal_VOID__ENUM_DOUBLE,
                  G_TYPE_NONE, 2,
                  GIMP_TYPE_ZOOM_TYPE,
                  G_TYPE_DOUBLE);

  view_signals[SCROLL] =
    g_signal_new ("scroll",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpNavigationViewClass, scroll),
                  NULL, NULL, NULL,
                  G_TYPE_NONE, 1,
                  GDK_TYPE_EVENT);

  widget_class->size_allocate        = gimp_navigation_view_size_allocate;
  widget_class->draw                 = gimp_navigation_view_draw;
  widget_class->button_press_event   = gimp_navigation_view_button_press;
  widget_class->button_release_event = gimp_navigation_view_button_release;
  widget_class->scroll_event         = gimp_navigation_view_scroll;
  widget_class->motion_notify_event  = gimp_navigation_view_motion_notify;
  widget_class->key_press_event      = gimp_navigation_view_key_press;
}

static void
gimp_navigation_view_init (GimpNavigationView *view)
{
  gtk_widget_set_can_focus (GTK_WIDGET (view), TRUE);
  gtk_widget_add_events (GTK_WIDGET (view),
                         GDK_SCROLL_MASK         |
                         GDK_SMOOTH_SCROLL_MASK  |
                         GDK_POINTER_MOTION_MASK |
                         GDK_KEY_PRESS_MASK);

  view->center_x          = 0.0;
  view->center_y          = 0.0;
  view->width             = 0.0;
  view->height            = 0.0;
  view->flip_horizontally = FALSE;
  view->flip_vertically   = FALSE;
  view->rotate_angle      = 0.0;

  view->canvas_visible    = FALSE;
  view->canvas_x          = 0.0;
  view->canvas_y          = 0.0;
  view->canvas_width      = 0.0;
  view->canvas_height     = 0.0;

  view->p_center_x      = 0;
  view->p_center_y      = 0;
  view->p_width         = 0;
  view->p_height        = 0;

  view->p_canvas_x      = 0;
  view->p_canvas_y      = 0;
  view->p_canvas_width  = 0;
  view->p_canvas_height = 0;

  view->motion_offset_x = 0;
  view->motion_offset_y = 0;
  view->has_grab        = FALSE;
}

static void
gimp_navigation_view_size_allocate (GtkWidget     *widget,
                                    GtkAllocation *allocation)
{
  GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);

  if (GIMP_VIEW (widget)->renderer->viewable)
    gimp_navigation_view_transform (GIMP_NAVIGATION_VIEW (widget));
}

static gboolean
gimp_navigation_view_draw (GtkWidget *widget,
                           cairo_t   *cr)
{
  GTK_WIDGET_CLASS (parent_class)->draw (widget, cr);

  gimp_navigation_view_draw_marker (GIMP_NAVIGATION_VIEW (widget), cr);

  return TRUE;
}

void
gimp_navigation_view_grab_pointer (GimpNavigationView *nav_view,
                                   GdkEvent           *event)
{
  GtkWidget  *widget = GTK_WIDGET (nav_view);
  GdkDisplay *display;
  GdkCursor  *cursor;
  GdkWindow  *window;

  nav_view->has_grab = TRUE;

  gtk_grab_add (widget);

  display = gtk_widget_get_display (widget);
  cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);

  window = GIMP_VIEW (nav_view)->event_window;

  gdk_seat_grab (gdk_event_get_seat (event),
                 window,
                 GDK_SEAT_CAPABILITY_ALL,
                 FALSE, cursor, event, NULL, NULL);

  g_object_unref (cursor);
}

static gboolean
gimp_navigation_view_button_press (GtkWidget      *widget,
                                   GdkEventButton *bevent)
{
  GimpNavigationView *nav_view = GIMP_NAVIGATION_VIEW (widget);
  gint                tx, ty;
  GdkDisplay         *display;

  tx = bevent->x;
  ty = bevent->y;

  if (bevent->type == GDK_BUTTON_PRESS && bevent->button == 1)
    {
      if (! gimp_navigation_view_point_in_marker (nav_view, tx, ty))
        {
          GdkCursor *cursor;

          nav_view->motion_offset_x = 0;
          nav_view->motion_offset_y = 0;

          gimp_navigation_view_move_to (nav_view, tx, ty);

          display = gtk_widget_get_display (widget);
          cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
          gdk_window_set_cursor (GIMP_VIEW (widget)->event_window, cursor);
          g_object_unref (cursor);
        }
      else
        {
          nav_view->motion_offset_x = tx - nav_view->p_center_x;
          nav_view->motion_offset_y = ty - nav_view->p_center_y;
        }

      gimp_navigation_view_grab_pointer (nav_view, (GdkEvent *) bevent);
    }

  return TRUE;
}

static gboolean
gimp_navigation_view_button_release (GtkWidget      *widget,
                                     GdkEventButton *bevent)
{
  GimpNavigationView *nav_view = GIMP_NAVIGATION_VIEW (widget);

  if (bevent->button == 1 && nav_view->has_grab)
    {
      nav_view->has_grab = FALSE;

      gtk_grab_remove (widget);
      gdk_seat_ungrab (gdk_event_get_seat ((GdkEvent *) bevent));
    }

  return TRUE;
}

static gboolean
gimp_navigation_view_scroll (GtkWidget      *widget,
                             GdkEventScroll *sevent)
{
  if (sevent->state & gimp_get_toggle_behavior_mask ())
    {
      gdouble delta;

      switch (sevent->direction)
        {
        case GDK_SCROLL_UP:
          g_signal_emit (widget, view_signals[ZOOM], 0, GIMP_ZOOM_IN, 0.0);
          break;

        case GDK_SCROLL_DOWN:
          g_signal_emit (widget, view_signals[ZOOM], 0, GIMP_ZOOM_OUT, 0.0);
          break;

        case GDK_SCROLL_SMOOTH:
          gdk_event_get_scroll_deltas ((GdkEvent *) sevent, NULL, &delta);
          g_signal_emit (widget, view_signals[ZOOM], 0, GIMP_ZOOM_SMOOTH, delta);
          break;

        default:
          break;
        }
    }
  else
    {
      g_signal_emit (widget, view_signals[SCROLL], 0, sevent);
    }

  return TRUE;
}

static gboolean
gimp_navigation_view_motion_notify (GtkWidget      *widget,
                                    GdkEventMotion *mevent)
{
  GimpNavigationView *nav_view = GIMP_NAVIGATION_VIEW (widget);
  GimpView           *view     = GIMP_VIEW (widget);

  if (! nav_view->has_grab)
    {
      GdkDisplay *display = gtk_widget_get_display (widget);
      GdkCursor  *cursor;

      if (nav_view->p_center_x == view->renderer->width  / 2 &&
          nav_view->p_center_y == view->renderer->height / 2 &&
          nav_view->p_width    == view->renderer->width      &&
          nav_view->p_height   == view->renderer->height)
        {
          gdk_window_set_cursor (view->event_window, NULL);
          return FALSE;
        }
      else if (gimp_navigation_view_point_in_marker (nav_view,
                                                     mevent->x, mevent->y))
        {
          cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
        }
      else
        {
          cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
        }

      gdk_window_set_cursor (view->event_window, cursor);
      g_object_unref (cursor);

      return FALSE;
    }

  /* Derive window-local coords from root coords and event_window's screen origin.
   * This only makes a difference on Wayland, on other platforms the event coords
   * are not local so this is a noop */

  {
    gint     origin_x, origin_y;
    gdouble  mx, my;

    gdk_window_get_origin (view->event_window, &origin_x, &origin_y);
    mx = mevent->x_root - origin_x;
    my = mevent->y_root - origin_y;

    gimp_navigation_view_move_to (nav_view,
                                  mx - nav_view->motion_offset_x,
                                  my - nav_view->motion_offset_y);
  }
  gdk_event_request_motions (mevent);

  return TRUE;
}

static gboolean
gimp_navigation_view_key_press (GtkWidget   *widget,
                                GdkEventKey *kevent)
{
  GimpNavigationView *nav_view = GIMP_NAVIGATION_VIEW (widget);
  gint                scroll_x = 0;
  gint                scroll_y = 0;

  switch (kevent->keyval)
    {
    case GDK_KEY_Up:
      scroll_y = -1;
      break;

    case GDK_KEY_Left:
      scroll_x = -1;
      break;

    case GDK_KEY_Right:
      scroll_x = 1;
      break;

    case GDK_KEY_Down:
      scroll_y = 1;
      break;

    default:
      break;
    }

  if (scroll_x || scroll_y)
    {
      gimp_navigation_view_move_to (nav_view,
                                    nav_view->p_center_x + scroll_x,
                                    nav_view->p_center_y + scroll_y);
      return TRUE;
    }

  return FALSE;
}


/*  public functions  */

void
gimp_navigation_view_set_marker (GimpNavigationView *nav_view,
                                 gdouble             center_x,
                                 gdouble             center_y,
                                 gdouble             width,
                                 gdouble             height,
                                 gboolean            flip_horizontally,
                                 gboolean            flip_vertically,
                                 gdouble             rotate_angle)
{
  GimpView *view;

  g_return_if_fail (GIMP_IS_NAVIGATION_VIEW (nav_view));

  view = GIMP_VIEW (nav_view);

  g_return_if_fail (view->renderer->viewable);

  nav_view->center_x          = center_x;
  nav_view->center_y          = center_y;
  nav_view->width             = MAX (1.0, width);
  nav_view->height            = MAX (1.0, height);
  nav_view->flip_horizontally = flip_horizontally ? TRUE : FALSE;
  nav_view->flip_vertically   = flip_vertically   ? TRUE : FALSE;
  nav_view->rotate_angle      = rotate_angle;

  gimp_navigation_view_transform (nav_view);

  /* Marker changed, redraw */
  gtk_widget_queue_draw (GTK_WIDGET (view));
}

void
gimp_navigation_view_set_canvas (GimpNavigationView *nav_view,
                                 gboolean            visible,
                                 gdouble             x,
                                 gdouble             y,
                                 gdouble             width,
                                 gdouble             height)
{
  GimpView *view;

  g_return_if_fail (GIMP_IS_NAVIGATION_VIEW (nav_view));

  view = GIMP_VIEW (nav_view);

  g_return_if_fail (view->renderer->viewable);

  nav_view->canvas_visible = visible;
  nav_view->canvas_x       = x;
  nav_view->canvas_y       = y;
  nav_view->canvas_width   = MAX (1.0, width);
  nav_view->canvas_height  = MAX (1.0, height);

  gimp_navigation_view_transform (nav_view);

  /* Marker changed, redraw */
  gtk_widget_queue_draw (GTK_WIDGET (view));
}

void
gimp_navigation_view_set_motion_offset (GimpNavigationView *view,
                                        gint                motion_offset_x,
                                        gint                motion_offset_y)
{
  g_return_if_fail (GIMP_IS_NAVIGATION_VIEW (view));

  view->motion_offset_x = motion_offset_x;
  view->motion_offset_y = motion_offset_y;
}

void
gimp_navigation_view_get_local_marker (GimpNavigationView *view,
                                       gint               *center_x,
                                       gint               *center_y,
                                       gint               *width,
                                       gint               *height)
{
  g_return_if_fail (GIMP_IS_NAVIGATION_VIEW (view));

  if (center_x) *center_x = view->p_center_x;
  if (center_y) *center_y = view->p_center_y;
  if (width)    *width    = view->p_width;
  if (height)   *height   = view->p_height;
}


/*  private functions  */

static void
gimp_navigation_view_transform (GimpNavigationView *nav_view)
{
  gdouble ratiox, ratioy;

  gimp_navigation_view_get_ratio (nav_view, &ratiox, &ratioy);

  nav_view->p_center_x = RINT (nav_view->center_x * ratiox);
  nav_view->p_center_y = RINT (nav_view->center_y * ratioy);

  nav_view->p_width  = ceil (nav_view->width  * ratiox);
  nav_view->p_height = ceil (nav_view->height * ratioy);

  nav_view->p_canvas_x = RINT (nav_view->canvas_x * ratiox);
  nav_view->p_canvas_y = RINT (nav_view->canvas_y * ratioy);

  nav_view->p_canvas_width  = ceil (nav_view->canvas_width  * ratiox);
  nav_view->p_canvas_height = ceil (nav_view->canvas_height * ratioy);
}

static void
gimp_navigation_view_draw_marker (GimpNavigationView *nav_view,
                                  cairo_t            *cr)
{
  GimpView *view = GIMP_VIEW (nav_view);

  if (view->renderer->viewable && nav_view->width && nav_view->height)
    {
      GtkWidget      *widget = GTK_WIDGET (view);
      GtkAllocation   allocation;
      cairo_matrix_t  matrix;
      gint            p_width_2;
      gint            p_height_2;
      gdouble         angle;

      p_width_2  = nav_view->p_width  / 2;
      p_height_2 = nav_view->p_height / 2;

      angle = G_PI * nav_view->rotate_angle / 180.0;
      if (nav_view->flip_horizontally != nav_view->flip_vertically)
        angle = -angle;

      gtk_widget_get_allocation (widget, &allocation);

      cairo_get_matrix (cr, &matrix);

      cairo_rectangle (cr,
                       0, 0,
                       allocation.width, allocation.height);
      cairo_translate (cr, nav_view->p_center_x, nav_view->p_center_y);
      cairo_rotate (cr, -angle);
      cairo_rectangle (cr,
                       -p_width_2, -p_height_2,
                       nav_view->p_width, nav_view->p_height);

      cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
      cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
      cairo_fill (cr);

      if (nav_view->canvas_visible &&
          nav_view->canvas_width && nav_view->canvas_height)
        {
          cairo_save (cr);
          cairo_set_matrix (cr, &matrix);
          cairo_rectangle (cr,
                           nav_view->p_canvas_x      + 0.5,
                           nav_view->p_canvas_y      + 0.5,
                           nav_view->p_canvas_width  - 1.0,
                           nav_view->p_canvas_height - 1.0);
          gimp_canvas_set_canvas_style (GTK_WIDGET (nav_view), cr, 0, 0);
          cairo_stroke (cr);
          cairo_restore (cr);
        }

      cairo_rectangle (cr,
                       -p_width_2, -p_height_2,
                       nav_view->p_width, nav_view->p_height);

      cairo_set_source_rgb (cr, 1, 1, 1);
      cairo_set_line_width (cr, BORDER_WIDTH);
      cairo_stroke (cr);
    }
}

static void
gimp_navigation_view_move_to (GimpNavigationView *nav_view,
                              gint                tx,
                              gint                ty)
{
  GimpView  *view = GIMP_VIEW (nav_view);
  gdouble    ratiox, ratioy;
  gdouble    x, y;

  if (! view->renderer->viewable)
    return;

  gimp_navigation_view_get_ratio (nav_view, &ratiox, &ratioy);

  x = tx / ratiox;
  y = ty / ratioy;

  g_signal_emit (view, view_signals[MARKER_CHANGED], 0,
                 x, y, nav_view->width, nav_view->height);
}

static void
gimp_navigation_view_get_ratio (GimpNavigationView *nav_view,
                                gdouble            *ratiox,
                                gdouble            *ratioy)
{
  GimpView  *view = GIMP_VIEW (nav_view);
  gint       width;
  gint       height;

  gimp_viewable_get_size (view->renderer->viewable, &width, &height);

  *ratiox = (gdouble) view->renderer->width  / (gdouble) width;
  *ratioy = (gdouble) view->renderer->height / (gdouble) height;
}

static gboolean
gimp_navigation_view_point_in_marker (GimpNavigationView *nav_view,
                                      gint                x,
                                      gint                y)
{
  gint    p_width_2, p_height_2;
  gdouble angle;
  gdouble tx, ty;

  p_width_2  = nav_view->p_width  / 2;
  p_height_2 = nav_view->p_height / 2;

  angle = G_PI * nav_view->rotate_angle / 180.0;
  if (nav_view->flip_horizontally != nav_view->flip_vertically)
    angle = -angle;

  x -= nav_view->p_center_x;
  y -= nav_view->p_center_y;

  tx = cos (angle) * x - sin (angle) * y;
  ty = sin (angle) * x + cos (angle) * y;

  return tx >= -p_width_2  && tx < p_width_2 &&
         ty >= -p_height_2 && ty < p_height_2;
}

Messung
CHZG
819910093

¤ Dauer der Verarbeitung: 0.7 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104856
#Domains=417307