2018-10-09 22:39:55 -05:00
|
|
|
// 9 october 2018
|
|
|
|
#define UNICODE
|
|
|
|
#define _UNICODE
|
|
|
|
#define STRICT
|
|
|
|
#define STRICT_TYPED_ITEMIDS
|
|
|
|
#define WINVER 0x0600 /* from Microsoft's winnls.h */
|
|
|
|
#define _WIN32_WINNT 0x0600
|
|
|
|
#define _WIN32_WINDOWS 0x0600 /* from Microsoft's pdh.h */
|
|
|
|
#define _WIN32_IE 0x0700
|
|
|
|
#define NTDDI_VERSION 0x06000000
|
|
|
|
#include <windows.h>
|
|
|
|
#include <commctrl.h>
|
|
|
|
#include <uxtheme.h>
|
|
|
|
#include <vsstyle.h>
|
|
|
|
#include <vssym32.h>
|
2018-10-13 16:56:44 -05:00
|
|
|
#include <windowsx.h>
|
2018-10-09 22:39:55 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2019-09-15 09:52:15 -05:00
|
|
|
// cl winrebarexplorertheme.cpp -MT -link user32.lib kernel32.lib gdi32.lib comctl32.lib uxtheme.lib msimg32.lib _res\windows.res
|
2018-10-12 19:56:53 -05:00
|
|
|
|
2018-10-09 22:39:55 -05:00
|
|
|
void diele(const char *func)
|
|
|
|
{
|
|
|
|
DWORD le;
|
|
|
|
|
|
|
|
le = GetLastError();
|
|
|
|
fprintf(stderr, "%s: %I32u\n", func, le);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void diehr(const char *func, HRESULT hr)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: 0x%08I32X\n", func, hr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
HINSTANCE hInstance;
|
|
|
|
HWND rebar;
|
|
|
|
HWND leftbar;
|
|
|
|
HWND rightbar;
|
2018-10-11 20:03:34 -05:00
|
|
|
HWND rebarCombo;
|
2018-10-11 21:19:10 -05:00
|
|
|
HWND toolbarCombo;
|
|
|
|
HWND toolbarTransparentCheckbox;
|
|
|
|
|
2018-10-14 14:12:00 -05:00
|
|
|
HICON shieldIcon;
|
|
|
|
HICON applicationIcon;
|
2018-10-12 21:45:37 -05:00
|
|
|
HICON helpIcon;
|
2018-10-14 14:12:00 -05:00
|
|
|
HIMAGELIST rightList;
|
2018-10-12 21:45:37 -05:00
|
|
|
|
2018-10-13 13:17:17 -05:00
|
|
|
#define toolbarStyles (WS_CHILD | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | TBSTYLE_FLAT)
|
2018-10-09 22:39:55 -05:00
|
|
|
|
|
|
|
static struct {
|
|
|
|
const WCHAR *text;
|
|
|
|
BOOL dropdown;
|
|
|
|
} leftbarButtons[] = {
|
|
|
|
{ L"Organize", TRUE },
|
|
|
|
{ L"Include in library", TRUE },
|
|
|
|
{ L"Share with", TRUE },
|
|
|
|
{ L"Burn", FALSE },
|
|
|
|
{ L"New folder", FALSE },
|
|
|
|
};
|
|
|
|
|
2018-10-11 21:49:37 -05:00
|
|
|
// TODO check errors
|
2018-10-12 19:56:53 -05:00
|
|
|
// TODO extract colors from the theme
|
2018-10-13 16:56:44 -05:00
|
|
|
void drawExplorerBackground(HTHEME theme, HDC dc, RECT *rcWindow, RECT *rcPaint)
|
2018-10-11 21:19:10 -05:00
|
|
|
{
|
2018-10-11 21:49:37 -05:00
|
|
|
static TRIVERTEX vertices[] = {
|
|
|
|
{ 0, 0, 4 << 8, 80 << 8, 130 << 8, 255 << 8 },
|
|
|
|
{ 0, 0, 17 << 8, 101 << 8, 132 << 8, 255 << 8 },
|
|
|
|
{ 0, 0, 17 << 8, 101 << 8, 132 << 8, 255 << 8 },
|
|
|
|
{ 0, 0, 29 << 8, 121 << 8, 134 << 8, 255 << 8 },
|
|
|
|
};
|
|
|
|
static GRADIENT_RECT gr[2] = {
|
|
|
|
{ 0, 1 },
|
|
|
|
{ 2, 3 },
|
|
|
|
};
|
2018-10-13 16:56:44 -05:00
|
|
|
|
|
|
|
vertices[0].x = rcPaint->left;
|
|
|
|
vertices[0].y = 0;
|
|
|
|
vertices[1].x = rcPaint->right;
|
|
|
|
vertices[1].y = (rcWindow->bottom - rcWindow->top) / 2;
|
|
|
|
vertices[2].x = rcPaint->left;
|
|
|
|
vertices[2].y = (rcWindow->bottom - rcWindow->top) / 2;
|
|
|
|
vertices[3].x = rcPaint->right;
|
|
|
|
vertices[3].y = rcWindow->bottom - rcWindow->top;
|
|
|
|
GradientFill(dc, vertices, 4, (PVOID) gr, 2, GRADIENT_FILL_RECT_V);
|
|
|
|
DrawThemeBackground(theme, dc,
|
|
|
|
1, 0,
|
|
|
|
rcWindow, rcPaint);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO check errors
|
|
|
|
void drawExplorerChevron(HTHEME theme, HDC dc, HWND rebar, WPARAM band, RECT *rcPaint)
|
|
|
|
{
|
|
|
|
REBARBANDINFOW rbi;
|
2018-10-11 21:49:37 -05:00
|
|
|
RECT r;
|
2018-10-13 16:56:44 -05:00
|
|
|
int state;
|
|
|
|
|
|
|
|
ZeroMemory(&rbi, sizeof (REBARBANDINFOW));
|
|
|
|
rbi.cbSize = sizeof (REBARBANDINFOW);
|
|
|
|
rbi.fMask = RBBIM_CHILD | RBBIM_CHEVRONLOCATION | RBBIM_CHEVRONSTATE;
|
|
|
|
SendMessageW(rebar, RB_GETBANDINFOW, band, (LPARAM) (&rbi));
|
|
|
|
if ((rbi.uChevronState & STATE_SYSTEM_INVISIBLE) != 0)
|
|
|
|
return;
|
|
|
|
state = 1;
|
|
|
|
// TODO check if this is correct
|
|
|
|
if ((rbi.uChevronState & STATE_SYSTEM_FOCUSED) != 0)
|
|
|
|
state = 4;
|
|
|
|
if ((rbi.uChevronState & STATE_SYSTEM_HOTTRACKED) != 0)
|
|
|
|
state = 2;
|
|
|
|
if ((rbi.uChevronState & STATE_SYSTEM_PRESSED) != 0)
|
|
|
|
state = 3;
|
|
|
|
r = rbi.rcChevronLocation;
|
|
|
|
// TODO commctrl.h says this should be correct for the chevron rect, but it's not?
|
|
|
|
// MapWindowRect(rbi.hwndChild, rebar, &r);
|
|
|
|
DrawThemeBackground(theme, dc,
|
|
|
|
3, state,
|
|
|
|
&r, rcPaint);
|
|
|
|
DrawThemeBackground(theme, dc,
|
|
|
|
7, 1,
|
|
|
|
&r, rcPaint);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO check errors
|
|
|
|
LRESULT customDrawExplorerRebar(NMCUSTOMDRAW *nm)
|
|
|
|
{
|
2018-10-11 21:49:37 -05:00
|
|
|
HTHEME theme;
|
2018-10-13 16:56:44 -05:00
|
|
|
RECT r;
|
2018-10-11 21:49:37 -05:00
|
|
|
|
|
|
|
if (nm->dwDrawStage != CDDS_PREPAINT)
|
2018-10-13 16:56:44 -05:00
|
|
|
return CDRF_DODEFAULT;
|
2018-10-11 21:49:37 -05:00
|
|
|
theme = OpenThemeData(nm->hdr.hwndFrom, L"CommandModule");
|
2018-10-13 16:56:44 -05:00
|
|
|
GetClientRect(nm->hdr.hwndFrom, &r);
|
|
|
|
drawExplorerBackground(theme, nm->hdc, &r, &(nm->rc));
|
|
|
|
// TODO dwItemSpec is often invalid?!
|
|
|
|
drawExplorerChevron(theme, nm->hdc, nm->hdr.hwndFrom, 0, &(nm->rc));
|
2018-10-11 21:49:37 -05:00
|
|
|
CloseThemeData(theme);
|
2018-10-13 16:56:44 -05:00
|
|
|
return CDRF_SKIPDEFAULT;
|
2018-10-11 21:19:10 -05:00
|
|
|
}
|
|
|
|
|
2018-10-13 16:56:44 -05:00
|
|
|
// TODO check errors
|
|
|
|
LRESULT customDrawExplorerToolbar(NMTBCUSTOMDRAW *nm)
|
2018-10-11 21:19:10 -05:00
|
|
|
{
|
2018-10-13 16:56:44 -05:00
|
|
|
HWND toolbar, rebar;
|
2018-10-14 18:08:02 -05:00
|
|
|
WPARAM itemIndex;
|
|
|
|
TBBUTTON tbb;
|
2018-10-13 16:56:44 -05:00
|
|
|
HTHEME theme;
|
|
|
|
RECT r;
|
2018-10-14 18:08:02 -05:00
|
|
|
int part, state;
|
2018-10-13 16:56:44 -05:00
|
|
|
|
|
|
|
toolbar = nm->nmcd.hdr.hwndFrom;
|
|
|
|
switch (nm->nmcd.dwDrawStage) {
|
|
|
|
case CDDS_PREPAINT:
|
|
|
|
theme = OpenThemeData(toolbar, L"CommandModule");
|
|
|
|
rebar = GetParent(toolbar);
|
|
|
|
GetWindowRect(rebar, &r);
|
|
|
|
MapWindowRect(NULL, toolbar, &r);
|
|
|
|
drawExplorerBackground(theme, nm->nmcd.hdc, &r, &(nm->nmcd.rc));
|
|
|
|
CloseThemeData(theme);
|
|
|
|
return CDRF_NOTIFYITEMDRAW;
|
|
|
|
case CDDS_ITEMPREPAINT:
|
2018-10-14 18:08:02 -05:00
|
|
|
itemIndex = (WPARAM) SendMessageW(toolbar, TB_COMMANDTOINDEX, nm->nmcd.dwItemSpec, 0);
|
|
|
|
ZeroMemory(&tbb, sizeof (TBBUTTON));
|
|
|
|
SendMessageW(toolbar, TB_GETBUTTON, itemIndex, (LPARAM) (&tbb));
|
2018-10-13 16:56:44 -05:00
|
|
|
theme = OpenThemeData(toolbar, L"CommandModule");
|
2018-10-14 18:08:02 -05:00
|
|
|
part = 3;
|
|
|
|
if ((tbb.fsStyle & BTNS_DROPDOWN) != 0)
|
|
|
|
part = 4;
|
2018-10-13 16:56:44 -05:00
|
|
|
state = 1;
|
|
|
|
// TODO this doesn't work; both keyboard and mouse are listed as HOT
|
|
|
|
if ((nm->nmcd.uItemState & CDIS_FOCUS) != 0)
|
|
|
|
state = 4;
|
|
|
|
if ((nm->nmcd.uItemState & CDIS_HOT) != 0)
|
|
|
|
state = 2;
|
|
|
|
if ((nm->nmcd.uItemState & CDIS_SELECTED) != 0)
|
|
|
|
state = 3;
|
2018-10-14 18:08:02 -05:00
|
|
|
SendMessageW(toolbar, TB_GETITEMRECT, itemIndex, (LPARAM) (&r));
|
2018-10-13 16:56:44 -05:00
|
|
|
DrawThemeBackground(theme, nm->nmcd.hdc,
|
|
|
|
3, state,
|
|
|
|
&r, &(nm->nmcd.rc));
|
|
|
|
CloseThemeData(theme);
|
|
|
|
return TBCDRF_NOBACKGROUND;
|
|
|
|
}
|
2018-10-11 21:19:10 -05:00
|
|
|
return CDRF_DODEFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
const WCHAR *text;
|
2018-10-13 16:56:44 -05:00
|
|
|
LRESULT (*handleRebar)(NMCUSTOMDRAW *nm);
|
|
|
|
LRESULT (*handleToolbar)(NMTBCUSTOMDRAW *nm);
|
2018-10-11 21:19:10 -05:00
|
|
|
} drawmodes[] = {
|
2018-10-13 16:56:44 -05:00
|
|
|
{ L"SetWindowTheme()", NULL, NULL },
|
|
|
|
{ L"Custom Draw Explorer", customDrawExplorerRebar, customDrawExplorerToolbar },
|
2018-10-11 21:19:10 -05:00
|
|
|
{ NULL, NULL },
|
2018-10-11 20:03:34 -05:00
|
|
|
};
|
|
|
|
|
2018-10-11 21:19:10 -05:00
|
|
|
int drawmode = 0;
|
|
|
|
|
2018-10-11 20:03:34 -05:00
|
|
|
static const WCHAR *rebarThemes[] = {
|
|
|
|
L"NULL",
|
|
|
|
L"",
|
|
|
|
L"AlternateRebar",
|
|
|
|
L"BrowserTabBar",
|
|
|
|
L"Communications",
|
|
|
|
L"Default",
|
|
|
|
L"ExplorerBar",
|
|
|
|
L"Help",
|
|
|
|
L"InactiveNavbar",
|
|
|
|
L"InactiveNavbarComposited",
|
|
|
|
L"ITBarBase",
|
|
|
|
L"MaxInactiveNavbar",
|
|
|
|
L"MaxInactiveNavbarComposited",
|
|
|
|
L"MaxNavbar",
|
|
|
|
L"MaxNavbarComposited",
|
|
|
|
L"Media",
|
|
|
|
L"Navbar",
|
|
|
|
L"NavbarBase",
|
|
|
|
L"NavbarComposited",
|
|
|
|
L"NavbarNonTopmost",
|
|
|
|
L"Rebar",
|
|
|
|
L"RebarStyle",
|
|
|
|
L"TaskBar",
|
|
|
|
L"TaskBarComposited",
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2018-10-11 21:19:10 -05:00
|
|
|
static WCHAR *toolbarThemes[] = {
|
|
|
|
L"NULL",
|
|
|
|
L"",
|
|
|
|
L"Alternate",
|
|
|
|
L"BB",
|
|
|
|
L"BBComposited",
|
|
|
|
L"Communications",
|
|
|
|
L"ExplorerMenu",
|
|
|
|
L"Go",
|
|
|
|
L"GoComposited",
|
|
|
|
L"InactiveBB",
|
|
|
|
L"InactiveBBComposited",
|
|
|
|
L"InactiveGo",
|
|
|
|
L"InactiveGoComposited",
|
|
|
|
L"InfoPaneToolbar",
|
|
|
|
L"LVPopup",
|
|
|
|
L"LVPopupBottom",
|
|
|
|
L"MaxBB",
|
|
|
|
L"MaxBBComposited",
|
|
|
|
L"MaxGo",
|
|
|
|
L"MaxGoComposited",
|
|
|
|
L"MaxInactiveBB",
|
|
|
|
L"MaxInactiveBBComposited",
|
|
|
|
L"MaxInactiveGo",
|
|
|
|
L"MaxInactiveGoComposited",
|
|
|
|
L"Media",
|
|
|
|
L"Placesbar",
|
|
|
|
L"SearchButton",
|
|
|
|
L"SearchButtonComposited",
|
|
|
|
L"StartMenu",
|
|
|
|
L"TaskBar",
|
|
|
|
L"TaskBarComposited",
|
|
|
|
L"TaskBarVert",
|
|
|
|
L"TaskBarVertComposited",
|
|
|
|
L"Toolbar",
|
|
|
|
L"ToolbarStyle",
|
|
|
|
L"TrayNotify",
|
|
|
|
L"TrayNotifyComposited",
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2018-10-11 20:03:34 -05:00
|
|
|
// TODO toolbarThemes
|
|
|
|
|
2018-10-09 22:39:55 -05:00
|
|
|
void onWM_CREATE(HWND hwnd)
|
|
|
|
{
|
|
|
|
TBBUTTON tbb[5];
|
2018-10-11 03:10:36 -05:00
|
|
|
RECT btnrect;
|
|
|
|
DWORD tbbtnsize;
|
|
|
|
LONG tbsizex, tbsizey;
|
2018-10-09 22:39:55 -05:00
|
|
|
REBARBANDINFOW rbi;
|
2018-10-11 20:03:34 -05:00
|
|
|
HWND button;
|
|
|
|
LONG buttonx, buttony;
|
|
|
|
LONG combox, comboy;
|
2018-10-09 22:39:55 -05:00
|
|
|
int i;
|
|
|
|
|
|
|
|
rebar = CreateWindowExW(0,
|
|
|
|
REBARCLASSNAMEW, NULL,
|
2018-10-13 13:17:17 -05:00
|
|
|
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NODIVIDER | CCS_TOP | RBS_FIXEDORDER,
|
2018-10-09 22:39:55 -05:00
|
|
|
0, 0, 0, 0,
|
|
|
|
hwnd, (HMENU) 100, hInstance, NULL);
|
|
|
|
if (rebar == NULL)
|
|
|
|
diele("CreateWindowExW(REBARCLASSNAMEW)");
|
|
|
|
|
|
|
|
leftbar = CreateWindowExW(0,
|
|
|
|
TOOLBARCLASSNAMEW, NULL,
|
2018-10-13 13:17:17 -05:00
|
|
|
toolbarStyles | TBSTYLE_LIST | TBSTYLE_TRANSPARENT,
|
2018-10-09 22:39:55 -05:00
|
|
|
0, 0, 0, 0,
|
|
|
|
hwnd, (HMENU) 101, hInstance, NULL);
|
2018-10-12 21:45:37 -05:00
|
|
|
if (leftbar == NULL)
|
|
|
|
diele("CreateWindowExW(TOOLBARCLASSNAMEW) leftbar");
|
2018-10-09 22:39:55 -05:00
|
|
|
SendMessageW(leftbar, TB_BUTTONSTRUCTSIZE, sizeof (TBBUTTON), 0);
|
2018-10-11 03:10:36 -05:00
|
|
|
// I_IMAGENONE causes the button text to be left-aligned; don't use it
|
2018-10-14 17:42:51 -05:00
|
|
|
// if (SendMessageW(leftbar, TB_SETBITMAPSIZE, 0, 0) == FALSE)
|
|
|
|
// diele("TB_SETBITMAPSIZE");
|
2018-10-11 03:10:36 -05:00
|
|
|
SendMessageW(leftbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_MIXEDBUTTONS);
|
2018-10-11 04:35:06 -05:00
|
|
|
// TODO this *should* be DIPs...
|
|
|
|
// TODO figure out where the *2 is documented
|
2018-10-14 17:42:51 -05:00
|
|
|
// SendMessageW(leftbar, TB_SETPADDING, 0, MAKELPARAM(6 * 2, 5 * 2));
|
2018-10-09 22:39:55 -05:00
|
|
|
ZeroMemory(tbb, 5 * sizeof (TBBUTTON));
|
|
|
|
for (i = 0; i < 5; i++) {
|
2018-10-11 03:10:36 -05:00
|
|
|
tbb[i].iBitmap = 0;
|
2018-10-09 22:39:55 -05:00
|
|
|
tbb[i].idCommand = i;
|
|
|
|
tbb[i].fsState = TBSTATE_ENABLED;
|
|
|
|
tbb[i].fsStyle = BTNS_AUTOSIZE | BTNS_BUTTON | BTNS_NOPREFIX | BTNS_SHOWTEXT;
|
|
|
|
if (leftbarButtons[i].dropdown)
|
|
|
|
tbb[i].fsStyle |= BTNS_DROPDOWN | BTNS_WHOLEDROPDOWN;
|
|
|
|
tbb[i].iString = (INT_PTR) (leftbarButtons[i].text);
|
|
|
|
}
|
2018-10-11 03:10:36 -05:00
|
|
|
if (SendMessageW(leftbar, TB_ADDBUTTONSW, 5, (LPARAM) tbb) == FALSE)
|
|
|
|
diele("TB_ADDBUTTONSW");
|
|
|
|
|
|
|
|
tbsizex = 0;
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
|
|
if (SendMessageW(leftbar, TB_GETITEMRECT, (WPARAM) i, (LPARAM) (&btnrect)) == FALSE)
|
|
|
|
diele("TB_GETITEMRECT");
|
|
|
|
tbsizex += btnrect.right - btnrect.left;
|
|
|
|
}
|
|
|
|
tbbtnsize = (DWORD) SendMessageW(leftbar, TB_GETBUTTONSIZE, 0, 0);
|
|
|
|
tbsizey = HIWORD(tbbtnsize);
|
2018-10-09 22:39:55 -05:00
|
|
|
|
|
|
|
ZeroMemory(&rbi, sizeof (REBARBANDINFOW));
|
|
|
|
rbi.cbSize = sizeof (REBARBANDINFOW);
|
2018-10-13 16:56:44 -05:00
|
|
|
rbi.fMask = RBBIM_CHILD | RBBIM_STYLE | RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_ID;
|
2018-10-13 13:17:17 -05:00
|
|
|
rbi.fStyle = RBBS_NOGRIPPER | RBBS_CHILDEDGE | RBBS_USECHEVRON | RBBS_HIDETITLE;
|
2018-10-09 22:39:55 -05:00
|
|
|
rbi.hwndChild = leftbar;
|
2018-10-11 03:10:36 -05:00
|
|
|
rbi.cx = tbsizex;
|
|
|
|
rbi.cyChild = tbsizey;
|
|
|
|
rbi.cxMinChild = 0;
|
|
|
|
rbi.cyMinChild = tbsizey;
|
2018-10-11 04:35:06 -05:00
|
|
|
rbi.cxIdeal = tbsizex;
|
2018-10-13 16:56:44 -05:00
|
|
|
rbi.wID = 0;
|
2018-10-13 13:17:17 -05:00
|
|
|
if (SendMessageW(rebar, RB_INSERTBANDW, (WPARAM) (-1), (LPARAM) (&rbi)) == 0)
|
|
|
|
diele("RB_INSERTBANDW leftbar");
|
2018-10-12 21:45:37 -05:00
|
|
|
|
|
|
|
rightbar = CreateWindowExW(0,
|
|
|
|
TOOLBARCLASSNAMEW, NULL,
|
2018-10-13 13:17:17 -05:00
|
|
|
toolbarStyles | TBSTYLE_TRANSPARENT,
|
2018-10-12 21:45:37 -05:00
|
|
|
0, 0, 0, 0,
|
|
|
|
hwnd, (HMENU) 102, hInstance, NULL);
|
|
|
|
if (rightbar == NULL)
|
|
|
|
diele("CreateWindowExW(TOOLBARCLASSNAMEW) rightbar");
|
|
|
|
SendMessageW(rightbar, TB_BUTTONSTRUCTSIZE, sizeof (TBBUTTON), 0);
|
2018-10-14 14:12:00 -05:00
|
|
|
SendMessageW(rightbar, TB_SETIMAGELIST, 0, (LPARAM) rightList);
|
|
|
|
SendMessageW(rightbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS);
|
2018-10-13 13:17:17 -05:00
|
|
|
// TODO this *should* be DIPs...
|
|
|
|
// TODO figure out where the *2 is documented
|
2018-10-14 17:42:51 -05:00
|
|
|
// SendMessageW(rightbar, TB_SETPADDING, 0, MAKELPARAM(6 * 2, 5 * 2));
|
2018-10-12 21:45:37 -05:00
|
|
|
ZeroMemory(tbb, 5 * sizeof (TBBUTTON));
|
|
|
|
tbb[0].iBitmap = 0;
|
|
|
|
tbb[0].idCommand = 0;
|
|
|
|
tbb[0].fsState = TBSTATE_ENABLED;
|
2018-10-14 14:12:00 -05:00
|
|
|
tbb[0].fsStyle = BTNS_AUTOSIZE | BTNS_BUTTON | BTNS_DROPDOWN;
|
|
|
|
tbb[1].iBitmap = 1;
|
|
|
|
tbb[1].idCommand = 1;
|
|
|
|
tbb[1].fsState = TBSTATE_ENABLED;
|
|
|
|
tbb[1].fsStyle = BTNS_AUTOSIZE | BTNS_BUTTON;
|
|
|
|
tbb[2].iBitmap = 2;
|
|
|
|
tbb[2].idCommand = 2;
|
|
|
|
tbb[2].fsState = TBSTATE_ENABLED;
|
|
|
|
tbb[2].fsStyle = BTNS_AUTOSIZE | BTNS_BUTTON;
|
|
|
|
if (SendMessageW(rightbar, TB_ADDBUTTONSW, 3, (LPARAM) tbb) == FALSE)
|
2018-10-12 21:45:37 -05:00
|
|
|
diele("TB_ADDBUTTONSW");
|
2018-10-13 13:17:17 -05:00
|
|
|
// TODO check error
|
|
|
|
// TODO figure out why this works here but not elsewhere
|
2018-10-14 14:12:00 -05:00
|
|
|
// SendMessageW(rightbar, TB_SETBUTTONSIZE, 0, 0);
|
2018-10-12 21:45:37 -05:00
|
|
|
|
2018-10-14 14:12:00 -05:00
|
|
|
tbsizex = 0;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
if (SendMessageW(rightbar, TB_GETITEMRECT, (WPARAM) i, (LPARAM) (&btnrect)) == FALSE)
|
|
|
|
diele("TB_GETITEMRECT");
|
|
|
|
tbsizex += btnrect.right - btnrect.left;
|
|
|
|
}
|
2018-10-12 21:45:37 -05:00
|
|
|
tbbtnsize = (DWORD) SendMessageW(rightbar, TB_GETBUTTONSIZE, 0, 0);
|
|
|
|
tbsizey = HIWORD(tbbtnsize);
|
|
|
|
|
|
|
|
ZeroMemory(&rbi, sizeof (REBARBANDINFOW));
|
|
|
|
rbi.cbSize = sizeof (REBARBANDINFOW);
|
2018-10-13 16:56:44 -05:00
|
|
|
rbi.fMask = RBBIM_CHILD | RBBIM_STYLE | RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_ID;
|
2018-10-12 21:45:37 -05:00
|
|
|
rbi.fStyle = RBBS_NOGRIPPER | RBBS_HIDETITLE;
|
|
|
|
rbi.hwndChild = rightbar;
|
|
|
|
rbi.cx = tbsizex;
|
|
|
|
rbi.cyChild = tbsizey;
|
|
|
|
rbi.cxMinChild = tbsizex;
|
|
|
|
rbi.cyMinChild = tbsizey;
|
2018-10-13 16:56:44 -05:00
|
|
|
rbi.wID = 1;
|
2018-10-09 22:39:55 -05:00
|
|
|
if (SendMessageW(rebar, RB_INSERTBANDW, (WPARAM) (-1), (LPARAM) (&rbi)) == 0)
|
2018-10-12 21:45:37 -05:00
|
|
|
diele("RB_INSERTBANDW rightbar");
|
2018-10-11 20:03:34 -05:00
|
|
|
|
|
|
|
buttonx = 10;
|
|
|
|
buttony = 40;
|
|
|
|
#define buttonwid 200
|
|
|
|
#define buttonht 25
|
2018-10-11 21:19:10 -05:00
|
|
|
for (i = 0; drawmodes[i].text != NULL; i++) {
|
2018-10-11 20:03:34 -05:00
|
|
|
button = CreateWindowExW(0,
|
2018-10-11 21:19:10 -05:00
|
|
|
L"BUTTON", drawmodes[i].text,
|
2018-10-11 20:03:34 -05:00
|
|
|
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
|
|
|
|
buttonx, buttony,
|
|
|
|
buttonwid, buttonht,
|
|
|
|
hwnd, (HMENU) (200 + i), hInstance, NULL);
|
|
|
|
if (button == NULL)
|
|
|
|
diele("CreateWIndowExW(L\"BUTTON\")");
|
|
|
|
if (i == 0) {
|
|
|
|
combox = buttonx + buttonwid + 5;
|
|
|
|
comboy = buttony;
|
|
|
|
}
|
|
|
|
buttony += buttonht + 5;
|
|
|
|
}
|
2018-10-13 16:56:44 -05:00
|
|
|
button = CreateWindowExW(0,
|
|
|
|
L"BUTTON", L"Give Toolbar Focus",
|
|
|
|
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
|
|
|
|
buttonx, buttony,
|
|
|
|
buttonwid, buttonht,
|
|
|
|
hwnd, (HMENU) (200 + i), hInstance, NULL);
|
|
|
|
if (button == NULL)
|
|
|
|
diele("CreateWIndowExW(L\"BUTTON\")");
|
2018-10-11 20:03:34 -05:00
|
|
|
rebarCombo = CreateWindowExW(WS_EX_CLIENTEDGE,
|
|
|
|
L"COMBOBOX", L"",
|
|
|
|
WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
|
|
|
|
combox, comboy,
|
|
|
|
buttonwid, buttonht,
|
|
|
|
hwnd, (HMENU) 300, hInstance, NULL);
|
|
|
|
if (rebarCombo == NULL)
|
|
|
|
diele("CreateWindowExW(L\"COMBOBOX\")");
|
|
|
|
for (i = 0; rebarThemes[i] != NULL; i++)
|
|
|
|
// TODO check error
|
|
|
|
SendMessageW(rebarCombo, CB_ADDSTRING, 0, (LPARAM) (rebarThemes[i]));
|
2018-10-11 21:19:10 -05:00
|
|
|
comboy += buttonht + 5;
|
|
|
|
toolbarCombo = CreateWindowExW(WS_EX_CLIENTEDGE,
|
|
|
|
L"COMBOBOX", L"",
|
|
|
|
WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
|
|
|
|
combox, comboy,
|
|
|
|
buttonwid, buttonht,
|
|
|
|
hwnd, (HMENU) 301, hInstance, NULL);
|
|
|
|
if (toolbarCombo == NULL)
|
|
|
|
diele("CreateWindowExW(L\"COMBOBOX\")");
|
|
|
|
for (i = 0; toolbarThemes[i] != NULL; i++)
|
|
|
|
// TODO check error
|
|
|
|
SendMessageW(toolbarCombo, CB_ADDSTRING, 0, (LPARAM) (toolbarThemes[i]));
|
|
|
|
comboy += buttonht + 5;
|
|
|
|
toolbarTransparentCheckbox = CreateWindowExW(0,
|
|
|
|
L"BUTTON", L"Transparent toolbar",
|
|
|
|
WS_CHILD | WS_VISIBLE | BS_CHECKBOX,
|
|
|
|
combox, comboy,
|
|
|
|
buttonwid, buttonht,
|
|
|
|
hwnd, (HMENU) 302, hInstance, NULL);
|
|
|
|
if (toolbarTransparentCheckbox == NULL)
|
|
|
|
diele("CreateWindowExW(L\"BUTTON\")");
|
|
|
|
SendMessage(toolbarTransparentCheckbox, BM_SETCHECK, BST_CHECKED, 0);
|
2018-10-09 22:39:55 -05:00
|
|
|
}
|
|
|
|
|
2018-10-11 04:35:06 -05:00
|
|
|
// TODO it seems like I shouldn't have to do this?
|
|
|
|
void repositionRebar(HWND hwnd)
|
|
|
|
{
|
|
|
|
RECT win, rb;
|
|
|
|
|
|
|
|
if (GetClientRect(hwnd, &win) == 0)
|
|
|
|
diele("GetClientRect()");
|
|
|
|
if (GetWindowRect(rebar, &rb) == 0)
|
|
|
|
diele("GetWindowRect()");
|
|
|
|
if (SetWindowPos(rebar, NULL,
|
|
|
|
0, 0, win.right - win.left, rb.bottom - rb.top,
|
|
|
|
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER) == 0)
|
|
|
|
diele("SetWindowPos()");
|
|
|
|
}
|
|
|
|
|
2018-10-11 20:03:34 -05:00
|
|
|
// TODO check errors
|
|
|
|
void handleEvents(HWND hwnd, WPARAM wParam)
|
|
|
|
{
|
|
|
|
LRESULT n;
|
|
|
|
const WCHAR *selRebar = NULL, *selToolbar = NULL;
|
|
|
|
WCHAR *bufRebar = NULL, *bufToolbar = NULL;
|
|
|
|
BOOL changeRebar = FALSE, changeToolbar = FALSE;
|
2018-10-11 21:19:10 -05:00
|
|
|
BOOL invalidate = FALSE;
|
|
|
|
WPARAM check;
|
2018-10-11 20:03:34 -05:00
|
|
|
|
|
|
|
switch (wParam) {
|
|
|
|
case MAKEWPARAM(300, CBN_SELCHANGE):
|
|
|
|
n = SendMessageW(rebarCombo, CB_GETCURSEL, 0, 0);
|
|
|
|
selRebar = rebarThemes[n];
|
|
|
|
changeRebar = TRUE;
|
|
|
|
break;
|
2018-10-11 21:19:10 -05:00
|
|
|
case MAKEWPARAM(301, CBN_SELCHANGE):
|
|
|
|
n = SendMessageW(toolbarCombo, CB_GETCURSEL, 0, 0);
|
|
|
|
selToolbar = toolbarThemes[n];
|
|
|
|
changeToolbar = TRUE;
|
|
|
|
break;
|
2018-10-11 20:03:34 -05:00
|
|
|
case MAKEWPARAM(200, BN_CLICKED):
|
2018-10-11 21:19:10 -05:00
|
|
|
drawmode = 0;
|
2018-10-11 20:03:34 -05:00
|
|
|
n = SendMessageW(rebarCombo, WM_GETTEXTLENGTH, 0, 0);
|
|
|
|
bufRebar = new WCHAR[n + 1];
|
|
|
|
GetWindowTextW(rebarCombo, bufRebar, n + 1);
|
2018-10-11 21:19:10 -05:00
|
|
|
n = SendMessageW(toolbarCombo, WM_GETTEXTLENGTH, 0, 0);
|
|
|
|
bufToolbar = new WCHAR[n + 1];
|
|
|
|
GetWindowTextW(toolbarCombo, bufToolbar, n + 1);
|
2018-10-11 20:03:34 -05:00
|
|
|
selRebar = bufRebar;
|
2018-10-11 21:19:10 -05:00
|
|
|
selToolbar = bufToolbar;
|
2018-10-11 20:03:34 -05:00
|
|
|
changeRebar = TRUE;
|
|
|
|
changeToolbar = TRUE;
|
|
|
|
break;
|
2018-10-11 21:19:10 -05:00
|
|
|
case MAKEWPARAM(201, BN_CLICKED):
|
|
|
|
drawmode = 1;
|
|
|
|
invalidate = TRUE;
|
|
|
|
break;
|
|
|
|
case MAKEWPARAM(302, BN_CLICKED):
|
|
|
|
ShowWindow(leftbar, SW_HIDE);
|
|
|
|
check = BST_CHECKED;
|
|
|
|
if (SendMessage(toolbarTransparentCheckbox, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
|
|
|
check = BST_UNCHECKED;
|
|
|
|
SendMessage(toolbarTransparentCheckbox, BM_SETCHECK, check, 0);
|
|
|
|
if (check == BST_CHECKED)
|
2018-10-13 13:17:17 -05:00
|
|
|
SendMessageW(leftbar, TB_SETSTYLE, 0, toolbarStyles | TBSTYLE_LIST | TBSTYLE_TRANSPARENT);
|
2018-10-11 21:19:10 -05:00
|
|
|
else
|
2018-10-13 13:17:17 -05:00
|
|
|
SendMessageW(leftbar, TB_SETSTYLE, 0, toolbarStyles | TBSTYLE_LIST);
|
2018-10-11 21:19:10 -05:00
|
|
|
ShowWindow(leftbar, SW_SHOW);
|
|
|
|
break;
|
2018-10-13 16:56:44 -05:00
|
|
|
case MAKEWPARAM(202, BN_CLICKED):
|
|
|
|
SetFocus(leftbar);
|
|
|
|
break;
|
2018-10-11 20:03:34 -05:00
|
|
|
}
|
|
|
|
if (changeRebar) {
|
|
|
|
if (selRebar != NULL && wcscmp(selRebar, L"NULL") == 0)
|
|
|
|
selRebar = NULL;
|
|
|
|
if (selRebar != NULL && *selRebar != L'\0')
|
|
|
|
SendMessageW(rebar, RB_SETWINDOWTHEME, 0, (LPARAM) selRebar);
|
|
|
|
else
|
|
|
|
SetWindowTheme(rebar, selRebar, selRebar);
|
2018-10-11 21:19:10 -05:00
|
|
|
invalidate = TRUE;
|
2018-10-11 20:03:34 -05:00
|
|
|
}
|
|
|
|
if (changeToolbar) {
|
|
|
|
if (selToolbar != NULL && wcscmp(selToolbar, L"NULL") == 0)
|
|
|
|
selToolbar = NULL;
|
2018-10-13 16:56:44 -05:00
|
|
|
if (selToolbar != NULL && *selToolbar != L'\0') {
|
2018-10-11 20:03:34 -05:00
|
|
|
SendMessageW(leftbar, TB_SETWINDOWTHEME, 0, (LPARAM) selToolbar);
|
2018-10-13 16:56:44 -05:00
|
|
|
SendMessageW(rightbar, TB_SETWINDOWTHEME, 0, (LPARAM) selToolbar);
|
|
|
|
} else {
|
2018-10-11 20:03:34 -05:00
|
|
|
SetWindowTheme(leftbar, selToolbar, selToolbar);
|
2018-10-13 16:56:44 -05:00
|
|
|
SetWindowTheme(rightbar, selToolbar, selToolbar);
|
|
|
|
}
|
2018-10-11 21:19:10 -05:00
|
|
|
invalidate = TRUE;
|
2018-10-11 20:03:34 -05:00
|
|
|
}
|
2018-10-11 21:19:10 -05:00
|
|
|
if (invalidate)
|
|
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
2018-10-11 20:03:34 -05:00
|
|
|
if (bufRebar != NULL)
|
|
|
|
delete[] bufRebar;
|
|
|
|
if (bufToolbar != NULL)
|
|
|
|
delete[] bufToolbar;
|
|
|
|
}
|
|
|
|
|
2018-10-09 22:39:55 -05:00
|
|
|
LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2018-10-11 21:19:10 -05:00
|
|
|
NMHDR *nm = (NMHDR *) lParam;
|
|
|
|
|
2018-10-09 22:39:55 -05:00
|
|
|
switch (uMsg) {
|
|
|
|
case WM_CREATE:
|
|
|
|
onWM_CREATE(hwnd);
|
|
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
|
|
PostQuitMessage(0);
|
|
|
|
break;
|
2018-10-11 04:35:06 -05:00
|
|
|
case WM_SIZE:
|
|
|
|
repositionRebar(hwnd);
|
|
|
|
break;
|
2018-10-11 20:03:34 -05:00
|
|
|
case WM_COMMAND:
|
|
|
|
handleEvents(hwnd, wParam);
|
|
|
|
break;
|
2018-10-11 21:19:10 -05:00
|
|
|
case WM_NOTIFY:
|
|
|
|
switch (nm->code) {
|
|
|
|
case NM_CUSTOMDRAW:
|
|
|
|
if (drawmode == 0)
|
|
|
|
break;
|
2018-10-13 16:56:44 -05:00
|
|
|
if (nm->hwndFrom == rebar)
|
|
|
|
return (*(drawmodes[drawmode].handleRebar))((NMCUSTOMDRAW *) nm);
|
|
|
|
else if (nm->hwndFrom == leftbar || nm->hwndFrom == rightbar)
|
|
|
|
return (*(drawmodes[drawmode].handleToolbar))((NMTBCUSTOMDRAW *) nm);
|
|
|
|
break;
|
2018-10-11 21:19:10 -05:00
|
|
|
}
|
|
|
|
break;
|
2018-10-09 22:39:55 -05:00
|
|
|
}
|
|
|
|
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
|
|
|
|
|
|
|
int main(void)
|
|
|
|
{
|
|
|
|
STARTUPINFOW si;
|
|
|
|
int nCmdShow;
|
|
|
|
INITCOMMONCONTROLSEX icc;
|
|
|
|
HICON hDefaultIcon;
|
|
|
|
HCURSOR hDefaultCursor;
|
|
|
|
WNDCLASSW wc;
|
|
|
|
HWND mainwin;
|
|
|
|
MSG msg;
|
2018-10-13 13:17:17 -05:00
|
|
|
HRESULT hr;
|
2018-10-09 22:39:55 -05:00
|
|
|
|
|
|
|
hInstance = (HINSTANCE) (&__ImageBase);
|
|
|
|
nCmdShow = SW_SHOWDEFAULT;
|
|
|
|
GetStartupInfoW(&si);
|
|
|
|
if ((si.dwFlags & STARTF_USESHOWWINDOW) != 0)
|
|
|
|
nCmdShow = si.wShowWindow;
|
|
|
|
|
|
|
|
ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
|
|
|
|
icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
|
|
|
|
icc.dwICC = ICC_STANDARD_CLASSES | ICC_BAR_CLASSES | ICC_COOL_CLASSES;
|
|
|
|
if (InitCommonControlsEx(&icc) == 0)
|
|
|
|
diele("InitCommonControlsEx()");
|
|
|
|
|
|
|
|
hDefaultIcon = LoadIconW(NULL, IDI_APPLICATION);
|
|
|
|
if (hDefaultIcon == NULL)
|
|
|
|
diele("LoadIconW(IDI_APPLICATION)");
|
|
|
|
hDefaultCursor = LoadCursorW(NULL, IDC_ARROW);
|
|
|
|
if (hDefaultCursor == NULL)
|
|
|
|
diele("LoadCursorW(IDC_ARROW)");
|
|
|
|
|
2018-10-14 14:12:00 -05:00
|
|
|
hr = LoadIconMetric(NULL, IDI_SHIELD, LIM_SMALL, &shieldIcon);
|
|
|
|
if (hr != S_OK)
|
|
|
|
diehr("LoadIconMetric(IDI_SHIELD)", hr);
|
|
|
|
hr = LoadIconMetric(NULL, IDI_APPLICATION, LIM_SMALL, &applicationIcon);
|
|
|
|
if (hr != S_OK)
|
|
|
|
diehr("LoadIconMetric(IDI_APPLICATION)", hr);
|
|
|
|
hr = LoadIconMetric(NULL, IDI_QUESTION, LIM_SMALL, &helpIcon);
|
2018-10-13 13:17:17 -05:00
|
|
|
if (hr != S_OK)
|
2018-10-14 14:12:00 -05:00
|
|
|
diehr("LoadIconMetric(IDI_QUESTION)", hr);
|
|
|
|
rightList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
|
|
|
|
ILC_COLOR32, 0, 3);
|
|
|
|
if (rightList == NULL)
|
2018-10-12 21:45:37 -05:00
|
|
|
diele("ImageList_Create()");
|
2018-10-14 14:12:00 -05:00
|
|
|
if (ImageList_ReplaceIcon(rightList, -1, shieldIcon) == -1)
|
|
|
|
diele("ImageList_ReplaceIcon(IDI_SHIELD)");
|
|
|
|
if (ImageList_ReplaceIcon(rightList, -1, applicationIcon) == -1)
|
|
|
|
diele("ImageList_ReplaceIcon(IDI_APPLICATION)");
|
|
|
|
if (ImageList_ReplaceIcon(rightList, -1, helpIcon) == -1)
|
|
|
|
diele("ImageList_ReplaceIcon(IDI_QUESTION)");
|
2018-10-12 21:45:37 -05:00
|
|
|
|
2018-10-09 22:39:55 -05:00
|
|
|
ZeroMemory(&wc, sizeof (WNDCLASSW));
|
|
|
|
wc.lpszClassName = L"mainwin";
|
|
|
|
wc.lpfnWndProc = wndproc;
|
|
|
|
wc.hInstance = hInstance;
|
|
|
|
wc.hIcon = hDefaultIcon;
|
|
|
|
wc.hCursor = hDefaultCursor;
|
|
|
|
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
|
|
|
|
if (RegisterClassW(&wc) == 0)
|
|
|
|
diele("RegisterClassW()");
|
|
|
|
|
|
|
|
mainwin = CreateWindowExW(0,
|
|
|
|
L"mainwin", L"Main Window",
|
|
|
|
WS_OVERLAPPEDWINDOW,
|
|
|
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
|
|
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
|
|
|
NULL, NULL, hInstance, NULL);
|
|
|
|
if (mainwin == NULL)
|
|
|
|
diele("CreateWindowExW(L\"mainwin\")");
|
|
|
|
|
|
|
|
ShowWindow(mainwin, nCmdShow);
|
|
|
|
if (UpdateWindow(mainwin) == 0)
|
|
|
|
diele("UpdateWindow()");
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
int res;
|
|
|
|
|
|
|
|
res = GetMessageW(&msg, NULL, 0, 0);
|
|
|
|
if (res < 0)
|
|
|
|
diele("GetMessageW()");
|
|
|
|
if (res == 0)
|
|
|
|
break;
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessageW(&msg);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|