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

vdkb_widsel.c

/*
 * ===========================
 * VDK Builder
 * Version 0.1
 * Revision 0.5
 * August 1999
 * ===========================
 *
 * Copyright (C) 1998,1999 Mario Motta
 * Developed by Mario Motta <mmotta@guest.net>
 *
 * Based on VDK Library 
 * Copyright (C) 1998, Mario Motta
 *
 * This library 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 library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 =======================================
 WIDGET SELECTION STUFF
 (Some parts were shameless 
 stolen to Damon Chaplin, glade author)
 ======================================= 
*/
#include <stdio.h>
#include <string.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>

#define VERBOSE 0


const int CORNER_HEIGHT = 6;
const int CORNER_WIDTH = 6;
const int GRID_DOTS = 1;

/*
 */
GtkWidget *
get_event_widget (GtkWidget *widget, GdkWindow *window, gint x, gint y,
                   gint * x_return, gint * y_return);

GdkWindow*
get_widget_window (GtkWidget *parent, GtkWidget *widget);

void
paint_selection (GdkWindow * window, GdkGC * gc, gint x, gint y,
             gint width, gint height);
static void
clear_child_windows (GdkWindow * window, gint x, gint y, gint w, gint h);

void
clear_widget_selection (GtkWidget * widget);

void
clear_widget_area (GtkWidget * widget, gint x, gint y, gint w, gint h);

void
fixed_draw_grid (GtkWidget *widget, int grid_horz_spacing,
             int grid_vert_spacing,int grid_style);

/*
in <gp> there is signal name to stop
 */
void StopSignal(GtkWidget *wid, gpointer gp)
{
#if VERBOSE
  printf("\n::StopSignal()");
  fflush(stdout);
#endif
  g_return_if_fail(wid != NULL);
  g_return_if_fail(gp != NULL);
  gtk_signal_emit_stop_by_name(GTK_OBJECT(wid), (char*) gp);
}


GdkWindow*
get_widget_window (GtkWidget *parent, GtkWidget *widget)
{
  if (parent)
    return parent->window;
  return widget->window;
}

void
paint_selection (GdkWindow * window, GdkGC * gc, gint x, gint y,
             gint width, gint height)
{
  GdkGCValues  gc_values;
  // Paint the four corner handles, if there is enough room. 
  if (width > CORNER_WIDTH && height > CORNER_HEIGHT)
    {
      gdk_draw_rectangle (window, gc, TRUE,
                    x, y,
                    CORNER_WIDTH, CORNER_HEIGHT);
      gdk_draw_rectangle (window, gc, TRUE,
                    x, y + height - CORNER_HEIGHT,
                    CORNER_WIDTH, CORNER_HEIGHT);
      gdk_draw_rectangle (window, gc, TRUE,
                    x + width - CORNER_WIDTH, y,
                    CORNER_WIDTH, CORNER_HEIGHT);
      gdk_draw_rectangle (window, gc, TRUE,
                    x + width - CORNER_WIDTH,
                    y + height - CORNER_HEIGHT,
                    CORNER_WIDTH, CORNER_HEIGHT);
    }

  gdk_gc_get_values  (gc, &gc_values);
  //  Paint the box around the widget. 
  gdk_gc_set_line_attributes(gc,
                       gc_values.line_width,
                       GDK_LINE_ON_OFF_DASH,
                       gc_values.cap_style,
                       gc_values.join_style);
  gdk_draw_rectangle (window, gc, FALSE,
                  x, y, width - 1, height - 1);
  gdk_gc_set_line_attributes(gc,
                       gc_values.line_width,
                       gc_values.line_style,
                       gc_values.cap_style,
                       gc_values.join_style);
}
/* This clears all child windows which fall within the given rectangle.
   If the rectangle width is -1, then all children are cleared. */

void
clear_child_windows (GdkWindow * window, gint x, gint y, gint w, gint h)
{
  GList *children;
  GdkWindow *child_window;
  gint win_x, win_y, win_w, win_h;
  XWindowAttributes xwa;
  GdkRectangle area, child, intersection;

  area.x = x;
  area.y = y;
  area.width = w;
  area.height = h;

  children = gdk_window_get_children (window);
  while (children)
    {
      child_window = (GdkWindow *) children->data;
      gdk_window_get_position (child_window, &win_x, &win_y);
      gdk_window_get_size (child_window, &win_w, &win_h);

      child.x = win_x;
      child.y = win_y;
      child.width = win_w;
      child.height = win_h;

      if (gdk_rectangle_intersect (&area, &child, &intersection))
      {
        /* We need to make sure this is not an InputOnly window, or we get
           a BadMatch. CList uses InputOnly windows - for resizing columns.
           FIXME: This may not be very efficient. */
        XGetWindowAttributes (GDK_DISPLAY (),
                        GDK_WINDOW_XWINDOW (child_window),
                        &xwa);
        if (xwa.class != InputOnly)
          {
            /* Convert to the child's coordinate space. */
            intersection.x -= child.x;
            intersection.y -= child.y;
            gdk_window_clear_area (child_window,
                             intersection.x, intersection.y,
                             intersection.width, intersection.height);
            clear_child_windows (child_window,
                           intersection.x, intersection.y,
                           intersection.width, intersection.height);
          }
      }
      children = children->next;
    }
  g_list_free (children);
}

