/* 
   Copyright 2001-2003 Free Software Foundation, Inc.

   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., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222

**********************************************************************

This is a wrapper for toolbars which is compatible with the docking
window mechanism.

**********************************************************************

*/
#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

#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

extern HWND hwndFrame ;

static char *szToolBarWindClassName = "ladSoftToolBarWindow" ;
static TBBUTTON sep = { 0,0,0,TBSTYLE_SEP, 0, 0 } ;
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 0 ;
}

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) {
               buttons[rv++] = ptr->u.tb.buttons[i] ;
            }
      }
      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 ChangeButtons(int num, HWND hwnd, TBBUTTON *buttons, CCW_params *ptr)
{
   int i ;
   RECT r ;
   if (num) {
      while(SendMessage(hwnd,TB_DELETEBUTTON,0,0)) ;
      for (i=0; i < num; i++) 
         SendMessage(hwnd,TB_INSERTBUTTON,i+1,(LPARAM)&buttons[i]) ;
      ChangeTips(num,hwnd, buttons,ptr) ;
      SendMessage(hwnd,TB_GETITEMRECT,i-1,(LPARAM)&r) ;
      if (hwnd == ptr->u.tb.hWnd) {
         ptr->u.tb.hsize.cx = r.right + GetSystemMetrics(SM_CXFRAME) ;
         ptr->u.tb.hsize.cy = r.bottom  ; // + GetSystemMetrics(SM_CYFRAME) ;
         
      } else {
         ptr->u.tb.vsize.cx = r.right ; // + GetSystemMetrics(SM_CXFRAME) ;
         ptr->u.tb.vsize.cy = r.bottom + GetSystemMetrics(SM_CYFRAME) ;
      }
   }
}
void SaveToolBar(FILE *fil, HWND hwnd)
{
   char buf[512] ;
   CCW_params *ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
   FormatToolBar(buf,ptr->u.tb.hWnd) ;
   fprintf(fil,"<HORIZ %s>\n",buf) ;
   FormatToolBar(buf,ptr->u.tb.vWnd) ;
   fprintf(fil,"<VERT %s>\n",buf) ;
}
int RestoreToolBar(FILE *fil, HWND hwnd)
{
   TBBUTTON buttons[60] ;
   int i;
   char buf[512] ;
   CCW_params *ptr = (CCW_params *)GetWindowLong(hwnd,0) ;

   if (ReadString(buf,fil,"<HORIZ"))
      return FALSE ;
   i = ParseToolBar(buf + 7,ptr->u.tb.hWnd,ptr,buttons) ;
   ChangeButtons(i,ptr->u.tb.hWnd, buttons,ptr ) ;
   if (ReadString(buf,fil,"<VERT"))
      return FALSE ;
   i = ParseToolBar(buf + 6,ptr->u.tb.vWnd,ptr,buttons) ;
   ChangeButtons(i,ptr->u.tb.vWnd, buttons,ptr ) ;
   return TRUE ;
}
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) ;
//               if (p) {
//                  tb->cchText = strlen(p) ;
//                  tb->pszText = p ;
//                  strcpy(tb->pszText,p) ;
//               } else
                  tb->cchText = 0 ;
               return TRUE ;
            case TBN_RESET:
               ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
               ChangeButtons(ptr->u.tb.btncount,ptr->vertical ? ptr->u.tb.vWnd : ptr->u.tb.hWnd,ptr->u.tb.buttons,ptr) ; 
               ChangeTips(ptr->u.tb.btncount,ptr->vertical ? ptr->u.tb.vWnd : ptr->u.tb.hWnd,ptr->u.tb.buttons,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:
               PostMessage(hwndFrame,WM_REDRAWTOOLBAR,0,0) ;
               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) ;
         GetClientRect(hwnd,&r) ;
         EndPaint(hwnd, &ps) ;
         break ;
      case WM_COMMAND:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         return SendMessage(ptr->u.tb.notifyparent,iMessage,wParam,lParam) ;
         break ;
		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++ ;
         sprintf(name,"TBH%d",ptr->id) ;
         p= ProfileToString(name,"") ;
         i = ParseToolBar(p,ptr->u.tb.hWnd,ptr,buttons) ;
         if (i == 0)
            memcpy(buttons,ptr->u.tb.buttons,(i = ptr->u.tb.btncount) * sizeof(TBBUTTON)) ;
         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, buttons, i, 
                        ptr->u.tb.width,ptr->u.tb.height,ptr->u.tb.width,ptr->u.tb.height,
                        sizeof(TBBUTTON)) ;
         ChangeTips(i,ptr->u.tb.hWnd, buttons,ptr ) ;
         SendMessage(ptr->u.tb.hWnd,TB_GETITEMRECT,i-1,(LPARAM)&r) ;
         ptr->u.tb.hsize.cx = r.right + GetSystemMetrics(SM_CXFRAME) ;
         ptr->u.tb.hsize.cy = r.bottom  ; // + GetSystemMetrics(SM_CYFRAME) ;
         MoveWindow(hwnd,0,0,ptr->u.tb.hsize.cy,ptr->u.tb.hsize.cx,0) ;
         sprintf(name,"TBV%d",ptr->id) ;
         p= ProfileToString(name,"") ;
         i = ParseToolBar(p,ptr->u.tb.vWnd,ptr,buttons) ;
         if (i == 0)
            memcpy(buttons,ptr->u.tb.buttons,(i = ptr->u.tb.btncount) * sizeof(TBBUTTON)) ;
         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, buttons, i, 
                        ptr->u.tb.width,ptr->u.tb.height,ptr->u.tb.width,ptr->u.tb.height,
                        sizeof(TBBUTTON)) ;
         ChangeTips(i,ptr->u.tb.vWnd, buttons,ptr) ;
         SendMessage(ptr->u.tb.vWnd,TB_GETITEMRECT,i-1,(LPARAM)&r) ;
         ptr->u.tb.vsize.cx = r.right ; // + GetSystemMetrics(SM_CXFRAME) ;
         ptr->u.tb.vsize.cy = r.bottom + GetSystemMetrics(SM_CYFRAME) ;
         MoveWindow(hwnd,0,0,ptr->u.tb.hsize.cx,ptr->u.tb.hsize.cy,0) ;
         SendMessage(hwnd,LCF_SETVERTICAL,0,ptr->vertical) ;
         dmgrAddClient(ptr) ;
			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,0,(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,0,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,0,0,LOWORD(lParam),HIWORD(lParam),FALSE) ;
         } else {
            MoveWindow(ptr->u.tb.hWnd,0,0,LOWORD(lParam),HIWORD(lParam),FALSE) ;
         }
         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_VISIBLE | WS_CHILD,
            CW_USEDEFAULT, CW_USEDEFAULT, 1000, 30,
            parent, (HMENU)0 ,(HINSTANCE)GetWindowLong(parent,GWL_HINSTANCE), &p) ;

   return hwnd ;
}