Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  imap_polygon.c   Sprache: C

 

/*
 * This is a plug-in for GIMP.
 *
 * Generates clickable image maps.
 *
 * Copyright (C) 1998-2005 Maurits Rijk  m.rijk@chello.nl
 *
 * 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 <stdlib.h>
#include <stdio.h>

#include "libgimp/gimp.h"
#include "libgimp/gimpui.h"

#include "imap_commands.h"
#include "imap_icons.h"
#include "imap_main.h"
#include "imap_misc.h"
#include "imap_menu.h"
#include "imap_object_popup.h"
#include "imap_polygon.h"
#include "imap_ui_grid.h"

#include "libgimp/stdplugins-intl.h"

#define MAX_POLYGON_POINTS 99

static gboolean polygon_is_valid(Object_t *obj);
static void polygon_destruct(Object_t *obj);
static Object_t *polygon_clone(Object_t *obj);
static void polygon_assign(Object_t *obj, Object_t *des);
static void polygon_draw(Object_t* obj, cairo_t *cr);
static void polygon_draw_sashes(Object_t* obj, cairo_t *cr);
static MoveSashFunc_t polygon_near_sash(Object_t *obj, gint x, gint y);
static gboolean polygon_point_is_on(Object_t *obj, gint x, gint y);
static void polygon_get_dimensions(Object_t *obj, gint *x, gint *y,
                                   gint *width, gint *height);
static void polygon_resize(Object_t *obj, gint percentage_x,
                           gint percentage_y);
static void polygon_move(Object_t *obj, gint dx, gint dy);
static gpointer polygon_create_info_widget(GtkWidget *frame);
static void polygon_update_info_widget(Object_t *obj, gpointer data);
static void polygon_fill_info_tab(Object_t *obj, gpointer data);
static void polygon_set_initial_focus(Object_t *obj, gpointer data);
static void polygon_update(Object_t* obj, gpointer data);
static void polygon_write_csim(Object_t* obj, gpointer param,
                               OutputFunc_t output);
static void polygon_write_cern(Object_t* obj, gpointer param,
                               OutputFunc_t output);
static void polygon_write_ncsa(Object_t* obj, gpointer param,
                               OutputFunc_t output);
static void polygon_do_popup  (Object_t       *obj,
                               GdkEventButton *event,
                               gpointer        data);
static const gchar* polygon_get_icon_name(void);

static ObjectClass_t polygon_class = {
   N_("_Polygon"),
   NULL,                        /* info_dialog */

   polygon_is_valid,
   polygon_destruct,
   polygon_clone,
   polygon_assign,
   NULL,                        /* polygon_normalize */
   polygon_draw,
   polygon_draw_sashes,
   polygon_near_sash,
   polygon_point_is_on,
   polygon_get_dimensions,
   polygon_resize,
   polygon_move,
   polygon_create_info_widget,
   polygon_update_info_widget,
   polygon_fill_info_tab,
   polygon_set_initial_focus,
   polygon_update,
   polygon_write_csim,
   polygon_write_cern,
   polygon_write_ncsa,
   polygon_do_popup,
   polygon_get_icon_name
};

Object_t*
create_polygon(GList *points)
{
   Polygon_t *polygon = g_new(Polygon_t, 1);
   polygon->points = points;
   return object_init(&polygon->obj, &polygon_class);
}

static void
polygon_free_list (Polygon_t *polygon)
{
  g_list_free_full (polygon->points, (GDestroyNotify) g_free);
  polygon->points = NULL;
}

static void
polygon_destruct(Object_t *obj)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   polygon_free_list(polygon);
}

static gboolean
polygon_is_valid(Object_t *obj)
{
   return g_list_length(ObjectToPolygon(obj)->points) > 2;
}

static Object_t*
polygon_clone(Object_t *obj)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   Polygon_t *clone = g_new(Polygon_t, 1);
   GList     *p;

   clone->points = NULL;
   for (p = polygon->points; p; p = p->next) {
      GdkPoint *point = (GdkPoint*) p->data;
      polygon_append_point(clone, point->x, point->y);
   }
   return &clone->obj;
}

