/*
This source file is part of Scol
For the latest info, see http://www.scolring.org

Copyright (c) 2010 Stephane Bisaro, aka Iri <iri@irizone.net>

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt

For others informations, please contact us from http://www.scolring.org/
*/



#include "../include/scol_gtk_container.h"




static void scol_gtk_box_create (GtkWidget **box, GtkWidget *parent, gboolean hg, gint sp, int subtype)
{
    switch (subtype)
    {
        case (SCOL_WIDGET_SUBTYPE_BOXHORIZ) :
            *box = gtk_hbox_new (hg, sp);
            break;

        case (SCOL_WIDGET_SUBTYPE_BOXVERT) :
            *box = gtk_vbox_new (hg, sp);
            break;

        default :
            ;
    }

    if (parent != NULL)
        gtk_container_add (GTK_CONTAINER (parent), *box);
    return;
}








/**
 * \brief Create a box (container) : fun [Chn ObjGtkWidget I I I] ObjGtkWidget
 *
 * A Box can not be a top level container, so a 'parent' should be defined
 *
 * Stack :
 * stage 0 : I : flag : SCOL_GTK_BOX_HZ for a horizontal box, SCOL_GTK_BOX_VT for a vertical box
 * stage 1 : I : spacing : the number of pixels to place by default between children
 * stage 2 : I : homogeneous : 1 if all children are to be given equal space allotments.
 * stage 3 : ObjGtkWidget : parent : parent container
 * stage 4 : Chn : channel
 *
 * \return : ObjGtkWidget : a new box
 */
