/* 
CCIDE
Copyright 2001-2006 David Lindauer.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

You may contact the author at:
	mailto::camille@bluegrass.net
 */
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "winconst.h"
#include "lsctrl.h"

#define TITLEWIDTH 15
#define EDGEWIDTH 1
#define TITLETOP 3
#define BARLEFT 2
#define BARRIGHT 2
#define BARTOP 2

#define INDENT 2

#ifndef __CCDL__
    #ifndef TBSTYLE_TRANSPARENT
        #define TBSTYLE_TRANSPARENT 0x8000
        #define TBSTYLE_FLAT            0x0800
    #endif 

    #ifndef BTNS_SEP
        #define BTNS_SEP TBSTYLE_SEP
    #endif 
    #ifndef TB_SETBUTTONINFO
        #define TBIF_IMAGE              0x00000001
        #define TBIF_TEXT               0x00000002
        #define TBIF_STATE              0x00000004
        #define TBIF_STYLE              0x00000008
        #define TBIF_LPARAM             0x00000010
        #define TBIF_COMMAND            0x00000020
        #define TBIF_SIZE               0x00000040
        typedef struct
        {
            UINT cbSize;
            DWORD dwMask;
            int idCommand;
            int iImage;
            BYTE fsState;
            BYTE fsStyle;
            WORD cx;
            LPDWORD lParam;
            LPSTR pszText;
            int cchText;
        } TBBUTTONINFOA,  *LPTBBUTTONINFOA;

        typedef struct
        {
            UINT cbSize;
            DWORD dwMask;
            int idCommand;
            int iImage;
            BYTE fsState;
            BYTE fsStyle;
            WORD cx;
            LPDWORD lParam;
            LPWSTR pszText;
            int cchText;
        } TBBUTTONINFOW,  *LPTBBUTTONINFOW;

        #ifdef UNICODE
            #define TBBUTTONINFO TBBUTTONINFOW
            #define LPTBBUTTONINFO LPTBBUTTONINFOW
        #else 
            #define TBBUTTONINFO TBBUTTONINFOA
            #define LPTBBUTTONINFO LPTBBUTTONINFOA
        #endif 


        // BUTTONINFO APIs do NOT support the string pool.
        #define TB_GETBUTTONINFOW        (WM_USER + 63)
        #define TB_SETBUTTONINFOW        (WM_USER + 64)
        #define TB_GETBUTTONINFOA        (WM_USER + 65)
        #define TB_SETBUTTONINFOA        (WM_USER + 66)
        #ifdef UNICODE
            #define TB_GETBUTTONINFO        TB_GETBUTTONINFOW
            #define TB_SETBUTTONINFO        TB_SETBUTTONINFOW
        #else 
            #define TB_GETBUTTONINFO        TB_GETBUTTONINFOA
            #define TB_SETBUTTONINFO        TB_SETBUTTONINFOA
        #endif 
    #endif 
#endif 

extern HWND hwndFrame;

static char *szToolBarWindClassName = "ladSoftToolBarWindow";
static TBBUTTON sep = 
{
    0, 0, 0, TBSTYLE_SEP
};
static char *GetTipText(CCW_params *ptr, int id)
{
    int i;
    for (i = 0; i < ptr->u.tb.btncount; i++)
    if (ptr->u.tb.buttons[i].idCommand == id)
    {
        return ptr->u.tb.hints[i];
    }
    return "";
}

//-------------------------------------------------------------------------

static void FormatToolBar(char *buf, HWND hwnd)
{
    TBBUTTON button;
    char *p = buf;
    int i = 0;
    buf[0] = 0;
    while (SendMessage(hwnd, TB_GETBUTTON, i++, (LPARAM) &button))
    {
        if (button.fsStyle == BTNS_SEP)
            sprintf(p, "-1 ");
        else
            sprintf(p, "%d ", button.idCommand);
        p += strlen(p);
    }
}

//-------------------------------------------------------------------------

