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

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

LSCTRL.C is the container window used when windows are docked.  It has
two bars at the top or left, followed by a close button and a button
to expand or contract the window when it is put in the same row
or column with similar windows.  Other windows are placed inside it to
perform whatever functionality is needed.

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

*/
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "lsctrl.h"

#define TITLEWIDTH 15
#define EDGEWIDTH 1
#define TITLETOP 3
#define BARLEFT 3
#define BARRIGHT (BUTTONCORNER + 2 * BUTTONWIDTH + 4)
#define BARTOP 0
#define BUTTONCORNER 1
#define BUTTONWIDTH 12

static char *szControlWindClassName = "ladSoftControlWindow" ;
static HCURSOR hcurs,vcurs,lcurs,rcurs,mcurs ;
static HBITMAP closebitmap,uparr,downarr,leftarr,rightarr,uparrdis,leftarrdis ;

static void DrawBorder(HDC dc, RECT *r1,int vertical)
{
   HBRUSH brush = CreateSolidBrush(GetSysColor(COLOR_INACTIVEBORDER)) ;
   RECT r2 ;

   r2 = *r1 ;
   if (vertical)
      r2.right = r2.left + TITLEWIDTH ;
   else
      r2.right = r2.left + EDGEWIDTH ;
   FillRect(dc,&r2,brush) ;

   r2 = *r1 ;
   r2.left = r2.right -EDGEWIDTH ;
   FillRect(dc,&r2,brush) ;

   r2 = *r1 ;
   if (vertical)
      r2.bottom = r2.top + EDGEWIDTH ;
   else
      r2.bottom = r2.top + TITLEWIDTH ;
   FillRect(dc,&r2,brush) ;

   r2 = *r1 ;
   r2.top = r2.bottom - EDGEWIDTH ;
   FillRect(dc,&r2,brush) ;

   DeleteObject(brush) ;

}
static void DrawTitle(HDC dc, RECT *r, int vertical)
{
   HPEN pen1,pen2,pen3,oldpen ;                       
         pen1 = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DLIGHT)) ;
         pen2 = CreatePen(PS_SOLID, 2, GetSysColor(COLOR_3DHILIGHT)) ;
         pen3 = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)) ;
         if (!vertical) {
            r->top = TITLETOP ;
            r->left+=EDGEWIDTH ;
            r->right-=EDGEWIDTH ;
            oldpen = SelectObject(dc,pen1) ;
            SelectObject(dc,pen1) ;
            MoveToEx(dc,r->left + BARLEFT,r->top+BARTOP,0) ;
            LineTo(dc,r->right - BARRIGHT + 1, r->top+BARTOP) ;
            SelectObject(dc,pen2) ;
            MoveToEx(dc,r->left + BARLEFT-1,r->top+BARTOP+1,0) ;
            LineTo(dc,r->right - BARRIGHT , r->top+BARTOP+1) ;
            SelectObject(dc,pen3) ;
            MoveToEx(dc,r->left + BARLEFT,r->top+BARTOP+3,0) ;
            LineTo(dc,r->right - BARRIGHT + 1, r->top+BARTOP+3) ;
            SelectObject(dc,pen2) ;
            MoveToEx(dc,r->left + BARLEFT-1,r->top+BARTOP+5,0) ;
            LineTo(dc,r->right - BARRIGHT, r->top+BARTOP+5) ;
            SelectObject(dc,pen3) ;
            MoveToEx(dc,r->left + BARLEFT,r->top+BARTOP+7,0) ;
            LineTo(dc,r->right - BARRIGHT + 1, r->top+BARTOP+7) ;
         } else {
            r->left = TITLETOP ;
            r->top += EDGEWIDTH ;
            r->bottom-=EDGEWIDTH ;
            oldpen = SelectObject(dc,pen1) ;
            MoveToEx(dc,r->left+BARTOP,r->top+BARRIGHT-1,0) ;
            LineTo(dc,r->left+BARTOP,r->bottom-BARLEFT) ;
            SelectObject(dc,pen2) ;
            MoveToEx(dc,r->left+BARTOP+1,r->top+BARRIGHT,0) ;
            LineTo(dc,r->left+BARTOP+1,r->bottom-BARLEFT+1) ;
            SelectObject(dc,pen3) ;
            MoveToEx(dc,r->left+BARTOP+3,r->top+BARRIGHT-1,0) ;
            LineTo(dc,r->left+BARTOP+3,r->bottom-BARLEFT) ;
            SelectObject(dc,pen2) ;
            MoveToEx(dc,r->left+BARTOP+5,r->top+BARRIGHT,0) ;
            LineTo(dc,r->left+BARTOP+5,r->bottom-BARLEFT + 1) ;
            SelectObject(dc,pen3) ;
            MoveToEx(dc,r->left+BARTOP+7,r->top+BARRIGHT-1,0) ;
            LineTo(dc,r->left+BARTOP+7,r->bottom-BARLEFT) ;
         }                    
         SelectObject(dc, oldpen) ;
         DeleteObject(pen1) ;
         DeleteObject(pen2) ;
         DeleteObject(pen3) ;
}
#define RANGE(x,y) ((x) == (y) || (x)+1 == (y)+1)
static void SetFlexBmp(CCW_params *ptr)
{
   if (ptr->vertical) {
      if (ptr->u.cw.disabled)
         SendMessage(ptr->u.cw.flexbutton,BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)leftarrdis) ;
      else if (ptr->u.cw.flexed)
         SendMessage(ptr->u.cw.flexbutton,BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)rightarr) ;
      else
         SendMessage(ptr->u.cw.flexbutton,BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)leftarr) ;
   } else {
      if (ptr->u.cw.disabled)
         SendMessage(ptr->u.cw.flexbutton,BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)uparrdis) ;
      else if (ptr->u.cw.flexed)
         SendMessage(ptr->u.cw.flexbutton,BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)downarr) ;
      else
         SendMessage(ptr->u.cw.flexbutton,BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)uparr) ;
   }
}
static LRESULT  CALLBACK _export ControlWindWndProc( HWND hwnd, UINT iMessage, WPARAM wParam,
                                                         LPARAM lParam )
{
   RECT r, *pr ;
   PAINTSTRUCT ps ;
   HDC dc ;
   CCW_params *ptr ;
   static int skip ;
   static int dragging,oncursor,sizing ;
   static HCURSOR oldCursor ;
   POINT temppt ;
   int temp ;
   HBRUSH brush ;
   switch(iMessage) {
      case WM_NOTIFY:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         return SendMessage(ptr->parent,iMessage,wParam,lParam) ;
      case WM_COMMAND:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == 64371)
            SendMessage(ptr->parent,WM_SYSCOMMAND,SC_CLOSE,0) ;
         else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == 64372) {
            SetFlexBmp(ptr) ;
            SetFocus(hwnd) ;
            dmgrFlex(ptr) ;
         } else
            return SendMessage(ptr->parent,iMessage,wParam,lParam) ;
         break ;
      case WM_ERASEBKGND:
         return 0 ;

      case WM_LBUTTONDOWN :
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         temppt.x = (long)(short)LOWORD(lParam) ;
         temppt.y = (long)(short)HIWORD(lParam) ;
         if (oldCursor) {
            dmgrStartSizeClient(ptr,oncursor,lParam) ;
            SetCapture(hwnd) ;
            sizing = TRUE ;
         } else if ((ptr->vertical && temppt.x < 17) ||
               (!ptr->vertical && temppt.y < 17))  {
            dmgrStartMoveClient(ptr,lParam) ;
            oldCursor = SetCursor(mcurs) ;
            SetCapture(hwnd) ;
            dragging = TRUE ;
         }
         break ;
      case WM_LBUTTONUP:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         if (dragging) {
            SetCursor(oldCursor) ;
            oldCursor = 0 ;
         }
         if (dragging)
            ReleaseCapture() ;
         dragging = FALSE ;
         sizing = FALSE ;
         dmgrEndMoveSizeClient(ptr) ;
         break ;
      case WM_MOUSEMOVE:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         if (dragging) {
            dmgrMoveClient(ptr, lParam) ;
         } else if (sizing) {
            dmgrSizeClient(ptr, lParam) ;
         }  else {
            HCURSOR cursor = 0 ;
            if (dmgrDocked(ptr))
               break ;
            ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
            temppt.x = (long)(short)LOWORD(lParam) ;
            temppt.y = (long)(short)HIWORD(lParam) ;
            GetClientRect(hwnd,&r) ;
            if (RANGE(temppt.x,r.right-1)) {
               if (RANGE(temppt.y, r.bottom -1)) {
                     cursor = SetCursor(lcurs) ;
                     oncursor = HTBOTTOMRIGHT ;
               } else if (RANGE(temppt.y, r.top)) {
                     cursor = SetCursor(rcurs) ;
                     oncursor = HTTOPRIGHT ;
               } else if (!oldCursor) {
                     cursor = SetCursor(hcurs) ;
                     oncursor = HTRIGHT ;
               }
            } else if (RANGE(temppt.y, r.bottom-1)) {
               if (temppt.x == r.left) {
                     cursor = SetCursor(rcurs) ;
                     oncursor = HTBOTTOMLEFT ;
               } else {
                  cursor = SetCursor(vcurs) ;
                  oncursor = HTBOTTOM;
               }
            } else if (RANGE(temppt.x, r.left)) {
               if (RANGE(temppt.y,r.top)) {
                     cursor = SetCursor(lcurs) ;
                     oncursor = HTTOPLEFT ;
               } else {
                  cursor = SetCursor(hcurs) ;
                  oncursor = HTLEFT ;
               }
            } else if (RANGE(temppt.y,r.top)) {
                  cursor = SetCursor(vcurs) ;
                  oncursor = HTTOP ;
            } else if (oldCursor) {
               ReleaseCapture() ;
               SetCursor(oldCursor) ;
               oldCursor = 0 ;
               oncursor = 0 ;
            }
            if (cursor && !oldCursor) {
                SetCapture(hwnd) ;
                oldCursor = cursor ;
            }
         }
         break ;
      case WM_PAINT:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         dc = BeginPaint(hwnd, &ps) ;
         GetClientRect(hwnd,&r) ;
         DrawBorder(dc,&r,ptr->vertical) ;
         
         DrawTitle(dc,&r,ptr->vertical) ;
         EndPaint(hwnd, &ps) ;
         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 = LSCONTROL ;
         dmgrAddClient(ptr) ;
         GetClientRect(hwnd,&r) ;
         ptr->u.cw.closebutton = CreateWindow("BUTTON","",
                     WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_BITMAP,
                     (!ptr->vertical ? r.right-BUTTONCORNER -BUTTONWIDTH: BUTTONCORNER),BUTTONCORNER,BUTTONWIDTH,BUTTONWIDTH,hwnd,(HMENU)64371,
                     (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0) ;
         ptr->u.cw.flexbutton = CreateWindow("BUTTON","",
                     WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_BITMAP,
                     (!ptr->vertical ? r.right-BUTTONCORNER - 2*BUTTONWIDTH-2 : BUTTONCORNER),(!ptr->vertical ? BUTTONCORNER: r.top + BUTTONCORNER + 2 + 2*BUTTONWIDTH),BUTTONWIDTH,BUTTONWIDTH,hwnd,(HMENU)64372,
                     (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0) ;
         ptr->u.cw.disabled = TRUE ;
         SetFlexBmp(ptr) ;
         SendMessage(ptr->u.cw.closebutton,BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)closebitmap) ;
			return 0 ;
		case WM_DESTROY:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         dmgrRemoveClient(ptr) ;
         DestroyWindow(ptr->u.cw.closebutton) ;
         DestroyWindow(ptr->u.cw.flexbutton) ;
         HeapFree(GetProcessHeap(),0,ptr) ;
         break ;
		case WM_CLOSE:

         return 0 ;
      case LCF_ADJUSTRECT:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         pr = (RECT *)lParam ;
         if (ptr->vertical) {
            pr->left += temp = EDGEWIDTH; //+ GetSystemMetrics(SM_CXDLGFRAME)+1;
            pr->right -= temp ;
            pr->left += TITLEWIDTH-EDGEWIDTH;
            pr->top += temp = EDGEWIDTH ; //GetSystemMetrics(SM_CYDLGFRAME)+1;
            pr->bottom-= temp ;
         } else {
            pr->left += temp = EDGEWIDTH ; // GetSystemMetrics(SM_CXDLGFRAME)+1;
            pr->right -= temp ;
            pr->top += temp = EDGEWIDTH ; //GetSystemMetrics(SM_CYDLGFRAME)+1;
            pr->bottom-= temp ;
            pr->top += TITLEWIDTH-EDGEWIDTH;

         }
         return 0 ;
      case LCF_SETFLEX:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         ptr->u.cw.disabled = !(int)lParam ;
         ptr->u.cw.flexed = (int)wParam ;
         SetFlexBmp(ptr) ;
         return 0 ;
      case LCF_SETVERTICAL:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         ptr->vertical = (int) lParam ;
         InvalidateRect(hwnd,0,0) ;
         return 0 ;
      case WM_CTLCOLORBTN:
      case WM_CTLCOLORDLG:
      case WM_CTLCOLOREDIT:
      case WM_CTLCOLORLISTBOX:
      case WM_CTLCOLORMSGBOX:
      case WM_CTLCOLORSCROLLBAR:
      case WM_CTLCOLORSTATIC:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         return SendMessage(ptr->parent,iMessage,wParam,lParam) ;
      case WM_SIZE :
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         SetFlexBmp(ptr) ;
         if (ptr->vertical) {
            MoveWindow(ptr->u.cw.closebutton,BUTTONCORNER,BUTTONCORNER,BUTTONWIDTH,BUTTONWIDTH,0 );
            MoveWindow(ptr->u.cw.flexbutton,BUTTONCORNER, BUTTONCORNER + BUTTONWIDTH +2,BUTTONWIDTH,BUTTONWIDTH,0 );
         } else {
            MoveWindow(ptr->u.cw.closebutton,LOWORD(lParam)-BUTTONCORNER-BUTTONWIDTH,BUTTONCORNER,BUTTONWIDTH,BUTTONWIDTH, 1) ;
            MoveWindow(ptr->u.cw.flexbutton,LOWORD(lParam)-BUTTONCORNER-2*BUTTONWIDTH-2,BUTTONCORNER,BUTTONWIDTH,BUTTONWIDTH, 1) ;
         }
         return 0 ;
      case WM_DRAWITEM:
         ptr = (CCW_params *)GetWindowLong(hwnd,0) ;
         return SendMessage(ptr->parent, iMessage, wParam, lParam) ;
	}
   return DefWindowProc(hwnd, iMessage, wParam, lParam) ;
}