static void
polygon_assign(Object_t *obj, Object_t *des)
{
   Polygon_t *src_polygon = ObjectToPolygon(obj);
   Polygon_t *des_polygon = ObjectToPolygon(des);
   GList     *p;

   polygon_free_list(des_polygon);
   for (p = src_polygon->points; p; p = p->next) {
      GdkPoint *point = (GdkPoint*) p->data;
      polygon_append_point(des_polygon, point->x, point->y);
   }
}

static void
polygon_draw(Object_t *obj, cairo_t *cr)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   draw_polygon(cr, polygon->points);
}

static void
polygon_draw_sashes(Object_t *obj, cairo_t *cr)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GList     *p;
   for (p = polygon->points; p; p = p->next) {
      GdkPoint *point = (GdkPoint*) p->data;
      draw_sash(cr, point->x, point->y);
   }
}

static GdkPoint *_sash_point;
static gint _sash_index;

static void
move_sash(Object_t *obj, gint dx, gint dy)
{
   _sash_point->x += dx;
   _sash_point->y += dy;
}

static MoveSashFunc_t
polygon_near_sash(Object_t *obj, gint x, gint y)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GList     *p;

   _sash_index = 0;
   for (p = polygon->points; p; p = p->next, _sash_index++) {
      GdkPoint *point = (GdkPoint*) p->data;
      if (near_sash(point->x, point->y, x, y)) {
         _sash_point = point;
         return move_sash;
      }
   }
   return NULL;
}

static gboolean
right_intersect(GdkPoint *p1, GdkPoint *p2, gint x, gint y)
{
   gint dx = p2->x - p1->x;
   gint dy = p2->y - p1->y;

   if ((dy > 0 && y > p1->y && y < p2->y) ||
       (dy < 0 && y > p2->y && y < p1->y)) {
      gint sx = p1->x + (y - p1->y) * dx / dy;
      return sx > x;
   }
   return FALSE;
}

static gboolean
polygon_point_is_on(Object_t *obj, gint x, gint y)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GList     *p;
   int        count = 0;
   GdkPoint  *first, *prev;

   p = polygon->points;
   first = prev = (GdkPoint*) p->data;
   p = p->next;

   for (; p; p = p->next) {
      GdkPoint *point = (GdkPoint*) p->data;
      if (right_intersect(prev, point, x, y))
         count++;
      prev = point;
   }
   if (right_intersect(prev, first, x, y))
       count++;

   return count % 2;
}

static void
polygon_get_dimensions(Object_t *obj, gint *x, gint *y,
                       gint *width, gint *height)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   gint min_x = G_MAXINT, min_y = G_MAXINT;
   gint max_x = G_MININT, max_y = G_MININT;
   GList     *p;

   for (p = polygon->points; p; p = p->next) {
      GdkPoint *point = (GdkPoint*) p->data;
      if (point->x < min_x)
         min_x = point->x;
      if (point->x > max_x)
         max_x = point->x;
      if (point->y < min_y)
         min_y = point->y;
      if (point->y > max_y)
         max_y = point->y;
   }
   *x = min_x;
   *y = min_y;
   *width = max_x - min_x;
   *height = max_y - min_y;
}

static void
polygon_resize(Object_t *obj, gint percentage_x, gint percentage_y)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GList     *p;
   for (p = polygon->points; p; p = p->next) {
      GdkPoint *point = (GdkPoint*) p->data;
      point->x = point->x * percentage_x / 100;
      point->y = point->y * percentage_y / 100;
   }
}

static void
polygon_move(Object_t *obj, gint dx, gint dy)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GList     *p;
   for (p = polygon->points; p; p = p->next) {
      GdkPoint *point = (GdkPoint*) p->data;
      point->x += dx;
      point->y += dy;
   }
}

typedef struct {
   Object_t  *obj;
   GtkListStore *store;
   GtkTreeSelection *selection;
   GtkWidget *x;
   GtkWidget *y;
   GtkWidget *update;
   GtkWidget *insert;
   GtkWidget *append;
   GtkWidget *remove;
   gint       selected_row;
   guint      timeout;
} PolygonProperties_t;

static void
select_row_cb(GtkTreeSelection *selection, PolygonProperties_t *data)
{
  GtkTreeIter iter;
  GtkTreeModel *model;

  if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
    GdkPoint *point;

    gtk_tree_model_get (model, &iter, 0, &point, -1);

    _sash_point = point;

    gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->x), point->x);
    gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->y), point->y);
  }
}

