/*
 * FIG : Facility for Interactive Generation of figures
 * Copyright (c) 1985-1988 by Supoj Sutanthavibul
 * Parts Copyright (c) 1989-2015 by Brian V. Smith
 * Parts Copyright (c) 1991 by Paul King
 * Parts Copyright (c) 1994 by Bill Taylor
 *       "Enter Compound" written by Bill Taylor (bill@mainstream.com) 1994
 * Parts Copyright (c) 2016-2023 by Thomas Loimer
 *
 * Any party obtaining a copy of these files is granted, free of charge, a
 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
 * nonexclusive right and license to deal in this software and documentation
 * files (the "Software"), including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
 * the Software, and to permit persons who receive copies from any such
 * party to do so, with the only requirement being that the above copyright
 * and this permission notice remain intact.
 *
 */

/*
 * open_compound lets the user select a compound with the left button,
 * then replaces the current drawing with that compound alone so that the
 * user can edit the insides of that compound without taking it apart.
 *
 * close_compound pops out one compound;
 * close_all_compounds pops all the way out.
 *
 */

#include "e_compound.h"

#include <stdlib.h>
#include <X11/Intrinsic.h>     /* includes X11/Xlib.h, which includes X11/X.h */
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <X11/Xatom.h>		/* XA_STRING */

#include "figx.h"
#include "resources.h"
#include "mode.h"
#include "object.h"
#include "e_scale.h"
#include "u_bound.h"
#include "u_list.h"
#include "u_markers.h"
#include "u_redraw.h"
#include "u_search.h"
#include "u_undo.h"
#include "w_canvas.h"
#include "w_color.h"
#include "w_cursor.h"
#include "w_drawprim.h"
#include "w_icons.h"
#include "w_indpanel.h"
#include "w_modepanel.h"
#include "w_mousefun.h"
#include "w_util.h"


static Widget	close_compound_popup;
static Boolean	close_popup_isup = False;
static int	save_mask;

static void	popup_close_compound (void);


static void
init_open_compound(F_compound *c, int type, int x, int y, int px, int py)
{
	(void)x;
	(void)y;
	(void)px;
	(void)py;

    if (type != O_COMPOUND)
	return;
    open_this_compound(c, False);
}

static void
init_open_compound_vis(F_compound *c, int type, int x, int y, int px, int py,
		int loc_tag)
{
	(void)x;
	(void)y;
	(void)px;
	(void)py;
	(void)loc_tag;

    if (type != O_COMPOUND)
	return;
    open_this_compound(c, True);
}

void
open_this_compound(F_compound *c, Boolean vis)
{
  F_compound *d;

  clean_up();
  set_action(F_ENTER_COMP);
  mask_toggle_compoundmarker(c);

  /* save current indicator panel button mask */
  save_mask = cur_indmask;
  /* show the point positioning button if user wants to control
     the compound when he closes it */
  update_indpanel(cur_indmask | I_POINTPOSN);

  c->parent = d = (F_compound *) malloc(sizeof(F_compound));
  *d = objects;			/* Preserve the parent, it points to c */
  objects = *c;
  objects.GABPtr = c;		/* Where original compound came from */
  objects.draw_parent = vis;
  if (!close_popup_isup)
	popup_close_compound();
  redisplay_canvas();
}

void
open_compound_selected(void)
{
  /* prepatory functions done for mode operations by sel_mode_but */
  update_markers((int)M_COMPOUND);

  set_mousefun("open compound", "open, keep visible", "",
		LOC_OBJ, LOC_OBJ, LOC_OBJ);
  canvas_kbd_proc = null_proc;
  canvas_locmove_proc = null_proc;
  canvas_ref_proc = null_proc;
  init_searchproc_left(init_open_compound);
  init_searchproc_middle(init_open_compound_vis);
  canvas_leftbut_proc = object_search_left;
  canvas_middlebut_proc = object_search_middle;
  canvas_rightbut_proc = null_proc;
  set_cursor(pick15_cursor);
  reset_action_on();
}

