Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gnome/demos/gtk-demo/   (Gnome Linux Desktop Version 4.23.2©)  Datei vom 30.5.2026 mit Größe 12 kB image not shown  

Quelle  imageview.c

  Sprache: C
 

#include <math.h>
#include "imageview.h"


enum
{
  PROP_TEXTURE = 1,
  PROP_FILTER,
  PROP_SCALE,
  PROP_ANGLE,
  N_PROPS
};

static GParamSpec *props[N_PROPS] = { NULL, };

struct _ImageView
{
  GtkWidget parent_instance;

  GdkTexture *texture;
  float scale;
  float angle;
  GskScalingFilter filter;

  GtkWidget *menu;
  float start_scale;
  float start_angle;
};

struct _ImageViewClass
{
  GtkWidgetClass parent_class;
};

G_DEFINE_TYPE (ImageView, image_view, GTK_TYPE_WIDGET)

static gboolean
query_tooltip (GtkWidget  *widget,
               int         x,
               int         y,
               gboolean    keyboard_mode,
               GtkTooltip *tooltip,
               gpointer    data)
{
  ImageView *self = IMAGE_VIEW (widget);
  GtkWidget *grid;
  GtkWidget *label;
  char *s, *s2;
  const char *filter[] = { "Linear""Nearest""Trilinear" };
  int precision, l;

  grid = gtk_grid_new ();
  gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
  gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
  label = gtk_label_new ("Texture");
  gtk_label_set_xalign (GTK_LABEL (label), 0);
  gtk_grid_attach (GTK_GRID (grid), label, 0011);
  s = g_strdup_printf ("%d\342\200\206\303\227\342\200\206%d",
                       gdk_texture_get_width (self->texture),
                       gdk_texture_get_height (self->texture));
  label = gtk_label_new (s);
  g_free (s);
  gtk_label_set_xalign (GTK_LABEL (label), 1);
  gtk_grid_attach (GTK_GRID (grid), label, 1011);

  label = gtk_label_new ("Rotation");
  gtk_label_set_xalign (GTK_LABEL (label), 0);
  gtk_grid_attach (GTK_GRID (grid), label, 0111);
  s = g_strdup_printf ("%.1f", self->angle);
  if (g_str_has_suffix (s, ".0"))
    s[strlen (s) - 2] = '\0';
  s2 = g_strconcat (s, "\302\260", NULL);
  label = gtk_label_new (s2);
  g_free (s2);
  g_free (s);
  gtk_label_set_xalign (GTK_LABEL (label), 1);
  gtk_grid_attach (GTK_GRID (grid), label, 1111);

  label = gtk_label_new ("Scale");
  gtk_label_set_xalign (GTK_LABEL (label), 0);
  gtk_grid_attach (GTK_GRID (grid), label, 0211);

  precision = 1;
  s = NULL;
  do {
    g_free (s);
    s = g_strdup_printf ("%.*f", precision, self->scale);
    l = strlen (s) - 1;
    while (s[l] == '0')
      l--;
    if (s[l] == '.')
      s[l] = '\0';
    precision++;
  } while (strcmp (s, "0") == 0);

  label = gtk_label_new (s);
  g_free (s);
  gtk_label_set_xalign (GTK_LABEL (label), 1);
  gtk_grid_attach (GTK_GRID (grid), label, 1211);

  label = gtk_label_new ("Filter");
  gtk_label_set_xalign (GTK_LABEL (label), 0);
  gtk_grid_attach (GTK_GRID (grid), label, 0311);
  label = gtk_label_new (filter[self->filter]);
  gtk_label_set_xalign (GTK_LABEL (label), 1);
  gtk_grid_attach (GTK_GRID (grid), label, 1311);

  gtk_tooltip_set_custom (tooltip, grid);

  return TRUE;
}

static void
image_view_init (ImageView *self)
{
  self->scale = 1.f;
  self->angle = 0.f;
  self->filter = GSK_SCALING_FILTER_LINEAR;
  gtk_widget_init_template (GTK_WIDGET (self));
}

static void
image_view_dispose (GObject *object)
{
  ImageView *self = IMAGE_VIEW (object);

  g_clear_object (&self->texture);

  gtk_widget_dispose_template (GTK_WIDGET (self), IMAGE_TYPE_VIEW);

  G_OBJECT_CLASS (image_view_parent_class)->dispose (object);
}