void
clear_widget_selection (GtkWidget * widget)
{
  gint x, y, w, h;

  x = widget->allocation.x;
  y = widget->allocation.y;
  w = widget->allocation.width;
  h = widget->allocation.height;

  /* Don't try to refresh an area if the width or height is 0. */
  if (w == 0 || h == 0)
    return;

  /* Clear the four corners. */
  clear_widget_area (widget,
                        x, y,
                        CORNER_WIDTH, CORNER_HEIGHT);
  clear_widget_area (widget,
                 x, y + h - CORNER_HEIGHT,
                 CORNER_WIDTH, CORNER_HEIGHT);
  clear_widget_area (widget,
                 x + w - CORNER_WIDTH, y,
                 CORNER_WIDTH, CORNER_HEIGHT);
  clear_widget_area (widget,
                 x + w - CORNER_WIDTH,
                 y + h - CORNER_HEIGHT,
                 CORNER_WIDTH, CORNER_HEIGHT);
  /* Clear the four lines along the edges. */
  clear_widget_area (widget,
                 x + CORNER_WIDTH, y,
                 w - 2 * CORNER_WIDTH, 1);
  clear_widget_area (widget,
                 x + CORNER_WIDTH, y + h - 1,
                 w - 2 * CORNER_WIDTH, 1);
  clear_widget_area (widget,
                 x, y + CORNER_HEIGHT,
                 1, h - 2 * CORNER_HEIGHT);
  clear_widget_area (widget,
                 x + w - 1,
                 y + CORNER_HEIGHT,
                 1, h - 2 * CORNER_HEIGHT);
  gtk_widget_draw (widget, NULL);
}


void
clear_widget_area (GtkWidget * widget, gint x, gint y, gint w, gint h)
{
  GdkWindow *window;
  GdkRectangle area;

  area.x = x;
  area.y = y;
  area.width = w;
  area.height = h;

  if (!GTK_WIDGET_DRAWABLE (widget))
    return;

  /* Don't try to refresh an area if the width or height is 0. */
  if (w == 0 || h == 0)
    return;

  window = get_widget_window (widget->parent, widget);
  if (widget->parent)
    {
      gdk_window_clear_area (window, x, y, w, h);
      clear_child_windows (window, x, y, w, h);
    }
  else
    {
      gdk_window_clear_area (window, x, y, w, h);
      clear_child_windows (window, x, y, w, h);
    }
}

/*
draw grid into fixed
*/
void
fixed_draw_grid (GtkWidget * widget,
             int grid_horz_spacing,
             int grid_vert_spacing,
             int grid_style)
{

  GdkGC *gc = NULL;
  int width =  0,height = 0;
  int gridx = 0, gridy = 0;
  
  // g_return_if_fail(!GTK_OBJECT_DESTROYED(GTK_OBJECT(widget)));
  g_return_if_fail(GTK_IS_WIDGET(widget));

  gc = widget->style->dark_gc[GTK_STATE_NORMAL];
  width = widget->allocation.width;
  height = widget->allocation.height;
  if (grid_style == GRID_DOTS)
    {
      for (gridx = 0; gridx < width; gridx += grid_horz_spacing)
      {
        for (gridy = 0; gridy < height; gridy += grid_vert_spacing)
          gdk_draw_point (widget->window, gc, gridx, gridy);
      }
    }
  else
    {
      for (gridx = 0; gridx < width; gridx += grid_horz_spacing)
      gdk_draw_line (widget->window, gc, gridx, 0, gridx, height);
      for (gridy = 0; gridy < height; gridy += grid_vert_spacing)
      gdk_draw_line (widget->window, gc, 0, gridy, width, gridy);
    }
}



/* 
   This function is passed a widget which has received a mouse event, and
   the coordinates of that event. It returns the widget which the event is
   really meant for (which could be a descendent of the given widget), and
   the position of the event in the widget's allocated area. 
*/
/* Struct only used for find_child_at callback */
typedef struct _GbFindChildAtData GbFindChildAtData;
struct _GbFindChildAtData
  {
    gint x;
    gint y;
    GtkWidget *found_child;
  };
