/*
 * $Id: gtkhost.c,v 1.15 1998/11/24 23:47:23 gregm Exp $
 * GTKEXT - Extensions to The GIMP Toolkit
 * Copyright (C) 1998 Gregory McLean
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library 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, Cambridge, MA 
 * 02139, USA.
 *
 * Host Widget
 */

#include "gtkhost.h"
#include <gtk/gtkhseparator.h>
#include <gtk/gtksignal.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkbox.h>
#include <gtk/gtkvbox.h>

enum {
  PRESSED,
  RELEASED,
  ENTER,
  LEAVE,
  LAST_SIGNAL
};

#define CHILD_SPACING     1
#define DEFAULT_LEFT_POS  4
#define DEFAULT_TOP_POS   4
#define DEFAULT_SPACING   7

static void       gtk_host_class_init       (GtkHostClass     *klass);
static void       gtk_host_init             (GtkHost          *host);

static void       gtk_host_size_request     (GtkWidget        *widget,
					     GtkRequisition   *area);
static void       gtk_host_size_allocate    (GtkWidget        *widget,
					     GtkAllocation    *area);
static void       gtk_host_draw             (GtkWidget        *widget,
					     GdkRectangle     *area);
static void       gtk_host_draw_focus       (GtkWidget        *widget);
static void       gtk_host_draw_default     (GtkWidget        *widget);
static void       gtk_host_paint            (GtkWidget        *widget,
					     GdkRectangle     *area);
static void       gtk_host_map              (GtkWidget        *widget);
static void       gtk_host_unmap            (GtkWidget        *widget);
static void       gtk_host_realize          (GtkWidget        *widget);
static gint       gtk_host_expose           (GtkWidget        *widget,
					     GdkEventExpose   *event);
static gint       gtk_host_enter_notify     (GtkWidget        *widget,
					     GdkEventCrossing *event);
static gint       gtk_host_leave_notify     (GtkWidget        *widget,
					     GdkEventCrossing *event);
static gint       gtk_host_press            (GtkWidget        *widget,
					     GdkEventButton   *event);
static void       gtk_host_real_leave       (GtkHost          *host);
static void       gtk_host_real_enter       (GtkHost          *host);

/*
 * Container functions 
 */
static void       gtk_host_add              (GtkContainer     *container,
					     GtkWidget        *widget);
static void       gtk_host_remove           (GtkContainer     *container,
					     GtkWidget        *widget);
static void       gtk_host_forall           (GtkContainer     *container,
					     gboolean	       include_internals,
					     GtkCallback       callback,
					     gpointer          callback_data);

static GtkContainerClass *parent_class;
static guint host_signals[LAST_SIGNAL] = { 0 };

guint
gtk_host_get_type ()
{
  static guint host_type = 0;

  if (!host_type)
    {
      GtkTypeInfo host_info = {
	"GtkHost",
	sizeof (GtkHost),
	sizeof (GtkHostClass),
	(GtkClassInitFunc) gtk_host_class_init,
	(GtkObjectInitFunc) gtk_host_init,
	(GtkArgSetFunc) NULL,
	(GtkArgGetFunc) NULL
      };
      host_type = gtk_type_unique (gtk_container_get_type (), 
				       &host_info);
    }
  return host_type;
}

static void
gtk_host_class_init (GtkHostClass *class)
{
  GtkObjectClass    *object_class;
  GtkWidgetClass    *widget_class;
  GtkContainerClass *container_class;

  object_class    = (GtkObjectClass *) class;
  widget_class    = (GtkWidgetClass *) class;
  container_class = (GtkContainerClass *) class;

  parent_class = gtk_type_class (gtk_container_get_type ());

  host_signals[PRESSED] = 
    gtk_signal_new ("pressed",
		    GTK_RUN_FIRST,
		    object_class->type,
		    GTK_SIGNAL_OFFSET (GtkHostClass, pressed),
		    gtk_signal_default_marshaller,
		    GTK_TYPE_NONE, 0);
  host_signals[ENTER] = 
    gtk_signal_new ("enter",
		    GTK_RUN_FIRST,
		    object_class->type,
		    GTK_SIGNAL_OFFSET (GtkHostClass, enter),
		    gtk_signal_default_marshaller,
		    GTK_TYPE_NONE, 0);
  host_signals[LEAVE] = 
    gtk_signal_new ("leave",
		    GTK_RUN_FIRST,
		    object_class->type,
		    GTK_SIGNAL_OFFSET (GtkHostClass, leave),
		    gtk_signal_default_marshaller,
		    GTK_TYPE_NONE, 0);

  gtk_object_class_add_signals (object_class, host_signals, LAST_SIGNAL);


  widget_class->size_request       = gtk_host_size_request;
  widget_class->size_allocate      = gtk_host_size_allocate;
  widget_class->realize            = gtk_host_realize;
  widget_class->draw               = gtk_host_draw;
  widget_class->draw_default       = gtk_host_draw_default;
  widget_class->map                = gtk_host_map;
  widget_class->unmap              = gtk_host_unmap;
  widget_class->draw_focus         = gtk_host_draw_focus;
  widget_class->enter_notify_event = gtk_host_enter_notify;
  widget_class->leave_notify_event = gtk_host_leave_notify;
  widget_class->button_press_event = gtk_host_press;
  widget_class->expose_event       = gtk_host_expose;

  container_class->add             = gtk_host_add;
  container_class->remove          = gtk_host_remove;
//  container_class->forall         = gtk_host_forall;

  class->enter = gtk_host_real_enter;
  class->leave = gtk_host_real_leave;
}