void RegisterControlWindow(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 = szControlWindClassName ;
		RegisterClass(&wc) ;

         closebitmap = LoadBitmap(hInstance,"ID_CLOSEBMP") ;
         ChangeBitmapColor(closebitmap,0xc0c0c0,GetSysColor(COLOR_INACTIVEBORDER)) ;
         uparr = LoadBitmap(hInstance,"ID_UPARR") ;
         ChangeBitmapColor(uparr,0xc0c0c0,GetSysColor(COLOR_INACTIVEBORDER)) ;
         downarr = LoadBitmap(hInstance,"ID_DOWNARR") ;
         ChangeBitmapColor(downarr,0xc0c0c0,GetSysColor(COLOR_INACTIVEBORDER)) ;
         leftarr = LoadBitmap(hInstance,"ID_LEFTARR") ;
         ChangeBitmapColor(leftarr,0xc0c0c0,GetSysColor(COLOR_INACTIVEBORDER)) ;
         rightarr = LoadBitmap(hInstance,"ID_RIGHTARR") ;
         ChangeBitmapColor(rightarr,0xc0c0c0,GetSysColor(COLOR_INACTIVEBORDER)) ;
         uparrdis = LoadBitmap(hInstance,"ID_UPARRDIS") ;
         ChangeBitmapColor(uparrdis,0xc0c0c0,GetSysColor(COLOR_INACTIVEBORDER)) ;
         leftarrdis = LoadBitmap(hInstance,"ID_LEFTARRDIS") ;
         ChangeBitmapColor(leftarrdis,0xc0c0c0,GetSysColor(COLOR_INACTIVEBORDER)) ;
         hcurs = LoadCursor(hInstance,"ID_SIZEHCUR") ;
         vcurs = LoadCursor(hInstance,"ID_SIZEVCUR") ;
         lcurs = LoadCursor(hInstance,"ID_SIZELCUR") ;
         rcurs = LoadCursor(hInstance,"ID_SIZERCUR") ;
         mcurs = LoadCursor(hInstance,"ID_MOVECUR") ;

}
HWND CreateControlWindow(int id, HWND parent, RECT *r, int vertical)
{
   CCW_params p ;
   HWND hwnd ;
   RECT r1,r2 ;
   memset(&p,0,sizeof(p)); 
   p.vertical = vertical ;
   p.parent = parent ;
   p.id = id ;
   hwnd = CreateWindow(szControlWindClassName, "",
            WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE | WS_CHILD,
            r->left,r->top,r->right-r->left,r->bottom-r->top, 
            parent, (HMENU)0 ,(HINSTANCE)GetWindowLong(parent,GWL_HINSTANCE), &p) ;

   return hwnd ;
#ifdef XXXXX
   GetWindowRect(hwnd,&r1) ;
   GetRelativeRect(hwndClient,hwnd,&r1) ;
   r2 = r1 ;
   r2.left = r2.right = r2.right + GetSystemMetrics(SM_CXDLGFRAME);
   r2.top -= GetSystemMetrics(SM_CYDLGFRAME) ;
   r2.bottom += GetSystemMetrics(SM_CYDLGFRAME) ;
   CreateFrameWindow(hwndClient,&r2,1) ;

   GetClientRect(hwndClient,&r2) ;
   r1.left = 0 ; r1.right = r2.right ;
   r1.top = r1.bottom = r1.bottom + GetSystemMetrics(SM_CYDLGFRAME);
   CreateFrameWindow(hwndClient,&r1,0) ;
   return hwnd ;   
#endif
}