#include "WINGsP.h"


typedef struct W_Frame {
    W_Class widgetClass;
    W_View *view;

    char *caption;

    struct {
        WMReliefType relief:4;
        WMTitlePosition titlePosition:4;
    } flags;
} Frame;


#define DEFAULT_RELIEF 	WRGroove
#define DEFAULT_TITLE_POSITION	WTPAtTop
#define DEFAULT_WIDTH		40
#define DEFAULT_HEIGHT		40


static void destroyFrame(Frame *fPtr);
static void paintFrame(Frame *fPtr);
static void repaintFrame(Frame *fPtr);



void
WMSetFrameTitlePosition(WMFrame *fPtr, WMTitlePosition position)
{
    fPtr->flags.titlePosition = position;

    if (fPtr->view->flags.realized) {
        repaintFrame(fPtr);
    }
}


void
WMSetFrameRelief(WMFrame *fPtr, WMReliefType relief)
{
    fPtr->flags.relief = relief;

    if (fPtr->view->flags.realized) {
        repaintFrame(fPtr);
    }
}


void
WMSetFrameTitle(WMFrame *fPtr, char *title)
{
    if (fPtr->caption)
        wfree(fPtr->caption);

    if (title)
        fPtr->caption = wstrdup(title);
    else
        fPtr->caption = NULL;

    if (fPtr->view->flags.realized) {
        repaintFrame(fPtr);
    }
}


static void
repaintFrame(Frame *fPtr)
{
    W_View *view = fPtr->view;
    W_Screen *scrPtr = view->screen;

    XClearWindow(scrPtr->display, view->window);
    paintFrame(fPtr);
}


static void
paintFrame(Frame *fPtr)
{
    W_View *view = fPtr->view;
    W_Screen *scrPtr = view->screen;
    WMFont *font = scrPtr->normalFont;
    Display *display = scrPtr->display;
    int tx, ty, tw, th, tlen;
    int fy, fh;
    Bool drawTitle;

    if (fPtr->caption!=NULL) {
        th = WMFontHeight(font);
        tlen = strlen(fPtr->caption);
    } else {
        th = 0;
        tlen = 0;
    }

    fh = view->size.height;
    fy = 0;

    switch (fPtr->flags.titlePosition) {
    case WTPAboveTop:
        ty = 0;
        fy = th + 4;
        fh = view->size.height - fy;
        break;

    case WTPAtTop:
        ty = 0;
        fy = th/2;
        fh = view->size.height - fy;
        break;

    case WTPBelowTop:
        ty = 4;
        fy = 0;
        fh = view->size.height;
        break;

    case WTPAboveBottom:
        ty = view->size.height - th - 4;
        fy = 0;
        fh = view->size.height;
        break;

    case WTPAtBottom:
        ty = view->size.height - th;
        fy = 0;
        fh = view->size.height - th/2;
        break;

    case WTPBelowBottom:
        ty = view->size.height - th;
        fy = 0;
        fh = view->size.height - th - 4;
        break;

    default:
        ty = 0;
        fy = 0;
        fh = view->size.height;
    }

    if (tlen>0 && fPtr->flags.titlePosition!=WTPNoTitle) {
        tw = WMWidthOfString(font, fPtr->caption, tlen);

        tx = (view->size.width - tw) / 2;

        drawTitle = True;
    } else {
        tw = tx = 0;
        drawTitle = False;
    }

    {
        XRectangle rect;
        Region region, tmp;
        GC gc[4];
        int i;

        region = XCreateRegion();

        rect.x = 0;
        rect.y = 0;
        rect.width = view->size.width;
        rect.height = view->size.height;
        XUnionRectWithRegion(&rect, region, region);
        if (drawTitle) {
            tmp = XCreateRegion();
            rect.x = tx;
            rect.y = ty;
            rect.width = tw;
            rect.height = th;
            XUnionRectWithRegion(&rect, tmp, tmp);
            XSubtractRegion(region, tmp, region);
            XDestroyRegion(tmp);
        }
        gc[0] = WMColorGC(scrPtr->black);
        gc[1] = WMColorGC(scrPtr->darkGray);
        gc[2] = WMColorGC(scrPtr->gray);
        gc[3] = WMColorGC(scrPtr->white);

        for (i = 0; i < 4; i++) {
            XSetRegion(display, gc[i], region);
        }
        XDestroyRegion(region);

        W_DrawReliefWithGC(scrPtr, view->window, 0, fy, view->size.width, fh,
                           fPtr->flags.relief, gc[0], gc[1], gc[2], gc[3]);

        for (i = 0; i < 4; i++) {
            XSetClipMask(display, gc[i], None);
        }
    }

    if (drawTitle) {
        /* can't draw AA text over and over again because it gets messed */
        /* // TODO create the dbl buffer pixmap when create/set frame title */
        if (scrPtr->antialiasedText) {
            Drawable d;

            d = XCreatePixmap(display, view->window, tw, th, scrPtr->depth);
            XFillRectangle(display, d, WMColorGC(view->backColor), 0, 0, tw, th);

            WMDrawString(scrPtr, d, scrPtr->black, font, 0, 0, fPtr->caption, tlen);
            XCopyArea(display, d, view->window, scrPtr->copyGC, 0, 0, tw, th, tx, ty);
            XFreePixmap(display, d);
        } else {
            WMDrawString(scrPtr, view->window, scrPtr->black, font, tx, ty,
                         fPtr->caption, tlen);
        }
    }
}





static void
handleEvents(XEvent *event, void *data)
{
    Frame *fPtr = (Frame*)data;

    CHECK_CLASS(data, WC_Frame);

    switch (event->type) {
    case Expose:
        if (event->xexpose.count == 0)
            paintFrame(fPtr);
        break;

    case DestroyNotify:
        destroyFrame(fPtr);
        break;
    }
}


WMFrame*
WMCreateFrame(WMWidget *parent)
{
    Frame *fPtr;

    fPtr = wmalloc(sizeof(Frame));
    memset(fPtr, 0, sizeof(Frame));

    fPtr->widgetClass = WC_Frame;

    fPtr->view = W_CreateView(W_VIEW(parent));
    if (!fPtr->view) {
        wfree(fPtr);
        return NULL;
    }
    fPtr->view->self = fPtr;

    WMCreateEventHandler(fPtr->view, ExposureMask|StructureNotifyMask,
                         handleEvents, fPtr);


    fPtr->flags.relief = DEFAULT_RELIEF;
    fPtr->flags.titlePosition = DEFAULT_TITLE_POSITION;

    WMResizeWidget(fPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT);

    return fPtr;
}


static void
destroyFrame(Frame *fPtr)
{
    if (fPtr->caption)
        wfree(fPtr->caption);

    wfree(fPtr);
}



syntax highlighted by Code2HTML, v. 0.9.1