static void
gtk_host_init (GtkHost *host)
{
  GTK_WIDGET_SET_FLAGS (host, GTK_CAN_FOCUS);

  host->child        = NULL;
  host->snmp_enabled = TRUE;
  host->host_state   = 0;
  host->snmp_request = 0;
  host->host_datum   = NULL;
}

static gint
gtk_host_expose (GtkWidget      *widget,
		 GdkEventExpose *event)
{
  GtkHost *host;
  GdkEventExpose child_event;

  g_return_val_if_fail (widget != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_HOST (widget), FALSE);
  g_return_val_if_fail (event != NULL, FALSE);

  if (GTK_WIDGET_DRAWABLE (widget))
    {
      host = GTK_HOST (widget);

      gtk_host_paint (widget, &event->area);

      child_event = *event;
      if (host->child && GTK_WIDGET_NO_WINDOW (host->child) &&
          gtk_widget_intersect (host->child, &event->area, &child_event.area))
	gtk_widget_event (host->child, (GdkEvent*) &child_event);

      gtk_widget_draw_default (widget);
      gtk_widget_draw_focus (widget);
    }

  return FALSE;

}

static gint
gtk_host_enter_notify (GtkWidget        *widget,
		       GdkEventCrossing *event)
{
  GtkHost   *host;
  GtkWidget *event_widget;

  g_return_val_if_fail (widget != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_HOST (widget), FALSE);
  g_return_val_if_fail (event != NULL, FALSE);

  host = GTK_HOST (widget);
  event_widget = gtk_get_event_widget ((GdkEvent *) event);

  if ((event_widget == widget) &&
      (event->detail != GDK_NOTIFY_INFERIOR))
    {
      gtk_host_enter (host);
    }
  return FALSE;
}

static gint
gtk_host_leave_notify (GtkWidget        *widget,
		       GdkEventCrossing *event)
{
/*  g_print ("Host Leave Notify.\n"); */
  return FALSE;
}

static gint
gtk_host_press (GtkWidget      *widget,
		GdkEventButton *event)
{
  GtkHost *host;

  g_return_val_if_fail (widget != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_HOST (widget), FALSE);
  g_return_val_if_fail (event != NULL, FALSE);

  if (event->type == GDK_BUTTON_PRESS)
    {
      host = GTK_HOST (widget);
      gtk_host_pressed (host);
    }
  return TRUE;
}

static void
gtk_host_real_enter (GtkHost *host)
{
/*  g_print ("Real Enter\n"); */
}

static void 
gtk_host_real_leave (GtkHost *host)
{
 /* g_print ("Real Leave\n"); */
}

static void
gtk_host_realize (GtkWidget *widget)
{
  GtkHost       *host;
  GdkWindowAttr attributes;
  gint attributes_mask;
  gint border_width;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_HOST (widget));


  host = GTK_HOST (widget);
  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
  border_width = GTK_CONTAINER (widget)->border_width;
  
  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.width       = widget->allocation.width - border_width * 2;
  attributes.height      = widget->allocation.height - border_width * 2;
  attributes.x           = widget->allocation.x + border_width;
  attributes.y           = widget->allocation.y + border_width;
  attributes.wclass      = GDK_INPUT_OUTPUT;
  attributes.visual      = gtk_widget_get_visual (widget);
  attributes.colormap    = gtk_widget_get_colormap (widget);
  attributes.event_mask  = gtk_widget_get_events (widget);
  attributes.event_mask  |= (GDK_EXPOSURE_MASK |
			     GDK_BUTTON_PRESS_MASK |
			     GDK_BUTTON_RELEASE_MASK |
			     GDK_ENTER_NOTIFY_MASK |
			     GDK_LEAVE_NOTIFY_MASK);
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
				   &attributes, attributes_mask);
  gdk_window_set_user_data (widget->window, host);

  widget->style = gtk_style_attach (widget->style, widget->window);
  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
}