static void
update_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
{
   GtkTreeIter iter;
   GtkTreeModel *model = GTK_TREE_MODEL(data->store);

   if (gtk_tree_selection_get_selected (data->selection, &model, &iter)) {
     GdkPoint *point;
     gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->x));
     gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->y));

     gtk_tree_model_get (model, &iter, 0, &point, -1);
     point->x = x;
     point->y = y;
     gtk_list_store_set (data->store, &iter, 0, point, -1);
   }
}

static void
set_buttons_sensitivity(PolygonProperties_t *data)
{
   gint rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(data->store),
                                               NULL);
   gtk_widget_set_sensitive(data->insert, rows != MAX_POLYGON_POINTS);
   gtk_widget_set_sensitive(data->append, rows != MAX_POLYGON_POINTS);
   gtk_widget_set_sensitive(data->remove, rows > 2);
}

static void
insert_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
{
   GtkTreeIter iter;
   GtkTreeModel *model = GTK_TREE_MODEL(data->store);

   if (gtk_tree_selection_get_selected (data->selection, &model, &iter)) {
     Polygon_t *polygon = ObjectToPolygon(data->obj);
     GdkPoint *point;
     GList *here;
     gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->x));
     gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->y));

     gtk_tree_model_get (model, &iter, 0, &point, -1);
     here = g_list_find(polygon->points, point);
     polygon->points = g_list_insert_before(polygon->points, here,
                                            new_point(x, y));
     polygon_fill_info_tab(data->obj, data);
   }
}

static void
append_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
{
   gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->x));
   gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->y));

   polygon_append_point(ObjectToPolygon(data->obj), x, y);
   polygon_fill_info_tab(data->obj, data);
}

static void
remove_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
{
  GtkTreeIter iter;
  GtkTreeModel *model = GTK_TREE_MODEL(data->store);

  if (gtk_tree_selection_get_selected (data->selection, &model, &iter)) {
    Polygon_t *polygon = ObjectToPolygon(data->obj);
    GdkPoint *point;

    gtk_tree_model_get (model, &iter, 0, &point, -1);
    polygon->points = g_list_remove(polygon->points, point);
    g_free(point);

    polygon_fill_info_tab(data->obj, data);
  }
}

static void
x_changed_cb(GtkWidget *widget, gpointer data)
{
   Object_t *obj = ((PolygonProperties_t*) data)->obj;
   gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
   _sash_point->x = x;
   edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
}

static void
y_changed_cb(GtkWidget *widget, gpointer data)
{
   Object_t *obj = ((PolygonProperties_t*) data)->obj;
   gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
   _sash_point->y = y;
   edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
}

