diff --git a/GNUmakefile.msvc b/GNUmakefile.msvc index 2313fbcd..e1840e8d 100644 --- a/GNUmakefile.msvc +++ b/GNUmakefile.msvc @@ -47,6 +47,7 @@ CFILES += \ windows/label.c \ windows/main.c \ windows/menu.c \ + windows/multilineentry.c \ windows/parent.c \ windows/progressbar.c \ windows/radiobuttons.c \ diff --git a/test/queuemaintest.cpp b/test/queuemaintest.cpp index 1314cf5f..338c4716 100644 --- a/test/queuemaintest.cpp +++ b/test/queuemaintest.cpp @@ -25,6 +25,7 @@ void sayTime(void *data) void threadproc(void) { + ourlock.lock(); while (cv.wait_for(ourlock, chrono::seconds(1)) == cv_status::timeout) { time_t t; char *base; @@ -80,6 +81,8 @@ int main(void) uiBoxAppend(b, uiControl(e), 1); + // timeThread needs to lock ourlock itself - see http://stackoverflow.com/a/34121629/3408572 + ourlock.unlock(); timeThread = new thread(threadproc); uiWindowOnClosing(w, onClosing, NULL); diff --git a/windows/GNUmakeinc.mk b/windows/GNUmakeinc.mk index c7c5b270..2831728d 100644 --- a/windows/GNUmakeinc.mk +++ b/windows/GNUmakeinc.mk @@ -20,6 +20,7 @@ CFILES += \ windows/label.c \ windows/main.c \ windows/menu.c \ + windows/multilineentry.c \ windows/parent.c \ windows/progressbar.c \ windows/radiobuttons.c \ diff --git a/windows/multilineentry.c b/windows/multilineentry.c new file mode 100644 index 00000000..7b54042d --- /dev/null +++ b/windows/multilineentry.c @@ -0,0 +1,119 @@ +// 8 april 2015 +#include "uipriv_windows.h" + +// TODO there's alpha darkening of text going on; something is up in our parent logic +// TODO resizing collapses newlines + +struct uiMultilineEntry { + uiWindowsControl c; + HWND hwnd; + void (*onChanged)(uiMultilineEntry *, void *); + void *onChangedData; + BOOL inhibitChanged; +}; + +uiWindowsDefineControlWithOnDestroy( + uiMultilineEntry, // type name + uiMultilineEntryType, // type function + uiWindowsUnregisterWM_COMMANDHandler(this->hwnd); // on destroy +) + +static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult) +{ + uiMultilineEntry *e = uiMultilineEntry(c); + + if (code != EN_CHANGE) + return FALSE; + if (e->inhibitChanged) + return FALSE; + (*(e->onChanged))(e, e->onChangedData); + *lResult = 0; + return TRUE; +} + +// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing +#define entryWidth 107 /* this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary */ +// TODO change this for multiline text boxes +#define entryHeight 14 + +static void minimumSize(uiWindowsControl *c, uiWindowsSizing *d, intmax_t *width, intmax_t *height) +{ + *width = uiWindowsDlgUnitsToX(entryWidth, d->BaseX); + *height = uiWindowsDlgUnitsToY(entryHeight, d->BaseY); +} + +static void defaultOnChanged(uiMultilineEntry *e, void *data) +{ + // do nothing +} + +char *uiMultilineEntryText(uiMultilineEntry *e) +{ + return uiWindowsUtilText(e->hwnd); +} + +void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text) +{ + // doing this raises an EN_CHANGED + e->inhibitChanged = TRUE; + uiWindowsUtilSetText(e->hwnd, text); + e->inhibitChanged = FALSE; + // don't queue the control for resize; entry sizes are independent of their contents +} + +void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text) +{ + LRESULT n; + WCHAR *wtext; + + // TODO does doing this raise EN_CHANGED? + // TODO preserve selection? caret? what if caret used to be at end? + // TODO scroll to bottom? + n = SendMessageW(e->hwnd, WM_GETTEXTLENGTH, 0, 0); + SendMessageW(e->hwnd, EM_SETSEL, n, n); + wtext = toUTF16(text); + SendMessageW(e->hwnd, EM_REPLACESEL, FALSE, (LPARAM) wtext); + uiFree(wtext); +} + +void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *, void *), void *data) +{ + e->onChanged = f; + e->onChangedData = data; +} + +int uiMultilineEntryReadOnly(uiMultilineEntry *e) +{ + return (getStyle(e->hwnd) & ES_READONLY) != 0; +} + +void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly) +{ + WPARAM ro; + + ro = (WPARAM) FALSE; + if (readonly) + ro = (WPARAM) TRUE; + if (SendMessage(e->hwnd, EM_SETREADONLY, ro, 0) == 0) + logLastError("error making uiMultilineEntry read-only in uiMultilineEntrySetReadOnly()"); +} + +uiMultilineEntry *uiNewMultilineEntry(void) +{ + uiMultilineEntry *e; + + e = (uiMultilineEntry *) uiNewControl(uiMultilineEntryType()); + + e->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE, + L"edit", L"", + ES_AUTOVSCROLL | ES_LEFT | ES_MULTILINE | ES_NOHIDESEL | ES_WANTRETURN | WS_TABSTOP | WS_VSCROLL, + hInstance, NULL, + TRUE); + + uiWindowsRegisterWM_COMMANDHandler(e->hwnd, onWM_COMMAND, uiControl(e)); + uiMultilineEntryOnChanged(e, defaultOnChanged, NULL); + + uiWindowsFinishNewControl(e, uiMultilineEntry); + + return e; +} diff --git a/windows/tabpage.c b/windows/tabpage.c index 0c2e9ecb..75b87eb0 100644 --- a/windows/tabpage.c +++ b/windows/tabpage.c @@ -22,6 +22,7 @@ void tabPageMargins(HWND hwnd, intmax_t *left, intmax_t *top, intmax_t *right, i // dummy dialog procedure; see below for details // let's handle parent messages here to avoid needing to subclass // TODO do we need to handle DM_GETDEFID/DM_SETDEFID here too because of the ES_WANTRETURN stuff at http://blogs.msdn.com/b/oldnewthing/archive/2007/08/20/4470527.aspx? what about multiple default buttons (TODO)? +// TODO we definitely need to do something about edit message handling; it does a fake close of our parent on pressing escape, causing uiWindow to stop responding to maximizes but still respond to events and then die horribly on destruction static INT_PTR CALLBACK dlgproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lResult;