static void 
gtk_host_size_request (GtkWidget      *widget,
		       GtkRequisition *requisition)
{
  GtkHost *host;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_HOST (widget));
  g_return_if_fail (requisition != NULL);

  host = GTK_HOST (widget);

  requisition->width = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
                        GTK_WIDGET (widget)->style->klass->xthickness) * 2;
  requisition->height = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
                         GTK_WIDGET (widget)->style->klass->ythickness) * 2;

  if (GTK_WIDGET_CAN_DEFAULT (widget))
    {
      requisition->width += (GTK_WIDGET 
			     (widget)->style->klass->xthickness * 2 +
                             DEFAULT_SPACING);
      requisition->height += (GTK_WIDGET 
			      (widget)->style->klass->ythickness * 2 +
                              DEFAULT_SPACING);
    }



  if (host->child && GTK_WIDGET_VISIBLE (host->child))
    {
      gtk_widget_size_request (host->child, &host->child->requisition);

      requisition->width += host->child->requisition.width;
      requisition->height += host->child->requisition.height;
    }

}

static void
gtk_host_size_allocate (GtkWidget     *widget,
			GtkAllocation *allocation)
{
  GtkHost       *host;
  GtkAllocation child_allocation;
  gint          border_width;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_HOST (widget));
  g_return_if_fail (allocation != NULL);

  widget->allocation = *allocation;
  border_width = GTK_CONTAINER (widget)->border_width;

  if (GTK_WIDGET_REALIZED (widget))
    gdk_window_move_resize (widget->window,
			    widget->allocation.x + border_width,
			    widget->allocation.y + border_width,
			    widget->allocation.width - border_width * 2,
			    widget->allocation.height - border_width * 2);
  host = GTK_HOST (widget);
  if (host->child && GTK_WIDGET_VISIBLE (host->child))
    {
      child_allocation.x = GTK_WIDGET (widget)->style->klass->xthickness;
      child_allocation.y = GTK_WIDGET (widget)->style->klass->ythickness;
      child_allocation.width = MAX (1, widget->allocation.width - 
				    child_allocation.x * 2 - border_width * 2);
      child_allocation.height = MAX (1, widget->allocation.height - 
				     child_allocation.y * 2 - border_width *2);
      if (GTK_WIDGET_CAN_DEFAULT (host))
        {
          child_allocation.x += (GTK_WIDGET (widget)->style->klass->xthickness +
                                 DEFAULT_LEFT_POS);
          child_allocation.y += (GTK_WIDGET (widget)->style->klass->ythickness +
                                 DEFAULT_TOP_POS);
          child_allocation.width -= (GTK_WIDGET (widget)->style->klass->xthickness * 2 +
                                     DEFAULT_SPACING);
          child_allocation.height -= (GTK_WIDGET (widget)->style->klass->xthickness * 2 +
                                      DEFAULT_SPACING);

	}
      gtk_widget_size_allocate (host->child, &child_allocation);
    }
}

static void 
gtk_host_draw (GtkWidget    *widget, 
	       GdkRectangle *area)
{
  GtkHost *host;
  GdkRectangle child_area;
  GdkRectangle tmp_area;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_HOST (widget));
  g_return_if_fail (area != NULL);

  if (GTK_WIDGET_DRAWABLE (widget))
    {
      host = GTK_HOST (widget);

      tmp_area = *area;
      tmp_area.x -= GTK_CONTAINER (host)->border_width;
      tmp_area.y -= GTK_CONTAINER (host)->border_width;

      gtk_host_paint (widget, &tmp_area);

      if (host->child && gtk_widget_intersect (host->child, &tmp_area, &child_area))
        gtk_widget_draw (host->child, &child_area);

      gtk_widget_draw_default (widget);
      gtk_widget_draw_focus (widget);
    }
}
static void
gtk_host_draw_default (GtkWidget *widget)
{
  gint width, height;
  gint x, y;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_HOST (widget));

  if (GTK_WIDGET_DRAWABLE (widget))
    {
      x = 0;
      y = 0;
      width  = widget->allocation.width - 
	       GTK_CONTAINER (widget)->border_width * 2;
      height = widget->allocation.height - 
	       GTK_CONTAINER (widget)->border_width * 2;

      if (GTK_WIDGET_HAS_DEFAULT (widget))
        {
          gtk_draw_shadow (widget->style, widget->window,
                           GTK_STATE_NORMAL, GTK_SHADOW_IN,
                           x, y, width, height);
        }
      else
        {
          gdk_draw_rectangle (widget->window, 
			      widget->style->bg_gc[GTK_STATE_NORMAL],
                              FALSE, x, y, width - 1, height - 1);
          gdk_draw_rectangle (widget->window, 
			      widget->style->bg_gc[GTK_STATE_NORMAL],
                              FALSE, x + 1, y + 1, width - 3, height - 3);
        }
    }

}