static void
render_x(GtkTreeViewColumn *column, GtkCellRenderer *cell,
         GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
{
  GdkPoint *point;
  gchar scratch[16];

  gtk_tree_model_get(tree_model, iter, 0, &point, -1);
  sprintf(scratch, "%d", point->x);
  g_object_set(cell, "text", scratch, "xalign", 1.0, NULL);
}

static void
render_y(GtkTreeViewColumn *column, GtkCellRenderer *cell,
         GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
{
  GdkPoint *point;
  gchar scratch[16];

  gtk_tree_model_get(tree_model, iter, 0, &point, -1);
  sprintf(scratch, "%d", point->y);
  g_object_set(cell, "text", scratch, "xalign", 1.0, NULL);
}

static gpointer
polygon_create_info_widget(GtkWidget *frame)
{
   PolygonProperties_t *props = g_new(PolygonProperties_t, 1);
   GtkWidget *hbox, *swin, *grid, *label;
   GtkWidget *view;
   gint max_width = get_image_width();
   gint max_height = get_image_height();
   GtkCellRenderer *renderer;
   GtkTreeViewColumn *column;

   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
   gtk_container_add(GTK_CONTAINER(frame), hbox);
   gtk_widget_show(hbox);

   swin = gtk_scrolled_window_new(NULL, NULL);

   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
                                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(swin),
                                        GTK_SHADOW_IN);
   gtk_box_pack_start(GTK_BOX(hbox), swin, FALSE, FALSE, FALSE);
   gtk_widget_show(swin);

   props->store = gtk_list_store_new (1, G_TYPE_POINTER);
   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (props->store));
   g_object_unref (props->store);
   gtk_widget_show (view);

   renderer = gtk_cell_renderer_text_new ();
   column = gtk_tree_view_column_new_with_attributes (_("x (pixels)"),
                                                      renderer,
                                                      NULL);
   gtk_tree_view_column_set_cell_data_func(column, renderer,
                                           render_x, props, NULL);
   gtk_tree_view_column_set_alignment(column, 0.5);
   gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);

   renderer = gtk_cell_renderer_text_new ();
   column = gtk_tree_view_column_new_with_attributes (_("y (pixels)"),
                                                      renderer,
                                                      NULL);
   gtk_tree_view_column_set_cell_data_func(column, renderer,
                                           render_y, props, NULL);
   gtk_tree_view_column_set_alignment(column, 0.5);
   gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);

   gtk_container_add (GTK_CONTAINER (swin), view);

   grid = gtk_grid_new ();
   gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
   gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
   gtk_box_pack_start (GTK_BOX(hbox), grid, FALSE, FALSE, FALSE);
   gtk_widget_show (grid);

   label = create_label_in_grid (grid, 0, 0, "_x:");
   props->x = create_spin_button_in_grid (grid, label, 0, 1, 1, 0,
                                          max_width - 1);
   g_signal_connect(props->x, "changed",
                    G_CALLBACK(x_changed_cb), (gpointer) props);
   gtk_widget_set_size_request(props->x, 64, -1);
   create_label_in_grid (grid, 0, 2, _("pixels"));

   label = create_label_in_grid (grid, 1, 0, "_y:");
   props->y = create_spin_button_in_grid (grid, label, 1, 1, 1, 0,
                                          max_height - 1);
   g_signal_connect(props->y, "changed",
                    G_CALLBACK(y_changed_cb), (gpointer) props);
   gtk_widget_set_size_request(props->y, 64, -1);
   create_label_in_grid (grid, 1, 2, _("pixels"));

   props->update = gtk_button_new_with_mnemonic(_("_Update"));
   g_signal_connect(props->update, "clicked",
                    G_CALLBACK(update_button_clicked), props);
   gtk_grid_attach (GTK_GRID (grid), props->update, 1, 2, 1, 1);
   gtk_widget_show(props->update);

   props->insert = gtk_button_new_with_mnemonic(_("_Insert"));
   g_signal_connect(props->insert, "clicked",
                    G_CALLBACK(insert_button_clicked), props);
   gtk_grid_attach (GTK_GRID (grid), props->insert, 1, 3, 1, 1);
   gtk_widget_show(props->insert);

   props->append = gtk_button_new_with_mnemonic(_("A_ppend"));
   g_signal_connect(props->append, "clicked",
                    G_CALLBACK(append_button_clicked), props);
   gtk_grid_attach (GTK_GRID (grid), props->append, 1, 4, 1, 1);
   gtk_widget_show(props->append);

   props->remove = gtk_button_new_with_mnemonic(_("_Remove"));
   g_signal_connect(props->remove, "clicked",
                    G_CALLBACK(remove_button_clicked), props);
   gtk_grid_attach (GTK_GRID (grid), props->remove, 1, 5, 1, 1);
   gtk_widget_show(props->remove);

   props->timeout = 0;

   props->selection = gtk_tree_view_get_selection(GTK_TREE_VIEW (view));
   gtk_tree_selection_set_mode(props->selection, GTK_SELECTION_SINGLE);
   g_signal_connect (props->selection, "changed",
                     G_CALLBACK (select_row_cb), props);

   return props;
}

static gboolean
update_timeout(gpointer data)
{
   PolygonProperties_t *props = (PolygonProperties_t*) data;
   polygon_fill_info_tab(props->obj, data);
   return FALSE;
}

static void
polygon_update_info_widget(Object_t *obj, gpointer data)
{
   PolygonProperties_t *props = (PolygonProperties_t*) data;
   GtkTreeIter iter;

   gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->x), _sash_point->x);
   gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->y), _sash_point->y);

   if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(props->store), &iter,
                                     NULL, _sash_index)) {
     gtk_tree_selection_select_iter(props->selection, &iter);
   }

   if (props->timeout)
      g_source_remove(props->timeout);
   props->timeout = g_timeout_add(1000, update_timeout, data);
}

