+// These are internal functions, based on the WINE sources. Currently they
+// are only implemented for DSS_NORMAL and DST_TEXT, although some handling
+// for DST_BITMAP has been included.
+
+WINBOOL INTERNAL_DrawStateDraw(HDC hdc, UINT type, DRAWSTATEPROC lpOutputFunc,
+ LPARAM lData, WPARAM wData, LPRECT rc, UINT dtflags,
+ BOOL unicode)
+{
+// HDC MemDC;
+// HBITMAP MemBMP;
+ BOOL retval = FALSE;
+ INT cx = rc->right - rc->left;
+ INT cy = rc->bottom - rc->top;
+
+// Is this supposed to happen?
+// if (((type == DST_TEXT) || (type == DST_PREFIXTEXT)) && (lpOutputFunc))
+// type = DST_COMPLEX;
+
+ switch(type)
+ {
+ case DST_TEXT :
+ case DST_PREFIXTEXT :
+ {
+ DbgPrint("Drawing DST_TEXT\n");
+ if (unicode)
+ return DrawTextW(hdc, (LPWSTR)lData, (INT)wData, rc, dtflags);
+ else
+ return DrawTextA(hdc, (LPSTR)lData, (INT)wData, rc, dtflags);
+ }
+
+ case DST_ICON :
+ {
+ // TODO
+ DbgPrint("Drawing DST_ICON\n");
+ return retval;
+ }
+
+ case DST_BITMAP :
+ {
+ // TODO
+ DbgPrint("Drawing DST_BITMAP\n");
+ return retval;
+ }
+
+ case DST_COMPLEX :
+ {
+ DbgPrint("Drawing DST_COMPLEX\n");
+ // Call lpOutputFunc, if necessary
+ if (lpOutputFunc)
+ {
+ // Something seems to be wrong with OffsetViewportOrgEx:
+ OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
+ DbgPrint("Calling lpOutputFunc(0x%x, 0x%x, 0x%x, %d, %d)\n", hdc, lData, wData, cx, cy);
+ retval = lpOutputFunc(hdc, lData, wData, cx, cy);
+ OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
+ return retval;
+ }
+ else
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+WINBOOL INTERNAL_DrawState(
+ HDC hdc,
+ HBRUSH hbr,
+ DRAWSTATEPROC lpOutputFunc,
+ LPARAM lData,
+ WPARAM wData,
+ int x,
+ int y,
+ int cx,
+ int cy,
+ UINT fuFlags,
+ BOOL unicode)
+{
+ UINT type;
+ UINT state;
+ INT len;
+ RECT rect;
+ UINT dtflags = DT_NOCLIP; // Flags for DrawText
+ BOOL retval = FALSE; // Return value
+
+ COLORREF ForeColor, // Foreground color
+ BackColor; // Background color
+
+ HDC MemDC = NULL; // Memory DC
+ HBITMAP MemBMP = NULL, // Memory bitmap (for MemDC)
+ OldBMP = NULL; // Old memory bitmap (for MemDC)
+ HFONT Font = NULL; // Old font (for MemDC)
+ HBRUSH OldBrush = NULL, // Old brush (for MemDC)
+ TempBrush = NULL; // Temporary brush (for MemDC)
+
+ // AG: Experimental, unfinished, and most likely buggy! I haven't been
+ // able to test this - my intention was to implement some things needed
+ // by the button control.
+
+ if ((! lpOutputFunc) && (fuFlags & DST_COMPLEX))
+ return FALSE;
+
+ type = fuFlags & 0xf; // DST_xxx
+ state = fuFlags & 0x7ff0; // DSS_xxx
+ len = wData; // Data length
+
+ DbgPrint("Entered DrawState, fuFlags %d, type %d, state %d\n", fuFlags, type, state);
+
+ if ((type == DST_TEXT || type == DST_PREFIXTEXT) && ! len)
+ {
+ // The string is NULL-terminated
+ if (unicode)
+ len = lstrlenW((LPWSTR) lData);
+ else
+ len = strlen((LPSTR) lData);
+ }
+
+ // Identify the image size if not specified
+ if (!cx || !cy)
+ {
+ SIZE s;
+// CURSORICONINFO *ici;
+ BITMAP bm;
+
+ switch(type) // TODO
+ {
+ case DST_TEXT :
+ case DST_PREFIXTEXT :
+ {
+ BOOL success;
+
+ DbgPrint("Calculating rect of DST_TEXT / DST_PREFIXTEXT\n");
+
+ if (unicode)
+ success = GetTextExtentPoint32W(hdc, (LPWSTR) lData, len, &s);
+ else
+ success = GetTextExtentPoint32A(hdc, (LPSTR) lData, len, &s);
+
+ if (!success) return FALSE;
+ break;
+ }
+
+ case DST_ICON :
+ {
+ DbgPrint("Calculating rect of DST_ICON\n");
+ // TODO
+ break;
+ }
+
+ case DST_BITMAP :
+ {
+ DbgPrint("Calculating rect of DST_BITMAP\n");
+
+ if (!GetObjectA((HBITMAP) lData, sizeof(bm), &bm))
+ return FALSE;
+
+ s.cx = bm.bmWidth;
+ s.cy = bm.bmHeight;
+ break;
+ }
+
+ case DST_COMPLEX : // cx and cy must be set in this mode
+ DbgPrint("Calculating rect of DST_COMPLEX - Not allowed!\n");
+ return FALSE;
+ }
+
+ if (! cx) cx = s.cx;
+ if (! cy) cy = s.cy;
+ }
+
+ // Flags for DrawText
+ if (fuFlags & DSS_RIGHT) // Undocumented
+ dtflags |= DT_RIGHT;
+ if (type == DST_TEXT)
+ dtflags |= DT_NOPREFIX;
+
+ // No additional processing needed for DSS_NORMAL
+ if (state == DSS_NORMAL)
+ {
+ DbgPrint("DSS_NORMAL (no additional processing necessary)\n");
+ SetRect(&rect, x, y, x + cx, y + cy);
+ return INTERNAL_DrawStateDraw(hdc, type, lpOutputFunc, lData, wData, &rect, dtflags, unicode);
+ }
+
+ // WARNING: FROM THIS POINT ON THE CODE IS VERY BUGGY
+
+ // Set the rectangle to that of the memory DC
+ SetRect(&rect, 0, 0, cx, cy);
+
+ // Set colors
+ ForeColor = SetTextColor(hdc, RGB(0, 0, 0));
+ BackColor = SetBkColor(hdc, RGB(255, 255, 255));
+
+ // Create and initialize the memory DC
+ MemDC = CreateCompatibleDC(hdc);
+ if (! MemDC) goto cleanup;
+ MemBMP = CreateBitmap(cx, cy, 1, 1, NULL);
+ if (! MemBMP) goto cleanup;
+ OldBMP = (HBITMAP) SelectObject(MemDC, MemBMP);
+ if (! OldBMP) goto cleanup;
+
+ DbgPrint("Created and inited MemDC\n");
+
+ // Set up the default colors and font
+ if (! FillRect(MemDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH))) goto cleanup;
+ SetBkColor(MemDC, RGB(255, 255, 255));
+ SetTextColor(MemDC, RGB(0, 0, 0));
+ Font = (HFONT)SelectObject(MemDC, GetCurrentObject(hdc, OBJ_FONT));
+
+ DbgPrint("Selected font and set colors\n");
+
+ // Enable this line to use the current DC image to begin with (wrong?)
+// if (! BitBlt(MemDC, 0, 0, cx, cy, hdc, x, y, SRCCOPY)) goto cleanup;
+
+ // DST_COMPLEX may draw text as well, so make sure font is selected
+ if (! Font && (type <= DST_PREFIXTEXT)) // THIS FAILS
+ goto cleanup;
+
+ {
+ BOOL TempResult = INTERNAL_DrawStateDraw(MemDC, type, lpOutputFunc, lData, wData, &rect, dtflags, unicode);
+ if (Font) SelectObject(MemDC, Font);
+ if (! TempResult) goto cleanup;
+ }
+
+ DbgPrint("Done drawing\n");
+
+ // Apply state(s?)
+ if (state & DSS_UNION)
+ {
+ DbgPrint("DSS_UNION\n");
+ // Dither the image (not implemented in ReactOS yet?)
+ // TODO
+ }
+
+ // Prepare shadow brush
+ if (state & DSS_DISABLED)
+ TempBrush = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
+ // else if (state & DSS_DEFAULT)
+ // TempBrush = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
+
+ // Draw shadow
+ if (state & (DSS_DISABLED /*|DSS_DEFAULT*/))
+ {
+ DbgPrint("DSS_DISABLED - Drawing shadow\n");
+ if (! TempBrush) goto cleanup;
+ OldBrush = (HBRUSH)SelectObject(hdc, TempBrush);
+ if (! OldBrush) goto cleanup;
+ if (! BitBlt(hdc, x + 1, y + 1, cx, cy, MemDC, 0, 0, 0x00B8074A)) goto cleanup;
+ SelectObject(hdc, OldBrush);
+ DeleteObject(TempBrush);
+ TempBrush = NULL;
+ }
+
+ if (state & DSS_DISABLED)
+ {
+ DbgPrint("DSS_DISABLED - Creating shadow brush 2\n");
+ hbr = TempBrush = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
+ if (! TempBrush) goto cleanup;
+ }
+ else if (! hbr)
+ {
+ DbgPrint("Creating a brush\n");
+ hbr = (HBRUSH) GetStockObject(BLACK_BRUSH);
+ }
+
+ DbgPrint("Selecting new brush\n");
+ OldBrush = (HBRUSH) SelectObject(hdc, hbr);
+
+ // Copy to hdc from MemDC
+ DbgPrint("Blitting\n");
+ if (! BitBlt(hdc, x, y, cx, cy, MemDC, 0, 0, 0x00B8074A)) goto cleanup;
+
+ retval = TRUE;
+
+
+ cleanup :
+ DbgPrint("In cleanup : Font %x OldBrush %x OldBMP %x Tempbrush %x MemBMP %x MemDC %x\n",
+ Font, OldBrush, OldBMP, TempBrush, MemBMP, MemDC);
+ SetTextColor(hdc, ForeColor);
+ SetBkColor(hdc, BackColor);
+ if (OldBrush) SelectObject(MemDC, OldBrush);
+ if (OldBMP) SelectObject(MemDC, OldBMP);
+ if (TempBrush) DeleteObject(TempBrush);
+ if (MemBMP) DeleteObject(MemBMP);
+ if (MemDC) DeleteDC(MemDC);
+
+ DbgPrint("Leaving DrawState() with retval %d\n", retval);
+
+ return retval;
+}
+
+
+/*
+ * @implemented
+ */