static void
gtk_host_paint (GtkWidget     *widget,
		GdkRectangle  *area)
{
  GdkRectangle restrict_area;
  GdkRectangle new_area;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_HOST (widget));

  if (GTK_WIDGET_DRAWABLE (widget))
    {
      restrict_area.x = GTK_WIDGET (widget)->style->klass->xthickness;
      restrict_area.y = GTK_WIDGET (widget)->style->klass->ythickness;
      restrict_area.width = (GTK_WIDGET (widget)->allocation.width -
			     restrict_area.x * 2 -
                             GTK_CONTAINER (widget)->border_width * 2);
      restrict_area.height = (GTK_WIDGET (widget)->allocation.height - 
			      restrict_area.y * 2 -
                              GTK_CONTAINER (widget)->border_width * 2);

      if (GTK_WIDGET_CAN_DEFAULT (widget))
        {
          restrict_area.x += DEFAULT_LEFT_POS;
          restrict_area.y += DEFAULT_TOP_POS;
          restrict_area.width -= DEFAULT_SPACING;
          restrict_area.height -= DEFAULT_SPACING;
        }

      if (gdk_rectangle_intersect (area, &restrict_area, &new_area))
        {
          gtk_style_set_background (widget->style, widget->window,
                                    GTK_WIDGET_STATE (widget));
          gdk_window_clear_area (widget->window,
                                 new_area.x, new_area.y,
                                 new_area.width, new_area.height);
        }
    }
}

static void
gtk_host_draw_focus (GtkWidget *widget)
{
  GtkHost *host;
  GtkShadowType shadow_type;
  gint width, height;
  gint x, y;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_HOST (widget));

  if (GTK_WIDGET_DRAWABLE (widget))
    {
      host = GTK_HOST (widget);

      x = 0;
      y = 0;
      width = widget->allocation.width - GTK_CONTAINER
        (widget)->border_width * 2;
      height = widget->allocation.height - GTK_CONTAINER
        (widget)->border_width * 2;

      if (GTK_WIDGET_CAN_DEFAULT (widget))
        {

          x += widget->style->klass->xthickness;
          y += widget->style->klass->ythickness;
          width -= 2 * x + DEFAULT_SPACING;
          height -= 2 * y + DEFAULT_SPACING;
          x += DEFAULT_LEFT_POS;
          y += DEFAULT_TOP_POS;
        }

      if (GTK_WIDGET_HAS_FOCUS (widget))
        {
          x += 1;
          y += 1;
          width -= 2;
          height -= 2;
        }
      else
        {
          if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
            gdk_draw_rectangle (widget->window,
                                widget->style->bg_gc[GTK_WIDGET_STATE
                                                    (widget)], FALSE,
                                x + 1, y + 1, width - 4, height - 4);

          else
            gdk_draw_rectangle (widget->window,
                                widget->style->bg_gc[GTK_WIDGET_STATE
                                                    (widget)], FALSE,
                                x + 2, y + 2, width - 5, height - 5);
        }

      if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
        shadow_type = GTK_SHADOW_IN;
      else
        shadow_type = GTK_SHADOW_OUT;

      gtk_draw_shadow (widget->style, widget->window,
                       GTK_WIDGET_STATE (widget), shadow_type,
                       x, y, width, height);

      if (GTK_WIDGET_HAS_FOCUS (widget))
        {
          x -= 1;
          y -= 1;
          width += 2;
          height += 2;

          gdk_draw_rectangle (widget->window,
                              widget->style->black_gc, FALSE,
                              x, y, width - 1, height - 1);
        }
    }
}