static int ParseToolBar(char *buf, HWND hwnd, CCW_params *ptr, TBBUTTON
    *buttons)
{
    int rv = 0, i, id, count;
    char *p = buf;
    while (*p)
    {
        if (!isdigit(*p) &&  *p != '-')
            break;
        sscanf(p, "%d %n", &id, &count);
        p += count;
        if (id ==  - 1)
            buttons[rv++] = sep;
        else
        {
            for (i = 0; i < ptr->u.tb.btncount; i++)
            if (ptr->u.tb.buttons[i].idCommand == id)
            {
				int state;
				if (!IsWindow(hwnd))
					state = FALSE;
				else
					state = SendMessage(hwnd, TB_ISBUTTONENABLED, id, 0) ? TBSTATE_ENABLED : 0;
                buttons[rv] = ptr->u.tb.buttons[i];
				buttons[rv].fsState = state;
                buttons[rv].fsStyle |= TBSTYLE_WRAPABLE;
				
                rv++;

            }
        }
        while (isspace(*p))
            p++;
    }
    return rv;

}

//-------------------------------------------------------------------------

static void ChangeTips(int num, HWND hwnd, TBBUTTON *buttons, CCW_params *ptr)
{
    int i;
    char *tip;
    TBBUTTONINFO s;
    memset(&s, 0, sizeof(s));
    if (num)
    {
        for (i = 0; i < num; i++)
        {
            tip = GetTipText(ptr, buttons[i].idCommand);
            if (tip)
            {
                s.cbSize = sizeof(s);
                s.dwMask = TBIF_TEXT;
                s.pszText = tip;
                s.cchText = strlen(tip);
                SendMessage(hwnd, TB_SETBUTTONINFO, buttons[i].idCommand, 
                    (LPARAM) &s);
            }
        }
    }
}

//-------------------------------------------------------------------------

static void SetRectSize(HWND hwnd, CCW_params *ptr)
{
    RECT r;
    TBBUTTON button;
    int num = 0;
    while (SendMessage(hwnd, TB_GETBUTTON, num, (LPARAM) &button))
        num++;
    if (hwnd == ptr->u.tb.hWnd)
    {
        MoveWindow(ptr->self, GRIPWIDTH, INDENT, 1000, 1000, 0);
        SendMessage(hwnd, TB_GETITEMRECT, num - 1, (LPARAM) &r);
        ptr->u.tb.hsize.cx = r.right + GetSystemMetrics(SM_CXFRAME) *2 ;
        ptr->u.tb.hsize.cy = r.bottom + GetSystemMetrics(SM_CYFRAME) *2 ;
		MoveWindow(ptr->self, GRIPWIDTH, INDENT, ptr->u.tb.hsize.cx, ptr->u.tb.hsize.cy, 0);
    }
    else
    {
        SendMessage(hwnd, TB_SETROWS, MAKEWPARAM(num, FALSE), (LPARAM) &r);
        //         SendMessage(hwnd,TB_GETITEMRECT,num-1,(LPARAM) & r) ;
        ptr->u.tb.vsize.cy = r.bottom + GetSystemMetrics(SM_CXFRAME) *2;
        ptr->u.tb.vsize.cx = r.right + GetSystemMetrics(SM_CYFRAME) *2;
    }
}

//-------------------------------------------------------------------------

static void ChangeButtons(int num, HWND hwnd, TBBUTTON *buttons, CCW_params
    *ptr)
{
    if (num)
    {
		while (SendMessage(hwnd, TB_DELETEBUTTON, 0, 0))
			;
		SendMessage(hwnd, TB_ADDBUTTONS, num, (LPARAM) buttons);
		
        ChangeTips(ptr->u.tb.btncount, hwnd, buttons, ptr);
        SetRectSize(hwnd, ptr);
    }
}

//-------------------------------------------------------------------------

static void CopyButtons(CCW_params *ptr)
{
    TBBUTTON buttons[60];
    int i = 0;
    HWND hwnds, hwndd;

    if (ptr->vertical)
    {
        hwnds = ptr->u.tb.vWnd;
        hwndd = ptr->u.tb.hWnd;
    }
    else
    {
        hwnds = ptr->u.tb.hWnd;
        hwndd = ptr->u.tb.vWnd;
    }
    while (SendMessage(hwnds, TB_GETBUTTON, i, (LPARAM) &buttons[i]))
        i++;
    ChangeButtons(i, hwndd, buttons, ptr);
}

//-------------------------------------------------------------------------

int GetToolBarData(HWND hwnd, char *horiz, char *vert)
{
    char hbuf[512], vbuf[512];
    CCW_params *ptr = (CCW_params*)GetWindowLong(hwnd, 0);
    FormatToolBar(horiz, ptr->u.tb.hWnd);
    FormatToolBar(vert, ptr->u.tb.vWnd);
    return ptr->id;
}

