/*-*-C-*-
 * Align processing for Window CSE
 */

#include "resed.h"
#include "main.h"

#include "wimp.h"
#include "resformat.h"
#include "newmsgs.h"

#include "format.h"
#include "windowedit.h"
#include "align.h"
#include "protocol.h"



/*
 * Returns the co-ordinate of the alignment line 'how' for the given 'gadget'
 */

static int align_pos (GadgetPtr gadget, int how)
{
    switch (how)
    {
    case ALIGNMENU_TOP:
        return gadget->hdr.bbox.maxy;
    case ALIGNMENU_HCENTRE:
        return (gadget->hdr.bbox.maxy + gadget->hdr.bbox.miny)/2;
    case ALIGNMENU_BOTTOM:
        return gadget->hdr.bbox.miny;
    case ALIGNMENU_LEFT:
        return gadget->hdr.bbox.minx;
    case ALIGNMENU_VCENTRE:
        return (gadget->hdr.bbox.minx + gadget->hdr.bbox.maxx)/2;
    case ALIGNMENU_RIGHT:
        return gadget->hdr.bbox.maxx;
    }
    return 0;
}


/*
 * If the alignment line for 'gadget' differs from 'fixpos', then the result
 *  is TRUE and the variables deltax and deltay will be updated by the
 *  distance that the gadget must move to bring it into alignment.
 *
 * This distance is rounded to a multiple of 4 OS units if necessary.
 */

static Bool align_gadget (
    GadgetPtr gadget,
    int *deltax,
    int *deltay,
    int fixpos,
    int how
)
{
    int gadgetpos = align_pos (gadget, how);
    int move;

    /* force alignment to multiple of 4 */
    move = WIMP_ALIGN_COORD (fixpos - gadgetpos);

    /* return FALSE if no move necessary */
    if (move == 0)
        return FALSE;

    switch (how)
    {
    case ALIGNMENU_TOP:
    case ALIGNMENU_HCENTRE:
    case ALIGNMENU_BOTTOM:
        *deltax = 0;
        *deltay = move;
        break;
    case ALIGNMENU_LEFT:
    case ALIGNMENU_VCENTRE:
    case ALIGNMENU_RIGHT:
        *deltax = move;
        *deltay = 0;
        break;
    }

    return TRUE;
}


/*
 * Called to align the current selection of gadgets to the 'nominated' gadget
 *  according to 'how', which takes one of the values:
 *    ALIGNMENU_TOP
 *    ALIGNMENU_HCENTRE
 *    ALIGNMENU_BOTTOM
 *    ALIGNMENU_LEFT
 *    ALIGNMENU_VCENTRE
 *    ALIGNMENU_RIGHT
 */

error * align_selection_to (GadgetPtr nominated, int how)
{
    GadgetPtr gadget = nominated->owner->gadgets;
    RectRec bbox;
    int deltax, deltay;
    int fixpos = align_pos (nominated, how);
    Bool modified = FALSE;

    bbox.minx = bbox.miny = BIG;
    bbox.maxx = bbox.maxy = -BIG;

    /* process each selected gadget in turn */
    while (gadget != NULL)
    {
        if (gadget->selected && gadget != nominated)
        {
            if (align_gadget (gadget, &deltax, &deltay, fixpos, how))
            {
                modified = TRUE;

                wimp_merge_bboxes (&bbox, &bbox, &gadget->hdr.bbox);
                gadget->hdr.bbox.minx += deltax;
                gadget->hdr.bbox.maxx += deltax;
                gadget->hdr.bbox.miny += deltay;
                gadget->hdr.bbox.maxy += deltay;
                wimp_merge_bboxes (&bbox, &bbox, &gadget->hdr.bbox);
            }
        }

        gadget = gadget->next;
    }

    if (modified)
    {
        /* invalidate rectangle that includes original and moved gadgets */
        windowedit_add_ears_to_bbox (&bbox, &bbox);
        wimp_invalidate (nominated->owner->window, &bbox);

        /* note modification */
        protocol_send_resed_object_modified (nominated->owner);
    }
    
    return NULL;
}
