static BOOL cbTypeToSelect(HWND cb, LRESULT *posOut, BOOL restoreAfter) { WCHAR *text; LRESULT pos; DWORD selStart, selEnd; // start by saving the current selection as setting the item will change the selection SendMessageW(cb, CB_GETEDITSEL, (WPARAM) (&selStart), (LPARAM) (&selEnd)); text = windowText(cb); pos = SendMessageW(cb, CB_FINDSTRINGEXACT, (WPARAM) (-1), (LPARAM) text); if (pos == (LRESULT) CB_ERR) { uiFree(text); return FALSE; } cbSetCurSel(cb, (WPARAM) pos); if (posOut != NULL) *posOut = pos; if (restoreAfter) if (SendMessageW(cb, WM_SETTEXT, 0, (LPARAM) text) != (LRESULT) TRUE) logLastError(L"error restoring old combobox text"); uiFree(text); // and restore the selection like above // TODO isn't there a 32-bit version of this if (SendMessageW(cb, CB_SETEDITSEL, 0, MAKELPARAM(selStart, selEnd)) != (LRESULT) TRUE) logLastError(L"error restoring combobox edit selection"); return TRUE; }
// the returned pointer is actually to the second character // if the first character is - then free, otherwise don't static const char *initerr(const char *message, const WCHAR *label, DWORD value) { WCHAR *sysmsg; BOOL hassysmsg; WCHAR *wmessage; WCHAR *wout; char *out; hassysmsg = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, value, 0, (LPWSTR) (&sysmsg), 0, NULL) != 0; if (!hassysmsg) sysmsg = L""; wmessage = toUTF16(message + 1); wout = debugstrf(L"-error initializing libui: %s; code %I32d (0x%08I32X) %s", wmessage, value, value, sysmsg); uiFree(wmessage); if (hassysmsg) LocalFree(sysmsg); // ignore error if (wout == NULL) // debugstrf() failed; return message raw return message + 1; out = toUTF8(wout); uiFree(wout); return out + 1; }
static const char *initerr(const char *message, const WCHAR *label, DWORD value) { WCHAR *sysmsg; BOOL hassysmsg; WCHAR *beforele; WCHAR *afterle; int n; WCHAR *wmessage; WCHAR *wstr; const char *str; if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, value, 0, (LPWSTR) (&sysmsg), 0, NULL) != 0) { hassysmsg = TRUE; beforele = L" ("; afterle = L")"; } else { hassysmsg = FALSE; sysmsg = L""; beforele = L""; afterle = L""; } wmessage = toUTF16(message); n = _scwprintf(initErrorFormat, initErrorArgs); wstr = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]"); snwprintf(wstr, n + 1, initErrorFormat, initErrorArgs); str = toUTF8(wstr); uiFree(wstr); if (hassysmsg) if (LocalFree(sysmsg) != NULL) logLastError("error freeing system message in loadLastError()"); uiFree(wmessage); return str; }
static void updateDialog(struct colorDialog *c, HWND whichChanged) { double r, g, b; uint8_t rb, gb, bb, ab; WCHAR *str; WCHAR hexbuf[16]; // more than enough c->updating = TRUE; updateDouble(c->editH, c->h, whichChanged); updateDouble(c->editS, c->s, whichChanged); updateDouble(c->editV, c->v, whichChanged); hsv2RGB(c->h, c->s, c->v, &r, &g, &b); updateDouble(c->editRDouble, r, whichChanged); updateDouble(c->editGDouble, g, whichChanged); updateDouble(c->editBDouble, b, whichChanged); updateDouble(c->editADouble, c->a, whichChanged); rb = (uint8_t) (r * 255); gb = (uint8_t) (g * 255); bb = (uint8_t) (b * 255); ab = (uint8_t) (c->a * 255); if (whichChanged != c->editRInt) { str = itoutf16(rb); setWindowText(c->editRInt, str); uiFree(str); } if (whichChanged != c->editGInt) { str = itoutf16(gb); setWindowText(c->editGInt, str); uiFree(str); } if (whichChanged != c->editBInt) { str = itoutf16(bb); setWindowText(c->editBInt, str); uiFree(str); } if (whichChanged != c->editAInt) { str = itoutf16(ab); setWindowText(c->editAInt, str); uiFree(str); } if (whichChanged != c->editHex) { rgba2Hex(rb, gb, bb, ab, hexbuf); setWindowText(c->editHex, hexbuf); } // TODO TRUE? invalidateRect(c->svChooser, NULL, TRUE); invalidateRect(c->hSlider, NULL, TRUE); invalidateRect(c->preview, NULL, TRUE); invalidateRect(c->opacitySlider, NULL, TRUE); c->updating = FALSE; }
void ptrArrayDestroy(struct ptrArray *p) { if (p->len != 0) complain("attempt to destroy ptrarray %p while it still has pointers inside", p); if (p->ptrs != NULL) // array was created but nothing was ever put inside uiFree(p->ptrs); uiFree(p); }
static void msgbox(HWND parent, const char *title, const char *description, TASKDIALOG_COMMON_BUTTON_FLAGS buttons, PCWSTR icon) { WCHAR *wtitle, *wdescription; HRESULT hr; wtitle = toUTF16(title); wdescription = toUTF16(description); hr = TaskDialog(parent, NULL, NULL, wtitle, wdescription, buttons, icon, NULL); if (hr != S_OK) logHRESULT(L"error showing task dialog", hr); uiFree(wdescription); uiFree(wtitle); }
void freeContext(uiDrawContext *c) { if (c->currentClip != NULL) ID2D1PathGeometry_Release(c->currentClip); uninitStates(c); uiFree(c); }
void uiRadioButtonsAppend(uiRadioButtons *r, const char *text) { HWND hwnd; WCHAR *wtext; DWORD groupTabStop; // the first radio button gets both WS_GROUP and WS_TABSTOP // successive radio buttons get *neither* groupTabStop = 0; if (r->hwnds->size() == 0) groupTabStop = WS_GROUP | WS_TABSTOP; wtext = toUTF16(text); hwnd = uiWindowsEnsureCreateControlHWND(0, L"button", wtext, BS_RADIOBUTTON | groupTabStop, hInstance, NULL, TRUE); uiFree(wtext); uiWindowsEnsureSetParentHWND(hwnd, r->hwnd); uiWindowsRegisterWM_COMMANDHandler(hwnd, onWM_COMMAND, uiControl(r)); r->hwnds->push_back(hwnd); radiobuttonsArrangeChildren(r); uiWindowsControlMinimumSizeChanged(uiWindowsControl(r)); }
static void familyChanged(struct fontDialog *f) { LRESULT pos; BOOL selected; IDWriteFontFamily *family; IDWriteFont *font, *matchFont; DWRITE_FONT_WEIGHT weight; DWRITE_FONT_STYLE style; DWRITE_FONT_STRETCH stretch; UINT32 i, n; UINT32 matching; WCHAR *label; HRESULT hr; selected = cbGetCurSel(f->familyCombobox, &pos); if (!selected) // on deselect, do nothing return; f->curFamily = pos; family = (IDWriteFontFamily *) cbGetItemData(f->familyCombobox, (WPARAM) (f->curFamily)); // for the nearest style match // when we select a new family, we want the nearest style to the previously selected one to be chosen // this is how the Choose Font sample does it hr = family->GetFirstMatchingFont( f->weight, f->stretch, f->style, &matchFont); if (hr != S_OK) logHRESULT(L"error finding first matching font to previous style in font dialog", hr); // we can't just compare pointers; a "newly created" object comes out // the Choose Font sample appears to do this instead weight = matchFont->GetWeight(); style = matchFont->GetStyle(); stretch = matchFont->GetStretch(); matchFont->Release(); // TODO test mutliple streteches; all the fonts I have have only one stretch value? wipeStylesBox(f); n = family->GetFontCount(); matching = 0; // a safe/suitable default just in case for (i = 0; i < n; i++) { hr = family->GetFont(i, &font); if (hr != S_OK) logHRESULT(L"error getting font for filling styles box", hr); label = fontStyleName(f->fc, font); pos = cbAddString(f->styleCombobox, label); uiFree(label); cbSetItemData(f->styleCombobox, (WPARAM) pos, (LPARAM) font); if (font->GetWeight() == weight && font->GetStyle() == style && font->GetStretch() == stretch) matching = i; } // and now, load the match cbSetCurSel(f->styleCombobox, (WPARAM) matching); styleChanged(f); }
static ID2D1GradientStopCollection *mkstops(uiDrawBrush *b, ID2D1RenderTarget *rt) { ID2D1GradientStopCollection *s; D2D1_GRADIENT_STOP *stops; size_t i; HRESULT hr; stops = uiAlloc(b->NumStops * sizeof (D2D1_GRADIENT_STOP), "D2D1_GRADIENT_STOP[]"); for (i = 0; i < b->NumStops; i++) { stops[i].position = b->Stops[i].Pos; stops[i].color.r = b->Stops[i].R; stops[i].color.g = b->Stops[i].G; stops[i].color.b = b->Stops[i].B; stops[i].color.a = b->Stops[i].A; } // TODO BUG IN MINGW // the Microsoft headers give this all 6 parameters // the MinGW headers use the 4-parameter version hr = (*(rt->lpVtbl->CreateGradientStopCollection))(rt, stops, b->NumStops, D2D1_GAMMA_2_2, // this is the default for the C++-only overload of ID2D1RenderTarget::GradientStopCollection() D2D1_EXTEND_MODE_CLAMP, &s); if (hr != S_OK) logHRESULT("error creating stop collection in mkstops()", hr); uiFree(stops); return s; }
int uiWindowsWindowTextWidth(HWND hwnd) { LRESULT len; WCHAR *text; HDC dc; HFONT prevfont; SIZE size; size.cx = 0; size.cy = 0; text = windowTextAndLen(hwnd, &len); if (len == 0) // no text; nothing to do goto noTextOrError; // now we can do the calculations dc = GetDC(hwnd); if (dc == NULL) { logLastError(L"error getting DC"); // on any error, assume no text goto noTextOrError; } prevfont = (HFONT) SelectObject(dc, hMessageFont); if (prevfont == NULL) { logLastError(L"error loading control font into device context"); ReleaseDC(hwnd, dc); goto noTextOrError; } if (GetTextExtentPoint32W(dc, text, len, &size) == 0) { logLastError(L"error getting text extent point"); // continue anyway, assuming size is 0 size.cx = 0; size.cy = 0; } // continue on errors; we got what we want if (SelectObject(dc, prevfont) != hMessageFont) logLastError(L"error restoring previous font into device context"); if (ReleaseDC(hwnd, dc) == 0) logLastError(L"error releasing DC"); uiFree(text); return size.cx; noTextOrError: uiFree(text); return 0; }
static gboolean doqueued(gpointer data) { struct queued *q = (struct queued *) data; (*(q->f))(q->data); uiFree(q); return FALSE; }
void uiWindowsSetWindowText(HWND hwnd, const char *text) { WCHAR *wtext; wtext = toUTF16(text); setWindowText(hwnd, wtext); uiFree(wtext); }
void uninitMenus(void) { uiMenu *m; uiMenuItem *item; size_t i, j; for (i = 0; i < len; i++) { m = menus[i]; uiFree(m->name); for (j = 0; j < m->len; j++) { item = m->items[j]; if (item->len != 0) // LONGTERM userbug()? implbug("menu item %p (%ws) still has uiWindows attached; did you forget to destroy some windows?", item, item->name); if (item->name != NULL) uiFree(item->name); if (item->hmenus != NULL) uiFree(item->hmenus); uiFree(item); } if (m->items != NULL) uiFree(m->items); uiFree(m); } if (menus != NULL) uiFree(menus); }
static void endFontDialog(struct fontDialog *f, INT_PTR code) { wipeStylesBox(f); cbWipeAndReleaseData(f->familyCombobox); fontCollectionFree(f->fc); if (EndDialog(f->hwnd, code) == 0) logLastError(L"error ending font dialog"); uiFree(f); }
static void msgbox(const char *title, const char *description, TASKDIALOG_COMMON_BUTTON_FLAGS buttons, PCWSTR icon) { WCHAR *wtitle, *wdescription; HWND dialogHelper; HRESULT hr; wtitle = toUTF16(title); wdescription = toUTF16(description); dialogHelper = beginDialogHelper(); hr = TaskDialog(dialogHelper, NULL, NULL, wtitle, wdescription, buttons, icon, NULL); if (hr != S_OK) logHRESULT("error showing task dialog in msgbox()", hr); endDialogHelper(dialogHelper); uiFree(wdescription); uiFree(wtitle); }
void uiWindowsUtilSetText(HWND hwnd, const char *text) { WCHAR *wtext; wtext = toUTF16(text); if (SetWindowTextW(hwnd, wtext) == 0) logLastError("error setting control text in uiWindowsControlSetText()"); uiFree(wtext); }
static double editDouble(HWND hwnd) { WCHAR *s; double d; s = windowText(hwnd); d = _wtof(s); uiFree(s); return d; }
void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text) { LRESULT n; char *crlf; WCHAR *wtext; // doing this raises an EN_CHANGED e->inhibitChanged = TRUE; // 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); crlf = LFtoCRLF(text); wtext = toUTF16(crlf); uiFree(crlf); SendMessageW(e->hwnd, EM_REPLACESEL, FALSE, (LPARAM) wtext); uiFree(wtext); e->inhibitChanged = FALSE; }
static int editInt(HWND hwnd) { WCHAR *s; int i; s = windowText(hwnd); i = _wtoi(s); uiFree(s); return i; }
static void updateDouble(HWND hwnd, double d, HWND whichChanged) { WCHAR *str; if (whichChanged == hwnd) return; str = ftoutf16(d); setWindowText(hwnd, str); uiFree(str); }
char *uiWindowsWindowText(HWND hwnd) { WCHAR *wtext; char *text; wtext = windowText(hwnd); text = toUTF8(wtext); uiFree(wtext); return text; }
void uiDrawFreePath(uiDrawPath *p) { if (p->inFigure) ID2D1GeometrySink_EndFigure(p->sink, D2D1_FIGURE_END_OPEN); if (p->sink != NULL) // TODO close sink first? ID2D1GeometrySink_Release(p->sink); ID2D1PathGeometry_Release(p->path); uiFree(p); }
void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text) { char *crlf; // doing this raises an EN_CHANGED e->inhibitChanged = TRUE; crlf = LFtoCRLF(text); uiWindowsSetWindowText(e->hwnd, text); uiFree(crlf); e->inhibitChanged = FALSE; // don't queue the control for resize; entry sizes are independent of their contents }
// TOOD crlf stuff 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); }
static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult) { uiSpinbox *s = (uiSpinbox *) c; WCHAR *wtext; if (code != EN_CHANGE) return FALSE; if (s->inhibitChanged) return FALSE; // We want to allow typing negative numbers; the natural way to do so is to start with a -. // However, if we just have the code below, the up-down will catch the bare - and reject it. // Let's fix that. // This won't handle leading spaces, but spaces aren't allowed *anyway*. wtext = windowText(s->edit); if (wcscmp(wtext, L"-") == 0) { uiFree(wtext); return TRUE; } uiFree(wtext); // value() does the work for us value(s); (*(s->onChanged))(s, s->onChangedData); return TRUE; }
static void hexChanged(struct colorDialog *c) { WCHAR *buf; double r, g, b, a; BOOL is; buf = windowText(c->editHex); is = hex2RGBA(buf, &r, &g, &b, &a); uiFree(buf); if (!is) return; rgb2HSV(r, g, b, &(c->h), &(c->s), &(c->v)); c->a = a; updateDialog(c, c->editHex); }
uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) { uiWindow *w; WCHAR *wtitle; BOOL hasMenubarBOOL; uiWindowsNewControl(uiWindow, w); hasMenubarBOOL = FALSE; if (hasMenubar) hasMenubarBOOL = TRUE; w->hasMenubar = hasMenubarBOOL; #define style WS_OVERLAPPEDWINDOW #define exstyle 0 wtitle = toUTF16(title); w->hwnd = CreateWindowExW(exstyle, windowClass, wtitle, style, CW_USEDEFAULT, CW_USEDEFAULT, // use the raw width and height for now // this will get CW_USEDEFAULT (hopefully) predicting well // even if it doesn't, we're adjusting it later width, height, NULL, NULL, hInstance, w); if (w->hwnd == NULL) logLastError(L"error creating window"); uiFree(wtitle); if (hasMenubar) { w->menubar = makeMenubar(); if (SetMenu(w->hwnd, w->menubar) == 0) logLastError(L"error giving menu to window"); } // and use the proper size setClientSize(w, width, height, hasMenubarBOOL, style, exstyle); uiWindowOnClosing(w, defaultOnClosing, NULL); windows[w] = true; return w; }
static struct fontDialog *beginFontDialog(HWND hwnd, LPARAM lParam) { struct fontDialog *f; UINT32 i, nFamilies; IDWriteFontFamily *family; WCHAR *wname; LRESULT pos; HWND samplePlacement; HRESULT hr; f = uiNew(struct fontDialog); f->hwnd = hwnd; f->params = (struct fontDialogParams *) lParam; 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(); for (i = 0; i < nFamilies; i++) { hr = f->fc->fonts->GetFontFamily(i, &family); if (hr != S_OK) logHRESULT(L"error getting font family", hr); wname = fontCollectionFamilyName(f->fc, family); pos = cbAddString(f->familyCombobox, wname); uiFree(wname); cbSetItemData(f->familyCombobox, (WPARAM) pos, (LPARAM) family); } for (i = 0; defaultSizes[i].text != NULL; i++) cbInsertString(f->sizeCombobox, defaultSizes[i].text, (WPARAM) i); samplePlacement = getDlgItem(f->hwnd, rcFontSamplePlacement); uiWindowsEnsureGetWindowRect(samplePlacement, &(f->sampleRect)); mapWindowRect(NULL, f->hwnd, &(f->sampleRect)); uiWindowsEnsureDestroyWindow(samplePlacement); f->sampleBox = newD2DScratch(f->hwnd, &(f->sampleRect), (HMENU) rcFontSamplePlacement, fontDialogSampleSubProc, (DWORD_PTR) f); setupInitialFontDialogState(f); return f; }
uiCheckbox *uiNewCheckbox(const char *text) { uiCheckbox *c; WCHAR *wtext; uiWindowsNewControl(uiCheckbox, c); wtext = toUTF16(text); c->hwnd = uiWindowsEnsureCreateControlHWND(0, L"button", wtext, BS_CHECKBOX | WS_TABSTOP, hInstance, NULL, TRUE); uiFree(wtext); uiWindowsRegisterWM_COMMANDHandler(c->hwnd, onWM_COMMAND, uiControl(c)); uiCheckboxOnToggled(c, defaultOnToggled, NULL); return c; }