First Commit
This commit is contained in:
commit
ae0fab9400
424 files changed
+71006
No files matched your search
@@ -0,0 +1,136 @@
|
||||
// 25 june 2018
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
GtkWidget *mainwin;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *startProgress;
|
||||
GtkWidget *startTable;
|
||||
GtkWidget *progressbar;
|
||||
GtkWidget *scrolledWindow;
|
||||
GtkListStore *model;
|
||||
GtkWidget *treeview;
|
||||
GtkWidget *hbox2;
|
||||
|
||||
static gboolean pulseProgress(gpointer data)
|
||||
{
|
||||
gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progressbar));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void onStartProgressClicked(GtkButton *button, gpointer data)
|
||||
{
|
||||
gtk_widget_set_sensitive(startProgress, FALSE);
|
||||
g_timeout_add(100, pulseProgress, NULL);
|
||||
}
|
||||
|
||||
gboolean pbarStarted = FALSE;
|
||||
gint pbarValue;
|
||||
|
||||
static void pbarDataFunc(GtkTreeViewColumn *col, GtkCellRenderer *r, GtkTreeModel *m, GtkTreeIter *iter, gpointer data)
|
||||
{
|
||||
if (!pbarStarted) {
|
||||
g_object_set(r,
|
||||
"pulse", -1,
|
||||
"value", 0,
|
||||
NULL);
|
||||
return;
|
||||
}
|
||||
pbarValue++;
|
||||
if (pbarValue == G_MAXINT)
|
||||
pbarValue = 1;
|
||||
g_object_set(r, "pulse", pbarValue, NULL);
|
||||
}
|
||||
|
||||
static gboolean pulseTable(gpointer data)
|
||||
{
|
||||
GtkTreePath *path;
|
||||
GtkTreeIter iter;
|
||||
|
||||
path = gtk_tree_path_new_from_indices(0, -1);
|
||||
gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
|
||||
gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter);
|
||||
gtk_tree_path_free(path);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void onStartTableClicked(GtkButton *button, gpointer data)
|
||||
{
|
||||
pbarStarted = TRUE;
|
||||
pbarValue = 0;
|
||||
|
||||
gtk_widget_set_sensitive(startTable, FALSE);
|
||||
g_timeout_add(100, pulseTable, NULL);
|
||||
}
|
||||
|
||||
static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data)
|
||||
{
|
||||
gtk_main_quit();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreeViewColumn *col;
|
||||
GtkCellRenderer *r;
|
||||
|
||||
gtk_init(NULL, NULL);
|
||||
|
||||
mainwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
g_signal_connect(mainwin, "delete-event", G_CALLBACK(onClosing), NULL);
|
||||
|
||||
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
|
||||
gtk_container_add(GTK_CONTAINER(mainwin), vbox);
|
||||
|
||||
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
gtk_widget_set_halign(hbox, GTK_ALIGN_CENTER);
|
||||
gtk_container_add(GTK_CONTAINER(vbox), hbox);
|
||||
|
||||
startProgress = gtk_button_new_with_label("Start Progress Bar");
|
||||
g_signal_connect(startProgress, "clicked", G_CALLBACK(onStartProgressClicked), NULL);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), startProgress);
|
||||
|
||||
startTable = gtk_button_new_with_label("Start Table Cell Renderer");
|
||||
g_signal_connect(startTable, "clicked", G_CALLBACK(onStartTableClicked), NULL);
|
||||
gtk_container_add(GTK_CONTAINER(hbox), startTable);
|
||||
|
||||
progressbar = gtk_progress_bar_new();
|
||||
gtk_container_add(GTK_CONTAINER(vbox), progressbar);
|
||||
|
||||
scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledWindow), GTK_SHADOW_IN);
|
||||
gtk_widget_set_vexpand(scrolledWindow, TRUE);
|
||||
gtk_container_add(GTK_CONTAINER(vbox), scrolledWindow);
|
||||
|
||||
model = gtk_list_store_new(1, G_TYPE_INT);
|
||||
gtk_list_store_append(model, &iter);
|
||||
gtk_list_store_set(model, &iter,
|
||||
0, 0,
|
||||
-1);
|
||||
|
||||
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
|
||||
gtk_container_add(GTK_CONTAINER(scrolledWindow), treeview);
|
||||
|
||||
col = gtk_tree_view_column_new();
|
||||
gtk_tree_view_column_set_resizable(col, TRUE);
|
||||
gtk_tree_view_column_set_title(col, "Column");
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col);
|
||||
|
||||
r = gtk_cell_renderer_progress_new();
|
||||
gtk_tree_view_column_pack_start(col, r, TRUE);
|
||||
gtk_tree_view_column_set_cell_data_func(col, r, pbarDataFunc, NULL, NULL);
|
||||
|
||||
hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
gtk_widget_set_halign(hbox2, GTK_ALIGN_CENTER);
|
||||
gtk_container_add(GTK_CONTAINER(vbox), hbox2);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(hbox2), gtk_button_new_with_label("These buttons"));
|
||||
gtk_container_add(GTK_CONTAINER(hbox2), gtk_button_new_with_label("do nothing"));
|
||||
gtk_container_add(GTK_CONTAINER(hbox2), gtk_button_new_with_label("when clicked"));
|
||||
|
||||
gtk_widget_show_all(mainwin);
|
||||
gtk_main();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,907 @@
|
||||
// 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>
|
||||
#include <windowsx.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// cl winbuttonexplorertheme.cpp -MT -link user32.lib kernel32.lib gdi32.lib comctl32.lib uxtheme.lib msimg32.lib windows.res
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// TODO if we merge this into libui proper, this will need to be deduplicated
|
||||
static inline HRESULT lastErrorToHRESULT(DWORD lastError)
|
||||
{
|
||||
if (lastError == 0)
|
||||
return E_FAIL;
|
||||
return HRESULT_FROM_WIN32(lastError);
|
||||
}
|
||||
|
||||
HINSTANCE hInstance;
|
||||
HWND leftButtons[5];
|
||||
HWND rightButtons[3];
|
||||
|
||||
class commandModuleStyleParams {
|
||||
public:
|
||||
virtual int partID_CMOD_MODULEBACKGROUND(void) const = 0;
|
||||
virtual int partID_CMOD_TASKBUTTON(void) const = 0;
|
||||
virtual int partID_CMOD_SPLITBUTTONLEFT(void) const = 0;
|
||||
virtual int partID_CMOD_SPLITBUTTONRIGHT(void) const = 0;
|
||||
virtual int partID_CMOD_MENUGLYPH(void) const = 0;
|
||||
virtual int partID_CMOD_OVERFLOWGLYPH(void) const = 0;
|
||||
|
||||
virtual int stateID_CMODS_NORMAL(void) const = 0;
|
||||
virtual int stateID_CMODS_HOT(void) const = 0;
|
||||
virtual int stateID_CMODS_PRESSED(void) const = 0;
|
||||
virtual int stateID_CMODS_KEYFOCUSED(void) const = 0;
|
||||
virtual int stateID_CMODS_NEARHOT(void) const = 0;
|
||||
|
||||
virtual HRESULT backgroundGradientColors(HTHEME theme, COLORREF *colors) const = 0;
|
||||
virtual HRESULT buttonTextColor(HTHEME theme, UINT uItemState, COLORREF *color) const = 0;
|
||||
virtual BOOL buttonTextShadowed(UINT uItemState) const = 0;
|
||||
|
||||
virtual int folderBarMarginsLeftDIP(void) const = 0;
|
||||
virtual int folderBarMarginsTopDIP(void) const = 0;
|
||||
virtual int folderBarMarginsRightDIP(void) const = 0;
|
||||
virtual int folderBarMarginsBottomDIP(void) const = 0;
|
||||
|
||||
virtual int buttonMarginsXDIP(void) const = 0;
|
||||
virtual int buttonMarginsYDIP(void) const = 0;
|
||||
virtual int buttonTextArrowSeparationXDIP(void) const = 0;
|
||||
};
|
||||
|
||||
class commandModuleStyleParamsVista : public commandModuleStyleParams {
|
||||
public:
|
||||
virtual int partID_CMOD_MODULEBACKGROUND(void) const { return 1; }
|
||||
virtual int partID_CMOD_TASKBUTTON(void) const { return 2; }
|
||||
virtual int partID_CMOD_SPLITBUTTONLEFT(void) const { return 3; }
|
||||
virtual int partID_CMOD_SPLITBUTTONRIGHT(void) const { return 4; }
|
||||
virtual int partID_CMOD_MENUGLYPH(void) const { return 5; }
|
||||
virtual int partID_CMOD_OVERFLOWGLYPH(void) const { return 6; }
|
||||
|
||||
virtual int stateID_CMODS_NORMAL(void) const { return 1; }
|
||||
virtual int stateID_CMODS_HOT(void) const { return 2; }
|
||||
virtual int stateID_CMODS_PRESSED(void) const { return 3; }
|
||||
virtual int stateID_CMODS_KEYFOCUSED(void) const { return 4; }
|
||||
virtual int stateID_CMODS_NEARHOT(void) const { return 5; }
|
||||
|
||||
virtual HRESULT backgroundGradientColors(HTHEME theme, COLORREF *colors) const
|
||||
{
|
||||
if (colors == NULL)
|
||||
return E_POINTER;
|
||||
#define argb(a, r, g, b) ((((COLORREF) ((BYTE) (a))) << 24) | RGB(r, g, b))
|
||||
colors[0] = argb(255, 4, 80, 130);
|
||||
colors[1] = argb(255, 17, 101, 132);
|
||||
colors[2] = argb(255, 29, 121, 134);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual HRESULT buttonTextColor(HTHEME theme, UINT uItemState, COLORREF *color) const
|
||||
{
|
||||
if (color == NULL)
|
||||
return E_POINTER;
|
||||
*color = GetSysColor(COLOR_WINDOW);
|
||||
if ((uItemState & CDIS_DISABLED) != 0)
|
||||
*color = argb(255, 161, 204, 210);
|
||||
#undef argb
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual BOOL buttonTextShadowed(UINT uItemState) const
|
||||
{
|
||||
return (uItemState & CDIS_DISABLED) == 0;
|
||||
}
|
||||
|
||||
virtual int folderBarMarginsLeftDIP(void) const { return 3; }
|
||||
virtual int folderBarMarginsTopDIP(void) const { return 2; }
|
||||
virtual int folderBarMarginsRightDIP(void) const { return 3; }
|
||||
virtual int folderBarMarginsBottomDIP(void) const { return 3; }
|
||||
|
||||
virtual int buttonMarginsXDIP(void) const { return 6; }
|
||||
virtual int buttonMarginsYDIP(void) const { return 5; }
|
||||
virtual int buttonTextArrowSeparationXDIP(void) const { return 3; }
|
||||
};
|
||||
|
||||
class commandModuleStyleParams7 : public commandModuleStyleParams {
|
||||
virtual int partID_CMOD_MODULEBACKGROUND(void) const { return 1; }
|
||||
virtual int partID_CMOD_TASKBUTTON(void) const { return 3; }
|
||||
virtual int partID_CMOD_SPLITBUTTONLEFT(void) const { return 4; }
|
||||
virtual int partID_CMOD_SPLITBUTTONRIGHT(void) const { return 5; }
|
||||
virtual int partID_CMOD_MENUGLYPH(void) const { return 6; }
|
||||
virtual int partID_CMOD_OVERFLOWGLYPH(void) const { return 7; }
|
||||
|
||||
virtual int stateID_CMODS_NORMAL(void) const { return 1; }
|
||||
virtual int stateID_CMODS_HOT(void) const { return 2; }
|
||||
virtual int stateID_CMODS_PRESSED(void) const { return 3; }
|
||||
virtual int stateID_CMODS_KEYFOCUSED(void) const { return 4; }
|
||||
/*TODO verify this*/virtual int stateID_CMODS_NEARHOT(void) const { return 5; }
|
||||
|
||||
virtual HRESULT backgroundGradientColors(HTHEME theme, COLORREF *colors) const
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (colors == NULL)
|
||||
return E_POINTER;
|
||||
hr = GetThemeColor(theme,
|
||||
2, 0,
|
||||
TMT_GRADIENTCOLOR1, colors + 0);
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
hr = GetThemeColor(theme,
|
||||
2, 0,
|
||||
TMT_GRADIENTCOLOR2, colors + 1);
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
return GetThemeColor(theme,
|
||||
2, 0,
|
||||
TMT_GRADIENTCOLOR3, colors + 2);
|
||||
}
|
||||
|
||||
virtual HRESULT buttonTextColor(HTHEME theme, UINT uItemState, COLORREF *color) const
|
||||
{
|
||||
int state;
|
||||
|
||||
if (color == NULL)
|
||||
return E_POINTER;
|
||||
state = 1;
|
||||
if ((uItemState & CDIS_DISABLED) != 0)
|
||||
state = 6;
|
||||
// TODO check if 3 is the correct part ID for all button types
|
||||
return GetThemeColor(theme,
|
||||
3, state,
|
||||
TMT_TEXTCOLOR, color);
|
||||
}
|
||||
|
||||
virtual BOOL buttonTextShadowed(UINT uItemState) const
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
virtual int folderBarMarginsLeftDIP(void) const { return 3; }
|
||||
virtual int folderBarMarginsTopDIP(void) const { return 2; }
|
||||
virtual int folderBarMarginsRightDIP(void) const { return 9; }
|
||||
virtual int folderBarMarginsBottomDIP(void) const { return 3; }
|
||||
|
||||
virtual int buttonMarginsXDIP(void) const { return 13; }
|
||||
virtual int buttonMarginsYDIP(void) const { return 5; }
|
||||
virtual int buttonTextArrowSeparationXDIP(void) const { return 1; }
|
||||
};
|
||||
|
||||
// all coordinates are in client space
|
||||
struct buttonMetrics {
|
||||
SIZE fittingSize;
|
||||
int baseX;
|
||||
int baseY;
|
||||
int dpiX;
|
||||
int dpiY;
|
||||
BOOL hasText;
|
||||
SIZE textSize;
|
||||
BOOL hasArrow;
|
||||
SIZE arrowSize;
|
||||
};
|
||||
|
||||
struct buttonRects {
|
||||
RECT clientRect;
|
||||
RECT textRect;
|
||||
RECT arrowRect;
|
||||
};
|
||||
|
||||
class commandModuleStyle {
|
||||
public:
|
||||
virtual HRESULT drawFolderBar(commandModuleStyleParams *p, HDC dc, RECT *rcWindow, RECT *rcPaint) const = 0;
|
||||
virtual HRESULT buttonMetrics(commandModuleStyleParams *p, HWND button, HDC dc, struct buttonMetrics *m) const = 0;
|
||||
virtual HRESULT buttonRects(commandModuleStyleParams *p, HWND button, struct buttonMetrics *m, struct buttonRects *r) const = 0;
|
||||
virtual HRESULT drawButton(commandModuleStyleParams *p, HWND button, HDC dc, UINT uItemState, RECT *rcPaint) const = 0;
|
||||
};
|
||||
|
||||
class commandModuleStyleThemed : public commandModuleStyle {
|
||||
HTHEME theme;
|
||||
HTHEME textstyleTheme;
|
||||
public:
|
||||
commandModuleStyleThemed(HTHEME theme, HTHEME textstyleTheme)
|
||||
{
|
||||
this->theme = theme;
|
||||
this->textstyleTheme = textstyleTheme;
|
||||
}
|
||||
|
||||
virtual HRESULT drawFolderBar(commandModuleStyleParams *p, HDC dc, RECT *rcWindow, RECT *rcPaint) const
|
||||
{
|
||||
COLORREF colors[3];
|
||||
TRIVERTEX vertices[4];
|
||||
static GRADIENT_RECT gr[2] = {
|
||||
{ 0, 1 },
|
||||
{ 2, 3 },
|
||||
};
|
||||
HRESULT hr;
|
||||
|
||||
hr = p->backgroundGradientColors(this->theme, colors);
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
||||
vertices[0].x = rcWindow->left;
|
||||
vertices[0].y = rcWindow->top;
|
||||
vertices[0].Red = ((COLOR16) GetRValue(colors[0])) << 8;
|
||||
vertices[0].Green = ((COLOR16) GetGValue(colors[0])) << 8;
|
||||
vertices[0].Blue = ((COLOR16) GetBValue(colors[0])) << 8;
|
||||
vertices[0].Alpha = ((COLOR16) LOBYTE(colors[0] >> 24)) << 8;
|
||||
|
||||
vertices[1].x = (rcWindow->right - rcWindow->left) / 2;
|
||||
vertices[1].y = rcWindow->bottom;
|
||||
vertices[1].Red = ((COLOR16) GetRValue(colors[1])) << 8;
|
||||
vertices[1].Green = ((COLOR16) GetGValue(colors[1])) << 8;
|
||||
vertices[1].Blue = ((COLOR16) GetBValue(colors[1])) << 8;
|
||||
vertices[1].Alpha = ((COLOR16) LOBYTE(colors[1] >> 24)) << 8;
|
||||
|
||||
vertices[2] = vertices[1];
|
||||
vertices[2].y = rcWindow->top;
|
||||
|
||||
vertices[3].x = rcWindow->right;
|
||||
vertices[3].y = rcWindow->bottom;
|
||||
vertices[3].Red = ((COLOR16) GetRValue(colors[2])) << 8;
|
||||
vertices[3].Green = ((COLOR16) GetGValue(colors[2])) << 8;
|
||||
vertices[3].Blue = ((COLOR16) GetBValue(colors[2])) << 8;
|
||||
vertices[3].Alpha = ((COLOR16) LOBYTE(colors[2] >> 24)) << 8;
|
||||
|
||||
if (GradientFill(dc, vertices, 4, (PVOID) gr, 2, GRADIENT_FILL_RECT_H) == FALSE)
|
||||
return lastErrorToHRESULT(GetLastError());
|
||||
return DrawThemeBackground(this->theme, dc,
|
||||
p->partID_CMOD_MODULEBACKGROUND(), 0,
|
||||
rcWindow, rcPaint);
|
||||
}
|
||||
|
||||
#define hasNonsplitArrow(button) ((button) == leftButtons[0] || (button) == leftButtons[1] || (button) == leftButtons[2])
|
||||
|
||||
#define dlgUnitsToX(dlg, baseX) MulDiv((dlg), (baseX), 4)
|
||||
#define dlgUnitsToY(dlg, baseY) MulDiv((dlg), (baseY), 8)
|
||||
// TODO verify the parameter order
|
||||
#define dipsToX(dip, dpiX) MulDiv((dip), (dpiX), 96)
|
||||
#define dipsToY(dip, dpiY) MulDiv((dip), (dpiY), 96)
|
||||
|
||||
// TODO for win7: the sizes are correct (according to UI Automation) but they don't visually match?
|
||||
virtual HRESULT buttonMetrics(commandModuleStyleParams *p, HWND button, HDC dc, struct buttonMetrics *m) const
|
||||
{
|
||||
BOOL releaseDC;
|
||||
TEXTMETRICW tm;
|
||||
RECT r;
|
||||
int minStdButtonHeight;
|
||||
HRESULT hr;
|
||||
|
||||
if (m == NULL)
|
||||
return E_POINTER;
|
||||
|
||||
releaseDC = FALSE;
|
||||
if (dc == NULL) {
|
||||
dc = GetDC(button);
|
||||
if (dc == NULL)
|
||||
return lastErrorToHRESULT(GetLastError());
|
||||
releaseDC = TRUE;
|
||||
}
|
||||
|
||||
ZeroMemory(&tm, sizeof (TEXTMETRICW));
|
||||
hr = GetThemeTextMetrics(this->textstyleTheme, dc,
|
||||
TEXT_BODYTEXT, 0,
|
||||
&tm);
|
||||
if (hr != S_OK)
|
||||
goto fail;
|
||||
hr = GetThemeTextExtent(this->textstyleTheme, dc,
|
||||
TEXT_BODYTEXT, 0,
|
||||
L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, 0,
|
||||
NULL, &r);
|
||||
if (hr != S_OK)
|
||||
goto fail;
|
||||
m->baseX = (int) (((r.right - r.left) / 26 + 1) / 2);
|
||||
m->baseY = (int) tm.tmHeight;
|
||||
m->dpiX = GetDeviceCaps(dc, LOGPIXELSX);
|
||||
m->dpiY = GetDeviceCaps(dc, LOGPIXELSY);
|
||||
|
||||
m->fittingSize.cx = 0;
|
||||
m->fittingSize.cy = 0;
|
||||
|
||||
m->hasText = TRUE;
|
||||
if (m->hasText) {
|
||||
LRESULT n;
|
||||
WCHAR *buf;
|
||||
LOGFONTW lf;
|
||||
|
||||
n = SendMessageW(button, WM_GETTEXTLENGTH, 0, 0);
|
||||
buf = new WCHAR[n + 1];
|
||||
GetWindowTextW(button, buf, n + 1);
|
||||
hr = GetThemeTextExtent(this->textstyleTheme, dc,
|
||||
TEXT_BODYTEXT, 0,
|
||||
buf, n, DT_CENTER,
|
||||
NULL, &r);
|
||||
delete[] buf;
|
||||
if (hr != S_OK)
|
||||
goto fail;
|
||||
m->textSize.cx = r.right - r.left;
|
||||
m->textSize.cy = r.bottom - r.top;
|
||||
m->fittingSize.cx += m->textSize.cx;
|
||||
m->fittingSize.cy += m->textSize.cy;
|
||||
|
||||
// dui70.dll adds this to the width when "overhang" is enabled, and it seems to be enabled for our cases, but I can't tell what conditions it's enabled for...
|
||||
// and yes, it seems to be using the raw lfHeight value here :/
|
||||
// TODO find the right TMT constant
|
||||
hr = GetThemeFont(this->textstyleTheme, dc,
|
||||
4, 0,
|
||||
TMT_FONT, &lf);
|
||||
if (hr != S_OK)
|
||||
goto fail;
|
||||
m->fittingSize.cx += 2 * (abs(lf.lfHeight) / 6);
|
||||
}
|
||||
|
||||
m->hasArrow = hasNonsplitArrow(button);
|
||||
if (m->hasArrow) {
|
||||
// TS_MIN returns 1x1 and TS_DRAW returns 0x0, so...
|
||||
hr = GetThemePartSize(theme, dc,
|
||||
p->partID_CMOD_MENUGLYPH(), 0,
|
||||
NULL, TS_TRUE, &(m->arrowSize));
|
||||
if (hr != S_OK)
|
||||
goto fail;
|
||||
m->fittingSize.cx += m->arrowSize.cx;
|
||||
// TODO I don't think dui70.dll takes this into consideration...
|
||||
if (m->fittingSize.cy < m->arrowSize.cy)
|
||||
m->fittingSize.cy = m->arrowSize.cy;
|
||||
m->fittingSize.cx += dipsToX(p->buttonTextArrowSeparationXDIP(), m->dpiX);
|
||||
}
|
||||
|
||||
m->fittingSize.cx += dipsToX(p->buttonMarginsXDIP(), m->dpiX) * 2;
|
||||
m->fittingSize.cy += dipsToY(p->buttonMarginsYDIP(), m->dpiY) * 2;
|
||||
|
||||
// and dui70.dll seems to do a variant of this but for text buttons only...
|
||||
minStdButtonHeight = dlgUnitsToY(14, m->baseY);
|
||||
if (m->fittingSize.cy < minStdButtonHeight)
|
||||
m->fittingSize.cy = minStdButtonHeight;
|
||||
|
||||
hr = S_OK;
|
||||
fail:
|
||||
if (releaseDC)
|
||||
// TODO when migrating this to libui, this will need to be renamed to indicate we are intentionally ignoring errors
|
||||
ReleaseDC(button, dc);
|
||||
return hr;
|
||||
};
|
||||
|
||||
// TODO check errors
|
||||
virtual HRESULT buttonRects(commandModuleStyleParams *p, HWND button, struct buttonMetrics *m, struct buttonRects *r) const
|
||||
{
|
||||
if (r == NULL)
|
||||
return E_POINTER;
|
||||
|
||||
GetClientRect(button, &(r->clientRect));
|
||||
|
||||
if (m->hasText)
|
||||
r->textRect = r->clientRect;
|
||||
|
||||
if (m->hasArrow) {
|
||||
r->arrowRect = r->clientRect;
|
||||
r->arrowRect.left = r->arrowRect.right;
|
||||
r->arrowRect.left -= dipsToX(p->buttonMarginsXDIP(), m->dpiX);
|
||||
r->arrowRect.right = r->arrowRect.left;
|
||||
r->arrowRect.left -= m->arrowSize.cx;
|
||||
r->arrowRect.top += ((r->arrowRect.bottom - r->arrowRect.top) - m->arrowSize.cy) / 2;
|
||||
r->arrowRect.bottom = r->arrowRect.top + m->arrowSize.cy;
|
||||
|
||||
if (m->hasText) {
|
||||
r->textRect.right = r->arrowRect.left - dipsToX(p->buttonTextArrowSeparationXDIP(), m->dpiX);
|
||||
r->textRect.right += dipsToX(p->buttonMarginsXDIP(), m->dpiX);
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// TODO check errors fully
|
||||
virtual HRESULT drawButton(commandModuleStyleParams *p, HWND button, HDC dc, UINT uItemState, RECT *rcPaint) const
|
||||
{
|
||||
struct buttonMetrics m;
|
||||
struct buttonRects r;
|
||||
int part, state;
|
||||
HRESULT hr;
|
||||
|
||||
hr = this->buttonMetrics(p, button, dc, &m);
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
hr = this->buttonRects(p, button, &m, &r);
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
||||
part = p->partID_CMOD_TASKBUTTON();
|
||||
state = p->stateID_CMODS_NORMAL();
|
||||
if ((uItemState & CDIS_FOCUS) != 0)
|
||||
state = p->stateID_CMODS_KEYFOCUSED();
|
||||
if ((uItemState & CDIS_HOT) != 0)
|
||||
state = p->stateID_CMODS_HOT();
|
||||
if ((uItemState & CDIS_SELECTED) != 0)
|
||||
state = p->stateID_CMODS_PRESSED();
|
||||
hr = DrawThemeParentBackground(button, dc, rcPaint);
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
hr = DrawThemeBackground(this->theme, dc,
|
||||
part, state,
|
||||
&(r.clientRect), rcPaint);
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
|
||||
if (m.hasText) {
|
||||
int textState;
|
||||
COLORREF textColor;
|
||||
LRESULT n;
|
||||
WCHAR *buf;
|
||||
DTTOPTS dttopts;
|
||||
|
||||
hr = p->buttonTextColor(this->theme, uItemState, &textColor);
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
n = SendMessageW(button, WM_GETTEXTLENGTH, 0, 0);
|
||||
buf = new WCHAR[n + 1];
|
||||
GetWindowTextW(button, buf, n + 1);
|
||||
ZeroMemory(&dttopts, sizeof (DTTOPTS));
|
||||
dttopts.dwSize = sizeof (DTTOPTS);
|
||||
dttopts.dwFlags = DTT_TEXTCOLOR;
|
||||
dttopts.crText = textColor;
|
||||
hr = DrawThemeTextEx(this->textstyleTheme, dc,
|
||||
TEXT_BODYTEXT, 0,
|
||||
buf, n, DT_CENTER | DT_VCENTER | DT_SINGLELINE,
|
||||
&(r.textRect), &dttopts);
|
||||
delete[] buf;
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (m.hasArrow) {
|
||||
// TODO verify the state ID on all platforms
|
||||
hr = DrawThemeBackground(this->theme, dc,
|
||||
p->partID_CMOD_MENUGLYPH(), 0,
|
||||
&(r.arrowRect), rcPaint);
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
// TODO check errors
|
||||
void drawExplorerChevron(HTHEME theme, HDC dc, HWND rebar, WPARAM band, RECT *rcPaint)
|
||||
{
|
||||
REBARBANDINFOW rbi;
|
||||
RECT r;
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
HICON shieldIcon;
|
||||
HICON applicationIcon;
|
||||
HICON helpIcon;
|
||||
HIMAGELIST rightList;
|
||||
|
||||
HTHEME theme = NULL;
|
||||
HTHEME textstyleTheme = NULL;
|
||||
const char *which = "7";
|
||||
commandModuleStyle *cms = NULL;
|
||||
commandModuleStyleParams *cmsp = NULL;
|
||||
HIMAGELIST dropdownArrowList = NULL;
|
||||
|
||||
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 },
|
||||
};
|
||||
|
||||
// TODO check errors
|
||||
LRESULT drawExplorerButton(NMCUSTOMDRAW *nm)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (nm->dwDrawStage != CDDS_PREPAINT)
|
||||
return CDRF_DODEFAULT;
|
||||
hr = cms->drawButton(cmsp, nm->hdr.hwndFrom,
|
||||
nm->hdc, nm->uItemState, &(nm->rc));
|
||||
if (hr != S_OK)
|
||||
return CDRF_DODEFAULT;
|
||||
return CDRF_SKIPDEFAULT;
|
||||
}
|
||||
|
||||
void onWM_CREATE(HWND hwnd)
|
||||
{
|
||||
int buttonx, buttony;
|
||||
int i;
|
||||
|
||||
buttonx = 5;
|
||||
buttony = 5;
|
||||
for (i = 0; i < 5; i++) {
|
||||
// TODO split buttons don't support arrow navigation?
|
||||
leftButtons[i] = CreateWindowExW(0,
|
||||
L"BUTTON", leftbarButtons[i].text,
|
||||
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
|
||||
buttonx, buttony,
|
||||
150, 30,
|
||||
hwnd, (HMENU) (100 + i), hInstance, NULL);
|
||||
if (leftButtons[i] == NULL)
|
||||
diele("CreateWindowExW(L\"BUTTON\")");
|
||||
buttonx += 150;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO check errors
|
||||
void updateTheme(HWND hwnd)
|
||||
{
|
||||
if (cmsp != NULL) {
|
||||
delete cmsp;
|
||||
cmsp = NULL;
|
||||
}
|
||||
if (cms != NULL) {
|
||||
delete cms;
|
||||
cms = NULL;
|
||||
}
|
||||
if (textstyleTheme != NULL) {
|
||||
CloseThemeData(textstyleTheme);
|
||||
textstyleTheme = NULL;
|
||||
}
|
||||
if (theme != NULL) {
|
||||
CloseThemeData(theme);
|
||||
theme = NULL;
|
||||
}
|
||||
|
||||
theme = OpenThemeData(hwnd, L"CommandModule");
|
||||
textstyleTheme = OpenThemeData(hwnd, L"TEXTSTYLE");
|
||||
cms = new commandModuleStyleThemed(theme, textstyleTheme);
|
||||
if (strcmp(which, "vista") == 0)
|
||||
cmsp = new commandModuleStyleParamsVista;
|
||||
else
|
||||
cmsp = new commandModuleStyleParams7;
|
||||
}
|
||||
|
||||
void repositionButtons(HWND hwnd)
|
||||
{
|
||||
HDWP dwp;
|
||||
int buttonx, buttony;
|
||||
HDC dc;
|
||||
int dpiX;
|
||||
int dpiY;
|
||||
struct buttonMetrics m;
|
||||
int i;
|
||||
|
||||
dc = GetDC(hwnd);
|
||||
if (dc == NULL)
|
||||
diele("GetDC()");
|
||||
dpiX = GetDeviceCaps(dc, LOGPIXELSX);
|
||||
dpiY = GetDeviceCaps(dc, LOGPIXELSY);
|
||||
// TODO check error
|
||||
ReleaseDC(hwnd, dc);
|
||||
|
||||
dwp = BeginDeferWindowPos(5);
|
||||
if (dwp == NULL)
|
||||
diele("BeginDeferWindowPos()");
|
||||
buttonx = dipsToX(cmsp->folderBarMarginsLeftDIP(), dpiX);
|
||||
buttony = dipsToY(cmsp->folderBarMarginsTopDIP(), dpiY);
|
||||
for (i = 0; i < 5; i++) {
|
||||
cms->buttonMetrics(cmsp, leftButtons[i], NULL, &m);
|
||||
dwp = DeferWindowPos(dwp, leftButtons[i], NULL,
|
||||
buttonx, buttony, m.fittingSize.cx, m.fittingSize.cy,
|
||||
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
if (dwp == NULL)
|
||||
diele("DeferWindowPos()");
|
||||
buttonx += m.fittingSize.cx;
|
||||
}
|
||||
if (EndDeferWindowPos(dwp) == 0)
|
||||
diele("EndDeferWindowPos()");
|
||||
}
|
||||
|
||||
// TODO check errors
|
||||
void folderBarRect(HWND hwnd, HDC dc, RECT *r)
|
||||
{
|
||||
int dpiX;
|
||||
int dpiY;
|
||||
RECT child;
|
||||
int i;
|
||||
|
||||
dpiX = GetDeviceCaps(dc, LOGPIXELSX);
|
||||
dpiY = GetDeviceCaps(dc, LOGPIXELSY);
|
||||
|
||||
GetClientRect(hwnd, r);
|
||||
r->right -= r->left;
|
||||
r->left = 0;
|
||||
r->top = 0;
|
||||
r->bottom = 0;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
GetWindowRect(leftButtons[i], &child);
|
||||
if (r->bottom < (child.bottom - child.top))
|
||||
r->bottom = (child.bottom - child.top);
|
||||
}
|
||||
|
||||
r->bottom += dipsToY(cmsp->folderBarMarginsTopDIP(), dpiY);
|
||||
r->bottom += dipsToY(cmsp->folderBarMarginsBottomDIP(), dpiY);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// 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;
|
||||
BOOL invalidate = FALSE;
|
||||
WPARAM check;
|
||||
|
||||
switch (wParam) {
|
||||
case MAKEWPARAM(300, CBN_SELCHANGE):
|
||||
n = SendMessageW(rebarCombo, CB_GETCURSEL, 0, 0);
|
||||
selRebar = rebarThemes[n];
|
||||
changeRebar = TRUE;
|
||||
break;
|
||||
case MAKEWPARAM(301, CBN_SELCHANGE):
|
||||
n = SendMessageW(toolbarCombo, CB_GETCURSEL, 0, 0);
|
||||
selToolbar = toolbarThemes[n];
|
||||
changeToolbar = TRUE;
|
||||
break;
|
||||
case MAKEWPARAM(200, BN_CLICKED):
|
||||
drawmode = 0;
|
||||
n = SendMessageW(rebarCombo, WM_GETTEXTLENGTH, 0, 0);
|
||||
bufRebar = new WCHAR[n + 1];
|
||||
GetWindowTextW(rebarCombo, bufRebar, n + 1);
|
||||
n = SendMessageW(toolbarCombo, WM_GETTEXTLENGTH, 0, 0);
|
||||
bufToolbar = new WCHAR[n + 1];
|
||||
GetWindowTextW(toolbarCombo, bufToolbar, n + 1);
|
||||
selRebar = bufRebar;
|
||||
selToolbar = bufToolbar;
|
||||
changeRebar = TRUE;
|
||||
changeToolbar = TRUE;
|
||||
break;
|
||||
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)
|
||||
SendMessageW(leftbar, TB_SETSTYLE, 0, toolbarStyles | TBSTYLE_LIST | TBSTYLE_TRANSPARENT);
|
||||
else
|
||||
SendMessageW(leftbar, TB_SETSTYLE, 0, toolbarStyles | TBSTYLE_LIST);
|
||||
ShowWindow(leftbar, SW_SHOW);
|
||||
break;
|
||||
case MAKEWPARAM(202, BN_CLICKED):
|
||||
SetFocus(leftbar);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
invalidate = TRUE;
|
||||
}
|
||||
if (changeToolbar) {
|
||||
if (selToolbar != NULL && wcscmp(selToolbar, L"NULL") == 0)
|
||||
selToolbar = NULL;
|
||||
if (selToolbar != NULL && *selToolbar != L'\0') {
|
||||
SendMessageW(leftbar, TB_SETWINDOWTHEME, 0, (LPARAM) selToolbar);
|
||||
SendMessageW(rightbar, TB_SETWINDOWTHEME, 0, (LPARAM) selToolbar);
|
||||
} else {
|
||||
SetWindowTheme(leftbar, selToolbar, selToolbar);
|
||||
SetWindowTheme(rightbar, selToolbar, selToolbar);
|
||||
}
|
||||
invalidate = TRUE;
|
||||
}
|
||||
if (invalidate)
|
||||
InvalidateRect(hwnd, NULL, TRUE);
|
||||
if (bufRebar != NULL)
|
||||
delete[] bufRebar;
|
||||
if (bufToolbar != NULL)
|
||||
delete[] bufToolbar;
|
||||
}
|
||||
#endif
|
||||
|
||||
LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
HDC dc;
|
||||
PAINTSTRUCT ps;
|
||||
NMHDR *nm = (NMHDR *) lParam;
|
||||
int i;
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_CREATE:
|
||||
onWM_CREATE(hwnd);
|
||||
updateTheme(hwnd);
|
||||
repositionButtons(hwnd);
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
case WM_SIZE:
|
||||
repositionButtons(hwnd);
|
||||
// TODO check errors
|
||||
InvalidateRect(hwnd, NULL, TRUE);
|
||||
break;
|
||||
case WM_THEMECHANGED:
|
||||
updateTheme(hwnd);
|
||||
repositionButtons(hwnd);
|
||||
break;
|
||||
case WM_PAINT:
|
||||
// TODO check errors
|
||||
dc = BeginPaint(hwnd, &ps);
|
||||
{RECT w;
|
||||
folderBarRect(hwnd, dc, &w);
|
||||
cms->drawFolderBar(cmsp, dc, &w, &(ps.rcPaint));}
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
case WM_PRINTCLIENT:
|
||||
{RECT w, paint;
|
||||
folderBarRect(hwnd, (HDC) wParam, &w);
|
||||
GetClientRect(hwnd,&paint);
|
||||
cms->drawFolderBar(cmsp, (HDC) wParam, &w, &w);}
|
||||
return 0;
|
||||
#if 0
|
||||
case WM_COMMAND:
|
||||
handleEvents(hwnd, wParam);
|
||||
break;
|
||||
#endif
|
||||
case WM_NOTIFY:
|
||||
switch (nm->code) {
|
||||
case NM_CUSTOMDRAW:
|
||||
for (i = 0; i < 5; i++)
|
||||
if (nm->hwndFrom == leftButtons[i])
|
||||
return drawExplorerButton((NMCUSTOMDRAW *) nm);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
STARTUPINFOW si;
|
||||
int nCmdShow;
|
||||
INITCOMMONCONTROLSEX icc;
|
||||
HICON hDefaultIcon;
|
||||
HCURSOR hDefaultCursor;
|
||||
WNDCLASSW wc;
|
||||
HWND mainwin;
|
||||
MSG msg;
|
||||
HRESULT hr;
|
||||
|
||||
if (argc > 1)
|
||||
which = argv[1];
|
||||
|
||||
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)");
|
||||
|
||||
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);
|
||||
if (hr != S_OK)
|
||||
diehr("LoadIconMetric(IDI_QUESTION)", hr);
|
||||
rightList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
|
||||
ILC_COLOR32, 0, 3);
|
||||
if (rightList == NULL)
|
||||
diele("ImageList_Create()");
|
||||
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)");
|
||||
|
||||
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;
|
||||
if (IsDialogMessageW(mainwin, &msg) == 0) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,676 @@
|
||||
// 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>
|
||||
#include <windowsx.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// cl winrebarexplorertheme.cpp -MT -link user32.lib kernel32.lib gdi32.lib comctl32.lib uxtheme.lib msimg32.lib windows.res
|
||||
|
||||
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;
|
||||
HWND rebarCombo;
|
||||
HWND toolbarCombo;
|
||||
HWND toolbarTransparentCheckbox;
|
||||
|
||||
HICON shieldIcon;
|
||||
HICON applicationIcon;
|
||||
HICON helpIcon;
|
||||
HIMAGELIST rightList;
|
||||
|
||||
#define toolbarStyles (WS_CHILD | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | TBSTYLE_FLAT)
|
||||
|
||||
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 },
|
||||
};
|
||||
|
||||
// TODO check errors
|
||||
// TODO extract colors from the theme
|
||||
void drawExplorerBackground(HTHEME theme, HDC dc, RECT *rcWindow, RECT *rcPaint)
|
||||
{
|
||||
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 },
|
||||
};
|
||||
|
||||
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;
|
||||
RECT r;
|
||||
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)
|
||||
{
|
||||
HTHEME theme;
|
||||
RECT r;
|
||||
|
||||
if (nm->dwDrawStage != CDDS_PREPAINT)
|
||||
return CDRF_DODEFAULT;
|
||||
theme = OpenThemeData(nm->hdr.hwndFrom, L"CommandModule");
|
||||
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));
|
||||
CloseThemeData(theme);
|
||||
return CDRF_SKIPDEFAULT;
|
||||
}
|
||||
|
||||
// TODO check errors
|
||||
LRESULT customDrawExplorerToolbar(NMTBCUSTOMDRAW *nm)
|
||||
{
|
||||
HWND toolbar, rebar;
|
||||
WPARAM itemIndex;
|
||||
TBBUTTON tbb;
|
||||
HTHEME theme;
|
||||
RECT r;
|
||||
int part, state;
|
||||
|
||||
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:
|
||||
itemIndex = (WPARAM) SendMessageW(toolbar, TB_COMMANDTOINDEX, nm->nmcd.dwItemSpec, 0);
|
||||
ZeroMemory(&tbb, sizeof (TBBUTTON));
|
||||
SendMessageW(toolbar, TB_GETBUTTON, itemIndex, (LPARAM) (&tbb));
|
||||
theme = OpenThemeData(toolbar, L"CommandModule");
|
||||
part = 3;
|
||||
if ((tbb.fsStyle & BTNS_DROPDOWN) != 0)
|
||||
part = 4;
|
||||
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;
|
||||
SendMessageW(toolbar, TB_GETITEMRECT, itemIndex, (LPARAM) (&r));
|
||||
DrawThemeBackground(theme, nm->nmcd.hdc,
|
||||
3, state,
|
||||
&r, &(nm->nmcd.rc));
|
||||
CloseThemeData(theme);
|
||||
return TBCDRF_NOBACKGROUND;
|
||||
}
|
||||
return CDRF_DODEFAULT;
|
||||
}
|
||||
|
||||
static struct {
|
||||
const WCHAR *text;
|
||||
LRESULT (*handleRebar)(NMCUSTOMDRAW *nm);
|
||||
LRESULT (*handleToolbar)(NMTBCUSTOMDRAW *nm);
|
||||
} drawmodes[] = {
|
||||
{ L"SetWindowTheme()", NULL, NULL },
|
||||
{ L"Custom Draw Explorer", customDrawExplorerRebar, customDrawExplorerToolbar },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
int drawmode = 0;
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
// TODO toolbarThemes
|
||||
|
||||
void onWM_CREATE(HWND hwnd)
|
||||
{
|
||||
TBBUTTON tbb[5];
|
||||
RECT btnrect;
|
||||
DWORD tbbtnsize;
|
||||
LONG tbsizex, tbsizey;
|
||||
REBARBANDINFOW rbi;
|
||||
HWND button;
|
||||
LONG buttonx, buttony;
|
||||
LONG combox, comboy;
|
||||
int i;
|
||||
|
||||
rebar = CreateWindowExW(0,
|
||||
REBARCLASSNAMEW, NULL,
|
||||
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NODIVIDER | CCS_TOP | RBS_FIXEDORDER,
|
||||
0, 0, 0, 0,
|
||||
hwnd, (HMENU) 100, hInstance, NULL);
|
||||
if (rebar == NULL)
|
||||
diele("CreateWindowExW(REBARCLASSNAMEW)");
|
||||
|
||||
leftbar = CreateWindowExW(0,
|
||||
TOOLBARCLASSNAMEW, NULL,
|
||||
toolbarStyles | TBSTYLE_LIST | TBSTYLE_TRANSPARENT,
|
||||
0, 0, 0, 0,
|
||||
hwnd, (HMENU) 101, hInstance, NULL);
|
||||
if (leftbar == NULL)
|
||||
diele("CreateWindowExW(TOOLBARCLASSNAMEW) leftbar");
|
||||
SendMessageW(leftbar, TB_BUTTONSTRUCTSIZE, sizeof (TBBUTTON), 0);
|
||||
// I_IMAGENONE causes the button text to be left-aligned; don't use it
|
||||
// if (SendMessageW(leftbar, TB_SETBITMAPSIZE, 0, 0) == FALSE)
|
||||
// diele("TB_SETBITMAPSIZE");
|
||||
SendMessageW(leftbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_MIXEDBUTTONS);
|
||||
// TODO this *should* be DIPs...
|
||||
// TODO figure out where the *2 is documented
|
||||
// SendMessageW(leftbar, TB_SETPADDING, 0, MAKELPARAM(6 * 2, 5 * 2));
|
||||
ZeroMemory(tbb, 5 * sizeof (TBBUTTON));
|
||||
for (i = 0; i < 5; i++) {
|
||||
tbb[i].iBitmap = 0;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
ZeroMemory(&rbi, sizeof (REBARBANDINFOW));
|
||||
rbi.cbSize = sizeof (REBARBANDINFOW);
|
||||
rbi.fMask = RBBIM_CHILD | RBBIM_STYLE | RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_ID;
|
||||
rbi.fStyle = RBBS_NOGRIPPER | RBBS_CHILDEDGE | RBBS_USECHEVRON | RBBS_HIDETITLE;
|
||||
rbi.hwndChild = leftbar;
|
||||
rbi.cx = tbsizex;
|
||||
rbi.cyChild = tbsizey;
|
||||
rbi.cxMinChild = 0;
|
||||
rbi.cyMinChild = tbsizey;
|
||||
rbi.cxIdeal = tbsizex;
|
||||
rbi.wID = 0;
|
||||
if (SendMessageW(rebar, RB_INSERTBANDW, (WPARAM) (-1), (LPARAM) (&rbi)) == 0)
|
||||
diele("RB_INSERTBANDW leftbar");
|
||||
|
||||
rightbar = CreateWindowExW(0,
|
||||
TOOLBARCLASSNAMEW, NULL,
|
||||
toolbarStyles | TBSTYLE_TRANSPARENT,
|
||||
0, 0, 0, 0,
|
||||
hwnd, (HMENU) 102, hInstance, NULL);
|
||||
if (rightbar == NULL)
|
||||
diele("CreateWindowExW(TOOLBARCLASSNAMEW) rightbar");
|
||||
SendMessageW(rightbar, TB_BUTTONSTRUCTSIZE, sizeof (TBBUTTON), 0);
|
||||
SendMessageW(rightbar, TB_SETIMAGELIST, 0, (LPARAM) rightList);
|
||||
SendMessageW(rightbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS);
|
||||
// TODO this *should* be DIPs...
|
||||
// TODO figure out where the *2 is documented
|
||||
// SendMessageW(rightbar, TB_SETPADDING, 0, MAKELPARAM(6 * 2, 5 * 2));
|
||||
ZeroMemory(tbb, 5 * sizeof (TBBUTTON));
|
||||
tbb[0].iBitmap = 0;
|
||||
tbb[0].idCommand = 0;
|
||||
tbb[0].fsState = TBSTATE_ENABLED;
|
||||
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)
|
||||
diele("TB_ADDBUTTONSW");
|
||||
// TODO check error
|
||||
// TODO figure out why this works here but not elsewhere
|
||||
// SendMessageW(rightbar, TB_SETBUTTONSIZE, 0, 0);
|
||||
|
||||
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;
|
||||
}
|
||||
tbbtnsize = (DWORD) SendMessageW(rightbar, TB_GETBUTTONSIZE, 0, 0);
|
||||
tbsizey = HIWORD(tbbtnsize);
|
||||
|
||||
ZeroMemory(&rbi, sizeof (REBARBANDINFOW));
|
||||
rbi.cbSize = sizeof (REBARBANDINFOW);
|
||||
rbi.fMask = RBBIM_CHILD | RBBIM_STYLE | RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_ID;
|
||||
rbi.fStyle = RBBS_NOGRIPPER | RBBS_HIDETITLE;
|
||||
rbi.hwndChild = rightbar;
|
||||
rbi.cx = tbsizex;
|
||||
rbi.cyChild = tbsizey;
|
||||
rbi.cxMinChild = tbsizex;
|
||||
rbi.cyMinChild = tbsizey;
|
||||
rbi.wID = 1;
|
||||
if (SendMessageW(rebar, RB_INSERTBANDW, (WPARAM) (-1), (LPARAM) (&rbi)) == 0)
|
||||
diele("RB_INSERTBANDW rightbar");
|
||||
|
||||
buttonx = 10;
|
||||
buttony = 40;
|
||||
#define buttonwid 200
|
||||
#define buttonht 25
|
||||
for (i = 0; drawmodes[i].text != NULL; i++) {
|
||||
button = CreateWindowExW(0,
|
||||
L"BUTTON", drawmodes[i].text,
|
||||
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;
|
||||
}
|
||||
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\")");
|
||||
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]));
|
||||
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);
|
||||
}
|
||||
|
||||
// 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()");
|
||||
}
|
||||
|
||||
// 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;
|
||||
BOOL invalidate = FALSE;
|
||||
WPARAM check;
|
||||
|
||||
switch (wParam) {
|
||||
case MAKEWPARAM(300, CBN_SELCHANGE):
|
||||
n = SendMessageW(rebarCombo, CB_GETCURSEL, 0, 0);
|
||||
selRebar = rebarThemes[n];
|
||||
changeRebar = TRUE;
|
||||
break;
|
||||
case MAKEWPARAM(301, CBN_SELCHANGE):
|
||||
n = SendMessageW(toolbarCombo, CB_GETCURSEL, 0, 0);
|
||||
selToolbar = toolbarThemes[n];
|
||||
changeToolbar = TRUE;
|
||||
break;
|
||||
case MAKEWPARAM(200, BN_CLICKED):
|
||||
drawmode = 0;
|
||||
n = SendMessageW(rebarCombo, WM_GETTEXTLENGTH, 0, 0);
|
||||
bufRebar = new WCHAR[n + 1];
|
||||
GetWindowTextW(rebarCombo, bufRebar, n + 1);
|
||||
n = SendMessageW(toolbarCombo, WM_GETTEXTLENGTH, 0, 0);
|
||||
bufToolbar = new WCHAR[n + 1];
|
||||
GetWindowTextW(toolbarCombo, bufToolbar, n + 1);
|
||||
selRebar = bufRebar;
|
||||
selToolbar = bufToolbar;
|
||||
changeRebar = TRUE;
|
||||
changeToolbar = TRUE;
|
||||
break;
|
||||
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)
|
||||
SendMessageW(leftbar, TB_SETSTYLE, 0, toolbarStyles | TBSTYLE_LIST | TBSTYLE_TRANSPARENT);
|
||||
else
|
||||
SendMessageW(leftbar, TB_SETSTYLE, 0, toolbarStyles | TBSTYLE_LIST);
|
||||
ShowWindow(leftbar, SW_SHOW);
|
||||
break;
|
||||
case MAKEWPARAM(202, BN_CLICKED):
|
||||
SetFocus(leftbar);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
invalidate = TRUE;
|
||||
}
|
||||
if (changeToolbar) {
|
||||
if (selToolbar != NULL && wcscmp(selToolbar, L"NULL") == 0)
|
||||
selToolbar = NULL;
|
||||
if (selToolbar != NULL && *selToolbar != L'\0') {
|
||||
SendMessageW(leftbar, TB_SETWINDOWTHEME, 0, (LPARAM) selToolbar);
|
||||
SendMessageW(rightbar, TB_SETWINDOWTHEME, 0, (LPARAM) selToolbar);
|
||||
} else {
|
||||
SetWindowTheme(leftbar, selToolbar, selToolbar);
|
||||
SetWindowTheme(rightbar, selToolbar, selToolbar);
|
||||
}
|
||||
invalidate = TRUE;
|
||||
}
|
||||
if (invalidate)
|
||||
InvalidateRect(hwnd, NULL, TRUE);
|
||||
if (bufRebar != NULL)
|
||||
delete[] bufRebar;
|
||||
if (bufToolbar != NULL)
|
||||
delete[] bufToolbar;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
NMHDR *nm = (NMHDR *) lParam;
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_CREATE:
|
||||
onWM_CREATE(hwnd);
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
case WM_SIZE:
|
||||
repositionRebar(hwnd);
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
handleEvents(hwnd, wParam);
|
||||
break;
|
||||
case WM_NOTIFY:
|
||||
switch (nm->code) {
|
||||
case NM_CUSTOMDRAW:
|
||||
if (drawmode == 0)
|
||||
break;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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;
|
||||
HRESULT hr;
|
||||
|
||||
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)");
|
||||
|
||||
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);
|
||||
if (hr != S_OK)
|
||||
diehr("LoadIconMetric(IDI_QUESTION)", hr);
|
||||
rightList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
|
||||
ILC_COLOR32, 0, 3);
|
||||
if (rightList == NULL)
|
||||
diele("ImageList_Create()");
|
||||
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)");
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in new issue
Block a user