void
close_compound(void)
{
  F_compound *c;
  F_compound *d;		/* Destination */

  /* if trying to close compound while drawing an object, don't allow it */
  if (check_action_on())
	return;

  clean_up();
  set_action(F_EXIT_COMP);

  if ((c = (F_compound *)objects.parent)) {
    objects.parent = NULL;
    d = (F_compound *)objects.GABPtr;	/* Where this compound was */
    objects.GABPtr   = NULL;

    /* go see if this is a dimension line and calculate angles, box size etc */
    rescale_dimension_line(&objects, 1.0, 1.0, 0, 0);

    /* compute new bounding box if changed */
    compound_bound(&objects, &objects.nwcorner.x, &objects.nwcorner.y,
			&objects.secorner.x, &objects.secorner.y);
    *d = objects;		/* Put in any changes */
    objects = *c;		/* Restore compound above */
    /* user may have deleted all objects inside the compound */
    if (object_count(d)==0) {
	list_delete_compound(&objects.compounds, d);
    } else {
	set_latestcompound(d);
    }
    free(c);
    /* popdown close panel if this is the last one */
    if ((F_compound *)objects.parent == NULL) {
	XtPopdown(close_compound_popup);
	XtDestroyWidget(close_compound_popup);
	close_popup_isup = False;
    }
    redisplay_canvas();
    /* re-select open compound mode */
    change_mode(&open_comp_ic);
    /* restore indicator panel mask */
    cur_indmask = save_mask;
    update_indpanel(cur_indmask);
  }
}

void
close_all_compounds(void)
{
  F_compound *c;
  F_compound *d;		/* Destination */

  /* if trying to close compound while drawing an object, don't allow it */
  if (check_action_on())
	return;

  clean_up();
  set_action(F_EXIT_ALL_COMP);
  /*
   * TODO: To be able to undo close_all_compounds(),
   * add list of closed compounds to saved_objects.
   */

  if (objects.parent) {
    while ((c = (F_compound *)objects.parent)) {
      objects.parent = NULL;
      d = (F_compound *)objects.GABPtr;	/* Where this compound was */
      objects.GABPtr   = NULL;
      /* compute new bounding box if changed */
      compound_bound(&objects, &objects.nwcorner.x, &objects.nwcorner.y,
			&objects.secorner.x, &objects.secorner.y);
      *d = objects;		/* Put in any changes */
      objects = *c;
      /* user may have deleted all objects inside the compound */
      if (object_count(d)==0) {
	list_delete_compound(&objects.compounds, d);
      }
      free(c);
    }
    /* popdown close panel */
    XtPopdown(close_compound_popup);
    XtDestroyWidget(close_compound_popup);
    close_popup_isup = False;
    redisplay_canvas();
    /* re-select open compound mode */
    change_mode(&open_comp_ic);
  }
}

static void
popup_close_compound(void)
{
    Widget	    close_compound_form;
    Widget	    close_compoundw, close_compound_allw;
    Position	    xposn, yposn;
    int		     llx, lly, urx, ury;

    DeclareArgs(10);

    /* position the popup above the compound we're opening */
    compound_bound(&objects, &llx, &lly, &urx, &ury);

    /* translate object coords to screen coords relative to the canvas */
    llx = ZOOMX(llx);
    lly = ZOOMY(lly);

    /* translate those to absolute screen coords */
    XtTranslateCoords(canvas_sw, llx, lly, &xposn, &yposn);
    /* but not off the screen */
    if (xposn < 100)
	xposn = 100;
    if (yposn < 100)
	yposn = 100;

    FirstArg(XtNallowShellResize, True);
    NextArg(XtNx, xposn-40);
    NextArg(XtNy, yposn-65);
    NextArg(XtNtitle, "Xfig: Close Compound");
    NextArg(XtNtitleEncoding, XA_STRING);
    NextArg(XtNcolormap, tool_cm);
    close_compound_popup = XtCreatePopupShell("close_compound_popup",
				transientShellWidgetClass, tool, Args, ArgCount);
    close_compound_form = XtCreateManagedWidget("close_compound_form", formWidgetClass,
				       close_compound_popup, (XtPointer) NULL, 0);

    FirstArg(XtNlabel, "Close This Compound");
    NextArg(XtNinternational, False);
    close_compoundw = XtCreateManagedWidget("close_compound",
					commandWidgetClass, close_compound_form,
					Args, ArgCount);
    XtAddEventHandler(close_compoundw, ButtonReleaseMask, False,
		      (XtEventHandler)close_compound, (XtPointer) NULL);

    FirstArg(XtNlabel, "Close All Compounds");
    NextArg(XtNinternational, False);
    NextArg(XtNfromHoriz, close_compoundw);
    close_compound_allw = XtCreateManagedWidget("close_all_compounds",
				commandWidgetClass, close_compound_form,
				Args, ArgCount);
    XtAddEventHandler(close_compound_allw, ButtonReleaseMask, False,
			  (XtEventHandler)close_all_compounds, (XtPointer) NULL);

    /* now pop it up */
    XtPopup(close_compound_popup, XtGrabNone);

    /* insure that the most recent colormap is installed */
    set_cmap(XtWindow(close_compound_popup));
    (void) XSetWMProtocols(tool_d, XtWindow(close_compound_popup),
                           &wm_delete_window, 1);
    XDefineCursor(tool_d, XtWindow(close_compound_popup), arrow_cursor);
    close_popup_isup = True;
}