/* Note: returns last found child if children overlap */
static void
find_child_at (GtkWidget * widget, GbFindChildAtData * data)
{
#if VERBOSE
  printf ("\nIn find_child_at: %s X:%i Y:%i W:%i H:%i",
         gtk_widget_get_name (widget),
         widget->allocation.x, widget->allocation.y,
         widget->allocation.width, widget->allocation.height);
  fflush(stdout);
#endif
  /* Notebook pages are visible but not mapped if they are not showing. */
  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)
      && (widget->allocation.x <= data->x)
      && (widget->allocation.y <= data->y)
      && (widget->allocation.x + widget->allocation.width > data->x)
      && (widget->allocation.y + widget->allocation.height > data->y))
    {
#if VERBOSE
      printf ("found child:%s", gtk_widget_get_name (widget));
      fflush(stdout);
#endif
      data->found_child = widget;
    }
}

GtkWidget *
get_event_widget (GtkWidget *widget, GdkWindow *window, gint x, gint y,
                   gint * x_return, gint * y_return)
{
  GbFindChildAtData data;
  gint win_x, win_y;
  GtkWidget *found_gbwidget = NULL;
  gint found_x = 0, found_y = 0;
  GdkWindow *parent_window;

#if VERBOSE
  printf ("\nOriginal:%s X:%i Y:%i", gtk_widget_get_name (widget), x, y);
  if (widget->parent)
    printf ("\nParent: %s", gtk_widget_get_name (widget->parent));
  fflush(stdout);
#endif

  /* FIXME: GTK bug workaround? - need to translate coords if mouse button was
     pressed in a child window. */
  /* Remember widgets can have other windows besides their main one, and
     when dragging the event may be sent to the parent's window? */
  parent_window = widget->parent ? widget->parent->window : widget->window;
  while (window && window != parent_window)
    {
      gdk_window_get_position (window, &win_x, &win_y);
      x += win_x;
      y += win_y;
      window = gdk_window_get_parent (window);
    }
  if (window != parent_window)
    return NULL;

  /* We now have correct coordinates relative to the parent's window.
     Now we find out which widget this event is really for.
     We step down the widget tree, trying to find the widget at the given
     position. We have to translate coordinates for children of widgets with
     windows. We may need to use bin_window for viewport. */
  if (1 /*GB_IS_GB_WIDGET (widget) || GB_IS_PLACEHOLDER (widget)*/)
    {
      found_gbwidget = widget;
      found_x = x;
      found_y = y;
    }
  /* I've added this mainly for the Combo widget's Entry. We don't want the
     Entry to get the signal first as it will add a grab which messes up
     our popup menu code. Before I added this we were letting the signal
     continue up the hierarchy, so the Entry got it first. */
  else if (widget->parent /*&& GB_IS_GB_WIDGET (widget->parent)*/
         && GTK_WIDGET_NO_WINDOW (widget->parent))
    {
      found_gbwidget = widget->parent;
      found_x = x;
      found_y = y;
    }

  if (!GTK_WIDGET_NO_WINDOW (widget) && widget->parent)
    {
      /* SPECIAL CODE: use bin_window for viewport. */
      if (GTK_IS_VIEWPORT (widget))
      window = GTK_VIEWPORT (widget)->bin_window;
      else
      window = widget->window;
      gdk_window_get_position (window, &win_x, &win_y);
      x -= win_x;
      y -= win_y;
    }

  for (;;)
    {
      if (!GTK_IS_CONTAINER (widget) || GTK_IS_MENU_BAR (widget))
      break;
      data.x = x;
      data.y = y;
      data.found_child = NULL;
      gtk_container_foreach (GTK_CONTAINER (widget),
                       (GtkCallback) find_child_at, &data);
      /* SPECIAL CODE - Check for notebook tabs. */
      if (GTK_IS_NOTEBOOK (widget))
      ; //find_notebook_tab (widget, &data);

      if (data.found_child)
      {
#if VERBOSE
        printf ("\nFound child:%s", 
              gtk_widget_get_name (data.found_child));
        fflush(stdout);
#endif
        widget = data.found_child;
        if (1 /*GB_IS_GB_WIDGET (widget) || GB_IS_PLACEHOLDER (widget)*/)
          {
            found_gbwidget = widget;
            found_x = x;
            found_y = y;
          }
      }
      else
      break;

      if (!GTK_WIDGET_NO_WINDOW (widget))
      {
        /* SPECIAL CODE; use bin_window for viewport. */
        if (GTK_IS_VIEWPORT (widget))
          window = GTK_VIEWPORT (widget)->bin_window;
        else
          window = widget->window;
        gdk_window_get_position (window, &win_x, &win_y);
        x -= win_x;
        y -= win_y;
      }
    }

  if (!found_gbwidget)
    return NULL;

  *x_return = found_x - found_gbwidget->allocation.x;
  *y_return = found_y - found_gbwidget->allocation.y;

#if VERBOSE
  printf ("\nEvent widget: %s X:%i Y:%i",
        gtk_widget_get_name (found_gbwidget), *x_return, *y_return);
  fflush(stdout);
#endif

  return found_gbwidget;
}

Generated by  Doxygen 1.6.0   Back to index