int SCOL_gtkBoxNew (mmachine m)
{
    int mchannel, mparent, mhg, msp, mflag;
    int subtype;
    GtkWidget *box, *parent;
    gboolean hg = TRUE;

    g_message ("SCOL_gtkBoxNew : entering");

    mflag = MTOI (MMpull (m));
    msp = MTOI (MMpull (m));
    mhg = MTOI (MMpull (m));
    mparent = MTOP (MMpull (m));
    mchannel = MMget (m, 0);

    if (mchannel == NIL)
    {
        g_warning ("SCOL_gtkBoxNew error : channel is nil");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    if (mparent == NIL)
        parent = NULL;
    else
        parent = (GtkWidget*) MMfetch (m, mparent, OBJ2DGTK_WIDGET_HANDLE);

    if (mhg != 1)
        hg = FALSE;

    if (msp < 0)
        msp = 0;

    if (mflag == BOX_HZ)
        subtype = SCOL_WIDGET_SUBTYPE_BOXHORIZ;
    else
        subtype = SCOL_WIDGET_SUBTYPE_BOXVERT;

    scol_gtk_box_create (&box, parent, hg, (gint) msp, subtype);
    return SCOL_gtk_memory_createObjectTAB (m, box, ObjGtkWidgetType, OBJ2DGTK_WIDGET_HANDLE);
}

/**
 * \brief Add widgets to a box : fun [ObjGtkWidget [ObjGtkWidget r1] I] ObjGtkWidget
 *
 * stack :
 * stage 0 : I : flag : if 0, widgets will add from the beginning, otherwise from the end
 * stage 1 : [ObjGtkWidget r1] : a list of widgets
 * stage 2 : ObjGtkWidget : a box.
 * \return : ObjGtkWidget : the same box
 */
int SCOL_gtkBoxAddChilds (mmachine m)
{
    int mbox, mchilds, mflag, mchild;
    GtkWidget *s, *box;

    g_message ("SCOL_gtkBoxAddChilds : entering");

    mflag = MTOI (MMpull (m));
    mchilds = MMpull (m)>>1;
    mbox = MTOP (MMget (m, 0));

    if (mflag != 1)
        mflag = 0;

    if (mbox == NIL)
    {
        g_warning ("SCOL_gtkBoxAddChilds error : box is nil");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    box = (GtkWidget*) MMfetch (m, mbox, OBJ2DGTK_WIDGET_HANDLE);

    while (mchilds != NIL)
    {
        mchild = MMfetch (m, mchilds, 0)>>1;
        s = (GtkWidget*) MMfetch (m, mchild, OBJ2DGTK_WIDGET_HANDLE);

        if (s != NULL)
        {
            if (mflag == 0)
                gtk_box_pack_start (GTK_BOX (box), s, TRUE, TRUE, 0);
            else
                gtk_box_pack_end (GTK_BOX (box), s, TRUE, TRUE, 0);
        }
        mchilds = MMfetch (m, mchilds, 1)>>1;
    }
    return 0;
}


/**
 * \brief Sets the same way childs are packed into box. fun [ObjGtkWidget [ObjGtkWidget r1] I I I I] ObjGtkWidget
 *
 * Stack :
 * stage 0 : I : flag : 1 : add from the end, other value : add from the begin
 * stage 1 : I : padding. If the value is negative, the padding will be 0
 * stage 2 : I : fill. 0 for False, other value  for True
 * stage 3 : I : expand. 0 for False, other value  for True
 * stage 4 : [ObjGtkWidget r1] : childs : list of the widgets
 * stage 5 : ObjGtkWidget : box : any box container.
 * return : ObjGtkWidget : the same box
 */
int SCOL_gtkBoxSetChildsSame (mmachine m)
{
    int mbox, mchilds, mexpand, mfill, mpadding, mflag;
    GtkPackType flag = GTK_PACK_START;
    GtkWidget *box, *child;

    g_message ("SCOL_gtkBoxSetChildsSame : entering");

    mflag = MTOI (MMpull (m));
    mpadding = MTOI (MMpull (m));
    mfill = MTOI (MMpull (m));
    mexpand = MTOI (MMpull (m));
    mchilds = MTOP (MMpull (m));
    mbox = MTOP (MMget (m, 0));

    if ((mbox == NIL) || (mchilds == NIL))
    {
        g_warning ("SCOL_gtkBoxSetChildsSame error : box or childs is nil");
        return 0;
    }

    box = (GtkWidget *) MMfetch (m, mbox, OBJ2DGTK_WIDGET_HANDLE);

    if (mpadding < 0)
        mpadding = 0;

    if (mexpand != 0)
        mexpand = TRUE;

    if (mfill != 0)
        mfill = TRUE;

    if (mflag)
        flag = GTK_PACK_END;

    while (mchilds != NIL)
    {
        child = (GtkWidget*) MMfetch (m, MMfetch (m, mchilds, 0)>>1, OBJ2DGTK_WIDGET_HANDLE);
        if (child != NULL)
            gtk_box_set_child_packing (GTK_BOX (box), child, mexpand, mfill, mpadding, flag);
        mchilds = MMfetch (m, mchilds, 1)>>1;
    }
    return 0;
}


/**
 * \brief Sets the differents way childs are packed into box. fun [ObjGtkWidget [[ObjGtkWidget I I I I ] r1]] ObjGtkWidget
 *
 * SCOL_gtkBoxSetChildsSame sets to the same parameters for all childs
 * Here, each child has these parameters
 * To set it, see SCOL_gtkBoxSetChildsSame
 */
int SCOL_gtkBoxSetChilds (mmachine m)
{
    int mbox, mchilds, mexpand, mfill, mpadding, mflag;
    int e;
    gboolean fill, expand;
    GtkPackType flag = GTK_PACK_START;
    GtkWidget *box, *child;

    g_message ("SCOL_gtkBoxSetChilds : entering");

    mchilds = MMpull (m);
    mbox = MMget (m, 0);

    if ((mbox == NIL) || (mchilds == NIL))
    {
        g_warning ("SCOL_gtkBoxSetChilds error : box or childs is nil");
        return 0;
    }
    box = (GtkWidget *) MMfetch (m, MTOP (mbox), OBJ2DGTK_WIDGET_HANDLE);

    mchilds = MTOP (mchilds);
    while (mchilds != NIL)
    {
        e = MMfetch (m, mchilds, 0)>>1;
        if (e != NIL)
        {
            child = (GtkWidget*) MMfetch (m, (MMfetch (m, e, 0)>>1), OBJ2DGTK_WIDGET_HANDLE);
            if (child != NULL)
            {
                mexpand = MTOI (MMfetch (m, e, 1));
                /*mpadding = MTOI (MMfetch (m, e, 2));*/
                mfill = MTOI (MMfetch (m, e, 2));
                mpadding = MTOI (MMfetch (m, e, 3));
                mflag = MTOI (MMfetch (m, e, 4));

                fill = FALSE;
                expand = FALSE;

                if (mpadding < 0)
                    mpadding = 0;
                if (mexpand != 0)
                    expand = TRUE;
                if (mfill != 0)
                    fill = TRUE;
                if (mflag)
                    flag = GTK_PACK_END;

                gtk_box_set_child_packing (GTK_BOX (box), child, expand, fill, (guint) mpadding, flag);
            }
        }
        mchilds = MMfetch (m, mchilds, 1)>>1;
    }
    return 0;
}

/**
 * \brief Sets the differents way childs are packed into any box. fun [[ObjGtkWidget ObjGtkWidget I I I I ] r1] I
 *
 * SCOL_gtkBoxSetChildsSame sets to the same parameters for all childs
 * Here, each child has these parameters into any/differents boxes
 * To set it, see SCOL_gtkBoxSetChildsSame
 * Stack : stage 0 : a list
 * Return : I : 0 or NIL if the list is nil
 */
int SCOL_gtkBoxSetChildsAny (mmachine m)
{
    int mlist, mexpand, mfill, mpadding, mflag;
    int e;
    GtkPackType flag = GTK_PACK_START;
    GtkWidget *box, *child;

    g_message ("SCOL_gtkBoxSetChildsAny : entering");

    mlist = MTOP (MMpull (m));

    if (mlist == NIL)
    {
        g_warning ("SCOL_gtkBoxSetChildsAny error : list is nil");
        MMpush (m, NIL);
        return 0;
    }

    while (mlist != NIL)
    {
        e = MMfetch (m, mlist, 0)>>1;
        if (e != NIL)
        {
            box = (GtkWidget *) MMfetch (m, MMfetch (m, e, 0)>>1, OBJ2DGTK_WIDGET_HANDLE);
            child = (GtkWidget*) MMfetch (m, MMfetch (m, e, 1)>>1, OBJ2DGTK_WIDGET_HANDLE);
            if ((child != NULL) && (box != NULL))
            {
                mexpand = MTOI (MMfetch (m, e, 2));
                /*mpadding = MTOI (MMfetch (m, e, 3));*/
                mfill = MTOI (MMfetch (m, e, 3));
                mpadding = MTOI (MMfetch (m, e, 4));
                mflag = MTOI (MMfetch (m, e, 5));

                if (mpadding < 0)
                    mpadding = 0;
                if (mexpand != 0)
                    mexpand = TRUE;
                if (mfill != 0)
                    mfill = TRUE;
                if (mflag)
                    flag = GTK_PACK_END;

                gtk_box_set_child_packing (GTK_BOX (box), child, mexpand, mfill, mpadding, flag);
            }
        }
        mlist = MMfetch (m, mlist, 1)>>1;
    }
    MMpush (m, 0);
    return 0;
}


/* Flags */
int SCOL_GTK_BOX_HZ (mmachine m) { MMpush (m, ITOM (BOX_HZ)); return 0; }
int SCOL_GTK_BOX_VT (mmachine m) { MMpush (m, ITOM (BOX_VT)); return 0; }



/* API définitions : */

char* gtk_cont_name[GTK_CONTAINER_PKG_NB]=
{
    "SCOL_GTK_BOX_HZ", "SCOL_GTK_BOX_VT",

    "_gtkBoxNew",
    "_gtkBoxAddChilds",
    "_gtkBoxSetChildsSame",
    "_gtkBoxSetChilds",
    "_gtkBoxSetChildsAny"
};

int (*gtk_cont_fun[GTK_CONTAINER_PKG_NB])(mmachine m)=
{
    SCOL_GTK_BOX_HZ, SCOL_GTK_BOX_VT,

    SCOL_gtkBoxNew,
    SCOL_gtkBoxAddChilds,
    SCOL_gtkBoxSetChildsSame,
    SCOL_gtkBoxSetChilds,
    SCOL_gtkBoxSetChildsAny
};

int gtk_cont_narg[GTK_CONTAINER_PKG_NB]=
{
    0, 0,

    5,
    3,
    6,
    2,
    1
};

char* gtk_cont_type[GTK_CONTAINER_PKG_NB]=
{
    "fun [] I", "fun [] I",

    "fun [Chn ObjGtkWidget I I I] ObjGtkWidget",                        /* _gtkBoxNew */
    "fun [ObjGtkWidget [ObjGtkWidget r1] I] ObjGtkWidget",              /* _gtkBoxAddChilds */
    "fun [ObjGtkWidget [ObjGtkWidget r1] I I I I] ObjGtkWidget",         /* _gtkBoxSetChildsSame */
    "fun [ObjGtkWidget [[ObjGtkWidget I I I I] r1]] ObjGtkWidget",      /* _gtkBoxSetChilds */
    "fun [[ObjGtkWidget ObjGtkWidget I I I I] r1] I"    /* _gtkBoxSetChildsAny */
};

int SCOLloadGTKcontainer (mmachine m)
{
    int k;

    MMechostr (0, "SCOLloadGTKcontainer : entering\n");

    k = PKhardpak (m, "GTK2DcontainerEngine", GTK_CONTAINER_PKG_NB, gtk_cont_name, gtk_cont_fun, gtk_cont_narg, gtk_cont_type);
    return k;
}