static void
gtk_host_map (GtkWidget *widget)
{
  GtkHost   *host;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_HOST (widget));
  
  GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
  gdk_window_show (widget->window);

  host = GTK_HOST (widget);
  
  if (host->child &&
      GTK_WIDGET_VISIBLE (host->child) &&
      !GTK_WIDGET_MAPPED (host->child))
    gtk_widget_map (host->child);

}

static void
gtk_host_unmap (GtkWidget *widget)
{
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_BUTTON (widget));

  GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
  gdk_window_hide (widget->window);
}

/*
 * Container functions
 */
static void
gtk_host_add (GtkContainer *container,
                GtkWidget    *widget)
{
  GtkHost *host;

  g_return_if_fail (container != NULL);
  g_return_if_fail (GTK_IS_HOST (container));
  g_return_if_fail (widget != NULL);

  host = GTK_HOST (container);
  
  if (!host->child)
    {
      gtk_widget_set_parent (widget, GTK_WIDGET (container));

      if (GTK_WIDGET_VISIBLE (widget->parent))
        {
          if (GTK_WIDGET_REALIZED (widget->parent) &&
              !GTK_WIDGET_REALIZED (widget))
            gtk_widget_realize (widget);

          if (GTK_WIDGET_MAPPED (widget->parent) &&
              !GTK_WIDGET_MAPPED (widget))
            gtk_widget_map (widget);
        }

      host->child = widget;

      if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
        gtk_widget_queue_resize (widget);
    }
}

static void
gtk_host_remove (GtkContainer *container,
		 GtkWidget    *widget)
{
  GtkHost *host;

  g_return_if_fail (container != NULL);
  g_return_if_fail (GTK_IS_HOST (container));
  g_return_if_fail (widget != NULL);

  host = GTK_HOST (container);
  

  if (host->child == widget)
    {
      gboolean widget_was_visible = GTK_WIDGET_VISIBLE(widget);

      gtk_widget_unparent (widget);

      host->child = NULL;

      if (widget_was_visible && GTK_WIDGET_VISIBLE (container))
        gtk_widget_queue_resize (GTK_WIDGET (container));

    }
}

static void
gtk_host_forall (GtkContainer *container,
		 gboolean      include_internals,
		 GtkCallback   callback,
		 gpointer      callback_data)
{
  GtkHost *host;

  g_return_if_fail (container != NULL);
  g_return_if_fail (GTK_IS_HOST (container));
  g_return_if_fail (callback != NULL);

  host = GTK_HOST (container);
  if (host->child)
    (* callback) (host->child, callback_data);
}

/*
 * Public functions
 */
void
gtk_host_enter (GtkHost *host)
{
  gtk_signal_emit (GTK_OBJECT (host), host_signals[ENTER]);
}

void 
gtk_host_leave (GtkHost *host)
{
  gtk_signal_emit (GTK_OBJECT (host), host_signals[LEAVE]);
}

void
gtk_host_pressed (GtkHost *host)
{
  gtk_signal_emit (GTK_OBJECT (host), host_signals[PRESSED]);
}

GtkWidget *
gtk_host_new ()
{
  return GTK_WIDGET (gtk_type_new (gtk_host_get_type ()));
}

GtkWidget *
gtk_host_new_with_label (const gchar *label)
{
  GtkWidget *widget;
  GtkHost   *host;

  widget = gtk_host_new ();
  host = GTK_HOST (widget);
  host->vbox = gtk_vbox_new (FALSE, 2);
  host->label = gtk_label_new (label);
  gtk_container_add (GTK_CONTAINER (widget), host->vbox);
  gtk_box_pack_end (GTK_BOX (host->vbox), host->label, FALSE, FALSE, 0);
  gtk_widget_show_all (host->vbox);

  return widget;
}

void
gtk_host_set_label (GtkWidget *host, const gchar *label)
{
}

void
gtk_host_set_pixmap (GtkWidget *widget, GtkWidget *pixmap)
{
  GtkHost   *host;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_HOST (widget));

  host = GTK_HOST (widget);
  if (!host->pixmap)
    {
      host->pixmap = pixmap;
      gtk_box_pack_start (GTK_BOX (host->vbox), host->pixmap, FALSE, FALSE, 1);
      gtk_widget_show (host->pixmap);
    }
  else
    {
      host->pixmap = pixmap;
    }
}

void
gtk_host_led_toggle (GtkWidget *host)
{
}