//-------------------------------------------------------------------------

void SetToolBarData(HWND hwnd, char *horiz, char *vert)
{
    TBBUTTON buttons[60];
    CCW_params *ptr = (CCW_params*)GetWindowLong(hwnd, 0);
    RECT c;
    int i;
//	ShowWindow(hwnd, SW_HIDE);
    GetClientRect(ptr->self, &c);
    MoveWindow(ptr->self, GRIPWIDTH, INDENT, 1000, 1000, 0);

    i = ParseToolBar(horiz, ptr->u.tb.hWnd, ptr, buttons);
    ChangeButtons(i, ptr->u.tb.hWnd, buttons, ptr);
    i = ParseToolBar(vert, ptr->u.tb.vWnd, ptr, buttons);
    ChangeButtons(i, ptr->u.tb.vWnd, buttons, ptr);
    if (ptr->vertical)
	{
        c.top += GRIPWIDTH;
		c.left += INDENT;
	}
    else 
	{
        c.left += GRIPWIDTH;
		c.top += INDENT;
	}
    MoveWindow(ptr->self, c.left, c.top, c.right - c.left, c.bottom - c.top, 1);
//	ShowWindow(hwnd, SW_SHOW);
}

//-------------------------------------------------------------------------

static void ResizeContainer(CCW_params *ptr)
{
    CalculateLayout( - 1, 0);
}

//-------------------------------------------------------------------------