static void
polygon_fill_info_tab(Object_t *obj, gpointer data)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   PolygonProperties_t *props = (PolygonProperties_t*) data;
   GtkTreeIter iter;
   GList     *p;

   props->obj = obj;

   gtk_list_store_clear(props->store);

   for (p = polygon->points; p; p = p->next) {
     gtk_list_store_append(props->store, &iter);
     gtk_list_store_set(props->store, &iter, 0, p->data, -1);
   }

   if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(props->store), &iter,
                                     NULL, _sash_index)) {
     gtk_tree_selection_select_iter(props->selection, &iter);
   }
   set_buttons_sensitivity(props);
}

static void
polygon_set_initial_focus(Object_t *obj, gpointer data)
{
   PolygonProperties_t *props = (PolygonProperties_t*) data;
   gtk_widget_grab_focus(props->x);
}

static void
polygon_update(Object_t* obj, gpointer data)
{
  /* Nothing to be done! */
}

static void
polygon_write_csim(Object_t *obj, gpointer param, OutputFunc_t output)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GList     *p;

   output(param, "\"poly\" coords=\"");
   for (p = polygon->points; p; p = p->next) {
      GdkPoint *point = (GdkPoint*) p->data;
      output(param, "%d,%d", point->x, point->y);
      output(param, "%c", (p->next) ? ',' : '"');
   }
}

static void
polygon_write_cern(Object_t *obj, gpointer param, OutputFunc_t output)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GList     *p;
   GdkPoint  *first = (GdkPoint*) polygon->points->data;

   output(param, "poly ");
   for (p = polygon->points; p; p = p->next) {
      GdkPoint *point = (GdkPoint*) p->data;
      output(param, "(%d,%d) ", point->x, point->y);
   }
   output(param, "(%d,%d)", first->x, first->y);
}

static void
polygon_write_ncsa(Object_t *obj, gpointer param, OutputFunc_t output)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GList     *p;
   GdkPoint  *first = (GdkPoint*) polygon->points->data;

   output(param, "poly %s", obj->url);
   for (p = polygon->points; p; p = p->next) {
      GdkPoint *point = (GdkPoint*) p->data;
      output(param, " %d,%d", point->x, point->y);
   }
   output(param, " %d,%d", first->x, first->y);
}

static Object_t *_current_obj;
static gboolean _insert_edge;
static gint _insert_x;
static gint _insert_y;

void
polygon_insert_point (GSimpleAction *action,
                      GVariant      *new_state,
                      gpointer       user_data)
{
  Command_t *command = insert_point_command_new (_current_obj, _insert_x,
                                                 _insert_y, _insert_edge);
  command_execute (command);
}

void
polygon_delete_point (GSimpleAction *action,
                      GVariant      *new_state,
                      gpointer       user_data)
{
  Command_t *command = delete_point_command_new(_current_obj, _sash_point);
  command_execute (command);
}

static gboolean
point_near_edge(GdkPoint *first, GdkPoint *second, gint x, gint y)
{
   gint den, nom;
   gdouble u;

   den = (first->x - x) * (first->x - second->x) +
      (first->y - y) * (first->y - second->y);
   nom = (second->x - first->x) * (second->x - first->x) +
      (second->y - first->y) * (second->y - first->y);
   u = (gdouble) den / nom;
   if (u >= 0.0 && u <= 1.0) {
      gint sx = first->x + (gint) (u * (second->x - first->x)) - x;
      gint sy = first->y + (gint) (u * (second->y - first->y)) - y;
      return sx * sx + sy * sy <= 25; /* Fix me! */
   }
   return FALSE;
}

static gint
polygon_near_edge(Object_t *obj, gint x, gint y)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GList     *p = polygon->points;
   GdkPoint  *first = (GdkPoint*) p->data;
   GdkPoint  *prev = first;
   gint n = 1;

   for (p = p->next; p; p = p->next, n++) {
      GdkPoint *next = (GdkPoint*) p->data;
      if (point_near_edge(prev, next, x, y))
         return n;
      prev = next;
   }
   return (point_near_edge(prev, first, x, y)) ? n + 1 : 0;
}

