/*
**  CUTILS.C
**
**  Common utilities for common controls
**
*/

#include "ctlspriv.h"

#define CCS_ALIGN (CCS_TOP|CCS_NOMOVEY|CCS_BOTTOM)


INT iDitherCount = 0;
HBRUSH hbrDither = NULL;

INT nSysColorChanges = 0;
DWORD rgbFace;       // globals used a lot
DWORD rgbShadow;
DWORD rgbHilight;
DWORD rgbFrame;

INT iThumbCount = 0;
HBITMAP hbmThumb = NULL;     // the thumb bitmap

// Note that the default alignment is CCS_BOTTOM
VOID NewSize(HWND hWnd, int nHeight, LONG style, int left, int top, int width, int height)
{
  RECT rc, rcWindow, rcBorder;

  /* Resize the window unless the user said not to
   */
  if (!(style & CCS_NORESIZE))
  {
      /* Calculate the borders around the client area of the status bar
       */
      GetWindowRect(hWnd, &rcWindow);
      rcWindow.right -= rcWindow.left;
      rcWindow.bottom -= rcWindow.top;

      GetClientRect(hWnd, &rc);
      ClientToScreen(hWnd, (LPPOINT)&rc);

      rcBorder.left = rc.left - rcWindow.left;
      rcBorder.top  = rc.top  - rcWindow.top ;
      rcBorder.right  = rcWindow.right  - rc.right  - rcBorder.left;
      rcBorder.bottom = rcWindow.bottom - rc.bottom - rcBorder.top ;

      nHeight += rcBorder.top + rcBorder.bottom;

      /* Check whether to align to the parent window
       */
      if (style & CCS_NOPARENTALIGN)
      {
         /* Check out whether this bar is top aligned or bottom aligned
          */
         switch ((style&CCS_ALIGN))
         {
            case CCS_TOP:
            case CCS_NOMOVEY:
               break;

            default:
               top = top + height - nHeight;
         }
      }
      else
      {
         /* It is assumed there is a parent by default
          */
         GetClientRect(GetParent(hWnd), &rc);

         /* Don't forget to account for the borders
          */
         left = -rcBorder.left;
         width = rc.right + rcBorder.left + rcBorder.right;

         if ((style&CCS_ALIGN) == CCS_TOP)
             top = -rcBorder.top;
         else if ((style&CCS_ALIGN) != CCS_NOMOVEY)
            top = rc.bottom - nHeight + rcBorder.bottom;
      }

      SetWindowPos(hWnd, NULL, left, top, width, nHeight, SWP_NOZORDER);
  }
}


HBITMAP NEAR PASCAL CreateDitherBitmap()
{
    PBITMAPINFO pbmi;
    HBITMAP hbm;
    HDC hdc;
    int i;
    long patGray[8];
    DWORD rgb;

    pbmi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) * 16));
    if (!pbmi)
        return NULL;

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = 8;
    pbmi->bmiHeader.biHeight = 8;
    pbmi->bmiHeader.biPlanes = 1;
    pbmi->bmiHeader.biBitCount = 1;
    pbmi->bmiHeader.biCompression = BI_RGB;

    rgb = GetSysColor(COLOR_BTNFACE);
    pbmi->bmiColors[0].rgbBlue  = GetBValue(rgb);
    pbmi->bmiColors[0].rgbGreen = GetGValue(rgb);
    pbmi->bmiColors[0].rgbRed   = GetRValue(rgb);
    pbmi->bmiColors[0].rgbReserved = 0;

    rgb = GetSysColor(COLOR_BTNHIGHLIGHT);
    pbmi->bmiColors[1].rgbBlue  = GetBValue(rgb);
    pbmi->bmiColors[1].rgbGreen = GetGValue(rgb);
    pbmi->bmiColors[1].rgbRed   = GetRValue(rgb);
    pbmi->bmiColors[1].rgbReserved = 0;

    /* initialize the brushes */

    for (i = 0; i < 8; i++)
       if (i & 1)
           patGray[i] = 0xAAAA5555L;   //  0x11114444L; // lighter gray
       else
           patGray[i] = 0x5555AAAAL;   //  0x11114444L; // lighter gray

    hdc = GetDC(NULL);

    hbm = CreateDIBitmap(hdc, &pbmi->bmiHeader, CBM_INIT, patGray, pbmi, DIB_RGB_COLORS);

    ReleaseDC(NULL, hdc);

    LocalFree(pbmi);

    return hbm;
}