static LRESULT CALLBACK _export ControlWindWndProc(HWND hwnd, UINT iMessage,
    WPARAM wParam, LPARAM lParam)
{
    TBBUTTON buttons[60];
    TBNOTIFY *tb;
    RECT r,  *pr, r1;
    PAINTSTRUCT ps;
    HDC dc;
    CCW_params *ptr;
    static int skip;
    static int dragging, oncursor, sizing;
    static HCURSOR oldCursor;
    POINT temppt;
    int temp;
    int i;
    HBRUSH brush;
    LPTOOLTIPTEXT lpt;
    LPMINMAXINFO minmax;
    SIZE size;
    char name[64], buf[512],  *p;
    switch (iMessage)
    {
        case WM_NOTIFY:
            ptr = (CCW_params*)GetWindowLong(hwnd, 0);
            switch (((LPNMHDR)lParam)->code)
            {
            case TBN_BEGINADJUST:
                break;
            case TBN_QUERYINSERT:
                return TRUE;
            case TBN_QUERYDELETE:
                return TRUE;
            case TBN_GETBUTTONINFO:
                ptr = (CCW_params*)GetWindowLong(hwnd, 0);
                tb = (TBNOTIFY*)lParam;
                if (tb->iItem >= ptr->u.tb.btncount)
                    return FALSE;
                tb->tbButton = ptr->u.tb.buttons[tb->iItem];
                p = GetTipText(ptr, tb->tbButton.idCommand);
                tb->cchText = strlen(p);
                strcpy(tb->pszText, p);
                //                  tb->cchText = 0 ;
                return TRUE;
            case TBN_RESET:
                ptr = (CCW_params*)GetWindowLong(hwnd, 0);
                ChangeButtons(ptr->u.tb.btncount, ptr->u.tb.hWnd, ptr
                    ->u.tb.buttons, ptr);
                ChangeButtons(ptr->u.tb.btncount, ptr->u.tb.vWnd, ptr
                    ->u.tb.buttons, ptr);
                ResizeContainer(ptr);
                return TRUE;
            case TBN_CUSTHELP:
                ptr = (CCW_params*)GetWindowLong(hwnd, 0);
                if (ptr->u.tb.helpitem)
                    ContextHelp(ptr->u.tb.helpitem);
                break;
            case TBN_ENDADJUST:
                ptr = (CCW_params*)GetWindowLong(hwnd, 0);
                CopyButtons(ptr);
                ResizeContainer(ptr);
                PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
                break;
            case TBN_TOOLBARCHANGE:
                SetRectSize(ptr->u.tb.hWnd, ptr);
                SetRectSize(ptr->u.tb.vWnd, ptr);
                ResizeContainer(ptr);
                break;
            case TTN_NEEDTEXT:
                ptr = (CCW_params*)GetWindowLong(hwnd, 0);
                lpt = (LPTOOLTIPTEXT)lParam;
                p = GetTipText(ptr, lpt->hdr.idFrom);
                if (p)
                    lpt->lpszText = p;
                break;
            default:
                return SendMessage(ptr->u.tb.notifyparent, iMessage, wParam,
                    lParam);
            }
            break;
        case WM_PAINT:
            dc = BeginPaint(hwnd, &ps);
            EndPaint(hwnd, &ps);
            break;
        case WM_COMMAND:
            ptr = (CCW_params*)GetWindowLong(hwnd, 0);
            return SendMessage(ptr->u.tb.notifyparent, iMessage, wParam, lParam)
                ;
        case WM_CREATE:
            ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof
                (CCW_params));
            SetWindowLong(hwnd, 0, (DWORD)ptr);
            *ptr = *(CCW_params*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
            ptr->self = hwnd;
            ptr->type = LSTOOLBAR;
            //         return 0 ;
            ptr->u.tb.btncount = 0;
            while (ptr->u.tb.buttons[ptr->u.tb.btncount].fsStyle || ptr
                ->u.tb.buttons[ptr->u.tb.btncount].idCommand)
                ptr->u.tb.btncount++;
            ptr->u.tb.hWnd = CreateToolbarEx(hwnd, WS_CHILD | (ptr->u.tb.hints 
                ? TBSTYLE_TOOLTIPS : 0) | CCS_NODIVIDER | CCS_ADJUSTABLE |
                TBSTYLE_WRAPABLE, ptr->u.tb.bmpid, ptr->u.tb.bmpcount, 
                (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), ptr->u.tb.bmpid,
                ptr->u.tb.buttons, ptr->u.tb.btncount, ptr->u.tb.width, ptr
                ->u.tb.height, ptr->u.tb.width, ptr->u.tb.height, sizeof
                (TBBUTTON));
            SendMessage(ptr->u.tb.hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON),
                0);
            SendMessage(ptr->u.tb.hWnd, TB_GETITEMRECT, i - 1, (LPARAM) &r);
            ptr->u.tb.hsize.cx = r.right + GetSystemMetrics(SM_CXFRAME) *2;
            ptr->u.tb.hsize.cy = r.bottom + GetSystemMetrics(SM_CYFRAME) *2;
            MoveWindow(hwnd, GRIPWIDTH, INDENT, ptr->u.tb.hsize.cy, ptr->u.tb.hsize.cx,
                1);
            sprintf(name, "TBH%d", ptr->id);
//            p = ProfileToString(name, "");
//            i = ParseToolBar(p, ptr->u.tb.hWnd, ptr, buttons);
//            if (i)
//                ChangeButtons(i, ptr->u.tb.hWnd, buttons, ptr);
//            else
                ChangeButtons(ptr->u.tb.btncount, ptr->u.tb.hWnd, ptr
                    ->u.tb.buttons, ptr);
            ptr->u.tb.vWnd = CreateToolbarEx(hwnd, WS_CHILD | (ptr->u.tb.hints 
                ? TBSTYLE_TOOLTIPS : 0) | CCS_NODIVIDER | CCS_ADJUSTABLE |
                TBSTYLE_WRAPABLE, ptr->u.tb.bmpid, ptr->u.tb.bmpcount, 
                (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), ptr->u.tb.bmpid,
                ptr->u.tb.buttons, ptr->u.tb.btncount, ptr->u.tb.width, ptr
                ->u.tb.height, ptr->u.tb.width, ptr->u.tb.height, sizeof
                (TBBUTTON));

            SendMessage(ptr->u.tb.vWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON),
                0);
            SendMessage(ptr->u.tb.vWnd, TB_SETROWS, MAKEWPARAM(i, FALSE), 
                (LPARAM) &r);
            SendMessage(hwnd, TB_GETITEMRECT, i - 1, (LPARAM) &r);
            ptr->u.tb.vsize.cx = r.right + GetSystemMetrics(SM_CXFRAME) *2;
            ptr->u.tb.vsize.cy = r.bottom + GetSystemMetrics(SM_CYFRAME) *2;
            MoveWindow(hwnd, INDENT, GRIPWIDTH, ptr->u.tb.hsize.cx, ptr->u.tb.hsize.cy,
                1);
            sprintf(name, "TBV%d", ptr->id);
