/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#include "arch.hh"
#include "window/dragwin.hh"
#include "device/kernel.hh"
#include "error/error.hh"
#include "window/win_evt.hh"
#include "area/rectlist.hh"
#include "image/image.hh"

class i4_drag_frame_class : public i4_window_class
{
  i4_coord ghost_x,ghost_y;

  public :
  i4_bool need_remove_ghost,
    draw_self;

  char *name() { return "drag_frame"; }

  i4_drag_frame_class(w16 w, w16 h) : 
    i4_window_class(w,h)
  {
    need_remove_ghost=i4_F;
    draw_self=i4_T;
  }

  virtual void draw(i4_draw_context_class &context)
  {
    // this draw is special in that it should not be subject to clipping and
    // window coordinate transformations

    i4_rect_list_class no_clip(0,0,local_image->width()-1,local_image->height()-1);
    context.clip.swap(&no_clip);
    i4_coord old_xoff=context.xoff,old_yoff=context.yoff;
    context.xoff=0;
    context.yoff=0;

    if (need_remove_ghost)
    {
      i4_coord x1=ghost_x,y1=ghost_y;
      i4_coord x2=x1+width()-1,y2=y1+height()-1;

      i4_color c=0xffffffff;

      local_image->xor_bar(x1,y1,x2,y1,c,context);
      local_image->xor_bar(x2,y1,x2,y2,c,context);
      local_image->xor_bar(x1,y1,x1,y2,c,context);
      local_image->xor_bar(x1,y2,x2,y2,c,context);      
    }

    if (draw_self)
    {
      i4_coord x1=x(),y1=y();
      i4_coord x2=x1+width()-1,y2=y1+height()-1;
      i4_color c=0xffffffff;

      local_image->xor_bar(x1,y1,x2,y1,c,context);
      local_image->xor_bar(x2,y1,x2,y2,c,context);
      local_image->xor_bar(x1,y1,x1,y2,c,context);
      local_image->xor_bar(x1,y2,x2,y2,c,context);
      ghost_x=x();
      ghost_y=y();
    }
    draw_self=i4_T;
    need_remove_ghost=i4_T;

    context.xoff=old_xoff;
    context.yoff=old_yoff;
    context.clip.swap(&no_clip);
  }

  virtual void show_self(w32 indent) 
  {    
    char fmt[50];
    sprintf(fmt,"%%%ds drag_window",indent);
    i4_warning(fmt," ");
  }

} ;


i4_draggable_window_class::i4_draggable_window_class(w16 w, w16 h) : i4_parent_window_class(w,h)
{
  drag_frame=0;
  last_mouse_x=0;
  last_mouse_y=0;
}

void i4_draggable_window_class::receive_event(i4_event *ev)
{
  if (ev->type()==i4_event::WINDOW_MESSAGE)
  {
    CAST_PTR(message,i4_window_request_drag_start_class,ev);
    // must have a parent in order to move/be dragged
    if (message->sub_type==i4_window_message_class::REQUEST_DRAG_START && parent)  
    {
      // see if we can grab the mouse     
      i4_window_request_mouse_grab_class grab(message->from());

      // ask ourself, we will check with our parent..
      i4_kernel.send_event(this,&grab);

      if (grab.return_result)
      {
        drag_frame=new i4_drag_frame_class(width(),height());
        parent->add_child(x(),y(),drag_frame);
        
        message->return_result=i4_T;      
      }
      else 
      {
        message->return_result=i4_F;
        i4_warning("draggable window:: unable to grab mouse");
      } 
    }
    // must have a parent in order to move/be dragged
    else if (message->sub_type==i4_window_message_class::REQUEST_DRAG_END && parent)  
    {
      if (!drag_frame)
        i4_error("got drag end message and not dragging");

      i4_window_request_mouse_ungrab_class ungrab(this);
      i4_kernel.send_event(this,&ungrab);

      // move ourself to the final position of the drag frame
      move(drag_frame->x()-x(),drag_frame->y()-y());
      request_redraw();

      // tell ourselves to delete the dragger next tick, 
      // so it gets a chance to clear itself off the screen
      i4_kernel.delete_handler(drag_frame);

      drag_frame->need_remove_ghost=i4_T;
      drag_frame->draw_self=i4_F;
      drag_frame=0;   // assume it is deleted now
    }
    else i4_parent_window_class::receive_event(ev);
  } else if (ev->type()==i4_event::MOUSE_MOVE)
  { 
    CAST_PTR(move,i4_mouse_move_event_class,ev);
    current_mouse_x=move->x+x();
    current_mouse_y=move->y+y();
    if (drag_frame &&
	((current_mouse_x!=last_mouse_x ||
          current_mouse_y!=last_mouse_y)))
    {
      if (current_mouse_x<0)
        current_mouse_x=0;
      if (current_mouse_y<0)
        current_mouse_y=0;
      i4_coord xo=current_mouse_x-last_mouse_x,yo=current_mouse_y-last_mouse_y;
      drag_frame->move(xo,yo,i4_F);
      drag_frame->request_redraw();
    }

    last_mouse_x=current_mouse_x;
    last_mouse_y=current_mouse_y;
    i4_parent_window_class::receive_event(ev);
  } else i4_parent_window_class::receive_event(ev);
}