static void
polygon_handle_popup (GdkEventButton *event,
                      GimpImap       *imap,
                      gboolean        near_sash,
                      gboolean        near_edge)
{
  GtkWidget  *menu;
  GMenuModel *model;
  GAction    *action;

  model = G_MENU_MODEL (gtk_builder_get_object (imap->builder, "imap-polygon-popup"));
  menu = gtk_menu_new_from_model (model);

  action = g_action_map_lookup_action (G_ACTION_MAP (imap->app), "insert-point");
  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), near_edge);
  action = g_action_map_lookup_action (G_ACTION_MAP (imap->app), "delete-point");
  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), near_sash);

  gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (imap->dlg), NULL);
  gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *) event);
}

static void
polygon_do_popup (Object_t       *obj,
                  GdkEventButton *event,
                  gpointer        data)
{
  gint       x   = get_real_coord ((gint) event->x);
  gint       y   = get_real_coord ((gint) event->y);
  GimpImap *imap = GIMP_IMAP (data);

  _current_obj = obj;

  if (polygon_near_sash (obj, x, y))
    {
      polygon_handle_popup (event, imap, TRUE, FALSE);
    }
  else
    {
      _insert_edge = polygon_near_edge (obj, x, y);
      if (_insert_edge)
        {
          _insert_x = x;
          _insert_y = y;

          polygon_handle_popup (event,imap, FALSE, TRUE);
        }
      else
        {
          object_do_popup (obj, event, imap);
        }
    }
}

static const gchar*
polygon_get_icon_name(void)
{
   return IMAP_POLYGON;
}

static GList *_prev_link;

static gboolean
polygon_factory_finish(Object_t *obj, gint x, gint y)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GdkPoint *prev_point = (GdkPoint*) _prev_link->data;

   if (x == prev_point->x && y == prev_point->y) {
      polygon_remove_last_point(polygon);
      return TRUE;
   } else {
      polygon_append_point(polygon, x, y);
      _prev_link = _prev_link->next;
   }
   return FALSE;
}

static gboolean
polygon_factory_cancel(GdkEventButton *event, Object_t *obj)
{
   if (event->state & GDK_SHIFT_MASK) {
      return TRUE;
   } else {
      Polygon_t *polygon = ObjectToPolygon(obj);
      GList *link = _prev_link;

      _prev_link = _prev_link->prev;
      g_free((GdkPoint*) link->data);
      polygon->points = g_list_remove_link(polygon->points, link);
   }
   return _prev_link == NULL;
}

static Object_t*
polygon_factory_create_object(gint x, gint y)
{
   GList *points;

   points = _prev_link = g_list_append(NULL, new_point(x, y));
   points = g_list_append(points, new_point(x, y));

   return create_polygon(points);
}

static void
polygon_factory_set_xy(Object_t *obj, guint state, gint x, gint y)
{
   Polygon_t *polygon = ObjectToPolygon(obj);
   GList *last = g_list_last(polygon->points);
   GdkPoint *point = (GdkPoint*) last->data;
   GdkPoint *prev = (GdkPoint*) last->prev->data;

   point->x = x;
   point->y = y;

   main_set_dimension(x - prev->x, y - prev->y);
}

static ObjectFactory_t polygon_factory = {
   NULL,                        /* Object pointer */
   polygon_factory_finish,
   polygon_factory_cancel,
   polygon_factory_create_object,
   polygon_factory_set_xy
};

ObjectFactory_t*
get_polygon_factory(guint state)
{
   return &polygon_factory;
}

void
polygon_remove_last_point(Polygon_t *polygon)
{
   GList *last = g_list_last(polygon->points);
   g_free((GdkPoint*) last->data);
   polygon->points = g_list_remove_link(polygon->points, last);
}

GdkPoint*
new_point(gint x, gint y)
{
   GdkPoint *point = g_new(GdkPoint, 1);
   point->x = x;
   point->y = y;
   return point;
}

void
polygon_append_point(Polygon_t *polygon, gint x, gint y)
{
  polygon->points = g_list_append(polygon->points, new_point(x, y));
}

Messung
CHZG
829510092

¤ Dauer der Verarbeitung: 0.4 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© 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=1104851
#Domains=417132