//            p = ProfileToString(name, "");
//            i = ParseToolBar(p, ptr->u.tb.vWnd, ptr, buttons);
//            if (i)
//                ChangeButtons(i, ptr->u.tb.vWnd, buttons, ptr);
//            else
                ChangeButtons(ptr->u.tb.btncount, ptr->u.tb.vWnd, ptr
                    ->u.tb.buttons, ptr);
            SendMessage(hwnd, LCF_SETVERTICAL, 0, ptr->vertical);
            dmgrAddClient(ptr);
			ShowWindow(hwnd, SW_SHOW);
            return 0;
        case WM_DESTROY:
            ptr = (CCW_params*)GetWindowLong(hwnd, 0);
//            FormatToolBar(buf, ptr->u.tb.hWnd);
//            sprintf(name, "TBH%d", ptr->id);
//            StringToProfile(name, buf);
//            FormatToolBar(buf, ptr->u.tb.vWnd);
//            sprintf(name, "TBV%d", ptr->id);
//            StringToProfile(name, buf);
            dmgrRemoveClient(ptr);
            HeapFree(GetProcessHeap(), 0, ptr);
            break;
        case LCF_SETVERTICAL:
            ptr = (CCW_params*)GetWindowLong(hwnd, 0);
            ptr->vertical = (int)lParam;
            if (ptr->vertical)
            {
                ShowWindow(ptr->u.tb.hWnd, SW_HIDE);
                ShowWindow(ptr->u.tb.vWnd, SW_SHOW);
                MoveWindow(hwnd, INDENT, (int)wParam, ptr->u.tb.vsize.cx, ptr
                    ->u.tb.vsize.cy, 1);
            }
            else
            {
                ShowWindow(ptr->u.tb.vWnd, SW_HIDE);
                ShowWindow(ptr->u.tb.hWnd, SW_SHOW);
                MoveWindow(hwnd, (int)wParam, INDENT, ptr->u.tb.hsize.cx, ptr
                    ->u.tb.hsize.cy, 1);
            }
            return 0;
        case WM_CLOSE:
            ptr = (CCW_params*)GetWindowLong(hwnd, 0);
            dmgrHideWindow(ptr->id, TRUE);
            return 0;
        case WM_SIZE:
            ptr = (CCW_params*)GetWindowLong(hwnd, 0);
            if (ptr->vertical)
            {
                MoveWindow(ptr->u.tb.vWnd, INDENT, 0, LOWORD(lParam), HIWORD
                    (lParam), TRUE);
            }
            else
            {
                MoveWindow(ptr->u.tb.hWnd, 0, INDENT, LOWORD(lParam), HIWORD
                    (lParam), TRUE);
            }
            return 0;
        default:
            if (iMessage >= WM_USER && iMessage <= WM_USER + 100)
            {
                ptr = (CCW_params*)GetWindowLong(hwnd, 0);
                return SendMessage(ptr->u.tb.hWnd, iMessage, wParam, lParam);
            }
    }
    return DefWindowProc(hwnd, iMessage, wParam, lParam);
}

//-------------------------------------------------------------------------

void RegisterToolBarWindow(HINSTANCE hInstance)
{
    WNDCLASS wc;
    memset(&wc, 0, sizeof(wc));
    wc.style = 0;
    wc.lpfnWndProc = &ControlWindWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = sizeof(LPVOID);
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_INACTIVEBORDER));
    wc.lpszMenuName = 0;
    wc.lpszClassName = szToolBarWindClassName;
    RegisterClass(&wc);

}

//-------------------------------------------------------------------------

HWND CreateToolBarWindow(int id, HWND notify, HWND parent, int width, int
    height, int bmp, int bmpcount, TBBUTTON *buttons, char **hints, int
    vertical, char *title, int helpitem)
{
    CCW_params p;
    HWND hwnd;
    RECT r1, r2;
    memset(&p, 0, sizeof(p));
    p.vertical = vertical;
    p.u.tb.width = width;
    p.u.tb.height = height;
    p.u.tb.buttons = buttons;
    p.u.tb.hints = hints;
    p.u.tb.bmpid = bmp;
    p.u.tb.bmpcount = bmpcount;
    p.u.tb.notifyparent = notify;
    p.u.tb.helpitem = helpitem;
    p.title = title;
    p.id = id;
    hwnd = CreateWindow(szToolBarWindClassName, "", WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, 1000, 30, parent, (HMENU)0,
        (HINSTANCE)GetWindowLong(parent, GWL_HINSTANCE), &p);

    return hwnd;
}