// initialize the hbrDither global brush
// Call this with bIgnoreCount == TRUE if you just want to update the
// current dither brush.

BOOL FAR PASCAL CreateDitherBrush(BOOL bIgnoreCount)
{
   HBITMAP hbmGray;
   HBRUSH hbrSave;

   if (bIgnoreCount && !iDitherCount)
      return TRUE;

   if (iDitherCount>0 && !bIgnoreCount) {
      iDitherCount++;
      return TRUE;
   }

   hbmGray = CreateDitherBitmap();
   if (hbmGray) {
      hbrSave = hbrDither;
      hbrDither = CreatePatternBrush(hbmGray);
      DeleteObject(hbmGray);
      if (hbrDither) {
         if (hbrSave)
            DeleteObject(hbrSave);
         if (!bIgnoreCount)
            iDitherCount = 1;
         return TRUE;
      } else {
         hbrDither = hbrSave;
      }
   }

   return FALSE;
}

BOOL FAR PASCAL FreeDitherBrush(void)
{
    iDitherCount--;

    if (iDitherCount > 0)
        return FALSE;

    DeleteObject(hbrDither);
    hbrDither = NULL;

    return TRUE;
}


// initialize the hbmThumb global bitmap
// Call this with bIgnoreCount == TRUE if you just want to update the
// current bitmap.

void FAR PASCAL CreateThumb(BOOL bIgnoreCount)
{
   HBITMAP hbmSave;

   if (bIgnoreCount && !iThumbCount)
      return;

   if (iThumbCount && !bIgnoreCount) {
      ++iThumbCount;
      return;
   }

   hbmSave = hbmThumb;
   hbmThumb = CreateMappedBitmap(hInst, IDB_THUMB, FALSE, NULL, 0);

   if (hbmThumb) {
      if (hbmSave)
         DeleteObject(hbmSave);
      if (!bIgnoreCount)
         iThumbCount = 1;
   }
   else
      hbmThumb = hbmSave;
}

void FAR PASCAL DestroyThumb(void)
{
   iThumbCount--;

   if (iThumbCount <= 0) {
      if (hbmThumb)
         DeleteObject(hbmThumb);

      hbmThumb = NULL;
      iThumbCount = 0;
   }
}

// Note that the trackbar will pass in NULL for pTBState, because it
// just wants the dither brush to be updated.

void FAR PASCAL CheckSysColors(void)
{
   static COLORREF rgbSaveFace    = 0xffffffffL,
                   rgbSaveShadow  = 0xffffffffL,
                   rgbSaveHilight = 0xffffffffL,
                   rgbSaveFrame   = 0xffffffffL;

   rgbFace    = GetSysColor(COLOR_BTNFACE);
   rgbShadow  = GetSysColor(COLOR_BTNSHADOW);
   rgbHilight = GetSysColor(COLOR_BTNHIGHLIGHT);
   rgbFrame   = GetSysColor(COLOR_WINDOWFRAME);

   if (rgbSaveFace != rgbFace || rgbSaveShadow != rgbShadow
      || rgbSaveHilight != rgbHilight || rgbSaveFrame != rgbFrame)
   {
      ++nSysColorChanges;
      // Update the brush for pushed-in buttons
      CreateDitherBrush(TRUE);
      CreateThumb(TRUE);
   }
}