diff --git a/windows/GNUfiles.mk b/windows/GNUfiles.mk index 1f691503..2791405b 100644 --- a/windows/GNUfiles.mk +++ b/windows/GNUfiles.mk @@ -11,6 +11,7 @@ CXXFILES += \ windows/button.cpp \ windows/checkbox.cpp \ windows/colorbutton.cpp \ + windows/colordialog.cpp \ windows/combobox.cpp \ windows/container.cpp \ windows/control.cpp \ diff --git a/windows/colorbutton.cpp b/windows/colorbutton.cpp index dd82340f..8c356950 100644 --- a/windows/colorbutton.cpp +++ b/windows/colorbutton.cpp @@ -28,17 +28,23 @@ static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult) { uiColorButton *b = uiColorButton(c); HWND parent; + struct colorDialogRGBA rgba; if (code != BN_CLICKED) return FALSE; -/* TODO parent = GetAncestor(b->hwnd, GA_ROOT); // TODO didn't we have a function for this - if (showColorDialog(parent, &(b->params))) { - updateColorButtonLabel(b); + rgba.r = b->r; + rgba.g = b->g; + rgba.b = b->b; + rgba.a = b->a; + if (showColorDialog(parent, &rgba)) { + b->r = rgba.r; + b->g = rgba.g; + b->b = rgba.b; + b->a = rgba.a; (*(b->onChanged))(b, b->onChangedData); } -*/ DialogBox(hInstance, MAKEINTRESOURCE(rcColorDialog), GetAncestor(b->hwnd, GA_ROOT), TODO); diff --git a/windows/colordialog.cpp b/windows/colordialog.cpp new file mode 100644 index 00000000..742cb3be --- /dev/null +++ b/windows/colordialog.cpp @@ -0,0 +1,207 @@ +// 16 may 2016 +#include "uipriv_windows.hpp" + +struct colorDialog { + HWND hwnd; + + HWND svChooser; + HWND hSlider; + HWND opacitySlider; + HWND editH; + HWND editS; + HWND editV; + HWND editRDouble, editRInt; + HWND editGDouble, editGInt; + HWND editBDouble, editBInt; + HWND editADouble, editAInt; + HWND editHex; + + double r; + double g; + double b; + double a; + struct colorDialogRGBA *out; +}; + +static void endColorDialog(struct colorDialog *c, INT_PTR code) +{ + if (EndDialog(c->hwnd, code) == 0) + logLastError(L"error ending color dialog"); + uiFree(c); +} + +static BOOL tryFinishDialog(struct colorDialog *c, WPARAM wParam) +{ + // cancelling + if (LOWORD(wParam) != IDOK) { + endColorDialog(c, 1); + return TRUE; + } + + // OK + c->out->r = c->r; + c->out->g = c->g; + c->out->b = c->b; + c->out->a = c->a; + endColorDialog(c, 2); + return TRUE; +} + +// a few issues: +// - some controls are positioned wrong; see http://stackoverflow.com/questions/37263267/why-are-some-of-my-controls-positioned-slightly-off-in-a-dialog-template-in-a-re +// - labels are too low; need to adjust them by the font's internal leading +// fixupControlPositions() and the following helper routines fix that for us + +static LONG offsetTo(HWND a, HWND b) +{ + RECT ra, rb; + + uiWindowsEnsureGetWindowRect(a, &ra); + uiWindowsEnsureGetWindowRect(b, &rb); + return rb.top - ra.bottom; +} + +static void moveWindowsUp(struct colorDialog *c, LONG by, ...) +{ + va_list ap; + HWND cur; + RECT r; + + va_start(ap, by); + for (;;) { + cur = va_arg(ap, HWND); + if (cur == NULL) + break; + uiWindowsEnsureGetWindowRect(cur, &r); + mapWindowRect(NULL, c->hwnd, &r); + r.top -= by; + r.bottom -= by; + // TODO this isn't technically during a resize + uiWindowsEnsureMoveWindowDuringResize(cur, + r.left, r.top, + r.right - r.left, r.bottom - r.top); + } + va_end(ap); +} + +static void fixupControlPositions(struct colorDialog *c) +{ + HWND labelH; + HWND labelS; + HWND labelV; + HWND labelR; + HWND labelG; + HWND labelB; + HWND labelA; + HWND labelHex; + LONG offset; + uiWindowsSizing sizing; + + labelH = getDlgItem(c->hwnd, rcHLabel); + labelS = getDlgItem(c->hwnd, rcSLabel); + labelV = getDlgItem(c->hwnd, rcVLabel); + labelR = getDlgItem(c->hwnd, rcRLabel); + labelG = getDlgItem(c->hwnd, rcGLabel); + labelB = getDlgItem(c->hwnd, rcBLabel); + labelA = getDlgItem(c->hwnd, rcALabel); + labelHex = getDlgItem(c->hwnd, rcHexLabel); + + offset = offsetTo(c->editH, c->editS); + moveWindowsUp(c, offset, + labelS, c->editS, + labelG, c->editGDouble, c->editGInt, + NULL); + offset = offsetTo(c->editS, c->editV); + moveWindowsUp(c, offset, + labelV, c->editV, + labelB, c->editBDouble, c->editBInt, + NULL); + offset = offsetTo(c->editBDouble, c->editADouble); + moveWindowsUp(c, offset, + labelA, c->editADouble, c->editAInt, + NULL); + + // TODO this uses the message font, not the dialog font + uiWindowsGetSizing(c->hwnd, &sizing); + offset = sizing.InternalLeading; + moveWindowsUp(c, offset, + labelH, labelS, labelV, + labelR, labelG, labelB, labelA, + labelHex, + NULL); +} + +static struct colorDialog *beginColorDialog(HWND hwnd, LPARAM lParam) +{ + struct colorDialog *c; + + c = uiNew(struct colorDialog); + c->hwnd = hwnd; + c->out = (struct colorDialogRGBA *) lParam; + c->r = c->out->r; // load initial values now + c->g = c->out->g; + c->b = c->out->b; + c->a = c->out->a; + + // TODO set up d2dscratches + + c->editH = getDlgItem(c->hwnd, rcH); + c->editS = getDlgItem(c->hwnd, rcS); + c->editV = getDlgItem(c->hwnd, rcV); + c->editRDouble = getDlgItem(c->hwnd, rcRDouble); + c->editRInt = getDlgItem(c->hwnd, rcRInt); + c->editGDouble = getDlgItem(c->hwnd, rcGDouble); + c->editGInt = getDlgItem(c->hwnd, rcGInt); + c->editBDouble = getDlgItem(c->hwnd, rcBDouble); + c->editBInt = getDlgItem(c->hwnd, rcBInt); + c->editADouble = getDlgItem(c->hwnd, rcADouble); + c->editAInt = getDlgItem(c->hwnd, rcAInt); + c->editHex = getDlgItem(c->hwnd, rcHex); + + fixupControlPositions(c); + + return c; +} + +static INT_PTR CALLBACK colorDialogDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + struct colorDialog *c; + + c = (struct colorDialog *) GetWindowLongPtrW(hwnd, DWLP_USER); + if (c == NULL) { + if (uMsg == WM_INITDIALOG) { + c = beginColorDialog(hwnd, lParam); + SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR) c); + return TRUE; + } + return FALSE; + } + + switch (uMsg) { + case WM_COMMAND: + SetWindowLongPtrW(c->hwnd, DWLP_MSGRESULT, 0); // just in case + switch (LOWORD(wParam)) { + case IDOK: + case IDCANCEL: + if (HIWORD(wParam) != BN_CLICKED) + return FALSE; + return tryFinishDialog(c, wParam); + } + return FALSE; + } + return FALSE; +} + +BOOL showColorDialog(HWND parent, struct colorDialogRGBA *c) +{ + switch (DialogBoxParamW(hInstance, MAKEINTRESOURCE(rcColorDialog), parent, colorDialogDlgProc, (LPARAM) c)) { + case 1: // cancel + return FALSE; + case 2: // ok + // make the compiler happy by putting the return after the switch + break; + default: + logLastError(L"error running color dialog"); + } + return TRUE; +} diff --git a/windows/fontdialog.cpp b/windows/fontdialog.cpp index feb264f0..ef1fae11 100644 --- a/windows/fontdialog.cpp +++ b/windows/fontdialog.cpp @@ -467,15 +467,9 @@ static struct fontDialog *beginFontDialog(HWND hwnd, LPARAM lParam) f->hwnd = hwnd; f->params = (struct fontDialogParams *) lParam; - f->familyCombobox = GetDlgItem(f->hwnd, rcFontFamilyCombobox); - if (f->familyCombobox == NULL) - logLastError(L"error getting font family combobox handle"); - f->styleCombobox = GetDlgItem(f->hwnd, rcFontStyleCombobox); - if (f->styleCombobox == NULL) - logLastError(L"error getting font style combobox handle"); - f->sizeCombobox = GetDlgItem(f->hwnd, rcFontSizeCombobox); - if (f->sizeCombobox == NULL) - logLastError(L"error getting font size combobox handle"); + f->familyCombobox = getDlgItem(f->hwnd, rcFontFamilyCombobox); + f->styleCombobox = getDlgItem(f->hwnd, rcFontStyleCombobox); + f->sizeCombobox = getDlgItem(f->hwnd, rcFontSizeCombobox); f->fc = loadFontCollection(); nFamilies = f->fc->fonts->GetFontFamilyCount(); @@ -492,9 +486,7 @@ static struct fontDialog *beginFontDialog(HWND hwnd, LPARAM lParam) for (i = 0; defaultSizes[i].text != NULL; i++) cbInsertString(f->sizeCombobox, defaultSizes[i].text, (WPARAM) i); - samplePlacement = GetDlgItem(f->hwnd, rcFontSamplePlacement); - if (samplePlacement == NULL) - logLastError(L"error getting sample placement static control handle"); + samplePlacement = getDlgItem(f->hwnd, rcFontSamplePlacement); uiWindowsEnsureGetWindowRect(samplePlacement, &(f->sampleRect)); mapWindowRect(NULL, f->hwnd, &(f->sampleRect)); uiWindowsEnsureDestroyWindow(samplePlacement); diff --git a/windows/resources.rc b/windows/resources.rc index 7029385b..a0acfcbd 100644 --- a/windows/resources.rc +++ b/windows/resources.rc @@ -74,16 +74,16 @@ BEGIN LTEXT "&R:", rcRLabel, 277, 81, 8, 8 EDITTEXT rcRDouble, 285, 78, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - EDITTEXT rcRInt, 315, 78, 20, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE + EDITTEXT rcRInt, 315, 78, 20, 14, ES_LEFT | ES_AUTOHSCROLL | ES_NUMBER | WS_TABSTOP, WS_EX_CLIENTEDGE LTEXT "&G:", rcGLabel, 277, 95, 8, 8 EDITTEXT rcGDouble, 285, 92, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - EDITTEXT rcGInt, 315, 92, 20, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE + EDITTEXT rcGInt, 315, 92, 20, 14, ES_LEFT | ES_AUTOHSCROLL | ES_NUMBER | WS_TABSTOP, WS_EX_CLIENTEDGE LTEXT "&B:", rcBLabel, 277, 109, 8, 8 EDITTEXT rcBDouble, 285, 106, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - EDITTEXT rcBInt, 315, 106, 20, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE + EDITTEXT rcBInt, 315, 106, 20, 14, ES_LEFT | ES_AUTOHSCROLL | ES_NUMBER | WS_TABSTOP, WS_EX_CLIENTEDGE LTEXT "&A:", rcALabel, 277, 123, 8, 8 EDITTEXT rcADouble, 285, 120, 30, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE - EDITTEXT rcAInt, 315, 120, 20, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE + EDITTEXT rcAInt, 315, 120, 20, 14, ES_LEFT | ES_AUTOHSCROLL | ES_NUMBER | WS_TABSTOP, WS_EX_CLIENTEDGE LTEXT "He&x:", rcHexLabel, 269, 146, 16, 8 EDITTEXT rcHex, 285, 143, 50, 14, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, WS_EX_CLIENTEDGE diff --git a/windows/uipriv_windows.hpp b/windows/uipriv_windows.hpp index 2929fd2b..e207f1bc 100644 --- a/windows/uipriv_windows.hpp +++ b/windows/uipriv_windows.hpp @@ -63,6 +63,7 @@ extern void clientSizeToWindowSize(HWND hwnd, intmax_t *width, intmax_t *height, extern HWND parentOf(HWND child); extern HWND parentToplevel(HWND child); extern void setWindowInsertAfter(HWND hwnd, HWND insertAfter); +extern HWND getDlgItem(HWND hwnd, int id); // text.cpp extern WCHAR *windowTextAndLen(HWND hwnd, LRESULT *len); @@ -124,6 +125,15 @@ extern struct tabPage *newTabPage(uiControl *child); extern void tabPageDestroy(struct tabPage *tp); extern void tabPageMinimumSize(struct tabPage *tp, intmax_t *width, intmax_t *height); +// colordialog.cpp +struct colorDialogRGBA { + double r; + double g; + double b; + double a; +}; +extern BOOL showColorDialog(HWND parent, struct colorDialogRGBA *c); + diff --git a/windows/winutil.cpp b/windows/winutil.cpp index b4fa692e..024260f2 100644 --- a/windows/winutil.cpp +++ b/windows/winutil.cpp @@ -120,3 +120,13 @@ void setWindowInsertAfter(HWND hwnd, HWND insertAfter) if (SetWindowPos(hwnd, insertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE) == 0) logLastError(L"error reordering window"); } + +HWND getDlgItem(HWND hwnd, int id) +{ + HWND out; + + out = GetDlgItem(hwnd, id); + if (out == NULL) + logLastError(L"error getting dialog item handle"); + return out; +}