// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775498%28v=vs.85%29.aspx /++ minigui is a smallish GUI widget library, aiming to be on par with at least HTML4 forms and a few other expected gui components. It uses native controls on Windows and does its own thing on Linux (Mac is not currently supported but may be later, and should use native controls) to keep size down. Its #1 goal is to be useful without being large and complicated like GTK and Qt. I love Qt, if you want something full featured, use it! But if you want something you can just drop into a small project and expect the basics to work without outside dependencies, hopefully minigui will work for you. The event model is similar to what you use in the browser with Javascript and the layout engine tries to automatically fit things in. FOR BEST RESULTS: be sure to link with the appropriate subsystem command `-L/SUBSYSTEM:WINDOWS:5.0`, for example, because otherwise you'll get a console and other visual bugs. Examples: +/ module arsd.minigui; /* The main goals of minigui.d are to: 1) Provide basic widgets that just work in a lightweight lib. I basically want things comparable to a plain HTML form, plus the easy and obvious things you expect from Windows apps like a menu. 2) Use native things when possible for best functionality with least library weight. 3) Give building blocks to provide easy extension for your custom widgets, or hooking into additional native widgets I didn't wrap. 4) Provide interfaces for easy interaction between third party minigui extensions. (event model, perhaps signals/slots, drop-in ease of use bits.) 5) Zero non-system dependencies, including Phobos as much as I reasonably can. It must only import arsd.color and my simpledisplay.d. If you need more, it will have to be an extension module. 6) An easy layout system that generally works. A stretch goal is to make it easy to make gui forms with code, some kind of resource file (xml?) and even a wysiwyg designer. Another stretch goal is to make it easy to hook data into the gui, including from reflection. So like auto-generate a form from a function signature or struct definition, or show a list from an array that automatically updates as the array is changed. Then, your program focuses on the data more than the gui interaction. STILL NEEDED: * combo box. (this is diff than select because you can free-form edit too. more like a lineedit with autoselect) * slider * listbox * spinner * label? * rich text */ abstract class ComboboxBase : Widget { // if the user can enter arbitrary data, we want to use 2 == CBS_DROPDOWN // or to always show the list, we want CBS_SIMPLE == 1 version(win32_widgets) this(uint style, Widget parent = null) { super(parent); parentWindow = parent.parentWindow; createWin32Window(this, "ComboBox", null, style); } private string[] options; private int selection = -1; void addOption(string s) { options ~= s; version(win32_widgets) SendMessageA(hwnd, 323 /*CB_ADDSTRING*/, 0, cast(LPARAM) toStringzInternal(s)); } void setSelection(int idx) { selection = idx; version(win32_widgets) SendMessageA(hwnd, 334 /*CB_SETCURSEL*/, idx, 0); } version(win32_widgets) override void handleWmCommand(ushort cmd, ushort id) { selection = SendMessageA(hwnd, 327 /* CB_GETCURSEL */, 0, 0); auto event = new Event("changed", this); event.dispatch(); } } class DropDownSelection : ComboboxBase { this(Widget parent = null) { version(win32_widgets) super(3 /* CBS_DROPDOWNLIST */, parent); } } class FreeEntrySelection : ComboboxBase { this(Widget parent = null) { version(win32_widgets) super(2 /* CBS_DROPDOWN */, parent); } } class ComboBox : ComboboxBase { this(Widget parent = null) { version(win32_widgets) super(1 /* CBS_SIMPLE */, parent); } } /+ class Spinner : Widget { version(win32_widgets) this(Widget parent = null) { super(parent); parentWindow = parent.parentWindow; auto hlayout = new HorizontalLayout(this); lineEdit = new LineEdit(hlayout); upDownControl = new UpDownControl(hlayout); } LineEdit lineEdit; UpDownControl upDownControl; } class UpDownControl : Widget { version(win32_widgets) this(Widget parent = null) { super(parent); parentWindow = parent.parentWindow; createWin32Window(this, "msctls_updown32", null, 4/*UDS_ALIGNRIGHT*/| 2 /* UDS_SETBUDDYINT */ | 16 /* UDS_AUTOBUDDY */ | 32 /* UDS_ARROWKEYS */); } override int minHeight() { return Window.lineHeight; } override int maxHeight() { return Window.lineHeight * 3/2; } override int minWidth() { return Window.lineHeight * 3/2; } override int maxWidth() { return Window.lineHeight * 3/2; } } +/ class DataView : Widget { // this is the omnibus data viewer // the internal data layout is something like: // string[string][] but also each node can have parents } // http://msdn.microsoft.com/en-us/library/windows/desktop/bb775491(v=vs.85).aspx#PROGRESS_CLASS // http://svn.dsource.org/projects/bindings/trunk/win32/commctrl.d // FIXME: menus should prolly capture the mouse. ugh i kno. public import arsd.simpledisplay; version(Windows) import core.sys.windows.windows; // this is a hack to call the original window procedure on native win32 widgets if our event listener thing prevents default. private bool lastDefaultPrevented; version(Windows) { // use native widgets when available unless specifically asked otherwise version(custom_widgets) { enum bool UsingCustomWidgets = true; } else { version = win32_widgets; enum bool UsingCustomWidgets = false; } // and native theming when needed //version = win32_theming; } else { enum bool UsingCustomWidgets = true; } /* TextEdit needs: * carat manipulation * selection control * convenience functions for appendText, insertText, insertTextAtCarat, etc. For example: connect(paste, &textEdit.insertTextAtCarat); would be nice. I kinda want an omnibus dataview that combines list, tree, and table - it can be switched dynamically between them. Flattening policy: only show top level, show recursive, show grouped List styles: plain list (e.g.