static void
image_view_snapshot (GtkWidget   *widget,
                     GtkSnapshot *snapshot)
{
  ImageView *self = IMAGE_VIEW (widget);
  int x, y, width, height;
  double w, h, w2, h2;

  width = gtk_widget_get_width (widget);
  height = gtk_widget_get_height (widget);

  w2 = w = self->scale * gdk_texture_get_width (self->texture);
  h2 = h = self->scale * gdk_texture_get_height (self->texture);

  if (G_APPROX_VALUE (self->angle, 90.f, FLT_EPSILON) ||
      G_APPROX_VALUE (self->angle, 270.f, FLT_EPSILON))
    {
      double s = w2;
      w2 = h2;
      h2 = s;
    }

  x = (width - ceil (w2)) / 2;
  y = (height - ceil (h2)) / 2;

  gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (00, width, height));
  gtk_snapshot_save (snapshot);
  gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
  gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (w2 / 2, h2 / 2));
  gtk_snapshot_rotate (snapshot, self->angle);
  gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- w / 2, - h / 2));
  gtk_snapshot_append_scaled_texture (snapshot,
                                      self->texture,
                                      self->filter,
                                      &GRAPHENE_RECT_INIT (00, w, h));
  gtk_snapshot_restore (snapshot);
  gtk_snapshot_pop (snapshot);
}

static void
image_view_measure (GtkWidget      *widget,
                    GtkOrientation  orientation,
                    int             for_size,
                    int            *minimum,
                    int            *natural,
                    int            *minimum_baseline,
                    int            *natural_baseline)
{
  ImageView *self = IMAGE_VIEW (widget);
  int width, height;
  int size;

  width = gdk_texture_get_width (self->texture);
  height = gdk_texture_get_height (self->texture);

  if (G_APPROX_VALUE (self->angle, 90.f, FLT_EPSILON) ||
      G_APPROX_VALUE (self->angle, 270.f, FLT_EPSILON))
    {
      int s = width;
      width = height;
      height = s;
    }

  if (orientation == GTK_ORIENTATION_HORIZONTAL)
    size = width;
  else
    size = height;

  *minimum = *natural = (int) ceil (self->scale * size);
}

static void
image_view_size_allocate (GtkWidget *widget,
                          int        width,
                          int        height,
                          int        baseline)
{
  ImageView *self = IMAGE_VIEW (widget);

  /* Since we are not using a layout manager (who would do this
   * for us), we need to allocate a size for our menu by calling
   * gtk_popover_present().
   */

  gtk_popover_present (GTK_POPOVER (self->menu));
}

static void update_actions (ImageView *self);

static void
image_view_set_property (GObject      *object,
                         guint         prop_id,
                         const GValue *value,
                         GParamSpec   *pspec)
{
  ImageView *self = IMAGE_VIEW (object);

  switch (prop_id)
    {
    case PROP_TEXTURE:
      g_clear_object (&self->texture);
      self->texture = g_value_dup_object (value);
      self->scale = 1.f;
      self->angle = 0.f;
      self->filter = GSK_SCALING_FILTER_LINEAR;
      update_actions (self);
      gtk_widget_queue_resize (GTK_WIDGET (object));
      g_object_notify_by_pspec (object, props[PROP_SCALE]);
      g_object_notify_by_pspec (object, props[PROP_ANGLE]);
      g_object_notify_by_pspec (object, props[PROP_FILTER]);
      break;

    case PROP_SCALE:
      self->scale = g_value_get_float (value);
      update_actions (self);
      gtk_widget_queue_resize (GTK_WIDGET (object));
      break;

    case PROP_ANGLE:
      self->angle = fmodf (g_value_get_float (value), 360.f);
      gtk_widget_queue_resize (GTK_WIDGET (object));
      break;

    case PROP_FILTER:
      self->filter = g_value_get_enum (value);
      gtk_widget_queue_resize (GTK_WIDGET (object));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
image_view_get_property (GObject     *object,
                         guint        prop_id,
                         GValue      *value,
                         GParamSpec  *pspec)
{
  ImageView *self = IMAGE_VIEW (object);

  switch (prop_id)
    {
    case PROP_TEXTURE:
      g_value_set_object (value, self->texture);
      break;

    case PROP_SCALE:
      g_value_set_float (value, self->scale);
      break;

    case PROP_ANGLE:
      g_value_set_float (value, self->angle);
      break;

    case PROP_FILTER:
      g_value_set_enum (value, self->filter);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
pressed_cb (GtkGestureClick *gesture,
            guint            n_press,
            double           x,
            double           y,
            ImageView     *self)
{
  /* We are placing our menu at the point where
   * the click happened, before popping it up.
   */

  gtk_popover_set_pointing_to (GTK_POPOVER (self->menu),
                               &(const GdkRectangle){ x, y, 11 });
  gtk_popover_popup (GTK_POPOVER (self->menu));
}

static void
update_actions (ImageView *self)
{
  gtk_widget_action_set_enabled (GTK_WIDGET (self), "zoom.in", self->scale < 1024.);
  gtk_widget_action_set_enabled (GTK_WIDGET (self), "zoom.out", self->scale > 1./1024.);
  gtk_widget_action_set_enabled (GTK_WIDGET (self), "zoom.reset", self->scale != 1.);
}

static void
zoom_cb (GtkWidget  *widget,
         const char *action_name,
         GVariant   *parameter)
{
  ImageView *self = IMAGE_VIEW (widget);
  float scale;

  if (g_str_equal (action_name, "zoom.in"))
    scale = MIN (1024., self->scale * M_SQRT2);
  else if (g_str_equal (action_name, "zoom.out"))
    scale = MAX (1./1024., self->scale / M_SQRT2);
  else if (g_str_equal (action_name, "zoom.reset"))
    scale = 1.0;
  else
    g_assert_not_reached ();

  g_object_set (widget, "scale", scale, NULL);
}

static void
rotate_cb (GtkWidget  *widget,
           const char *action_name,
           GVariant   *parameter)
{
  ImageView *self = IMAGE_VIEW (widget);
  int angle;

  g_variant_get (parameter, "i", &angle);

  g_object_set (widget, "angle", fmodf (self->angle + angle, 360.f), NULL);
}

static void
scale_begin_cb (GtkGesture       *gesture,
                GdkEventSequence *sequence,
         ImageView        *self)
{
  self->start_scale = self->scale;
}

static void
scale_changed_cb (GtkGestureZoom *gesture,
    double          scale,
    ImageView      *self)
{
  g_object_set (self, "scale", self->start_scale*scale, NULL);
}

#define RAD_TO_DEG(a) (180.0 * (a) / M_PI)

static void
rotate_begin_cb (GtkGesture       *gesture,
          GdkEventSequence *sequence,
          ImageView        *self)
{
  self->start_angle = self->angle;
}

static void
angle_changed_cb (GtkGestureRotate *gesture,
    double            angle,
    double            delta,
    ImageView        *self)
{
  double a;

  a = 90 * round (RAD_TO_DEG (delta) / 10);

  g_object_set (self, "angle", fmodf (self->start_angle + a, 360.f), NULL);
}

static void
image_view_class_init (ImageViewClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);

  object_class->dispose = image_view_dispose;
  object_class->set_property = image_view_set_property;
  object_class->get_property = image_view_get_property;

  widget_class->snapshot = image_view_snapshot;
  widget_class->measure = image_view_measure;
  widget_class->size_allocate = image_view_size_allocate;

  props[PROP_TEXTURE] = g_param_spec_object ("texture", NULL, NULL,
                                             GDK_TYPE_TEXTURE,
                                             G_PARAM_READWRITE | G_PARAM_STATIC_NAME);

  props[PROP_SCALE] = g_param_spec_float ("scale", NULL, NULL,
                                          1./1024., 1024., 1.0,
                                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);

  props[PROP_ANGLE] = g_param_spec_float ("angle", NULL, NULL,
                                          0.0360.00.0,
                                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);

  props[PROP_FILTER] = g_param_spec_enum ("filter", NULL, NULL,
                                          GSK_TYPE_SCALING_FILTER, GSK_SCALING_FILTER_LINEAR,
                                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);

  g_object_class_install_properties (object_class, N_PROPS, props);

  /* These are the actions that we are using in the menu */
  gtk_widget_class_install_action (widget_class, "zoom.in", NULL, zoom_cb);
  gtk_widget_class_install_action (widget_class, "zoom.out", NULL, zoom_cb);
  gtk_widget_class_install_action (widget_class, "zoom.reset", NULL, zoom_cb);
  gtk_widget_class_install_action (widget_class, "rotate""i", rotate_cb);

  gtk_widget_class_set_template_from_resource (widget_class, "/menu/imageview.ui");
  gtk_widget_class_bind_template_child (widget_class, ImageView, menu);
  gtk_widget_class_bind_template_callback (widget_class, pressed_cb);
  gtk_widget_class_bind_template_callback (widget_class, scale_changed_cb);
  gtk_widget_class_bind_template_callback (widget_class, scale_begin_cb);
  gtk_widget_class_bind_template_callback (widget_class, angle_changed_cb);
  gtk_widget_class_bind_template_callback (widget_class, rotate_begin_cb);
  gtk_widget_class_bind_template_callback (widget_class, query_tooltip);

  gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_IMG);
}

GtkWidget *
image_view_new (const char *resource)
{
  ImageView *self;
  GdkTexture *texture;

  texture = gdk_texture_new_from_resource (resource);

  self = g_object_new (IMAGE_TYPE_VIEW,
                       "texture", texture,
                       NULL);

  g_object_unref (texture);

  return GTK_WIDGET (self);
}

Messung V0.5 in Prozent
C=98 H=95 G=96

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet am  2026-07-02) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

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.