[
  {
    "path": "AUTHORS",
    "content": "# This is the official list of 'Walk' authors for copyright purposes.\n\n# Names should be added to this file as\n#   Name or Organization <email address>\n# The email address is not required for organizations.\n\n# Please keep the list sorted.\n\n# Contributors\n# ============\n\nAlexander Neumann <an2048@gmail.com>\nAman Gupta <aman@tmm1.net>\nAnthony Dong <adongy@users.noreply.github.com>\nAttila Tajti <attila.tajti@gmail.com>\nAudrius Karabanovas <audrius@karabanovas.net>\nBenny Siegert <bsiegert@gmail.com>\nCary Cherng <ccherng@gmail.com>\nDmitry Bagdanov <dimbojob@gmail.com>\nHam Yeongtaek <yeongtaek.ham@gmail.com>\nHill <zhu.bicen@gmail.com>\niquanxin <iquanxin@aliyun.com>\nJames Scholes <james@jamesscholes.com>\nJason A. Donenfeld <Jason@zx2c4.com>\nJoseph Watson <jtwatson@linux-consulting.us>\nJoshua D. Sjoding <joshua.sjoding@scjalliance.com>\nktye <ktye.users.noreply.github.com>\nllxwj <llxwjlove@gmail.com>\nMateusz Czapliński <czapkofan@gmail.com>\nMichael Teichgräber <mteichgraeber@gmx.de>\nPaul Wolf <paul.wolf23@gmail.com>\nryujimiya <ryujimiya236@gmail.com>\nSemyon Tokarev <zlobzn@gmail.com>\nShawn Sun <datago@yeah.net>\nSimon Rozman <simon@rozman.si>\nTim Dufrane <tim.dufrane@gmail.com>\nVincent Vanackere <vincent.vanackere@gmail.com>\nxoviat <xoviat@gmail.com>\nevangwt <evangwt@gmail.com>\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2010 The Walk Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n3. The names of the authors may not be used to endorse or promote products\n   derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\nNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.mdown",
    "content": "About Walk\n==========\n\nWalk is a \"Windows Application Library Kit\" for the Go Programming Language.\n\nIts primarily useful for Desktop GUI development, but there is some more stuff.\n\nSetup\n=====\n\nMake sure you have a working Go installation.\nSee [Getting Started](http://golang.org/doc/install.html)\n\n##### Note\nWalk currently requires Go 1.11.x or later.\n\n##### To Install\nNow run `go get github.com/lxn/walk`\n\nUsing Walk\n==========\n\nThe preferred way to create GUIs with Walk is to use its declarative sub package,\nas illustrated in this small example:\n\n##### `test.go`\n\n```go\npackage main\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n\t\"strings\"\n)\n\nfunc main() {\n\tvar inTE, outTE *walk.TextEdit\n\n\tMainWindow{\n\t\tTitle:   \"SCREAMO\",\n\t\tMinSize: Size{600, 400},\n\t\tLayout:  VBox{},\n\t\tChildren: []Widget{\n\t\t\tHSplitter{\n\t\t\t\tChildren: []Widget{\n\t\t\t\t\tTextEdit{AssignTo: &inTE},\n\t\t\t\t\tTextEdit{AssignTo: &outTE, ReadOnly: true},\n\t\t\t\t},\n\t\t\t},\n\t\t\tPushButton{\n\t\t\t\tText: \"SCREAM\",\n\t\t\t\tOnClicked: func() {\n\t\t\t\t\toutTE.SetText(strings.ToUpper(inTE.Text()))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}.Run()\n}\n```\n\n##### Create Manifest `test.manifest`\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n    <assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n    <dependency>\n        <dependentAssembly>\n            <assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n        </dependentAssembly>\n    </dependency>\n    <application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n        <windowsSettings>\n            <dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n            <dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n        </windowsSettings>\n    </application>\n</assembly>\n```\n\nThen either compile the manifest using the [rsrc tool](https://github.com/akavel/rsrc), like this:\n\n\tgo get github.com/akavel/rsrc\n\trsrc -manifest test.manifest -o rsrc.syso\n\nor rename the `test.manifest` file to `test.exe.manifest` and distribute it with the application instead.\n\n##### Build app\n\nIn the directory containing `test.go` run\n\n\tgo build\n\t\nTo get rid of the cmd window, instead run\n\n\tgo build -ldflags=\"-H windowsgui\"\n\n##### Run app\n\t\n\ttest.exe\n\t\n##### Sample Output (Windows 7)\n\n![alt tag](http://i.imgur.com/lUrgE2Q.png)\n\n##### More Examples\nThere are some [examples](examples) that should get you started.\n\nApplication Manifest Files\n==========================\nWalk requires Common Controls 6. This means that you must put an appropriate\napplication manifest file either next to your executable or embedded as a\nresource.\n\nYou can copy one of the application manifest files that come with the examples.\n\nTo embed a manifest file as a resource, you can use the [rsrc tool](https://github.com/akavel/rsrc).\n\nIMPORTANT: If you don't embed a manifest as a resource, then you should not launch\nyour executable before the manifest file is in place.\nIf you do anyway, the program will not run properly. And worse, Windows will not\nrecognize a manifest file, you later drop next to the executable. To fix this,\nrebuild your executable and only launch it with a manifest file in place.\n\nCGo Optimizations\n=================\n\nThe usual default message loop includes calls to win32 API functions, which incurs a decent amount\nof runtime overhead coming from Go. As an alternative to this, you may compile Walk using an\noptional C implementation of the main message loop, by passing the `walk_use_cgo` build tag:\n\n   go build -tags walk_use_cgo\n"
  },
  {
    "path": "accessibility.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport \"github.com/lxn/win\"\n\n// AccState enum defines the state of the window/control\ntype AccState int32\n\n// Window/control states\nconst (\n\tAccStateNormal          AccState = win.STATE_SYSTEM_NORMAL\n\tAccStateUnavailable     AccState = win.STATE_SYSTEM_UNAVAILABLE\n\tAccStateSelected        AccState = win.STATE_SYSTEM_SELECTED\n\tAccStateFocused         AccState = win.STATE_SYSTEM_FOCUSED\n\tAccStatePressed         AccState = win.STATE_SYSTEM_PRESSED\n\tAccStateChecked         AccState = win.STATE_SYSTEM_CHECKED\n\tAccStateMixed           AccState = win.STATE_SYSTEM_MIXED\n\tAccStateIndeterminate   AccState = win.STATE_SYSTEM_INDETERMINATE\n\tAccStateReadonly        AccState = win.STATE_SYSTEM_READONLY\n\tAccStateHotTracked      AccState = win.STATE_SYSTEM_HOTTRACKED\n\tAccStateDefault         AccState = win.STATE_SYSTEM_DEFAULT\n\tAccStateExpanded        AccState = win.STATE_SYSTEM_EXPANDED\n\tAccStateCollapsed       AccState = win.STATE_SYSTEM_COLLAPSED\n\tAccStateBusy            AccState = win.STATE_SYSTEM_BUSY\n\tAccStateFloating        AccState = win.STATE_SYSTEM_FLOATING\n\tAccStateMarqueed        AccState = win.STATE_SYSTEM_MARQUEED\n\tAccStateAnimated        AccState = win.STATE_SYSTEM_ANIMATED\n\tAccStateInvisible       AccState = win.STATE_SYSTEM_INVISIBLE\n\tAccStateOffscreen       AccState = win.STATE_SYSTEM_OFFSCREEN\n\tAccStateSizeable        AccState = win.STATE_SYSTEM_SIZEABLE\n\tAccStateMoveable        AccState = win.STATE_SYSTEM_MOVEABLE\n\tAccStateSelfVoicing     AccState = win.STATE_SYSTEM_SELFVOICING\n\tAccStateFocusable       AccState = win.STATE_SYSTEM_FOCUSABLE\n\tAccStateSelectable      AccState = win.STATE_SYSTEM_SELECTABLE\n\tAccStateLinked          AccState = win.STATE_SYSTEM_LINKED\n\tAccStateTraversed       AccState = win.STATE_SYSTEM_TRAVERSED\n\tAccStateMultiselectable AccState = win.STATE_SYSTEM_MULTISELECTABLE\n\tAccStateExtselectable   AccState = win.STATE_SYSTEM_EXTSELECTABLE\n\tAccStateAlertLow        AccState = win.STATE_SYSTEM_ALERT_LOW\n\tAccStateAlertMedium     AccState = win.STATE_SYSTEM_ALERT_MEDIUM\n\tAccStateAlertHigh       AccState = win.STATE_SYSTEM_ALERT_HIGH\n\tAccStateProtected       AccState = win.STATE_SYSTEM_PROTECTED\n\tAccStateHasPopup        AccState = win.STATE_SYSTEM_HASPOPUP\n\tAccStateValid           AccState = win.STATE_SYSTEM_VALID\n)\n\n// AccRole enum defines the role of the window/control in UI.\ntype AccRole int32\n\n// Window/control system roles\nconst (\n\tAccRoleTitlebar           AccRole = win.ROLE_SYSTEM_TITLEBAR\n\tAccRoleMenubar            AccRole = win.ROLE_SYSTEM_MENUBAR\n\tAccRoleScrollbar          AccRole = win.ROLE_SYSTEM_SCROLLBAR\n\tAccRoleGrip               AccRole = win.ROLE_SYSTEM_GRIP\n\tAccRoleSound              AccRole = win.ROLE_SYSTEM_SOUND\n\tAccRoleCursor             AccRole = win.ROLE_SYSTEM_CURSOR\n\tAccRoleCaret              AccRole = win.ROLE_SYSTEM_CARET\n\tAccRoleAlert              AccRole = win.ROLE_SYSTEM_ALERT\n\tAccRoleWindow             AccRole = win.ROLE_SYSTEM_WINDOW\n\tAccRoleClient             AccRole = win.ROLE_SYSTEM_CLIENT\n\tAccRoleMenuPopup          AccRole = win.ROLE_SYSTEM_MENUPOPUP\n\tAccRoleMenuItem           AccRole = win.ROLE_SYSTEM_MENUITEM\n\tAccRoleTooltip            AccRole = win.ROLE_SYSTEM_TOOLTIP\n\tAccRoleApplication        AccRole = win.ROLE_SYSTEM_APPLICATION\n\tAccRoleDocument           AccRole = win.ROLE_SYSTEM_DOCUMENT\n\tAccRolePane               AccRole = win.ROLE_SYSTEM_PANE\n\tAccRoleChart              AccRole = win.ROLE_SYSTEM_CHART\n\tAccRoleDialog             AccRole = win.ROLE_SYSTEM_DIALOG\n\tAccRoleBorder             AccRole = win.ROLE_SYSTEM_BORDER\n\tAccRoleGrouping           AccRole = win.ROLE_SYSTEM_GROUPING\n\tAccRoleSeparator          AccRole = win.ROLE_SYSTEM_SEPARATOR\n\tAccRoleToolbar            AccRole = win.ROLE_SYSTEM_TOOLBAR\n\tAccRoleStatusbar          AccRole = win.ROLE_SYSTEM_STATUSBAR\n\tAccRoleTable              AccRole = win.ROLE_SYSTEM_TABLE\n\tAccRoleColumnHeader       AccRole = win.ROLE_SYSTEM_COLUMNHEADER\n\tAccRoleRowHeader          AccRole = win.ROLE_SYSTEM_ROWHEADER\n\tAccRoleColumn             AccRole = win.ROLE_SYSTEM_COLUMN\n\tAccRoleRow                AccRole = win.ROLE_SYSTEM_ROW\n\tAccRoleCell               AccRole = win.ROLE_SYSTEM_CELL\n\tAccRoleLink               AccRole = win.ROLE_SYSTEM_LINK\n\tAccRoleHelpBalloon        AccRole = win.ROLE_SYSTEM_HELPBALLOON\n\tAccRoleCharacter          AccRole = win.ROLE_SYSTEM_CHARACTER\n\tAccRoleList               AccRole = win.ROLE_SYSTEM_LIST\n\tAccRoleListItem           AccRole = win.ROLE_SYSTEM_LISTITEM\n\tAccRoleOutline            AccRole = win.ROLE_SYSTEM_OUTLINE\n\tAccRoleOutlineItem        AccRole = win.ROLE_SYSTEM_OUTLINEITEM\n\tAccRolePagetab            AccRole = win.ROLE_SYSTEM_PAGETAB\n\tAccRolePropertyPage       AccRole = win.ROLE_SYSTEM_PROPERTYPAGE\n\tAccRoleIndicator          AccRole = win.ROLE_SYSTEM_INDICATOR\n\tAccRoleGraphic            AccRole = win.ROLE_SYSTEM_GRAPHIC\n\tAccRoleStatictext         AccRole = win.ROLE_SYSTEM_STATICTEXT\n\tAccRoleText               AccRole = win.ROLE_SYSTEM_TEXT\n\tAccRolePushbutton         AccRole = win.ROLE_SYSTEM_PUSHBUTTON\n\tAccRoleCheckbutton        AccRole = win.ROLE_SYSTEM_CHECKBUTTON\n\tAccRoleRadiobutton        AccRole = win.ROLE_SYSTEM_RADIOBUTTON\n\tAccRoleCombobox           AccRole = win.ROLE_SYSTEM_COMBOBOX\n\tAccRoleDroplist           AccRole = win.ROLE_SYSTEM_DROPLIST\n\tAccRoleProgressbar        AccRole = win.ROLE_SYSTEM_PROGRESSBAR\n\tAccRoleDial               AccRole = win.ROLE_SYSTEM_DIAL\n\tAccRoleHotkeyfield        AccRole = win.ROLE_SYSTEM_HOTKEYFIELD\n\tAccRoleSlider             AccRole = win.ROLE_SYSTEM_SLIDER\n\tAccRoleSpinbutton         AccRole = win.ROLE_SYSTEM_SPINBUTTON\n\tAccRoleDiagram            AccRole = win.ROLE_SYSTEM_DIAGRAM\n\tAccRoleAnimation          AccRole = win.ROLE_SYSTEM_ANIMATION\n\tAccRoleEquation           AccRole = win.ROLE_SYSTEM_EQUATION\n\tAccRoleButtonDropdown     AccRole = win.ROLE_SYSTEM_BUTTONDROPDOWN\n\tAccRoleButtonMenu         AccRole = win.ROLE_SYSTEM_BUTTONMENU\n\tAccRoleButtonDropdownGrid AccRole = win.ROLE_SYSTEM_BUTTONDROPDOWNGRID\n\tAccRoleWhitespace         AccRole = win.ROLE_SYSTEM_WHITESPACE\n\tAccRolePageTabList        AccRole = win.ROLE_SYSTEM_PAGETABLIST\n\tAccRoleClock              AccRole = win.ROLE_SYSTEM_CLOCK\n\tAccRoleSplitButton        AccRole = win.ROLE_SYSTEM_SPLITBUTTON\n\tAccRoleIPAddress          AccRole = win.ROLE_SYSTEM_IPADDRESS\n\tAccRoleOutlineButton      AccRole = win.ROLE_SYSTEM_OUTLINEBUTTON\n)\n\n// Accessibility provides basic Dynamic Annotation of windows and controls.\ntype Accessibility struct {\n\twb *WindowBase\n}\n\n// SetAccelerator sets window accelerator name using Dynamic Annotation.\nfunc (a *Accessibility) SetAccelerator(acc string) error {\n\treturn a.accSetPropertyStr(a.wb.hWnd, &win.PROPID_ACC_KEYBOARDSHORTCUT, win.EVENT_OBJECT_ACCELERATORCHANGE, acc)\n}\n\n// SetDefaultAction sets window default action using Dynamic Annotation.\nfunc (a *Accessibility) SetDefaultAction(defAction string) error {\n\treturn a.accSetPropertyStr(a.wb.hWnd, &win.PROPID_ACC_DEFAULTACTION, win.EVENT_OBJECT_DEFACTIONCHANGE, defAction)\n}\n\n// SetDescription sets window description using Dynamic Annotation.\nfunc (a *Accessibility) SetDescription(acc string) error {\n\treturn a.accSetPropertyStr(a.wb.hWnd, &win.PROPID_ACC_DESCRIPTION, win.EVENT_OBJECT_DESCRIPTIONCHANGE, acc)\n}\n\n// SetHelp sets window help using Dynamic Annotation.\nfunc (a *Accessibility) SetHelp(help string) error {\n\treturn a.accSetPropertyStr(a.wb.hWnd, &win.PROPID_ACC_HELP, win.EVENT_OBJECT_HELPCHANGE, help)\n}\n\n// SetName sets window name using Dynamic Annotation.\nfunc (a *Accessibility) SetName(name string) error {\n\treturn a.accSetPropertyStr(a.wb.hWnd, &win.PROPID_ACC_NAME, win.EVENT_OBJECT_NAMECHANGE, name)\n}\n\n// SetRole sets window role using Dynamic Annotation. The role must be set when the window is\n// created and is not to be modified later.\nfunc (a *Accessibility) SetRole(role AccRole) error {\n\treturn a.accSetPropertyInt(a.wb.hWnd, &win.PROPID_ACC_ROLE, 0, int32(role))\n}\n\n// SetRoleMap sets window role map using Dynamic Annotation. The role map must be set when the\n// window is created and is not to be modified later.\nfunc (a *Accessibility) SetRoleMap(roleMap string) error {\n\treturn a.accSetPropertyStr(a.wb.hWnd, &win.PROPID_ACC_ROLEMAP, 0, roleMap)\n}\n\n// SetState sets window state using Dynamic Annotation.\nfunc (a *Accessibility) SetState(state AccState) error {\n\treturn a.accSetPropertyInt(a.wb.hWnd, &win.PROPID_ACC_STATE, win.EVENT_OBJECT_STATECHANGE, int32(state))\n}\n\n// SetStateMap sets window state map using Dynamic Annotation. The state map must be set when\n// the window is created and is not to be modified later.\nfunc (a *Accessibility) SetStateMap(stateMap string) error {\n\treturn a.accSetPropertyStr(a.wb.hWnd, &win.PROPID_ACC_STATEMAP, 0, stateMap)\n}\n\n// SetValueMap sets window value map using Dynamic Annotation. The value map must be set when\n// the window is created and is not to be modified later.\nfunc (a *Accessibility) SetValueMap(valueMap string) error {\n\treturn a.accSetPropertyStr(a.wb.hWnd, &win.PROPID_ACC_VALUEMAP, 0, valueMap)\n}\n\n// accSetPropertyInt sets integer window property for Dynamic Annotation.\nfunc (a *Accessibility) accSetPropertyInt(hwnd win.HWND, idProp *win.MSAAPROPID, event uint32, value int32) error {\n\taccPropServices := a.wb.group.accessibilityServices()\n\tif accPropServices == nil {\n\t\treturn newError(\"Dynamic Annotation not available\")\n\t}\n\tvar v win.VARIANT\n\tv.SetLong(value)\n\thr := accPropServices.SetHwndProp(hwnd, win.OBJID_CLIENT, win.CHILDID_SELF, idProp, &v)\n\tif win.FAILED(hr) {\n\t\treturn errorFromHRESULT(\"IAccPropServices.SetHwndProp\", hr)\n\t}\n\tif win.EVENT_OBJECT_CREATE <= event && event <= win.EVENT_OBJECT_END {\n\t\twin.NotifyWinEvent(event, hwnd, win.OBJID_CLIENT, win.CHILDID_SELF)\n\t}\n\treturn nil\n}\n\n// accSetPropertyStr sets string window property for Dynamic Annotation.\nfunc (a *Accessibility) accSetPropertyStr(hwnd win.HWND, idProp *win.MSAAPROPID, event uint32, value string) error {\n\taccPropServices := a.wb.group.accessibilityServices()\n\tif accPropServices == nil {\n\t\treturn newError(\"Dynamic Annotation not available\")\n\t}\n\thr := accPropServices.SetHwndPropStr(hwnd, win.OBJID_CLIENT, win.CHILDID_SELF, idProp, value)\n\tif win.FAILED(hr) {\n\t\treturn errorFromHRESULT(\"IAccPropServices.SetHwndPropStr\", hr)\n\t}\n\tif win.EVENT_OBJECT_CREATE <= event && event <= win.EVENT_OBJECT_END {\n\t\twin.NotifyWinEvent(event, hwnd, win.OBJID_CLIENT, win.CHILDID_SELF)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "action.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype actionChangedHandler interface {\n\tonActionChanged(action *Action) error\n\tonActionVisibleChanged(action *Action) error\n}\n\nvar (\n\t// ISSUE: When pressing enter resp. escape,\n\t// WM_COMMAND with wParam=1 resp. 2 is sent.\n\t// Maybe there is more to consider.\n\tnextActionId    uint16 = 3\n\tactionsById            = make(map[uint16]*Action)\n\tshortcut2Action        = make(map[Shortcut]*Action)\n)\n\ntype Action struct {\n\tmenu                          *Menu\n\ttriggeredPublisher            EventPublisher\n\tchangedHandlers               []actionChangedHandler\n\ttext                          string\n\ttoolTip                       string\n\timage                         Image\n\tcheckedCondition              Condition\n\tcheckedConditionChangedHandle int\n\tdefaultCondition              Condition\n\tdefaultConditionChangedHandle int\n\tenabledCondition              Condition\n\tenabledConditionChangedHandle int\n\tvisibleCondition              Condition\n\tvisibleConditionChangedHandle int\n\trefCount                      int\n\tshortcut                      Shortcut\n\tenabled                       bool\n\tvisible                       bool\n\tcheckable                     bool\n\tchecked                       bool\n\tdefawlt                       bool\n\texclusive                     bool\n\tid                            uint16\n}\n\nfunc NewAction() *Action {\n\ta := &Action{\n\t\tenabled: true,\n\t\tid:      nextActionId,\n\t\tvisible: true,\n\t}\n\n\tactionsById[a.id] = a\n\n\tnextActionId++\n\n\treturn a\n}\n\nfunc NewMenuAction(menu *Menu) *Action {\n\ta := NewAction()\n\ta.menu = menu\n\n\treturn a\n}\n\nfunc NewSeparatorAction() *Action {\n\treturn &Action{\n\t\tenabled: true,\n\t\tvisible: true,\n\t}\n}\n\nfunc (a *Action) addRef() {\n\ta.refCount++\n}\n\nfunc (a *Action) release() {\n\ta.refCount--\n\n\tif a.refCount == 0 {\n\t\ta.SetEnabledCondition(nil)\n\t\ta.SetVisibleCondition(nil)\n\n\t\tif a.menu != nil {\n\t\t\ta.menu.actions.Clear()\n\t\t\ta.menu.Dispose()\n\t\t}\n\n\t\tdelete(actionsById, a.id)\n\t\tdelete(shortcut2Action, a.shortcut)\n\t}\n}\n\nfunc (a *Action) Menu() *Menu {\n\treturn a.menu\n}\n\nfunc (a *Action) Checkable() bool {\n\treturn a.checkable\n}\n\nfunc (a *Action) SetCheckable(value bool) (err error) {\n\tif value != a.checkable {\n\t\told := a.checkable\n\n\t\ta.checkable = value\n\n\t\tif err = a.raiseChanged(); err != nil {\n\t\t\ta.checkable = old\n\t\t\ta.raiseChanged()\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (a *Action) Checked() bool {\n\treturn a.checked\n}\n\nfunc (a *Action) SetChecked(value bool) (err error) {\n\tif a.checkedCondition != nil {\n\t\tif bp, ok := a.checkedCondition.(*boolProperty); ok {\n\t\t\tif err := bp.Set(value); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\treturn newError(\"CheckedCondition != nil\")\n\t\t}\n\t}\n\n\tif value != a.checked {\n\t\told := a.checked\n\n\t\ta.checked = value\n\n\t\tif err = a.raiseChanged(); err != nil {\n\t\t\ta.checked = old\n\t\t\ta.raiseChanged()\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (a *Action) CheckedCondition() Condition {\n\treturn a.checkedCondition\n}\n\nfunc (a *Action) SetCheckedCondition(c Condition) {\n\tif a.checkedCondition != nil {\n\t\ta.checkedCondition.Changed().Detach(a.checkedConditionChangedHandle)\n\t}\n\n\ta.checkedCondition = c\n\n\tif c != nil {\n\t\ta.checked = c.Satisfied()\n\n\t\ta.checkedConditionChangedHandle = c.Changed().Attach(func() {\n\t\t\tif a.checked != c.Satisfied() {\n\t\t\t\ta.checked = !a.checked\n\n\t\t\t\ta.raiseChanged()\n\t\t\t}\n\t\t})\n\t}\n\n\ta.raiseChanged()\n}\n\nfunc (a *Action) Default() bool {\n\treturn a.defawlt\n}\n\nfunc (a *Action) SetDefault(value bool) (err error) {\n\tif a.defaultCondition != nil {\n\t\tif bp, ok := a.defaultCondition.(*boolProperty); ok {\n\t\t\tif err := bp.Set(value); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\treturn newError(\"DefaultCondition != nil\")\n\t\t}\n\t}\n\n\tif value != a.defawlt {\n\t\told := a.defawlt\n\n\t\ta.defawlt = value\n\n\t\tif err = a.raiseChanged(); err != nil {\n\t\t\ta.defawlt = old\n\t\t\ta.raiseChanged()\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (a *Action) DefaultCondition() Condition {\n\treturn a.defaultCondition\n}\n\nfunc (a *Action) SetDefaultCondition(c Condition) {\n\tif a.defaultCondition != nil {\n\t\ta.defaultCondition.Changed().Detach(a.defaultConditionChangedHandle)\n\t}\n\n\ta.defaultCondition = c\n\n\tif c != nil {\n\t\ta.defawlt = c.Satisfied()\n\n\t\ta.defaultConditionChangedHandle = c.Changed().Attach(func() {\n\t\t\tif a.defawlt != c.Satisfied() {\n\t\t\t\ta.defawlt = !a.defawlt\n\n\t\t\t\ta.raiseChanged()\n\t\t\t}\n\t\t})\n\t}\n\n\ta.raiseChanged()\n}\n\nfunc (a *Action) Enabled() bool {\n\treturn a.enabled\n}\n\nfunc (a *Action) SetEnabled(value bool) (err error) {\n\tif a.enabledCondition != nil {\n\t\treturn newError(\"EnabledCondition != nil\")\n\t}\n\n\tif value != a.enabled {\n\t\told := a.enabled\n\n\t\ta.enabled = value\n\n\t\tif err = a.raiseChanged(); err != nil {\n\t\t\ta.enabled = old\n\t\t\ta.raiseChanged()\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (a *Action) EnabledCondition() Condition {\n\treturn a.enabledCondition\n}\n\nfunc (a *Action) SetEnabledCondition(c Condition) {\n\tif a.enabledCondition != nil {\n\t\ta.enabledCondition.Changed().Detach(a.enabledConditionChangedHandle)\n\t}\n\n\ta.enabledCondition = c\n\n\tif c != nil {\n\t\ta.enabled = c.Satisfied()\n\n\t\ta.enabledConditionChangedHandle = c.Changed().Attach(func() {\n\t\t\tif a.enabled != c.Satisfied() {\n\t\t\t\ta.enabled = !a.enabled\n\n\t\t\t\ta.raiseChanged()\n\t\t\t}\n\t\t})\n\t}\n\n\ta.raiseChanged()\n}\n\nfunc (a *Action) Exclusive() bool {\n\treturn a.exclusive\n}\n\nfunc (a *Action) SetExclusive(value bool) (err error) {\n\tif value != a.exclusive {\n\t\told := a.exclusive\n\n\t\ta.exclusive = value\n\n\t\tif err = a.raiseChanged(); err != nil {\n\t\t\ta.exclusive = old\n\t\t\ta.raiseChanged()\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (a *Action) Image() Image {\n\treturn a.image\n}\n\nfunc (a *Action) SetImage(value Image) (err error) {\n\tif value != a.image {\n\t\told := a.image\n\n\t\ta.image = value\n\n\t\tif err = a.raiseChanged(); err != nil {\n\t\t\ta.image = old\n\t\t\ta.raiseChanged()\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (a *Action) Shortcut() Shortcut {\n\treturn a.shortcut\n}\n\nfunc (a *Action) SetShortcut(shortcut Shortcut) (err error) {\n\tif shortcut != a.shortcut {\n\t\told := a.shortcut\n\n\t\ta.shortcut = shortcut\n\t\tdefer func() {\n\t\t\tif err != nil {\n\t\t\t\ta.shortcut = old\n\t\t\t}\n\t\t}()\n\n\t\tif err = a.raiseChanged(); err != nil {\n\t\t\ta.shortcut = old\n\t\t\ta.raiseChanged()\n\t\t} else {\n\t\t\tif shortcut.Key == 0 {\n\t\t\t\tdelete(shortcut2Action, old)\n\t\t\t} else {\n\t\t\t\tshortcut2Action[shortcut] = a\n\t\t\t}\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (a *Action) Text() string {\n\treturn a.text\n}\n\nfunc (a *Action) SetText(value string) (err error) {\n\tif value != a.text {\n\t\told := a.text\n\n\t\ta.text = value\n\n\t\tif err = a.raiseChanged(); err != nil {\n\t\t\ta.text = old\n\t\t\ta.raiseChanged()\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (a *Action) IsSeparator() bool {\n\treturn a.id == 0 || a.text == \"-\"\n}\n\nfunc (a *Action) ToolTip() string {\n\treturn a.toolTip\n}\n\nfunc (a *Action) SetToolTip(value string) (err error) {\n\tif value != a.toolTip {\n\t\told := a.toolTip\n\n\t\ta.toolTip = value\n\n\t\tif err = a.raiseChanged(); err != nil {\n\t\t\ta.toolTip = old\n\t\t\ta.raiseChanged()\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (a *Action) Visible() bool {\n\treturn a.visible\n}\n\nfunc (a *Action) SetVisible(value bool) (err error) {\n\tif a.visibleCondition != nil {\n\t\treturn newError(\"VisibleCondition != nil\")\n\t}\n\n\tif value != a.visible {\n\t\told := a.visible\n\n\t\ta.visible = value\n\n\t\tif err = a.raiseVisibleChanged(); err != nil {\n\t\t\ta.visible = old\n\t\t\ta.raiseVisibleChanged()\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (a *Action) VisibleCondition() Condition {\n\treturn a.visibleCondition\n}\n\nfunc (a *Action) SetVisibleCondition(c Condition) {\n\tif a.visibleCondition != nil {\n\t\ta.visibleCondition.Changed().Detach(a.visibleConditionChangedHandle)\n\t}\n\n\ta.visibleCondition = c\n\n\tif c != nil {\n\t\ta.visible = c.Satisfied()\n\n\t\ta.visibleConditionChangedHandle = c.Changed().Attach(func() {\n\t\t\tif a.visible != c.Satisfied() {\n\t\t\t\ta.visible = !a.visible\n\n\t\t\t\ta.raiseVisibleChanged()\n\t\t\t}\n\t\t})\n\t}\n\n\ta.raiseChanged()\n}\n\nfunc (a *Action) Triggered() *Event {\n\treturn a.triggeredPublisher.Event()\n}\n\nfunc (a *Action) raiseTriggered() {\n\tif a.Checkable() {\n\t\ta.SetChecked(!a.Checked())\n\t}\n\n\ta.triggeredPublisher.Publish()\n}\n\nfunc (a *Action) addChangedHandler(handler actionChangedHandler) {\n\ta.changedHandlers = append(a.changedHandlers, handler)\n}\n\nfunc (a *Action) removeChangedHandler(handler actionChangedHandler) {\n\tfor i, h := range a.changedHandlers {\n\t\tif h == handler {\n\t\t\ta.changedHandlers = append(a.changedHandlers[:i], a.changedHandlers[i+1:]...)\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc (a *Action) raiseChanged() error {\n\tfor _, handler := range a.changedHandlers {\n\t\tif err := handler.onActionChanged(a); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (a *Action) raiseVisibleChanged() error {\n\tfor _, handler := range a.changedHandlers {\n\t\tif err := handler.onActionVisibleChanged(a); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "actionlist.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype actionListObserver interface {\n\tonInsertedAction(action *Action) error\n\tonRemovingAction(action *Action) error\n\tonClearingActions() error\n}\n\ntype nopActionListObserver struct{}\n\nfunc (nopActionListObserver) onInsertedAction(action *Action) error {\n\treturn nil\n}\n\nfunc (nopActionListObserver) onRemovingAction(action *Action) error {\n\treturn nil\n}\n\nfunc (nopActionListObserver) onClearingActions() error {\n\treturn nil\n}\n\ntype ActionList struct {\n\tactions  []*Action\n\tobserver actionListObserver\n}\n\nfunc newActionList(observer actionListObserver) *ActionList {\n\tif observer == nil {\n\t\tpanic(\"observer == nil\")\n\t}\n\n\treturn &ActionList{observer: observer}\n}\n\nfunc (l *ActionList) Add(action *Action) error {\n\treturn l.Insert(len(l.actions), action)\n}\n\nfunc (l *ActionList) AddMenu(menu *Menu) (*Action, error) {\n\treturn l.InsertMenu(len(l.actions), menu)\n}\n\nfunc (l *ActionList) At(index int) *Action {\n\treturn l.actions[index]\n}\n\nfunc (l *ActionList) Clear() error {\n\tif err := l.observer.onClearingActions(); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, a := range l.actions {\n\t\ta.release()\n\t}\n\n\tl.actions = l.actions[:0]\n\n\treturn nil\n}\n\nfunc (l *ActionList) Contains(action *Action) bool {\n\treturn l.Index(action) > -1\n}\n\nfunc (l *ActionList) Index(action *Action) int {\n\tfor i, a := range l.actions {\n\t\tif a == action {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (l *ActionList) indexInObserver(action *Action) int {\n\tvar idx int\n\n\tfor _, a := range l.actions {\n\t\tif a == action {\n\t\t\treturn idx\n\t\t}\n\t\tif a.Visible() {\n\t\t\tidx++\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (l *ActionList) Insert(index int, action *Action) error {\n\tl.actions = append(l.actions, nil)\n\tcopy(l.actions[index+1:], l.actions[index:])\n\tl.actions[index] = action\n\n\tif err := l.observer.onInsertedAction(action); err != nil {\n\t\tl.actions = append(l.actions[:index], l.actions[index+1:]...)\n\n\t\treturn err\n\t}\n\n\taction.addRef()\n\n\tif action.Visible() {\n\t\treturn l.updateSeparatorVisibility()\n\t}\n\n\treturn nil\n}\n\nfunc (l *ActionList) InsertMenu(index int, menu *Menu) (*Action, error) {\n\taction := NewAction()\n\taction.menu = menu\n\n\tif err := l.Insert(index, action); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn action, nil\n}\n\nfunc (l *ActionList) Len() int {\n\treturn len(l.actions)\n}\n\nfunc (l *ActionList) Remove(action *Action) error {\n\tindex := l.Index(action)\n\tif index == -1 {\n\t\treturn nil\n\t}\n\n\treturn l.RemoveAt(index)\n}\n\nfunc (l *ActionList) RemoveAt(index int) error {\n\taction := l.actions[index]\n\tif action.Visible() {\n\t\tif err := l.observer.onRemovingAction(action); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\taction.release()\n\n\tl.actions = append(l.actions[:index], l.actions[index+1:]...)\n\n\tif action.Visible() {\n\t\treturn l.updateSeparatorVisibility()\n\t}\n\n\treturn nil\n}\n\nfunc (l *ActionList) updateSeparatorVisibility() error {\n\tvar hasCurVisAct bool\n\tvar curVisSep *Action\n\n\tfor _, a := range l.actions {\n\t\tif visible := a.Visible(); a.IsSeparator() {\n\t\t\ttoggle := visible != hasCurVisAct\n\n\t\t\tif toggle {\n\t\t\t\tvisible = !visible\n\t\t\t\tif err := a.SetVisible(visible); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif visible {\n\t\t\t\tcurVisSep = a\n\t\t\t}\n\n\t\t\thasCurVisAct = false\n\t\t} else if visible {\n\t\t\thasCurVisAct = true\n\t\t}\n\t}\n\n\tif !hasCurVisAct && curVisSep != nil {\n\t\treturn curVisSep.SetVisible(false)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "application.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype Settings interface {\n\tGet(key string) (string, bool)\n\tTimestamp(key string) (time.Time, bool)\n\tPut(key, value string) error\n\tPutExpiring(key, value string) error\n\tRemove(key string) error\n\tExpireDuration() time.Duration\n\tSetExpireDuration(expireDuration time.Duration)\n\tLoad() error\n\tSave() error\n}\n\ntype Persistable interface {\n\tPersistent() bool\n\tSetPersistent(value bool)\n\tSaveState() error\n\tRestoreState() error\n}\n\ntype Application struct {\n\tmutex              sync.RWMutex\n\torganizationName   string\n\tproductName        string\n\tsettings           Settings\n\texiting            bool\n\texitCode           int\n\tpanickingPublisher ErrorEventPublisher\n}\n\nvar appSingleton *Application = new(Application)\n\nfunc App() *Application {\n\treturn appSingleton\n}\n\nfunc (app *Application) OrganizationName() string {\n\tapp.mutex.RLock()\n\tdefer app.mutex.RUnlock()\n\treturn app.organizationName\n}\n\nfunc (app *Application) SetOrganizationName(value string) {\n\tapp.mutex.Lock()\n\tdefer app.mutex.Unlock()\n\tapp.organizationName = value\n}\n\nfunc (app *Application) ProductName() string {\n\tapp.mutex.RLock()\n\tdefer app.mutex.RUnlock()\n\treturn app.productName\n}\n\nfunc (app *Application) SetProductName(value string) {\n\tapp.mutex.Lock()\n\tdefer app.mutex.Unlock()\n\tapp.productName = value\n}\n\nfunc (app *Application) Settings() Settings {\n\tapp.mutex.RLock()\n\tdefer app.mutex.RUnlock()\n\treturn app.settings\n}\n\nfunc (app *Application) SetSettings(value Settings) {\n\tapp.mutex.Lock()\n\tdefer app.mutex.Unlock()\n\tapp.settings = value\n}\n\nfunc (app *Application) Exit(exitCode int) {\n\tapp.mutex.Lock()\n\tdefer app.mutex.Unlock()\n\tapp.exiting = true\n\tapp.exitCode = exitCode\n\twin.PostQuitMessage(int32(exitCode))\n}\n\nfunc (app *Application) ExitCode() int {\n\tapp.mutex.RLock()\n\tdefer app.mutex.RUnlock()\n\treturn app.exitCode\n}\n\nfunc (app *Application) Panicking() *ErrorEvent {\n\tapp.mutex.RLock()\n\tdefer app.mutex.RUnlock()\n\treturn app.panickingPublisher.Event()\n}\n\n// ActiveForm returns the currently active form for the caller's thread.\n// It returns nil if no form is active or the caller's thread does not\n// have any windows associated with it. It should be called from within\n// synchronized functions.\nfunc (app *Application) ActiveForm() Form {\n\truntime.LockOSThread()\n\tdefer runtime.UnlockOSThread()\n\ttid := win.GetCurrentThreadId()\n\tgroup := wgm.Group(tid)\n\tif group == nil {\n\t\treturn nil\n\t}\n\treturn group.ActiveForm()\n}\n"
  },
  {
    "path": "bitmap.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"image\"\n\t\"image/color\"\n\t\"math\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst inchesPerMeter float64 = 39.37007874\n\ntype Bitmap struct {\n\thBmp               win.HBITMAP\n\thPackedDIB         win.HGLOBAL\n\tsize               Size // in native pixels\n\tdpi                int\n\ttransparencyStatus transparencyStatus\n}\n\ntype transparencyStatus byte\n\nconst (\n\ttransparencyUnknown transparencyStatus = iota\n\ttransparencyOpaque\n\ttransparencyTransparent\n)\n\nfunc BitmapFrom(src interface{}, dpi int) (*Bitmap, error) {\n\tif src == nil {\n\t\treturn nil, nil\n\t}\n\n\timg, err := ImageFrom(src)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn iconCache.Bitmap(img, dpi)\n}\n\n// NewBitmap creates an opaque bitmap with given size in 1/96\" units at screen DPI.\n//\n// Deprecated: Newer applications should use NewBitmapForDPI.\nfunc NewBitmap(size Size) (*Bitmap, error) {\n\tdpi := screenDPI()\n\treturn newBitmap(SizeFrom96DPI(size, dpi), false, dpi)\n}\n\n// NewBitmapForDPI creates an opaque bitmap with given size in native pixels and DPI.\nfunc NewBitmapForDPI(size Size, dpi int) (*Bitmap, error) {\n\treturn newBitmap(size, false, dpi)\n}\n\n// NewBitmapWithTransparentPixels creates a transparent bitmap with given size in 1/96\" units at screen DPI.\n//\n// Deprecated: Newer applications should use NewBitmapWithTransparentPixelsForDPI.\nfunc NewBitmapWithTransparentPixels(size Size) (*Bitmap, error) {\n\tdpi := screenDPI()\n\treturn newBitmap(SizeFrom96DPI(size, dpi), true, dpi)\n}\n\n// NewBitmapWithTransparentPixelsForDPI creates a transparent bitmap with given size in native pixels and DPI.\nfunc NewBitmapWithTransparentPixelsForDPI(size Size, dpi int) (*Bitmap, error) {\n\treturn newBitmap(size, true, dpi)\n}\n\n// newBitmap creates a bitmap with given size in native pixels and DPI.\nfunc newBitmap(size Size, transparent bool, dpi int) (bmp *Bitmap, err error) {\n\terr = withCompatibleDC(func(hdc win.HDC) error {\n\t\tbufSize := int(size.Width * size.Height * 4)\n\n\t\tvar hdr win.BITMAPINFOHEADER\n\t\thdr.BiSize = uint32(unsafe.Sizeof(hdr))\n\t\thdr.BiBitCount = 32\n\t\thdr.BiCompression = win.BI_RGB\n\t\thdr.BiPlanes = 1\n\t\thdr.BiWidth = int32(size.Width)\n\t\thdr.BiHeight = int32(size.Height)\n\t\thdr.BiSizeImage = uint32(bufSize)\n\t\tdpm := int32(math.Round(float64(dpi) * inchesPerMeter))\n\t\thdr.BiXPelsPerMeter = dpm\n\t\thdr.BiYPelsPerMeter = dpm\n\n\t\tvar bitsPtr unsafe.Pointer\n\n\t\thBmp := win.CreateDIBSection(hdc, &hdr, win.DIB_RGB_COLORS, &bitsPtr, 0, 0)\n\t\tswitch hBmp {\n\t\tcase 0, win.ERROR_INVALID_PARAMETER:\n\t\t\treturn newError(\"CreateDIBSection failed\")\n\t\t}\n\n\t\tif transparent {\n\t\t\twin.GdiFlush()\n\n\t\t\tbits := (*[1 << 24]byte)(bitsPtr)\n\n\t\t\tfor i := 0; i < bufSize; i += 4 {\n\t\t\t\t// Mark pixel as not drawn to by GDI.\n\t\t\t\tbits[i+3] = 0x01\n\t\t\t}\n\t\t}\n\n\t\tbmp, err = newBitmapFromHBITMAP(hBmp, dpi)\n\t\treturn err\n\t})\n\n\treturn\n}\n\n// NewBitmapFromFile creates new bitmap from a bitmap file at 96dpi.\n//\n// Deprecated: Newer applications should use NewBitmapFromFileForDPI.\nfunc NewBitmapFromFile(filePath string) (*Bitmap, error) {\n\treturn NewBitmapFromFileForDPI(filePath, 96)\n}\n\n// NewBitmapFromFileForDPI creates new bitmap from a bitmap file at given DPI.\nfunc NewBitmapFromFileForDPI(filePath string, dpi int) (*Bitmap, error) {\n\tvar si win.GdiplusStartupInput\n\tsi.GdiplusVersion = 1\n\tif status := win.GdiplusStartup(&si, nil); status != win.Ok {\n\t\treturn nil, newError(fmt.Sprintf(\"GdiplusStartup failed with status '%s'\", status))\n\t}\n\tdefer win.GdiplusShutdown()\n\n\tvar gpBmp *win.GpBitmap\n\tif status := win.GdipCreateBitmapFromFile(syscall.StringToUTF16Ptr(filePath), &gpBmp); status != win.Ok {\n\t\treturn nil, newError(fmt.Sprintf(\"GdipCreateBitmapFromFile failed with status '%s' for file '%s'\", status, filePath))\n\t}\n\tdefer win.GdipDisposeImage((*win.GpImage)(gpBmp))\n\n\tvar hBmp win.HBITMAP\n\tif status := win.GdipCreateHBITMAPFromBitmap(gpBmp, &hBmp, 0); status != win.Ok {\n\t\treturn nil, newError(fmt.Sprintf(\"GdipCreateHBITMAPFromBitmap failed with status '%s' for file '%s'\", status, filePath))\n\t}\n\n\treturn newBitmapFromHBITMAP(hBmp, dpi)\n}\n\n// NewBitmapFromImage creates a Bitmap from image.Image at 96dpi.\n//\n// Deprecated: Newer applications should use NewBitmapFromImageForDPI.\nfunc NewBitmapFromImage(im image.Image) (*Bitmap, error) {\n\treturn NewBitmapFromImageForDPI(im, 96)\n}\n\n// NewBitmapFromImageForDPI creates a Bitmap from image.Image at given DPI.\nfunc NewBitmapFromImageForDPI(im image.Image, dpi int) (*Bitmap, error) {\n\thBmp, err := hBitmapFromImage(im, dpi)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn newBitmapFromHBITMAP(hBmp, dpi)\n}\n\n// NewBitmapFromResource creates a Bitmap at 96dpi from resource by name.\n//\n// Deprecated: Newer applications should use NewBitmapFromResourceForDPI.\nfunc NewBitmapFromResource(name string) (*Bitmap, error) {\n\treturn newBitmapFromResource(syscall.StringToUTF16Ptr(name), 96)\n}\n\n// NewBitmapFromResourceForDPI creates a Bitmap at given DPI from resource by name.\nfunc NewBitmapFromResourceForDPI(name string, dpi int) (*Bitmap, error) {\n\treturn newBitmapFromResource(syscall.StringToUTF16Ptr(name), dpi)\n}\n\n// NewBitmapFromResourceId creates a Bitmap at 96dpi from resource by ID.\n//\n// Deprecated: Newer applications should use NewBitmapFromResourceIdForDPI.\nfunc NewBitmapFromResourceId(id int) (*Bitmap, error) {\n\treturn newBitmapFromResource(win.MAKEINTRESOURCE(uintptr(id)), 96)\n}\n\n// NewBitmapFromResourceIdForDPI creates a Bitmap at given DPI from resource by ID.\nfunc NewBitmapFromResourceIdForDPI(id int, dpi int) (*Bitmap, error) {\n\treturn newBitmapFromResource(win.MAKEINTRESOURCE(uintptr(id)), dpi)\n}\n\nfunc newBitmapFromResource(res *uint16, dpi int) (bm *Bitmap, err error) {\n\thInst := win.GetModuleHandle(nil)\n\tif hInst == 0 {\n\t\terr = lastError(\"GetModuleHandle\")\n\t\treturn\n\t}\n\n\tif hBmp := win.LoadImage(hInst, res, win.IMAGE_BITMAP, 0, 0, win.LR_CREATEDIBSECTION); hBmp == 0 {\n\t\terr = lastError(\"LoadImage\")\n\t} else {\n\t\tbm, err = newBitmapFromHBITMAP(win.HBITMAP(hBmp), dpi)\n\t}\n\n\treturn\n}\n\n// NewBitmapFromImageWithSize creates a bitmap with given size in native units and paints the image on it streched.\nfunc NewBitmapFromImageWithSize(image Image, size Size) (*Bitmap, error) {\n\tvar disposables Disposables\n\tdefer disposables.Treat()\n\n\tdpi := int(math.Round(float64(size.Width) / float64(image.Size().Width) * 96.0))\n\tbmp, err := NewBitmapWithTransparentPixelsForDPI(size, dpi)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdisposables.Add(bmp)\n\n\tcanvas, err := NewCanvasFromImage(bmp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer canvas.Dispose()\n\n\tcanvas.dpi = dpi\n\n\tif err := canvas.DrawImageStretchedPixels(image, Rectangle{0, 0, size.Width, size.Height}); err != nil {\n\t\treturn nil, err\n\t}\n\n\tdisposables.Spare()\n\n\treturn bmp, nil\n}\n\nfunc NewBitmapFromWindow(window Window) (*Bitmap, error) {\n\thBmp, err := hBitmapFromWindow(window)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn newBitmapFromHBITMAP(hBmp, window.DPI())\n}\n\n// NewBitmapFromIcon creates a new bitmap with given size in native pixels and 96dpi and paints the\n// icon on it.\n//\n// Deprecated: Newer applications should use NewBitmapFromIconForDPI.\nfunc NewBitmapFromIcon(icon *Icon, size Size) (*Bitmap, error) {\n\treturn NewBitmapFromIconForDPI(icon, size, 96)\n}\n\n// NewBitmapFromIconForDPI creates a new bitmap with given size in native pixels and DPI and paints\n// the icon on it.\nfunc NewBitmapFromIconForDPI(icon *Icon, size Size, dpi int) (*Bitmap, error) {\n\thBmp, err := hBitmapFromIcon(icon, size, dpi)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn newBitmapFromHBITMAP(hBmp, dpi)\n}\n\nfunc (bmp *Bitmap) ToImage() (*image.RGBA, error) {\n\tvar bi win.BITMAPINFO\n\tbi.BmiHeader.BiSize = uint32(unsafe.Sizeof(bi.BmiHeader))\n\thdc := win.GetDC(0)\n\tif ret := win.GetDIBits(hdc, bmp.hBmp, 0, 0, nil, &bi, win.DIB_RGB_COLORS); ret == 0 {\n\t\treturn nil, newError(\"GetDIBits get bitmapinfo failed\")\n\t}\n\n\tbuf := make([]byte, bi.BmiHeader.BiSizeImage)\n\tbi.BmiHeader.BiCompression = win.BI_RGB\n\tif ret := win.GetDIBits(hdc, bmp.hBmp, 0, uint32(bi.BmiHeader.BiHeight), &buf[0], &bi, win.DIB_RGB_COLORS); ret == 0 {\n\t\treturn nil, newError(\"GetDIBits failed\")\n\t}\n\n\twidth := int(bi.BmiHeader.BiWidth)\n\theight := int(bi.BmiHeader.BiHeight)\n\timg := image.NewRGBA(image.Rect(0, 0, width, height))\n\n\tn := 0\n\tfor y := 0; y < height; y++ {\n\t\tfor x := 0; x < width; x++ {\n\t\t\ta := buf[n+3]\n\t\t\tr := buf[n+2]\n\t\t\tg := buf[n+1]\n\t\t\tb := buf[n+0]\n\t\t\tn += int(bi.BmiHeader.BiBitCount) / 8\n\t\t\timg.Set(x, height-y-1, color.RGBA{r, g, b, a})\n\t\t}\n\t}\n\n\treturn img, nil\n}\n\nfunc (bmp *Bitmap) hasTransparency() (bool, error) {\n\tif bmp.transparencyStatus == transparencyUnknown {\n\t\tif err := bmp.withPixels(func(bi *win.BITMAPINFO, hdc win.HDC, pixels *[maxPixels]bgraPixel, pixelsLen int) error {\n\t\t\tfor i := 0; i < pixelsLen; i++ {\n\t\t\t\tif pixels[i].A == 0x00 {\n\t\t\t\t\tbmp.transparencyStatus = transparencyTransparent\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tif bmp.transparencyStatus == transparencyUnknown {\n\t\t\tbmp.transparencyStatus = transparencyOpaque\n\t\t}\n\t}\n\n\treturn bmp.transparencyStatus == transparencyTransparent, nil\n}\n\nfunc (bmp *Bitmap) postProcess() error {\n\treturn bmp.withPixels(func(bi *win.BITMAPINFO, hdc win.HDC, pixels *[maxPixels]bgraPixel, pixelsLen int) error {\n\t\tfor i := 0; i < pixelsLen; i++ {\n\t\t\tswitch pixels[i].A {\n\t\t\tcase 0x00:\n\t\t\t\t// The pixel has been drawn to by GDI, so we make it fully opaque.\n\t\t\t\tpixels[i].A = 0xff\n\n\t\t\tcase 0x01:\n\t\t\t\t// The pixel has not been drawn to by GDI, so we make it fully transparent.\n\t\t\t\tpixels[i].A = 0x00\n\t\t\t\tbmp.transparencyStatus = transparencyTransparent\n\t\t\t}\n\t\t}\n\n\t\tif 0 == win.SetDIBits(hdc, bmp.hBmp, 0, uint32(bi.BmiHeader.BiHeight), &pixels[0].B, bi, win.DIB_RGB_COLORS) {\n\t\t\treturn newError(\"SetDIBits\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\ntype bgraPixel struct {\n\tB byte\n\tG byte\n\tR byte\n\tA byte\n}\n\nconst maxPixels = 2 << 27\n\nfunc (bmp *Bitmap) withPixels(f func(bi *win.BITMAPINFO, hdc win.HDC, pixels *[maxPixels]bgraPixel, pixelsLen int) error) error {\n\tvar bi win.BITMAPINFO\n\tbi.BmiHeader.BiSize = uint32(unsafe.Sizeof(bi.BmiHeader))\n\n\thdc := win.GetDC(0)\n\tif hdc == 0 {\n\t\treturn newError(\"GetDC\")\n\t}\n\tdefer win.ReleaseDC(0, hdc)\n\n\tif ret := win.GetDIBits(hdc, bmp.hBmp, 0, 0, nil, &bi, win.DIB_RGB_COLORS); ret == 0 {\n\t\treturn newError(\"GetDIBits #1\")\n\t}\n\n\thPixels := win.GlobalAlloc(win.GMEM_FIXED, uintptr(bi.BmiHeader.BiSizeImage))\n\tdefer win.GlobalFree(hPixels)\n\n\tpixels := (*[maxPixels]bgraPixel)(unsafe.Pointer(uintptr(hPixels)))\n\n\tbi.BmiHeader.BiCompression = win.BI_RGB\n\tif ret := win.GetDIBits(hdc, bmp.hBmp, 0, uint32(bi.BmiHeader.BiHeight), &pixels[0].B, &bi, win.DIB_RGB_COLORS); ret == 0 {\n\t\treturn newError(\"GetDIBits #2\")\n\t}\n\n\twin.GdiFlush()\n\n\treturn f(&bi, hdc, pixels, int(bi.BmiHeader.BiSizeImage)/4)\n}\n\nfunc (bmp *Bitmap) Dispose() {\n\tif bmp.hBmp != 0 {\n\t\twin.DeleteObject(win.HGDIOBJ(bmp.hBmp))\n\n\t\twin.GlobalUnlock(bmp.hPackedDIB)\n\t\twin.GlobalFree(bmp.hPackedDIB)\n\n\t\tbmp.hPackedDIB = 0\n\t\tbmp.hBmp = 0\n\t}\n}\n\n// Size returns bitmap size in 1/96\" units.\nfunc (bmp *Bitmap) Size() Size {\n\treturn SizeTo96DPI(bmp.size, bmp.dpi)\n}\n\nfunc (bmp *Bitmap) handle() win.HBITMAP {\n\treturn bmp.hBmp\n}\n\nfunc (bmp *Bitmap) draw(hdc win.HDC, location Point) error {\n\treturn bmp.drawStretched(hdc, Rectangle{X: location.X, Y: location.Y, Width: bmp.size.Width, Height: bmp.size.Height})\n}\n\nfunc (bmp *Bitmap) drawStretched(hdc win.HDC, bounds Rectangle) error {\n\treturn bmp.alphaBlend(hdc, bounds, 255)\n}\n\n// alphaBlend displays bitmaps that have transparent or semitransparent pixels. bounds is represented in native pixels.\nfunc (bmp *Bitmap) alphaBlend(hdc win.HDC, bounds Rectangle, opacity byte) error {\n\treturn bmp.alphaBlendPart(hdc, bounds, Rectangle{0, 0, bmp.size.Width, bmp.size.Height}, opacity)\n}\n\n// alphaBlendPart displays bitmaps that have transparent or semitransparent pixels. dst and src are\n// represented in native pixels.\nfunc (bmp *Bitmap) alphaBlendPart(hdc win.HDC, dst, src Rectangle, opacity byte) error {\n\treturn bmp.withSelectedIntoMemDC(func(hdcMem win.HDC) error {\n\t\tif opacity == 255 && (dst.Width != src.Width || dst.Height != src.Height) {\n\t\t\ttransparent, err := bmp.hasTransparency()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif !transparent {\n\t\t\t\tif 0 == win.SetStretchBltMode(hdc, win.HALFTONE) {\n\t\t\t\t\treturn newError(\"SetStretchBltMode\")\n\t\t\t\t}\n\n\t\t\t\tif !win.StretchBlt(\n\t\t\t\t\thdc,\n\t\t\t\t\tint32(dst.X),\n\t\t\t\t\tint32(dst.Y),\n\t\t\t\t\tint32(dst.Width),\n\t\t\t\t\tint32(dst.Height),\n\t\t\t\t\thdcMem,\n\t\t\t\t\tint32(src.X),\n\t\t\t\t\tint32(src.Y),\n\t\t\t\t\tint32(src.Width),\n\t\t\t\t\tint32(src.Height),\n\t\t\t\t\twin.SRCCOPY,\n\t\t\t\t) {\n\t\t\t\t\treturn newError(\"StretchBlt failed\")\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\tif !win.AlphaBlend(\n\t\t\thdc,\n\t\t\tint32(dst.X),\n\t\t\tint32(dst.Y),\n\t\t\tint32(dst.Width),\n\t\t\tint32(dst.Height),\n\t\t\thdcMem,\n\t\t\tint32(src.X),\n\t\t\tint32(src.Y),\n\t\t\tint32(src.Width),\n\t\t\tint32(src.Height),\n\t\t\twin.BLENDFUNCTION{AlphaFormat: win.AC_SRC_ALPHA, SourceConstantAlpha: opacity},\n\t\t) {\n\t\t\treturn newError(\"AlphaBlend failed\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\nfunc (bmp *Bitmap) withSelectedIntoMemDC(f func(hdcMem win.HDC) error) error {\n\treturn withCompatibleDC(func(hdcMem win.HDC) error {\n\t\thBmpOld := win.SelectObject(hdcMem, win.HGDIOBJ(bmp.hBmp))\n\t\tif hBmpOld == 0 {\n\t\t\treturn newError(\"SelectObject failed\")\n\t\t}\n\t\tdefer win.SelectObject(hdcMem, hBmpOld)\n\n\t\treturn f(hdcMem)\n\t})\n}\n\n// newBitmapFromHBITMAP creates Bitmap from win.HBITMAP.\n//\n// The BiXPelsPerMeter and BiYPelsPerMeter fields of win.BITMAPINFOHEADER are unreliable (for\n// loaded PNG they are both unset). Therefore, we require caller to specify DPI explicitly.\nfunc newBitmapFromHBITMAP(hBmp win.HBITMAP, dpi int) (bmp *Bitmap, err error) {\n\tvar dib win.DIBSECTION\n\tif win.GetObject(win.HGDIOBJ(hBmp), unsafe.Sizeof(dib), unsafe.Pointer(&dib)) == 0 {\n\t\treturn nil, newError(\"GetObject failed\")\n\t}\n\n\tbmih := &dib.DsBmih\n\n\tbmihSize := uintptr(unsafe.Sizeof(*bmih))\n\tpixelsSize := uintptr(int32(bmih.BiBitCount)*bmih.BiWidth*bmih.BiHeight) / 8\n\n\ttotalSize := uintptr(bmihSize + pixelsSize)\n\n\thPackedDIB := win.GlobalAlloc(win.GHND, totalSize)\n\tdest := win.GlobalLock(hPackedDIB)\n\tdefer win.GlobalUnlock(hPackedDIB)\n\n\tsrc := unsafe.Pointer(&dib.DsBmih)\n\n\twin.MoveMemory(dest, src, bmihSize)\n\n\tdest = unsafe.Pointer(uintptr(dest) + bmihSize)\n\tsrc = dib.DsBm.BmBits\n\n\twin.MoveMemory(dest, src, pixelsSize)\n\n\treturn &Bitmap{\n\t\thBmp:       hBmp,\n\t\thPackedDIB: hPackedDIB,\n\t\tsize: Size{\n\t\t\tint(bmih.BiWidth),\n\t\t\tint(bmih.BiHeight),\n\t\t},\n\t\tdpi: dpi,\n\t}, nil\n}\n\nfunc hBitmapFromImage(im image.Image, dpi int) (win.HBITMAP, error) {\n\tvar bi win.BITMAPV5HEADER\n\tbi.BiSize = uint32(unsafe.Sizeof(bi))\n\tbi.BiWidth = int32(im.Bounds().Dx())\n\tbi.BiHeight = -int32(im.Bounds().Dy())\n\tbi.BiPlanes = 1\n\tbi.BiBitCount = 32\n\tbi.BiCompression = win.BI_BITFIELDS\n\tdpm := int32(math.Round(float64(dpi) * inchesPerMeter))\n\tbi.BiXPelsPerMeter = dpm\n\tbi.BiYPelsPerMeter = dpm\n\t// The following mask specification specifies a supported 32 BPP\n\t// alpha format for Windows XP.\n\tbi.BV4RedMask = 0x00FF0000\n\tbi.BV4GreenMask = 0x0000FF00\n\tbi.BV4BlueMask = 0x000000FF\n\tbi.BV4AlphaMask = 0xFF000000\n\n\thdc := win.GetDC(0)\n\tdefer win.ReleaseDC(0, hdc)\n\n\tvar lpBits unsafe.Pointer\n\n\t// Create the DIB section with an alpha channel.\n\thBitmap := win.CreateDIBSection(hdc, &bi.BITMAPINFOHEADER, win.DIB_RGB_COLORS, &lpBits, 0, 0)\n\tswitch hBitmap {\n\tcase 0, win.ERROR_INVALID_PARAMETER:\n\t\treturn 0, newError(\"CreateDIBSection failed\")\n\t}\n\n\t// Fill the image\n\tbitmap_array := (*[1 << 30]byte)(unsafe.Pointer(lpBits))\n\ti := 0\n\tfor y := im.Bounds().Min.Y; y != im.Bounds().Max.Y; y++ {\n\t\tfor x := im.Bounds().Min.X; x != im.Bounds().Max.X; x++ {\n\t\t\tr, g, b, a := im.At(x, y).RGBA()\n\t\t\tbitmap_array[i+3] = byte(a >> 8)\n\t\t\tbitmap_array[i+2] = byte(r >> 8)\n\t\t\tbitmap_array[i+1] = byte(g >> 8)\n\t\t\tbitmap_array[i+0] = byte(b >> 8)\n\t\t\ti += 4\n\t\t}\n\t}\n\n\treturn hBitmap, nil\n}\n\nfunc hBitmapFromWindow(window Window) (win.HBITMAP, error) {\n\thdcMem := win.CreateCompatibleDC(0)\n\tif hdcMem == 0 {\n\t\treturn 0, newError(\"CreateCompatibleDC failed\")\n\t}\n\tdefer win.DeleteDC(hdcMem)\n\n\tvar r win.RECT\n\tif !win.GetWindowRect(window.Handle(), &r) {\n\t\treturn 0, newError(\"GetWindowRect failed\")\n\t}\n\n\thdc := win.GetDC(window.Handle())\n\twidth, height := r.Right-r.Left, r.Bottom-r.Top\n\thBmp := win.CreateCompatibleBitmap(hdc, width, height)\n\twin.ReleaseDC(window.Handle(), hdc)\n\n\thOld := win.SelectObject(hdcMem, win.HGDIOBJ(hBmp))\n\tflags := win.PRF_CHILDREN | win.PRF_CLIENT | win.PRF_ERASEBKGND | win.PRF_NONCLIENT | win.PRF_OWNED\n\twindow.SendMessage(win.WM_PRINT, uintptr(hdcMem), uintptr(flags))\n\n\twin.SelectObject(hdcMem, hOld)\n\n\treturn hBmp, nil\n}\n\n// hBitmapFromIcon creates a new win.HBITMAP with given size in native pixels and DPI, and paints\n// the icon on it stretched.\nfunc hBitmapFromIcon(icon *Icon, size Size, dpi int) (win.HBITMAP, error) {\n\thdc := win.GetDC(0)\n\tdefer win.ReleaseDC(0, hdc)\n\n\thdcMem := win.CreateCompatibleDC(hdc)\n\tif hdcMem == 0 {\n\t\treturn 0, newError(\"CreateCompatibleDC failed\")\n\t}\n\tdefer win.DeleteDC(hdcMem)\n\n\tvar bi win.BITMAPV5HEADER\n\tbi.BiSize = uint32(unsafe.Sizeof(bi))\n\tbi.BiWidth = int32(size.Width)\n\tbi.BiHeight = int32(size.Height)\n\tbi.BiPlanes = 1\n\tbi.BiBitCount = 32\n\tbi.BiCompression = win.BI_RGB\n\tdpm := int32(math.Round(float64(dpi) * inchesPerMeter))\n\tbi.BiXPelsPerMeter = dpm\n\tbi.BiYPelsPerMeter = dpm\n\t// The following mask specification specifies a supported 32 BPP\n\t// alpha format for Windows XP.\n\tbi.BV4RedMask = 0x00FF0000\n\tbi.BV4GreenMask = 0x0000FF00\n\tbi.BV4BlueMask = 0x000000FF\n\tbi.BV4AlphaMask = 0xFF000000\n\n\thBmp := win.CreateDIBSection(hdcMem, &bi.BITMAPINFOHEADER, win.DIB_RGB_COLORS, nil, 0, 0)\n\tswitch hBmp {\n\tcase 0, win.ERROR_INVALID_PARAMETER:\n\t\treturn 0, newError(\"CreateDIBSection failed\")\n\t}\n\n\thOld := win.SelectObject(hdcMem, win.HGDIOBJ(hBmp))\n\tdefer win.SelectObject(hdcMem, hOld)\n\n\terr := icon.drawStretched(hdcMem, Rectangle{Width: size.Width, Height: size.Height})\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn hBmp, nil\n}\n\nfunc withCompatibleDC(f func(hdc win.HDC) error) error {\n\thdc := win.CreateCompatibleDC(0)\n\tif hdc == 0 {\n\t\treturn newError(\"CreateCompatibleDC failed\")\n\t}\n\tdefer win.DeleteDC(hdc)\n\n\treturn f(hdc)\n}\n"
  },
  {
    "path": "boxlayout.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"math\"\n\t\"sort\"\n\t\"sync\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype Orientation byte\n\nconst (\n\tNoOrientation Orientation = 0\n\tHorizontal                = 1 << 0\n\tVertical                  = 1 << 1\n)\n\ntype BoxLayout struct {\n\tLayoutBase\n\torientation        Orientation\n\thwnd2StretchFactor map[win.HWND]int\n}\n\nfunc newBoxLayout(orientation Orientation) *BoxLayout {\n\tl := &BoxLayout{\n\t\tLayoutBase: LayoutBase{\n\t\t\tmargins96dpi: Margins{9, 9, 9, 9},\n\t\t\tspacing96dpi: 6,\n\t\t},\n\t\torientation:        orientation,\n\t\thwnd2StretchFactor: make(map[win.HWND]int),\n\t}\n\tl.layout = l\n\n\treturn l\n}\n\nfunc NewHBoxLayout() *BoxLayout {\n\treturn newBoxLayout(Horizontal)\n}\n\nfunc NewVBoxLayout() *BoxLayout {\n\treturn newBoxLayout(Vertical)\n}\n\nfunc (l *BoxLayout) Orientation() Orientation {\n\treturn l.orientation\n}\n\nfunc (l *BoxLayout) SetOrientation(value Orientation) error {\n\tif value != l.orientation {\n\t\tswitch value {\n\t\tcase Horizontal, Vertical:\n\n\t\tdefault:\n\t\t\treturn newError(\"invalid Orientation value\")\n\t\t}\n\n\t\tl.orientation = value\n\n\t\tl.container.RequestLayout()\n\t}\n\n\treturn nil\n}\n\nfunc (l *BoxLayout) StretchFactor(widget Widget) int {\n\tif factor, ok := l.hwnd2StretchFactor[widget.Handle()]; ok {\n\t\treturn factor\n\t}\n\n\treturn 1\n}\n\nfunc (l *BoxLayout) SetStretchFactor(widget Widget, factor int) error {\n\tif factor != l.StretchFactor(widget) {\n\t\tif l.container == nil {\n\t\t\treturn newError(\"container required\")\n\t\t}\n\n\t\thandle := widget.Handle()\n\n\t\tif !l.container.Children().containsHandle(handle) {\n\t\t\treturn newError(\"unknown widget\")\n\t\t}\n\t\tif factor < 1 {\n\t\t\treturn newError(\"factor must be >= 1\")\n\t\t}\n\n\t\tl.hwnd2StretchFactor[handle] = factor\n\n\t\tl.container.RequestLayout()\n\t}\n\n\treturn nil\n}\n\nfunc (l *BoxLayout) CreateLayoutItem(ctx *LayoutContext) ContainerLayoutItem {\n\tli := &boxLayoutItem{\n\t\tsize2MinSize:       make(map[Size]Size),\n\t\torientation:        l.orientation,\n\t\thwnd2StretchFactor: make(map[win.HWND]int),\n\t}\n\n\tfor hwnd, sf := range l.hwnd2StretchFactor {\n\t\tli.hwnd2StretchFactor[hwnd] = sf\n\t}\n\n\treturn li\n}\n\ntype boxLayoutItemInfo struct {\n\titem     LayoutItem\n\tindex    int\n\tprefSize int // in native pixels\n\tminSize  int // in native pixels\n\tmaxSize  int // in native pixels\n\tstretch  int\n\tgreedy   bool\n}\n\ntype boxLayoutItemInfoList []boxLayoutItemInfo\n\nfunc (l boxLayoutItemInfoList) Len() int {\n\treturn len(l)\n}\n\nfunc (l boxLayoutItemInfoList) Less(i, j int) bool {\n\t_, iIsSpacer := l[i].item.(*spacerLayoutItem)\n\t_, jIsSpacer := l[j].item.(*spacerLayoutItem)\n\n\tif l[i].greedy == l[j].greedy {\n\t\tif iIsSpacer == jIsSpacer {\n\t\t\tminDiff := l[i].minSize - l[j].minSize\n\n\t\t\tif minDiff == 0 {\n\t\t\t\treturn l[i].maxSize/l[i].stretch < l[j].maxSize/l[j].stretch\n\t\t\t}\n\n\t\t\treturn minDiff > 0\n\t\t}\n\n\t\treturn jIsSpacer\n\t}\n\n\treturn l[i].greedy\n}\n\nfunc (l boxLayoutItemInfoList) Swap(i, j int) {\n\tl[i], l[j] = l[j], l[i]\n}\n\ntype boxLayoutItem struct {\n\tContainerLayoutItemBase\n\tmutex              sync.Mutex\n\tsize2MinSize       map[Size]Size // in native pixels\n\torientation        Orientation\n\thwnd2StretchFactor map[win.HWND]int\n}\n\nfunc (li *boxLayoutItem) LayoutFlags() LayoutFlags {\n\treturn boxLayoutFlags(li.orientation, li.children)\n}\n\nfunc (li *boxLayoutItem) IdealSize() Size {\n\treturn li.MinSize()\n}\n\nfunc (li *boxLayoutItem) MinSize() Size {\n\treturn li.MinSizeForSize(li.geometry.ClientSize)\n}\n\nfunc (li *boxLayoutItem) HeightForWidth(width int) int {\n\treturn li.MinSizeForSize(Size{width, li.geometry.ClientSize.Height}).Height\n}\n\nfunc (li *boxLayoutItem) MinSizeForSize(size Size) Size {\n\tli.mutex.Lock()\n\tdefer li.mutex.Unlock()\n\n\tif min, ok := li.size2MinSize[size]; ok {\n\t\treturn min\n\t}\n\n\tbounds := Rectangle{Width: size.Width, Height: size.Height}\n\n\titems := boxLayoutItems(li, itemsToLayout(li.children), li.orientation, li.alignment, bounds, li.margins96dpi, li.spacing96dpi, li.hwnd2StretchFactor)\n\n\tmargins := MarginsFrom96DPI(li.margins96dpi, li.ctx.dpi)\n\tspacing := IntFrom96DPI(li.spacing96dpi, li.ctx.dpi)\n\ts := Size{margins.HNear + margins.HFar, margins.VNear + margins.VFar}\n\n\tvar maxSecondary int\n\tfor _, item := range items {\n\t\tmin := li.MinSizeEffectiveForChild(item.Item)\n\n\t\tif hfw, ok := item.Item.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\t\titem.Bounds.Height = hfw.HeightForWidth(item.Bounds.Width)\n\t\t} else {\n\t\t\titem.Bounds.Height = min.Height\n\t\t}\n\t\titem.Bounds.Width = min.Width\n\n\t\tif li.orientation == Horizontal {\n\t\t\tmaxSecondary = maxi(maxSecondary, item.Bounds.Height)\n\n\t\t\ts.Width += item.Bounds.Width\n\t\t} else {\n\t\t\tmaxSecondary = maxi(maxSecondary, item.Bounds.Width)\n\n\t\t\ts.Height += item.Bounds.Height\n\t\t}\n\t}\n\n\tif li.orientation == Horizontal {\n\t\ts.Width += (len(items) - 1) * spacing\n\t\ts.Height += maxSecondary\n\t} else {\n\t\ts.Height += (len(items) - 1) * spacing\n\t\ts.Width += maxSecondary\n\t}\n\n\tif s.Width > 0 && s.Height > 0 {\n\t\tli.size2MinSize[size] = s\n\t}\n\n\treturn s\n}\n\nfunc (li *boxLayoutItem) PerformLayout() []LayoutResultItem {\n\tcb := Rectangle{Width: li.geometry.ClientSize.Width, Height: li.geometry.ClientSize.Height}\n\treturn boxLayoutItems(li, itemsToLayout(li.children), li.orientation, li.alignment, cb, li.margins96dpi, li.spacing96dpi, li.hwnd2StretchFactor)\n}\n\nfunc boxLayoutFlags(orientation Orientation, children []LayoutItem) LayoutFlags {\n\tif len(children) == 0 {\n\t\treturn ShrinkableHorz | ShrinkableVert | GrowableHorz | GrowableVert\n\t}\n\n\tvar flags LayoutFlags\n\tfor i := 0; i < len(children); i++ {\n\t\titem := children[i]\n\n\t\tif _, ok := item.(*splitterHandleLayoutItem); ok || !shouldLayoutItem(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif s, ok := item.(*spacerLayoutItem); ok {\n\t\t\tif s.greedyLocallyOnly {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tf := item.LayoutFlags()\n\t\tflags |= f\n\t}\n\n\treturn flags\n}\n\n// boxLayoutItems lays out items. bounds parameter is in native pixels.\nfunc boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientation Orientation, alignment Alignment2D, bounds Rectangle, margins96dpi Margins, spacing96dpi int, hwnd2StretchFactor map[win.HWND]int) []LayoutResultItem {\n\tif len(items) == 0 {\n\t\treturn nil\n\t}\n\n\tdpi := container.Context().dpi\n\tmargins := MarginsFrom96DPI(margins96dpi, dpi)\n\tspacing := IntFrom96DPI(spacing96dpi, dpi)\n\n\tvar greedyNonSpacerCount int\n\tvar greedySpacerCount int\n\tvar stretchFactorsTotal [3]int\n\tstretchFactors := make([]int, len(items))\n\tvar minSizesRemaining int\n\tminSizes := make([]int, len(items))\n\tmaxSizes := make([]int, len(items))\n\tsizes := make([]int, len(items))\n\tprefSizes2 := make([]int, len(items))\n\tvar shrinkableAmount1Total int\n\tshrinkableAmount1 := make([]int, len(items))\n\tshrinkable2 := make([]bool, len(items))\n\tgrowable2 := make([]bool, len(items))\n\tsortedItemInfo := boxLayoutItemInfoList(make([]boxLayoutItemInfo, len(items)))\n\n\tfor i, item := range items {\n\t\tsf := hwnd2StretchFactor[item.Handle()]\n\t\tif sf == 0 {\n\t\t\tsf = 1\n\t\t}\n\t\tstretchFactors[i] = sf\n\n\t\tgeometry := item.Geometry()\n\n\t\tflags := item.LayoutFlags()\n\n\t\tmax := geometry.MaxSize\n\t\tvar pref Size\n\t\tif hfw, ok := item.(HeightForWidther); !ok || !hfw.HasHeightForWidth() {\n\t\t\tif is, ok := item.(IdealSizer); ok {\n\t\t\t\tpref = is.IdealSize()\n\t\t\t}\n\t\t}\n\n\t\tif orientation == Horizontal {\n\t\t\tgrowable2[i] = flags&GrowableVert > 0\n\n\t\t\tminSizes[i] = container.MinSizeEffectiveForChild(item).Width\n\n\t\t\tif max.Width > 0 {\n\t\t\t\tmaxSizes[i] = max.Width\n\t\t\t} else if pref.Width > 0 && flags&GrowableHorz == 0 {\n\t\t\t\tmaxSizes[i] = pref.Width\n\t\t\t} else {\n\t\t\t\tmaxSizes[i] = 32768\n\t\t\t}\n\n\t\t\tprefSizes2[i] = pref.Height\n\n\t\t\tsortedItemInfo[i].prefSize = pref.Width\n\t\t\tsortedItemInfo[i].greedy = flags&GreedyHorz > 0\n\t\t} else {\n\t\t\tgrowable2[i] = flags&GrowableHorz > 0\n\n\t\t\tif hfw, ok := item.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\t\t\tminSizes[i] = hfw.HeightForWidth(bounds.Width - margins.HNear - margins.HFar)\n\t\t\t} else {\n\t\t\t\tminSizes[i] = container.MinSizeEffectiveForChild(item).Height\n\t\t\t}\n\n\t\t\tif max.Height > 0 {\n\t\t\t\tmaxSizes[i] = max.Height\n\t\t\t} else if hfw, ok := item.(HeightForWidther); ok && flags&GrowableVert == 0 && hfw.HasHeightForWidth() {\n\t\t\t\tmaxSizes[i] = minSizes[i]\n\t\t\t} else if pref.Height > 0 && flags&GrowableVert == 0 {\n\t\t\t\tmaxSizes[i] = pref.Height\n\t\t\t} else {\n\t\t\t\tmaxSizes[i] = 32768\n\t\t\t}\n\n\t\t\tprefSizes2[i] = pref.Width\n\n\t\t\tsortedItemInfo[i].prefSize = pref.Height\n\t\t\tsortedItemInfo[i].greedy = flags&GreedyVert > 0\n\t\t}\n\n\t\tsortedItemInfo[i].index = i\n\t\tsortedItemInfo[i].minSize = minSizes[i]\n\t\tsortedItemInfo[i].maxSize = maxSizes[i]\n\t\tsortedItemInfo[i].stretch = sf\n\t\tsortedItemInfo[i].item = item\n\n\t\tif orientation == Horizontal && flags&(ShrinkableHorz|GrowableHorz|GreedyHorz) == ShrinkableHorz ||\n\t\t\torientation == Vertical && flags&(ShrinkableVert|GrowableVert|GreedyVert) == ShrinkableVert {\n\t\t\tif amount := sortedItemInfo[i].prefSize - minSizes[i]; amount > 0 {\n\t\t\t\tshrinkableAmount1[i] = amount\n\t\t\t\tshrinkableAmount1Total += amount\n\t\t\t}\n\t\t}\n\t\tshrinkable2[i] = orientation == Horizontal && flags&ShrinkableVert != 0 || orientation == Vertical && flags&ShrinkableHorz != 0\n\n\t\tif shrinkableAmount1[i] > 0 {\n\t\t\tminSizesRemaining += sortedItemInfo[i].prefSize\n\t\t} else {\n\t\t\tminSizesRemaining += minSizes[i]\n\t\t}\n\n\t\tif sortedItemInfo[i].greedy {\n\t\t\tif _, isSpacer := item.(*spacerLayoutItem); !isSpacer {\n\t\t\t\tgreedyNonSpacerCount++\n\t\t\t\tstretchFactorsTotal[0] += sf\n\t\t\t} else {\n\t\t\t\tgreedySpacerCount++\n\t\t\t\tstretchFactorsTotal[1] += sf\n\t\t\t}\n\t\t} else {\n\t\t\tstretchFactorsTotal[2] += sf\n\t\t}\n\t}\n\n\tsort.Stable(sortedItemInfo)\n\n\tvar start1, start2, space1, space2 int\n\tif orientation == Horizontal {\n\t\tstart1 = bounds.X + margins.HNear\n\t\tstart2 = bounds.Y + margins.VNear\n\t\tspace1 = bounds.Width - margins.HNear - margins.HFar\n\t\tspace2 = bounds.Height - margins.VNear - margins.VFar\n\t} else {\n\t\tstart1 = bounds.Y + margins.VNear\n\t\tstart2 = bounds.X + margins.HNear\n\t\tspace1 = bounds.Height - margins.VNear - margins.VFar\n\t\tspace2 = bounds.Width - margins.HNear - margins.HFar\n\t}\n\n\tspacingRemaining := spacing * (len(items) - 1)\n\texcess := float64(space1 - minSizesRemaining - spacingRemaining)\n\n\toffsets := [3]int{0, greedyNonSpacerCount, greedyNonSpacerCount + greedySpacerCount}\n\tcounts := [3]int{greedyNonSpacerCount, greedySpacerCount, len(items) - greedyNonSpacerCount - greedySpacerCount}\n\n\tfor i := 0; i < 3; i++ {\n\t\tstretchFactorsRemaining := stretchFactorsTotal[i]\n\n\t\tfor j := 0; j < counts[i]; j++ {\n\t\t\tinfo := sortedItemInfo[offsets[i]+j]\n\t\t\tk := info.index\n\n\t\t\tstretch := stretchFactors[k]\n\t\t\tmin := info.minSize\n\t\t\tmax := info.maxSize\n\t\t\tvar size int\n\t\t\tvar corrected bool\n\t\t\tif shrinkableAmount1[k] > 0 {\n\t\t\t\tsize = info.prefSize\n\t\t\t\tif excess < 0.0 {\n\t\t\t\t\tsize -= mini(shrinkableAmount1[k], int(math.Round(-excess/float64(shrinkableAmount1Total)*float64(shrinkableAmount1[k]))))\n\t\t\t\t\tcorrected = true\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsize = min\n\t\t\t}\n\n\t\t\tif !corrected && min < max {\n\t\t\t\texcessSpace := float64(space1 - minSizesRemaining - spacingRemaining)\n\t\t\t\tsize += int(math.Round(excessSpace * float64(stretch) / float64(stretchFactorsRemaining)))\n\t\t\t\tif size < min {\n\t\t\t\t\tsize = min\n\t\t\t\t} else if size > max {\n\t\t\t\t\tsize = max\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsizes[k] = size\n\n\t\t\tif shrinkableAmount1[k] > 0 {\n\t\t\t\tminSizesRemaining -= info.prefSize\n\t\t\t} else {\n\t\t\t\tminSizesRemaining -= min\n\t\t\t}\n\t\t\tstretchFactorsRemaining -= stretch\n\t\t\tspace1 -= (size + spacing)\n\t\t\tspacingRemaining -= spacing\n\t\t}\n\t}\n\n\tresults := make([]LayoutResultItem, 0, len(items))\n\n\texcessTotal := space1 - minSizesRemaining - spacingRemaining\n\texcessShare := excessTotal / len(items)\n\thalfExcessShare := excessTotal / (len(items) * 2)\n\tp1 := start1\n\tfor i, item := range items {\n\t\ts1 := sizes[i]\n\n\t\tvar s2 int\n\t\tif hfw, ok := item.(HeightForWidther); ok && orientation == Horizontal && hfw.HasHeightForWidth() {\n\t\t\ts2 = hfw.HeightForWidth(s1)\n\t\t} else if shrinkable2[i] || growable2[i] {\n\t\t\ts2 = space2\n\t\t} else {\n\t\t\ts2 = prefSizes2[i]\n\t\t}\n\n\t\talign := item.Geometry().Alignment\n\t\tif align == AlignHVDefault {\n\t\t\talign = alignment\n\t\t}\n\n\t\tvar x, y, w, h, p2 int\n\t\tif orientation == Horizontal {\n\t\t\tswitch align {\n\t\t\tcase AlignHNearVNear, AlignHNearVCenter, AlignHNearVFar:\n\t\t\t\t// nop\n\n\t\t\tcase AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar:\n\t\t\t\tp1 += excessShare\n\n\t\t\tdefault:\n\t\t\t\tp1 += halfExcessShare\n\t\t\t}\n\n\t\t\tswitch align {\n\t\t\tcase AlignHNearVNear, AlignHCenterVNear, AlignHFarVNear:\n\t\t\t\tp2 = start2\n\n\t\t\tcase AlignHNearVFar, AlignHCenterVFar, AlignHFarVFar:\n\t\t\t\tp2 = start2 + space2 - s2\n\n\t\t\tdefault:\n\t\t\t\tp2 = start2 + (space2-s2)/2\n\t\t\t}\n\n\t\t\tx, y, w, h = p1, p2, s1, s2\n\t\t} else {\n\t\t\tswitch align {\n\t\t\tcase AlignHNearVNear, AlignHCenterVNear, AlignHFarVNear:\n\t\t\t\t// nop\n\n\t\t\tcase AlignHNearVFar, AlignHCenterVFar, AlignHFarVFar:\n\t\t\t\tp1 += excessShare\n\n\t\t\tdefault:\n\t\t\t\tp1 += halfExcessShare\n\t\t\t}\n\n\t\t\tswitch align {\n\t\t\tcase AlignHNearVNear, AlignHNearVCenter, AlignHNearVFar:\n\t\t\t\tp2 = start2\n\n\t\t\tcase AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar:\n\t\t\t\tp2 = start2 + space2 - s2\n\n\t\t\tdefault:\n\t\t\t\tp2 = start2 + (space2-s2)/2\n\t\t\t}\n\n\t\t\tx, y, w, h = p2, p1, s2, s1\n\t\t}\n\n\t\tif orientation == Horizontal {\n\t\t\tswitch align {\n\t\t\tcase AlignHNearVNear, AlignHNearVCenter, AlignHNearVFar:\n\t\t\t\tp1 += excessShare\n\n\t\t\tcase AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar:\n\t\t\t\t// nop\n\n\t\t\tdefault:\n\t\t\t\tp1 += halfExcessShare\n\t\t\t}\n\n\t\t} else {\n\t\t\tswitch align {\n\t\t\tcase AlignHNearVNear, AlignHCenterVNear, AlignHFarVNear:\n\t\t\t\tp1 += excessShare\n\n\t\t\tcase AlignHNearVFar, AlignHCenterVFar, AlignHFarVFar:\n\t\t\t\t// nop\n\n\t\t\tdefault:\n\t\t\t\tp1 += halfExcessShare\n\t\t\t}\n\t\t}\n\n\t\tp1 += s1 + spacing\n\n\t\tresults = append(results, LayoutResultItem{Item: item, Bounds: Rectangle{X: x, Y: y, Width: w, Height: h}})\n\t}\n\n\treturn results\n}\n"
  },
  {
    "path": "brush.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype HatchStyle int\n\nconst (\n\tHatchHorizontal       HatchStyle = win.HS_HORIZONTAL\n\tHatchVertical         HatchStyle = win.HS_VERTICAL\n\tHatchForwardDiagonal  HatchStyle = win.HS_FDIAGONAL\n\tHatchBackwardDiagonal HatchStyle = win.HS_BDIAGONAL\n\tHatchCross            HatchStyle = win.HS_CROSS\n\tHatchDiagonalCross    HatchStyle = win.HS_DIAGCROSS\n)\n\ntype SystemColor int\n\nconst (\n\tSysColor3DDkShadow              SystemColor = win.COLOR_3DDKSHADOW\n\tSysColor3DFace                  SystemColor = win.COLOR_3DFACE\n\tSysColor3DHighlight             SystemColor = win.COLOR_3DHIGHLIGHT\n\tSysColor3DLight                 SystemColor = win.COLOR_3DLIGHT\n\tSysColor3DShadow                SystemColor = win.COLOR_3DSHADOW\n\tSysColorActiveBorder            SystemColor = win.COLOR_ACTIVEBORDER\n\tSysColorActiveCaption           SystemColor = win.COLOR_ACTIVECAPTION\n\tSysColorAppWorkspace            SystemColor = win.COLOR_APPWORKSPACE\n\tSysColorBackground              SystemColor = win.COLOR_BACKGROUND\n\tSysColorDesktop                 SystemColor = win.COLOR_DESKTOP\n\tSysColorBtnFace                 SystemColor = win.COLOR_BTNFACE\n\tSysColorBtnHighlight            SystemColor = win.COLOR_BTNHIGHLIGHT\n\tSysColorBtnShadow               SystemColor = win.COLOR_BTNSHADOW\n\tSysColorBtnText                 SystemColor = win.COLOR_BTNTEXT\n\tSysColorCaptionText             SystemColor = win.COLOR_CAPTIONTEXT\n\tSysColorGrayText                SystemColor = win.COLOR_GRAYTEXT\n\tSysColorHighlight               SystemColor = win.COLOR_HIGHLIGHT\n\tSysColorHighlightText           SystemColor = win.COLOR_HIGHLIGHTTEXT\n\tSysColorInactiveBorder          SystemColor = win.COLOR_INACTIVEBORDER\n\tSysColorInactiveCaption         SystemColor = win.COLOR_INACTIVECAPTION\n\tSysColorInactiveCaptionText     SystemColor = win.COLOR_INACTIVECAPTIONTEXT\n\tSysColorInfoBk                  SystemColor = win.COLOR_INFOBK\n\tSysColorInfoText                SystemColor = win.COLOR_INFOTEXT\n\tSysColorMenu                    SystemColor = win.COLOR_MENU\n\tSysColorMenuText                SystemColor = win.COLOR_MENUTEXT\n\tSysColorScrollBar               SystemColor = win.COLOR_SCROLLBAR\n\tSysColorWindow                  SystemColor = win.COLOR_WINDOW\n\tSysColorWindowFrame             SystemColor = win.COLOR_WINDOWFRAME\n\tSysColorWindowText              SystemColor = win.COLOR_WINDOWTEXT\n\tSysColorHotLight                SystemColor = win.COLOR_HOTLIGHT\n\tSysColorGradientActiveCaption   SystemColor = win.COLOR_GRADIENTACTIVECAPTION\n\tSysColorGradientInactiveCaption SystemColor = win.COLOR_GRADIENTINACTIVECAPTION\n)\n\ntype Brush interface {\n\tDispose()\n\thandle() win.HBRUSH\n\tlogbrush() *win.LOGBRUSH\n\tattachWindow(wb *WindowBase)\n\tdetachWindow(wb *WindowBase)\n\tsimple() bool\n}\n\ntype perWindowBrush interface {\n\tBrush\n\tdelegateForWindow(wb *WindowBase) Brush\n}\n\ntype windowBrushInfo struct {\n\tSizeChangedHandle int\n\tDelegate          *BitmapBrush\n}\n\ntype brushBase struct {\n\thBrush  win.HBRUSH\n\twb2info map[*WindowBase]*windowBrushInfo\n}\n\nfunc (bb *brushBase) Dispose() {\n\tif bb.hBrush != 0 {\n\t\twin.DeleteObject(win.HGDIOBJ(bb.hBrush))\n\n\t\tbb.hBrush = 0\n\t}\n}\n\nfunc (bb *brushBase) handle() win.HBRUSH {\n\treturn bb.hBrush\n}\n\nfunc (bb *brushBase) attachWindow(wb *WindowBase) {\n\tif wb == nil {\n\t\treturn\n\t}\n\n\tif bb.wb2info == nil {\n\t\tbb.wb2info = make(map[*WindowBase]*windowBrushInfo)\n\t}\n\n\tbb.wb2info[wb] = nil\n}\n\nfunc (bb *brushBase) detachWindow(wb *WindowBase) {\n\tif bb.wb2info == nil || wb == nil {\n\t\treturn\n\t}\n\n\tdelete(bb.wb2info, wb)\n\n\tif len(bb.wb2info) == 0 {\n\t\tbb.Dispose()\n\t}\n}\n\ntype nullBrush struct {\n\tbrushBase\n}\n\nfunc newNullBrush() *nullBrush {\n\tlb := &win.LOGBRUSH{LbStyle: win.BS_NULL}\n\n\thBrush := win.CreateBrushIndirect(lb)\n\tif hBrush == 0 {\n\t\tpanic(\"failed to create null brush\")\n\t}\n\n\treturn &nullBrush{brushBase: brushBase{hBrush: hBrush}}\n}\n\nfunc (b *nullBrush) Dispose() {\n\tif b == nullBrushSingleton {\n\t\treturn\n\t}\n\n\tb.brushBase.Dispose()\n}\n\nfunc (*nullBrush) logbrush() *win.LOGBRUSH {\n\treturn &win.LOGBRUSH{LbStyle: win.BS_NULL}\n}\n\nfunc (*nullBrush) simple() bool {\n\treturn true\n}\n\nvar (\n\tnullBrushSingleton   Brush\n\tsysColorBtnFaceBrush *SystemColorBrush\n)\n\nfunc NullBrush() Brush {\n\treturn nullBrushSingleton\n}\n\ntype SystemColorBrush struct {\n\tbrushBase\n\tsysColor SystemColor\n}\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tnullBrushSingleton = newNullBrush()\n\t\tsysColorBtnFaceBrush, _ = NewSystemColorBrush(SysColorBtnFace)\n\t})\n}\n\nfunc NewSystemColorBrush(sysColor SystemColor) (*SystemColorBrush, error) {\n\thBrush := win.GetSysColorBrush(int(sysColor))\n\tif hBrush == 0 {\n\t\treturn nil, newError(\"GetSysColorBrush failed\")\n\t}\n\n\treturn &SystemColorBrush{brushBase: brushBase{hBrush: hBrush}, sysColor: sysColor}, nil\n}\n\nfunc (b *SystemColorBrush) Color() Color {\n\treturn Color(win.GetSysColor(int(b.sysColor)))\n}\n\nfunc (b *SystemColorBrush) SystemColor() SystemColor {\n\treturn b.sysColor\n}\n\nfunc (*SystemColorBrush) Dispose() {\n\t// nop\n}\n\nfunc (b *SystemColorBrush) logbrush() *win.LOGBRUSH {\n\treturn &win.LOGBRUSH{\n\t\tLbStyle: win.BS_SOLID,\n\t\tLbColor: win.COLORREF(win.GetSysColor(int(b.sysColor))),\n\t}\n}\n\nfunc (*SystemColorBrush) simple() bool {\n\treturn true\n}\n\ntype SolidColorBrush struct {\n\tbrushBase\n\tcolor Color\n}\n\nfunc NewSolidColorBrush(color Color) (*SolidColorBrush, error) {\n\tlb := &win.LOGBRUSH{LbStyle: win.BS_SOLID, LbColor: win.COLORREF(color)}\n\n\thBrush := win.CreateBrushIndirect(lb)\n\tif hBrush == 0 {\n\t\treturn nil, newError(\"CreateBrushIndirect failed\")\n\t}\n\n\treturn &SolidColorBrush{brushBase: brushBase{hBrush: hBrush}, color: color}, nil\n}\n\nfunc (b *SolidColorBrush) Color() Color {\n\treturn b.color\n}\n\nfunc (b *SolidColorBrush) logbrush() *win.LOGBRUSH {\n\treturn &win.LOGBRUSH{LbStyle: win.BS_SOLID, LbColor: win.COLORREF(b.color)}\n}\n\nfunc (*SolidColorBrush) simple() bool {\n\treturn true\n}\n\ntype HatchBrush struct {\n\tbrushBase\n\tcolor Color\n\tstyle HatchStyle\n}\n\nfunc NewHatchBrush(color Color, style HatchStyle) (*HatchBrush, error) {\n\tlb := &win.LOGBRUSH{LbStyle: win.BS_HATCHED, LbColor: win.COLORREF(color), LbHatch: uintptr(style)}\n\n\thBrush := win.CreateBrushIndirect(lb)\n\tif hBrush == 0 {\n\t\treturn nil, newError(\"CreateBrushIndirect failed\")\n\t}\n\n\treturn &HatchBrush{brushBase: brushBase{hBrush: hBrush}, color: color, style: style}, nil\n}\n\nfunc (b *HatchBrush) Color() Color {\n\treturn b.color\n}\n\nfunc (b *HatchBrush) logbrush() *win.LOGBRUSH {\n\treturn &win.LOGBRUSH{LbStyle: win.BS_HATCHED, LbColor: win.COLORREF(b.color), LbHatch: uintptr(b.style)}\n}\n\nfunc (b *HatchBrush) Style() HatchStyle {\n\treturn b.style\n}\n\nfunc (b *HatchBrush) simple() bool {\n\treturn false\n}\n\ntype BitmapBrush struct {\n\tbrushBase\n\tbitmap *Bitmap\n}\n\nfunc NewBitmapBrush(bitmap *Bitmap) (*BitmapBrush, error) {\n\tif bitmap == nil {\n\t\treturn nil, newError(\"bitmap cannot be nil\")\n\t}\n\n\thBrush := win.CreatePatternBrush(bitmap.hBmp)\n\tif hBrush == 0 {\n\t\treturn nil, newError(\"CreatePatternBrush failed\")\n\t}\n\n\treturn &BitmapBrush{brushBase: brushBase{hBrush: hBrush}, bitmap: bitmap}, nil\n}\n\nfunc (b *BitmapBrush) logbrush() *win.LOGBRUSH {\n\treturn &win.LOGBRUSH{LbStyle: win.BS_DIBPATTERN, LbColor: win.DIB_RGB_COLORS, LbHatch: uintptr(b.bitmap.hPackedDIB)}\n}\n\nfunc (b *BitmapBrush) Bitmap() *Bitmap {\n\treturn b.bitmap\n}\n\nfunc (b *BitmapBrush) simple() bool {\n\treturn false\n}\n\ntype GradientStop struct {\n\tOffset float64\n\tColor  Color\n}\n\ntype GradientVertex struct {\n\tX     float64\n\tY     float64\n\tColor Color\n}\n\ntype GradientTriangle struct {\n\tVertex1 int\n\tVertex2 int\n\tVertex3 int\n}\n\ntype GradientBrush struct {\n\tbrushBase\n\tmainDelegate *BitmapBrush\n\tvertexes     []GradientVertex\n\ttriangles    []GradientTriangle\n\torientation  gradientOrientation\n\tabsolute     bool\n}\n\ntype gradientOrientation int\n\nconst (\n\tgradientOrientationNone gradientOrientation = iota\n\tgradientOrientationHorizontal\n\tgradientOrientationVertical\n)\n\nfunc NewHorizontalGradientBrush(stops []GradientStop) (*GradientBrush, error) {\n\treturn newGradientBrushWithOrientation(stops, gradientOrientationHorizontal)\n}\n\nfunc NewVerticalGradientBrush(stops []GradientStop) (*GradientBrush, error) {\n\treturn newGradientBrushWithOrientation(stops, gradientOrientationVertical)\n}\n\nfunc newGradientBrushWithOrientation(stops []GradientStop, orientation gradientOrientation) (*GradientBrush, error) {\n\tif len(stops) < 2 {\n\t\treturn nil, newError(\"at least 2 stops are required\")\n\t}\n\n\tvar vertexes []GradientVertex\n\tvar triangles []GradientTriangle\n\n\tfor i, stop := range stops {\n\t\tvar x0, y0, x1, y1 float64\n\t\tif orientation == gradientOrientationHorizontal {\n\t\t\tx0 = stop.Offset\n\t\t\tx1 = stop.Offset\n\t\t\ty1 = 1.0\n\t\t} else {\n\t\t\ty0 = stop.Offset\n\t\t\tx1 = 1.0\n\t\t\ty1 = stop.Offset\n\t\t}\n\n\t\tvertexes = append(vertexes, GradientVertex{X: x0, Y: y0, Color: stop.Color})\n\t\tvertexes = append(vertexes, GradientVertex{X: x1, Y: y1, Color: stop.Color})\n\n\t\tif i > 0 {\n\t\t\ttriangles = append(triangles, GradientTriangle{Vertex1: i*2 - 2, Vertex2: i*2 + 1, Vertex3: i*2 - 1})\n\t\t\ttriangles = append(triangles, GradientTriangle{Vertex1: i*2 - 2, Vertex2: i * 2, Vertex3: i*2 + 1})\n\t\t}\n\t}\n\n\treturn newGradientBrush(vertexes, triangles, orientation)\n}\n\nfunc NewGradientBrush(vertexes []GradientVertex, triangles []GradientTriangle) (*GradientBrush, error) {\n\tif len(vertexes) < 3 {\n\t\treturn nil, newError(\"at least 3 vertexes are required\")\n\t}\n\n\tif len(triangles) < 1 {\n\t\treturn nil, newError(\"at least 1 triangle is required\")\n\t}\n\n\treturn newGradientBrush(vertexes, triangles, gradientOrientationNone)\n}\n\nfunc newGradientBrush(vertexes []GradientVertex, triangles []GradientTriangle, orientation gradientOrientation) (*GradientBrush, error) {\n\tvar size Size\n\tfor _, v := range vertexes {\n\t\tsize = maxSize(size, Size{int(v.X), int(v.Y)})\n\t}\n\n\tgb := &GradientBrush{vertexes: vertexes, triangles: triangles, orientation: orientation, absolute: size.Width > 1 || size.Height > 1}\n\n\tif gb.absolute {\n\t\tbb, err := gb.create(size)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tgb.mainDelegate = bb\n\t\tgb.hBrush = bb.hBrush\n\t}\n\n\treturn gb, nil\n}\n\nfunc (b *GradientBrush) logbrush() *win.LOGBRUSH {\n\tif b.mainDelegate == nil {\n\t\treturn nil\n\t}\n\n\treturn b.mainDelegate.logbrush()\n}\n\nfunc (*GradientBrush) simple() bool {\n\treturn false\n}\n\n// create creates a gradient brush at given size in native pixels.\nfunc (b *GradientBrush) create(size Size) (*BitmapBrush, error) {\n\tvar disposables Disposables\n\tdefer disposables.Treat()\n\n\tswitch b.orientation {\n\tcase gradientOrientationHorizontal:\n\t\tsize.Height = 1\n\n\tcase gradientOrientationVertical:\n\t\tsize.Width = 1\n\t}\n\n\tbitmap, err := NewBitmapForDPI(size, 96) // Size is in native pixels and bitmap is used for brush only => DPI is not used anywhere.\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdisposables.Add(bitmap)\n\n\tcanvas, err := NewCanvasFromImage(bitmap)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer canvas.Dispose()\n\n\tvar scaleX, scaleY float64\n\tif b.absolute {\n\t\tscaleX, scaleY = 1, 1\n\t} else {\n\t\tscaleX, scaleY = float64(size.Width), float64(size.Height)\n\t}\n\n\tvertexes := make([]win.TRIVERTEX, len(b.vertexes))\n\tfor i, src := range b.vertexes {\n\t\tdst := &vertexes[i]\n\n\t\tdst.X = int32(src.X * scaleX)\n\t\tdst.Y = int32(src.Y * scaleY)\n\t\tdst.Red = uint16(src.Color.R()) * 256\n\t\tdst.Green = uint16(src.Color.G()) * 256\n\t\tdst.Blue = uint16(src.Color.B()) * 256\n\t}\n\n\ttriangles := make([]win.GRADIENT_TRIANGLE, len(b.triangles))\n\tfor i, src := range b.triangles {\n\t\tdst := &triangles[i]\n\n\t\tdst.Vertex1 = uint32(src.Vertex1)\n\t\tdst.Vertex2 = uint32(src.Vertex2)\n\t\tdst.Vertex3 = uint32(src.Vertex3)\n\t}\n\n\tif !win.GradientFill(canvas.hdc, &vertexes[0], uint32(len(vertexes)), unsafe.Pointer(&triangles[0]), uint32(len(triangles)), win.GRADIENT_FILL_TRIANGLE) {\n\t\treturn nil, newError(\"GradientFill failed\")\n\t}\n\n\tdisposables.Spare()\n\n\treturn NewBitmapBrush(bitmap)\n}\n\nfunc (b *GradientBrush) attachWindow(wb *WindowBase) {\n\tb.brushBase.attachWindow(wb)\n\n\tif b.absolute {\n\t\treturn\n\t}\n\n\tvar info *windowBrushInfo\n\n\tupdate := func() {\n\t\tif bb, err := b.create(wb.window.ClientBoundsPixels().Size()); err == nil {\n\t\t\tif info.Delegate != nil {\n\t\t\t\tinfo.Delegate.bitmap.Dispose()\n\t\t\t\tinfo.Delegate.Dispose()\n\t\t\t}\n\n\t\t\tinfo.Delegate = bb\n\n\t\t\twb.Invalidate()\n\t\t}\n\t}\n\n\tinfo = &windowBrushInfo{\n\t\tSizeChangedHandle: wb.SizeChanged().Attach(update),\n\t}\n\n\tupdate()\n\n\tb.wb2info[wb] = info\n}\n\nfunc (b *GradientBrush) detachWindow(wb *WindowBase) {\n\tif !b.absolute {\n\t\tif info, ok := b.wb2info[wb]; ok {\n\t\t\tif info.Delegate != nil {\n\t\t\t\tinfo.Delegate.bitmap.Dispose()\n\t\t\t\tinfo.Delegate.Dispose()\n\t\t\t}\n\n\t\t\twb.SizeChanged().Detach(info.SizeChangedHandle)\n\t\t}\n\t}\n\n\tb.brushBase.detachWindow(wb)\n}\n\nfunc (b *GradientBrush) delegateForWindow(wb *WindowBase) Brush {\n\tif b.absolute {\n\t\treturn b.mainDelegate\n\t}\n\n\tif info, ok := b.wb2info[wb]; ok && info.Delegate != nil {\n\t\treturn info.Delegate\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "button.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype clickable interface {\n\traiseClicked()\n}\n\ntype setCheckeder interface {\n\tsetChecked(checked bool)\n}\n\ntype Button struct {\n\tWidgetBase\n\tcheckedChangedPublisher EventPublisher\n\tclickedPublisher        EventPublisher\n\ttextChangedPublisher    EventPublisher\n\timageChangedPublisher   EventPublisher\n\timage                   Image\n\tpersistent              bool\n}\n\nfunc (b *Button) init() {\n\tb.MustRegisterProperty(\"Checked\", NewBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn b.Checked()\n\t\t},\n\t\tfunc(v bool) error {\n\t\t\tb.SetChecked(v)\n\t\t\treturn nil\n\t\t},\n\t\tb.CheckedChanged()))\n\n\tb.MustRegisterProperty(\"Image\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn b.Image()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\timg, err := ImageFrom(v)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tb.SetImage(img)\n\n\t\t\treturn nil\n\t\t},\n\t\tb.imageChangedPublisher.Event()))\n\n\tb.MustRegisterProperty(\"Text\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn b.Text()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn b.SetText(assertStringOr(v, \"\"))\n\t\t},\n\t\tb.textChangedPublisher.Event()))\n}\n\nfunc (b *Button) ApplyDPI(dpi int) {\n\tb.WidgetBase.ApplyDPI(dpi)\n\n\tb.SetImage(b.image)\n}\n\nfunc (b *Button) Image() Image {\n\treturn b.image\n}\n\nfunc (b *Button) SetImage(image Image) error {\n\tvar typ, handle uintptr\n\tswitch img := image.(type) {\n\tcase nil:\n\n\tcase *Bitmap:\n\t\ttyp = win.IMAGE_BITMAP\n\t\thandle = uintptr(img.hBmp)\n\n\tcase *Icon:\n\t\ttyp = win.IMAGE_ICON\n\t\thandle = uintptr(img.handleForDPI(b.DPI()))\n\n\tdefault:\n\t\tbmp, err := iconCache.Bitmap(image, b.DPI())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttyp = win.IMAGE_BITMAP\n\t\thandle = uintptr(bmp.hBmp)\n\t}\n\n\tb.SendMessage(win.BM_SETIMAGE, typ, handle)\n\n\tb.image = image\n\n\tb.RequestLayout()\n\n\tb.imageChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (b *Button) ImageChanged() *Event {\n\treturn b.imageChangedPublisher.Event()\n}\n\nfunc (b *Button) Text() string {\n\treturn b.text()\n}\n\nfunc (b *Button) SetText(value string) error {\n\tif value == b.Text() {\n\t\treturn nil\n\t}\n\n\tif err := b.setText(value); err != nil {\n\t\treturn err\n\t}\n\n\tb.RequestLayout()\n\n\treturn nil\n}\n\nfunc (b *Button) Checked() bool {\n\treturn b.SendMessage(win.BM_GETCHECK, 0, 0) == win.BST_CHECKED\n}\n\nfunc (b *Button) SetChecked(checked bool) {\n\tif checked == b.Checked() {\n\t\treturn\n\t}\n\n\tb.window.(setCheckeder).setChecked(checked)\n}\n\nfunc (b *Button) setChecked(checked bool) {\n\tvar chk uintptr\n\n\tif checked {\n\t\tchk = win.BST_CHECKED\n\t} else {\n\t\tchk = win.BST_UNCHECKED\n\t}\n\n\tb.SendMessage(win.BM_SETCHECK, chk, 0)\n\n\tb.checkedChangedPublisher.Publish()\n}\n\nfunc (b *Button) CheckedChanged() *Event {\n\treturn b.checkedChangedPublisher.Event()\n}\n\nfunc (b *Button) Persistent() bool {\n\treturn b.persistent\n}\n\nfunc (b *Button) SetPersistent(value bool) {\n\tb.persistent = value\n}\n\nfunc (b *Button) SaveState() error {\n\treturn b.WriteState(fmt.Sprintf(\"%t\", b.Checked()))\n}\n\nfunc (b *Button) RestoreState() error {\n\ts, err := b.ReadState()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tb.SetChecked(s == \"true\")\n\n\treturn nil\n}\n\nfunc (b *Button) Clicked() *Event {\n\treturn b.clickedPublisher.Event()\n}\n\nfunc (b *Button) raiseClicked() {\n\tb.clickedPublisher.Publish()\n}\n\nfunc (b *Button) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_COMMAND:\n\t\thiWP := win.HIWORD(uint32(wParam))\n\n\t\tif hiWP == 0 && lParam == 0 {\n\t\t\tif a, ok := actionsById[win.LOWORD(uint32(wParam))]; ok {\n\t\t\t\ta.raiseTriggered()\n\t\t\t}\n\t\t} else {\n\t\t\tswitch hiWP {\n\t\t\tcase win.BN_CLICKED:\n\t\t\t\tb.raiseClicked()\n\t\t\t}\n\t\t}\n\n\tcase win.WM_SETTEXT:\n\t\tb.textChangedPublisher.Publish()\n\t}\n\n\treturn b.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\n// idealSize returns ideal button size in native pixels.\nfunc (b *Button) idealSize() Size {\n\tmin := b.dialogBaseUnitsToPixels(Size{50, 14})\n\n\tif b.Text() == \"\" {\n\t\treturn min\n\t}\n\n\tvar s win.SIZE\n\tb.SendMessage(win.BCM_GETIDEALSIZE, 0, uintptr(unsafe.Pointer(&s)))\n\n\treturn maxSize(sizeFromSIZE(s), min)\n}\n\nfunc (b *Button) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn &buttonLayoutItem{\n\t\tidealSize: b.idealSize(),\n\t}\n}\n\ntype buttonLayoutItem struct {\n\tLayoutItemBase\n\tidealSize Size // in native pixels\n}\n\nfunc (li *buttonLayoutItem) LayoutFlags() LayoutFlags {\n\treturn 0\n}\n\nfunc (li *buttonLayoutItem) IdealSize() Size {\n\treturn li.MinSize()\n}\n\nfunc (li *buttonLayoutItem) MinSize() Size {\n\treturn li.idealSize\n}\n"
  },
  {
    "path": "cancelevent.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype cancelEventHandlerInfo struct {\n\thandler CancelEventHandler\n\tonce    bool\n}\n\ntype CancelEventHandler func(canceled *bool)\n\ntype CancelEvent struct {\n\thandlers []cancelEventHandlerInfo\n}\n\nfunc (e *CancelEvent) Attach(handler CancelEventHandler) int {\n\thandlerInfo := cancelEventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *CancelEvent) Detach(handle int) {\n\te.handlers[handle].handler = nil\n}\n\nfunc (e *CancelEvent) Once(handler CancelEventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype CancelEventPublisher struct {\n\tevent CancelEvent\n}\n\nfunc (p *CancelEventPublisher) Event() *CancelEvent {\n\treturn &p.event\n}\n\nfunc (p *CancelEventPublisher) Publish(canceled *bool) {\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler(canceled)\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "canvas.go",
    "content": "// Copyright 2010 The Walk Authorc. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"log\"\n\t\"syscall\"\n\t\"unicode/utf8\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\n// DrawText format flags\ntype DrawTextFormat uint\n\nconst (\n\tTextTop                  DrawTextFormat = win.DT_TOP\n\tTextLeft                 DrawTextFormat = win.DT_LEFT\n\tTextCenter               DrawTextFormat = win.DT_CENTER\n\tTextRight                DrawTextFormat = win.DT_RIGHT\n\tTextVCenter              DrawTextFormat = win.DT_VCENTER\n\tTextBottom               DrawTextFormat = win.DT_BOTTOM\n\tTextWordbreak            DrawTextFormat = win.DT_WORDBREAK\n\tTextSingleLine           DrawTextFormat = win.DT_SINGLELINE\n\tTextExpandTabs           DrawTextFormat = win.DT_EXPANDTABS\n\tTextTabstop              DrawTextFormat = win.DT_TABSTOP\n\tTextNoClip               DrawTextFormat = win.DT_NOCLIP\n\tTextExternalLeading      DrawTextFormat = win.DT_EXTERNALLEADING\n\tTextCalcRect             DrawTextFormat = win.DT_CALCRECT\n\tTextNoPrefix             DrawTextFormat = win.DT_NOPREFIX\n\tTextInternal             DrawTextFormat = win.DT_INTERNAL\n\tTextEditControl          DrawTextFormat = win.DT_EDITCONTROL\n\tTextPathEllipsis         DrawTextFormat = win.DT_PATH_ELLIPSIS\n\tTextEndEllipsis          DrawTextFormat = win.DT_END_ELLIPSIS\n\tTextModifyString         DrawTextFormat = win.DT_MODIFYSTRING\n\tTextRTLReading           DrawTextFormat = win.DT_RTLREADING\n\tTextWordEllipsis         DrawTextFormat = win.DT_WORD_ELLIPSIS\n\tTextNoFullWidthCharBreak DrawTextFormat = win.DT_NOFULLWIDTHCHARBREAK\n\tTextHidePrefix           DrawTextFormat = win.DT_HIDEPREFIX\n\tTextPrefixOnly           DrawTextFormat = win.DT_PREFIXONLY\n)\n\nvar gM *uint16\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tgM = syscall.StringToUTF16Ptr(\"gM\")\n\t})\n}\n\ntype Canvas struct {\n\thdc                 win.HDC\n\thBmpStock           win.HBITMAP\n\twindow              Window\n\tdpi                 int\n\tbitmap              *Bitmap\n\trecordingMetafile   *Metafile\n\tmeasureTextMetafile *Metafile\n\tdoNotDispose        bool\n}\n\nfunc NewCanvasFromImage(image Image) (*Canvas, error) {\n\tswitch img := image.(type) {\n\tcase *Bitmap:\n\t\thdc := win.CreateCompatibleDC(0)\n\t\tif hdc == 0 {\n\t\t\treturn nil, newError(\"CreateCompatibleDC failed\")\n\t\t}\n\t\tsucceeded := false\n\n\t\tdefer func() {\n\t\t\tif !succeeded {\n\t\t\t\twin.DeleteDC(hdc)\n\t\t\t}\n\t\t}()\n\n\t\tvar hBmpStock win.HBITMAP\n\t\tif hBmpStock = win.HBITMAP(win.SelectObject(hdc, win.HGDIOBJ(img.hBmp))); hBmpStock == 0 {\n\t\t\treturn nil, newError(\"SelectObject failed\")\n\t\t}\n\n\t\tsucceeded = true\n\n\t\treturn (&Canvas{hdc: hdc, hBmpStock: hBmpStock, bitmap: img, dpi: img.dpi}).init()\n\n\tcase *Metafile:\n\t\tc, err := newCanvasFromHDC(img.hdc)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tc.recordingMetafile = img\n\n\t\treturn c, nil\n\t}\n\n\treturn nil, newError(\"unsupported image type\")\n}\n\nfunc newCanvasFromWindow(window Window) (*Canvas, error) {\n\thdc := win.GetDC(window.Handle())\n\tif hdc == 0 {\n\t\treturn nil, newError(\"GetDC failed\")\n\t}\n\n\treturn (&Canvas{hdc: hdc, window: window}).init()\n}\n\nfunc newCanvasFromHDC(hdc win.HDC) (*Canvas, error) {\n\tif hdc == 0 {\n\t\treturn nil, newError(\"invalid hdc\")\n\t}\n\n\treturn (&Canvas{hdc: hdc, doNotDispose: true}).init()\n}\n\nfunc (c *Canvas) init() (*Canvas, error) {\n\tif c.dpi == 0 {\n\t\tc.dpi = dpiForHDC(c.hdc)\n\t}\n\n\tif win.SetBkMode(c.hdc, win.TRANSPARENT) == 0 {\n\t\treturn nil, newError(\"SetBkMode failed\")\n\t}\n\n\tswitch win.SetStretchBltMode(c.hdc, win.HALFTONE) {\n\tcase 0, win.ERROR_INVALID_PARAMETER:\n\t\treturn nil, newError(\"SetStretchBltMode failed\")\n\t}\n\n\tif !win.SetBrushOrgEx(c.hdc, 0, 0, nil) {\n\t\treturn nil, newError(\"SetBrushOrgEx failed\")\n\t}\n\n\treturn c, nil\n}\n\nfunc (c *Canvas) Dispose() {\n\tif !c.doNotDispose && c.hdc != 0 {\n\t\tif c.bitmap != nil {\n\t\t\twin.SelectObject(c.hdc, win.HGDIOBJ(c.hBmpStock))\n\t\t\twin.DeleteDC(c.hdc)\n\t\t\tif err := c.bitmap.postProcess(); err != nil {\n\t\t\t\tlog.Printf(\"*Canvas.Dispose - failed to post-process bitmap: %s\", err.Error())\n\t\t\t}\n\t\t} else {\n\t\t\twin.ReleaseDC(c.window.Handle(), c.hdc)\n\t\t}\n\n\t\tc.hdc = 0\n\t}\n\n\tif c.recordingMetafile != nil {\n\t\tc.recordingMetafile.ensureFinished()\n\t\tc.recordingMetafile = nil\n\t}\n\n\tif c.measureTextMetafile != nil {\n\t\tc.measureTextMetafile.Dispose()\n\t\tc.measureTextMetafile = nil\n\t}\n}\n\nfunc (c *Canvas) DPI() int {\n\tif c.window != nil {\n\t\treturn c.window.DPI()\n\t}\n\n\treturn c.dpi\n}\n\nfunc (c *Canvas) withGdiObj(handle win.HGDIOBJ, f func() error) error {\n\toldHandle := win.SelectObject(c.hdc, handle)\n\tif oldHandle == 0 {\n\t\treturn newError(\"SelectObject failed\")\n\t}\n\tdefer win.SelectObject(c.hdc, oldHandle)\n\n\treturn f()\n}\n\nfunc (c *Canvas) withBrush(brush Brush, f func() error) error {\n\treturn c.withGdiObj(win.HGDIOBJ(brush.handle()), f)\n}\n\nfunc (c *Canvas) withFontAndTextColor(font *Font, color Color, f func() error) error {\n\treturn c.withGdiObj(win.HGDIOBJ(font.handleForDPI(c.DPI())), func() error {\n\t\toldColor := win.SetTextColor(c.hdc, win.COLORREF(color))\n\t\tif oldColor == win.CLR_INVALID {\n\t\t\treturn newError(\"SetTextColor failed\")\n\t\t}\n\t\tdefer func() {\n\t\t\twin.SetTextColor(c.hdc, oldColor)\n\t\t}()\n\n\t\treturn f()\n\t})\n}\n\nfunc (c *Canvas) HDC() win.HDC {\n\treturn c.hdc\n}\n\nfunc (c *Canvas) Bounds() Rectangle {\n\treturn RectangleTo96DPI(c.BoundsPixels(), c.DPI())\n}\n\nfunc (c *Canvas) BoundsPixels() Rectangle {\n\treturn Rectangle{\n\t\tWidth:  int(win.GetDeviceCaps(c.hdc, win.HORZRES)),\n\t\tHeight: int(win.GetDeviceCaps(c.hdc, win.VERTRES)),\n\t}\n}\n\nfunc (c *Canvas) withPen(pen Pen, f func() error) error {\n\treturn c.withGdiObj(win.HGDIOBJ(pen.handleForDPI(c.dpi)), f)\n}\n\nfunc (c *Canvas) withBrushAndPen(brush Brush, pen Pen, f func() error) error {\n\treturn c.withBrush(brush, func() error {\n\t\treturn c.withPen(pen, f)\n\t})\n}\n\n// ellipse draws an ellipse in 1/96\" units. sizeCorrection parameter is in native pixels.\n//\n// Deprecated: Newer applications should use ellipsePixels.\nfunc (c *Canvas) ellipse(brush Brush, pen Pen, bounds Rectangle, sizeCorrection int) error {\n\treturn c.ellipsePixels(brush, pen, RectangleFrom96DPI(bounds, c.DPI()), sizeCorrection)\n}\n\n// ellipsePixels draws an ellipse in native pixels.\nfunc (c *Canvas) ellipsePixels(brush Brush, pen Pen, bounds Rectangle, sizeCorrection int) error {\n\treturn c.withBrushAndPen(brush, pen, func() error {\n\t\tif !win.Ellipse(\n\t\t\tc.hdc,\n\t\t\tint32(bounds.X),\n\t\t\tint32(bounds.Y),\n\t\t\tint32(bounds.X+bounds.Width+sizeCorrection),\n\t\t\tint32(bounds.Y+bounds.Height+sizeCorrection)) {\n\n\t\t\treturn newError(\"Ellipse failed\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// DrawEllipse draws an ellipse in 1/96\" units.\n//\n// Deprecated: Newer applications should use DrawEllipsePixels.\nfunc (c *Canvas) DrawEllipse(pen Pen, bounds Rectangle) error {\n\treturn c.ellipse(nullBrushSingleton, pen, bounds, 0)\n}\n\n// DrawEllipsePixels draws an ellipse in native pixels.\nfunc (c *Canvas) DrawEllipsePixels(pen Pen, bounds Rectangle) error {\n\treturn c.ellipsePixels(nullBrushSingleton, pen, bounds, 0)\n}\n\n// FillEllipse draws a filled ellipse in 1/96\" units.\n//\n// Deprecated: Newer applications should use FillEllipsePixels.\nfunc (c *Canvas) FillEllipse(brush Brush, bounds Rectangle) error {\n\treturn c.ellipse(brush, nullPenSingleton, bounds, 1)\n}\n\n// FillEllipsePixels draws a filled in native pixels.\nfunc (c *Canvas) FillEllipsePixels(brush Brush, bounds Rectangle) error {\n\treturn c.ellipsePixels(brush, nullPenSingleton, bounds, 1)\n}\n\n// DrawImage draws image at given location (upper left) in 1/96\" units unstretched.\n//\n// Deprecated: Newer applications should use DrawImagePixels.\nfunc (c *Canvas) DrawImage(image Image, location Point) error {\n\treturn c.DrawImagePixels(image, PointFrom96DPI(location, c.DPI()))\n}\n\n// DrawImagePixels draws image at given location (upper left) in native pixels unstretched.\nfunc (c *Canvas) DrawImagePixels(image Image, location Point) error {\n\tif image == nil {\n\t\treturn newError(\"image cannot be nil\")\n\t}\n\n\treturn image.draw(c.hdc, location)\n}\n\n// DrawImageStretched draws image at given location in 1/96\" units stretched.\n//\n// Deprecated: Newer applications should use DrawImageStretchedPixels.\nfunc (c *Canvas) DrawImageStretched(image Image, bounds Rectangle) error {\n\treturn c.DrawImageStretchedPixels(image, RectangleFrom96DPI(bounds, c.DPI()))\n}\n\n// DrawImageStretchedPixels draws image at given location in native pixels stretched.\nfunc (c *Canvas) DrawImageStretchedPixels(image Image, bounds Rectangle) error {\n\tif image == nil {\n\t\treturn newError(\"image cannot be nil\")\n\t}\n\n\tif dsoc, ok := image.(interface {\n\t\tdrawStretchedOnCanvasPixels(canvas *Canvas, bounds Rectangle) error\n\t}); ok {\n\t\treturn dsoc.drawStretchedOnCanvasPixels(c, bounds)\n\t}\n\n\treturn image.drawStretched(c.hdc, bounds)\n}\n\n// DrawBitmapWithOpacity draws bitmap with opacity at given location in 1/96\" units stretched.\n//\n// Deprecated: Newer applications should use DrawBitmapWithOpacityPixels.\nfunc (c *Canvas) DrawBitmapWithOpacity(bmp *Bitmap, bounds Rectangle, opacity byte) error {\n\treturn c.DrawBitmapWithOpacityPixels(bmp, RectangleFrom96DPI(bounds, c.DPI()), opacity)\n}\n\n// DrawBitmapWithOpacityPixels draws bitmap with opacity at given location in native pixels\n// stretched.\nfunc (c *Canvas) DrawBitmapWithOpacityPixels(bmp *Bitmap, bounds Rectangle, opacity byte) error {\n\tif bmp == nil {\n\t\treturn newError(\"bmp cannot be nil\")\n\t}\n\n\treturn bmp.alphaBlend(c.hdc, bounds, opacity)\n}\n\n// DrawBitmapPart draws bitmap at given location in native pixels.\nfunc (c *Canvas) DrawBitmapPart(bmp *Bitmap, dst, src Rectangle) error {\n\treturn c.DrawBitmapPartWithOpacityPixels(bmp, dst, src, 0xff)\n}\n\n// DrawBitmapPartWithOpacity draws bitmap at given location in 1/96\" units.\n//\n// Deprecated: Newer applications should use DrawBitmapPartWithOpacityPixels.\nfunc (c *Canvas) DrawBitmapPartWithOpacity(bmp *Bitmap, dst, src Rectangle, opacity byte) error {\n\tdpi := c.DPI()\n\treturn c.DrawBitmapPartWithOpacityPixels(bmp, RectangleFrom96DPI(dst, dpi), RectangleFrom96DPI(src, dpi), opacity)\n}\n\n// DrawBitmapPartWithOpacityPixels draws bitmap at given location in native pixels.\nfunc (c *Canvas) DrawBitmapPartWithOpacityPixels(bmp *Bitmap, dst, src Rectangle, opacity byte) error {\n\tif bmp == nil {\n\t\treturn newError(\"bmp cannot be nil\")\n\t}\n\n\treturn bmp.alphaBlendPart(c.hdc, dst, src, opacity)\n}\n\n// DrawLine draws a line between two points in 1/96\" units.\n//\n// Deprecated: Newer applications should use DrawLinePixels.\nfunc (c *Canvas) DrawLine(pen Pen, from, to Point) error {\n\tdpi := c.DPI()\n\treturn c.DrawLinePixels(pen, PointFrom96DPI(from, dpi), PointFrom96DPI(to, dpi))\n}\n\n// DrawLinePixels draws a line between two points in native pixels.\nfunc (c *Canvas) DrawLinePixels(pen Pen, from, to Point) error {\n\tif !win.MoveToEx(c.hdc, int(from.X), int(from.Y), nil) {\n\t\treturn newError(\"MoveToEx failed\")\n\t}\n\n\treturn c.withPen(pen, func() error {\n\t\tif !win.LineTo(c.hdc, int32(to.X), int32(to.Y)) {\n\t\t\treturn newError(\"LineTo failed\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// DrawLine draws a line between given points in 1/96\" units.\n//\n// Deprecated: Newer applications should use DrawLinePixels.\nfunc (c *Canvas) DrawPolyline(pen Pen, points []Point) error {\n\tif len(points) < 1 {\n\t\treturn nil\n\t}\n\n\tdpi := c.DPI()\n\n\tpts := make([]win.POINT, len(points))\n\tfor i, p := range points {\n\t\tpts[i] = PointFrom96DPI(p, dpi).toPOINT()\n\t}\n\n\treturn c.withPen(pen, func() error {\n\t\tif !win.Polyline(c.hdc, unsafe.Pointer(&pts[0].X), int32(len(pts))) {\n\t\t\treturn newError(\"Polyline failed\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// DrawPolylinePixels draws a line between given points in native pixels.\nfunc (c *Canvas) DrawPolylinePixels(pen Pen, points []Point) error {\n\tif len(points) < 1 {\n\t\treturn nil\n\t}\n\n\tpts := make([]win.POINT, len(points))\n\tfor i, p := range points {\n\t\tpts[i] = p.toPOINT()\n\t}\n\n\treturn c.withPen(pen, func() error {\n\t\tif !win.Polyline(c.hdc, unsafe.Pointer(&pts[0].X), int32(len(pts))) {\n\t\t\treturn newError(\"Polyline failed\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// rectangle draws a rectangle in 1/96\" units. sizeCorrection parameter is in native pixels.\n//\n// Deprecated: Newer applications should use rectanglePixels.\nfunc (c *Canvas) rectangle(brush Brush, pen Pen, bounds Rectangle, sizeCorrection int) error {\n\treturn c.rectanglePixels(brush, pen, RectangleFrom96DPI(bounds, c.DPI()), sizeCorrection)\n}\n\n// rectanglePixels draws a rectangle in native pixels.\nfunc (c *Canvas) rectanglePixels(brush Brush, pen Pen, bounds Rectangle, sizeCorrection int) error {\n\treturn c.withBrushAndPen(brush, pen, func() error {\n\t\tif !win.Rectangle_(\n\t\t\tc.hdc,\n\t\t\tint32(bounds.X),\n\t\t\tint32(bounds.Y),\n\t\t\tint32(bounds.X+bounds.Width+sizeCorrection),\n\t\t\tint32(bounds.Y+bounds.Height+sizeCorrection)) {\n\n\t\t\treturn newError(\"Rectangle_ failed\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// DrawRectangle draws a rectangle in 1/96\" units.\n//\n// Deprecated: Newer applications should use DrawRectanglePixels.\nfunc (c *Canvas) DrawRectangle(pen Pen, bounds Rectangle) error {\n\treturn c.rectangle(nullBrushSingleton, pen, bounds, 0)\n}\n\n// DrawRectanglePixels draws a rectangle in native pixels.\nfunc (c *Canvas) DrawRectanglePixels(pen Pen, bounds Rectangle) error {\n\treturn c.rectanglePixels(nullBrushSingleton, pen, bounds, 0)\n}\n\n// FillRectangle draws a filled rectangle in 1/96\" units.\n//\n// Deprecated: Newer applications should use FillRectanglePixels.\nfunc (c *Canvas) FillRectangle(brush Brush, bounds Rectangle) error {\n\treturn c.rectangle(brush, nullPenSingleton, bounds, 1)\n}\n\n// FillRectanglePixels draws a filled rectangle in native pixels.\nfunc (c *Canvas) FillRectanglePixels(brush Brush, bounds Rectangle) error {\n\treturn c.rectanglePixels(brush, nullPenSingleton, bounds, 1)\n}\n\n// roundedRectangle draws a rounded rectangle in 1/96\" units. sizeCorrection parameter is in native\n// pixels.\n//\n// Deprecated: Newer applications should use roundedRectanglePixels.\nfunc (c *Canvas) roundedRectangle(brush Brush, pen Pen, bounds Rectangle, ellipseSize Size, sizeCorrection int) error {\n\tdpi := c.DPI()\n\treturn c.roundedRectanglePixels(brush, pen, RectangleFrom96DPI(bounds, dpi), SizeFrom96DPI(ellipseSize, dpi), sizeCorrection)\n}\n\n// roundedRectanglePixels draws a rounded rectangle in native pixels.\nfunc (c *Canvas) roundedRectanglePixels(brush Brush, pen Pen, bounds Rectangle, ellipseSize Size, sizeCorrection int) error {\n\treturn c.withBrushAndPen(brush, pen, func() error {\n\t\tif !win.RoundRect(\n\t\t\tc.hdc,\n\t\t\tint32(bounds.X),\n\t\t\tint32(bounds.Y),\n\t\t\tint32(bounds.X+bounds.Width+sizeCorrection),\n\t\t\tint32(bounds.Y+bounds.Height+sizeCorrection),\n\t\t\tint32(ellipseSize.Width),\n\t\t\tint32(ellipseSize.Height)) {\n\n\t\t\treturn newError(\"RoundRect failed\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// DrawRoundedRectangle draws a rounded rectangle in 1/96\" units. sizeCorrection parameter is in native\n// pixels.\n//\n// Deprecated: Newer applications should use DrawRoundedRectanglePixels.\nfunc (c *Canvas) DrawRoundedRectangle(pen Pen, bounds Rectangle, ellipseSize Size) error {\n\treturn c.roundedRectangle(nullBrushSingleton, pen, bounds, ellipseSize, 0)\n}\n\n// DrawRoundedRectanglePixels draws a rounded rectangle in native pixels.\nfunc (c *Canvas) DrawRoundedRectanglePixels(pen Pen, bounds Rectangle, ellipseSize Size) error {\n\treturn c.roundedRectanglePixels(nullBrushSingleton, pen, bounds, ellipseSize, 0)\n}\n\n// FillRoundedRectangle draws a filled rounded rectangle in 1/96\" units. sizeCorrection parameter\n// is in native\n// pixels.\n//\n// Deprecated: Newer applications should use FillRoundedRectanglePixels.\nfunc (c *Canvas) FillRoundedRectangle(brush Brush, bounds Rectangle, ellipseSize Size) error {\n\treturn c.roundedRectangle(brush, nullPenSingleton, bounds, ellipseSize, 1)\n}\n\n// FillRoundedRectanglePixels draws a filled rounded rectangle in native pixels.\nfunc (c *Canvas) FillRoundedRectanglePixels(brush Brush, bounds Rectangle, ellipseSize Size) error {\n\treturn c.roundedRectanglePixels(brush, nullPenSingleton, bounds, ellipseSize, 1)\n}\n\n// GradientFillRectangle draws a gradient filled rectangle in 1/96\" units.\n//\n// Deprecated: Newer applications should use GradientFillRectanglePixels.\nfunc (c *Canvas) GradientFillRectangle(color1, color2 Color, orientation Orientation, bounds Rectangle) error {\n\treturn c.GradientFillRectanglePixels(color1, color2, orientation, RectangleFrom96DPI(bounds, c.DPI()))\n}\n\n// GradientFillRectanglePixels draws a gradient filled rectangle in native pixels.\nfunc (c *Canvas) GradientFillRectanglePixels(color1, color2 Color, orientation Orientation, bounds Rectangle) error {\n\tvertices := [2]win.TRIVERTEX{\n\t\t{\n\t\t\tX:     int32(bounds.X),\n\t\t\tY:     int32(bounds.Y),\n\t\t\tRed:   uint16(color1.R()) * 256,\n\t\t\tGreen: uint16(color1.G()) * 256,\n\t\t\tBlue:  uint16(color1.B()) * 256,\n\t\t\tAlpha: 0,\n\t\t}, {\n\t\t\tX:     int32(bounds.X + bounds.Width),\n\t\t\tY:     int32(bounds.Y + bounds.Height),\n\t\t\tRed:   uint16(color2.R()) * 256,\n\t\t\tGreen: uint16(color2.G()) * 256,\n\t\t\tBlue:  uint16(color2.B()) * 256,\n\t\t\tAlpha: 0,\n\t\t},\n\t}\n\n\tindices := win.GRADIENT_RECT{\n\t\tUpperLeft:  0,\n\t\tLowerRight: 1,\n\t}\n\n\tvar o uint32\n\tif orientation == Vertical {\n\t\to = 1\n\t}\n\n\tif !win.GradientFill(c.hdc, &vertices[0], 2, unsafe.Pointer(&indices), 1, o) {\n\t\treturn newError(\"GradientFill failed\")\n\t}\n\n\treturn nil\n}\n\n// DrawText draws text at given location in 1/96\" units.\n//\n// Deprecated: Newer applications should use DrawTextPixels.\nfunc (c *Canvas) DrawText(text string, font *Font, color Color, bounds Rectangle, format DrawTextFormat) error {\n\treturn c.DrawTextPixels(text, font, color, RectangleFrom96DPI(bounds, c.DPI()), format)\n}\n\n// DrawTextPixels draws text at given location in native pixels.\nfunc (c *Canvas) DrawTextPixels(text string, font *Font, color Color, bounds Rectangle, format DrawTextFormat) error {\n\treturn c.withFontAndTextColor(font, color, func() error {\n\t\trect := bounds.toRECT()\n\t\tret := win.DrawTextEx(\n\t\t\tc.hdc,\n\t\t\tsyscall.StringToUTF16Ptr(text),\n\t\t\t-1,\n\t\t\t&rect,\n\t\t\tuint32(format)|win.DT_EDITCONTROL,\n\t\t\tnil)\n\t\tif ret == 0 {\n\t\t\treturn newError(\"DrawTextEx failed\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// fontHeight returns font height in native pixels.\nfunc (c *Canvas) fontHeight(font *Font) (height int, err error) {\n\terr = c.withFontAndTextColor(font, 0, func() error {\n\t\tvar size win.SIZE\n\t\tif !win.GetTextExtentPoint32(c.hdc, gM, 2, &size) {\n\t\t\treturn newError(\"GetTextExtentPoint32 failed\")\n\t\t}\n\n\t\theight = int(size.CY)\n\t\tif height == 0 {\n\t\t\treturn newError(\"invalid font height\")\n\t\t}\n\n\t\treturn nil\n\t})\n\n\treturn\n}\n\n// measureTextForDPI measures text for given DPI. Input and output bounds are in native pixels.\nfunc (c *Canvas) measureTextForDPI(text string, font *Font, bounds Rectangle, format DrawTextFormat, dpi int) (boundsMeasured Rectangle, err error) {\n\thFont := win.HGDIOBJ(font.handleForDPI(dpi))\n\toldHandle := win.SelectObject(c.hdc, hFont)\n\tif oldHandle == 0 {\n\t\terr = newError(\"SelectObject failed\")\n\t\treturn\n\t}\n\tdefer win.SelectObject(c.hdc, oldHandle)\n\n\trect := &win.RECT{\n\t\tint32(bounds.X),\n\t\tint32(bounds.Y),\n\t\tint32(bounds.X + bounds.Width),\n\t\tint32(bounds.Y + bounds.Height),\n\t}\n\tvar params win.DRAWTEXTPARAMS\n\tparams.CbSize = uint32(unsafe.Sizeof(params))\n\n\tstrPtr := syscall.StringToUTF16Ptr(text)\n\tdtfmt := uint32(format) | win.DT_CALCRECT | win.DT_EDITCONTROL | win.DT_NOPREFIX | win.DT_WORDBREAK\n\n\theight := win.DrawTextEx(\n\t\tc.hdc, strPtr, -1, rect, dtfmt, &params)\n\tif height == 0 {\n\t\terr = newError(\"DrawTextEx failed\")\n\t\treturn\n\t}\n\n\tboundsMeasured = Rectangle{\n\t\tint(rect.Left),\n\t\tint(rect.Top),\n\t\tint(rect.Right - rect.Left),\n\t\tint(height),\n\t}\n\n\treturn\n}\n\n// MeasureText measures text size. Input and output bounds are in 1/96\" units.\n//\n// Deprecated: Newer applications should use MeasureTextPixels.\nfunc (c *Canvas) MeasureText(text string, font *Font, bounds Rectangle, format DrawTextFormat) (boundsMeasured Rectangle, runesFitted int, err error) {\n\tdpi := c.DPI()\n\tvar boundsMeasuredPixels Rectangle\n\tboundsMeasuredPixels, runesFitted, err = c.MeasureTextPixels(text, font, RectangleFrom96DPI(bounds, dpi), format)\n\tif err != nil {\n\t\treturn\n\t}\n\tboundsMeasured = RectangleTo96DPI(boundsMeasuredPixels, dpi)\n\treturn\n}\n\n// MeasureTextPixels measures text size. Input and output bounds are in native pixels.\nfunc (c *Canvas) MeasureTextPixels(text string, font *Font, bounds Rectangle, format DrawTextFormat) (boundsMeasured Rectangle, runesFitted int, err error) {\n\tboundsMeasured, _, runesFitted, err = c.measureAndModifyTextPixels(text, font, bounds, format)\n\treturn\n}\n\n// MeasureAndModifyTextPixels measures text size and also supports modification\n// of the text which occurs if it does not fit into the specified bounds.\n//\n// Input and output bounds are in native pixels.\nfunc (c *Canvas) MeasureAndModifyTextPixels(text string, font *Font, bounds Rectangle, format DrawTextFormat) (boundsMeasured Rectangle, textDisplayed string, err error) {\n\tvar textPtr *uint16\n\tvar runesFitted int\n\tif boundsMeasured, textPtr, runesFitted, err = c.measureAndModifyTextPixels(text, font, bounds, format|TextModifyString); err != nil {\n\t\treturn\n\t}\n\n\tif runesFitted == utf8.RuneCountInString(text) {\n\t\ttextDisplayed = text\n\t} else {\n\t\tif format&(TextEndEllipsis|TextPathEllipsis) != 0 {\n\t\t\ttextDisplayed = win.UTF16PtrToString(textPtr)\n\t\t} else {\n\t\t\ttextDisplayed = string(([]rune)(text)[:runesFitted])\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (c *Canvas) measureAndModifyTextPixels(text string, font *Font, bounds Rectangle, format DrawTextFormat) (boundsMeasured Rectangle, textPtr *uint16, runesFitted int, err error) {\n\t// HACK: We don't want to actually draw on the Canvas here, but if we use\n\t// the DT_CALCRECT flag to avoid drawing, params.UiLengthDrawn will\n\t// not contain a useful value. To work around this, we create an in-memory\n\t// metafile and draw into that instead.\n\tif c.measureTextMetafile == nil {\n\t\tc.measureTextMetafile, err = NewMetafile(c)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\thFont := win.HGDIOBJ(font.handleForDPI(c.DPI()))\n\toldHandle := win.SelectObject(c.measureTextMetafile.hdc, hFont)\n\tif oldHandle == 0 {\n\t\terr = newError(\"SelectObject failed\")\n\t\treturn\n\t}\n\tdefer win.SelectObject(c.measureTextMetafile.hdc, oldHandle)\n\n\trect := &win.RECT{\n\t\tint32(bounds.X),\n\t\tint32(bounds.Y),\n\t\tint32(bounds.X + bounds.Width),\n\t\tint32(bounds.Y + bounds.Height),\n\t}\n\tvar params win.DRAWTEXTPARAMS\n\tparams.CbSize = uint32(unsafe.Sizeof(params))\n\n\tstrPtr := syscall.StringToUTF16Ptr(text)\n\tdtfmt := uint32(format) | win.DT_EDITCONTROL | win.DT_WORDBREAK\n\n\theight := win.DrawTextEx(\n\t\tc.measureTextMetafile.hdc, strPtr, -1, rect, dtfmt, &params)\n\tif height == 0 {\n\t\terr = newError(\"DrawTextEx failed\")\n\t\treturn\n\t}\n\n\tboundsMeasured = Rectangle{\n\t\tint(rect.Left),\n\t\tint(rect.Top),\n\t\tint(rect.Right - rect.Left),\n\t\tint(height),\n\t}\n\ttextPtr = strPtr\n\trunesFitted = int(params.UiLengthDrawn)\n\n\treturn\n}\n"
  },
  {
    "path": "checkbox.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype CheckState int\n\nconst (\n\tCheckUnchecked     CheckState = win.BST_UNCHECKED\n\tCheckChecked       CheckState = win.BST_CHECKED\n\tCheckIndeterminate CheckState = win.BST_INDETERMINATE\n)\n\nvar checkBoxCheckSize Size // in native pixels\n\ntype CheckBox struct {\n\tButton\n\tcheckStateChangedPublisher EventPublisher\n}\n\nfunc NewCheckBox(parent Container) (*CheckBox, error) {\n\tcb := new(CheckBox)\n\n\tif err := InitWidget(\n\t\tcb,\n\t\tparent,\n\t\t\"BUTTON\",\n\t\twin.WS_TABSTOP|win.WS_VISIBLE|win.BS_AUTOCHECKBOX,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tcb.Button.init()\n\n\tcb.SetBackground(nullBrushSingleton)\n\n\tcb.GraphicsEffects().Add(InteractionEffect)\n\tcb.GraphicsEffects().Add(FocusEffect)\n\n\tcb.MustRegisterProperty(\"CheckState\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn cb.CheckState()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\tcb.SetCheckState(CheckState(assertIntOr(v, 0)))\n\n\t\t\treturn nil\n\t\t},\n\t\tcb.CheckStateChanged()))\n\n\treturn cb, nil\n}\n\nfunc (cb *CheckBox) TextOnLeftSide() bool {\n\treturn cb.hasStyleBits(win.BS_LEFTTEXT)\n}\n\nfunc (cb *CheckBox) SetTextOnLeftSide(textLeft bool) error {\n\treturn cb.ensureStyleBits(win.BS_LEFTTEXT, textLeft)\n}\n\nfunc (cb *CheckBox) setChecked(checked bool) {\n\tcb.Button.setChecked(checked)\n\n\tcb.checkStateChangedPublisher.Publish()\n}\n\nfunc (cb *CheckBox) Tristate() bool {\n\treturn cb.hasStyleBits(win.BS_AUTO3STATE)\n}\n\nfunc (cb *CheckBox) SetTristate(tristate bool) error {\n\tvar set, clear uint32\n\tif tristate {\n\t\tset, clear = win.BS_AUTO3STATE, win.BS_AUTOCHECKBOX\n\t} else {\n\t\tset, clear = win.BS_AUTOCHECKBOX, win.BS_AUTO3STATE\n\t}\n\n\treturn cb.setAndClearStyleBits(set, clear)\n}\n\nfunc (cb *CheckBox) CheckState() CheckState {\n\treturn CheckState(cb.SendMessage(win.BM_GETCHECK, 0, 0))\n}\n\nfunc (cb *CheckBox) SetCheckState(state CheckState) {\n\tif state == cb.CheckState() {\n\t\treturn\n\t}\n\n\tcb.SendMessage(win.BM_SETCHECK, uintptr(state), 0)\n\n\tcb.checkedChangedPublisher.Publish()\n\tcb.checkStateChangedPublisher.Publish()\n}\n\nfunc (cb *CheckBox) CheckStateChanged() *Event {\n\treturn cb.checkStateChangedPublisher.Event()\n}\n\nfunc (cb *CheckBox) SaveState() error {\n\treturn cb.WriteState(strconv.Itoa(int(cb.CheckState())))\n}\n\nfunc (cb *CheckBox) RestoreState() error {\n\ts, err := cb.ReadState()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcs, err := strconv.Atoi(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcb.SetCheckState(CheckState(cs))\n\n\treturn nil\n}\n\nfunc (cb *CheckBox) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_COMMAND:\n\t\tswitch win.HIWORD(uint32(wParam)) {\n\t\tcase win.BN_CLICKED:\n\t\t\tcb.checkedChangedPublisher.Publish()\n\t\t\tcb.checkStateChangedPublisher.Publish()\n\t\t}\n\t}\n\n\treturn cb.Button.WndProc(hwnd, msg, wParam, lParam)\n}\n"
  },
  {
    "path": "clipboard.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst clipboardWindowClass = `\\o/ Walk_Clipboard_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClassWithWndProcPtr(clipboardWindowClass, syscall.NewCallback(clipboardWndProc))\n\n\t\thwnd := win.CreateWindowEx(\n\t\t\t0,\n\t\t\tsyscall.StringToUTF16Ptr(clipboardWindowClass),\n\t\t\tnil,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\twin.HWND_MESSAGE,\n\t\t\t0,\n\t\t\t0,\n\t\t\tnil)\n\n\t\tif hwnd == 0 {\n\t\t\tpanic(\"failed to create clipboard window\")\n\t\t}\n\n\t\tif !win.AddClipboardFormatListener(hwnd) {\n\t\t\tlastError(\"AddClipboardFormatListener\")\n\t\t}\n\n\t\tclipboard.hwnd = hwnd\n\t})\n}\n\nfunc clipboardWndProc(hwnd win.HWND, msg uint32, wp, lp uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_CLIPBOARDUPDATE:\n\t\tclipboard.contentsChangedPublisher.Publish()\n\t\treturn 0\n\t}\n\n\treturn win.DefWindowProc(hwnd, msg, wp, lp)\n}\n\nvar clipboard ClipboardService\n\n// Clipboard returns an object that provides access to the system clipboard.\nfunc Clipboard() *ClipboardService {\n\treturn &clipboard\n}\n\n// ClipboardService provides access to the system clipboard.\ntype ClipboardService struct {\n\thwnd                     win.HWND\n\tcontentsChangedPublisher EventPublisher\n}\n\n// ContentsChanged returns an Event that you can attach to for handling\n// clipboard content changes.\nfunc (c *ClipboardService) ContentsChanged() *Event {\n\treturn c.contentsChangedPublisher.Event()\n}\n\n// Clear clears the contents of the clipboard.\nfunc (c *ClipboardService) Clear() error {\n\treturn c.withOpenClipboard(func() error {\n\t\tif !win.EmptyClipboard() {\n\t\t\treturn lastError(\"EmptyClipboard\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// ContainsText returns whether the clipboard currently contains text data.\nfunc (c *ClipboardService) ContainsText() (available bool, err error) {\n\terr = c.withOpenClipboard(func() error {\n\t\tavailable = win.IsClipboardFormatAvailable(win.CF_UNICODETEXT)\n\n\t\treturn nil\n\t})\n\n\treturn\n}\n\n// Text returns the current text data of the clipboard.\nfunc (c *ClipboardService) Text() (text string, err error) {\n\terr = c.withOpenClipboard(func() error {\n\t\thMem := win.HGLOBAL(win.GetClipboardData(win.CF_UNICODETEXT))\n\t\tif hMem == 0 {\n\t\t\treturn lastError(\"GetClipboardData\")\n\t\t}\n\n\t\tp := win.GlobalLock(hMem)\n\t\tif p == nil {\n\t\t\treturn lastError(\"GlobalLock()\")\n\t\t}\n\t\tdefer win.GlobalUnlock(hMem)\n\n\t\ttext = win.UTF16PtrToString((*uint16)(p))\n\n\t\treturn nil\n\t})\n\n\treturn\n}\n\n// SetText sets the current text data of the clipboard.\nfunc (c *ClipboardService) SetText(s string) error {\n\treturn c.withOpenClipboard(func() error {\n\t\tutf16, err := syscall.UTF16FromString(s)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\thMem := win.GlobalAlloc(win.GMEM_MOVEABLE, uintptr(len(utf16)*2))\n\t\tif hMem == 0 {\n\t\t\treturn lastError(\"GlobalAlloc\")\n\t\t}\n\n\t\tp := win.GlobalLock(hMem)\n\t\tif p == nil {\n\t\t\treturn lastError(\"GlobalLock()\")\n\t\t}\n\n\t\twin.MoveMemory(p, unsafe.Pointer(&utf16[0]), uintptr(len(utf16)*2))\n\n\t\twin.GlobalUnlock(hMem)\n\n\t\tif 0 == win.SetClipboardData(win.CF_UNICODETEXT, win.HANDLE(hMem)) {\n\t\t\t// We need to free hMem.\n\t\t\tdefer win.GlobalFree(hMem)\n\n\t\t\treturn lastError(\"SetClipboardData\")\n\t\t}\n\n\t\t// The system now owns the memory referred to by hMem.\n\n\t\treturn nil\n\t})\n}\n\nfunc (c *ClipboardService) withOpenClipboard(f func() error) error {\n\tif !win.OpenClipboard(c.hwnd) {\n\t\treturn lastError(\"OpenClipboard\")\n\t}\n\tdefer win.CloseClipboard()\n\n\treturn f()\n}\n"
  },
  {
    "path": "closeevent.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype closeEventHandlerInfo struct {\n\thandler CloseEventHandler\n\tonce    bool\n}\n\ntype CloseEventHandler func(canceled *bool, reason CloseReason)\n\ntype CloseEvent struct {\n\thandlers []closeEventHandlerInfo\n}\n\nfunc (e *CloseEvent) Attach(handler CloseEventHandler) int {\n\thandlerInfo := closeEventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *CloseEvent) Detach(handle int) {\n\te.handlers[handle].handler = nil\n}\n\nfunc (e *CloseEvent) Once(handler CloseEventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype CloseEventPublisher struct {\n\tevent CloseEvent\n}\n\nfunc (p *CloseEventPublisher) Event() *CloseEvent {\n\treturn &p.event\n}\n\nfunc (p *CloseEventPublisher) Publish(canceled *bool, reason CloseReason) {\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler(canceled, reason)\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "color.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype Color uint32\n\nfunc RGB(r, g, b byte) Color {\n\treturn Color(uint32(r) | uint32(g)<<8 | uint32(b)<<16)\n}\n\nfunc (c Color) R() byte {\n\treturn byte(c & 0xff)\n}\n\nfunc (c Color) G() byte {\n\treturn byte((c >> 8) & 0xff)\n}\n\nfunc (c Color) B() byte {\n\treturn byte((c >> 16) & 0xff)\n}\n"
  },
  {
    "path": "combobox.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype ComboBox struct {\n\tWidgetBase\n\tbindingValueProvider         BindingValueProvider\n\tmodel                        ListModel\n\tprovidedModel                interface{}\n\tbindingMember                string\n\tdisplayMember                string\n\tformat                       string\n\tprecision                    int\n\titemsResetHandlerHandle      int\n\titemChangedHandlerHandle     int\n\titemsInsertedHandlerHandle   int\n\titemsRemovedHandlerHandle    int\n\tmaxItemTextWidth             int // in native pixels\n\tcurrentValue                 interface{}\n\tprevCurIndex                 int\n\tselChangeIndex               int\n\tmaxLength                    int\n\tcurrentIndexChangedPublisher EventPublisher\n\ttextChangedPublisher         EventPublisher\n\teditingFinishedPublisher     EventPublisher\n\teditOrigWndProcPtr           uintptr\n\tediting                      bool\n\tpersistent                   bool\n}\n\nvar comboBoxEditWndProcPtr uintptr\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tcomboBoxEditWndProcPtr = syscall.NewCallback(comboBoxEditWndProc)\n\t})\n}\n\nfunc comboBoxEditWndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tcb := (*ComboBox)(unsafe.Pointer(win.GetWindowLongPtr(hwnd, win.GWLP_USERDATA)))\n\n\tswitch msg {\n\tcase win.WM_GETDLGCODE:\n\t\tif !cb.editing {\n\t\t\tif form := ancestor(cb); form != nil {\n\t\t\t\tif dlg, ok := form.(dialogish); ok {\n\t\t\t\t\tif dlg.DefaultButton() != nil {\n\t\t\t\t\t\t// If the ComboBox lives in a Dialog that has a\n\t\t\t\t\t\t// DefaultButton, we won't swallow the return key.\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif wParam == win.VK_RETURN {\n\t\t\treturn win.DLGC_WANTALLKEYS\n\t\t}\n\n\tcase win.WM_KEYDOWN:\n\t\tif wParam != win.VK_RETURN || 0 == cb.SendMessage(win.CB_GETDROPPEDSTATE, 0, 0) {\n\t\t\tcb.handleKeyDown(wParam, lParam)\n\t\t}\n\n\t\tif cb.editing && wParam == win.VK_RETURN {\n\t\t\tcb.editing = false\n\t\t\tcb.editingFinishedPublisher.Publish()\n\t\t}\n\n\tcase win.WM_KEYUP:\n\t\tif wParam != win.VK_RETURN || 0 == cb.SendMessage(win.CB_GETDROPPEDSTATE, 0, 0) {\n\t\t\tcb.handleKeyUp(wParam, lParam)\n\t\t}\n\n\tcase win.WM_SETFOCUS, win.WM_KILLFOCUS:\n\t\tcb.invalidateBorderInParent()\n\n\t\tif cb.editing && msg == win.WM_KILLFOCUS {\n\t\t\tcb.editing = false\n\t\t\tcb.editingFinishedPublisher.Publish()\n\t\t}\n\t}\n\n\treturn win.CallWindowProc(cb.editOrigWndProcPtr, hwnd, msg, wParam, lParam)\n}\n\nfunc NewComboBox(parent Container) (*ComboBox, error) {\n\tcb, err := newComboBoxWithStyle(parent, win.CBS_AUTOHSCROLL|win.CBS_DROPDOWN)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\teditHwnd := win.GetWindow(cb.hWnd, win.GW_CHILD)\n\n\twin.SetWindowLongPtr(editHwnd, win.GWLP_USERDATA, uintptr(unsafe.Pointer(cb)))\n\tcb.editOrigWndProcPtr = win.SetWindowLongPtr(editHwnd, win.GWLP_WNDPROC, comboBoxEditWndProcPtr)\n\n\treturn cb, nil\n}\n\nfunc NewDropDownBox(parent Container) (*ComboBox, error) {\n\treturn newComboBoxWithStyle(parent, win.CBS_DROPDOWNLIST)\n}\n\nfunc newComboBoxWithStyle(parent Container, style uint32) (*ComboBox, error) {\n\tcb := &ComboBox{prevCurIndex: -1, selChangeIndex: -1, precision: 2}\n\n\tif err := InitWidget(\n\t\tcb,\n\t\tparent,\n\t\t\"COMBOBOX\",\n\t\twin.WS_TABSTOP|win.WS_VISIBLE|win.WS_VSCROLL|style,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tcb.Dispose()\n\t\t}\n\t}()\n\n\tvar event *Event\n\tif style&win.CBS_DROPDOWNLIST == win.CBS_DROPDOWNLIST {\n\t\tevent = cb.CurrentIndexChanged()\n\t} else {\n\t\tevent = cb.TextChanged()\n\t}\n\n\tcb.GraphicsEffects().Add(InteractionEffect)\n\tcb.GraphicsEffects().Add(FocusEffect)\n\n\tcb.MustRegisterProperty(\"CurrentIndex\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn cb.CurrentIndex()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn cb.SetCurrentIndex(assertIntOr(v, -1))\n\t\t},\n\t\tcb.CurrentIndexChanged()))\n\n\tcb.MustRegisterProperty(\"Text\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn cb.Text()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn cb.SetText(assertStringOr(v, \"\"))\n\t\t},\n\t\tevent))\n\n\tcb.MustRegisterProperty(\"CurrentItem\", NewReadOnlyProperty(\n\t\tfunc() interface{} {\n\t\t\tif rlm, ok := cb.providedModel.(ReflectListModel); ok {\n\t\t\t\tif i := cb.CurrentIndex(); i > -1 {\n\t\t\t\t\treturn reflect.ValueOf(rlm.Items()).Index(i).Interface()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\tcb.CurrentIndexChanged()))\n\n\tcb.MustRegisterProperty(\"HasCurrentItem\", NewReadOnlyBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn cb.CurrentIndex() != -1\n\t\t},\n\t\tcb.CurrentIndexChanged()))\n\n\tcb.MustRegisterProperty(\"TextNotEmpty\", NewReadOnlyBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn cb.Text() != \"\"\n\t\t},\n\t\tcb.CurrentIndexChanged()))\n\n\tcb.MustRegisterProperty(\"Value\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\tif cb.Editable() {\n\t\t\t\treturn cb.Text()\n\t\t\t}\n\n\t\t\tindex := cb.CurrentIndex()\n\n\t\t\tif cb.bindingValueProvider == nil || index == -1 {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn cb.bindingValueProvider.BindingValue(index)\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\tif cb.Editable() {\n\t\t\t\treturn cb.SetText(assertStringOr(v, \"\"))\n\t\t\t}\n\n\t\t\tif cb.bindingValueProvider == nil {\n\t\t\t\tif cb.model == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t} else {\n\t\t\t\t\treturn newError(\"Data binding is only supported using a model that implements BindingValueProvider.\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tindex := -1\n\n\t\t\tcount := cb.model.ItemCount()\n\t\t\tfor i := 0; i < count; i++ {\n\t\t\t\tif cb.bindingValueProvider.BindingValue(i) == v {\n\t\t\t\t\tindex = i\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn cb.SetCurrentIndex(index)\n\t\t},\n\t\tevent))\n\n\tsucceeded = true\n\n\treturn cb, nil\n}\n\nfunc (cb *ComboBox) applyFont(font *Font) {\n\tcb.WidgetBase.applyFont(font)\n\n\tif cb.model != nil {\n\t\tcb.maxItemTextWidth = cb.calculateMaxItemTextWidth()\n\t\tcb.RequestLayout()\n\t}\n}\n\nfunc (cb *ComboBox) Editable() bool {\n\treturn !cb.hasStyleBits(win.CBS_DROPDOWNLIST)\n}\n\nfunc (cb *ComboBox) itemString(index int) string {\n\tswitch val := cb.model.Value(index).(type) {\n\tcase string:\n\t\treturn val\n\n\tcase time.Time:\n\t\treturn val.Format(cb.format)\n\n\tcase *big.Rat:\n\t\treturn val.FloatString(cb.precision)\n\n\tdefault:\n\t\treturn fmt.Sprintf(cb.format, val)\n\t}\n\n\tpanic(\"unreachable\")\n}\n\nfunc (cb *ComboBox) insertItemAt(index int) error {\n\tstr := cb.itemString(index)\n\tlp := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(str)))\n\n\tif win.CB_ERR == cb.SendMessage(win.CB_INSERTSTRING, uintptr(index), lp) {\n\t\treturn newError(\"SendMessage(CB_INSERTSTRING)\")\n\t}\n\n\treturn nil\n}\n\nfunc (cb *ComboBox) removeItem(index int) error {\n\tif win.CB_ERR == cb.SendMessage(win.CB_DELETESTRING, uintptr(index), 0) {\n\t\treturn newError(\"SendMessage(CB_DELETESTRING\")\n\t}\n\n\treturn nil\n}\n\nfunc (cb *ComboBox) resetItems() error {\n\tcb.SetSuspended(true)\n\tdefer cb.SetSuspended(false)\n\n\tcb.selChangeIndex = -1\n\n\tif win.FALSE == cb.SendMessage(win.CB_RESETCONTENT, 0, 0) {\n\t\treturn newError(\"SendMessage(CB_RESETCONTENT)\")\n\t}\n\n\tcb.maxItemTextWidth = 0\n\n\toldValue := cb.currentValue\n\n\tif cb.model == nil {\n\t\tcb.SetCurrentIndex(-1)\n\t\treturn nil\n\t}\n\n\tcount := cb.model.ItemCount()\n\n\tfor i := 0; i < count; i++ {\n\t\tif err := cb.insertItemAt(i); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif oldValue != nil {\n\t\tcb.Property(\"Value\").Set(oldValue)\n\t} else {\n\t\tcb.SetCurrentIndex(-1)\n\t}\n\n\tcb.RequestLayout()\n\n\treturn nil\n}\n\nfunc (cb *ComboBox) attachModel() {\n\titemsResetHandler := func() {\n\t\tcb.resetItems()\n\t}\n\tcb.itemsResetHandlerHandle = cb.model.ItemsReset().Attach(itemsResetHandler)\n\n\titemChangedHandler := func(index int) {\n\t\tif win.CB_ERR == cb.SendMessage(win.CB_DELETESTRING, uintptr(index), 0) {\n\t\t\tnewError(\"SendMessage(CB_DELETESTRING)\")\n\t\t}\n\n\t\tcb.insertItemAt(index)\n\n\t\tcb.SetCurrentIndex(cb.prevCurIndex)\n\t}\n\tcb.itemChangedHandlerHandle = cb.model.ItemChanged().Attach(itemChangedHandler)\n\n\tcb.itemsInsertedHandlerHandle = cb.model.ItemsInserted().Attach(func(from, to int) {\n\t\tfor i := from; i <= to; i++ {\n\t\t\tcb.insertItemAt(i)\n\t\t}\n\t})\n\n\tcb.itemsRemovedHandlerHandle = cb.model.ItemsRemoved().Attach(func(from, to int) {\n\t\tfor i := to; i >= from; i-- {\n\t\t\tcb.removeItem(i)\n\t\t}\n\t})\n}\n\nfunc (cb *ComboBox) detachModel() {\n\tcb.model.ItemsReset().Detach(cb.itemsResetHandlerHandle)\n\tcb.model.ItemChanged().Detach(cb.itemChangedHandlerHandle)\n\tcb.model.ItemsInserted().Detach(cb.itemsInsertedHandlerHandle)\n\tcb.model.ItemsRemoved().Detach(cb.itemsRemovedHandlerHandle)\n}\n\n// Model returns the model of the ComboBox.\nfunc (cb *ComboBox) Model() interface{} {\n\treturn cb.providedModel\n}\n\n// SetModel sets the model of the ComboBox.\n//\n// It is required that mdl either implements walk.ListModel or\n// walk.ReflectListModel or be a slice of pointers to struct or a []string.\nfunc (cb *ComboBox) SetModel(mdl interface{}) error {\n\tmodel, ok := mdl.(ListModel)\n\tif !ok && mdl != nil {\n\t\tvar err error\n\t\tif model, err = newReflectListModel(mdl); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif _, ok := mdl.([]string); !ok {\n\t\t\tif badms, ok := model.(bindingAndDisplayMemberSetter); ok {\n\t\t\t\tvar bindingMember string\n\t\t\t\tif cb.Editable() {\n\t\t\t\t\tbindingMember = cb.displayMember\n\t\t\t\t} else {\n\t\t\t\t\tbindingMember = cb.bindingMember\n\t\t\t\t}\n\t\t\t\tbadms.setBindingMember(bindingMember)\n\t\t\t\tbadms.setDisplayMember(cb.displayMember)\n\t\t\t}\n\t\t}\n\t}\n\tcb.providedModel = mdl\n\n\tif cb.model != nil {\n\t\tcb.detachModel()\n\t}\n\n\tcb.model = model\n\tcb.bindingValueProvider, _ = model.(BindingValueProvider)\n\n\tif model != nil {\n\t\tcb.attachModel()\n\t}\n\n\tif err := cb.resetItems(); err != nil {\n\t\treturn err\n\t}\n\n\tif !cb.Editable() && model != nil && model.ItemCount() == 1 {\n\t\tcb.SetCurrentIndex(0)\n\t}\n\n\treturn cb.Invalidate()\n}\n\n// BindingMember returns the member from the model of the ComboBox that is bound\n// to a field of the data source managed by an associated DataBinder.\n//\n// This is only applicable to walk.ReflectListModel models and simple slices of\n// pointers to struct.\nfunc (cb *ComboBox) BindingMember() string {\n\treturn cb.bindingMember\n}\n\n// SetBindingMember sets the member from the model of the ComboBox that is bound\n// to a field of the data source managed by an associated DataBinder.\n//\n// This is only applicable to walk.ReflectListModel models and simple slices of\n// pointers to struct.\n//\n// For a model consisting of items of type S, data source field of type T and\n// bindingMember \"Foo\", this can be one of the following:\n//\n//\tA field\t\tFoo T\n//\tA method\tfunc (s S) Foo() T\n//\tA method\tfunc (s S) Foo() (T, error)\n//\n// If bindingMember is not a simple member name like \"Foo\", but a path to a\n// member like \"A.B.Foo\", members \"A\" and \"B\" both must be one of the options\n// mentioned above, but with T having type pointer to struct.\nfunc (cb *ComboBox) SetBindingMember(bindingMember string) error {\n\tif bindingMember != \"\" {\n\t\tif _, ok := cb.providedModel.([]string); ok {\n\t\t\treturn newError(\"invalid for []string model\")\n\t\t}\n\t}\n\n\tcb.bindingMember = bindingMember\n\n\tif badms, ok := cb.model.(bindingAndDisplayMemberSetter); ok {\n\t\tbadms.setBindingMember(bindingMember)\n\t}\n\n\treturn nil\n}\n\n// DisplayMember returns the member from the model of the ComboBox that is\n// displayed in the ComboBox.\n//\n// This is only applicable to walk.ReflectListModel models and simple slices of\n// pointers to struct.\nfunc (cb *ComboBox) DisplayMember() string {\n\treturn cb.displayMember\n}\n\n// SetDisplayMember sets the member from the model of the ComboBox that is\n// displayed in the ComboBox.\n//\n// This is only applicable to walk.ReflectListModel models and simple slices of\n// pointers to struct.\n//\n// For a model consisting of items of type S, the type of the specified member T\n// and displayMember \"Foo\", this can be one of the following:\n//\n//\tA field\t\tFoo T\n//\tA method\tfunc (s S) Foo() T\n//\tA method\tfunc (s S) Foo() (T, error)\n//\n// If displayMember is not a simple member name like \"Foo\", but a path to a\n// member like \"A.B.Foo\", members \"A\" and \"B\" both must be one of the options\n// mentioned above, but with T having type pointer to struct.\nfunc (cb *ComboBox) SetDisplayMember(displayMember string) error {\n\tif displayMember != \"\" {\n\t\tif _, ok := cb.providedModel.([]string); ok {\n\t\t\treturn newError(\"invalid for []string model\")\n\t\t}\n\t}\n\n\tcb.displayMember = displayMember\n\n\tif badms, ok := cb.model.(bindingAndDisplayMemberSetter); ok {\n\t\tbadms.setDisplayMember(displayMember)\n\t}\n\n\treturn nil\n}\n\nfunc (cb *ComboBox) Format() string {\n\treturn cb.format\n}\n\nfunc (cb *ComboBox) SetFormat(value string) {\n\tcb.format = value\n}\n\nfunc (cb *ComboBox) Precision() int {\n\treturn cb.precision\n}\n\nfunc (cb *ComboBox) SetPrecision(value int) {\n\tcb.precision = value\n}\n\nfunc (cb *ComboBox) MaxLength() int {\n\treturn cb.maxLength\n}\n\nfunc (cb *ComboBox) SetMaxLength(value int) {\n\tcb.SendMessage(win.CB_LIMITTEXT, uintptr(value), 0)\n\n\tcb.maxLength = value\n}\n\n// calculateMaxItemTextWidth returns maximum item text width in native pixels.\nfunc (cb *ComboBox) calculateMaxItemTextWidth() int {\n\thdc := win.GetDC(cb.hWnd)\n\tif hdc == 0 {\n\t\tnewError(\"GetDC failed\")\n\t\treturn -1\n\t}\n\tdefer win.ReleaseDC(cb.hWnd, hdc)\n\n\thFontOld := win.SelectObject(hdc, win.HGDIOBJ(cb.Font().handleForDPI(cb.DPI())))\n\tdefer win.SelectObject(hdc, hFontOld)\n\n\tvar maxWidth int\n\n\tcount := cb.model.ItemCount()\n\tfor i := 0; i < count; i++ {\n\t\tvar s win.SIZE\n\t\tstr := syscall.StringToUTF16(cb.itemString(i))\n\n\t\tif !win.GetTextExtentPoint32(hdc, &str[0], int32(len(str)-1), &s) {\n\t\t\tnewError(\"GetTextExtentPoint32 failed\")\n\t\t\treturn -1\n\t\t}\n\n\t\tmaxWidth = maxi(maxWidth, int(s.CX))\n\t}\n\n\treturn maxWidth\n}\n\nfunc (cb *ComboBox) CurrentIndex() int {\n\treturn int(int32(cb.SendMessage(win.CB_GETCURSEL, 0, 0)))\n}\n\nfunc (cb *ComboBox) SetCurrentIndex(value int) error {\n\tindex := int(int32(cb.SendMessage(win.CB_SETCURSEL, uintptr(value), 0)))\n\n\tif index != value {\n\t\treturn newError(\"invalid index\")\n\t}\n\n\tif value != cb.prevCurIndex {\n\t\tif value == -1 {\n\t\t\tcb.currentValue = nil\n\t\t} else {\n\t\t\tcb.currentValue = cb.Property(\"Value\").Get()\n\t\t}\n\n\t\tcb.prevCurIndex = value\n\t\tcb.currentIndexChangedPublisher.Publish()\n\t}\n\n\treturn nil\n}\n\nfunc (cb *ComboBox) CurrentIndexChanged() *Event {\n\treturn cb.currentIndexChangedPublisher.Event()\n}\n\nfunc (cb *ComboBox) Text() string {\n\treturn cb.text()\n}\n\nfunc (cb *ComboBox) SetText(value string) error {\n\tvar oldText string\n\toldText, _ = cb.currentValue.(string)\n\n\tif err := cb.setText(value); err != nil {\n\t\treturn err\n\t}\n\n\tif value == oldText {\n\t\treturn nil\n\t}\n\n\tif cb.Editable() {\n\t\tcb.currentValue = value\n\t}\n\n\tcb.textChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (cb *ComboBox) TextSelection() (start, end int) {\n\tcb.SendMessage(win.CB_GETEDITSEL, uintptr(unsafe.Pointer(&start)), uintptr(unsafe.Pointer(&end)))\n\treturn\n}\n\nfunc (cb *ComboBox) SetTextSelection(start, end int) {\n\tcb.SendMessage(win.CB_SETEDITSEL, 0, uintptr(win.MAKELONG(uint16(start), uint16(end))))\n}\n\nfunc (cb *ComboBox) TextChanged() *Event {\n\treturn cb.textChangedPublisher.Event()\n}\n\nfunc (cb *ComboBox) EditingFinished() *Event {\n\treturn cb.editingFinishedPublisher.Event()\n}\n\nfunc (cb *ComboBox) Persistent() bool {\n\treturn cb.persistent\n}\n\nfunc (cb *ComboBox) SetPersistent(value bool) {\n\tcb.persistent = value\n}\n\nfunc (cb *ComboBox) SaveState() error {\n\tcb.WriteState(strconv.Itoa(cb.CurrentIndex()))\n\n\treturn nil\n}\n\nfunc (cb *ComboBox) RestoreState() error {\n\tstate, err := cb.ReadState()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif state == \"\" {\n\t\treturn nil\n\t}\n\n\tif i, err := strconv.Atoi(state); err == nil {\n\t\tcb.SetCurrentIndex(i)\n\t}\n\n\treturn nil\n}\n\nfunc (cb *ComboBox) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_COMMAND:\n\t\tcode := win.HIWORD(uint32(wParam))\n\t\tselIndex := cb.CurrentIndex()\n\n\t\tswitch code {\n\t\tcase win.CBN_EDITCHANGE:\n\t\t\tcb.editing = true\n\t\t\tcb.selChangeIndex = -1\n\t\t\tcb.textChangedPublisher.Publish()\n\n\t\tcase win.CBN_SELCHANGE:\n\t\t\tcb.selChangeIndex = selIndex\n\t\t\tcb.currentIndexChangedPublisher.Publish()\n\n\t\tcase win.CBN_SELENDCANCEL:\n\t\t\tif cb.selChangeIndex != -1 {\n\t\t\t\tif cb.selChangeIndex < cb.model.ItemCount() {\n\t\t\t\t\tcb.SetCurrentIndex(cb.selChangeIndex)\n\t\t\t\t}\n\n\t\t\t\tcb.selChangeIndex = -1\n\t\t\t}\n\n\t\tcase win.CBN_SELENDOK:\n\t\t\tif editable := cb.Editable(); editable || selIndex != cb.prevCurIndex {\n\t\t\t\tvalueProp := cb.Property(\"Value\")\n\t\t\t\tif editable && selIndex > -1 {\n\t\t\t\t\tvalueProp.Set(cb.model.Value(selIndex))\n\t\t\t\t} else {\n\t\t\t\t\tcb.currentValue = valueProp.Get()\n\t\t\t\t}\n\t\t\t\tcb.currentIndexChangedPublisher.Publish()\n\t\t\t\tcb.prevCurIndex = selIndex\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tcb.selChangeIndex = -1\n\t\t}\n\n\tcase win.WM_MOUSEWHEEL:\n\t\tif !cb.Enabled() {\n\t\t\treturn 0\n\t\t}\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif cb.Editable() {\n\t\t\tresult := cb.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n\n\t\t\tcb.SetTextSelection(0, 0)\n\n\t\t\treturn result\n\t\t}\n\t}\n\n\treturn cb.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (*ComboBox) NeedsWmSize() bool {\n\treturn true\n}\n\nfunc (cb *ComboBox) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tvar layoutFlags LayoutFlags\n\tif cb.Editable() {\n\t\tlayoutFlags = GrowableHorz | GreedyHorz\n\t} else {\n\t\tlayoutFlags = GrowableHorz\n\t}\n\n\tdefaultSize := cb.dialogBaseUnitsToPixels(Size{30, 12})\n\n\tif cb.model != nil && cb.maxItemTextWidth <= 0 {\n\t\tcb.maxItemTextWidth = cb.calculateMaxItemTextWidth()\n\t}\n\n\t// FIXME: Use GetThemePartSize instead of guessing\n\tw := maxi(defaultSize.Width, cb.maxItemTextWidth+int(win.GetSystemMetricsForDpi(win.SM_CXVSCROLL, uint32(ctx.dpi)))+8)\n\th := defaultSize.Height + 1\n\n\treturn &comboBoxLayoutItem{\n\t\tlayoutFlags: layoutFlags,\n\t\tidealSize:   Size{w, h},\n\t}\n}\n\ntype comboBoxLayoutItem struct {\n\tLayoutItemBase\n\tlayoutFlags LayoutFlags\n\tidealSize   Size // in native pixels\n}\n\nfunc (li *comboBoxLayoutItem) LayoutFlags() LayoutFlags {\n\treturn li.layoutFlags\n}\n\nfunc (li *comboBoxLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *comboBoxLayoutItem) MinSize() Size {\n\treturn li.idealSize\n}\n"
  },
  {
    "path": "commondialogs.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"syscall\"\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype FileDialog struct {\n\tTitle          string\n\tFilePath       string\n\tFilePaths      []string\n\tInitialDirPath string\n\tFilter         string\n\tFilterIndex    int\n\tFlags          uint32\n\tShowReadOnlyCB bool\n}\n\nfunc (dlg *FileDialog) show(owner Form, fun func(ofn *win.OPENFILENAME) bool, flags uint32) (accepted bool, err error) {\n\tofn := new(win.OPENFILENAME)\n\n\tofn.LStructSize = uint32(unsafe.Sizeof(*ofn))\n\tif owner != nil {\n\t\tofn.HwndOwner = owner.Handle()\n\t}\n\n\tfilter := make([]uint16, len(dlg.Filter)+2)\n\tcopy(filter, syscall.StringToUTF16(dlg.Filter))\n\t// Replace '|' with the expected '\\0'.\n\tfor i, c := range filter {\n\t\tif byte(c) == '|' {\n\t\t\tfilter[i] = uint16(0)\n\t\t}\n\t}\n\tofn.LpstrFilter = &filter[0]\n\tofn.NFilterIndex = uint32(dlg.FilterIndex)\n\n\tofn.LpstrInitialDir = syscall.StringToUTF16Ptr(dlg.InitialDirPath)\n\tofn.LpstrTitle = syscall.StringToUTF16Ptr(dlg.Title)\n\tofn.Flags = win.OFN_FILEMUSTEXIST | flags | dlg.Flags\n\n\tif !dlg.ShowReadOnlyCB {\n\t\tofn.Flags |= win.OFN_HIDEREADONLY\n\t}\n\n\tvar fileBuf []uint16\n\tif flags&win.OFN_ALLOWMULTISELECT > 0 {\n\t\tfileBuf = make([]uint16, 65536)\n\t} else {\n\t\tfileBuf = make([]uint16, 1024)\n\t\tcopy(fileBuf, syscall.StringToUTF16(dlg.FilePath))\n\t}\n\tofn.LpstrFile = &fileBuf[0]\n\tofn.NMaxFile = uint32(len(fileBuf))\n\n\tif !fun(ofn) {\n\t\terrno := win.CommDlgExtendedError()\n\t\tif errno != 0 {\n\t\t\terr = newError(fmt.Sprintf(\"Error %d\", errno))\n\t\t}\n\t\treturn\n\t}\n\n\tdlg.FilterIndex = int(ofn.NFilterIndex)\n\n\tif flags&win.OFN_ALLOWMULTISELECT > 0 {\n\t\tsplit := func() [][]uint16 {\n\t\t\tvar parts [][]uint16\n\n\t\t\tfrom := 0\n\t\t\tfor i, c := range fileBuf {\n\t\t\t\tif c == 0 {\n\t\t\t\t\tif i == from {\n\t\t\t\t\t\treturn parts\n\t\t\t\t\t}\n\n\t\t\t\t\tparts = append(parts, fileBuf[from:i])\n\t\t\t\t\tfrom = i + 1\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn parts\n\t\t}\n\n\t\tparts := split()\n\n\t\tif len(parts) == 1 {\n\t\t\tdlg.FilePaths = []string{syscall.UTF16ToString(parts[0])}\n\t\t} else {\n\t\t\tdirPath := syscall.UTF16ToString(parts[0])\n\t\t\tdlg.FilePaths = make([]string, len(parts)-1)\n\n\t\t\tfor i, fp := range parts[1:] {\n\t\t\t\tdlg.FilePaths[i] = filepath.Join(dirPath, syscall.UTF16ToString(fp))\n\t\t\t}\n\t\t}\n\t} else {\n\t\tdlg.FilePath = syscall.UTF16ToString(fileBuf)\n\t}\n\n\taccepted = true\n\n\treturn\n}\n\nfunc (dlg *FileDialog) ShowOpen(owner Form) (accepted bool, err error) {\n\treturn dlg.show(owner, win.GetOpenFileName, win.OFN_NOCHANGEDIR)\n}\n\nfunc (dlg *FileDialog) ShowOpenMultiple(owner Form) (accepted bool, err error) {\n\treturn dlg.show(owner, win.GetOpenFileName, win.OFN_ALLOWMULTISELECT|win.OFN_EXPLORER|win.OFN_NOCHANGEDIR)\n}\n\nfunc (dlg *FileDialog) ShowSave(owner Form) (accepted bool, err error) {\n\treturn dlg.show(owner, win.GetSaveFileName, win.OFN_NOCHANGEDIR)\n}\n\nfunc pathFromPIDL(pidl uintptr) (string, error) {\n\tvar path [win.MAX_PATH]uint16\n\tif !win.SHGetPathFromIDList(pidl, &path[0]) {\n\t\treturn \"\", newError(\"SHGetPathFromIDList failed\")\n\t}\n\n\treturn syscall.UTF16ToString(path[:]), nil\n}\n\n// We use this callback to disable the OK button in case of \"invalid\" selections.\nfunc browseFolderCallback(hwnd win.HWND, msg uint32, lp, wp uintptr) uintptr {\n\tconst BFFM_SELCHANGED = 2\n\tif msg == BFFM_SELCHANGED {\n\t\t_, err := pathFromPIDL(lp)\n\t\tvar enabled uintptr\n\t\tif err == nil {\n\t\t\tenabled = 1\n\t\t}\n\n\t\tconst BFFM_ENABLEOK = win.WM_USER + 101\n\n\t\twin.SendMessage(hwnd, BFFM_ENABLEOK, 0, enabled)\n\t}\n\n\treturn 0\n}\n\nvar browseFolderCallbackPtr uintptr\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tbrowseFolderCallbackPtr = syscall.NewCallback(browseFolderCallback)\n\t})\n}\n\nfunc (dlg *FileDialog) ShowBrowseFolder(owner Form) (accepted bool, err error) {\n\t// Calling OleInitialize (or similar) is required for BIF_NEWDIALOGSTYLE.\n\tif hr := win.OleInitialize(); hr != win.S_OK && hr != win.S_FALSE {\n\t\treturn false, newError(fmt.Sprint(\"OleInitialize Error: \", hr))\n\t}\n\tdefer win.OleUninitialize()\n\n\tvar ownerHwnd win.HWND\n\tif owner != nil {\n\t\townerHwnd = owner.Handle()\n\t}\n\n\t// We need to put the initial path into a buffer of at least MAX_LENGTH\n\t// length, or we may get random crashes.\n\tvar buf [win.MAX_PATH]uint16\n\tcopy(buf[:], syscall.StringToUTF16(dlg.InitialDirPath))\n\n\tconst BIF_NEWDIALOGSTYLE = 0x00000040\n\n\tbi := win.BROWSEINFO{\n\t\tHwndOwner: ownerHwnd,\n\t\tLpszTitle: syscall.StringToUTF16Ptr(dlg.Title),\n\t\tUlFlags:   BIF_NEWDIALOGSTYLE,\n\t\tLpfn:      browseFolderCallbackPtr,\n\t}\n\n\twin.SHParseDisplayName(&buf[0], 0, &bi.PidlRoot, 0, nil)\n\n\tpidl := win.SHBrowseForFolder(&bi)\n\tif pidl == 0 {\n\t\treturn false, nil\n\t}\n\tdefer win.CoTaskMemFree(pidl)\n\n\tdlg.FilePath, err = pathFromPIDL(pidl)\n\taccepted = dlg.FilePath != \"\"\n\treturn\n}\n"
  },
  {
    "path": "composite.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\nconst compositeWindowClass = `\\o/ Walk_Composite_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(compositeWindowClass)\n\t})\n}\n\ntype Composite struct {\n\tContainerBase\n}\n\nfunc NewCompositeWithStyle(parent Window, style uint32) (*Composite, error) {\n\tc := new(Composite)\n\tc.children = newWidgetList(c)\n\tc.SetPersistent(true)\n\n\tif err := InitWidget(\n\t\tc,\n\t\tparent,\n\t\tcompositeWindowClass,\n\t\twin.WS_CHILD|win.WS_VISIBLE|style,\n\t\twin.WS_EX_CONTROLPARENT); err != nil {\n\t\treturn nil, err\n\t}\n\n\tc.SetBackground(NullBrush())\n\n\treturn c, nil\n}\n\nfunc NewComposite(parent Container) (*Composite, error) {\n\treturn NewCompositeWithStyle(parent, 0)\n}\n"
  },
  {
    "path": "condition.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype Condition interface {\n\tExpression\n\tSatisfied() bool\n}\n\ntype MutableCondition struct {\n\tsatisfied        bool\n\tchangedPublisher EventPublisher\n}\n\nfunc NewMutableCondition() *MutableCondition {\n\treturn new(MutableCondition)\n}\n\nfunc (mc *MutableCondition) Value() interface{} {\n\treturn mc.satisfied\n}\n\nfunc (mc *MutableCondition) Satisfied() bool {\n\treturn mc.satisfied\n}\n\nfunc (mc *MutableCondition) SetSatisfied(satisfied bool) error {\n\tif satisfied == mc.satisfied {\n\t\treturn nil\n\t}\n\n\tmc.satisfied = satisfied\n\n\tmc.changedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (mc *MutableCondition) Changed() *Event {\n\treturn mc.changedPublisher.Event()\n}\n\ntype DelegateCondition struct {\n\tsatisfied func() bool\n\tchanged   *Event\n}\n\nfunc NewDelegateCondition(satisfied func() bool, changed *Event) *DelegateCondition {\n\treturn &DelegateCondition{satisfied, changed}\n}\n\nfunc (dc *DelegateCondition) Value() interface{} {\n\treturn dc.satisfied()\n}\n\nfunc (dc *DelegateCondition) Satisfied() bool {\n\treturn dc.satisfied()\n}\n\nfunc (dc *DelegateCondition) Changed() *Event {\n\treturn dc.changed\n}\n\ntype compositeCondition struct {\n\titems               []Condition\n\titemsChangedHandles []int\n\tchangedPublisher    EventPublisher\n}\n\nfunc (cc *compositeCondition) init(items []Condition) {\n\tcc.items = append(cc.items, items...)\n\n\tfor _, item := range items {\n\t\thandle := item.Changed().Attach(func() {\n\t\t\tcc.changedPublisher.Publish()\n\t\t})\n\t\tcc.itemsChangedHandles = append(cc.itemsChangedHandles, handle)\n\t}\n}\n\nfunc (cc *compositeCondition) satisfied(all bool) bool {\n\tfor _, item := range cc.items {\n\t\tif all != item.Satisfied() {\n\t\t\treturn !all\n\t\t}\n\t}\n\n\treturn all\n}\n\nfunc (cc *compositeCondition) Changed() *Event {\n\treturn cc.changedPublisher.Event()\n}\n\nfunc (cc *compositeCondition) Dispose() {\n\tfor i, item := range cc.items {\n\t\titem.Changed().Detach(cc.itemsChangedHandles[i])\n\t}\n}\n\ntype allCondition struct {\n\tcompositeCondition\n}\n\nfunc NewAllCondition(items ...Condition) Condition {\n\tac := new(allCondition)\n\n\tac.init(items)\n\n\treturn ac\n}\n\nfunc (ac *allCondition) Value() interface{} {\n\treturn ac.Satisfied()\n}\n\nfunc (ac *allCondition) Satisfied() bool {\n\treturn ac.satisfied(true)\n}\n\ntype anyCondition struct {\n\tcompositeCondition\n}\n\nfunc NewAnyCondition(items ...Condition) Condition {\n\tac := new(anyCondition)\n\n\tac.init(items)\n\n\treturn ac\n}\n\nfunc (ac *anyCondition) Value() interface{} {\n\treturn ac.Satisfied()\n}\n\nfunc (ac *anyCondition) Satisfied() bool {\n\treturn ac.satisfied(false)\n}\n\ntype negatedCondition struct {\n\tother Condition\n}\n\nfunc NewNegatedCondition(other Condition) Condition {\n\treturn &negatedCondition{other}\n}\n\nfunc (nc *negatedCondition) Value() interface{} {\n\treturn nc.Satisfied()\n}\n\nfunc (nc *negatedCondition) Satisfied() bool {\n\treturn !nc.other.Satisfied()\n}\n\nfunc (nc *negatedCondition) Changed() *Event {\n\treturn nc.other.Changed()\n}\n"
  },
  {
    "path": "container.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype Container interface {\n\tWindow\n\tAsContainerBase() *ContainerBase\n\tChildren() *WidgetList\n\tLayout() Layout\n\tSetLayout(value Layout) error\n\tDataBinder() *DataBinder\n\tSetDataBinder(dbm *DataBinder)\n}\n\ntype ContainerBase struct {\n\tWidgetBase\n\tlayout      Layout\n\tchildren    *WidgetList\n\tdataBinder  *DataBinder\n\tnextChildID int32\n\tpersistent  bool\n}\n\nfunc (cb *ContainerBase) AsWidgetBase() *WidgetBase {\n\treturn &cb.WidgetBase\n}\n\nfunc (cb *ContainerBase) AsContainerBase() *ContainerBase {\n\treturn cb\n}\n\nfunc (cb *ContainerBase) NextChildID() int32 {\n\tcb.nextChildID++\n\treturn cb.nextChildID\n}\n\nfunc (cb *ContainerBase) applyEnabled(enabled bool) {\n\tcb.WidgetBase.applyEnabled(enabled)\n\n\tapplyEnabledToDescendants(cb.window.(Widget), enabled)\n\n\tif InteractionEffect != nil {\n\t\tfor _, wb := range cb.children.items {\n\t\t\tif wb.GraphicsEffects().Contains(InteractionEffect) {\n\t\t\t\twb.invalidateBorderInParent()\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (cb *ContainerBase) applyFont(font *Font) {\n\tcb.WidgetBase.applyFont(font)\n\n\tapplyFontToDescendants(cb.window.(Widget), font)\n}\n\nfunc (cb *ContainerBase) ApplySysColors() {\n\tcb.WidgetBase.ApplySysColors()\n\n\tapplySysColorsToDescendants(cb.window.(Widget))\n}\n\nfunc (cb *ContainerBase) ApplyDPI(dpi int) {\n\tcb.WidgetBase.ApplyDPI(dpi)\n\n\tapplyDPIToDescendants(cb.window.(Widget), dpi)\n\n\tif cb.layout != nil {\n\t\tif ums, ok := cb.layout.(interface {\n\t\t\tupdateMargins()\n\t\t\tupdateSpacing()\n\t\t}); ok {\n\t\t\tums.updateMargins()\n\t\t\tums.updateSpacing()\n\t\t}\n\n\t\tcb.RequestLayout()\n\t}\n}\n\nfunc (cb *ContainerBase) Children() *WidgetList {\n\treturn cb.children\n}\n\nfunc (cb *ContainerBase) Layout() Layout {\n\treturn cb.layout\n}\n\nfunc (cb *ContainerBase) SetLayout(value Layout) error {\n\tif cb.layout != value {\n\t\tif cb.layout != nil {\n\t\t\tcb.layout.SetContainer(nil)\n\t\t}\n\n\t\tcb.layout = value\n\n\t\tif value != nil && value.Container() != Container(cb) {\n\t\t\tvalue.SetContainer(cb)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (cb *ContainerBase) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn cb.layout.CreateLayoutItem(ctx)\n}\n\nfunc (cb *ContainerBase) DataBinder() *DataBinder {\n\treturn cb.dataBinder\n}\n\nfunc (cb *ContainerBase) SetDataBinder(db *DataBinder) {\n\tif db == cb.dataBinder {\n\t\treturn\n\t}\n\n\tif cb.dataBinder != nil {\n\t\tcb.dataBinder.SetBoundWidgets(nil)\n\t}\n\n\tcb.dataBinder = db\n\n\tif db != nil {\n\t\tvar boundWidgets []Widget\n\n\t\twalkDescendants(cb.window, func(w Window) bool {\n\t\t\tif w.Handle() == cb.hWnd {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tif c, ok := w.(Container); ok && c.DataBinder() != nil {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tfor _, prop := range w.AsWindowBase().name2Property {\n\t\t\t\tif _, ok := prop.Source().(string); ok {\n\t\t\t\t\tboundWidgets = append(boundWidgets, w.(Widget))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true\n\t\t})\n\n\t\tdb.SetBoundWidgets(boundWidgets)\n\t}\n}\n\nfunc (cb *ContainerBase) forEachPersistableChild(f func(p Persistable) error) error {\n\tif cb.children == nil {\n\t\treturn nil\n\t}\n\n\tfor _, wb := range cb.children.items {\n\t\tif persistable, ok := wb.window.(Persistable); ok && persistable.Persistent() {\n\t\t\tif err := f(persistable); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (cb *ContainerBase) Persistent() bool {\n\treturn cb.persistent\n}\n\nfunc (cb *ContainerBase) SetPersistent(value bool) {\n\tcb.persistent = value\n}\n\nfunc (cb *ContainerBase) SaveState() error {\n\treturn cb.forEachPersistableChild(func(p Persistable) error {\n\t\treturn p.SaveState()\n\t})\n}\n\nfunc (cb *ContainerBase) RestoreState() error {\n\treturn cb.forEachPersistableChild(func(p Persistable) error {\n\t\treturn p.RestoreState()\n\t})\n}\n\nfunc (cb *ContainerBase) doPaint() error {\n\tvar ps win.PAINTSTRUCT\n\n\thdc := win.BeginPaint(cb.hWnd, &ps)\n\tdefer win.EndPaint(cb.hWnd, &ps)\n\n\tcanvas, err := newCanvasFromHDC(hdc)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer canvas.Dispose()\n\n\tfor _, wb := range cb.children.items {\n\t\twidget := wb.window.(Widget)\n\n\t\tfor _, effect := range widget.GraphicsEffects().items {\n\t\t\tswitch effect {\n\t\t\tcase InteractionEffect:\n\t\t\t\ttype ReadOnlyer interface {\n\t\t\t\t\tReadOnly() bool\n\t\t\t\t}\n\t\t\t\tif ro, ok := widget.(ReadOnlyer); ok {\n\t\t\t\t\tif ro.ReadOnly() {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif hwnd := widget.Handle(); !win.IsWindowEnabled(hwnd) || !win.IsWindowVisible(hwnd) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\tcase FocusEffect:\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tb := widget.BoundsPixels().toRECT()\n\t\t\twin.ExcludeClipRect(hdc, b.Left, b.Top, b.Right, b.Bottom)\n\n\t\t\tif err := effect.Draw(widget, canvas); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tif FocusEffect != nil {\n\t\thwndFocused := win.GetFocus()\n\t\tvar widget Widget\n\t\tif wnd := windowFromHandle(hwndFocused); wnd != nil {\n\t\t\twidget, _ = wnd.(Widget)\n\t\t}\n\t\tfor hwndFocused != 0 && (widget == nil || widget.Parent() == nil) {\n\t\t\thwndFocused = win.GetParent(hwndFocused)\n\t\t\tif wnd := windowFromHandle(hwndFocused); wnd != nil {\n\t\t\t\twidget, _ = wnd.(Widget)\n\t\t\t}\n\t\t}\n\n\t\tif widget != nil && widget.Parent() != nil && widget.Parent().Handle() == cb.hWnd {\n\t\t\tfor _, effect := range widget.GraphicsEffects().items {\n\t\t\t\tif effect == FocusEffect {\n\t\t\t\t\tb := widget.BoundsPixels().toRECT()\n\t\t\t\t\twin.ExcludeClipRect(hdc, b.Left, b.Top, b.Right, b.Bottom)\n\n\t\t\t\t\tif err := FocusEffect.Draw(widget, canvas); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (cb *ContainerBase) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_CTLCOLOREDIT, win.WM_CTLCOLORSTATIC:\n\t\tif hBrush := cb.handleWMCTLCOLOR(wParam, lParam); hBrush != 0 {\n\t\t\treturn hBrush\n\t\t}\n\n\tcase win.WM_PAINT:\n\t\tif FocusEffect == nil && InteractionEffect == nil && ValidationErrorEffect == nil {\n\t\t\tbreak\n\t\t}\n\n\t\t// If it fails, what can we do about it? Panic? That's extreme. So just ignore it.\n\t\t_ = cb.doPaint()\n\n\t\treturn 0\n\n\tcase win.WM_COMMAND:\n\t\tif lParam == 0 {\n\t\t\tswitch win.HIWORD(uint32(wParam)) {\n\t\t\tcase 0:\n\t\t\t\tcmdId := win.LOWORD(uint32(wParam))\n\t\t\t\tswitch cmdId {\n\t\t\t\tcase win.IDOK, win.IDCANCEL:\n\t\t\t\t\tform := ancestor(cb)\n\t\t\t\t\tif form == nil {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\n\t\t\t\t\tdlg, ok := form.(dialogish)\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\n\t\t\t\t\tvar button *PushButton\n\t\t\t\t\tif cmdId == win.IDOK {\n\t\t\t\t\t\tbutton = dlg.DefaultButton()\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbutton = dlg.CancelButton()\n\t\t\t\t\t}\n\n\t\t\t\t\tif button != nil && button.Visible() && button.Enabled() {\n\t\t\t\t\t\tbutton.raiseClicked()\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t// Menu\n\t\t\t\tactionId := uint16(win.LOWORD(uint32(wParam)))\n\t\t\t\tif action, ok := actionsById[actionId]; ok {\n\t\t\t\t\taction.raiseTriggered()\n\t\t\t\t\treturn 0\n\t\t\t\t}\n\n\t\t\tcase 1:\n\t\t\t\t// Accelerator\n\t\t\t}\n\t\t} else {\n\t\t\t// The window that sent the notification shall handle it itself.\n\t\t\thwndSrc := win.GetDlgItem(cb.hWnd, int32(win.LOWORD(uint32(wParam))))\n\n\t\t\tvar toolBarOnly bool\n\t\t\tif hwndSrc == 0 {\n\t\t\t\ttoolBarOnly = true\n\t\t\t\thwndSrc = win.HWND(lParam)\n\t\t\t}\n\n\t\t\tif window := windowFromHandle(hwndSrc); window != nil {\n\t\t\t\tif _, ok := window.(*ToolBar); toolBarOnly && !ok {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\twindow.WndProc(hwnd, msg, wParam, lParam)\n\t\t\t\treturn 0\n\t\t\t}\n\t\t}\n\n\tcase win.WM_MEASUREITEM:\n\t\tmis := (*win.MEASUREITEMSTRUCT)(unsafe.Pointer(lParam))\n\t\tif window := windowFromHandle(win.GetDlgItem(hwnd, int32(mis.CtlID))); window != nil {\n\t\t\t// The window that sent the notification shall handle it itself.\n\t\t\treturn window.WndProc(hwnd, msg, wParam, lParam)\n\t\t}\n\n\tcase win.WM_DRAWITEM:\n\t\tdis := (*win.DRAWITEMSTRUCT)(unsafe.Pointer(lParam))\n\t\tif window := windowFromHandle(dis.HwndItem); window != nil {\n\t\t\t// The window that sent the notification shall handle it itself.\n\t\t\treturn window.WndProc(hwnd, msg, wParam, lParam)\n\t\t}\n\n\tcase win.WM_NOTIFY:\n\t\tnmh := (*win.NMHDR)(unsafe.Pointer(lParam))\n\t\tif window := windowFromHandle(nmh.HwndFrom); window != nil {\n\t\t\t// The window that sent the notification shall handle it itself.\n\t\t\treturn window.WndProc(hwnd, msg, wParam, lParam)\n\t\t}\n\n\tcase win.WM_HSCROLL, win.WM_VSCROLL:\n\t\tif window := windowFromHandle(win.HWND(lParam)); window != nil {\n\t\t\t// The window that sent the notification shall handle it itself.\n\t\t\treturn window.WndProc(hwnd, msg, wParam, lParam)\n\t\t}\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 || cb.Layout() == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tif cb.background == nullBrushSingleton {\n\t\t\tcb.Invalidate()\n\t\t}\n\t}\n\n\treturn cb.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (cb *ContainerBase) onInsertingWidget(index int, widget Widget) (err error) {\n\treturn nil\n}\n\nfunc (cb *ContainerBase) onInsertedWidget(index int, widget Widget) (err error) {\n\tif parent := widget.Parent(); parent == nil || parent.Handle() != cb.hWnd {\n\t\tif err = widget.SetParent(cb.window.(Container)); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\tcb.RequestLayout()\n\n\twidget.(applyFonter).applyFont(cb.Font())\n\n\treturn\n}\n\nfunc (cb *ContainerBase) onRemovingWidget(index int, widget Widget) (err error) {\n\tif widget.Parent() == nil {\n\t\treturn\n\t}\n\n\tif widget.Parent().Handle() == cb.hWnd {\n\t\terr = widget.SetParent(nil)\n\t}\n\n\treturn\n}\n\nfunc (cb *ContainerBase) onRemovedWidget(index int, widget Widget) (err error) {\n\tcb.RequestLayout()\n\n\treturn\n}\n\nfunc (cb *ContainerBase) onClearingWidgets() (err error) {\n\tfor i := cb.children.Len() - 1; i >= 0; i-- {\n\t\twidget := cb.children.At(i)\n\n\t\tif parent := widget.Parent(); parent != nil && parent.Handle() == cb.hWnd {\n\t\t\tif err = widget.SetParent(nil); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (cb *ContainerBase) onClearedWidgets() (err error) {\n\tcb.RequestLayout()\n\n\treturn\n}\n\nfunc (cb *ContainerBase) focusFirstCandidateDescendant() {\n\twindow := firstFocusableDescendant(cb)\n\tif window == nil {\n\t\treturn\n\t}\n\n\tif err := window.SetFocus(); err != nil {\n\t\treturn\n\t}\n\n\tif textSel, ok := window.(textSelectable); ok {\n\t\ttime.AfterFunc(time.Millisecond, func() {\n\t\t\twindow.Synchronize(func() {\n\t\t\t\tif window.Focused() {\n\t\t\t\t\ttextSel.SetTextSelection(0, -1)\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t}\n}\n\nfunc firstFocusableDescendantCallback(hwnd win.HWND, lParam uintptr) uintptr {\n\tif !win.IsWindowVisible(hwnd) || !win.IsWindowEnabled(hwnd) {\n\t\treturn 1\n\t}\n\n\tif win.GetWindowLong(hwnd, win.GWL_STYLE)&win.WS_TABSTOP > 0 {\n\t\tif rb, ok := windowFromHandle(hwnd).(radioButtonish); ok {\n\t\t\tif !rb.radioButton().Checked() {\n\t\t\t\treturn 1\n\t\t\t}\n\t\t}\n\n\t\thwndPtr := (*win.HWND)(unsafe.Pointer(lParam))\n\t\t*hwndPtr = hwnd\n\t\treturn 0\n\t}\n\n\treturn 1\n}\n\nvar firstFocusableDescendantCallbackPtr uintptr\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tfirstFocusableDescendantCallbackPtr = syscall.NewCallback(firstFocusableDescendantCallback)\n\t})\n}\n\nfunc firstFocusableDescendant(container Container) Window {\n\tvar hwnd win.HWND\n\n\twin.EnumChildWindows(container.Handle(), firstFocusableDescendantCallbackPtr, uintptr(unsafe.Pointer(&hwnd)))\n\n\twindow := windowFromHandle(hwnd)\n\n\tfor hwnd != 0 && window == nil {\n\t\thwnd = win.GetParent(hwnd)\n\t\twindow = windowFromHandle(hwnd)\n\t}\n\n\treturn window\n}\n\ntype textSelectable interface {\n\tSetTextSelection(start, end int)\n}\n\nfunc DescendantByName(container Container, name string) Widget {\n\tvar widget Widget\n\n\twalkDescendants(container.AsContainerBase(), func(w Window) bool {\n\t\tif w.Name() == name {\n\t\t\twidget = w.(Widget)\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t})\n\n\tif widget == nil {\n\t\treturn nil\n\t}\n\n\treturn widget\n}\n"
  },
  {
    "path": "cursor.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"image\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype Cursor interface {\n\tDispose()\n\thandle() win.HCURSOR\n}\n\ntype stockCursor struct {\n\thCursor win.HCURSOR\n}\n\nfunc (sc stockCursor) Dispose() {\n\t// nop\n}\n\nfunc (sc stockCursor) handle() win.HCURSOR {\n\treturn sc.hCursor\n}\n\nfunc CursorArrow() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_ARROW))}\n}\n\nfunc CursorIBeam() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_IBEAM))}\n}\n\nfunc CursorWait() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_WAIT))}\n}\n\nfunc CursorCross() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_CROSS))}\n}\n\nfunc CursorUpArrow() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_UPARROW))}\n}\n\nfunc CursorSizeNWSE() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_SIZENWSE))}\n}\n\nfunc CursorSizeNESW() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_SIZENESW))}\n}\n\nfunc CursorSizeWE() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_SIZEWE))}\n}\n\nfunc CursorSizeNS() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_SIZENS))}\n}\n\nfunc CursorSizeAll() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_SIZEALL))}\n}\n\nfunc CursorNo() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_NO))}\n}\n\nfunc CursorHand() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_HAND))}\n}\n\nfunc CursorAppStarting() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_APPSTARTING))}\n}\n\nfunc CursorHelp() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_HELP))}\n}\n\nfunc CursorIcon() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_ICON))}\n}\n\nfunc CursorSize() Cursor {\n\treturn stockCursor{win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_SIZE))}\n}\n\ntype customCursor struct {\n\thCursor win.HCURSOR\n}\n\nfunc NewCursorFromImage(im image.Image, hotspot image.Point) (Cursor, error) {\n\ti, err := createAlphaCursorOrIconFromImage(im, hotspot, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn customCursor{win.HCURSOR(i)}, nil\n}\n\nfunc (cc customCursor) Dispose() {\n\twin.DestroyIcon(win.HICON(cc.hCursor))\n}\n\nfunc (cc customCursor) handle() win.HCURSOR {\n\treturn cc.hCursor\n}\n"
  },
  {
    "path": "customwidget.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst customWidgetWindowClass = `\\o/ Walk_CustomWidget_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(customWidgetWindowClass)\n\t})\n}\n\n// PaintFunc paints custom widget content. updateBounds is specified in 1/96\" or native pixels.\ntype PaintFunc func(canvas *Canvas, updateBounds Rectangle) error\n\ntype PaintMode int\n\nconst (\n\tPaintNormal   PaintMode = iota // erase background before PaintFunc\n\tPaintNoErase                   // PaintFunc clears background, single buffered\n\tPaintBuffered                  // PaintFunc clears background, double buffered\n)\n\ntype CustomWidget struct {\n\tWidgetBase\n\tpaint               PaintFunc // in 1/96\" units\n\tpaintPixels         PaintFunc // in native pixels\n\tinvalidatesOnResize bool\n\tpaintMode           PaintMode\n}\n\n// NewCustomWidget creates and initializes a new custom draw widget.\n//\n// Deprecated: PaintFunc is taking updateBounds parameter at 96dpi for backward compatibility with\n// clients. On high-DPI displays this is too sparse and may incur a thin unpainted edge around\n// control due to rounding errors. Newer applications should use NewCustomWidgetPixels.\nfunc NewCustomWidget(parent Container, style uint, paint PaintFunc) (*CustomWidget, error) {\n\tcw := &CustomWidget{paint: paint}\n\terr := cw.init(parent, style)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn cw, nil\n}\n\n// NewCustomWidgetPixels creates and initializes a new custom draw widget.\nfunc NewCustomWidgetPixels(parent Container, style uint, paintPixels PaintFunc) (*CustomWidget, error) {\n\tcw := &CustomWidget{paintPixels: paintPixels}\n\terr := cw.init(parent, style)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn cw, nil\n}\n\nfunc (cw *CustomWidget) init(parent Container, style uint) error {\n\tif err := InitWidget(\n\t\tcw,\n\t\tparent,\n\t\tcustomWidgetWindowClass,\n\t\twin.WS_VISIBLE|uint32(style),\n\t\t0); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// deprecated, use PaintMode\nfunc (cw *CustomWidget) ClearsBackground() bool {\n\treturn cw.paintMode != PaintNormal\n}\n\n// deprecated, use SetPaintMode\nfunc (cw *CustomWidget) SetClearsBackground(value bool) {\n\tif value != cw.ClearsBackground() {\n\t\tif value {\n\t\t\tcw.paintMode = PaintNormal\n\t\t} else {\n\t\t\tcw.paintMode = PaintNoErase\n\t\t}\n\t}\n}\n\nfunc (cw *CustomWidget) InvalidatesOnResize() bool {\n\treturn cw.invalidatesOnResize\n}\n\nfunc (cw *CustomWidget) SetInvalidatesOnResize(value bool) {\n\tcw.invalidatesOnResize = value\n}\n\nfunc (cw *CustomWidget) PaintMode() PaintMode {\n\treturn cw.paintMode\n}\n\nfunc (cw *CustomWidget) SetPaintMode(value PaintMode) {\n\tcw.paintMode = value\n}\n\nfunc (cw *CustomWidget) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_PAINT:\n\t\tif cw.paint == nil && cw.paintPixels == nil {\n\t\t\tnewError(\"paint(Pixels) func is nil\")\n\t\t\tbreak\n\t\t}\n\n\t\tvar ps win.PAINTSTRUCT\n\n\t\tvar hdc win.HDC\n\t\tif wParam == 0 {\n\t\t\thdc = win.BeginPaint(cw.hWnd, &ps)\n\t\t} else {\n\t\t\thdc = win.HDC(wParam)\n\t\t}\n\t\tif hdc == 0 {\n\t\t\tnewError(\"BeginPaint failed\")\n\t\t\tbreak\n\t\t}\n\t\tdefer func() {\n\t\t\tif wParam == 0 {\n\t\t\t\twin.EndPaint(cw.hWnd, &ps)\n\t\t\t}\n\t\t}()\n\n\t\tcanvas, err := newCanvasFromHDC(hdc)\n\t\tif err != nil {\n\t\t\tnewError(\"newCanvasFromHDC failed\")\n\t\t\tbreak\n\t\t}\n\t\tdefer canvas.Dispose()\n\n\t\tbounds := rectangleFromRECT(ps.RcPaint)\n\t\tif cw.paintMode == PaintBuffered {\n\t\t\terr = cw.bufferedPaint(canvas, bounds)\n\t\t} else if cw.paintPixels != nil {\n\t\t\terr = cw.paintPixels(canvas, bounds)\n\t\t} else {\n\t\t\terr = cw.paint(canvas, RectangleTo96DPI(bounds, cw.DPI()))\n\t\t}\n\n\t\tif err != nil {\n\t\t\tnewError(\"paint failed\")\n\t\t\tbreak\n\t\t}\n\n\t\treturn 0\n\n\tcase win.WM_ERASEBKGND:\n\t\tif cw.paintMode != PaintNormal {\n\t\t\treturn 1\n\t\t}\n\n\tcase win.WM_PRINTCLIENT:\n\t\twin.SendMessage(hwnd, win.WM_PAINT, wParam, lParam)\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif cw.invalidatesOnResize {\n\t\t\tcw.Invalidate()\n\t\t}\n\t}\n\n\treturn cw.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\n// bufferedPaint draws widget on a memory buffer. updateBounds are in native pixels.\nfunc (cw *CustomWidget) bufferedPaint(canvas *Canvas, updateBounds Rectangle) error {\n\thdc := win.CreateCompatibleDC(canvas.hdc)\n\tif hdc == 0 {\n\t\treturn newError(\"CreateCompatibleDC failed\")\n\t}\n\tdefer win.DeleteDC(hdc)\n\n\tbuffered := Canvas{hdc: hdc, doNotDispose: true}\n\tif _, err := buffered.init(); err != nil {\n\t\treturn err\n\t}\n\n\tw, h := int32(updateBounds.Width), int32(updateBounds.Height)\n\tif w < 1 {\n\t\tw = 1\n\t}\n\tif h < 1 {\n\t\th = 1\n\t}\n\thbmp := win.CreateCompatibleBitmap(canvas.hdc, w, h)\n\tif hbmp == 0 {\n\t\treturn lastError(\"CreateCompatibleBitmap failed\")\n\t}\n\tdefer win.DeleteObject(win.HGDIOBJ(hbmp))\n\n\toldbmp := win.SelectObject(buffered.hdc, win.HGDIOBJ(hbmp))\n\tif oldbmp == 0 {\n\t\treturn newError(\"SelectObject failed\")\n\t}\n\tdefer win.SelectObject(buffered.hdc, oldbmp)\n\n\twin.SetViewportOrgEx(buffered.hdc, -int32(updateBounds.X), -int32(updateBounds.Y), nil)\n\twin.SetBrushOrgEx(buffered.hdc, -int32(updateBounds.X), -int32(updateBounds.Y), nil)\n\n\tvar err error\n\tif cw.paintPixels != nil {\n\t\terr = cw.paintPixels(&buffered, updateBounds)\n\t} else {\n\t\terr = cw.paint(&buffered, RectangleTo96DPI(updateBounds, cw.DPI()))\n\t}\n\n\tif !win.BitBlt(canvas.hdc,\n\t\tint32(updateBounds.X), int32(updateBounds.Y), w, h,\n\t\tbuffered.hdc,\n\t\tint32(updateBounds.X), int32(updateBounds.Y), win.SRCCOPY) {\n\t\treturn lastError(\"buffered BitBlt failed\")\n\t}\n\n\treturn err\n}\n\nfunc (*CustomWidget) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn NewGreedyLayoutItem()\n}\n"
  },
  {
    "path": "databinding.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"time\"\n)\n\nvar (\n\terrValidationFailed = errors.New(\"validation failed\")\n)\n\ntype ErrorPresenter interface {\n\tPresentError(err error, widget Widget)\n}\n\ntype DataBinder struct {\n\tdataSource                 interface{}\n\tboundWidgets               []Widget\n\tproperties                 []Property\n\tproperty2Widget            map[Property]Widget\n\tproperty2ChangedHandle     map[Property]int\n\trootExpression             Expression\n\tpath2Expression            map[string]Expression\n\terrorPresenter             ErrorPresenter\n\tdataSourceChangedPublisher EventPublisher\n\tcanSubmitChangedPublisher  EventPublisher\n\tsubmittedPublisher         EventPublisher\n\tresetPublisher             EventPublisher\n\tautoSubmitDelay            time.Duration\n\tautoSubmitTimer            *time.Timer\n\tautoSubmit                 bool\n\tautoSubmitSuspended        bool\n\tcanSubmit                  bool\n\tinReset                    bool\n\tdirty                      bool\n}\n\nfunc NewDataBinder() *DataBinder {\n\tdb := new(DataBinder)\n\n\tdb.rootExpression = &dataBinderRootExpression{db}\n\n\treturn db\n}\n\nfunc (db *DataBinder) AutoSubmit() bool {\n\treturn db.autoSubmit\n}\n\nfunc (db *DataBinder) SetAutoSubmit(autoSubmit bool) {\n\tdb.autoSubmit = autoSubmit\n\tif autoSubmit {\n\t\tdb.canSubmit = true\n\t}\n}\n\nfunc (db *DataBinder) AutoSubmitDelay() time.Duration {\n\treturn db.autoSubmitDelay\n}\n\nfunc (db *DataBinder) SetAutoSubmitDelay(delay time.Duration) {\n\tdb.autoSubmitDelay = delay\n}\n\nfunc (db *DataBinder) AutoSubmitSuspended() bool {\n\treturn db.autoSubmitSuspended\n}\n\nfunc (db *DataBinder) SetAutoSubmitSuspended(suspended bool) {\n\tif suspended == db.autoSubmitSuspended {\n\t\treturn\n\t}\n\n\tdb.autoSubmitSuspended = suspended\n\n\tif suspended {\n\t\tif db.autoSubmitTimer != nil {\n\t\t\tdb.autoSubmitTimer.Stop()\n\t\t}\n\t} else {\n\t\tdb.Submit()\n\t}\n}\n\nfunc (db *DataBinder) Submitted() *Event {\n\treturn db.submittedPublisher.Event()\n}\n\nfunc (db *DataBinder) DataSource() interface{} {\n\treturn db.dataSource\n}\n\nfunc (db *DataBinder) SetDataSource(dataSource interface{}) error {\n\tif kind := reflect.ValueOf(dataSource).Kind(); kind != reflect.Func && kind != reflect.Map && kind != reflect.Slice &&\n\t\tkind == reflect.ValueOf(db.dataSource).Kind() && dataSource == db.dataSource {\n\t\treturn nil\n\t}\n\n\tif dataSource != nil {\n\t\tif t := reflect.TypeOf(dataSource); t.Kind() != reflect.Map && (t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct) {\n\t\t\treturn newError(\"dataSource must be pointer to struct or map[string]interface{}\")\n\t\t}\n\t}\n\n\tdb.dataSource = dataSource\n\n\tdb.dataSourceChangedPublisher.Publish()\n\n\treturn nil\n}\n\ntype dataBinderRootExpression struct {\n\tdb *DataBinder\n}\n\nfunc (dbre *dataBinderRootExpression) Value() interface{} {\n\treturn dbre.db.dataSource\n}\n\nfunc (dbre *dataBinderRootExpression) Changed() *Event {\n\treturn dbre.db.resetPublisher.Event()\n}\n\nfunc (db *DataBinder) DataSourceChanged() *Event {\n\treturn db.dataSourceChangedPublisher.Event()\n}\n\nfunc (db *DataBinder) BoundWidgets() []Widget {\n\treturn db.boundWidgets\n}\n\nfunc (db *DataBinder) SetBoundWidgets(boundWidgets []Widget) {\n\tfor prop, handle := range db.property2ChangedHandle {\n\t\tprop.Changed().Detach(handle)\n\t}\n\n\tdb.boundWidgets = boundWidgets\n\n\tdb.property2Widget = make(map[Property]Widget)\n\tdb.property2ChangedHandle = make(map[Property]int)\n\n\tfor _, widget := range boundWidgets {\n\t\twidget := widget\n\n\t\tfor _, prop := range widget.AsWindowBase().name2Property {\n\t\t\tprop := prop\n\t\t\tif _, ok := prop.Source().(string); !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdb.properties = append(db.properties, prop)\n\t\t\tdb.property2Widget[prop] = widget\n\n\t\t\tdb.property2ChangedHandle[prop] = prop.Changed().Attach(func() {\n\t\t\t\tdb.dirty = true\n\n\t\t\t\tif db.autoSubmit && !db.autoSubmitSuspended {\n\t\t\t\t\tif db.autoSubmitDelay > 0 {\n\t\t\t\t\t\tif db.autoSubmitTimer == nil {\n\t\t\t\t\t\t\tdb.autoSubmitTimer = time.AfterFunc(db.autoSubmitDelay, func() {\n\t\t\t\t\t\t\t\twidget.Synchronize(func() {\n\t\t\t\t\t\t\t\t\tdb.Submit()\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdb.autoSubmitTimer.Reset(db.autoSubmitDelay)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tv := reflect.ValueOf(db.dataSource)\n\t\t\t\t\t\tfield := db.fieldBoundToProperty(v, prop)\n\t\t\t\t\t\tif field == nil {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif err := db.submitProperty(prop, field); err != nil {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdb.submittedPublisher.Publish()\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif !db.inReset {\n\t\t\t\t\t\tdb.validateProperties()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc (db *DataBinder) Expression(path string) Expression {\n\tif db.path2Expression == nil {\n\t\tdb.path2Expression = make(map[string]Expression)\n\t}\n\n\tif prop, ok := db.path2Expression[path]; ok {\n\t\treturn prop\n\t}\n\n\texpr := NewReflectExpression(db.rootExpression, path)\n\n\tdb.path2Expression[path] = expr\n\n\treturn expr\n}\n\nfunc (db *DataBinder) validateProperties() {\n\tvar hasError bool\n\n\tfor _, prop := range db.properties {\n\t\tvalidator := prop.Validator()\n\t\tif validator == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\terr := validator.Validate(prop.Get())\n\t\tif err != nil {\n\t\t\thasError = true\n\t\t}\n\n\t\tif db.errorPresenter != nil {\n\t\t\twidget := db.property2Widget[prop]\n\n\t\t\tdb.errorPresenter.PresentError(err, widget)\n\t\t}\n\t}\n\n\tif hasError == db.canSubmit {\n\t\tdb.canSubmit = !hasError\n\t\tdb.canSubmitChangedPublisher.Publish()\n\t}\n}\n\nfunc (db *DataBinder) ErrorPresenter() ErrorPresenter {\n\treturn db.errorPresenter\n}\n\nfunc (db *DataBinder) SetErrorPresenter(ep ErrorPresenter) {\n\tdb.errorPresenter = ep\n}\n\nfunc (db *DataBinder) CanSubmit() bool {\n\treturn db.canSubmit\n}\n\nfunc (db *DataBinder) CanSubmitChanged() *Event {\n\treturn db.canSubmitChangedPublisher.Event()\n}\n\nfunc (db *DataBinder) Reset() error {\n\tdb.inReset = true\n\tdefer func() {\n\t\tdb.inReset = false\n\t}()\n\n\tif err := db.forEach(func(prop Property, field DataField) error {\n\t\tif f64, ok := prop.Get().(float64); ok {\n\t\t\tswitch v := field.Get().(type) {\n\t\t\tcase float32:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase float64:\n\t\t\t\tf64 = v\n\n\t\t\tcase int:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase int8:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase int16:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase int32:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase int64:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase uint:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase uint8:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase uint16:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase uint32:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase uint64:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tcase uintptr:\n\t\t\t\tf64 = float64(v)\n\n\t\t\tdefault:\n\t\t\t\treturn newError(fmt.Sprintf(\"Field '%s': Can't convert %T to float64.\", prop.Source().(string), field.Get()))\n\t\t\t}\n\n\t\t\tif err := prop.Set(f64); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tif err := prop.Set(field.Get()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tdb.validateProperties()\n\n\tdb.dirty = false\n\n\tdb.resetPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (db *DataBinder) ResetFinished() *Event {\n\treturn db.resetPublisher.Event()\n}\n\nfunc (db *DataBinder) Submit() error {\n\tif !db.CanSubmit() {\n\t\treturn errValidationFailed\n\t}\n\n\tif err := db.forEach(func(prop Property, field DataField) error {\n\t\treturn db.submitProperty(prop, field)\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tdb.dirty = false\n\n\tdb.submittedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (db *DataBinder) Dirty() bool {\n\treturn db.dirty\n}\n\nfunc (db *DataBinder) submitProperty(prop Property, field DataField) error {\n\tif !field.CanSet() {\n\t\t// FIXME: handle properly\n\t\treturn nil\n\t}\n\n\tvalue := prop.Get()\n\tif value == nil {\n\t\tif _, ok := db.property2Widget[prop].(*RadioButton); ok {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn field.Set(field.Zero())\n\t}\n\tif err, ok := value.(error); ok {\n\t\treturn err\n\t}\n\n\treturn field.Set(value)\n}\n\nfunc (db *DataBinder) forEach(f func(prop Property, field DataField) error) error {\n\tdsv := reflect.ValueOf(db.dataSource)\n\tif dsv.Kind() == reflect.Ptr && dsv.IsNil() {\n\t\treturn nil\n\t}\n\n\tfor _, prop := range db.properties {\n\t\t// if widget := db.property2Widget[prop]; !widget.Visible() {\n\t\t// \tcontinue\n\t\t// }\n\n\t\tfield := db.fieldBoundToProperty(dsv, prop)\n\t\tif field == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := f(prop, field); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (db *DataBinder) fieldBoundToProperty(v reflect.Value, prop Property) DataField {\n\tif db.dataSource == nil {\n\t\treturn nilField{prop: prop}\n\t}\n\n\tsource, ok := prop.Source().(string)\n\tif !ok || source == \"\" {\n\t\treturn nil\n\t}\n\n\tf, err := dataFieldFromPath(v, source)\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"invalid source '%s'\", source))\n\t}\n\n\treturn f\n}\n\nfunc validateBindingMemberSyntax(member string) error {\n\t// FIXME\n\treturn nil\n}\n\ntype DataField interface {\n\tCanSet() bool\n\tGet() interface{}\n\tSet(interface{}) error\n\tZero() interface{}\n}\n\nfunc dataFieldFromPath(root reflect.Value, path string) (DataField, error) {\n\tparent, value, err := reflectValueFromPath(root, path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// convert to DataField\n\tif i, ok := value.Interface().(DataField); ok {\n\t\treturn i, nil\n\t}\n\n\treturn &reflectField{parent: parent, value: value, key: path[strings.LastIndexByte(path, '.')+1:]}, nil\n}\n\nfunc reflectValueFromPath(root reflect.Value, path string) (parent, value reflect.Value, err error) {\n\tfullPath := path\n\tvalue = root\n\n\tfor path != \"\" {\n\t\tvar name string\n\t\tname, path = nextPathPart(path)\n\n\t\tvar p reflect.Value\n\t\tfor value.Kind() == reflect.Interface || value.Kind() == reflect.Ptr {\n\t\t\tp = value\n\t\t\tvalue = value.Elem()\n\t\t}\n\n\t\tswitch value.Kind() {\n\t\tcase reflect.Map:\n\t\t\tparent = value\n\t\t\tvalue = value.MapIndex(reflect.ValueOf(name))\n\n\t\tcase reflect.Struct:\n\t\t\tparent = value\n\n\t\t\tvar fun reflect.Value\n\n\t\t\t// Try as field first.\n\t\t\tif f := value.FieldByName(name); f.IsValid() {\n\t\t\t\tswitch f.Kind() {\n\t\t\t\tcase reflect.Func:\n\t\t\t\t\tfun = f\n\n\t\t\t\tcase reflect.Interface:\n\t\t\t\t\tif fn := f.Elem(); fn.Kind() == reflect.Func {\n\t\t\t\t\t\tfun = fn\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalue = f\n\t\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tvalue = f\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No field, so let's see if we got a method.\n\t\t\t\tif p.IsValid() {\n\t\t\t\t\t// Try pointer receiver first.\n\t\t\t\t\tfun = p.MethodByName(name)\n\t\t\t\t}\n\n\t\t\t\tif !fun.IsValid() {\n\t\t\t\t\t// No pointer, try directly.\n\t\t\t\t\tfun = value.MethodByName(name)\n\t\t\t\t}\n\t\t\t\tif !fun.IsValid() {\n\t\t\t\t\treturn parent, value, fmt.Errorf(\"bad member: '%s', path: '%s'\", path, fullPath)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif fun.IsValid() {\n\t\t\t\t// We assume it takes no args and returns one mandatory value plus\n\t\t\t\t// maybe an error.\n\t\t\t\trvs := fun.Call(nil)\n\t\t\t\tswitch len(rvs) {\n\t\t\t\tcase 1:\n\t\t\t\t\tvalue = rvs[0]\n\n\t\t\t\tcase 2:\n\t\t\t\t\trv2 := rvs[1].Interface()\n\t\t\t\t\tif err, ok := rv2.(error); ok {\n\t\t\t\t\t\treturn parent, value, err\n\t\t\t\t\t} else if rv2 != nil {\n\t\t\t\t\t\treturn parent, value, fmt.Errorf(\"Second method return value must implement error.\")\n\t\t\t\t\t}\n\n\t\t\t\t\tvalue = rvs[0]\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn parent, value, fmt.Errorf(\"Method must return a value plus optionally an error: %s\", name)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn parent, value, nil\n}\n\nfunc nextPathPart(p string) (next, remaining string) {\n\tfor i, r := range p {\n\t\tif r == '.' {\n\t\t\treturn p[:i], p[i+1:]\n\t\t}\n\t}\n\treturn p, \"\"\n}\n\ntype nilField struct {\n\tprop Property\n}\n\nfunc (nilField) CanSet() bool {\n\treturn false\n}\n\nfunc (f nilField) Get() interface{} {\n\treturn f.Zero()\n}\n\nfunc (nilField) Set(interface{}) error {\n\treturn nil\n}\n\nfunc (f nilField) Zero() interface{} {\n\treturn reflect.Zero(reflect.TypeOf(f.prop.Get())).Interface()\n}\n\ntype reflectField struct {\n\tparent reflect.Value\n\tvalue  reflect.Value\n\tkey    string\n}\n\nfunc (f *reflectField) CanSet() bool {\n\tif f.parent.IsValid() && f.parent.Kind() == reflect.Map {\n\t\treturn true\n\t}\n\n\treturn f.value.CanSet()\n}\n\nfunc (f *reflectField) Get() interface{} {\n\treturn f.value.Interface()\n}\n\nfunc (f *reflectField) Set(value interface{}) error {\n\tif f.parent.IsValid() && f.parent.Kind() == reflect.Map {\n\t\tf.parent.SetMapIndex(reflect.ValueOf(f.key), reflect.ValueOf(value))\n\t\treturn nil\n\t}\n\n\tif f64, ok := value.(float64); ok {\n\t\tswitch f.value.Kind() {\n\t\tcase reflect.Float32, reflect.Float64:\n\t\t\tf.value.SetFloat(f64)\n\n\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\t\tf.value.SetInt(int64(f64))\n\n\t\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:\n\t\t\tf.value.SetUint(uint64(f64))\n\n\t\tdefault:\n\t\t\treturn newError(fmt.Sprintf(\"Can't convert float64 to %s.\", f.value.Type().Name()))\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tf.value.Set(reflect.ValueOf(value))\n\n\treturn nil\n}\n\nfunc (f *reflectField) Zero() interface{} {\n\treturn reflect.Zero(f.value.Type()).Interface()\n}\n"
  },
  {
    "path": "dateedit.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype DateEdit struct {\n\tWidgetBase\n\tdateChangedPublisher EventPublisher\n\tformat               string\n}\n\nfunc newDateEdit(parent Container, style uint32) (*DateEdit, error) {\n\tde := new(DateEdit)\n\n\tif err := InitWidget(\n\t\tde,\n\t\tparent,\n\t\t\"SysDateTimePick32\",\n\t\twin.WS_TABSTOP|win.WS_VISIBLE|win.DTS_SHORTDATEFORMAT|style,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif style&win.DTS_SHOWNONE != 0 {\n\t\tde.setSystemTime(nil)\n\t}\n\n\tde.GraphicsEffects().Add(InteractionEffect)\n\tde.GraphicsEffects().Add(FocusEffect)\n\n\tde.MustRegisterProperty(\"Date\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn de.Date()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn de.SetDate(assertTimeOr(v, time.Time{}))\n\t\t},\n\t\tde.dateChangedPublisher.Event()))\n\n\treturn de, nil\n}\n\nfunc NewDateEdit(parent Container) (*DateEdit, error) {\n\treturn newDateEdit(parent, 0)\n}\n\nfunc NewDateEditWithNoneOption(parent Container) (*DateEdit, error) {\n\treturn newDateEdit(parent, win.DTS_SHOWNONE)\n}\n\nfunc (de *DateEdit) systemTimeToTime(st *win.SYSTEMTIME) time.Time {\n\tif st == nil || !de.hasStyleBits(win.DTS_SHOWNONE) && st.WYear == 1601 && st.WMonth == 1 && st.WDay == 1 {\n\t\treturn time.Time{}\n\t}\n\n\tvar hour, minute, second int\n\tif de.timeOfDayDisplayed() {\n\t\thour = int(st.WHour)\n\t\tminute = int(st.WMinute)\n\t\tsecond = int(st.WSecond)\n\t}\n\n\treturn time.Date(int(st.WYear), time.Month(st.WMonth), int(st.WDay), hour, minute, second, 0, time.Local)\n}\n\nfunc (de *DateEdit) timeToSystemTime(t time.Time) *win.SYSTEMTIME {\n\tif t.Year() < 1601 {\n\t\tif de.hasStyleBits(win.DTS_SHOWNONE) {\n\t\t\treturn nil\n\t\t} else {\n\t\t\treturn &win.SYSTEMTIME{\n\t\t\t\tWYear:  uint16(1601),\n\t\t\t\tWMonth: uint16(1),\n\t\t\t\tWDay:   uint16(1),\n\t\t\t}\n\t\t}\n\t}\n\n\tst := &win.SYSTEMTIME{\n\t\tWYear:  uint16(t.Year()),\n\t\tWMonth: uint16(t.Month()),\n\t\tWDay:   uint16(t.Day()),\n\t}\n\n\tif de.timeOfDayDisplayed() {\n\t\tst.WHour = uint16(t.Hour())\n\t\tst.WMinute = uint16(t.Minute())\n\t\tst.WSecond = uint16(t.Second())\n\t}\n\n\treturn st\n}\n\nfunc (de *DateEdit) systemTime() (*win.SYSTEMTIME, error) {\n\tvar st win.SYSTEMTIME\n\n\tswitch de.SendMessage(win.DTM_GETSYSTEMTIME, 0, uintptr(unsafe.Pointer(&st))) {\n\tcase win.GDT_VALID:\n\t\treturn &st, nil\n\n\tcase win.GDT_NONE:\n\t\treturn nil, nil\n\t}\n\n\treturn nil, newError(\"SendMessage(DTM_GETSYSTEMTIME)\")\n}\n\nfunc (de *DateEdit) setSystemTime(st *win.SYSTEMTIME) error {\n\tvar wParam uintptr\n\n\tif st != nil {\n\t\twParam = win.GDT_VALID\n\t} else {\n\t\t// Ensure today's date is displayed.\n\t\tde.setSystemTime(de.timeToSystemTime(time.Now()))\n\n\t\twParam = win.GDT_NONE\n\t}\n\n\tif 0 == de.SendMessage(win.DTM_SETSYSTEMTIME, wParam, uintptr(unsafe.Pointer(st))) {\n\t\treturn newError(\"SendMessage(DTM_SETSYSTEMTIME)\")\n\t}\n\n\treturn nil\n}\n\nfunc (de *DateEdit) timeOfDayDisplayed() bool {\n\treturn strings.ContainsAny(de.format, \"Hhms\")\n}\n\nfunc (de *DateEdit) Format() string {\n\treturn de.format\n}\n\nfunc (de *DateEdit) SetFormat(format string) error {\n\tlp := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(format)))\n\n\tif 0 == de.SendMessage(win.DTM_SETFORMAT, 0, lp) {\n\t\treturn newError(\"DTM_SETFORMAT failed\")\n\t}\n\n\tde.format = format\n\n\treturn nil\n}\n\nfunc (de *DateEdit) Range() (min, max time.Time) {\n\tvar st [2]win.SYSTEMTIME\n\n\tret := de.SendMessage(win.DTM_GETRANGE, 0, uintptr(unsafe.Pointer(&st[0])))\n\n\tif ret&win.GDTR_MIN > 0 {\n\t\tmin = de.systemTimeToTime(&st[0])\n\t}\n\n\tif ret&win.GDTR_MAX > 0 {\n\t\tmax = de.systemTimeToTime(&st[1])\n\t}\n\n\treturn\n}\n\nfunc (de *DateEdit) SetRange(min, max time.Time) error {\n\tif !min.IsZero() && !max.IsZero() {\n\t\tif min.Year() > max.Year() ||\n\t\t\tmin.Year() == max.Year() && min.Month() > max.Month() ||\n\t\t\tmin.Year() == max.Year() && min.Month() == max.Month() && min.Day() > max.Day() {\n\t\t\treturn newError(\"invalid range\")\n\t\t}\n\t}\n\n\tvar st [2]win.SYSTEMTIME\n\tvar wParam uintptr\n\n\tif !min.IsZero() {\n\t\twParam |= win.GDTR_MIN\n\t\tst[0] = *de.timeToSystemTime(min)\n\t}\n\n\tif !max.IsZero() {\n\t\twParam |= win.GDTR_MAX\n\t\tst[1] = *de.timeToSystemTime(max)\n\t}\n\n\tif 0 == de.SendMessage(win.DTM_SETRANGE, wParam, uintptr(unsafe.Pointer(&st[0]))) {\n\t\treturn newError(\"SendMessage(DTM_SETRANGE)\")\n\t}\n\n\treturn nil\n}\n\nfunc (de *DateEdit) Date() time.Time {\n\tst, err := de.systemTime()\n\tif err != nil || st == nil {\n\t\treturn time.Time{}\n\t}\n\n\treturn de.systemTimeToTime(st)\n}\n\nfunc (de *DateEdit) SetDate(date time.Time) error {\n\tstNew := de.timeToSystemTime(date)\n\tstOld, err := de.systemTime()\n\tif err != nil {\n\t\treturn err\n\t} else if stNew == stOld || stNew != nil && stOld != nil && *stNew == *stOld {\n\t\treturn nil\n\t}\n\n\tif err := de.setSystemTime(stNew); err != nil {\n\t\treturn err\n\t}\n\n\tde.dateChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (de *DateEdit) DateChanged() *Event {\n\treturn de.dateChangedPublisher.Event()\n}\n\nfunc (de *DateEdit) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_NOTIFY:\n\t\tswitch uint32(((*win.NMHDR)(unsafe.Pointer(lParam))).Code) {\n\t\tcase win.DTN_DATETIMECHANGE:\n\t\t\tde.dateChangedPublisher.Publish()\n\t\t}\n\t}\n\n\treturn de.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (*DateEdit) NeedsWmSize() bool {\n\treturn true\n}\n\nfunc (de *DateEdit) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn &dateEditLayoutItem{\n\t\tidealSize: de.dialogBaseUnitsToPixels(Size{80, 12}),\n\t}\n}\n\ntype dateEditLayoutItem struct {\n\tLayoutItemBase\n\tidealSize Size // in native pixels\n}\n\nfunc (*dateEditLayoutItem) LayoutFlags() LayoutFlags {\n\treturn GrowableHorz\n}\n\nfunc (li *dateEditLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *dateEditLayoutItem) MinSize() Size {\n\treturn li.idealSize\n}\n"
  },
  {
    "path": "datelabel.go",
    "content": "// Copyright 2018 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"time\"\n)\n\ntype DateLabel struct {\n\tstatic\n\tdate                   time.Time\n\tdateChangedPublisher   EventPublisher\n\tformat                 string\n\tformatChangedPublisher EventPublisher\n}\n\nfunc NewDateLabel(parent Container) (*DateLabel, error) {\n\tdl := new(DateLabel)\n\n\tif err := dl.init(dl, parent, 0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tdl.SetTextAlignment(AlignFar)\n\tif _, err := dl.updateText(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tdl.MustRegisterProperty(\"Date\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn dl.Date()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn dl.SetDate(assertTimeOr(v, time.Time{}))\n\t\t},\n\t\tdl.dateChangedPublisher.Event()))\n\n\tdl.MustRegisterProperty(\"Format\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn dl.Format()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn dl.SetFormat(assertStringOr(v, \"\"))\n\t\t},\n\t\tdl.formatChangedPublisher.Event()))\n\n\treturn dl, nil\n}\n\nfunc (dl *DateLabel) asStatic() *static {\n\treturn &dl.static\n}\n\nfunc (dl *DateLabel) TextAlignment() Alignment1D {\n\treturn dl.textAlignment1D()\n}\n\nfunc (dl *DateLabel) SetTextAlignment(alignment Alignment1D) error {\n\tif alignment == AlignDefault {\n\t\talignment = AlignNear\n\t}\n\n\treturn dl.setTextAlignment1D(alignment)\n}\n\nfunc (dl *DateLabel) Date() time.Time {\n\treturn dl.date\n}\n\nfunc (dl *DateLabel) SetDate(date time.Time) error {\n\tif date == dl.date {\n\t\treturn nil\n\t}\n\n\told := dl.date\n\n\tdl.date = date\n\n\tif _, err := dl.updateText(); err != nil {\n\t\tdl.date = old\n\t\treturn err\n\t}\n\n\tdl.dateChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (dl *DateLabel) Format() string {\n\treturn dl.format\n}\n\nfunc (dl *DateLabel) SetFormat(format string) error {\n\tif format == dl.format {\n\t\treturn nil\n\t}\n\n\told := dl.format\n\n\tdl.format = format\n\n\tif _, err := dl.updateText(); err != nil {\n\t\tdl.format = old\n\t\treturn err\n\t}\n\n\tdl.formatChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (dl *DateLabel) updateText() (changed bool, err error) {\n\treturn dl.setText(dl.date.Format(dl.format))\n}\n"
  },
  {
    "path": "declarative/accessibility.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\n// AccState enum defines the state of the window/control\ntype AccState int32\n\n// Window/control states\nconst (\n\tAccStateNormal          = AccState(walk.AccStateNormal)\n\tAccStateUnavailable     = AccState(walk.AccStateUnavailable)\n\tAccStateSelected        = AccState(walk.AccStateSelected)\n\tAccStateFocused         = AccState(walk.AccStateFocused)\n\tAccStatePressed         = AccState(walk.AccStatePressed)\n\tAccStateChecked         = AccState(walk.AccStateChecked)\n\tAccStateMixed           = AccState(walk.AccStateMixed)\n\tAccStateIndeterminate   = AccState(walk.AccStateIndeterminate)\n\tAccStateReadonly        = AccState(walk.AccStateReadonly)\n\tAccStateHotTracked      = AccState(walk.AccStateHotTracked)\n\tAccStateDefault         = AccState(walk.AccStateDefault)\n\tAccStateExpanded        = AccState(walk.AccStateExpanded)\n\tAccStateCollapsed       = AccState(walk.AccStateCollapsed)\n\tAccStateBusy            = AccState(walk.AccStateBusy)\n\tAccStateFloating        = AccState(walk.AccStateFloating)\n\tAccStateMarqueed        = AccState(walk.AccStateMarqueed)\n\tAccStateAnimated        = AccState(walk.AccStateAnimated)\n\tAccStateInvisible       = AccState(walk.AccStateInvisible)\n\tAccStateOffscreen       = AccState(walk.AccStateOffscreen)\n\tAccStateSizeable        = AccState(walk.AccStateSizeable)\n\tAccStateMoveable        = AccState(walk.AccStateMoveable)\n\tAccStateSelfVoicing     = AccState(walk.AccStateSelfVoicing)\n\tAccStateFocusable       = AccState(walk.AccStateFocusable)\n\tAccStateSelectable      = AccState(walk.AccStateSelectable)\n\tAccStateLinked          = AccState(walk.AccStateLinked)\n\tAccStateTraversed       = AccState(walk.AccStateTraversed)\n\tAccStateMultiselectable = AccState(walk.AccStateMultiselectable)\n\tAccStateExtselectable   = AccState(walk.AccStateExtselectable)\n\tAccStateAlertLow        = AccState(walk.AccStateAlertLow)\n\tAccStateAlertMedium     = AccState(walk.AccStateAlertMedium)\n\tAccStateAlertHigh       = AccState(walk.AccStateAlertHigh)\n\tAccStateProtected       = AccState(walk.AccStateProtected)\n\tAccStateHasPopup        = AccState(walk.AccStateHasPopup)\n\tAccStateValid           = AccState(walk.AccStateValid)\n)\n\n// AccRole enum defines the role of the window/control in UI.\ntype AccRole int32\n\n// Window/control system roles\nconst (\n\tAccRoleTitlebar           = AccRole(walk.AccRoleTitlebar)\n\tAccRoleMenubar            = AccRole(walk.AccRoleMenubar)\n\tAccRoleScrollbar          = AccRole(walk.AccRoleScrollbar)\n\tAccRoleGrip               = AccRole(walk.AccRoleGrip)\n\tAccRoleSound              = AccRole(walk.AccRoleSound)\n\tAccRoleCursor             = AccRole(walk.AccRoleCursor)\n\tAccRoleCaret              = AccRole(walk.AccRoleCaret)\n\tAccRoleAlert              = AccRole(walk.AccRoleAlert)\n\tAccRoleWindow             = AccRole(walk.AccRoleWindow)\n\tAccRoleClient             = AccRole(walk.AccRoleClient)\n\tAccRoleMenuPopup          = AccRole(walk.AccRoleMenuPopup)\n\tAccRoleMenuItem           = AccRole(walk.AccRoleMenuItem)\n\tAccRoleTooltip            = AccRole(walk.AccRoleTooltip)\n\tAccRoleApplication        = AccRole(walk.AccRoleApplication)\n\tAccRoleDocument           = AccRole(walk.AccRoleDocument)\n\tAccRolePane               = AccRole(walk.AccRolePane)\n\tAccRoleChart              = AccRole(walk.AccRoleChart)\n\tAccRoleDialog             = AccRole(walk.AccRoleDialog)\n\tAccRoleBorder             = AccRole(walk.AccRoleBorder)\n\tAccRoleGrouping           = AccRole(walk.AccRoleGrouping)\n\tAccRoleSeparator          = AccRole(walk.AccRoleSeparator)\n\tAccRoleToolbar            = AccRole(walk.AccRoleToolbar)\n\tAccRoleStatusbar          = AccRole(walk.AccRoleStatusbar)\n\tAccRoleTable              = AccRole(walk.AccRoleTable)\n\tAccRoleColumnHeader       = AccRole(walk.AccRoleColumnHeader)\n\tAccRoleRowHeader          = AccRole(walk.AccRoleRowHeader)\n\tAccRoleColumn             = AccRole(walk.AccRoleColumn)\n\tAccRoleRow                = AccRole(walk.AccRoleRow)\n\tAccRoleCell               = AccRole(walk.AccRoleCell)\n\tAccRoleLink               = AccRole(walk.AccRoleLink)\n\tAccRoleHelpBalloon        = AccRole(walk.AccRoleHelpBalloon)\n\tAccRoleCharacter          = AccRole(walk.AccRoleCharacter)\n\tAccRoleList               = AccRole(walk.AccRoleList)\n\tAccRoleListItem           = AccRole(walk.AccRoleListItem)\n\tAccRoleOutline            = AccRole(walk.AccRoleOutline)\n\tAccRoleOutlineItem        = AccRole(walk.AccRoleOutlineItem)\n\tAccRolePagetab            = AccRole(walk.AccRolePagetab)\n\tAccRolePropertyPage       = AccRole(walk.AccRolePropertyPage)\n\tAccRoleIndicator          = AccRole(walk.AccRoleIndicator)\n\tAccRoleGraphic            = AccRole(walk.AccRoleGraphic)\n\tAccRoleStatictext         = AccRole(walk.AccRoleStatictext)\n\tAccRoleText               = AccRole(walk.AccRoleText)\n\tAccRolePushbutton         = AccRole(walk.AccRolePushbutton)\n\tAccRoleCheckbutton        = AccRole(walk.AccRoleCheckbutton)\n\tAccRoleRadiobutton        = AccRole(walk.AccRoleRadiobutton)\n\tAccRoleCombobox           = AccRole(walk.AccRoleCombobox)\n\tAccRoleDroplist           = AccRole(walk.AccRoleDroplist)\n\tAccRoleProgressbar        = AccRole(walk.AccRoleProgressbar)\n\tAccRoleDial               = AccRole(walk.AccRoleDial)\n\tAccRoleHotkeyfield        = AccRole(walk.AccRoleHotkeyfield)\n\tAccRoleSlider             = AccRole(walk.AccRoleSlider)\n\tAccRoleSpinbutton         = AccRole(walk.AccRoleSpinbutton)\n\tAccRoleDiagram            = AccRole(walk.AccRoleDiagram)\n\tAccRoleAnimation          = AccRole(walk.AccRoleAnimation)\n\tAccRoleEquation           = AccRole(walk.AccRoleEquation)\n\tAccRoleButtonDropdown     = AccRole(walk.AccRoleButtonDropdown)\n\tAccRoleButtonMenu         = AccRole(walk.AccRoleButtonMenu)\n\tAccRoleButtonDropdownGrid = AccRole(walk.AccRoleButtonDropdownGrid)\n\tAccRoleWhitespace         = AccRole(walk.AccRoleWhitespace)\n\tAccRolePageTabList        = AccRole(walk.AccRolePageTabList)\n\tAccRoleClock              = AccRole(walk.AccRoleClock)\n\tAccRoleSplitButton        = AccRole(walk.AccRoleSplitButton)\n\tAccRoleIPAddress          = AccRole(walk.AccRoleIPAddress)\n\tAccRoleOutlineButton      = AccRole(walk.AccRoleOutlineButton)\n)\n\n// Accessibility properties\ntype Accessibility struct {\n\tAccelerator   string\n\tDefaultAction string\n\tDescription   string\n\tHelp          string\n\tName          string\n\tRole          AccRole\n\tRoleMap       string\n\tState         AccState\n\tStateMap      string\n\tValueMap      string\n}\n"
  },
  {
    "path": "declarative/action.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/lxn/walk\"\n)\n\ntype Shortcut struct {\n\tModifiers walk.Modifiers\n\tKey       walk.Key\n}\n\ntype Action struct {\n\tAssignTo    **walk.Action\n\tText        string\n\tImage       interface{}\n\tChecked     Property\n\tEnabled     Property\n\tVisible     Property\n\tShortcut    Shortcut\n\tOnTriggered walk.EventHandler\n\tCheckable   bool\n}\n\nfunc (a Action) createAction(builder *Builder, menu *walk.Menu) (*walk.Action, error) {\n\taction := walk.NewAction()\n\n\tif a.AssignTo != nil {\n\t\t*a.AssignTo = action\n\t}\n\n\tif err := action.SetText(a.Text); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := setActionImage(action, a.Image, builder.dpi); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setActionBoolOrCondition(action.SetChecked, action.SetCheckedCondition, a.Checked, \"Action.Checked\", builder); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := setActionBoolOrCondition(action.SetEnabled, action.SetEnabledCondition, a.Enabled, \"Action.Enabled\", builder); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := setActionBoolOrCondition(action.SetVisible, action.SetVisibleCondition, a.Visible, \"Action.Visible\", builder); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := action.SetCheckable(a.Checkable || action.CheckedCondition() != nil); err != nil {\n\t\treturn nil, err\n\t}\n\n\ts := a.Shortcut\n\tif err := action.SetShortcut(walk.Shortcut{s.Modifiers, s.Key}); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif a.OnTriggered != nil {\n\t\taction.Triggered().Attach(a.OnTriggered)\n\t}\n\n\tif menu != nil {\n\t\tif err := menu.Actions().Add(action); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn action, nil\n}\n\ntype ActionRef struct {\n\tAction **walk.Action\n}\n\nfunc (ar ActionRef) createAction(builder *Builder, menu *walk.Menu) (*walk.Action, error) {\n\tif menu != nil {\n\t\tif err := menu.Actions().Add(*ar.Action); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn *ar.Action, nil\n}\n\ntype Menu struct {\n\tAssignTo       **walk.Menu\n\tAssignActionTo **walk.Action\n\tText           string\n\tImage          interface{}\n\tEnabled        Property\n\tVisible        Property\n\tItems          []MenuItem\n\tOnTriggered    walk.EventHandler\n}\n\nfunc (m Menu) createAction(builder *Builder, menu *walk.Menu) (*walk.Action, error) {\n\tsubMenu, err := walk.NewMenu()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar action *walk.Action\n\tif menu == nil {\n\t\taction = walk.NewMenuAction(subMenu)\n\t} else if action, err = menu.Actions().AddMenu(subMenu); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := action.SetText(m.Text); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := setActionImage(action, m.Image, builder.dpi); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setActionBoolOrCondition(action.SetEnabled, action.SetEnabledCondition, m.Enabled, \"Menu.Enabled\", builder); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := setActionBoolOrCondition(action.SetVisible, action.SetVisibleCondition, m.Visible, \"Menu.Visible\", builder); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, item := range m.Items {\n\t\tif _, err := item.createAction(builder, subMenu); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif m.OnTriggered != nil {\n\t\taction.Triggered().Attach(m.OnTriggered)\n\t}\n\n\tif m.AssignActionTo != nil {\n\t\t*m.AssignActionTo = action\n\t}\n\tif m.AssignTo != nil {\n\t\t*m.AssignTo = subMenu\n\t}\n\n\treturn action, nil\n}\n\ntype Separator struct {\n}\n\nfunc (s Separator) createAction(builder *Builder, menu *walk.Menu) (*walk.Action, error) {\n\taction := walk.NewSeparatorAction()\n\n\tif menu != nil {\n\t\tif err := menu.Actions().Add(action); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn action, nil\n}\n\nfunc addToActionList(list *walk.ActionList, actions []*walk.Action) error {\n\tfor _, a := range actions {\n\t\tif err := list.Add(a); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc setActionImage(action *walk.Action, image interface{}, dpi int) (err error) {\n\tvar img walk.Image\n\n\tswitch image.(type) {\n\tcase *walk.Bitmap:\n\t\tif img, err = walk.BitmapFrom(image, dpi); err != nil {\n\t\t\treturn\n\t\t}\n\n\tcase walk.ExtractableIcon, *walk.Icon:\n\t\tif img, err = walk.IconFrom(image, dpi); err != nil {\n\t\t\treturn\n\t\t}\n\n\tdefault:\n\t\tif img, err = walk.ImageFrom(image); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\treturn action.SetImage(img)\n}\n\nfunc setActionBoolOrCondition(setBool func(bool) error, setCond func(walk.Condition), value Property, path string, builder *Builder) error {\n\tif value != nil {\n\t\tif b, ok := value.(bool); ok {\n\t\t\tif err := setBool(b); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if s := builder.conditionOrProperty(value); s != nil {\n\t\t\tif c, ok := s.(walk.Condition); ok {\n\t\t\t\tsetCond(c)\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"value of invalid type bound to %s: %T\", path, s)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "declarative/brush.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/lxn/walk\"\n)\n\ntype TransparentBrush struct {\n}\n\nfunc (TransparentBrush) Create() (walk.Brush, error) {\n\treturn walk.NullBrush(), nil\n}\n\ntype SolidColorBrush struct {\n\tColor walk.Color\n}\n\nfunc (scb SolidColorBrush) Create() (walk.Brush, error) {\n\treturn walk.NewSolidColorBrush(scb.Color)\n}\n\ntype SystemColorBrush struct {\n\tColor walk.SystemColor\n}\n\nfunc (scb SystemColorBrush) Create() (walk.Brush, error) {\n\treturn walk.NewSystemColorBrush(scb.Color)\n}\n\ntype BitmapBrush struct {\n\tImage interface{}\n}\n\nfunc (bb BitmapBrush) Create() (walk.Brush, error) {\n\tvar bmp *walk.Bitmap\n\tvar err error\n\n\tswitch img := bb.Image.(type) {\n\tcase *walk.Bitmap:\n\t\tbmp = img\n\n\tcase string:\n\t\tif bmp, err = walk.Resources.Bitmap(img); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\tcase int:\n\t\tif bmp, err = walk.Resources.Bitmap(strconv.Itoa(img)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\tdefault:\n\t\treturn nil, walk.ErrInvalidType\n\t}\n\n\treturn walk.NewBitmapBrush(bmp)\n}\n\ntype GradientBrush struct {\n\tVertexes  []walk.GradientVertex\n\tTriangles []walk.GradientTriangle\n}\n\nfunc (gb GradientBrush) Create() (walk.Brush, error) {\n\treturn walk.NewGradientBrush(gb.Vertexes, gb.Triangles)\n}\n\ntype HorizontalGradientBrush struct {\n\tStops []walk.GradientStop\n}\n\nfunc (hgb HorizontalGradientBrush) Create() (walk.Brush, error) {\n\treturn walk.NewHorizontalGradientBrush(hgb.Stops)\n}\n\ntype VerticalGradientBrush struct {\n\tStops []walk.GradientStop\n}\n\nfunc (vgb VerticalGradientBrush) Create() (walk.Brush, error) {\n\treturn walk.NewVerticalGradientBrush(vgb.Stops)\n}\n"
  },
  {
    "path": "declarative/builder.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/lxn/walk\"\n\t\"gopkg.in/Knetic/govaluate.v3\"\n)\n\nvar (\n\tconditionsByName = make(map[string]walk.Condition)\n\tpropertyRE       *regexp.Regexp\n)\n\nfunc init() {\n\twalk.AppendToWalkInit(func() {\n\t\tpropertyRE = regexp.MustCompile(\"[A-Za-z]+[0-9A-Za-z]*(\\\\.[A-Za-z]+[0-9A-Za-z]*)+\")\n\t})\n}\n\nfunc MustRegisterCondition(name string, condition walk.Condition) {\n\tif name == \"\" {\n\t\tpanic(`name == \"\"`)\n\t}\n\tif condition == nil {\n\t\tpanic(\"condition == nil\")\n\t}\n\tif _, ok := conditionsByName[name]; ok {\n\t\tpanic(\"name already registered\")\n\t}\n\n\tconditionsByName[name] = condition\n}\n\ntype declWidget struct {\n\td Widget\n\tw walk.Window\n}\n\ntype Builder struct {\n\tdpi                      int\n\tlevel                    int\n\trows                     int\n\tcolumns                  int\n\trow                      int\n\tcol                      int\n\twidgetValue              reflect.Value\n\tparent                   walk.Container\n\tdeclWidgets              []declWidget\n\tname2Window              map[string]walk.Window\n\tname2DataBinder          map[string]*walk.DataBinder\n\tdeferredFuncs            []func() error\n\tknownCompositeConditions map[string]walk.Condition\n\texpressions              map[string]walk.Expression\n\tfunctions                map[string]govaluate.ExpressionFunction\n}\n\nfunc NewBuilder(parent walk.Container) *Builder {\n\tvar dpi int\n\n\tif parent != nil {\n\t\tdpi = parent.DPI()\n\t}\n\n\treturn &Builder{\n\t\tdpi:                      dpi,\n\t\tparent:                   parent,\n\t\tname2Window:              make(map[string]walk.Window),\n\t\tname2DataBinder:          make(map[string]*walk.DataBinder),\n\t\tknownCompositeConditions: make(map[string]walk.Condition),\n\t\texpressions:              make(map[string]walk.Expression),\n\t\tfunctions:                make(map[string]govaluate.ExpressionFunction),\n\t}\n}\n\nfunc (b *Builder) Parent() walk.Container {\n\treturn b.parent\n}\n\nfunc (b *Builder) Defer(f func() error) {\n\tb.deferredFuncs = append(b.deferredFuncs, f)\n}\n\nfunc (b *Builder) deferBuildMenuActions(menu *walk.Menu, items []MenuItem) {\n\tif len(items) > 0 {\n\t\tb.Defer(func() error {\n\t\t\tfor _, item := range items {\n\t\t\t\tif _, err := item.createAction(b, menu); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n}\n\nfunc (b *Builder) deferBuildActions(actionList *walk.ActionList, items []MenuItem) {\n\tif len(items) > 0 {\n\t\tb.Defer(func() error {\n\t\t\tfor _, item := range items {\n\t\t\t\taction, err := item.createAction(b, nil)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := actionList.Add(action); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n}\n\nfunc (b *Builder) InitWidget(d Widget, w walk.Window, customInit func() error) error {\n\tif b.dpi == 0 {\n\t\tb.dpi = w.DPI()\n\t}\n\toldWidgetValue := b.widgetValue\n\tb.widgetValue = reflect.ValueOf(d)\n\tb.level++\n\tdefer func() {\n\t\tb.widgetValue = oldWidgetValue\n\t\tb.level--\n\t}()\n\n\tvar succeeded bool\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tw.Dispose()\n\t\t}\n\t}()\n\n\tb.declWidgets = append(b.declWidgets, declWidget{d, w})\n\n\t// Window\n\tb.initAccessibility(d, w)\n\n\t// Widget\n\tif name := b.string(\"Name\"); name != \"\" {\n\t\tw.SetName(name)\n\t\tb.name2Window[name] = w\n\t}\n\n\tif val := b.widgetValue.FieldByName(\"Background\"); val.IsValid() {\n\t\tif brush := val.Interface(); brush != nil {\n\t\t\tbg, err := brush.(Brush).Create()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tw.SetBackground(bg)\n\t\t}\n\t}\n\n\tif val := b.widgetValue.FieldByName(\"Font\"); val.IsValid() {\n\t\tif f, err := val.Interface().(Font).Create(); err != nil {\n\t\t\treturn err\n\t\t} else if f != nil {\n\t\t\tw.SetFont(f)\n\t\t}\n\t}\n\n\tif err := w.SetMinMaxSize(b.size(\"MinSize\").toW(), b.size(\"MaxSize\").toW()); err != nil {\n\t\treturn err\n\t}\n\n\tif contextMenuItems := b.menuItems(\"ContextMenuItems\"); len(contextMenuItems) > 0 {\n\t\tcm, err := walk.NewMenu()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tb.deferBuildMenuActions(cm, contextMenuItems)\n\n\t\tw.SetContextMenu(cm)\n\t}\n\n\tif handler := b.eventHandler(\"OnBoundsChanged\"); handler != nil {\n\t\tw.BoundsChanged().Attach(handler)\n\t}\n\n\tif handler := b.keyEventHandler(\"OnKeyDown\"); handler != nil {\n\t\tw.KeyDown().Attach(handler)\n\t}\n\n\tif handler := b.keyEventHandler(\"OnKeyPress\"); handler != nil {\n\t\tw.KeyPress().Attach(handler)\n\t}\n\n\tif handler := b.keyEventHandler(\"OnKeyUp\"); handler != nil {\n\t\tw.KeyUp().Attach(handler)\n\t}\n\n\tif handler := b.mouseEventHandler(\"OnMouseDown\"); handler != nil {\n\t\tw.MouseDown().Attach(handler)\n\t}\n\n\tif handler := b.mouseEventHandler(\"OnMouseMove\"); handler != nil {\n\t\tw.MouseMove().Attach(handler)\n\t}\n\n\tif handler := b.mouseEventHandler(\"OnMouseUp\"); handler != nil {\n\t\tw.MouseUp().Attach(handler)\n\t}\n\n\tif handler := b.eventHandler(\"OnSizeChanged\"); handler != nil {\n\t\tw.SizeChanged().Attach(handler)\n\t}\n\n\tif db := b.bool(\"DoubleBuffering\"); db {\n\t\tw.SetDoubleBuffering(true)\n\t}\n\n\tif rtl := b.bool(\"RightToLeftReading\"); rtl {\n\t\tw.SetRightToLeftReading(true)\n\t}\n\n\trow := b.int(\"Row\")\n\trowSpan := b.int(\"RowSpan\")\n\tcolumn := b.int(\"Column\")\n\tcolumnSpan := b.int(\"ColumnSpan\")\n\n\trowBackup := row\n\tcolumnBackup := column\n\n\tif widget, ok := w.(walk.Widget); ok {\n\t\tif alignment := b.alignment(); alignment != AlignHVDefault {\n\t\t\tif err := widget.SetAlignment(walk.Alignment2D(alignment)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err := widget.SetAlwaysConsumeSpace(b.bool(\"AlwaysConsumeSpace\")); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif field := b.widgetValue.FieldByName(\"GraphicsEffects\"); field.IsValid() {\n\t\t\tfor _, effect := range field.Interface().([]walk.WidgetGraphicsEffect) {\n\t\t\t\twidget.GraphicsEffects().Add(effect)\n\t\t\t}\n\t\t}\n\n\t\tif p := widget.Parent(); p != nil {\n\t\t\ttype SetStretchFactorer interface {\n\t\t\t\tSetStretchFactor(widget walk.Widget, factor int) error\n\t\t\t}\n\n\t\t\tstretchFactor := b.int(\"StretchFactor\")\n\n\t\t\tif stretchFactor < 1 {\n\t\t\t\tstretchFactor = 1\n\t\t\t}\n\n\t\t\tswitch l := p.Layout().(type) {\n\t\t\tcase SetStretchFactorer:\n\t\t\t\tif err := l.SetStretchFactor(widget, stretchFactor); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\tcase *walk.GridLayout:\n\t\t\t\tcsf := l.ColumnStretchFactor(column)\n\t\t\t\tif csf < stretchFactor {\n\t\t\t\t\tcsf = stretchFactor\n\t\t\t\t}\n\t\t\t\tl.SetColumnStretchFactor(column, csf)\n\n\t\t\t\trsf := l.RowStretchFactor(row)\n\t\t\t\tif rsf < stretchFactor {\n\t\t\t\t\trsf = stretchFactor\n\t\t\t\t}\n\t\t\t\tl.SetRowStretchFactor(row, rsf)\n\n\t\t\t\tif rowSpan < 1 {\n\t\t\t\t\trowSpan = 1\n\t\t\t\t}\n\t\t\t\tif columnSpan < 1 {\n\t\t\t\t\tcolumnSpan = 1\n\t\t\t\t}\n\n\t\t\t\tif b.rows > 0 && column == 0 && row == 0 {\n\t\t\t\t\tif b.row+rowSpan > b.rows {\n\t\t\t\t\t\tb.col++\n\t\t\t\t\t\tb.row = 0\n\t\t\t\t\t}\n\n\t\t\t\t\tcolumn = b.col\n\t\t\t\t\trow = b.row\n\n\t\t\t\t\tb.row += rowSpan\n\t\t\t\t}\n\n\t\t\t\tif b.columns > 0 && row == 0 && column == 0 {\n\t\t\t\t\tif b.col+columnSpan > b.columns {\n\t\t\t\t\t\tb.row++\n\t\t\t\t\t\tb.col = 0\n\t\t\t\t\t}\n\n\t\t\t\t\trow = b.row\n\t\t\t\t\tcolumn = b.col\n\n\t\t\t\t\tb.col += columnSpan\n\t\t\t\t}\n\n\t\t\t\tr := walk.Rectangle{column, row, columnSpan, rowSpan}\n\n\t\t\t\tif err := l.SetRange(widget, r); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\toldParent := b.parent\n\n\t// Container\n\tvar db *walk.DataBinder\n\tif wc, ok := w.(walk.Container); ok {\n\t\tvar layout Layout\n\t\tif val := b.widgetValue.FieldByName(\"Layout\"); val.IsValid() {\n\t\t\tlayout, _ = val.Interface().(Layout)\n\t\t}\n\n\t\tif layout != nil {\n\t\t\tl, err := layout.Create()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := wc.SetLayout(l); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\ttype DelegateContainerer interface {\n\t\t\tDelegateContainer() walk.Container\n\t\t}\n\n\t\tif dc, ok := wc.(DelegateContainerer); ok {\n\t\t\tif parent := dc.DelegateContainer(); parent != nil {\n\t\t\t\tb.parent = parent\n\t\t\t} else {\n\t\t\t\tb.parent = wc\n\t\t\t}\n\t\t} else {\n\t\t\tb.parent = wc\n\t\t}\n\t\tdefer func() {\n\t\t\tb.parent = oldParent\n\t\t}()\n\n\t\tif layout != nil {\n\t\t\tif g, ok := layout.(Grid); ok {\n\t\t\t\trowBackup = b.row\n\t\t\t\tcolumnBackup = b.col\n\n\t\t\t\trows := b.rows\n\t\t\t\tcolumns := b.columns\n\t\t\t\tdefer func() {\n\t\t\t\t\tb.rows, b.columns, b.row, b.col = rows, columns, rowBackup+rowSpan, columnBackup+columnSpan\n\t\t\t\t}()\n\n\t\t\t\tb.rows = g.Rows\n\t\t\t\tb.columns = g.Columns\n\t\t\t\tb.row = 0\n\t\t\t\tb.col = 0\n\t\t\t}\n\t\t}\n\n\t\tif val := b.widgetValue.FieldByName(\"Children\"); val.IsValid() {\n\t\t\tfor _, child := range val.Interface().([]Widget) {\n\t\t\t\tif err := child.Create(b); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdataBinder := b.widgetValue.FieldByName(\"DataBinder\").Interface().(DataBinder)\n\n\t\tif dataBinder.AssignTo != nil || dataBinder.DataSource != nil {\n\t\t\tif dataB, err := dataBinder.create(); err != nil {\n\t\t\t\treturn err\n\t\t\t} else {\n\t\t\t\tdb = dataB\n\n\t\t\t\tb.name2DataBinder[dataBinder.Name] = db\n\n\t\t\t\tif ep := db.ErrorPresenter(); ep != nil {\n\t\t\t\t\tif dep, ok := ep.(walk.Disposable); ok {\n\t\t\t\t\t\twc.AddDisposable(dep)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Custom\n\tif customInit != nil {\n\t\tif err := customInit(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tb.parent = oldParent\n\n\tif b.level == 1 {\n\t\tif err := b.initProperties(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Call Reset on DataBinder after customInit, so a Dialog gets a chance to first\n\t// wire up its DefaultButton to the CanSubmitChanged event of a DataBinder.\n\tif db != nil {\n\t\tif wc, ok := w.(walk.Container); ok {\n\t\t\tb.Defer(func() error {\n\t\t\t\t// FIXME: Currently SetDataBinder must be called after initProperties.\n\t\t\t\twc.SetDataBinder(db)\n\n\t\t\t\tif db.DataSource() == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\treturn db.Reset()\n\t\t\t})\n\t\t}\n\t}\n\n\tif b.level == 1 {\n\t\tfor _, f := range b.deferredFuncs {\n\t\t\tif err := f(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tsucceeded = true\n\n\treturn nil\n}\n\nfunc (b *Builder) initAccessibility(d Widget, w walk.Window) error {\n\taccessibility := b.widgetValue.FieldByName(\"Accessibility\")\n\n\tif accessibility.IsValid() {\n\t\ta := accessibility.Interface().(Accessibility)\n\n\t\tif a.Accelerator != \"\" {\n\t\t\tw.Accessibility().SetAccelerator(a.Accelerator)\n\t\t}\n\n\t\tif a.DefaultAction != \"\" {\n\t\t\tw.Accessibility().SetDefaultAction(a.DefaultAction)\n\t\t}\n\n\t\tif a.Description != \"\" {\n\t\t\tw.Accessibility().SetDescription(a.Description)\n\t\t}\n\n\t\tif a.Help != \"\" {\n\t\t\tw.Accessibility().SetHelp(a.Help)\n\t\t}\n\n\t\tif a.Name != \"\" {\n\t\t\tw.Accessibility().SetName(a.Name)\n\t\t}\n\n\t\tif a.Role > 0 {\n\t\t\tw.Accessibility().SetRole(walk.AccRole(a.Role))\n\t\t}\n\n\t\tif a.RoleMap != \"\" {\n\t\t\tw.Accessibility().SetRoleMap(a.RoleMap)\n\t\t}\n\n\t\tif a.State > 0 {\n\t\t\tw.Accessibility().SetState(walk.AccState(a.State))\n\t\t}\n\n\t\tif a.StateMap != \"\" {\n\t\t\tw.Accessibility().SetStateMap(a.StateMap)\n\t\t}\n\n\t\tif a.ValueMap != \"\" {\n\t\t\tw.Accessibility().SetValueMap(a.ValueMap)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (b *Builder) alignment() Alignment2D {\n\tfieldValue := b.widgetValue.FieldByName(\"Alignment\")\n\n\tif fieldValue.IsValid() {\n\t\treturn fieldValue.Interface().(Alignment2D)\n\t}\n\n\treturn AlignHVDefault\n}\n\nfunc (b *Builder) bool(fieldName string) bool {\n\tfieldValue := b.widgetValue.FieldByName(fieldName)\n\n\tif fieldValue.IsValid() {\n\t\treturn fieldValue.Interface().(bool)\n\t}\n\n\treturn false\n}\n\nfunc (b *Builder) eventHandler(fieldName string) walk.EventHandler {\n\tfieldValue := b.widgetValue.FieldByName(fieldName)\n\n\tif fieldValue.IsValid() {\n\t\treturn fieldValue.Interface().(walk.EventHandler)\n\t}\n\n\treturn nil\n}\n\nfunc (b *Builder) float64(fieldName string) float64 {\n\tfieldValue := b.widgetValue.FieldByName(fieldName)\n\n\tif fieldValue.IsValid() {\n\t\treturn fieldValue.Interface().(float64)\n\t}\n\n\treturn 0\n}\n\nfunc (b *Builder) int(fieldName string) int {\n\tfieldValue := b.widgetValue.FieldByName(fieldName)\n\n\tif fieldValue.IsValid() {\n\t\treturn fieldValue.Interface().(int)\n\t}\n\n\treturn 0\n}\n\nfunc (b *Builder) keyEventHandler(fieldName string) walk.KeyEventHandler {\n\tfieldValue := b.widgetValue.FieldByName(fieldName)\n\n\tif fieldValue.IsValid() {\n\t\treturn fieldValue.Interface().(walk.KeyEventHandler)\n\t}\n\n\treturn nil\n}\n\nfunc (b *Builder) menuItems(fieldName string) []MenuItem {\n\tfieldValue := b.widgetValue.FieldByName(fieldName)\n\n\tif fieldValue.IsValid() {\n\t\treturn fieldValue.Interface().([]MenuItem)\n\t}\n\n\treturn nil\n}\n\nfunc (b *Builder) mouseEventHandler(fieldName string) walk.MouseEventHandler {\n\tfieldValue := b.widgetValue.FieldByName(fieldName)\n\n\tif fieldValue.IsValid() {\n\t\treturn fieldValue.Interface().(walk.MouseEventHandler)\n\t}\n\n\treturn nil\n}\n\nfunc (b *Builder) size(fieldName string) Size {\n\tfieldValue := b.widgetValue.FieldByName(fieldName)\n\n\tif fieldValue.IsValid() {\n\t\treturn fieldValue.Interface().(Size)\n\t}\n\n\treturn Size{}\n}\n\nfunc (b *Builder) string(fieldName string) string {\n\tfieldValue := b.widgetValue.FieldByName(fieldName)\n\n\tif fieldValue.IsValid() {\n\t\treturn fieldValue.Interface().(string)\n\t}\n\n\treturn \"\"\n}\n\nfunc (b *Builder) initProperties() error {\n\tfor _, dw := range b.declWidgets {\n\t\td, w := dw.d, dw.w\n\n\t\tsv := reflect.ValueOf(d)\n\t\tst := sv.Type()\n\t\tif st.Kind() != reflect.Struct {\n\t\t\tpanic(\"d must be a struct value\")\n\t\t}\n\n\t\twb := w.AsWindowBase()\n\n\t\tfieldCount := st.NumField()\n\t\tfor i := 0; i < fieldCount; i++ {\n\t\t\tsf := st.Field(i)\n\n\t\t\tprop := wb.Property(sf.Name)\n\n\t\t\tswitch val := sv.Field(i).Interface().(type) {\n\t\t\tcase nil:\n\t\t\t\t// nop\n\n\t\t\tcase bindData:\n\t\t\t\tif prop == nil {\n\t\t\t\t\tpanic(sf.Name + \" is not a property\")\n\t\t\t\t}\n\n\t\t\t\tsrc := b.conditionOrProperty(val)\n\n\t\t\t\tif src == nil {\n\t\t\t\t\t// No luck so far, so we assume the expression refers to\n\t\t\t\t\t// something in the data source.\n\t\t\t\t\tsrc = val.expression\n\n\t\t\t\t\tif val.validator != nil {\n\t\t\t\t\t\tvalidator, err := val.validator.Create()\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif err := prop.SetValidator(validator); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif err := prop.SetSource(src); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\tcase walk.Condition:\n\t\t\t\tif prop == nil {\n\t\t\t\t\tpanic(sf.Name + \" is not a property\")\n\t\t\t\t}\n\n\t\t\t\tif err := prop.SetSource(val); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tif prop == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif err := prop.Set(val); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (b *Builder) conditionOrProperty(data Property) interface{} {\n\tswitch val := data.(type) {\n\tcase bindData:\n\t\tif val.expression == \"\" {\n\t\t\treturn nil\n\t\t}\n\n\t\te := &expression{\n\t\t\ttext:           val.expression,\n\t\t\tsubExprsByPath: subExpressions(make(map[string]walk.Expression)),\n\t\t}\n\n\t\tvar singleExpr walk.Expression\n\n\t\ttext := propertyRE.ReplaceAllStringFunc(val.expression, func(s string) string {\n\t\t\tif _, ok := e.subExprsByPath[s]; !ok {\n\t\t\t\tparts := strings.Split(s, \".\")\n\n\t\t\t\tif w, ok := b.name2Window[parts[0]]; ok {\n\t\t\t\t\tif prop := w.AsWindowBase().Property(parts[1]); prop != nil {\n\t\t\t\t\t\tif len(s) == len(val.expression) {\n\t\t\t\t\t\t\tsingleExpr = prop\n\t\t\t\t\t\t\treturn \"\"\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif len(parts) == 2 {\n\t\t\t\t\t\t\te.addSubExpression(s, prop)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\te.addSubExpression(s, walk.NewReflectExpression(prop, s[len(parts[0])+len(parts[1])+2:]))\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpanic(fmt.Errorf(`invalid sub expression: \"%s\"`, s))\n\t\t\t\t\t}\n\t\t\t\t} else if db, ok := b.name2DataBinder[parts[0]]; ok {\n\t\t\t\t\te.addSubExpression(s, db.Expression(s[len(parts[0])+1:]))\n\t\t\t\t} else if expr, ok := b.expressions[parts[0]]; ok {\n\t\t\t\t\te.addSubExpression(s, walk.NewReflectExpression(expr, s[len(parts[0])+1:]))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn strings.Replace(s, \".\", \"\\\\.\", -1)\n\t\t})\n\n\t\tif singleExpr != nil {\n\t\t\treturn singleExpr\n\t\t}\n\n\t\texpr, err := govaluate.NewEvaluableExpressionWithFunctions(text, b.functions)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Errorf(`invalid expression \"%s\": %s`, e.text, err.Error()))\n\t\t}\n\n\t\tfor _, token := range expr.Tokens() {\n\t\t\tif token.Kind == govaluate.VARIABLE {\n\t\t\t\tname := token.Value.(string)\n\t\t\t\tif c, ok := conditionsByName[name]; ok {\n\t\t\t\t\te.addSubExpression(name, c)\n\t\t\t\t}\n\t\t\t\tif x, ok := b.expressions[name]; ok {\n\t\t\t\t\te.addSubExpression(name, x)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\te.expr = expr\n\n\t\tif _, err := e.expr.Eval(e.subExprsByPath); err != nil {\n\t\t\t// We hope for the best and leave it to a DataBinder...\n\t\t\treturn nil\n\t\t}\n\n\t\tif _, ok := e.Value().(bool); ok {\n\t\t\treturn &boolExpression{expression: e}\n\t\t}\n\n\t\treturn e\n\n\tcase walk.Expression:\n\t\treturn val\n\t}\n\n\treturn nil\n}\n\ntype expression struct {\n\texpr                   *govaluate.EvaluableExpression\n\ttext                   string\n\tsubExprsByPath         subExpressions\n\tsubExprsChangedHandles []int\n\tchangedPublisher       walk.EventPublisher\n\tlastReportedValue      interface{}\n}\n\ntype subExpressions map[string]walk.Expression\n\nfunc (se subExpressions) Get(name string) (interface{}, error) {\n\tif sub, ok := se[name]; ok {\n\t\treturn sub.Value(), nil\n\t}\n\n\treturn nil, fmt.Errorf(`invalid sub expression: \"%s\"`, name)\n}\n\nfunc (e *expression) String() string {\n\treturn e.text\n}\n\nfunc (e *expression) Value() interface{} {\n\tval, err := e.expr.Eval(e.subExprsByPath)\n\tif err != nil {\n\t\tlog.Printf(`walk - failed to evaluate expression \"%s\": %s`, e.text, err.Error())\n\t}\n\n\te.lastReportedValue = val\n\n\treturn val\n}\n\nfunc (e *expression) Changed() *walk.Event {\n\treturn e.changedPublisher.Event()\n}\n\nfunc (e *expression) addSubExpression(path string, subExpr walk.Expression) {\n\te.subExprsByPath[path] = subExpr\n\n\thandle := subExpr.Changed().Attach(func() {\n\t\tlast := e.lastReportedValue\n\t\tif v := e.Value(); v != last {\n\t\t\te.changedPublisher.Publish()\n\t\t}\n\t})\n\te.subExprsChangedHandles = append(e.subExprsChangedHandles, handle)\n}\n\ntype boolExpression struct {\n\t*expression\n}\n\nfunc (be *boolExpression) Satisfied() bool {\n\tsatisfied, ok := be.Value().(bool)\n\treturn ok && satisfied\n}\n"
  },
  {
    "path": "declarative/checkbox.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype CheckBox struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Button\n\n\tChecked          Property\n\tOnCheckedChanged walk.EventHandler\n\tOnClicked        walk.EventHandler\n\tText             Property\n\n\t// CheckBox\n\n\tAssignTo            **walk.CheckBox\n\tCheckState          Property\n\tOnCheckStateChanged walk.EventHandler\n\tTextOnLeftSide      bool\n\tTristate            bool\n}\n\nfunc (cb CheckBox) Create(builder *Builder) error {\n\tw, err := walk.NewCheckBox(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cb.AssignTo != nil {\n\t\t*cb.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(cb, w, func() error {\n\t\tw.SetPersistent(cb.Persistent)\n\n\t\tif err := w.SetTextOnLeftSide(cb.TextOnLeftSide); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := w.SetTristate(cb.Tristate); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif _, isBindData := cb.CheckState.(bindData); cb.Tristate && (cb.CheckState == nil || isBindData) {\n\t\t\tw.SetCheckState(walk.CheckIndeterminate)\n\t\t}\n\n\t\tif cb.OnClicked != nil {\n\t\t\tw.Clicked().Attach(cb.OnClicked)\n\t\t}\n\n\t\tif cb.OnCheckedChanged != nil {\n\t\t\tw.CheckedChanged().Attach(cb.OnCheckedChanged)\n\t\t}\n\n\t\tif cb.OnCheckStateChanged != nil {\n\t\t\tw.CheckStateChanged().Attach(cb.OnCheckStateChanged)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/combobox.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"errors\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype ComboBox struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// ComboBox\n\n\tAssignTo              **walk.ComboBox\n\tBindingMember         string\n\tCurrentIndex          Property\n\tDisplayMember         string\n\tEditable              bool\n\tFormat                string\n\tMaxLength             int\n\tModel                 interface{}\n\tOnCurrentIndexChanged walk.EventHandler\n\tOnEditingFinished     walk.EventHandler\n\tOnTextChanged         walk.EventHandler\n\tPrecision             int\n\tValue                 Property\n}\n\nfunc (cb ComboBox) Create(builder *Builder) error {\n\tif _, ok := cb.Model.([]string); ok &&\n\t\t(cb.BindingMember != \"\" || cb.DisplayMember != \"\") {\n\n\t\treturn errors.New(\"ComboBox.Create: BindingMember and DisplayMember must be empty for []string models.\")\n\t}\n\n\tvar w *walk.ComboBox\n\tvar err error\n\tif cb.Editable {\n\t\tw, err = walk.NewComboBox(builder.Parent())\n\t} else {\n\t\tw, err = walk.NewDropDownBox(builder.Parent())\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cb.AssignTo != nil {\n\t\t*cb.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(cb, w, func() error {\n\t\tw.SetPersistent(cb.Persistent)\n\t\tw.SetFormat(cb.Format)\n\t\tw.SetPrecision(cb.Precision)\n\t\tw.SetMaxLength(cb.MaxLength)\n\n\t\tif err := w.SetBindingMember(cb.BindingMember); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := w.SetDisplayMember(cb.DisplayMember); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := w.SetModel(cb.Model); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif cb.OnCurrentIndexChanged != nil {\n\t\t\tw.CurrentIndexChanged().Attach(cb.OnCurrentIndexChanged)\n\t\t}\n\t\tif cb.OnEditingFinished != nil {\n\t\t\tw.EditingFinished().Attach(cb.OnEditingFinished)\n\t\t}\n\t\tif cb.OnTextChanged != nil {\n\t\t\tw.TextChanged().Attach(cb.OnTextChanged)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/composite.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n\t\"github.com/lxn/win\"\n)\n\ntype Composite struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Container\n\n\tChildren   []Widget\n\tDataBinder DataBinder\n\tLayout     Layout\n\n\t// Composite\n\n\tAssignTo    **walk.Composite\n\tBorder      bool\n\tExpressions func() map[string]walk.Expression\n\tFunctions   map[string]func(args ...interface{}) (interface{}, error)\n}\n\nfunc (c Composite) Create(builder *Builder) error {\n\tvar style uint32\n\tif c.Border {\n\t\tstyle |= win.WS_BORDER\n\t}\n\tw, err := walk.NewCompositeWithStyle(builder.Parent(), style)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif c.AssignTo != nil {\n\t\t*c.AssignTo = w\n\t}\n\n\tw.SetSuspended(true)\n\tbuilder.Defer(func() error {\n\t\tw.SetSuspended(false)\n\t\treturn nil\n\t})\n\n\treturn builder.InitWidget(c, w, func() error {\n\t\tif c.Expressions != nil {\n\t\t\tfor name, expr := range c.Expressions() {\n\t\t\t\tbuilder.expressions[name] = expr\n\t\t\t}\n\t\t}\n\t\tif c.Functions != nil {\n\t\t\tfor name, fn := range c.Functions {\n\t\t\t\tbuilder.functions[name] = fn\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/customwidget.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype PaintMode int\n\nconst (\n\tPaintNormal   PaintMode = iota // erase background before PaintFunc\n\tPaintNoErase                   // PaintFunc clears background, single buffered\n\tPaintBuffered                  // PaintFunc clears background, double buffered\n)\n\ntype CustomWidget struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// CustomWidget\n\n\tAssignTo            **walk.CustomWidget\n\tClearsBackground    bool\n\tInvalidatesOnResize bool\n\tPaint               walk.PaintFunc\n\tPaintPixels         walk.PaintFunc\n\tPaintMode           PaintMode\n\tStyle               uint32\n}\n\nfunc (cw CustomWidget) Create(builder *Builder) error {\n\tvar w *walk.CustomWidget\n\tvar err error\n\tif cw.PaintPixels != nil {\n\t\tw, err = walk.NewCustomWidgetPixels(builder.Parent(), uint(cw.Style), cw.PaintPixels)\n\t} else {\n\t\tw, err = walk.NewCustomWidget(builder.Parent(), uint(cw.Style), cw.Paint)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cw.AssignTo != nil {\n\t\t*cw.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(cw, w, func() error {\n\t\tif cw.PaintMode != PaintNormal && cw.ClearsBackground {\n\t\t\tpanic(\"PaintMode and ClearsBackground are incompatible\")\n\t\t}\n\t\tw.SetClearsBackground(cw.ClearsBackground)\n\t\tw.SetInvalidatesOnResize(cw.InvalidatesOnResize)\n\t\tw.SetPaintMode(walk.PaintMode(cw.PaintMode))\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/databinder.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"time\"\n\n\t\"github.com/lxn/walk\"\n)\n\ntype DataBinder struct {\n\tAssignTo            **walk.DataBinder\n\tAutoSubmit          bool\n\tAutoSubmitDelay     time.Duration\n\tDataSource          interface{}\n\tErrorPresenter      ErrorPresenter\n\tName                string\n\tOnCanSubmitChanged  walk.EventHandler\n\tOnDataSourceChanged walk.EventHandler\n\tOnReset             walk.EventHandler\n\tOnSubmitted         walk.EventHandler\n}\n\nfunc (db DataBinder) create() (*walk.DataBinder, error) {\n\tb := walk.NewDataBinder()\n\n\tif db.AssignTo != nil {\n\t\t*db.AssignTo = b\n\t}\n\n\tif db.ErrorPresenter != nil {\n\t\tep, err := db.ErrorPresenter.Create()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tb.SetErrorPresenter(ep)\n\t}\n\n\tb.SetDataSource(db.DataSource)\n\n\tb.SetAutoSubmit(db.AutoSubmit)\n\tb.SetAutoSubmitDelay(db.AutoSubmitDelay)\n\n\tif db.OnCanSubmitChanged != nil {\n\t\tb.CanSubmitChanged().Attach(db.OnCanSubmitChanged)\n\t}\n\tif db.OnDataSourceChanged != nil {\n\t\tb.DataSourceChanged().Attach(db.OnDataSourceChanged)\n\t}\n\tif db.OnReset != nil {\n\t\tb.ResetFinished().Attach(db.OnReset)\n\t}\n\tif db.OnSubmitted != nil {\n\t\tb.Submitted().Attach(db.OnSubmitted)\n\t}\n\n\treturn b, nil\n}\n"
  },
  {
    "path": "declarative/dateedit.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"time\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype DateEdit struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// DateEdit\n\n\tAssignTo      **walk.DateEdit\n\tDate          Property\n\tFormat        string\n\tMaxDate       time.Time\n\tMinDate       time.Time\n\tNoneOption    bool // Deprecated: use Optional instead\n\tOnDateChanged walk.EventHandler\n\tOptional      bool\n}\n\nfunc (de DateEdit) Create(builder *Builder) error {\n\tvar w *walk.DateEdit\n\tvar err error\n\n\tif de.Optional || de.NoneOption {\n\t\tw, err = walk.NewDateEditWithNoneOption(builder.Parent())\n\t} else {\n\t\tw, err = walk.NewDateEdit(builder.Parent())\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif de.AssignTo != nil {\n\t\t*de.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(de, w, func() error {\n\t\tif err := w.SetFormat(de.Format); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := w.SetRange(de.MinDate, de.MaxDate); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif de.OnDateChanged != nil {\n\t\t\tw.DateChanged().Attach(de.OnDateChanged)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/datelabel.go",
    "content": "// Copyright 2018 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype DateLabel struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// static\n\n\tTextColor walk.Color\n\n\t// DateLabel\n\n\tAssignTo      **walk.DateLabel\n\tDate          Property\n\tFormat        Property\n\tTextAlignment Alignment1D\n}\n\nfunc (dl DateLabel) Create(builder *Builder) error {\n\tw, err := walk.NewDateLabel(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif dl.AssignTo != nil {\n\t\t*dl.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(dl, w, func() error {\n\t\tif err := w.SetTextAlignment(walk.Alignment1D(dl.TextAlignment)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tw.SetTextColor(dl.TextColor)\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/dialog.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype Dialog struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftLayout  bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Container\n\n\tDataBinder DataBinder\n\tLayout     Layout\n\tChildren   []Widget\n\n\t// Form\n\n\tExpressions func() map[string]walk.Expression\n\tFunctions   map[string]func(args ...interface{}) (interface{}, error)\n\tIcon        Property\n\tTitle       Property\n\tSize        Size\n\n\t// Dialog\n\n\tAssignTo      **walk.Dialog\n\tCancelButton  **walk.PushButton\n\tDefaultButton **walk.PushButton\n\tFixedSize     bool\n}\n\nfunc (d Dialog) Create(owner walk.Form) error {\n\tvar w *walk.Dialog\n\tvar err error\n\n\tif d.FixedSize {\n\t\tw, err = walk.NewDialogWithFixedSize(owner)\n\t} else {\n\t\tw, err = walk.NewDialog(owner)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif d.AssignTo != nil {\n\t\t*d.AssignTo = w\n\t}\n\n\tfi := formInfo{\n\t\t// Window\n\t\tBackground:         d.Background,\n\t\tContextMenuItems:   d.ContextMenuItems,\n\t\tDoubleBuffering:    d.DoubleBuffering,\n\t\tEnabled:            d.Enabled,\n\t\tFont:               d.Font,\n\t\tMaxSize:            d.MaxSize,\n\t\tMinSize:            d.MinSize,\n\t\tName:               d.Name,\n\t\tOnBoundsChanged:    d.OnBoundsChanged,\n\t\tOnKeyDown:          d.OnKeyDown,\n\t\tOnKeyPress:         d.OnKeyPress,\n\t\tOnKeyUp:            d.OnKeyUp,\n\t\tOnMouseDown:        d.OnMouseDown,\n\t\tOnMouseMove:        d.OnMouseMove,\n\t\tOnMouseUp:          d.OnMouseUp,\n\t\tOnSizeChanged:      d.OnSizeChanged,\n\t\tRightToLeftReading: d.RightToLeftReading,\n\t\tToolTipText:        \"\",\n\t\tVisible:            d.Visible,\n\t\tAccessibility:      d.Accessibility,\n\n\t\t// Container\n\t\tChildren:   d.Children,\n\t\tDataBinder: d.DataBinder,\n\t\tLayout:     d.Layout,\n\n\t\t// Form\n\t\tIcon:  d.Icon,\n\t\tTitle: d.Title,\n\t}\n\n\tvar db *walk.DataBinder\n\tif d.DataBinder.AssignTo == nil {\n\t\td.DataBinder.AssignTo = &db\n\t}\n\n\tbuilder := NewBuilder(nil)\n\n\tw.SetSuspended(true)\n\tbuilder.Defer(func() error {\n\t\tw.SetSuspended(false)\n\t\treturn nil\n\t})\n\n\tif err := w.SetRightToLeftLayout(d.RightToLeftLayout); err != nil {\n\t\treturn err\n\t}\n\n\treturn builder.InitWidget(fi, w, func() error {\n\t\tif d.Size.Width > 0 && d.Size.Height > 0 {\n\t\t\tif err := w.SetSize(d.Size.toW()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif d.DefaultButton != nil {\n\t\t\tif err := w.SetDefaultButton(*d.DefaultButton); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif db := *d.DataBinder.AssignTo; db != nil {\n\t\t\t\tif db.DataSource() != nil {\n\t\t\t\t\t(*d.DefaultButton).SetEnabled(db.CanSubmit())\n\t\t\t\t}\n\n\t\t\t\tdb.CanSubmitChanged().Attach(func() {\n\t\t\t\t\t(*d.DefaultButton).SetEnabled(db.CanSubmit())\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\tif d.CancelButton != nil {\n\t\t\tif err := w.SetCancelButton(*d.CancelButton); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif d.Expressions != nil {\n\t\t\tfor name, expr := range d.Expressions() {\n\t\t\t\tbuilder.expressions[name] = expr\n\t\t\t}\n\t\t}\n\t\tif d.Functions != nil {\n\t\t\tfor name, fn := range d.Functions {\n\t\t\t\tbuilder.functions[name] = fn\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\nfunc (d Dialog) Run(owner walk.Form) (int, error) {\n\tvar w *walk.Dialog\n\n\tif d.AssignTo == nil {\n\t\td.AssignTo = &w\n\t}\n\n\tif err := d.Create(owner); err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn (*d.AssignTo).Run(), nil\n}\n"
  },
  {
    "path": "declarative/font.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype Font struct {\n\tFamily    string\n\tPointSize int\n\tBold      bool\n\tItalic    bool\n\tUnderline bool\n\tStrikeOut bool\n}\n\nfunc (f Font) Create() (*walk.Font, error) {\n\tif f.Family == \"\" && f.PointSize == 0 {\n\t\treturn nil, nil\n\t}\n\n\tvar fs walk.FontStyle\n\n\tif f.Bold {\n\t\tfs |= walk.FontBold\n\t}\n\tif f.Italic {\n\t\tfs |= walk.FontItalic\n\t}\n\tif f.Underline {\n\t\tfs |= walk.FontUnderline\n\t}\n\tif f.StrikeOut {\n\t\tfs |= walk.FontStrikeOut\n\t}\n\n\treturn walk.NewFont(f.Family, f.PointSize, fs)\n}\n"
  },
  {
    "path": "declarative/gradientcomposite.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n\t\"github.com/lxn/win\"\n)\n\ntype GradientComposite struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Container\n\n\tChildren   []Widget\n\tLayout     Layout\n\tDataBinder DataBinder\n\n\t// GradientComposite\n\n\tAssignTo    **walk.GradientComposite\n\tBorder      bool\n\tColor1      Property\n\tColor2      Property\n\tExpressions func() map[string]walk.Expression\n\tFunctions   map[string]func(args ...interface{}) (interface{}, error)\n\tVertical    Property\n}\n\nfunc (gc GradientComposite) Create(builder *Builder) error {\n\tvar style uint32\n\tif gc.Border {\n\t\tstyle |= win.WS_BORDER\n\t}\n\tw, err := walk.NewGradientCompositeWithStyle(builder.Parent(), style)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif gc.AssignTo != nil {\n\t\t*gc.AssignTo = w\n\t}\n\n\tw.SetSuspended(true)\n\tbuilder.Defer(func() error {\n\t\tw.SetSuspended(false)\n\t\treturn nil\n\t})\n\n\treturn builder.InitWidget(gc, w, func() error {\n\t\tif gc.Expressions != nil {\n\t\t\tfor name, expr := range gc.Expressions() {\n\t\t\t\tbuilder.expressions[name] = expr\n\t\t\t}\n\t\t}\n\t\tif gc.Functions != nil {\n\t\t\tfor name, fn := range gc.Functions {\n\t\t\t\tbuilder.functions[name] = fn\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/groupbox.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype GroupBox struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Container\n\n\tChildren   []Widget\n\tDataBinder DataBinder\n\tLayout     Layout\n\n\t// GroupBox\n\n\tAssignTo  **walk.GroupBox\n\tCheckable bool\n\tChecked   Property\n\tTitle     string\n}\n\nfunc (gb GroupBox) Create(builder *Builder) error {\n\tw, err := walk.NewGroupBox(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif gb.AssignTo != nil {\n\t\t*gb.AssignTo = w\n\t}\n\n\tw.SetSuspended(true)\n\tbuilder.Defer(func() error {\n\t\tw.SetSuspended(false)\n\t\treturn nil\n\t})\n\n\treturn builder.InitWidget(gb, w, func() error {\n\t\tif err := w.SetTitle(gb.Title); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tw.SetCheckable(gb.Checkable)\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/imageview.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype ImageViewMode int\n\nconst (\n\tImageViewModeIdeal   = ImageViewMode(walk.ImageViewModeIdeal)\n\tImageViewModeCorner  = ImageViewMode(walk.ImageViewModeCorner)\n\tImageViewModeCenter  = ImageViewMode(walk.ImageViewModeCenter)\n\tImageViewModeShrink  = ImageViewMode(walk.ImageViewModeShrink)\n\tImageViewModeZoom    = ImageViewMode(walk.ImageViewModeZoom)\n\tImageViewModeStretch = ImageViewMode(walk.ImageViewModeStretch)\n)\n\ntype ImageView struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// ImageView\n\n\tAssignTo **walk.ImageView\n\tImage    Property\n\tMargin   Property\n\tMode     ImageViewMode\n}\n\nfunc (iv ImageView) Create(builder *Builder) error {\n\tw, err := walk.NewImageView(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif iv.AssignTo != nil {\n\t\t*iv.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(iv, w, func() error {\n\t\tw.SetMode(walk.ImageViewMode(iv.Mode))\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/interfaces.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"path/filepath\"\n\n\t\"github.com/lxn/walk\"\n)\n\nfunc tr(source string, context ...string) string {\n\tif translation := walk.TranslationFunc(); translation != nil {\n\t\treturn translation(source, context...)\n\t}\n\n\treturn source\n}\n\ntype Property interface{}\n\ntype bindData struct {\n\texpression string\n\tvalidator  Validator\n}\n\nfunc Bind(expression string, validators ...Validator) Property {\n\tbd := bindData{expression: expression}\n\tswitch len(validators) {\n\tcase 0:\n\t\t// nop\n\n\tcase 1:\n\t\tbd.validator = validators[0]\n\n\tdefault:\n\t\tbd.validator = dMultiValidator{validators}\n\t}\n\n\treturn bd\n}\n\ntype SysDLLIcon struct {\n\tFileName string\n\tIndex    int\n\tSize     int\n}\n\nfunc (sdi SysDLLIcon) FilePath_() string {\n\troot, _ := walk.SystemPath()\n\n\tname := sdi.FileName\n\tif filepath.Ext(name) == \"\" {\n\t\tname += \".dll\"\n\t}\n\n\treturn filepath.Join(root, name)\n}\n\nfunc (sdi SysDLLIcon) Index_() int {\n\treturn sdi.Index\n}\n\nfunc (sdi SysDLLIcon) Size_() int {\n\tif sdi.Size == 0 {\n\t\treturn 16\n\t}\n\n\treturn sdi.Size\n}\n\ntype Brush interface {\n\tCreate() (walk.Brush, error)\n}\n\ntype Layout interface {\n\tCreate() (walk.Layout, error)\n}\n\ntype Widget interface {\n\tCreate(builder *Builder) error\n}\n\ntype MenuItem interface {\n\tcreateAction(builder *Builder, menu *walk.Menu) (*walk.Action, error)\n}\n\ntype Validator interface {\n\tCreate() (walk.Validator, error)\n}\n\ntype ErrorPresenter interface {\n\tCreate() (walk.ErrorPresenter, error)\n}\n\ntype ErrorPresenterRef struct {\n\tErrorPresenter *walk.ErrorPresenter\n}\n\nfunc (epr ErrorPresenterRef) Create() (walk.ErrorPresenter, error) {\n\tif epr.ErrorPresenter != nil {\n\t\treturn *epr.ErrorPresenter, nil\n\t}\n\n\treturn nil, nil\n}\n\ntype ToolTipErrorPresenter struct {\n}\n\nfunc (ToolTipErrorPresenter) Create() (walk.ErrorPresenter, error) {\n\treturn walk.NewToolTipErrorPresenter()\n}\n\ntype formInfo struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tRightToLeftReading bool\n\tToolTipText        string\n\tVisible            Property\n\n\t// Container\n\n\tChildren   []Widget\n\tDataBinder DataBinder\n\tLayout     Layout\n\n\t// Form\n\n\tIcon  Property\n\tTitle Property\n}\n\nfunc (formInfo) Create(builder *Builder) error {\n\treturn nil\n}\n"
  },
  {
    "path": "declarative/label.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n\t\"github.com/lxn/win\"\n)\n\ntype EllipsisMode int\n\nconst (\n\tEllipsisNone = EllipsisMode(walk.EllipsisNone)\n\tEllipsisEnd  = EllipsisMode(walk.EllipsisEnd)\n\tEllipsisPath = EllipsisMode(walk.EllipsisPath)\n)\n\ntype Label struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Label\n\n\tAssignTo      **walk.Label\n\tEllipsisMode  EllipsisMode\n\tNoPrefix      bool\n\tText          Property\n\tTextAlignment Alignment1D\n\tTextColor     walk.Color\n}\n\nfunc (l Label) Create(builder *Builder) error {\n\tvar style uint32\n\tif l.NoPrefix {\n\t\tstyle |= win.SS_NOPREFIX\n\t}\n\n\tw, err := walk.NewLabelWithStyle(builder.Parent(), style)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif l.AssignTo != nil {\n\t\t*l.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(l, w, func() error {\n\t\tif err := w.SetEllipsisMode(walk.EllipsisMode(l.EllipsisMode)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := w.SetTextAlignment(walk.Alignment1D(l.TextAlignment)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tw.SetTextColor(l.TextColor)\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/layouts.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"errors\"\n\n\t\"github.com/lxn/walk\"\n)\n\ntype Orientation byte\n\nconst (\n\tHorizontal Orientation = Orientation(walk.Horizontal)\n\tVertical   Orientation = Orientation(walk.Vertical)\n)\n\ntype Margins struct {\n\tLeft   int\n\tTop    int\n\tRight  int\n\tBottom int\n}\n\nfunc (m Margins) isZero() bool {\n\treturn m.Left == 0 && m.Top == 0 && m.Right == 0 && m.Bottom == 0\n}\n\nfunc (m Margins) toW() walk.Margins {\n\treturn walk.Margins{m.Left, m.Top, m.Right, m.Bottom}\n}\n\ntype Rectangle struct {\n\tX      int\n\tY      int\n\tWidth  int\n\tHeight int\n}\n\nfunc (r Rectangle) toW() walk.Rectangle {\n\treturn walk.Rectangle{r.X, r.Y, r.Width, r.Height}\n}\n\ntype Size struct {\n\tWidth  int\n\tHeight int\n}\n\nfunc (s Size) toW() walk.Size {\n\treturn walk.Size{s.Width, s.Height}\n}\n\nfunc setLayoutMargins(layout walk.Layout, margins Margins, marginsZero bool) error {\n\tif !marginsZero && margins.isZero() {\n\t\tmargins = Margins{9, 9, 9, 9}\n\t}\n\n\treturn layout.SetMargins(margins.toW())\n}\n\nfunc setLayoutSpacing(layout walk.Layout, spacing int, spacingZero bool) error {\n\tif !spacingZero && spacing == 0 {\n\t\tspacing = 6\n\t}\n\n\treturn layout.SetSpacing(spacing)\n}\n\ntype HBox struct {\n\tMargins     Margins\n\tAlignment   Alignment2D\n\tSpacing     int\n\tMarginsZero bool\n\tSpacingZero bool\n}\n\nfunc (hb HBox) Create() (walk.Layout, error) {\n\tl := walk.NewHBoxLayout()\n\n\tif err := setLayoutMargins(l, hb.Margins, hb.MarginsZero); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setLayoutSpacing(l, hb.Spacing, hb.SpacingZero); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := l.SetAlignment(walk.Alignment2D(hb.Alignment)); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn l, nil\n}\n\ntype VBox struct {\n\tMargins     Margins\n\tAlignment   Alignment2D\n\tSpacing     int\n\tMarginsZero bool\n\tSpacingZero bool\n}\n\nfunc (vb VBox) Create() (walk.Layout, error) {\n\tl := walk.NewVBoxLayout()\n\n\tif err := setLayoutMargins(l, vb.Margins, vb.MarginsZero); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setLayoutSpacing(l, vb.Spacing, vb.SpacingZero); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := l.SetAlignment(walk.Alignment2D(vb.Alignment)); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn l, nil\n}\n\ntype Grid struct {\n\tRows        int\n\tColumns     int\n\tMargins     Margins\n\tAlignment   Alignment2D\n\tSpacing     int\n\tMarginsZero bool\n\tSpacingZero bool\n}\n\nfunc (g Grid) Create() (walk.Layout, error) {\n\tif g.Rows > 0 && g.Columns > 0 {\n\t\treturn nil, errors.New(\"only one of Rows and Columns may be > 0\")\n\t}\n\n\tl := walk.NewGridLayout()\n\n\tif err := setLayoutMargins(l, g.Margins, g.MarginsZero); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setLayoutSpacing(l, g.Spacing, g.SpacingZero); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := l.SetAlignment(walk.Alignment2D(g.Alignment)); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn l, nil\n}\n\ntype Flow struct {\n\tMargins     Margins\n\tAlignment   Alignment2D\n\tSpacing     int\n\tMarginsZero bool\n\tSpacingZero bool\n}\n\nfunc (f Flow) Create() (walk.Layout, error) {\n\tl := walk.NewFlowLayout()\n\n\tif err := setLayoutMargins(l, f.Margins, f.MarginsZero); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setLayoutSpacing(l, f.Spacing, f.SpacingZero); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := l.SetAlignment(walk.Alignment2D(f.Alignment)); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn l, nil\n}\n"
  },
  {
    "path": "declarative/lineedit.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype CaseMode uint32\n\nconst (\n\tCaseModeMixed CaseMode = CaseMode(walk.CaseModeMixed)\n\tCaseModeUpper CaseMode = CaseMode(walk.CaseModeUpper)\n\tCaseModeLower CaseMode = CaseMode(walk.CaseModeLower)\n)\n\ntype LineEdit struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// LineEdit\n\n\tAssignTo          **walk.LineEdit\n\tCaseMode          CaseMode\n\tCueBanner         string\n\tMaxLength         int\n\tOnEditingFinished walk.EventHandler\n\tOnTextChanged     walk.EventHandler\n\tPasswordMode      bool\n\tReadOnly          Property\n\tText              Property\n\tTextAlignment     Alignment1D\n\tTextColor         walk.Color\n}\n\nfunc (le LineEdit) Create(builder *Builder) error {\n\tw, err := walk.NewLineEdit(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif le.AssignTo != nil {\n\t\t*le.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(le, w, func() error {\n\t\tw.SetTextColor(le.TextColor)\n\n\t\tif err := w.SetTextAlignment(walk.Alignment1D(le.TextAlignment)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif le.CueBanner != \"\" {\n\t\t\tif err := w.SetCueBanner(le.CueBanner); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tw.SetMaxLength(le.MaxLength)\n\t\tw.SetPasswordMode(le.PasswordMode)\n\n\t\tif err := w.SetCaseMode(walk.CaseMode(le.CaseMode)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif le.OnEditingFinished != nil {\n\t\t\tw.EditingFinished().Attach(le.OnEditingFinished)\n\t\t}\n\t\tif le.OnTextChanged != nil {\n\t\t\tw.TextChanged().Attach(le.OnTextChanged)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/linklabel.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype LinkLabel struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// LinkLabel\n\n\tAssignTo        **walk.LinkLabel\n\tOnLinkActivated walk.LinkLabelLinkEventHandler\n\tText            Property\n}\n\nfunc (ll LinkLabel) Create(builder *Builder) error {\n\tw, err := walk.NewLinkLabel(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif ll.AssignTo != nil {\n\t\t*ll.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(ll, w, func() error {\n\t\tif ll.OnLinkActivated != nil {\n\t\t\tw.LinkActivated().Attach(ll.OnLinkActivated)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/listbox.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"errors\"\n\n\t\"github.com/lxn/walk\"\n\t\"github.com/lxn/win\"\n)\n\ntype ListBox struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// ListBox\n\n\tAssignTo                 **walk.ListBox\n\tBindingMember            string\n\tCurrentIndex             Property\n\tDisplayMember            string\n\tFormat                   string\n\tItemStyler               walk.ListItemStyler\n\tModel                    interface{}\n\tMultiSelection           bool\n\tOnCurrentIndexChanged    walk.EventHandler\n\tOnItemActivated          walk.EventHandler\n\tOnSelectedIndexesChanged walk.EventHandler\n\tPrecision                int\n\tValue                    Property\n}\n\nfunc (lb ListBox) Create(builder *Builder) error {\n\tvar w *walk.ListBox\n\tvar err error\n\tif _, ok := lb.Model.([]string); ok &&\n\t\t(lb.BindingMember != \"\" || lb.DisplayMember != \"\") {\n\n\t\treturn errors.New(\"ListBox.Create: BindingMember and DisplayMember must be empty for []string models.\")\n\t}\n\n\tvar style uint32\n\n\tif lb.ItemStyler != nil {\n\t\tstyle |= win.LBS_OWNERDRAWVARIABLE\n\t}\n\tif lb.MultiSelection {\n\t\tstyle |= win.LBS_EXTENDEDSEL\n\t}\n\n\tw, err = walk.NewListBoxWithStyle(builder.Parent(), style)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif lb.AssignTo != nil {\n\t\t*lb.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(lb, w, func() error {\n\t\tif lb.ItemStyler != nil {\n\t\t\tw.SetItemStyler(lb.ItemStyler)\n\t\t}\n\t\tw.SetFormat(lb.Format)\n\t\tw.SetPrecision(lb.Precision)\n\n\t\tif err := w.SetBindingMember(lb.BindingMember); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := w.SetDisplayMember(lb.DisplayMember); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := w.SetModel(lb.Model); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif lb.OnCurrentIndexChanged != nil {\n\t\t\tw.CurrentIndexChanged().Attach(lb.OnCurrentIndexChanged)\n\t\t}\n\t\tif lb.OnSelectedIndexesChanged != nil {\n\t\t\tw.SelectedIndexesChanged().Attach(lb.OnSelectedIndexesChanged)\n\t\t}\n\t\tif lb.OnItemActivated != nil {\n\t\t\tw.ItemActivated().Attach(lb.OnItemActivated)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/mainwindow.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport \"github.com/lxn/walk\"\n\ntype MainWindow struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftLayout  bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Container\n\n\tChildren   []Widget\n\tDataBinder DataBinder\n\tLayout     Layout\n\n\t// Form\n\n\tIcon  Property\n\tSize  Size\n\tTitle Property\n\n\t// MainWindow\n\n\tAssignTo          **walk.MainWindow\n\tBounds            Rectangle\n\tExpressions       func() map[string]walk.Expression\n\tFunctions         map[string]func(args ...interface{}) (interface{}, error)\n\tMenuItems         []MenuItem\n\tOnDropFiles       walk.DropFilesEventHandler\n\tStatusBarItems    []StatusBarItem\n\tSuspendedUntilRun bool\n\tToolBar           ToolBar\n\tToolBarItems      []MenuItem // Deprecated: use ToolBar instead\n}\n\nfunc (mw MainWindow) Create() error {\n\tw, err := walk.NewMainWindowWithCfg(&walk.MainWindowCfg{\n\t\tName:   mw.Name,\n\t\tBounds: mw.Bounds.toW(),\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif mw.AssignTo != nil {\n\t\t*mw.AssignTo = w\n\t}\n\n\tfi := formInfo{\n\t\t// Window\n\t\tBackground:         mw.Background,\n\t\tContextMenuItems:   mw.ContextMenuItems,\n\t\tDoubleBuffering:    mw.DoubleBuffering,\n\t\tEnabled:            mw.Enabled,\n\t\tFont:               mw.Font,\n\t\tMaxSize:            mw.MaxSize,\n\t\tMinSize:            mw.MinSize,\n\t\tName:               mw.Name,\n\t\tOnBoundsChanged:    mw.OnBoundsChanged,\n\t\tOnKeyDown:          mw.OnKeyDown,\n\t\tOnKeyPress:         mw.OnKeyPress,\n\t\tOnKeyUp:            mw.OnKeyUp,\n\t\tOnMouseDown:        mw.OnMouseDown,\n\t\tOnMouseMove:        mw.OnMouseMove,\n\t\tOnMouseUp:          mw.OnMouseUp,\n\t\tOnSizeChanged:      mw.OnSizeChanged,\n\t\tRightToLeftReading: mw.RightToLeftReading,\n\t\tVisible:            mw.Visible,\n\t\tAccessibility:      mw.Accessibility,\n\n\t\t// Container\n\t\tChildren:   mw.Children,\n\t\tDataBinder: mw.DataBinder,\n\t\tLayout:     mw.Layout,\n\n\t\t// Form\n\t\tIcon:  mw.Icon,\n\t\tTitle: mw.Title,\n\t}\n\n\tbuilder := NewBuilder(nil)\n\n\tw.SetSuspended(true)\n\tif !mw.SuspendedUntilRun {\n\t\tbuilder.Defer(func() error {\n\t\t\tw.SetSuspended(false)\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tbuilder.deferBuildMenuActions(w.Menu(), mw.MenuItems)\n\n\tif err := w.SetRightToLeftLayout(mw.RightToLeftLayout); err != nil {\n\t\treturn err\n\t}\n\n\treturn builder.InitWidget(fi, w, func() error {\n\t\tif len(mw.ToolBar.Items) > 0 {\n\t\t\tvar tb *walk.ToolBar\n\t\t\tif mw.ToolBar.AssignTo == nil {\n\t\t\t\tmw.ToolBar.AssignTo = &tb\n\t\t\t}\n\n\t\t\tif err := mw.ToolBar.Create(builder); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\told := w.ToolBar()\n\t\t\tw.SetToolBar(*mw.ToolBar.AssignTo)\n\t\t\told.Dispose()\n\t\t} else {\n\t\t\tbuilder.deferBuildActions(w.ToolBar().Actions(), mw.ToolBarItems)\n\t\t}\n\n\t\tfor _, sbi := range mw.StatusBarItems {\n\t\t\ts := walk.NewStatusBarItem()\n\t\t\tif sbi.AssignTo != nil {\n\t\t\t\t*sbi.AssignTo = s\n\t\t\t}\n\t\t\ts.SetIcon(sbi.Icon)\n\t\t\ts.SetText(sbi.Text)\n\t\t\ts.SetToolTipText(sbi.ToolTipText)\n\t\t\tif sbi.Width > 0 {\n\t\t\t\ts.SetWidth(sbi.Width)\n\t\t\t}\n\t\t\tif sbi.OnClicked != nil {\n\t\t\t\ts.Clicked().Attach(sbi.OnClicked)\n\t\t\t}\n\t\t\tw.StatusBar().Items().Add(s)\n\t\t}\n\n\t\tif mw.Size.Width > 0 && mw.Size.Height > 0 {\n\t\t\tif err := w.SetSize(mw.Size.toW()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\timageList, err := walk.NewImageListForDPI(walk.SizeFrom96DPI(walk.Size{16, 16}, builder.dpi), 0, builder.dpi)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tw.ToolBar().SetImageList(imageList)\n\n\t\tif mw.OnDropFiles != nil {\n\t\t\tw.DropFiles().Attach(mw.OnDropFiles)\n\t\t}\n\n\t\t// if mw.AssignTo != nil {\n\t\t// \t*mw.AssignTo = w\n\t\t// }\n\n\t\tif mw.Expressions != nil {\n\t\t\tfor name, expr := range mw.Expressions() {\n\t\t\t\tbuilder.expressions[name] = expr\n\t\t\t}\n\t\t}\n\t\tif mw.Functions != nil {\n\t\t\tfor name, fn := range mw.Functions {\n\t\t\t\tbuilder.functions[name] = fn\n\t\t\t}\n\t\t}\n\n\t\tbuilder.Defer(func() error {\n\t\t\tif mw.Visible != false {\n\t\t\t\tw.Show()\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\n\t\treturn nil\n\t})\n}\n\nfunc (mw MainWindow) Run() (int, error) {\n\tvar w *walk.MainWindow\n\n\tif mw.AssignTo == nil {\n\t\tmw.AssignTo = &w\n\t}\n\n\tif err := mw.Create(); err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn (*mw.AssignTo).Run(), nil\n}\n\ntype StatusBarItem struct {\n\tAssignTo    **walk.StatusBarItem\n\tIcon        *walk.Icon\n\tText        string\n\tToolTipText string\n\tWidth       int\n\tOnClicked   walk.EventHandler\n}\n"
  },
  {
    "path": "declarative/nonwin.go",
    "content": "// Copyright 2010 The win Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build !windows\n\npackage declarative\n"
  },
  {
    "path": "declarative/numberedit.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype NumberEdit struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// NumberEdit\n\n\tAssignTo           **walk.NumberEdit\n\tDecimals           int\n\tIncrement          float64\n\tMaxValue           float64\n\tMinValue           float64\n\tPrefix             Property\n\tOnValueChanged     walk.EventHandler\n\tReadOnly           Property\n\tSpinButtonsVisible bool\n\tSuffix             Property\n\tTextColor          walk.Color\n\tValue              Property\n}\n\nfunc (ne NumberEdit) Create(builder *Builder) error {\n\tw, err := walk.NewNumberEdit(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif ne.AssignTo != nil {\n\t\t*ne.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(ne, w, func() error {\n\t\tw.SetTextColor(ne.TextColor)\n\n\t\tif err := w.SetDecimals(ne.Decimals); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tinc := ne.Increment\n\t\tif inc == 0 {\n\t\t\tinc = 1\n\t\t}\n\n\t\tif err := w.SetIncrement(inc); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif ne.MinValue != 0 || ne.MaxValue != 0 {\n\t\t\tif err := w.SetRange(ne.MinValue, ne.MaxValue); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err := w.SetSpinButtonsVisible(ne.SpinButtonsVisible); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif ne.OnValueChanged != nil {\n\t\t\tw.ValueChanged().Attach(ne.OnValueChanged)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/numberlabel.go",
    "content": "// Copyright 2018 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype NumberLabel struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// static\n\n\tTextColor walk.Color\n\n\t// NumberLabel\n\n\tAssignTo      **walk.NumberLabel\n\tDecimals      Property\n\tSuffix        Property\n\tTextAlignment Alignment1D\n\tValue         Property\n}\n\nfunc (nl NumberLabel) Create(builder *Builder) error {\n\tw, err := walk.NewNumberLabel(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif nl.AssignTo != nil {\n\t\t*nl.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(nl, w, func() error {\n\t\tif err := w.SetTextAlignment(walk.Alignment1D(nl.TextAlignment)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tw.SetTextColor(nl.TextColor)\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/progressbar.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype ProgressBar struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// ProgressBar\n\n\tAssignTo    **walk.ProgressBar\n\tMarqueeMode bool\n\tMaxValue    int\n\tMinValue    int\n\tValue       int\n}\n\nfunc (pb ProgressBar) Create(builder *Builder) error {\n\tw, err := walk.NewProgressBar(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif pb.AssignTo != nil {\n\t\t*pb.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(pb, w, func() error {\n\t\tif pb.MaxValue > pb.MinValue {\n\t\t\tw.SetRange(pb.MinValue, pb.MaxValue)\n\t\t}\n\t\tw.SetValue(pb.Value)\n\n\t\tif err := w.SetMarqueeMode(pb.MarqueeMode); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/pushbutton.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype PushButton struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Button\n\n\tImage     Property\n\tOnClicked walk.EventHandler\n\tText      Property\n\n\t// PushButton\n\n\tAssignTo       **walk.PushButton\n\tImageAboveText bool\n}\n\nfunc (pb PushButton) Create(builder *Builder) error {\n\tw, err := walk.NewPushButton(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif pb.AssignTo != nil {\n\t\t*pb.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(pb, w, func() error {\n\t\tif err := w.SetImageAboveText(pb.ImageAboveText); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif pb.OnClicked != nil {\n\t\t\tw.Clicked().Attach(pb.OnClicked)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/radiobutton.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype RadioButton struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Button\n\n\tOnClicked walk.EventHandler\n\tText      Property\n\n\t// RadioButton\n\n\tAssignTo       **walk.RadioButton\n\tTextOnLeftSide bool\n\tValue          interface{}\n}\n\nfunc (rb RadioButton) Create(builder *Builder) error {\n\tw, err := walk.NewRadioButton(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif rb.AssignTo != nil {\n\t\t*rb.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(rb, w, func() error {\n\t\tw.SetValue(rb.Value)\n\n\t\tif err := w.SetTextOnLeftSide(rb.TextOnLeftSide); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif rb.OnClicked != nil {\n\t\t\tw.Clicked().Attach(rb.OnClicked)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/radiobuttongroup.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype RadioButtonGroup struct {\n\tButtons    []RadioButton\n\tDataMember string\n\tOptional   bool\n}\n\nfunc (rbg RadioButtonGroup) Create(builder *Builder) error {\n\tif len(rbg.Buttons) == 0 {\n\t\treturn nil\n\t}\n\n\tvar first *walk.RadioButton\n\n\tfor _, rb := range rbg.Buttons {\n\t\tif first == nil {\n\t\t\tif rb.AssignTo == nil {\n\t\t\t\trb.AssignTo = &first\n\t\t\t}\n\t\t}\n\n\t\tif err := rb.Create(builder); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif first == nil {\n\t\t\tfirst = *rb.AssignTo\n\t\t}\n\t}\n\n\tparent := builder.Parent()\n\n\tbuilder.Defer(func() error {\n\t\tgroup := first.Group()\n\n\t\tvalidator := newRadioButtonGroupValidator(group, parent)\n\n\t\tfor _, rb := range group.Buttons() {\n\t\t\tprop := rb.AsWindowBase().Property(\"CheckedValue\")\n\n\t\t\tif err := prop.SetSource(rbg.DataMember); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := prop.SetValidator(validator); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n\n\treturn nil\n}\n\ntype radioButtonGroupValidator struct {\n\tgroup *walk.RadioButtonGroup\n\terr   error\n}\n\nfunc newRadioButtonGroupValidator(group *walk.RadioButtonGroup, parent walk.Container) *radioButtonGroupValidator {\n\tb := new(bytes.Buffer)\n\n\tif gb, ok := parent.(*walk.GroupBox); ok {\n\t\tb.WriteString(gb.Title())\n\t} else {\n\t\tfor i, rb := range group.Buttons() {\n\t\t\tif i > 0 {\n\t\t\t\tb.WriteString(\", \")\n\t\t\t}\n\n\t\t\tb.WriteString(rb.Text())\n\t\t}\n\t}\n\n\tb.WriteString(\": \")\n\n\tb.WriteString(tr(\"A selection is required.\", \"walk\"))\n\n\treturn &radioButtonGroupValidator{group: group, err: errors.New(b.String())}\n}\n\nfunc (rbgv *radioButtonGroupValidator) Validate(v interface{}) error {\n\tif rbgv.group.CheckedButton() == nil {\n\t\treturn rbgv.err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "declarative/radiobuttongroupbox.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype RadioButtonGroupBox struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Container\n\n\tChildren   []Widget\n\tDataBinder DataBinder\n\tLayout     Layout\n\n\t// GroupBox\n\n\tAssignTo  **walk.GroupBox\n\tCheckable bool\n\tChecked   Property\n\tTitle     string\n\n\t// RadioButtonGroupBox\n\n\tButtons    []RadioButton\n\tDataMember string\n\tOptional   bool\n}\n\nfunc (rbgb RadioButtonGroupBox) Create(builder *Builder) error {\n\tw, err := walk.NewGroupBox(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif rbgb.AssignTo != nil {\n\t\t*rbgb.AssignTo = w\n\t}\n\n\tw.SetSuspended(true)\n\tbuilder.Defer(func() error {\n\t\tw.SetSuspended(false)\n\t\treturn nil\n\t})\n\n\treturn builder.InitWidget(rbgb, w, func() error {\n\t\tif err := w.SetTitle(rbgb.Title); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tw.SetCheckable(rbgb.Checkable)\n\n\t\tif err := (RadioButtonGroup{\n\t\t\tDataMember: rbgb.DataMember,\n\t\t\tOptional:   rbgb.Optional,\n\t\t\tButtons:    rbgb.Buttons,\n\t\t}).Create(builder); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/scrollview.go",
    "content": "// Copyright 2014 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype ScrollView struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Container\n\n\tChildren   []Widget\n\tDataBinder DataBinder\n\tLayout     Layout\n\n\t// ScrollView\n\n\tAssignTo        **walk.ScrollView\n\tHorizontalFixed bool\n\tVerticalFixed   bool\n}\n\nfunc (sv ScrollView) Create(builder *Builder) error {\n\tw, err := walk.NewScrollView(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif sv.AssignTo != nil {\n\t\t*sv.AssignTo = w\n\t}\n\n\tw.SetSuspended(true)\n\tbuilder.Defer(func() error {\n\t\tw.SetSuspended(false)\n\t\treturn nil\n\t})\n\n\tw.SetScrollbars(!sv.HorizontalFixed, !sv.VerticalFixed)\n\n\treturn builder.InitWidget(sv, w, func() error {\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/separator.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype HSeparator struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Separator\n\n\tAssignTo **walk.Separator\n}\n\nfunc (s HSeparator) Create(builder *Builder) error {\n\tw, err := walk.NewHSeparator(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif s.AssignTo != nil {\n\t\t*s.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(s, w, func() error {\n\t\treturn nil\n\t})\n}\n\ntype VSeparator struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tContextMenuItems []MenuItem\n\tEnabled          Property\n\tFont             Font\n\tMaxSize          Size\n\tMinSize          Size\n\tName             string\n\tOnBoundsChanged  walk.EventHandler\n\tOnKeyDown        walk.KeyEventHandler\n\tOnKeyPress       walk.KeyEventHandler\n\tOnKeyUp          walk.KeyEventHandler\n\tOnMouseDown      walk.MouseEventHandler\n\tOnMouseMove      walk.MouseEventHandler\n\tOnMouseUp        walk.MouseEventHandler\n\tOnSizeChanged    walk.EventHandler\n\tPersistent       bool\n\tToolTipText      Property\n\tVisible          Property\n\n\t// Widget\n\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Separator\n\n\tAssignTo **walk.Separator\n}\n\nfunc (s VSeparator) Create(builder *Builder) error {\n\tw, err := walk.NewVSeparator(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif s.AssignTo != nil {\n\t\t*s.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(s, w, func() error {\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/slider.go",
    "content": "// Copyright 2016 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype Slider struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Slider\n\n\tAssignTo       **walk.Slider\n\tLineSize       int\n\tMaxValue       int\n\tMinValue       int\n\tOrientation    Orientation\n\tOnValueChanged walk.EventHandler\n\tPageSize       int\n\tToolTipsHidden bool\n\tTracking       bool\n\tValue          Property\n}\n\nfunc (sl Slider) Create(builder *Builder) error {\n\tw, err := walk.NewSliderWithCfg(builder.Parent(), &walk.SliderCfg{\n\t\tOrientation:    walk.Orientation(sl.Orientation),\n\t\tToolTipsHidden: sl.ToolTipsHidden,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif sl.AssignTo != nil {\n\t\t*sl.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(sl, w, func() error {\n\t\tw.SetPersistent(sl.Persistent)\n\t\tif sl.LineSize > 0 {\n\t\t\tw.SetLineSize(sl.LineSize)\n\t\t}\n\t\tif sl.PageSize > 0 {\n\t\t\tw.SetPageSize(sl.PageSize)\n\t\t}\n\t\tw.SetTracking(sl.Tracking)\n\n\t\tif sl.MaxValue > sl.MinValue {\n\t\t\tw.SetRange(sl.MinValue, sl.MaxValue)\n\t\t}\n\n\t\tif sl.OnValueChanged != nil {\n\t\t\tw.ValueChanged().Attach(sl.OnValueChanged)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/spacer.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype HSpacer struct {\n\t// Window\n\n\tMaxSize Size\n\tMinSize Size\n\tName    string\n\n\t// Widget\n\n\tColumn        int\n\tColumnSpan    int\n\tRow           int\n\tRowSpan       int\n\tStretchFactor int\n\n\t// Spacer\n\n\tGreedyLocallyOnly bool\n\tSize              int\n}\n\nfunc (hs HSpacer) Create(builder *Builder) (err error) {\n\tvar flags walk.LayoutFlags\n\tif hs.Size == 0 {\n\t\tflags = walk.ShrinkableHorz | walk.GrowableHorz | walk.GreedyHorz\n\t}\n\n\tvar w *walk.Spacer\n\tif w, err = walk.NewSpacerWithCfg(builder.Parent(), &walk.SpacerCfg{\n\t\tLayoutFlags:       flags,\n\t\tSizeHint:          Size{Width: hs.Size}.toW(),\n\t\tGreedyLocallyOnly: hs.GreedyLocallyOnly,\n\t}); err != nil {\n\t\treturn\n\t}\n\n\treturn builder.InitWidget(hs, w, nil)\n}\n\ntype VSpacer struct {\n\t// Window\n\n\tMaxSize Size\n\tMinSize Size\n\tName    string\n\n\t// Widget\n\n\tColumn        int\n\tColumnSpan    int\n\tRow           int\n\tRowSpan       int\n\tStretchFactor int\n\n\t// Spacer\n\n\tGreedyLocallyOnly bool\n\tSize              int\n}\n\nfunc (vs VSpacer) Create(builder *Builder) (err error) {\n\tvar flags walk.LayoutFlags\n\tif vs.Size == 0 {\n\t\tflags = walk.ShrinkableVert | walk.GrowableVert | walk.GreedyVert\n\t}\n\n\tvar w *walk.Spacer\n\tif w, err = walk.NewSpacerWithCfg(builder.Parent(), &walk.SpacerCfg{\n\t\tLayoutFlags:       flags,\n\t\tSizeHint:          Size{Height: vs.Size}.toW(),\n\t\tGreedyLocallyOnly: vs.GreedyLocallyOnly,\n\t}); err != nil {\n\t\treturn\n\t}\n\n\treturn builder.InitWidget(vs, w, nil)\n}\n"
  },
  {
    "path": "declarative/splitbutton.go",
    "content": "// Copyright 2016 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype SplitButton struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Button\n\n\tImage     Property\n\tText      Property\n\tOnClicked walk.EventHandler\n\n\t// SplitButton\n\n\tAssignTo       **walk.SplitButton\n\tImageAboveText bool\n\tMenuItems      []MenuItem\n}\n\nfunc (sb SplitButton) Create(builder *Builder) error {\n\tw, err := walk.NewSplitButton(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif sb.AssignTo != nil {\n\t\t*sb.AssignTo = w\n\t}\n\n\tbuilder.deferBuildMenuActions(w.Menu(), sb.MenuItems)\n\n\treturn builder.InitWidget(sb, w, func() error {\n\t\tif err := w.SetImageAboveText(sb.ImageAboveText); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif sb.OnClicked != nil {\n\t\t\tw.Clicked().Attach(sb.OnClicked)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/splitter.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype HSplitter struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Container\n\n\tChildren   []Widget\n\tDataBinder DataBinder\n\n\t// Splitter\n\n\tAssignTo    **walk.Splitter\n\tHandleWidth int\n}\n\nfunc (s HSplitter) Create(builder *Builder) error {\n\tw, err := walk.NewHSplitter(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif s.AssignTo != nil {\n\t\t*s.AssignTo = w\n\t}\n\n\tw.SetSuspended(true)\n\tbuilder.Defer(func() error {\n\t\tw.SetSuspended(false)\n\t\treturn nil\n\t})\n\n\treturn builder.InitWidget(s, w, func() error {\n\t\tif s.HandleWidth > 0 {\n\t\t\tif err := w.SetHandleWidth(s.HandleWidth); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\ntype VSplitter struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Container\n\n\tChildren   []Widget\n\tDataBinder DataBinder\n\n\t// Splitter\n\n\tAssignTo    **walk.Splitter\n\tHandleWidth int\n}\n\nfunc (s VSplitter) Create(builder *Builder) error {\n\tw, err := walk.NewVSplitter(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif s.AssignTo != nil {\n\t\t*s.AssignTo = w\n\t}\n\n\tw.SetSuspended(true)\n\tbuilder.Defer(func() error {\n\t\tw.SetSuspended(false)\n\t\treturn nil\n\t})\n\n\treturn builder.InitWidget(s, w, func() error {\n\t\tif s.HandleWidth > 0 {\n\t\t\tif err := w.SetHandleWidth(s.HandleWidth); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/tableview.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n\t\"github.com/lxn/win\"\n)\n\ntype TableView struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// TableView\n\n\tAlternatingRowBG            bool\n\tAssignTo                    **walk.TableView\n\tCellStyler                  walk.CellStyler\n\tCheckBoxes                  bool\n\tColumns                     []TableViewColumn\n\tColumnsOrderable            Property\n\tColumnsSizable              Property\n\tCustomHeaderHeight          int\n\tCustomRowHeight             int\n\tItemStateChangedEventDelay  int\n\tHeaderHidden                bool\n\tLastColumnStretched         bool\n\tModel                       interface{}\n\tMultiSelection              bool\n\tNotSortableByHeaderClick    bool\n\tOnCurrentIndexChanged       walk.EventHandler\n\tOnItemActivated             walk.EventHandler\n\tOnSelectedIndexesChanged    walk.EventHandler\n\tSelectionHiddenWithoutFocus bool\n\tStyleCell                   func(style *walk.CellStyle)\n}\n\ntype tvStyler struct {\n\tdflt              walk.CellStyler\n\tcolStyleCellFuncs []func(style *walk.CellStyle)\n}\n\nfunc (tvs *tvStyler) StyleCell(style *walk.CellStyle) {\n\tif tvs.dflt != nil {\n\t\ttvs.dflt.StyleCell(style)\n\t}\n\n\tif col := style.Col(); col >= 0 {\n\t\tif styleCell := tvs.colStyleCellFuncs[col]; styleCell != nil {\n\t\t\tstyleCell(style)\n\t\t}\n\t}\n}\n\ntype styleCellFunc func(style *walk.CellStyle)\n\nfunc (scf styleCellFunc) StyleCell(style *walk.CellStyle) {\n\tscf(style)\n}\n\nfunc (tv TableView) Create(builder *Builder) error {\n\tvar w *walk.TableView\n\tvar err error\n\tif tv.NotSortableByHeaderClick {\n\t\tw, err = walk.NewTableViewWithStyle(builder.Parent(), win.LVS_NOSORTHEADER)\n\t} else {\n\t\tw, err = walk.NewTableViewWithCfg(builder.Parent(), &walk.TableViewCfg{CustomHeaderHeight: tv.CustomHeaderHeight, CustomRowHeight: tv.CustomRowHeight})\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif tv.AssignTo != nil {\n\t\t*tv.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(tv, w, func() error {\n\t\tfor i := range tv.Columns {\n\t\t\tif err := tv.Columns[i].Create(w); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err := w.SetModel(tv.Model); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefaultStyler, _ := tv.Model.(walk.CellStyler)\n\n\t\tif tv.CellStyler != nil {\n\t\t\tdefaultStyler = tv.CellStyler\n\t\t}\n\n\t\tif tv.StyleCell != nil {\n\t\t\tdefaultStyler = styleCellFunc(tv.StyleCell)\n\t\t}\n\n\t\tvar hasColStyleFunc bool\n\t\tfor _, c := range tv.Columns {\n\t\t\tif c.StyleCell != nil {\n\t\t\t\thasColStyleFunc = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif defaultStyler != nil || hasColStyleFunc {\n\t\t\tvar styler walk.CellStyler\n\n\t\t\tif hasColStyleFunc {\n\t\t\t\ttvs := &tvStyler{\n\t\t\t\t\tdflt:              defaultStyler,\n\t\t\t\t\tcolStyleCellFuncs: make([]func(style *walk.CellStyle), len(tv.Columns)),\n\t\t\t\t}\n\n\t\t\t\tstyler = tvs\n\n\t\t\t\tfor i, c := range tv.Columns {\n\t\t\t\t\ttvs.colStyleCellFuncs[i] = c.StyleCell\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tstyler = defaultStyler\n\t\t\t}\n\n\t\t\tw.SetCellStyler(styler)\n\t\t}\n\n\t\tw.SetAlternatingRowBG(tv.AlternatingRowBG)\n\t\tw.SetCheckBoxes(tv.CheckBoxes)\n\t\tw.SetItemStateChangedEventDelay(tv.ItemStateChangedEventDelay)\n\t\tif err := w.SetLastColumnStretched(tv.LastColumnStretched); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := w.SetMultiSelection(tv.MultiSelection); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := w.SetSelectionHiddenWithoutFocus(tv.SelectionHiddenWithoutFocus); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := w.SetHeaderHidden(tv.HeaderHidden); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif tv.OnCurrentIndexChanged != nil {\n\t\t\tw.CurrentIndexChanged().Attach(tv.OnCurrentIndexChanged)\n\t\t}\n\t\tif tv.OnSelectedIndexesChanged != nil {\n\t\t\tw.SelectedIndexesChanged().Attach(tv.OnSelectedIndexesChanged)\n\t\t}\n\t\tif tv.OnItemActivated != nil {\n\t\t\tw.ItemActivated().Attach(tv.OnItemActivated)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/tableviewcolumn.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype Alignment1D uint\n\nconst (\n\tAlignDefault = Alignment1D(walk.AlignDefault)\n\tAlignNear    = Alignment1D(walk.AlignNear)\n\tAlignCenter  = Alignment1D(walk.AlignCenter)\n\tAlignFar     = Alignment1D(walk.AlignFar)\n)\n\ntype TableViewColumn struct {\n\tName       string\n\tDataMember string\n\tFormat     string\n\tTitle      string\n\tAlignment  Alignment1D\n\tPrecision  int\n\tWidth      int\n\tHidden     bool\n\tFrozen     bool\n\tStyleCell  func(style *walk.CellStyle)\n\tLessFunc   func(i, j int) bool\n\tFormatFunc func(value interface{}) string\n}\n\nfunc (tvc TableViewColumn) Create(tv *walk.TableView) error {\n\tw := walk.NewTableViewColumn()\n\n\tif err := w.SetAlignment(walk.Alignment1D(tvc.Alignment)); err != nil {\n\t\treturn err\n\t}\n\tw.SetDataMember(tvc.DataMember)\n\tif tvc.Format != \"\" {\n\t\tif err := w.SetFormat(tvc.Format); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := w.SetPrecision(tvc.Precision); err != nil {\n\t\treturn err\n\t}\n\tw.SetName(tvc.Name)\n\tif err := w.SetTitle(tvc.Title); err != nil {\n\t\treturn err\n\t}\n\tif err := w.SetVisible(!tvc.Hidden); err != nil {\n\t\treturn err\n\t}\n\tif err := w.SetFrozen(tvc.Frozen); err != nil {\n\t\treturn err\n\t}\n\tif err := w.SetWidth(tvc.Width); err != nil {\n\t\treturn err\n\t}\n\tw.SetLessFunc(tvc.LessFunc)\n\tw.SetFormatFunc(tvc.FormatFunc)\n\n\treturn tv.Columns().Add(w)\n}\n"
  },
  {
    "path": "declarative/tabpage.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype TabPage struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Container\n\n\tChildren   []Widget\n\tDataBinder DataBinder\n\tLayout     Layout\n\n\t// TabPage\n\n\tAssignTo **walk.TabPage\n\tContent  Widget\n\tImage    Property\n\tTitle    Property\n}\n\nfunc (tp TabPage) Create(builder *Builder) error {\n\tw, err := walk.NewTabPage()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif tp.AssignTo != nil {\n\t\t*tp.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(tp, w, func() error {\n\t\tif tp.Content != nil && len(tp.Children) == 0 {\n\t\t\tif err := tp.Content.Create(builder); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/tabwidget.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype TabWidget struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// TabWidget\n\n\tAssignTo              **walk.TabWidget\n\tContentMargins        Margins\n\tContentMarginsZero    bool\n\tOnCurrentIndexChanged walk.EventHandler\n\tPages                 []TabPage\n}\n\nfunc (tw TabWidget) Create(builder *Builder) error {\n\tw, err := walk.NewTabWidget(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif tw.AssignTo != nil {\n\t\t*tw.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(tw, w, func() error {\n\t\tfor _, tp := range tw.Pages {\n\t\t\tvar wp *walk.TabPage\n\t\t\tif tp.AssignTo == nil {\n\t\t\t\ttp.AssignTo = &wp\n\t\t\t}\n\n\t\t\tif tp.Content != nil && len(tp.Children) == 0 {\n\t\t\t\ttp.Layout = HBox{Margins: tw.ContentMargins, MarginsZero: tw.ContentMarginsZero}\n\t\t\t}\n\n\t\t\tif err := tp.Create(builder); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := w.Pages().Add(*tp.AssignTo); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif tw.OnCurrentIndexChanged != nil {\n\t\t\tw.CurrentIndexChanged().Attach(tw.OnCurrentIndexChanged)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/textedit.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n\t\"github.com/lxn/win\"\n)\n\ntype TextEdit struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// TextEdit\n\n\tAssignTo      **walk.TextEdit\n\tCompactHeight bool\n\tHScroll       bool\n\tMaxLength     int\n\tOnTextChanged walk.EventHandler\n\tReadOnly      Property\n\tText          Property\n\tTextAlignment Alignment1D\n\tTextColor     walk.Color\n\tVScroll       bool\n}\n\nfunc (te TextEdit) Create(builder *Builder) error {\n\tvar style uint32\n\tif te.HScroll {\n\t\tstyle |= win.WS_HSCROLL\n\t}\n\tif te.VScroll {\n\t\tstyle |= win.WS_VSCROLL\n\t}\n\n\tw, err := walk.NewTextEditWithStyle(builder.Parent(), style)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif te.AssignTo != nil {\n\t\t*te.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(te, w, func() error {\n\t\tw.SetCompactHeight(te.CompactHeight)\n\t\tw.SetTextColor(te.TextColor)\n\n\t\tif err := w.SetTextAlignment(walk.Alignment1D(te.TextAlignment)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif te.MaxLength > 0 {\n\t\t\tw.SetMaxLength(te.MaxLength)\n\t\t}\n\n\t\tif te.OnTextChanged != nil {\n\t\t\tw.TextChanged().Attach(te.OnTextChanged)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/textlabel.go",
    "content": "// Copyright 2018 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n\t\"github.com/lxn/win\"\n)\n\ntype Alignment2D uint\n\nconst (\n\tAlignHVDefault      = Alignment2D(walk.AlignHVDefault)\n\tAlignHNearVNear     = Alignment2D(walk.AlignHNearVNear)\n\tAlignHCenterVNear   = Alignment2D(walk.AlignHCenterVNear)\n\tAlignHFarVNear      = Alignment2D(walk.AlignHFarVNear)\n\tAlignHNearVCenter   = Alignment2D(walk.AlignHNearVCenter)\n\tAlignHCenterVCenter = Alignment2D(walk.AlignHCenterVCenter)\n\tAlignHFarVCenter    = Alignment2D(walk.AlignHFarVCenter)\n\tAlignHNearVFar      = Alignment2D(walk.AlignHNearVFar)\n\tAlignHCenterVFar    = Alignment2D(walk.AlignHCenterVFar)\n\tAlignHFarVFar       = Alignment2D(walk.AlignHFarVFar)\n)\n\ntype TextLabel struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size // Set MinSize.Width to a value > 0 to enable dynamic line wrapping.\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// static\n\n\tTextColor walk.Color\n\n\t// Text\n\n\tAssignTo      **walk.TextLabel\n\tNoPrefix      bool\n\tTextAlignment Alignment2D\n\tText          Property\n}\n\nfunc (tl TextLabel) Create(builder *Builder) error {\n\tvar style uint32\n\tif tl.NoPrefix {\n\t\tstyle |= win.SS_NOPREFIX\n\t}\n\n\tw, err := walk.NewTextLabelWithStyle(builder.Parent(), style)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif tl.AssignTo != nil {\n\t\t*tl.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(tl, w, func() error {\n\t\tw.SetTextColor(tl.TextColor)\n\n\t\tif err := w.SetTextAlignment(walk.Alignment2D(tl.TextAlignment)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/toolbar.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype ToolBarButtonStyle int\n\nconst (\n\tToolBarButtonImageOnly ToolBarButtonStyle = iota\n\tToolBarButtonTextOnly\n\tToolBarButtonImageBeforeText\n\tToolBarButtonImageAboveText\n)\n\ntype ToolBar struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// ToolBar\n\n\tActions     []*walk.Action // Deprecated, use Items instead\n\tAssignTo    **walk.ToolBar\n\tButtonStyle ToolBarButtonStyle\n\tItems       []MenuItem\n\tMaxTextRows int\n\tOrientation Orientation\n}\n\nfunc (tb ToolBar) Create(builder *Builder) error {\n\tw, err := walk.NewToolBarWithOrientationAndButtonStyle(builder.Parent(), walk.Orientation(tb.Orientation), walk.ToolBarButtonStyle(tb.ButtonStyle))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif tb.AssignTo != nil {\n\t\t*tb.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(tb, w, func() error {\n\t\timageList, err := walk.NewImageList(walk.Size{16, 16}, 0)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tw.SetImageList(imageList)\n\n\t\tmtr := tb.MaxTextRows\n\t\tif mtr < 1 {\n\t\t\tmtr = 1\n\t\t}\n\t\tif err := w.SetMaxTextRows(mtr); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif len(tb.Items) > 0 {\n\t\t\tbuilder.deferBuildActions(w.Actions(), tb.Items)\n\t\t} else {\n\t\t\tif err := addToActionList(w.Actions(), tb.Actions); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/toolbutton.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype ToolButton struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// Button\n\n\tImage     Property\n\tOnClicked walk.EventHandler\n\tText      Property\n\n\t// ToolButton\n\n\tAssignTo **walk.ToolButton\n}\n\nfunc (tb ToolButton) Create(builder *Builder) error {\n\tw, err := walk.NewToolButton(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif tb.AssignTo != nil {\n\t\t*tb.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(tb, w, func() error {\n\t\tif tb.OnClicked != nil {\n\t\t\tw.Clicked().Attach(tb.OnClicked)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/treeview.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype TreeView struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// TreeView\n\n\tAssignTo             **walk.TreeView\n\tItemHeight           int\n\tModel                walk.TreeModel\n\tOnCurrentItemChanged walk.EventHandler\n\tOnExpandedChanged    walk.TreeItemEventHandler\n\tOnItemActivated      walk.EventHandler\n}\n\nfunc (tv TreeView) Create(builder *Builder) error {\n\tw, err := walk.NewTreeView(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif tv.AssignTo != nil {\n\t\t*tv.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(tv, w, func() error {\n\t\tif tv.ItemHeight > 0 {\n\t\t\tw.SetItemHeight(w.IntFrom96DPI(tv.ItemHeight)) // VERIFY: Item height should resize on DPI change.\n\t\t}\n\n\t\tif err := w.SetModel(tv.Model); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif tv.OnCurrentItemChanged != nil {\n\t\t\tw.CurrentItemChanged().Attach(tv.OnCurrentItemChanged)\n\t\t}\n\n\t\tif tv.OnExpandedChanged != nil {\n\t\t\tw.ExpandedChanged().Attach(tv.OnExpandedChanged)\n\t\t}\n\n\t\tif tv.OnItemActivated != nil {\n\t\t\tw.ItemActivated().Attach(tv.OnItemActivated)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "declarative/validators.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype ValidatorRef struct {\n\tValidator walk.Validator\n}\n\nfunc (vr ValidatorRef) Create() (walk.Validator, error) {\n\treturn vr.Validator, nil\n}\n\ntype Range struct {\n\tMin float64\n\tMax float64\n}\n\nfunc (r Range) Create() (walk.Validator, error) {\n\treturn walk.NewRangeValidator(r.Min, r.Max)\n}\n\ntype Regexp struct {\n\tPattern string\n}\n\nfunc (re Regexp) Create() (walk.Validator, error) {\n\treturn walk.NewRegexpValidator(re.Pattern)\n}\n\ntype SelRequired struct {\n}\n\nfunc (SelRequired) Create() (walk.Validator, error) {\n\treturn walk.SelectionRequiredValidator(), nil\n}\n\ntype dMultiValidator struct {\n\tvalidators []Validator\n}\n\nfunc (av dMultiValidator) Create() (walk.Validator, error) {\n\tvar validators []walk.Validator\n\n\tfor _, dv := range av.validators {\n\t\tif wv, err := dv.Create(); err != nil {\n\t\t\treturn nil, err\n\t\t} else {\n\t\t\tvalidators = append(validators, wv)\n\t\t}\n\t}\n\n\treturn &wMultiValidator{validators}, nil\n}\n\ntype wMultiValidator struct {\n\tvalidators []walk.Validator\n}\n\nfunc (av *wMultiValidator) Validate(v interface{}) error {\n\tfor _, validator := range av.validators {\n\t\tif err := validator.Validate(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "declarative/webview.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage declarative\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype WebView struct {\n\t// Window\n\n\tAccessibility      Accessibility\n\tBackground         Brush\n\tContextMenuItems   []MenuItem\n\tDoubleBuffering    bool\n\tEnabled            Property\n\tFont               Font\n\tMaxSize            Size\n\tMinSize            Size\n\tName               string\n\tOnBoundsChanged    walk.EventHandler\n\tOnKeyDown          walk.KeyEventHandler\n\tOnKeyPress         walk.KeyEventHandler\n\tOnKeyUp            walk.KeyEventHandler\n\tOnMouseDown        walk.MouseEventHandler\n\tOnMouseMove        walk.MouseEventHandler\n\tOnMouseUp          walk.MouseEventHandler\n\tOnSizeChanged      walk.EventHandler\n\tPersistent         bool\n\tRightToLeftReading bool\n\tToolTipText        Property\n\tVisible            Property\n\n\t// Widget\n\n\tAlignment          Alignment2D\n\tAlwaysConsumeSpace bool\n\tColumn             int\n\tColumnSpan         int\n\tGraphicsEffects    []walk.WidgetGraphicsEffect\n\tRow                int\n\tRowSpan            int\n\tStretchFactor      int\n\n\t// WebView\n\n\tAssignTo                          **walk.WebView\n\tNativeContextMenuEnabled          Property\n\tOnBrowserVisibleChanged           walk.EventHandler\n\tOnCanGoBackChanged                walk.EventHandler\n\tOnCanGoForwardChanged             walk.EventHandler\n\tOnDocumentCompleted               walk.StringEventHandler\n\tOnDocumentTitleChanged            walk.EventHandler\n\tOnDownloaded                      walk.EventHandler\n\tOnDownloading                     walk.EventHandler\n\tOnNativeContextMenuEnabledChanged walk.EventHandler\n\tOnNavigated                       walk.StringEventHandler\n\tOnNavigatedError                  walk.WebViewNavigatedErrorEventHandler\n\tOnNavigating                      walk.WebViewNavigatingEventHandler\n\tOnNewWindow                       walk.WebViewNewWindowEventHandler\n\tOnProgressChanged                 walk.EventHandler\n\tOnQuitting                        walk.EventHandler\n\tOnShortcutsEnabledChanged         walk.EventHandler\n\tOnStatusBarVisibleChanged         walk.EventHandler\n\tOnStatusTextChanged               walk.EventHandler\n\tOnTheaterModeChanged              walk.EventHandler\n\tOnToolBarEnabledChanged           walk.EventHandler\n\tOnToolBarVisibleChanged           walk.EventHandler\n\tOnURLChanged                      walk.EventHandler\n\tOnWindowClosing                   walk.WebViewWindowClosingEventHandler\n\tShortcutsEnabled                  Property\n\tURL                               Property\n}\n\nfunc (wv WebView) Create(builder *Builder) error {\n\tw, err := walk.NewWebView(builder.Parent())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif wv.AssignTo != nil {\n\t\t*wv.AssignTo = w\n\t}\n\n\treturn builder.InitWidget(wv, w, func() error {\n\t\tif wv.OnBrowserVisibleChanged != nil {\n\t\t\tw.BrowserVisibleChanged().Attach(wv.OnBrowserVisibleChanged)\n\t\t}\n\t\tif wv.OnCanGoBackChanged != nil {\n\t\t\tw.CanGoBackChanged().Attach(wv.OnCanGoBackChanged)\n\t\t}\n\t\tif wv.OnCanGoForwardChanged != nil {\n\t\t\tw.CanGoForwardChanged().Attach(wv.OnCanGoForwardChanged)\n\t\t}\n\t\tif wv.OnDocumentCompleted != nil {\n\t\t\tw.DocumentCompleted().Attach(wv.OnDocumentCompleted)\n\t\t}\n\t\tif wv.OnDocumentTitleChanged != nil {\n\t\t\tw.DocumentTitleChanged().Attach(wv.OnDocumentTitleChanged)\n\t\t}\n\t\tif wv.OnDownloaded != nil {\n\t\t\tw.Downloaded().Attach(wv.OnDownloaded)\n\t\t}\n\t\tif wv.OnDownloading != nil {\n\t\t\tw.Downloading().Attach(wv.OnDownloading)\n\t\t}\n\t\tif wv.OnNativeContextMenuEnabledChanged != nil {\n\t\t\tw.NativeContextMenuEnabledChanged().Attach(wv.OnNativeContextMenuEnabledChanged)\n\t\t}\n\t\tif wv.OnNavigated != nil {\n\t\t\tw.Navigated().Attach(wv.OnNavigated)\n\t\t}\n\t\tif wv.OnNavigatedError != nil {\n\t\t\tw.NavigatedError().Attach(wv.OnNavigatedError)\n\t\t}\n\t\tif wv.OnNavigating != nil {\n\t\t\tw.Navigating().Attach(wv.OnNavigating)\n\t\t}\n\t\tif wv.OnNewWindow != nil {\n\t\t\tw.NewWindow().Attach(wv.OnNewWindow)\n\t\t}\n\t\tif wv.OnProgressChanged != nil {\n\t\t\tw.ProgressChanged().Attach(wv.OnProgressChanged)\n\t\t}\n\t\tif wv.OnURLChanged != nil {\n\t\t\tw.URLChanged().Attach(wv.OnURLChanged)\n\t\t}\n\t\tif wv.OnShortcutsEnabledChanged != nil {\n\t\t\tw.ShortcutsEnabledChanged().Attach(wv.OnShortcutsEnabledChanged)\n\t\t}\n\t\tif wv.OnStatusBarVisibleChanged != nil {\n\t\t\tw.StatusBarVisibleChanged().Attach(wv.OnStatusBarVisibleChanged)\n\t\t}\n\t\tif wv.OnStatusTextChanged != nil {\n\t\t\tw.StatusTextChanged().Attach(wv.OnStatusTextChanged)\n\t\t}\n\t\tif wv.OnTheaterModeChanged != nil {\n\t\t\tw.TheaterModeChanged().Attach(wv.OnTheaterModeChanged)\n\t\t}\n\t\tif wv.OnToolBarEnabledChanged != nil {\n\t\t\tw.ToolBarEnabledChanged().Attach(wv.OnToolBarEnabledChanged)\n\t\t}\n\t\tif wv.OnToolBarVisibleChanged != nil {\n\t\t\tw.ToolBarVisibleChanged().Attach(wv.OnToolBarVisibleChanged)\n\t\t}\n\t\tif wv.OnQuitting != nil {\n\t\t\tw.Quitting().Attach(wv.OnQuitting)\n\t\t}\n\t\tif wv.OnWindowClosing != nil {\n\t\t\tw.WindowClosing().Attach(wv.OnWindowClosing)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "dialog.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst (\n\tDlgCmdNone     = 0\n\tDlgCmdOK       = win.IDOK\n\tDlgCmdCancel   = win.IDCANCEL\n\tDlgCmdAbort    = win.IDABORT\n\tDlgCmdRetry    = win.IDRETRY\n\tDlgCmdIgnore   = win.IDIGNORE\n\tDlgCmdYes      = win.IDYES\n\tDlgCmdNo       = win.IDNO\n\tDlgCmdClose    = win.IDCLOSE\n\tDlgCmdHelp     = win.IDHELP\n\tDlgCmdTryAgain = win.IDTRYAGAIN\n\tDlgCmdContinue = win.IDCONTINUE\n\tDlgCmdTimeout  = win.IDTIMEOUT\n)\n\nconst dialogWindowClass = `\\o/ Walk_Dialog_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(dialogWindowClass)\n\t})\n}\n\ntype dialogish interface {\n\tDefaultButton() *PushButton\n\tCancelButton() *PushButton\n}\n\ntype Dialog struct {\n\tFormBase\n\tresult               int\n\tdefaultButton        *PushButton\n\tcancelButton         *PushButton\n\tcenterInOwnerWhenRun bool\n}\n\nfunc NewDialog(owner Form) (*Dialog, error) {\n\treturn newDialogWithStyle(owner, win.WS_THICKFRAME)\n}\n\nfunc NewDialogWithFixedSize(owner Form) (*Dialog, error) {\n\treturn newDialogWithStyle(owner, 0)\n}\n\nfunc newDialogWithStyle(owner Form, style uint32) (*Dialog, error) {\n\tdlg := &Dialog{\n\t\tFormBase: FormBase{\n\t\t\towner: owner,\n\t\t},\n\t}\n\n\tif err := InitWindow(\n\t\tdlg,\n\t\towner,\n\t\tdialogWindowClass,\n\t\twin.WS_CAPTION|win.WS_SYSMENU|style,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tdlg.Dispose()\n\t\t}\n\t}()\n\n\tdlg.centerInOwnerWhenRun = owner != nil\n\n\tdlg.result = DlgCmdNone\n\n\tsucceeded = true\n\n\treturn dlg, nil\n}\n\nfunc (dlg *Dialog) DefaultButton() *PushButton {\n\treturn dlg.defaultButton\n}\n\nfunc (dlg *Dialog) SetDefaultButton(button *PushButton) error {\n\tif button != nil && !win.IsChild(dlg.hWnd, button.hWnd) {\n\t\treturn newError(\"not a descendant of the dialog\")\n\t}\n\n\tsucceeded := false\n\tif dlg.defaultButton != nil {\n\t\tif err := dlg.defaultButton.setAndClearStyleBits(win.BS_PUSHBUTTON, win.BS_DEFPUSHBUTTON); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer func() {\n\t\t\tif !succeeded {\n\t\t\t\tdlg.defaultButton.setAndClearStyleBits(win.BS_DEFPUSHBUTTON, win.BS_PUSHBUTTON)\n\t\t\t}\n\t\t}()\n\t}\n\n\tif button != nil {\n\t\tif err := button.setAndClearStyleBits(win.BS_DEFPUSHBUTTON, win.BS_PUSHBUTTON); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tdlg.defaultButton = button\n\n\tsucceeded = true\n\n\treturn nil\n}\n\nfunc (dlg *Dialog) CancelButton() *PushButton {\n\treturn dlg.cancelButton\n}\n\nfunc (dlg *Dialog) SetCancelButton(button *PushButton) error {\n\tif button != nil && !win.IsChild(dlg.hWnd, button.hWnd) {\n\t\treturn newError(\"not a descendant of the dialog\")\n\t}\n\n\tdlg.cancelButton = button\n\n\treturn nil\n}\n\nfunc (dlg *Dialog) Result() int {\n\treturn dlg.result\n}\n\nfunc (dlg *Dialog) Accept() {\n\tdlg.Close(DlgCmdOK)\n}\n\nfunc (dlg *Dialog) Cancel() {\n\tdlg.Close(DlgCmdCancel)\n}\n\nfunc (dlg *Dialog) Close(result int) {\n\tdlg.result = result\n\n\tdlg.FormBase.Close()\n}\n\nfunc (dlg *Dialog) Show() {\n\tvar willRestore bool\n\tif dlg.Persistent() {\n\t\tstate, _ := dlg.ReadState()\n\t\twillRestore = state != \"\"\n\t}\n\n\tif !willRestore {\n\t\tvar size Size\n\t\tif layout := dlg.Layout(); layout != nil {\n\t\t\tsize = maxSize(dlg.clientComposite.MinSizeHint(), dlg.MinSizePixels())\n\t\t} else {\n\t\t\tsize = dlg.SizePixels()\n\t\t}\n\n\t\tif dlg.owner != nil {\n\t\t\tob := dlg.owner.BoundsPixels()\n\n\t\t\tif dlg.centerInOwnerWhenRun {\n\t\t\t\tdlg.SetBoundsPixels(fitRectToScreen(dlg.hWnd, Rectangle{\n\t\t\t\t\tob.X + (ob.Width-size.Width)/2,\n\t\t\t\t\tob.Y + (ob.Height-size.Height)/2,\n\t\t\t\t\tsize.Width,\n\t\t\t\t\tsize.Height,\n\t\t\t\t}))\n\t\t\t}\n\t\t} else {\n\t\t\tb := dlg.BoundsPixels()\n\n\t\t\tdlg.SetBoundsPixels(Rectangle{b.X, b.Y, size.Width, size.Height})\n\t\t}\n\t}\n\n\tdlg.FormBase.Show()\n\n\tdlg.startLayout()\n}\n\n// fitRectToScreen fits rectangle to screen. Input and output rectangles are in native pixels.\nfunc fitRectToScreen(hWnd win.HWND, r Rectangle) Rectangle {\n\tvar mi win.MONITORINFO\n\tmi.CbSize = uint32(unsafe.Sizeof(mi))\n\n\tif !win.GetMonitorInfo(win.MonitorFromWindow(\n\t\thWnd, win.MONITOR_DEFAULTTOPRIMARY), &mi) {\n\n\t\treturn r\n\t}\n\n\tmon := rectangleFromRECT(mi.RcWork)\n\n\tdpi := win.GetDpiForWindow(hWnd)\n\tmon.Height -= int(win.GetSystemMetricsForDpi(win.SM_CYCAPTION, dpi))\n\n\tif r.Width <= mon.Width {\n\t\tswitch {\n\t\tcase r.X < mon.X:\n\t\t\tr.X = mon.X\n\t\tcase r.X+r.Width > mon.X+mon.Width:\n\t\t\tr.X = mon.X + mon.Width - r.Width\n\t\t}\n\t}\n\n\tif r.Height <= mon.Height {\n\t\tswitch {\n\t\tcase r.Y < mon.Y:\n\t\t\tr.Y = mon.Y\n\t\tcase r.Y+r.Height > mon.Y+mon.Height:\n\t\t\tr.Y = mon.Y + mon.Height - r.Height\n\t\t}\n\t}\n\n\treturn r\n}\n\nfunc (dlg *Dialog) Run() int {\n\tdlg.Show()\n\n\tdlg.FormBase.Run()\n\n\treturn dlg.result\n}\n\nfunc (dlg *Dialog) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_COMMAND:\n\t\tif win.HIWORD(uint32(wParam)) == 0 {\n\t\t\tswitch win.LOWORD(uint32(wParam)) {\n\t\t\tcase DlgCmdOK:\n\t\t\t\tif dlg.defaultButton != nil {\n\t\t\t\t\tdlg.defaultButton.raiseClicked()\n\t\t\t\t}\n\n\t\t\tcase DlgCmdCancel:\n\t\t\t\tif dlg.cancelButton != nil {\n\t\t\t\t\tdlg.cancelButton.raiseClicked()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn dlg.FormBase.WndProc(hwnd, msg, wParam, lParam)\n}\n"
  },
  {
    "path": "dropfilesevent.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype dropFilesEventHandlerInfo struct {\n\thandler DropFilesEventHandler\n\tonce    bool\n}\n\ntype DropFilesEventHandler func([]string)\n\ntype DropFilesEvent struct {\n\thWnd     win.HWND\n\thandlers []dropFilesEventHandlerInfo\n}\n\nfunc (e *DropFilesEvent) Attach(handler DropFilesEventHandler) int {\n\tif len(e.handlers) == 0 {\n\t\twin.DragAcceptFiles(e.hWnd, true)\n\t}\n\n\thandlerInfo := dropFilesEventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *DropFilesEvent) Detach(handle int) {\n\te.handlers[handle].handler = nil\n\n\tfor _, h := range e.handlers {\n\t\tif h.handler != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\twin.DragAcceptFiles(e.hWnd, false)\n}\n\nfunc (e *DropFilesEvent) Once(handler DropFilesEventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype DropFilesEventPublisher struct {\n\tevent DropFilesEvent\n}\n\nfunc (p *DropFilesEventPublisher) Event(hWnd win.HWND) *DropFilesEvent {\n\tp.event.hWnd = hWnd\n\treturn &p.event\n}\n\nfunc (p *DropFilesEventPublisher) Publish(hDrop win.HDROP) {\n\tvar files []string\n\n\tn := win.DragQueryFile(hDrop, 0xFFFFFFFF, nil, 0)\n\tfor i := 0; i < int(n); i++ {\n\t\tbufSize := uint(512)\n\t\tbuf := make([]uint16, bufSize)\n\t\tif win.DragQueryFile(hDrop, uint(i), &buf[0], bufSize) > 0 {\n\t\t\tfiles = append(files, syscall.UTF16ToString(buf))\n\t\t}\n\t}\n\twin.DragFinish(hDrop)\n\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler(files)\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "error.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"runtime/debug\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\nvar (\n\tlogErrors    bool\n\tpanicOnError bool\n)\n\ntype Error struct {\n\tinner   error\n\tmessage string\n\tstack   []byte\n}\n\nfunc (err *Error) Inner() error {\n\treturn err.inner\n}\n\nfunc (err *Error) Message() string {\n\tif err.message != \"\" {\n\t\treturn err.message\n\t}\n\n\tif err.inner != nil {\n\t\tif walkErr, ok := err.inner.(*Error); ok {\n\t\t\treturn walkErr.Message()\n\t\t} else {\n\t\t\treturn err.inner.Error()\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\nfunc (err *Error) Stack() []byte {\n\treturn err.stack\n}\n\nfunc (err *Error) Error() string {\n\treturn fmt.Sprintf(\"%s\\n\\nStack:\\n%s\", err.Message(), err.stack)\n}\n\nfunc processErrorNoPanic(err error) error {\n\tif logErrors {\n\t\tif walkErr, ok := err.(*Error); ok {\n\t\t\tlog.Print(walkErr.Error())\n\t\t} else {\n\t\t\tlog.Printf(\"%s\\n\\nStack:\\n%s\", err, debug.Stack())\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc processError(err error) error {\n\tprocessErrorNoPanic(err)\n\n\tif panicOnError {\n\t\tpanic(err)\n\t}\n\n\treturn err\n}\n\nfunc newErr(message string) error {\n\treturn &Error{message: message, stack: debug.Stack()}\n}\n\nfunc newError(message string) error {\n\treturn processError(newErr(message))\n}\n\nfunc newErrorNoPanic(message string) error {\n\treturn processErrorNoPanic(newErr(message))\n}\n\nfunc lastError(win32FuncName string) error {\n\tif errno := win.GetLastError(); errno != win.ERROR_SUCCESS {\n\t\treturn newError(fmt.Sprintf(\"%s: Error %d\", win32FuncName, errno))\n\t}\n\n\treturn newError(win32FuncName)\n}\n\nfunc errorFromHRESULT(funcName string, hr win.HRESULT) error {\n\treturn newError(fmt.Sprintf(\"%s: Error %d\", funcName, hr))\n}\n\nfunc wrapErr(err error) error {\n\tif _, ok := err.(*Error); ok {\n\t\treturn err\n\t}\n\n\treturn &Error{inner: err, stack: debug.Stack()}\n}\n\nfunc wrapErrorNoPanic(err error) error {\n\treturn processErrorNoPanic(wrapErr(err))\n}\n\nfunc wrapError(err error) error {\n\treturn processError(wrapErr(err))\n}\n\nfunc toErrorNoPanic(x interface{}) error {\n\tswitch x := x.(type) {\n\tcase *Error:\n\t\treturn x\n\n\tcase error:\n\t\treturn wrapErrorNoPanic(x)\n\n\tcase string:\n\t\treturn newErrorNoPanic(x)\n\t}\n\n\treturn newErrorNoPanic(fmt.Sprintf(\"Error: %v\", x))\n}\n\nfunc toError(x interface{}) error {\n\terr := toErrorNoPanic(x)\n\n\tif panicOnError {\n\t\tpanic(err)\n\t}\n\n\treturn err\n}\n"
  },
  {
    "path": "errorevent.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype errorEventHandlerInfo struct {\n\thandler ErrorEventHandler\n\tonce    bool\n}\n\ntype ErrorEventHandler func(err error)\n\ntype ErrorEvent struct {\n\thandlers []errorEventHandlerInfo\n}\n\nfunc (e *ErrorEvent) Attach(handler ErrorEventHandler) int {\n\thandlerInfo := errorEventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *ErrorEvent) Detach(handle int) {\n\te.handlers[handle].handler = nil\n}\n\nfunc (e *ErrorEvent) Once(handler ErrorEventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype ErrorEventPublisher struct {\n\tevent ErrorEvent\n}\n\nfunc (p *ErrorEventPublisher) Event() *ErrorEvent {\n\treturn &p.event\n}\n\nfunc (p *ErrorEventPublisher) Publish(err error) {\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler(err)\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "event.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype eventHandlerInfo struct {\n\thandler EventHandler\n\tonce    bool\n}\n\ntype EventHandler func()\n\ntype Event struct {\n\thandlers []eventHandlerInfo\n}\n\nfunc (e *Event) Attach(handler EventHandler) int {\n\thandlerInfo := eventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *Event) Detach(handle int) {\n\te.handlers[handle].handler = nil\n}\n\nfunc (e *Event) Once(handler EventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype EventPublisher struct {\n\tevent Event\n}\n\nfunc (p *EventPublisher) Event() *Event {\n\treturn &p.event\n}\n\nfunc (p *EventPublisher) Publish() {\n\t// This is a kludge to find the form that the event publisher is\n\t// affiliated with. It's only necessary because the event publisher\n\t// doesn't keep a pointer to the form on its own, and the call\n\t// to Publish isn't providing it either.\n\tif form := App().ActiveForm(); form != nil {\n\t\tfb := form.AsFormBase()\n\t\tfb.inProgressEventCount++\n\t\tdefer func() {\n\t\t\tfb.inProgressEventCount--\n\t\t\tif fb.inProgressEventCount == 0 && fb.layoutScheduled {\n\t\t\t\tfb.layoutScheduled = false\n\t\t\t\tfb.startLayout()\n\t\t\t}\n\t\t}()\n\t}\n\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler()\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "examples/actions/actions.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/actions/actions.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nvar isSpecialMode = walk.NewMutableCondition()\n\ntype MyMainWindow struct {\n\t*walk.MainWindow\n}\n\nfunc main() {\n\tMustRegisterCondition(\"isSpecialMode\", isSpecialMode)\n\n\tmw := new(MyMainWindow)\n\n\tvar openAction, showAboutBoxAction *walk.Action\n\tvar recentMenu *walk.Menu\n\tvar toggleSpecialModePB *walk.PushButton\n\n\tif err := (MainWindow{\n\t\tAssignTo: &mw.MainWindow,\n\t\tTitle:    \"Walk Actions Example\",\n\t\tMenuItems: []MenuItem{\n\t\t\tMenu{\n\t\t\t\tText: \"&File\",\n\t\t\t\tItems: []MenuItem{\n\t\t\t\t\tAction{\n\t\t\t\t\t\tAssignTo:    &openAction,\n\t\t\t\t\t\tText:        \"&Open\",\n\t\t\t\t\t\tImage:       \"../img/open.png\",\n\t\t\t\t\t\tEnabled:     Bind(\"enabledCB.Checked\"),\n\t\t\t\t\t\tVisible:     Bind(\"!openHiddenCB.Checked\"),\n\t\t\t\t\t\tShortcut:    Shortcut{walk.ModControl, walk.KeyO},\n\t\t\t\t\t\tOnTriggered: mw.openAction_Triggered,\n\t\t\t\t\t},\n\t\t\t\t\tMenu{\n\t\t\t\t\t\tAssignTo: &recentMenu,\n\t\t\t\t\t\tText:     \"Recent\",\n\t\t\t\t\t},\n\t\t\t\t\tSeparator{},\n\t\t\t\t\tAction{\n\t\t\t\t\t\tText:        \"E&xit\",\n\t\t\t\t\t\tOnTriggered: func() { mw.Close() },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tMenu{\n\t\t\t\tText: \"&View\",\n\t\t\t\tItems: []MenuItem{\n\t\t\t\t\tAction{\n\t\t\t\t\t\tText:    \"Open / Special Enabled\",\n\t\t\t\t\t\tChecked: Bind(\"enabledCB.Visible\"),\n\t\t\t\t\t},\n\t\t\t\t\tAction{\n\t\t\t\t\t\tText:    \"Open Hidden\",\n\t\t\t\t\t\tChecked: Bind(\"openHiddenCB.Visible\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tMenu{\n\t\t\t\tText: \"&Help\",\n\t\t\t\tItems: []MenuItem{\n\t\t\t\t\tAction{\n\t\t\t\t\t\tAssignTo:    &showAboutBoxAction,\n\t\t\t\t\t\tText:        \"About\",\n\t\t\t\t\t\tOnTriggered: mw.showAboutBoxAction_Triggered,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tToolBar: ToolBar{\n\t\t\tButtonStyle: ToolBarButtonImageBeforeText,\n\t\t\tItems: []MenuItem{\n\t\t\t\tActionRef{&openAction},\n\t\t\t\tMenu{\n\t\t\t\t\tText:  \"New A\",\n\t\t\t\t\tImage: \"../img/document-new.png\",\n\t\t\t\t\tItems: []MenuItem{\n\t\t\t\t\t\tAction{\n\t\t\t\t\t\t\tText:        \"A\",\n\t\t\t\t\t\t\tOnTriggered: mw.newAction_Triggered,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAction{\n\t\t\t\t\t\t\tText:        \"B\",\n\t\t\t\t\t\t\tOnTriggered: mw.newAction_Triggered,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAction{\n\t\t\t\t\t\t\tText:        \"C\",\n\t\t\t\t\t\t\tOnTriggered: mw.newAction_Triggered,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tOnTriggered: mw.newAction_Triggered,\n\t\t\t\t},\n\t\t\t\tSeparator{},\n\t\t\t\tMenu{\n\t\t\t\t\tText:  \"View\",\n\t\t\t\t\tImage: \"../img/document-properties.png\",\n\t\t\t\t\tItems: []MenuItem{\n\t\t\t\t\t\tAction{\n\t\t\t\t\t\t\tText:        \"X\",\n\t\t\t\t\t\t\tOnTriggered: mw.changeViewAction_Triggered,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAction{\n\t\t\t\t\t\t\tText:        \"Y\",\n\t\t\t\t\t\t\tOnTriggered: mw.changeViewAction_Triggered,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAction{\n\t\t\t\t\t\t\tText:        \"Z\",\n\t\t\t\t\t\t\tOnTriggered: mw.changeViewAction_Triggered,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSeparator{},\n\t\t\t\tAction{\n\t\t\t\t\tText:        \"Special\",\n\t\t\t\t\tImage:       \"../img/system-shutdown.png\",\n\t\t\t\t\tEnabled:     Bind(\"isSpecialMode && enabledCB.Checked\"),\n\t\t\t\t\tOnTriggered: mw.specialAction_Triggered,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tContextMenuItems: []MenuItem{\n\t\t\tActionRef{&showAboutBoxAction},\n\t\t},\n\t\tMinSize: Size{300, 200},\n\t\tLayout:  VBox{},\n\t\tChildren: []Widget{\n\t\t\tCheckBox{\n\t\t\t\tName:    \"enabledCB\",\n\t\t\t\tText:    \"Open / Special Enabled\",\n\t\t\t\tChecked: true,\n\t\t\t\tAccessibility: Accessibility{\n\t\t\t\t\tHelp: \"Enables Open and Special\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tCheckBox{\n\t\t\t\tName:    \"openHiddenCB\",\n\t\t\t\tText:    \"Open Hidden\",\n\t\t\t\tChecked: true,\n\t\t\t},\n\t\t\tPushButton{\n\t\t\t\tAssignTo: &toggleSpecialModePB,\n\t\t\t\tText:     \"Enable Special Mode\",\n\t\t\t\tOnClicked: func() {\n\t\t\t\t\tisSpecialMode.SetSatisfied(!isSpecialMode.Satisfied())\n\n\t\t\t\t\tif isSpecialMode.Satisfied() {\n\t\t\t\t\t\ttoggleSpecialModePB.SetText(\"Disable Special Mode\")\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttoggleSpecialModePB.SetText(\"Enable Special Mode\")\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tAccessibility: Accessibility{\n\t\t\t\t\tHelp: \"Toggles special mode\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}.Create()); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\taddRecentFileActions := func(texts ...string) {\n\t\tfor _, text := range texts {\n\t\t\ta := walk.NewAction()\n\t\t\ta.SetText(text)\n\t\t\ta.Triggered().Attach(mw.openAction_Triggered)\n\t\t\trecentMenu.Actions().Add(a)\n\t\t}\n\t}\n\n\taddRecentFileActions(\"Foo\", \"Bar\", \"Baz\")\n\n\tmw.Run()\n}\n\nfunc (mw *MyMainWindow) openAction_Triggered() {\n\twalk.MsgBox(mw, \"Open\", \"Pretend to open a file...\", walk.MsgBoxIconInformation)\n}\n\nfunc (mw *MyMainWindow) newAction_Triggered() {\n\twalk.MsgBox(mw, \"New\", \"Newing something up... or not.\", walk.MsgBoxIconInformation)\n}\n\nfunc (mw *MyMainWindow) changeViewAction_Triggered() {\n\twalk.MsgBox(mw, \"Change View\", \"By now you may have guessed it. Nothing changed.\", walk.MsgBoxIconInformation)\n}\n\nfunc (mw *MyMainWindow) showAboutBoxAction_Triggered() {\n\twalk.MsgBox(mw, \"About\", \"Walk Actions Example\", walk.MsgBoxIconInformation)\n}\n\nfunc (mw *MyMainWindow) specialAction_Triggered() {\n\twalk.MsgBox(mw, \"Special\", \"Nothing to see here.\", walk.MsgBoxIconInformation)\n}\n"
  },
  {
    "path": "examples/clipboard/clipboard.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/clipboard/clipboard.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tvar te *walk.TextEdit\n\n\tif _, err := (MainWindow{\n\t\tTitle:   \"Walk Clipboard Example\",\n\t\tMinSize: Size{300, 200},\n\t\tLayout:  VBox{},\n\t\tChildren: []Widget{\n\t\t\tPushButton{\n\t\t\t\tText: \"Copy\",\n\t\t\t\tOnClicked: func() {\n\t\t\t\t\tif err := walk.Clipboard().SetText(te.Text()); err != nil {\n\t\t\t\t\t\tlog.Print(\"Copy: \", err)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\tPushButton{\n\t\t\t\tText: \"Paste\",\n\t\t\t\tOnClicked: func() {\n\t\t\t\t\tif text, err := walk.Clipboard().Text(); err != nil {\n\t\t\t\t\t\tlog.Print(\"Paste: \", err)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tte.SetText(text)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\tTextEdit{\n\t\t\t\tAssignTo: &te,\n\t\t\t},\n\t\t},\n\t}).Run(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "examples/databinding/databinding.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/databinding/databinding.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/lxn/walk\"\n\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\twalk.AppendToWalkInit(func() {\n\t\twalk.FocusEffect, _ = walk.NewBorderGlowEffect(walk.RGB(0, 63, 255))\n\t\twalk.InteractionEffect, _ = walk.NewDropShadowEffect(walk.RGB(63, 63, 63))\n\t\twalk.ValidationErrorEffect, _ = walk.NewBorderGlowEffect(walk.RGB(255, 0, 0))\n\t})\n\n\tvar mw *walk.MainWindow\n\tvar outTE *walk.TextEdit\n\n\tanimal := new(Animal)\n\n\tif _, err := (MainWindow{\n\t\tAssignTo: &mw,\n\t\tTitle:    \"Walk Data Binding Example\",\n\t\tMinSize:  Size{300, 200},\n\t\tLayout:   VBox{},\n\t\tChildren: []Widget{\n\t\t\tPushButton{\n\t\t\t\tText: \"Edit Animal\",\n\t\t\t\tOnClicked: func() {\n\t\t\t\t\tif cmd, err := RunAnimalDialog(mw, animal); err != nil {\n\t\t\t\t\t\tlog.Print(err)\n\t\t\t\t\t} else if cmd == walk.DlgCmdOK {\n\t\t\t\t\t\toutTE.SetText(fmt.Sprintf(\"%+v\", animal))\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\tLabel{\n\t\t\t\tText: \"animal:\",\n\t\t\t},\n\t\t\tTextEdit{\n\t\t\t\tAssignTo: &outTE,\n\t\t\t\tReadOnly: true,\n\t\t\t\tText:     fmt.Sprintf(\"%+v\", animal),\n\t\t\t},\n\t\t},\n\t}.Run()); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\ntype Animal struct {\n\tName          string\n\tArrivalDate   time.Time\n\tSpeciesId     int\n\tSpeed         int\n\tSex           Sex\n\tWeight        float64\n\tPreferredFood string\n\tDomesticated  bool\n\tRemarks       string\n\tPatience      time.Duration\n}\n\nfunc (a *Animal) PatienceField() *DurationField {\n\treturn &DurationField{&a.Patience}\n}\n\ntype Species struct {\n\tId   int\n\tName string\n}\n\nfunc KnownSpecies() []*Species {\n\treturn []*Species{\n\t\t{1, \"Dog\"},\n\t\t{2, \"Cat\"},\n\t\t{3, \"Bird\"},\n\t\t{4, \"Fish\"},\n\t\t{5, \"Elephant\"},\n\t}\n}\n\ntype DurationField struct {\n\tp *time.Duration\n}\n\nfunc (*DurationField) CanSet() bool       { return true }\nfunc (f *DurationField) Get() interface{} { return f.p.String() }\nfunc (f *DurationField) Set(v interface{}) error {\n\tx, err := time.ParseDuration(v.(string))\n\tif err == nil {\n\t\t*f.p = x\n\t}\n\treturn err\n}\nfunc (f *DurationField) Zero() interface{} { return \"\" }\n\ntype Sex byte\n\nconst (\n\tSexMale Sex = 1 + iota\n\tSexFemale\n\tSexHermaphrodite\n)\n\nfunc RunAnimalDialog(owner walk.Form, animal *Animal) (int, error) {\n\tvar dlg *walk.Dialog\n\tvar db *walk.DataBinder\n\tvar acceptPB, cancelPB *walk.PushButton\n\n\treturn Dialog{\n\t\tAssignTo:      &dlg,\n\t\tTitle:         Bind(\"'Animal Details' + (animal.Name == '' ? '' : ' - ' + animal.Name)\"),\n\t\tDefaultButton: &acceptPB,\n\t\tCancelButton:  &cancelPB,\n\t\tDataBinder: DataBinder{\n\t\t\tAssignTo:       &db,\n\t\t\tName:           \"animal\",\n\t\t\tDataSource:     animal,\n\t\t\tErrorPresenter: ToolTipErrorPresenter{},\n\t\t},\n\t\tMinSize: Size{300, 300},\n\t\tLayout:  VBox{},\n\t\tChildren: []Widget{\n\t\t\tComposite{\n\t\t\t\tLayout: Grid{Columns: 2},\n\t\t\t\tChildren: []Widget{\n\t\t\t\t\tLabel{\n\t\t\t\t\t\tText: \"Name:\",\n\t\t\t\t\t},\n\t\t\t\t\tLineEdit{\n\t\t\t\t\t\tText: Bind(\"Name\"),\n\t\t\t\t\t},\n\n\t\t\t\t\tLabel{\n\t\t\t\t\t\tText: \"Arrival Date:\",\n\t\t\t\t\t},\n\t\t\t\t\tDateEdit{\n\t\t\t\t\t\tDate: Bind(\"ArrivalDate\"),\n\t\t\t\t\t},\n\n\t\t\t\t\tLabel{\n\t\t\t\t\t\tText: \"Species:\",\n\t\t\t\t\t},\n\t\t\t\t\tComboBox{\n\t\t\t\t\t\tValue:         Bind(\"SpeciesId\", SelRequired{}),\n\t\t\t\t\t\tBindingMember: \"Id\",\n\t\t\t\t\t\tDisplayMember: \"Name\",\n\t\t\t\t\t\tModel:         KnownSpecies(),\n\t\t\t\t\t},\n\n\t\t\t\t\tLabel{\n\t\t\t\t\t\tText: \"Speed:\",\n\t\t\t\t\t},\n\t\t\t\t\tSlider{\n\t\t\t\t\t\tValue: Bind(\"Speed\"),\n\t\t\t\t\t},\n\n\t\t\t\t\tRadioButtonGroupBox{\n\t\t\t\t\t\tColumnSpan: 2,\n\t\t\t\t\t\tTitle:      \"Sex\",\n\t\t\t\t\t\tLayout:     HBox{},\n\t\t\t\t\t\tDataMember: \"Sex\",\n\t\t\t\t\t\tButtons: []RadioButton{\n\t\t\t\t\t\t\t{Text: \"Male\", Value: SexMale},\n\t\t\t\t\t\t\t{Text: \"Female\", Value: SexFemale},\n\t\t\t\t\t\t\t{Text: \"Hermaphrodite\", Value: SexHermaphrodite},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\n\t\t\t\t\tLabel{\n\t\t\t\t\t\tText: \"Weight:\",\n\t\t\t\t\t},\n\t\t\t\t\tNumberEdit{\n\t\t\t\t\t\tValue:    Bind(\"Weight\", Range{0.01, 9999.99}),\n\t\t\t\t\t\tSuffix:   \" kg\",\n\t\t\t\t\t\tDecimals: 2,\n\t\t\t\t\t},\n\n\t\t\t\t\tLabel{\n\t\t\t\t\t\tText: \"Preferred Food:\",\n\t\t\t\t\t},\n\t\t\t\t\tComboBox{\n\t\t\t\t\t\tEditable: true,\n\t\t\t\t\t\tValue:    Bind(\"PreferredFood\"),\n\t\t\t\t\t\tModel:    []string{\"Fruit\", \"Grass\", \"Fish\", \"Meat\"},\n\t\t\t\t\t},\n\n\t\t\t\t\tLabel{\n\t\t\t\t\t\tText: \"Domesticated:\",\n\t\t\t\t\t},\n\t\t\t\t\tCheckBox{\n\t\t\t\t\t\tChecked: Bind(\"Domesticated\"),\n\t\t\t\t\t},\n\n\t\t\t\t\tVSpacer{\n\t\t\t\t\t\tColumnSpan: 2,\n\t\t\t\t\t\tSize:       8,\n\t\t\t\t\t},\n\n\t\t\t\t\tLabel{\n\t\t\t\t\t\tColumnSpan: 2,\n\t\t\t\t\t\tText:       \"Remarks:\",\n\t\t\t\t\t},\n\t\t\t\t\tTextEdit{\n\t\t\t\t\t\tColumnSpan: 2,\n\t\t\t\t\t\tMinSize:    Size{100, 50},\n\t\t\t\t\t\tText:       Bind(\"Remarks\"),\n\t\t\t\t\t},\n\n\t\t\t\t\tLabel{\n\t\t\t\t\t\tColumnSpan: 2,\n\t\t\t\t\t\tText:       \"Patience:\",\n\t\t\t\t\t},\n\t\t\t\t\tLineEdit{\n\t\t\t\t\t\tColumnSpan: 2,\n\t\t\t\t\t\tText:       Bind(\"PatienceField\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tComposite{\n\t\t\t\tLayout: HBox{},\n\t\t\t\tChildren: []Widget{\n\t\t\t\t\tHSpacer{},\n\t\t\t\t\tPushButton{\n\t\t\t\t\t\tAssignTo: &acceptPB,\n\t\t\t\t\t\tText:     \"OK\",\n\t\t\t\t\t\tOnClicked: func() {\n\t\t\t\t\t\t\tif err := db.Submit(); err != nil {\n\t\t\t\t\t\t\t\tlog.Print(err)\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tdlg.Accept()\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tPushButton{\n\t\t\t\t\t\tAssignTo:  &cancelPB,\n\t\t\t\t\t\tText:      \"Cancel\",\n\t\t\t\t\t\tOnClicked: func() { dlg.Cancel() },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}.Run(owner)\n}\n"
  },
  {
    "path": "examples/drawing/drawing.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/drawing/drawing.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n\t\"math\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tmw := new(MyMainWindow)\n\n\tif _, err := (MainWindow{\n\t\tAssignTo: &mw.MainWindow,\n\t\tTitle:    \"Walk Drawing Example\",\n\t\tMinSize:  Size{320, 240},\n\t\tSize:     Size{800, 600},\n\t\tLayout:   VBox{MarginsZero: true},\n\t\tChildren: []Widget{\n\t\t\tCustomWidget{\n\t\t\t\tAssignTo:            &mw.paintWidget,\n\t\t\t\tClearsBackground:    true,\n\t\t\t\tInvalidatesOnResize: true,\n\t\t\t\tPaint:               mw.drawStuff,\n\t\t\t},\n\t\t},\n\t}).Run(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\ntype MyMainWindow struct {\n\t*walk.MainWindow\n\tpaintWidget *walk.CustomWidget\n}\n\nfunc (mw *MyMainWindow) drawStuff(canvas *walk.Canvas, updateBounds walk.Rectangle) error {\n\tbmp, err := createBitmap()\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer bmp.Dispose()\n\n\tbounds := mw.paintWidget.ClientBounds()\n\n\trectPen, err := walk.NewCosmeticPen(walk.PenSolid, walk.RGB(255, 0, 0))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rectPen.Dispose()\n\n\tif err := canvas.DrawRectangle(rectPen, bounds); err != nil {\n\t\treturn err\n\t}\n\n\tellipseBrush, err := walk.NewHatchBrush(walk.RGB(0, 255, 0), walk.HatchCross)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer ellipseBrush.Dispose()\n\n\tif err := canvas.FillEllipse(ellipseBrush, bounds); err != nil {\n\t\treturn err\n\t}\n\n\tlinesBrush, err := walk.NewSolidColorBrush(walk.RGB(0, 0, 255))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer linesBrush.Dispose()\n\n\tlinesPen, err := walk.NewGeometricPen(walk.PenDash, 8, linesBrush)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer linesPen.Dispose()\n\n\tif err := canvas.DrawLine(linesPen, walk.Point{bounds.X, bounds.Y}, walk.Point{bounds.Width, bounds.Height}); err != nil {\n\t\treturn err\n\t}\n\tif err := canvas.DrawLine(linesPen, walk.Point{bounds.X, bounds.Height}, walk.Point{bounds.Width, bounds.Y}); err != nil {\n\t\treturn err\n\t}\n\n\tpoints := make([]walk.Point, 10)\n\tdx := bounds.Width / (len(points) - 1)\n\tfor i := range points {\n\t\tpoints[i].X = i * dx\n\t\tpoints[i].Y = int(float64(bounds.Height) / math.Pow(float64(bounds.Width/2), 2) * math.Pow(float64(i*dx-bounds.Width/2), 2))\n\t}\n\tif err := canvas.DrawPolyline(linesPen, points); err != nil {\n\t\treturn err\n\t}\n\n\tbmpSize := bmp.Size()\n\tif err := canvas.DrawImage(bmp, walk.Point{(bounds.Width - bmpSize.Width) / 2, (bounds.Height - bmpSize.Height) / 2}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc createBitmap() (*walk.Bitmap, error) {\n\tbounds := walk.Rectangle{Width: 200, Height: 200}\n\n\tbmp, err := walk.NewBitmap(bounds.Size())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tbmp.Dispose()\n\t\t}\n\t}()\n\n\tcanvas, err := walk.NewCanvasFromImage(bmp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer canvas.Dispose()\n\n\tbrushBmp, err := walk.NewBitmapFromFile(\"../img/plus.png\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer brushBmp.Dispose()\n\n\tbrush, err := walk.NewBitmapBrush(brushBmp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer brush.Dispose()\n\n\tif err := canvas.FillRectangle(brush, bounds); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfont, err := walk.NewFont(\"Times New Roman\", 40, walk.FontBold|walk.FontItalic)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer font.Dispose()\n\n\tif err := canvas.DrawText(\"Walk Drawing Example\", font, walk.RGB(0, 0, 0), bounds, walk.TextWordbreak); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded = true\n\n\treturn bmp, nil\n}\n"
  },
  {
    "path": "examples/dropfiles/dropfiles.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/dropfiles/dropfiles.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"strings\"\n\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tvar textEdit *walk.TextEdit\n\tMainWindow{\n\t\tTitle:   \"Walk DropFiles Example\",\n\t\tMinSize: Size{320, 240},\n\t\tLayout:  VBox{},\n\t\tOnDropFiles: func(files []string) {\n\t\t\ttextEdit.SetText(strings.Join(files, \"\\r\\n\"))\n\t\t},\n\t\tChildren: []Widget{\n\t\t\tTextEdit{\n\t\t\t\tAssignTo: &textEdit,\n\t\t\t\tReadOnly: true,\n\t\t\t\tText:     \"Drop files here, from windows explorer...\",\n\t\t\t},\n\t\t},\n\t}.Run()\n}\n"
  },
  {
    "path": "examples/externalwidgets/externalwidgets.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/externalwidgets/externalwidgets.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n\n\t\"github.com/lxn/walk\"\n\n\t. \"github.com/lxn/walk/declarative\"\n\t\"github.com/lxn/win\"\n)\n\nconst myWidgetWindowClass = \"MyWidget Class\"\n\nfunc init() {\n\twalk.AppendToWalkInit(func() {\n\t\twalk.MustRegisterWindowClass(myWidgetWindowClass)\n\t})\n}\n\nfunc main() {\n\tvar mw *walk.MainWindow\n\n\tif err := (MainWindow{\n\t\tAssignTo: &mw,\n\t\tTitle:    \"Walk External Widgets Example\",\n\t\tSize:     Size{400, 300},\n\t\tLayout:   HBox{},\n\t}).Create(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tfor _, name := range []string{\"a\", \"b\", \"c\"} {\n\t\tif w, err := NewMyWidget(mw); err != nil {\n\t\t\tlog.Fatal(err)\n\t\t} else {\n\t\t\tw.SetName(name)\n\t\t}\n\t}\n\n\tmpb, err := NewMyPushButton(mw)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tmpb.SetText(\"MyPushButton\")\n\n\tmw.Run()\n}\n\ntype MyWidget struct {\n\twalk.WidgetBase\n}\n\nfunc NewMyWidget(parent walk.Container) (*MyWidget, error) {\n\tw := new(MyWidget)\n\n\tif err := walk.InitWidget(\n\t\tw,\n\t\tparent,\n\t\tmyWidgetWindowClass,\n\t\twin.WS_VISIBLE,\n\t\t0); err != nil {\n\n\t\treturn nil, err\n\t}\n\n\tbg, err := walk.NewSolidColorBrush(walk.RGB(0, 255, 0))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tw.SetBackground(bg)\n\n\treturn w, nil\n}\n\nfunc (*MyWidget) CreateLayoutItem(ctx *walk.LayoutContext) walk.LayoutItem {\n\treturn &myWidgetLayoutItem{idealSize: walk.SizeFrom96DPI(walk.Size{50, 50}, ctx.DPI())}\n}\n\ntype myWidgetLayoutItem struct {\n\twalk.LayoutItemBase\n\tidealSize walk.Size // in native pixels\n}\n\nfunc (li *myWidgetLayoutItem) LayoutFlags() walk.LayoutFlags {\n\treturn 0\n}\n\nfunc (li *myWidgetLayoutItem) IdealSize() walk.Size {\n\treturn li.idealSize\n}\n\nfunc (w *MyWidget) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_LBUTTONDOWN:\n\t\tlog.Printf(\"%s: WM_LBUTTONDOWN\", w.Name())\n\t}\n\n\treturn w.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\ntype MyPushButton struct {\n\t*walk.PushButton\n}\n\nfunc NewMyPushButton(parent walk.Container) (*MyPushButton, error) {\n\tpb, err := walk.NewPushButton(parent)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmpb := &MyPushButton{pb}\n\n\tif err := walk.InitWrapperWindow(mpb); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn mpb, nil\n}\n\nfunc (mpb *MyPushButton) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_LBUTTONDOWN:\n\t\tlog.Printf(\"%s: WM_LBUTTONDOWN\", mpb.Text())\n\t}\n\n\treturn mpb.PushButton.WndProc(hwnd, msg, wParam, lParam)\n}\n"
  },
  {
    "path": "examples/filebrowser/filebrowser.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/filebrowser/filebrowser.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\ntype Directory struct {\n\tname     string\n\tparent   *Directory\n\tchildren []*Directory\n}\n\nfunc NewDirectory(name string, parent *Directory) *Directory {\n\treturn &Directory{name: name, parent: parent}\n}\n\nvar _ walk.TreeItem = new(Directory)\n\nfunc (d *Directory) Text() string {\n\treturn d.name\n}\n\nfunc (d *Directory) Parent() walk.TreeItem {\n\tif d.parent == nil {\n\t\t// We can't simply return d.parent in this case, because the interface\n\t\t// value then would not be nil.\n\t\treturn nil\n\t}\n\n\treturn d.parent\n}\n\nfunc (d *Directory) ChildCount() int {\n\tif d.children == nil {\n\t\t// It seems this is the first time our child count is checked, so we\n\t\t// use the opportunity to populate our direct children.\n\t\tif err := d.ResetChildren(); err != nil {\n\t\t\tlog.Print(err)\n\t\t}\n\t}\n\n\treturn len(d.children)\n}\n\nfunc (d *Directory) ChildAt(index int) walk.TreeItem {\n\treturn d.children[index]\n}\n\nfunc (d *Directory) Image() interface{} {\n\treturn d.Path()\n}\n\nfunc (d *Directory) ResetChildren() error {\n\td.children = nil\n\n\tdirPath := d.Path()\n\n\tif err := filepath.Walk(d.Path(), func(path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\tif info == nil {\n\t\t\t\treturn filepath.SkipDir\n\t\t\t}\n\t\t}\n\n\t\tname := info.Name()\n\n\t\tif !info.IsDir() || path == dirPath || shouldExclude(name) {\n\t\t\treturn nil\n\t\t}\n\n\t\td.children = append(d.children, NewDirectory(name, d))\n\n\t\treturn filepath.SkipDir\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (d *Directory) Path() string {\n\telems := []string{d.name}\n\n\tdir, _ := d.Parent().(*Directory)\n\n\tfor dir != nil {\n\t\telems = append([]string{dir.name}, elems...)\n\t\tdir, _ = dir.Parent().(*Directory)\n\t}\n\n\treturn filepath.Join(elems...)\n}\n\ntype DirectoryTreeModel struct {\n\twalk.TreeModelBase\n\troots []*Directory\n}\n\nvar _ walk.TreeModel = new(DirectoryTreeModel)\n\nfunc NewDirectoryTreeModel() (*DirectoryTreeModel, error) {\n\tmodel := new(DirectoryTreeModel)\n\n\tdrives, err := walk.DriveNames()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, drive := range drives {\n\t\tswitch drive {\n\t\tcase \"A:\\\\\", \"B:\\\\\":\n\t\t\tcontinue\n\t\t}\n\n\t\tmodel.roots = append(model.roots, NewDirectory(drive, nil))\n\t}\n\n\treturn model, nil\n}\n\nfunc (*DirectoryTreeModel) LazyPopulation() bool {\n\t// We don't want to eagerly populate our tree view with the whole file system.\n\treturn true\n}\n\nfunc (m *DirectoryTreeModel) RootCount() int {\n\treturn len(m.roots)\n}\n\nfunc (m *DirectoryTreeModel) RootAt(index int) walk.TreeItem {\n\treturn m.roots[index]\n}\n\ntype FileInfo struct {\n\tName     string\n\tSize     int64\n\tModified time.Time\n}\n\ntype FileInfoModel struct {\n\twalk.SortedReflectTableModelBase\n\tdirPath string\n\titems   []*FileInfo\n}\n\nvar _ walk.ReflectTableModel = new(FileInfoModel)\n\nfunc NewFileInfoModel() *FileInfoModel {\n\treturn new(FileInfoModel)\n}\n\nfunc (m *FileInfoModel) Items() interface{} {\n\treturn m.items\n}\n\nfunc (m *FileInfoModel) SetDirPath(dirPath string) error {\n\tm.dirPath = dirPath\n\tm.items = nil\n\n\tif err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\tif info == nil {\n\t\t\t\treturn filepath.SkipDir\n\t\t\t}\n\t\t}\n\n\t\tname := info.Name()\n\n\t\tif path == dirPath || shouldExclude(name) {\n\t\t\treturn nil\n\t\t}\n\n\t\titem := &FileInfo{\n\t\t\tName:     name,\n\t\t\tSize:     info.Size(),\n\t\t\tModified: info.ModTime(),\n\t\t}\n\n\t\tm.items = append(m.items, item)\n\n\t\tif info.IsDir() {\n\t\t\treturn filepath.SkipDir\n\t\t}\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tm.PublishRowsReset()\n\n\treturn nil\n}\n\nfunc (m *FileInfoModel) Image(row int) interface{} {\n\treturn filepath.Join(m.dirPath, m.items[row].Name)\n}\n\nfunc shouldExclude(name string) bool {\n\tswitch name {\n\tcase \"System Volume Information\", \"pagefile.sys\", \"swapfile.sys\":\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc main() {\n\tvar mainWindow *walk.MainWindow\n\tvar splitter *walk.Splitter\n\tvar treeView *walk.TreeView\n\tvar tableView *walk.TableView\n\tvar webView *walk.WebView\n\n\ttreeModel, err := NewDirectoryTreeModel()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\ttableModel := NewFileInfoModel()\n\n\tif err := (MainWindow{\n\t\tAssignTo: &mainWindow,\n\t\tTitle:    \"Walk File Browser Example\",\n\t\tMinSize:  Size{600, 400},\n\t\tSize:     Size{1024, 640},\n\t\tLayout:   HBox{MarginsZero: true},\n\t\tChildren: []Widget{\n\t\t\tHSplitter{\n\t\t\t\tAssignTo: &splitter,\n\t\t\t\tChildren: []Widget{\n\t\t\t\t\tTreeView{\n\t\t\t\t\t\tAssignTo: &treeView,\n\t\t\t\t\t\tModel:    treeModel,\n\t\t\t\t\t\tOnCurrentItemChanged: func() {\n\t\t\t\t\t\t\tdir := treeView.CurrentItem().(*Directory)\n\t\t\t\t\t\t\tif err := tableModel.SetDirPath(dir.Path()); err != nil {\n\t\t\t\t\t\t\t\twalk.MsgBox(\n\t\t\t\t\t\t\t\t\tmainWindow,\n\t\t\t\t\t\t\t\t\t\"Error\",\n\t\t\t\t\t\t\t\t\terr.Error(),\n\t\t\t\t\t\t\t\t\twalk.MsgBoxOK|walk.MsgBoxIconError)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tTableView{\n\t\t\t\t\t\tAssignTo:      &tableView,\n\t\t\t\t\t\tStretchFactor: 2,\n\t\t\t\t\t\tColumns: []TableViewColumn{\n\t\t\t\t\t\t\tTableViewColumn{\n\t\t\t\t\t\t\t\tDataMember: \"Name\",\n\t\t\t\t\t\t\t\tWidth:      192,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tTableViewColumn{\n\t\t\t\t\t\t\t\tDataMember: \"Size\",\n\t\t\t\t\t\t\t\tFormat:     \"%d\",\n\t\t\t\t\t\t\t\tAlignment:  AlignFar,\n\t\t\t\t\t\t\t\tWidth:      64,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tTableViewColumn{\n\t\t\t\t\t\t\t\tDataMember: \"Modified\",\n\t\t\t\t\t\t\t\tFormat:     \"2006-01-02 15:04:05\",\n\t\t\t\t\t\t\t\tWidth:      120,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tModel: tableModel,\n\t\t\t\t\t\tOnCurrentIndexChanged: func() {\n\t\t\t\t\t\t\tvar url string\n\t\t\t\t\t\t\tif index := tableView.CurrentIndex(); index > -1 {\n\t\t\t\t\t\t\t\tname := tableModel.items[index].Name\n\t\t\t\t\t\t\t\tdir := treeView.CurrentItem().(*Directory)\n\t\t\t\t\t\t\t\turl = filepath.Join(dir.Path(), name)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\twebView.SetURL(url)\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tWebView{\n\t\t\t\t\t\tAssignTo:      &webView,\n\t\t\t\t\t\tStretchFactor: 2,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}.Create()); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tsplitter.SetFixed(treeView, true)\n\tsplitter.SetFixed(tableView, true)\n\n\tmainWindow.Run()\n}\n"
  },
  {
    "path": "examples/gradientcomposite/gradientcomposite.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/gradientcomposite/gradientcomposite.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tMainWindow{\n\t\tTitle:   \"Walk GradientComposite Example\",\n\t\tMinSize: Size{400, 0},\n\t\tBackground: GradientBrush{\n\t\t\tVertexes: []walk.GradientVertex{\n\t\t\t\t{X: 0, Y: 0, Color: walk.RGB(255, 255, 127)},\n\t\t\t\t{X: 1, Y: 0, Color: walk.RGB(127, 191, 255)},\n\t\t\t\t{X: 0.5, Y: 0.5, Color: walk.RGB(255, 255, 255)},\n\t\t\t\t{X: 1, Y: 1, Color: walk.RGB(127, 255, 127)},\n\t\t\t\t{X: 0, Y: 1, Color: walk.RGB(255, 127, 127)},\n\t\t\t},\n\t\t\tTriangles: []walk.GradientTriangle{\n\t\t\t\t{0, 1, 2},\n\t\t\t\t{1, 3, 2},\n\t\t\t\t{3, 4, 2},\n\t\t\t\t{4, 0, 2},\n\t\t\t},\n\t\t},\n\t\tLayout: HBox{Margins: Margins{100, 100, 100, 100}},\n\t\tChildren: []Widget{\n\t\t\tGradientComposite{\n\t\t\t\tBorder:   true,\n\t\t\t\tVertical: Bind(\"verticalCB.Checked\"),\n\t\t\t\tColor1:   Bind(\"rgb(c1RedSld.Value, c1GreenSld.Value, c1BlueSld.Value)\"),\n\t\t\t\tColor2:   Bind(\"rgb(c2RedSld.Value, c2GreenSld.Value, c2BlueSld.Value)\"),\n\t\t\t\tLayout:   HBox{},\n\t\t\t\tChildren: []Widget{\n\t\t\t\t\tGroupBox{\n\t\t\t\t\t\tTitle:  \"Gradient Parameters\",\n\t\t\t\t\t\tLayout: VBox{},\n\t\t\t\t\t\tChildren: []Widget{\n\t\t\t\t\t\t\tCheckBox{Name: \"verticalCB\", Text: \"Vertical\", Checked: true},\n\t\t\t\t\t\t\tGroupBox{\n\t\t\t\t\t\t\t\tTitle:  \"Color1\",\n\t\t\t\t\t\t\t\tLayout: Grid{Columns: 2},\n\t\t\t\t\t\t\t\tChildren: []Widget{\n\t\t\t\t\t\t\t\t\tLabel{Text: \"Red:\"},\n\t\t\t\t\t\t\t\t\tSlider{Name: \"c1RedSld\", Tracking: true, MaxValue: 255, Value: 95},\n\t\t\t\t\t\t\t\t\tLabel{Text: \"Green:\"},\n\t\t\t\t\t\t\t\t\tSlider{Name: \"c1GreenSld\", Tracking: true, MaxValue: 255, Value: 191},\n\t\t\t\t\t\t\t\t\tLabel{Text: \"Blue:\"},\n\t\t\t\t\t\t\t\t\tSlider{Name: \"c1BlueSld\", Tracking: true, MaxValue: 255, Value: 255},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tGroupBox{\n\t\t\t\t\t\t\t\tTitle:  \"Color2\",\n\t\t\t\t\t\t\t\tLayout: Grid{Columns: 2},\n\t\t\t\t\t\t\t\tChildren: []Widget{\n\t\t\t\t\t\t\t\t\tLabel{Text: \"Red:\"},\n\t\t\t\t\t\t\t\t\tSlider{Name: \"c2RedSld\", Tracking: true, MaxValue: 255, Value: 239},\n\t\t\t\t\t\t\t\t\tLabel{Text: \"Green:\"},\n\t\t\t\t\t\t\t\t\tSlider{Name: \"c2GreenSld\", Tracking: true, MaxValue: 255, Value: 63},\n\t\t\t\t\t\t\t\t\tLabel{Text: \"Blue:\"},\n\t\t\t\t\t\t\t\t\tSlider{Name: \"c2BlueSld\", Tracking: true, MaxValue: 255, Value: 0},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tFunctions: map[string]func(args ...interface{}) (interface{}, error){\n\t\t\t\"rgb\": func(args ...interface{}) (interface{}, error) {\n\t\t\t\treturn walk.RGB(byte(args[0].(float64)), byte(args[1].(float64)), byte(args[2].(float64))), nil\n\t\t\t},\n\t\t},\n\t}.Run()\n}\n"
  },
  {
    "path": "examples/imageicon/imageicon.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/imageicon/main.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"image\"\n\t\"image/color\"\n\t\"image/draw\"\n\t\"log\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tvar mw *walk.MainWindow\n\tvar windowIcon *walk.Icon\n\tcounter := 0\n\n\tif _, err := (MainWindow{\n\t\tAssignTo: &mw,\n\t\tTitle:    \"Walk Image Icon Example\",\n\t\tLayout:   HBox{},\n\t\tChildren: []Widget{\n\t\t\tHSpacer{},\n\t\t\tPushButton{\n\t\t\t\tText: \"Push me\",\n\t\t\t\tOnClicked: func() {\n\t\t\t\t\tic, err := walk.NewIconFromImage(makeDigitImage(counter))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tcounter++\n\t\t\t\t\tmw.SetIcon(ic)\n\t\t\t\t\tif windowIcon != nil {\n\t\t\t\t\t\twindowIcon.Dispose()\n\t\t\t\t\t}\n\t\t\t\t\twindowIcon = ic\n\t\t\t\t},\n\t\t\t},\n\t\t\tHSpacer{},\n\t\t},\n\t}.Run()); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\n//  A\n// F B\n//  G\n// E C\n//  D\nvar hexdigits = []int{0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71}\n\n//0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B, 0x77, 0x1F, 0x4E, 0x3D, 0x4F, 0x47\n\ntype seg struct {\n\tsx, sy int\n\tdx, dy int\n}\n\nvar segments = []seg{\n\t{0, 0, 1, 0},\n\t{1, 0, 0, 1},\n\t{1, 1, 0, 1},\n\t{0, 2, 1, 0},\n\t{0, 1, 0, 1},\n\t{0, 0, 0, 1},\n\t{0, 1, 1, 0},\n}\n\nfunc digit(im draw.Image, col color.Color, x, y, size, digit int) {\n\tn := hexdigits[digit]\n\tfor _, s := range segments {\n\t\tif n&1 != 0 {\n\t\t\txx, yy := x+s.sx*size, y+s.sy*size\n\t\t\tfor i := 0; i <= size; i++ {\n\t\t\t\tim.Set(xx, yy, col)\n\t\t\t\txx += s.dx\n\t\t\t\tyy += s.dy\n\t\t\t}\n\t\t}\n\t\tn >>= 1\n\t}\n}\n\nfunc makeDigitImage(n int) image.Image {\n\tim := image.NewRGBA(image.Rect(0, 0, 16, 16))\n\tfor p := 11; p >= 0; p -= 5 {\n\t\tdigit(im, color.Black, p, 5, 3, n%10)\n\t\tn /= 10\n\t}\n\treturn im\n}\n"
  },
  {
    "path": "examples/imageview/imageview.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/imageview/imageview.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\twalk.Resources.SetRootDirPath(\"../img\")\n\n\ttype Mode struct {\n\t\tName  string\n\t\tValue ImageViewMode\n\t}\n\n\tmodes := []Mode{\n\t\t{\"ImageViewModeIdeal\", ImageViewModeIdeal},\n\t\t{\"ImageViewModeCorner\", ImageViewModeCorner},\n\t\t{\"ImageViewModeCenter\", ImageViewModeCenter},\n\t\t{\"ImageViewModeShrink\", ImageViewModeShrink},\n\t\t{\"ImageViewModeZoom\", ImageViewModeZoom},\n\t\t{\"ImageViewModeStretch\", ImageViewModeStretch},\n\t}\n\n\tvar widgets []Widget\n\n\tfor _, mode := range modes {\n\t\twidgets = append(widgets,\n\t\t\tLabel{\n\t\t\t\tText: mode.Name,\n\t\t\t},\n\t\t\tImageView{\n\t\t\t\tBackground: SolidColorBrush{Color: walk.RGB(255, 191, 0)},\n\t\t\t\tImage:      \"open.png\",\n\t\t\t\tMargin:     10,\n\t\t\t\tMode:       mode.Value,\n\t\t\t},\n\t\t)\n\t}\n\n\tMainWindow{\n\t\tTitle:    \"Walk ImageView Example\",\n\t\tSize:     Size{400, 600},\n\t\tLayout:   Grid{Columns: 2},\n\t\tChildren: widgets,\n\t}.Run()\n}\n"
  },
  {
    "path": "examples/imageviewer/imageviewer.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/imageviewer/imageviewer.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n\t\"path\"\n\t\"strings\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tmw := new(MyMainWindow)\n\tvar openAction *walk.Action\n\n\tif _, err := (MainWindow{\n\t\tAssignTo: &mw.MainWindow,\n\t\tTitle:    \"Walk Image Viewer Example\",\n\t\tMenuItems: []MenuItem{\n\t\t\tMenu{\n\t\t\t\tText: \"&File\",\n\t\t\t\tItems: []MenuItem{\n\t\t\t\t\tAction{\n\t\t\t\t\t\tAssignTo:    &openAction,\n\t\t\t\t\t\tText:        \"&Open\",\n\t\t\t\t\t\tImage:       \"../img/open.png\",\n\t\t\t\t\t\tOnTriggered: mw.openAction_Triggered,\n\t\t\t\t\t},\n\t\t\t\t\tSeparator{},\n\t\t\t\t\tAction{\n\t\t\t\t\t\tText:        \"Exit\",\n\t\t\t\t\t\tOnTriggered: func() { mw.Close() },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tMenu{\n\t\t\t\tText: \"&Help\",\n\t\t\t\tItems: []MenuItem{\n\t\t\t\t\tAction{\n\t\t\t\t\t\tText:        \"About\",\n\t\t\t\t\t\tOnTriggered: mw.aboutAction_Triggered,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tToolBarItems: []MenuItem{\n\t\t\tActionRef{&openAction},\n\t\t},\n\t\tMinSize: Size{320, 240},\n\t\tSize:    Size{800, 600},\n\t\tLayout:  VBox{MarginsZero: true},\n\t\tChildren: []Widget{\n\t\t\tTabWidget{\n\t\t\t\tAssignTo: &mw.tabWidget,\n\t\t\t},\n\t\t},\n\t}.Run()); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\ntype MyMainWindow struct {\n\t*walk.MainWindow\n\ttabWidget    *walk.TabWidget\n\tprevFilePath string\n}\n\nfunc (mw *MyMainWindow) openAction_Triggered() {\n\tif err := mw.openImage(); err != nil {\n\t\tlog.Print(err)\n\t}\n}\n\nfunc (mw *MyMainWindow) openImage() error {\n\tdlg := new(walk.FileDialog)\n\n\tdlg.FilePath = mw.prevFilePath\n\tdlg.Filter = \"Image Files (*.emf;*.bmp;*.exif;*.gif;*.jpeg;*.jpg;*.png;*.tiff)|*.emf;*.bmp;*.exif;*.gif;*.jpeg;*.jpg;*.png;*.tiff\"\n\tdlg.Title = \"Select an Image\"\n\n\tif ok, err := dlg.ShowOpen(mw); err != nil {\n\t\treturn err\n\t} else if !ok {\n\t\treturn nil\n\t}\n\n\tmw.prevFilePath = dlg.FilePath\n\n\timg, err := walk.NewImageFromFile(dlg.FilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar succeeded bool\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\timg.Dispose()\n\t\t}\n\t}()\n\n\tpage, err := walk.NewTabPage()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif page.SetTitle(path.Base(strings.Replace(dlg.FilePath, \"\\\\\", \"/\", -1))); err != nil {\n\t\treturn err\n\t}\n\tpage.SetLayout(walk.NewHBoxLayout())\n\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tpage.Dispose()\n\t\t}\n\t}()\n\n\timageView, err := walk.NewImageView(page)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\timageView.Dispose()\n\t\t}\n\t}()\n\n\timageView.SetMode(walk.ImageViewModeShrink)\n\n\tif err := imageView.SetImage(img); err != nil {\n\t\treturn err\n\t}\n\n\tif err := mw.tabWidget.Pages().Add(page); err != nil {\n\t\treturn err\n\t}\n\n\tif err := mw.tabWidget.SetCurrentIndex(mw.tabWidget.Pages().Len() - 1); err != nil {\n\t\treturn err\n\t}\n\n\tsucceeded = true\n\n\treturn nil\n}\n\nfunc (mw *MyMainWindow) aboutAction_Triggered() {\n\twalk.MsgBox(mw, \"About\", \"Walk Image Viewer Example\", walk.MsgBoxIconInformation)\n}\n"
  },
  {
    "path": "examples/img/README",
    "content": "Most image files in this directory are from the base icon theme of the\nTango Desktop Project at http://tango.freedesktop.org.\n\nThanks for releasing those to the Public Domain.\n"
  },
  {
    "path": "examples/linklabel/linklabel.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/linklabel/linklabel.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tif _, err := (MainWindow{\n\t\tTitle:   \"Walk LinkLabel Example\",\n\t\tMinSize: Size{300, 200},\n\t\tLayout:  VBox{},\n\t\tChildren: []Widget{\n\t\t\tLinkLabel{\n\t\t\t\tMaxSize: Size{100, 0},\n\t\t\t\tText:    `I can contain multiple links like <a id=\"this\" href=\"https://golang.org\">this</a> or <a id=\"that\" href=\"https://github.com/lxn/walk\">that one</a>.`,\n\t\t\t\tOnLinkActivated: func(link *walk.LinkLabelLink) {\n\t\t\t\t\tlog.Printf(\"id: '%s', url: '%s'\\n\", link.Id(), link.URL())\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}).Run(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "examples/listbox/listbox.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/listbox/listbox.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tmw := &MyMainWindow{model: NewEnvModel()}\n\n\tif _, err := (MainWindow{\n\t\tAssignTo: &mw.MainWindow,\n\t\tTitle:    \"Walk ListBox Example\",\n\t\tMinSize:  Size{240, 320},\n\t\tSize:     Size{300, 400},\n\t\tLayout:   VBox{MarginsZero: true},\n\t\tChildren: []Widget{\n\t\t\tHSplitter{\n\t\t\t\tChildren: []Widget{\n\t\t\t\t\tListBox{\n\t\t\t\t\t\tAssignTo: &mw.lb,\n\t\t\t\t\t\tModel:    mw.model,\n\t\t\t\t\t\tOnCurrentIndexChanged: mw.lb_CurrentIndexChanged,\n\t\t\t\t\t\tOnItemActivated:       mw.lb_ItemActivated,\n\t\t\t\t\t},\n\t\t\t\t\tTextEdit{\n\t\t\t\t\t\tAssignTo: &mw.te,\n\t\t\t\t\t\tReadOnly: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}.Run()); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\ntype MyMainWindow struct {\n\t*walk.MainWindow\n\tmodel *EnvModel\n\tlb    *walk.ListBox\n\tte    *walk.TextEdit\n}\n\nfunc (mw *MyMainWindow) lb_CurrentIndexChanged() {\n\ti := mw.lb.CurrentIndex()\n\titem := &mw.model.items[i]\n\n\tmw.te.SetText(item.value)\n\n\tfmt.Println(\"CurrentIndex: \", i)\n\tfmt.Println(\"CurrentEnvVarName: \", item.name)\n}\n\nfunc (mw *MyMainWindow) lb_ItemActivated() {\n\tvalue := mw.model.items[mw.lb.CurrentIndex()].value\n\n\twalk.MsgBox(mw, \"Value\", value, walk.MsgBoxIconInformation)\n}\n\ntype EnvItem struct {\n\tname  string\n\tvalue string\n}\n\ntype EnvModel struct {\n\twalk.ListModelBase\n\titems []EnvItem\n}\n\nfunc NewEnvModel() *EnvModel {\n\tenv := os.Environ()\n\n\tm := &EnvModel{items: make([]EnvItem, len(env))}\n\n\tfor i, e := range env {\n\t\tj := strings.Index(e, \"=\")\n\t\tif j == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tname := e[0:j]\n\t\tvalue := strings.Replace(e[j+1:], \";\", \"\\r\\n\", -1)\n\n\t\tm.items[i] = EnvItem{name, value}\n\t}\n\n\treturn m\n}\n\nfunc (m *EnvModel) ItemCount() int {\n\treturn len(m.items)\n}\n\nfunc (m *EnvModel) Value(index int) interface{} {\n\treturn m.items[index].name\n}\n"
  },
  {
    "path": "examples/listbox_ownerdrawing/listbox_ownerdrawing.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/listbox_ownerdrawing/listbox_ownerdrawing.go",
    "content": "// Copyright 2019 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n\t\"github.com/lxn/win\"\n)\n\nfunc main() {\n\tvar mw *walk.MainWindow\n\tvar lb *walk.ListBox\n\tvar items []logEntry\n\tfor i := 10000; i > 0; i-- {\n\t\titems = append(items, logEntry{time.Now().Add(-time.Second * time.Duration(i)), fmt.Sprintf(\"Some stuff just happend. %s\", strings.TrimSpace(strings.Repeat(\"blah \", i%100)))})\n\t}\n\tmodel := &logModel{items: items}\n\tstyler := &Styler{\n\t\tlb:                  &lb,\n\t\tmodel:               model,\n\t\tdpi2StampSize:       make(map[int]walk.Size),\n\t\twidthDPI2WsPerLine:  make(map[widthDPI]int),\n\t\ttextWidthDPI2Height: make(map[textWidthDPI]int),\n\t}\n\n\tif err := (MainWindow{\n\t\tAssignTo: &mw,\n\t\tTitle:    \"Walk ListBox Owner Drawing Example\",\n\t\tMinSize:  Size{200, 200},\n\t\tSize:     Size{800, 600},\n\t\tFont:     Font{Family: \"Segoe UI\", PointSize: 9},\n\t\tLayout:   VBox{},\n\t\tChildren: []Widget{\n\t\t\tComposite{\n\t\t\t\tDoubleBuffering: true,\n\t\t\t\tLayout:          VBox{},\n\t\t\t\tChildren: []Widget{\n\t\t\t\t\tListBox{\n\t\t\t\t\t\tAssignTo:       &lb,\n\t\t\t\t\t\tMultiSelection: true,\n\t\t\t\t\t\tModel:          model,\n\t\t\t\t\t\tItemStyler:     styler,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}).Create(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tticker := time.NewTicker(time.Second)\n\tdefer ticker.Stop()\n\n\tcancel := make(chan bool, 1)\n\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ticker.C:\n\t\t\t\tmw.Synchronize(func() {\n\t\t\t\t\ttrackLatest := lb.ItemVisible(len(model.items)-1) && len(lb.SelectedIndexes()) <= 1\n\n\t\t\t\t\tmodel.items = append(model.items, logEntry{time.Now(), \"Some new stuff.\"})\n\t\t\t\t\tindex := len(model.items) - 1\n\t\t\t\t\tmodel.PublishItemsInserted(index, index)\n\n\t\t\t\t\tif trackLatest {\n\t\t\t\t\t\tlb.EnsureItemVisible(len(model.items) - 1)\n\t\t\t\t\t}\n\t\t\t\t})\n\n\t\t\tcase <-cancel:\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}()\n\n\tmw.Show()\n\tmw.Run()\n\n\tcancel <- true\n}\n\ntype logModel struct {\n\twalk.ReflectListModelBase\n\titems []logEntry\n}\n\nfunc (m *logModel) Items() interface{} {\n\treturn m.items\n}\n\ntype logEntry struct {\n\ttimestamp time.Time\n\tmessage   string\n}\n\ntype widthDPI struct {\n\twidth int // in native pixels\n\tdpi   int\n}\n\ntype textWidthDPI struct {\n\ttext  string\n\twidth int // in native pixels\n\tdpi   int\n}\n\ntype Styler struct {\n\tlb                  **walk.ListBox\n\tcanvas              *walk.Canvas\n\tmodel               *logModel\n\tfont                *walk.Font\n\tdpi2StampSize       map[int]walk.Size\n\twidthDPI2WsPerLine  map[widthDPI]int\n\ttextWidthDPI2Height map[textWidthDPI]int // in native pixels\n}\n\nfunc (s *Styler) ItemHeightDependsOnWidth() bool {\n\treturn true\n}\n\nfunc (s *Styler) DefaultItemHeight() int {\n\tdpi := (*s.lb).DPI()\n\tmarginV := walk.IntFrom96DPI(marginV96dpi, dpi)\n\n\treturn s.StampSize().Height + marginV*2\n}\n\nconst (\n\tmarginH96dpi int = 6\n\tmarginV96dpi int = 2\n\tlineW96dpi   int = 1\n)\n\nfunc (s *Styler) ItemHeight(index, width int) int {\n\tdpi := (*s.lb).DPI()\n\tmarginH := walk.IntFrom96DPI(marginH96dpi, dpi)\n\tmarginV := walk.IntFrom96DPI(marginV96dpi, dpi)\n\tlineW := walk.IntFrom96DPI(lineW96dpi, dpi)\n\n\tmsg := s.model.items[index].message\n\n\ttwd := textWidthDPI{msg, width, dpi}\n\n\tif height, ok := s.textWidthDPI2Height[twd]; ok {\n\t\treturn height + marginV*2\n\t}\n\n\tcanvas, err := s.Canvas()\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\tstampSize := s.StampSize()\n\n\twd := widthDPI{width, dpi}\n\twsPerLine, ok := s.widthDPI2WsPerLine[wd]\n\tif !ok {\n\t\tbounds, _, err := canvas.MeasureTextPixels(\"W\", (*s.lb).Font(), walk.Rectangle{Width: 9999999}, walk.TextCalcRect)\n\t\tif err != nil {\n\t\t\treturn 0\n\t\t}\n\t\twsPerLine = (width - marginH*4 - lineW - stampSize.Width) / bounds.Width\n\t\ts.widthDPI2WsPerLine[wd] = wsPerLine\n\t}\n\n\tif len(msg) <= wsPerLine {\n\t\ts.textWidthDPI2Height[twd] = stampSize.Height\n\t\treturn stampSize.Height + marginV*2\n\t}\n\n\tbounds, _, err := canvas.MeasureTextPixels(msg, (*s.lb).Font(), walk.Rectangle{Width: width - marginH*4 - lineW - stampSize.Width, Height: 255}, walk.TextEditControl|walk.TextWordbreak|walk.TextEndEllipsis)\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\ts.textWidthDPI2Height[twd] = bounds.Height\n\n\treturn bounds.Height + marginV*2\n}\n\nfunc (s *Styler) StyleItem(style *walk.ListItemStyle) {\n\tif canvas := style.Canvas(); canvas != nil {\n\t\tif style.Index()%2 == 1 && style.BackgroundColor == walk.Color(win.GetSysColor(win.COLOR_WINDOW)) {\n\t\t\tstyle.BackgroundColor = walk.Color(win.GetSysColor(win.COLOR_BTNFACE))\n\t\t\tif err := style.DrawBackground(); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tpen, err := walk.NewCosmeticPen(walk.PenSolid, style.LineColor)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tdefer pen.Dispose()\n\n\t\tdpi := (*s.lb).DPI()\n\t\tmarginH := walk.IntFrom96DPI(marginH96dpi, dpi)\n\t\tmarginV := walk.IntFrom96DPI(marginV96dpi, dpi)\n\t\tlineW := walk.IntFrom96DPI(lineW96dpi, dpi)\n\n\t\tb := style.BoundsPixels()\n\t\tb.X += marginH\n\t\tb.Y += marginV\n\n\t\titem := s.model.items[style.Index()]\n\n\t\tstyle.DrawText(item.timestamp.Format(time.StampMilli), b, walk.TextEditControl|walk.TextWordbreak)\n\n\t\tstampSize := s.StampSize()\n\n\t\tx := b.X + stampSize.Width + marginH + lineW\n\t\tcanvas.DrawLinePixels(pen, walk.Point{x, b.Y - marginV}, walk.Point{x, b.Y - marginV + b.Height})\n\n\t\tb.X += stampSize.Width + marginH*2 + lineW\n\t\tb.Width -= stampSize.Width + marginH*4 + lineW\n\n\t\tstyle.DrawText(item.message, b, walk.TextEditControl|walk.TextWordbreak|walk.TextEndEllipsis)\n\t}\n}\n\nfunc (s *Styler) StampSize() walk.Size {\n\tdpi := (*s.lb).DPI()\n\n\tstampSize, ok := s.dpi2StampSize[dpi]\n\tif !ok {\n\t\tcanvas, err := s.Canvas()\n\t\tif err != nil {\n\t\t\treturn walk.Size{}\n\t\t}\n\n\t\tbounds, _, err := canvas.MeasureTextPixels(\"Jan _2 20:04:05.000\", (*s.lb).Font(), walk.Rectangle{Width: 9999999}, walk.TextCalcRect)\n\t\tif err != nil {\n\t\t\treturn walk.Size{}\n\t\t}\n\n\t\tstampSize = bounds.Size()\n\t\ts.dpi2StampSize[dpi] = stampSize\n\t}\n\n\treturn stampSize\n}\n\nfunc (s *Styler) Canvas() (*walk.Canvas, error) {\n\tif s.canvas != nil {\n\t\treturn s.canvas, nil\n\t}\n\n\tcanvas, err := (*s.lb).CreateCanvas()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ts.canvas = canvas\n\t(*s.lb).AddDisposable(canvas)\n\n\treturn canvas, nil\n}\n"
  },
  {
    "path": "examples/logview/logview.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/logview/logview.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\npackage main\n\nimport (\n\t\"errors\"\n\t\"syscall\"\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t\"github.com/lxn/win\"\n)\n\ntype LogView struct {\n\twalk.WidgetBase\n\tlogChan chan string\n}\n\nconst (\n\tTEM_APPENDTEXT = win.WM_USER + 6\n)\n\nfunc NewLogView(parent walk.Container) (*LogView, error) {\n\tlc := make(chan string, 1024)\n\tlv := &LogView{logChan: lc}\n\n\tif err := walk.InitWidget(\n\t\tlv,\n\t\tparent,\n\t\t\"EDIT\",\n\t\twin.WS_TABSTOP|win.WS_VISIBLE|win.WS_VSCROLL|win.ES_MULTILINE|win.ES_WANTRETURN,\n\t\twin.WS_EX_CLIENTEDGE); err != nil {\n\t\treturn nil, err\n\t}\n\tlv.setReadOnly(true)\n\tlv.SendMessage(win.EM_SETLIMITTEXT, 4294967295, 0)\n\treturn lv, nil\n}\n\nfunc (*LogView) CreateLayoutItem(ctx *walk.LayoutContext) walk.LayoutItem {\n\treturn walk.NewGreedyLayoutItem()\n}\n\nfunc (lv *LogView) setTextSelection(start, end int) {\n\tlv.SendMessage(win.EM_SETSEL, uintptr(start), uintptr(end))\n}\n\nfunc (lv *LogView) textLength() int {\n\treturn int(lv.SendMessage(0x000E, uintptr(0), uintptr(0)))\n}\n\nfunc (lv *LogView) AppendText(value string) {\n\ttextLength := lv.textLength()\n\tlv.setTextSelection(textLength, textLength)\n\tlv.SendMessage(win.EM_REPLACESEL, 0, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value))))\n}\n\nfunc (lv *LogView) setReadOnly(readOnly bool) error {\n\tif 0 == lv.SendMessage(win.EM_SETREADONLY, uintptr(win.BoolToBOOL(readOnly)), 0) {\n\t\treturn errors.New(\"fail to call EM_SETREADONLY\")\n\t}\n\n\treturn nil\n}\n\nfunc (lv *LogView) PostAppendText(value string) {\n\tlv.logChan <- value\n\twin.PostMessage(lv.Handle(), TEM_APPENDTEXT, 0, 0)\n}\n\nfunc (lv *LogView) Write(p []byte) (int, error) {\n\tlv.PostAppendText(string(p) + \"\\r\\n\")\n\treturn len(p), nil\n}\n\nfunc (lv *LogView) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_GETDLGCODE:\n\t\tif wParam == win.VK_RETURN {\n\t\t\treturn win.DLGC_WANTALLKEYS\n\t\t}\n\n\t\treturn win.DLGC_HASSETSEL | win.DLGC_WANTARROWS | win.DLGC_WANTCHARS\n\tcase TEM_APPENDTEXT:\n\t\tselect {\n\t\tcase value := <-lv.logChan:\n\t\t\tlv.AppendText(value)\n\t\tdefault:\n\t\t\treturn 0\n\t\t}\n\t}\n\n\treturn lv.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n"
  },
  {
    "path": "examples/logview/logviewapp.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n\t\"time\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tvar mw *walk.MainWindow\n\n\tif err := (MainWindow{\n\t\tAssignTo: &mw,\n\t\tTitle:    \"Walk LogView Example\",\n\t\tMinSize:  Size{320, 240},\n\t\tSize:     Size{400, 600},\n\t\tLayout:   VBox{MarginsZero: true},\n\t}.Create()); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tlv, err := NewLogView(mw)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tlv.PostAppendText(\"XXX\")\n\tlog.SetOutput(lv)\n\n\tgo func() {\n\t\tfor i := 0; i < 10000; i++ {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tlog.Println(\"Text\" + \"\\r\\n\")\n\t\t}\n\t}()\n\n\tmw.Run()\n}\n"
  },
  {
    "path": "examples/multiplepages/main.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"bytes\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\twalk.Resources.SetRootDirPath(\"../img\")\n\n\tmw := new(AppMainWindow)\n\n\tcfg := &MultiPageMainWindowConfig{\n\t\tName:    \"mainWindow\",\n\t\tMinSize: Size{600, 400},\n\t\tMenuItems: []MenuItem{\n\t\t\tMenu{\n\t\t\t\tText: \"&Help\",\n\t\t\t\tItems: []MenuItem{\n\t\t\t\t\tAction{\n\t\t\t\t\t\tText:        \"About\",\n\t\t\t\t\t\tOnTriggered: func() { mw.aboutAction_Triggered() },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tOnCurrentPageChanged: func() {\n\t\t\tmw.updateTitle(mw.CurrentPageTitle())\n\t\t},\n\t\tPageCfgs: []PageConfig{\n\t\t\t{\"Foo\", \"document-new.png\", newFooPage},\n\t\t\t{\"Bar\", \"document-properties.png\", newBarPage},\n\t\t\t{\"Baz\", \"system-shutdown.png\", newBazPage},\n\t\t},\n\t}\n\n\tmpmw, err := NewMultiPageMainWindow(cfg)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tmw.MultiPageMainWindow = mpmw\n\n\tmw.updateTitle(mw.CurrentPageTitle())\n\n\tmw.Run()\n}\n\ntype AppMainWindow struct {\n\t*MultiPageMainWindow\n}\n\nfunc (mw *AppMainWindow) updateTitle(prefix string) {\n\tvar buf bytes.Buffer\n\n\tif prefix != \"\" {\n\t\tbuf.WriteString(prefix)\n\t\tbuf.WriteString(\" - \")\n\t}\n\n\tbuf.WriteString(\"Walk Multiple Pages Example\")\n\n\tmw.SetTitle(buf.String())\n}\n\nfunc (mw *AppMainWindow) aboutAction_Triggered() {\n\twalk.MsgBox(mw,\n\t\t\"About Walk Multiple Pages Example\",\n\t\t\"An example that demonstrates a main window that supports multiple pages.\",\n\t\twalk.MsgBoxOK|walk.MsgBoxIconInformation)\n}\n\ntype FooPage struct {\n\t*walk.Composite\n}\n\nfunc newFooPage(parent walk.Container) (Page, error) {\n\tp := new(FooPage)\n\n\tif err := (Composite{\n\t\tAssignTo: &p.Composite,\n\t\tName:     \"fooPage\",\n\t\tLayout:   HBox{},\n\t\tChildren: []Widget{\n\t\t\tHSpacer{},\n\t\t\tLabel{Text: \"I'm the Foo page\"},\n\t\t\tHSpacer{},\n\t\t},\n\t}).Create(NewBuilder(parent)); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := walk.InitWrapperWindow(p); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn p, nil\n}\n\ntype BarPage struct {\n\t*walk.Composite\n}\n\nfunc newBarPage(parent walk.Container) (Page, error) {\n\tp := new(BarPage)\n\n\tif err := (Composite{\n\t\tAssignTo: &p.Composite,\n\t\tName:     \"barPage\",\n\t\tLayout:   HBox{},\n\t\tChildren: []Widget{\n\t\t\tHSpacer{},\n\t\t\tLabel{Text: \"I'm the Bar page\"},\n\t\t\tHSpacer{},\n\t\t},\n\t}).Create(NewBuilder(parent)); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := walk.InitWrapperWindow(p); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn p, nil\n}\n\ntype BazPage struct {\n\t*walk.Composite\n}\n\nfunc newBazPage(parent walk.Container) (Page, error) {\n\tp := new(BazPage)\n\n\tif err := (Composite{\n\t\tAssignTo: &p.Composite,\n\t\tName:     \"bazPage\",\n\t\tLayout:   HBox{},\n\t\tChildren: []Widget{\n\t\t\tHSpacer{},\n\t\t\tLabel{Text: \"I'm the Baz page\"},\n\t\t\tHSpacer{},\n\t\t},\n\t}).Create(NewBuilder(parent)); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := walk.InitWrapperWindow(p); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn p, nil\n}\n"
  },
  {
    "path": "examples/multiplepages/multipagemainwindow.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\ntype MultiPageMainWindowConfig struct {\n\tName                 string\n\tEnabled              Property\n\tVisible              Property\n\tFont                 Font\n\tMinSize              Size\n\tMaxSize              Size\n\tContextMenuItems     []MenuItem\n\tOnKeyDown            walk.KeyEventHandler\n\tOnKeyPress           walk.KeyEventHandler\n\tOnKeyUp              walk.KeyEventHandler\n\tOnMouseDown          walk.MouseEventHandler\n\tOnMouseMove          walk.MouseEventHandler\n\tOnMouseUp            walk.MouseEventHandler\n\tOnSizeChanged        walk.EventHandler\n\tOnCurrentPageChanged walk.EventHandler\n\tTitle                string\n\tSize                 Size\n\tMenuItems            []MenuItem\n\tToolBar              ToolBar\n\tPageCfgs             []PageConfig\n}\n\ntype PageConfig struct {\n\tTitle   string\n\tImage   string\n\tNewPage PageFactoryFunc\n}\n\ntype PageFactoryFunc func(parent walk.Container) (Page, error)\n\ntype Page interface {\n\t// Provided by Walk\n\twalk.Container\n\tParent() walk.Container\n\tSetParent(parent walk.Container) error\n}\n\ntype MultiPageMainWindow struct {\n\t*walk.MainWindow\n\tnavTB                       *walk.ToolBar\n\tpageCom                     *walk.Composite\n\taction2NewPage              map[*walk.Action]PageFactoryFunc\n\tpageActions                 []*walk.Action\n\tcurrentAction               *walk.Action\n\tcurrentPage                 Page\n\tcurrentPageChangedPublisher walk.EventPublisher\n}\n\nfunc NewMultiPageMainWindow(cfg *MultiPageMainWindowConfig) (*MultiPageMainWindow, error) {\n\tmpmw := &MultiPageMainWindow{\n\t\taction2NewPage: make(map[*walk.Action]PageFactoryFunc),\n\t}\n\n\tif err := (MainWindow{\n\t\tAssignTo:         &mpmw.MainWindow,\n\t\tName:             cfg.Name,\n\t\tTitle:            cfg.Title,\n\t\tEnabled:          cfg.Enabled,\n\t\tVisible:          cfg.Visible,\n\t\tFont:             cfg.Font,\n\t\tMinSize:          cfg.MinSize,\n\t\tMaxSize:          cfg.MaxSize,\n\t\tMenuItems:        cfg.MenuItems,\n\t\tToolBar:          cfg.ToolBar,\n\t\tContextMenuItems: cfg.ContextMenuItems,\n\t\tOnKeyDown:        cfg.OnKeyDown,\n\t\tOnKeyPress:       cfg.OnKeyPress,\n\t\tOnKeyUp:          cfg.OnKeyUp,\n\t\tOnMouseDown:      cfg.OnMouseDown,\n\t\tOnMouseMove:      cfg.OnMouseMove,\n\t\tOnMouseUp:        cfg.OnMouseUp,\n\t\tOnSizeChanged:    cfg.OnSizeChanged,\n\t\tLayout:           HBox{MarginsZero: true, SpacingZero: true},\n\t\tChildren: []Widget{\n\t\t\tScrollView{\n\t\t\t\tHorizontalFixed: true,\n\t\t\t\tLayout:          VBox{MarginsZero: true},\n\t\t\t\tChildren: []Widget{\n\t\t\t\t\tComposite{\n\t\t\t\t\t\tLayout: VBox{MarginsZero: true},\n\t\t\t\t\t\tChildren: []Widget{\n\t\t\t\t\t\t\tToolBar{\n\t\t\t\t\t\t\t\tAssignTo:    &mpmw.navTB,\n\t\t\t\t\t\t\t\tOrientation: Vertical,\n\t\t\t\t\t\t\t\tButtonStyle: ToolBarButtonImageAboveText,\n\t\t\t\t\t\t\t\tMaxTextRows: 2,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tComposite{\n\t\t\t\tAssignTo: &mpmw.pageCom,\n\t\t\t\tName:     \"pageCom\",\n\t\t\t\tLayout:   HBox{MarginsZero: true, SpacingZero: true},\n\t\t\t},\n\t\t},\n\t}).Create(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tmpmw.Dispose()\n\t\t}\n\t}()\n\n\tfor _, pc := range cfg.PageCfgs {\n\t\taction, err := mpmw.newPageAction(pc.Title, pc.Image, pc.NewPage)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tmpmw.pageActions = append(mpmw.pageActions, action)\n\t}\n\n\tif err := mpmw.updateNavigationToolBar(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(mpmw.pageActions) > 0 {\n\t\tif err := mpmw.setCurrentAction(mpmw.pageActions[0]); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif cfg.OnCurrentPageChanged != nil {\n\t\tmpmw.CurrentPageChanged().Attach(cfg.OnCurrentPageChanged)\n\t}\n\n\tsucceeded = true\n\n\treturn mpmw, nil\n}\n\nfunc (mpmw *MultiPageMainWindow) CurrentPage() Page {\n\treturn mpmw.currentPage\n}\n\nfunc (mpmw *MultiPageMainWindow) CurrentPageTitle() string {\n\tif mpmw.currentAction == nil {\n\t\treturn \"\"\n\t}\n\n\treturn mpmw.currentAction.Text()\n}\n\nfunc (mpmw *MultiPageMainWindow) CurrentPageChanged() *walk.Event {\n\treturn mpmw.currentPageChangedPublisher.Event()\n}\n\nfunc (mpmw *MultiPageMainWindow) newPageAction(title, image string, newPage PageFactoryFunc) (*walk.Action, error) {\n\timg, err := walk.Resources.Bitmap(image)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\taction := walk.NewAction()\n\taction.SetCheckable(true)\n\taction.SetExclusive(true)\n\taction.SetImage(img)\n\taction.SetText(title)\n\n\tmpmw.action2NewPage[action] = newPage\n\n\taction.Triggered().Attach(func() {\n\t\tmpmw.setCurrentAction(action)\n\t})\n\n\treturn action, nil\n}\n\nfunc (mpmw *MultiPageMainWindow) setCurrentAction(action *walk.Action) error {\n\tdefer func() {\n\t\tif !mpmw.pageCom.IsDisposed() {\n\t\t\tmpmw.pageCom.RestoreState()\n\t\t}\n\t}()\n\n\tmpmw.SetFocus()\n\n\tif prevPage := mpmw.currentPage; prevPage != nil {\n\t\tmpmw.pageCom.SaveState()\n\t\tprevPage.SetVisible(false)\n\t\tprevPage.(walk.Widget).SetParent(nil)\n\t\tprevPage.Dispose()\n\t}\n\n\tnewPage := mpmw.action2NewPage[action]\n\n\tpage, err := newPage(mpmw.pageCom)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\taction.SetChecked(true)\n\n\tmpmw.currentPage = page\n\tmpmw.currentAction = action\n\n\tmpmw.currentPageChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (mpmw *MultiPageMainWindow) updateNavigationToolBar() error {\n\tmpmw.navTB.SetSuspended(true)\n\tdefer mpmw.navTB.SetSuspended(false)\n\n\tactions := mpmw.navTB.Actions()\n\n\tif err := actions.Clear(); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, action := range mpmw.pageActions {\n\t\tif err := actions.Add(action); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif mpmw.currentAction != nil {\n\t\tif !actions.Contains(mpmw.currentAction) {\n\t\t\tfor _, action := range mpmw.pageActions {\n\t\t\t\tif action != mpmw.currentAction {\n\t\t\t\t\tif err := mpmw.setCurrentAction(action); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "examples/multiplepages/multiplepages.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/notifyicon/notifyicon.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/notifyicon/notifyicon.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\nfunc main() {\n\t// We need either a walk.MainWindow or a walk.Dialog for their message loop.\n\t// We will not make it visible in this example, though.\n\tmw, err := walk.NewMainWindow()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// We load our icon from a file.\n\ticon, err := walk.Resources.Icon(\"../img/stop.ico\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// Create the notify icon and make sure we clean it up on exit.\n\tni, err := walk.NewNotifyIcon(mw)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdefer ni.Dispose()\n\n\t// Set the icon and a tool tip text.\n\tif err := ni.SetIcon(icon); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tif err := ni.SetToolTip(\"Click for info or use the context menu to exit.\"); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// When the left mouse button is pressed, bring up our balloon.\n\tni.MouseDown().Attach(func(x, y int, button walk.MouseButton) {\n\t\tif button != walk.LeftButton {\n\t\t\treturn\n\t\t}\n\n\t\tif err := ni.ShowCustom(\n\t\t\t\"Walk NotifyIcon Example\",\n\t\t\t\"There are multiple ShowX methods sporting different icons.\",\n\t\t\ticon); err != nil {\n\n\t\t\tlog.Fatal(err)\n\t\t}\n\t})\n\n\t// We put an exit action into the context menu.\n\texitAction := walk.NewAction()\n\tif err := exitAction.SetText(\"E&xit\"); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\texitAction.Triggered().Attach(func() { walk.App().Exit(0) })\n\tif err := ni.ContextMenu().Actions().Add(exitAction); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// The notify icon is hidden initially, so we have to make it visible.\n\tif err := ni.SetVisible(true); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// Now that the icon is visible, we can bring up an info balloon.\n\tif err := ni.ShowInfo(\"Walk NotifyIcon Example\", \"Click the icon to show again.\"); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// Run the message loop.\n\tmw.Run()\n}\n"
  },
  {
    "path": "examples/progressindicator/dialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>Dialog</class>\n <widget class=\"QDialog\" name=\"Dialog\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>598</width>\n    <height>300</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Dialog</string>\n  </property>\n  <widget class=\"QDialogButtonBox\" name=\"buttonBox\">\n   <property name=\"geometry\">\n    <rect>\n     <x>500</x>\n     <y>10</y>\n     <width>81</width>\n     <height>241</height>\n    </rect>\n   </property>\n   <property name=\"orientation\">\n    <enum>Qt::Vertical</enum>\n   </property>\n   <property name=\"standardButtons\">\n    <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>\n   </property>\n  </widget>\n  <widget class=\"QPushButton\" name=\"noProgressBtn\">\n   <property name=\"geometry\">\n    <rect>\n     <x>40</x>\n     <y>60</y>\n     <width>161</width>\n     <height>23</height>\n    </rect>\n   </property>\n   <property name=\"maximumSize\">\n    <size>\n     <width>161</width>\n     <height>16777215</height>\n    </size>\n   </property>\n   <property name=\"text\">\n    <string>NoProgress</string>\n   </property>\n  </widget>\n  <widget class=\"QPushButton\" name=\"indeterminateBtn\">\n   <property name=\"geometry\">\n    <rect>\n     <x>40</x>\n     <y>90</y>\n     <width>161</width>\n     <height>23</height>\n    </rect>\n   </property>\n   <property name=\"maximumSize\">\n    <size>\n     <width>161</width>\n     <height>16777215</height>\n    </size>\n   </property>\n   <property name=\"text\">\n    <string>Indeterminate</string>\n   </property>\n  </widget>\n  <widget class=\"QPushButton\" name=\"normalBtn\">\n   <property name=\"geometry\">\n    <rect>\n     <x>40</x>\n     <y>120</y>\n     <width>161</width>\n     <height>23</height>\n    </rect>\n   </property>\n   <property name=\"maximumSize\">\n    <size>\n     <width>161</width>\n     <height>16777215</height>\n    </size>\n   </property>\n   <property name=\"text\">\n    <string>Normal</string>\n   </property>\n  </widget>\n  <widget class=\"QPushButton\" name=\"errBtn\">\n   <property name=\"geometry\">\n    <rect>\n     <x>40</x>\n     <y>150</y>\n     <width>161</width>\n     <height>23</height>\n    </rect>\n   </property>\n   <property name=\"text\">\n    <string>Error</string>\n   </property>\n  </widget>\n  <widget class=\"QPushButton\" name=\"pausedBtn\">\n   <property name=\"geometry\">\n    <rect>\n     <x>40</x>\n     <y>180</y>\n     <width>161</width>\n     <height>23</height>\n    </rect>\n   </property>\n   <property name=\"text\">\n    <string>Paused</string>\n   </property>\n  </widget>\n  <widget class=\"QPushButton\" name=\"startBtn\">\n   <property name=\"geometry\">\n    <rect>\n     <x>290</x>\n     <y>180</y>\n     <width>75</width>\n     <height>23</height>\n    </rect>\n   </property>\n   <property name=\"text\">\n    <string>START</string>\n   </property>\n  </widget>\n </widget>\n <resources/>\n <connections>\n  <connection>\n   <sender>buttonBox</sender>\n   <signal>accepted()</signal>\n   <receiver>Dialog</receiver>\n   <slot>accept()</slot>\n   <hints>\n    <hint type=\"sourcelabel\">\n     <x>248</x>\n     <y>254</y>\n    </hint>\n    <hint type=\"destinationlabel\">\n     <x>157</x>\n     <y>274</y>\n    </hint>\n   </hints>\n  </connection>\n  <connection>\n   <sender>buttonBox</sender>\n   <signal>rejected()</signal>\n   <receiver>Dialog</receiver>\n   <slot>reject()</slot>\n   <hints>\n    <hint type=\"sourcelabel\">\n     <x>316</x>\n     <y>260</y>\n    </hint>\n    <hint type=\"destinationlabel\">\n     <x>286</x>\n     <y>274</y>\n    </hint>\n   </hints>\n  </connection>\n </connections>\n</ui>\n"
  },
  {
    "path": "examples/progressindicator/dialog_ui.go",
    "content": "// THIS FILE WAS GENERATED BY A TOOL, DO NOT EDIT!\n\npackage main\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\ntype myDialogUI struct {\n\tnoProgressBtn    *walk.PushButton\n\tindeterminateBtn *walk.PushButton\n\tnormalBtn        *walk.PushButton\n\terrBtn           *walk.PushButton\n\tpausedBtn        *walk.PushButton\n\tstartBtn         *walk.PushButton\n}\n\nfunc (w *MyDialog) init(owner walk.Form) (err error) {\n\tif w.Dialog, err = walk.NewDialog(owner); err != nil {\n\t\treturn err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tw.Dispose()\n\t\t}\n\t}()\n\n\tvar font *walk.Font\n\tif font == nil {\n\t\tfont = nil\n\t}\n\n\tw.SetName(\"Dialog\")\n\tif err := w.SetClientSize(walk.Size{598, 300}); err != nil {\n\t\treturn err\n\t}\n\tif err := w.SetTitle(`Dialog`); err != nil {\n\t\treturn err\n\t}\n\n\t// noProgressBtn\n\tif w.ui.noProgressBtn, err = walk.NewPushButton(w); err != nil {\n\t\treturn err\n\t}\n\tw.ui.noProgressBtn.SetName(\"noProgressBtn\")\n\tif err := w.ui.noProgressBtn.SetBounds(walk.Rectangle{40, 60, 161, 23}); err != nil {\n\t\treturn err\n\t}\n\tif err := w.ui.noProgressBtn.SetText(`NoProgress`); err != nil {\n\t\treturn err\n\t}\n\tif err := w.ui.noProgressBtn.SetMinMaxSize(walk.Size{0, 0}, walk.Size{161, 16777215}); err != nil {\n\t\treturn err\n\t}\n\n\t// indeterminateBtn\n\tif w.ui.indeterminateBtn, err = walk.NewPushButton(w); err != nil {\n\t\treturn err\n\t}\n\tw.ui.indeterminateBtn.SetName(\"indeterminateBtn\")\n\tif err := w.ui.indeterminateBtn.SetBounds(walk.Rectangle{40, 90, 161, 23}); err != nil {\n\t\treturn err\n\t}\n\tif err := w.ui.indeterminateBtn.SetText(`Indeterminate`); err != nil {\n\t\treturn err\n\t}\n\tif err := w.ui.indeterminateBtn.SetMinMaxSize(walk.Size{0, 0}, walk.Size{161, 16777215}); err != nil {\n\t\treturn err\n\t}\n\n\t// normalBtn\n\tif w.ui.normalBtn, err = walk.NewPushButton(w); err != nil {\n\t\treturn err\n\t}\n\tw.ui.normalBtn.SetName(\"normalBtn\")\n\tif err := w.ui.normalBtn.SetBounds(walk.Rectangle{40, 120, 161, 23}); err != nil {\n\t\treturn err\n\t}\n\tif err := w.ui.normalBtn.SetText(`Normal`); err != nil {\n\t\treturn err\n\t}\n\tif err := w.ui.normalBtn.SetMinMaxSize(walk.Size{0, 0}, walk.Size{161, 16777215}); err != nil {\n\t\treturn err\n\t}\n\n\t// errBtn\n\tif w.ui.errBtn, err = walk.NewPushButton(w); err != nil {\n\t\treturn err\n\t}\n\tw.ui.errBtn.SetName(\"errBtn\")\n\tif err := w.ui.errBtn.SetBounds(walk.Rectangle{40, 150, 161, 23}); err != nil {\n\t\treturn err\n\t}\n\tif err := w.ui.errBtn.SetText(`Error`); err != nil {\n\t\treturn err\n\t}\n\n\t// pausedBtn\n\tif w.ui.pausedBtn, err = walk.NewPushButton(w); err != nil {\n\t\treturn err\n\t}\n\tw.ui.pausedBtn.SetName(\"pausedBtn\")\n\tif err := w.ui.pausedBtn.SetBounds(walk.Rectangle{40, 180, 161, 23}); err != nil {\n\t\treturn err\n\t}\n\tif err := w.ui.pausedBtn.SetText(`Paused`); err != nil {\n\t\treturn err\n\t}\n\n\t// startBtn\n\tif w.ui.startBtn, err = walk.NewPushButton(w); err != nil {\n\t\treturn err\n\t}\n\tw.ui.startBtn.SetName(\"startBtn\")\n\tif err := w.ui.startBtn.SetBounds(walk.Rectangle{290, 180, 75, 23}); err != nil {\n\t\treturn err\n\t}\n\tif err := w.ui.startBtn.SetText(`START`); err != nil {\n\t\treturn err\n\t}\n\n\t// Tab order\n\n\tsucceeded = true\n\n\treturn nil\n}\n"
  },
  {
    "path": "examples/progressindicator/pi.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n)\n\nfunc main() {\n\tif _, err := RunMyDialog(nil); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\ntype MyDialog struct {\n\t*walk.Dialog\n\tui myDialogUI\n}\n\nfunc (dlg *MyDialog) setState(state walk.PIState) {\n\tif err := dlg.ProgressIndicator().SetState(state); err != nil {\n\t\tlog.Print(err)\n\t}\n}\n\nfunc RunMyDialog(owner walk.Form) (int, error) {\n\tdlg := new(MyDialog)\n\tif err := dlg.init(owner); err != nil {\n\t\treturn 0, err\n\t}\n\n\tdlg.ui.indeterminateBtn.Clicked().Attach(func() {\n\t\tfmt.Println(\"SetState indeterminate\")\n\t\tdlg.setState(walk.PIIndeterminate)\n\t})\n\tdlg.ui.noProgressBtn.Clicked().Attach(func() {\n\t\tfmt.Println(\"SetState noprogress\")\n\t\tdlg.setState(walk.PINoProgress)\n\t})\n\n\tdlg.ui.normalBtn.Clicked().Attach(func() {\n\t\tfmt.Println(\"SetState normal\")\n\t\tdlg.setState(walk.PINormal)\n\t})\n\n\tdlg.ui.errBtn.Clicked().Attach(func() {\n\t\tfmt.Println(\"SetState error\")\n\t\tdlg.setState(walk.PIError)\n\t})\n\n\tdlg.ui.pausedBtn.Clicked().Attach(func() {\n\t\tfmt.Println(\"SetState paused\")\n\t\tdlg.setState(walk.PIPaused)\n\t})\n\n\tdlg.ui.startBtn.Clicked().Attach(func() {\n\t\tgo func() {\n\t\t\tdlg.ProgressIndicator().SetTotal(100)\n\t\t\tvar i uint32\n\t\t\tfor i = 0; i < 100; i++ {\n\t\t\t\tfmt.Println(\"SetProgress\", i)\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\tif err := dlg.ProgressIndicator().SetCompleted(i); err != nil {\n\t\t\t\t\tlog.Print(err)\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t})\n\n\treturn dlg.Run(), nil\n}\n"
  },
  {
    "path": "examples/progressindicator/progressindicator.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/radiobutton/radiobutton.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/radiobutton/radiobutton.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n)\n\nimport (\n\t. \"github.com/lxn/walk/declarative\"\n)\n\ntype Foo struct {\n\tBar string\n\tBaz int\n}\n\nfunc main() {\n\tfoo := &Foo{\"b\", 0}\n\n\tMainWindow{\n\t\tTitle:   \"Walk RadioButton Example\",\n\t\tMinSize: Size{320, 240},\n\t\tLayout:  VBox{},\n\t\tDataBinder: DataBinder{\n\t\t\tDataSource: foo,\n\t\t\tAutoSubmit: true,\n\t\t\tOnSubmitted: func() {\n\t\t\t\tfmt.Println(foo)\n\t\t\t},\n\t\t},\n\t\tChildren: []Widget{\n\t\t\t// RadioButtonGroup is needed for data binding only.\n\t\t\tRadioButtonGroup{\n\t\t\t\tDataMember: \"Bar\",\n\t\t\t\tButtons: []RadioButton{\n\t\t\t\t\tRadioButton{\n\t\t\t\t\t\tName:  \"aRB\",\n\t\t\t\t\t\tText:  \"A\",\n\t\t\t\t\t\tValue: \"a\",\n\t\t\t\t\t},\n\t\t\t\t\tRadioButton{\n\t\t\t\t\t\tName:  \"bRB\",\n\t\t\t\t\t\tText:  \"B\",\n\t\t\t\t\t\tValue: \"b\",\n\t\t\t\t\t},\n\t\t\t\t\tRadioButton{\n\t\t\t\t\t\tName:  \"cRB\",\n\t\t\t\t\t\tText:  \"C\",\n\t\t\t\t\t\tValue: \"c\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tLabel{\n\t\t\t\tText:    \"A\",\n\t\t\t\tEnabled: Bind(\"aRB.Checked\"),\n\t\t\t},\n\t\t\tLabel{\n\t\t\t\tText:    \"B\",\n\t\t\t\tEnabled: Bind(\"bRB.Checked\"),\n\t\t\t},\n\t\t\tLabel{\n\t\t\t\tText:    \"C\",\n\t\t\t\tEnabled: Bind(\"cRB.Checked\"),\n\t\t\t},\n\t\t\tRadioButtonGroup{\n\t\t\t\tDataMember: \"Baz\",\n\t\t\t\tButtons: []RadioButton{\n\t\t\t\t\tRadioButton{\n\t\t\t\t\t\tName:  \"oneRB\",\n\t\t\t\t\t\tText:  \"1\",\n\t\t\t\t\t\tValue: 1,\n\t\t\t\t\t},\n\t\t\t\t\tRadioButton{\n\t\t\t\t\t\tName:  \"twoRB\",\n\t\t\t\t\t\tText:  \"2\",\n\t\t\t\t\t\tValue: 2,\n\t\t\t\t\t},\n\t\t\t\t\tRadioButton{\n\t\t\t\t\t\tName:  \"threeRB\",\n\t\t\t\t\t\tText:  \"3\",\n\t\t\t\t\t\tValue: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tLabel{\n\t\t\t\tText:    \"1\",\n\t\t\t\tEnabled: Bind(\"oneRB.Checked\"),\n\t\t\t},\n\t\t\tLabel{\n\t\t\t\tText:    \"2\",\n\t\t\t\tEnabled: Bind(\"twoRB.Checked\"),\n\t\t\t},\n\t\t\tLabel{\n\t\t\t\tText:    \"3\",\n\t\t\t\tEnabled: Bind(\"threeRB.Checked\"),\n\t\t\t},\n\t\t},\n\t}.Run()\n}\n"
  },
  {
    "path": "examples/settings/settings.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/settings/settings.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"time\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tapp := walk.App()\n\n\t// These specify the app data sub directory for the settings file.\n\tapp.SetOrganizationName(\"The Walk Authors\")\n\tapp.SetProductName(\"Walk Settings Example\")\n\n\t// Settings file name.\n\tsettings := walk.NewIniFileSettings(\"settings.ini\")\n\n\t// All settings marked as expiring will expire after this duration w/o use.\n\t// This applies to all widgets settings.\n\tsettings.SetExpireDuration(time.Hour * 24 * 30 * 3)\n\n\tif err := settings.Load(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tapp.SetSettings(settings)\n\n\tif err := RunMainWindow(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tif err := settings.Save(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc RunMainWindow() error {\n\tif _, err := (MainWindow{\n\t\tName:    \"mainWindow\", // Name is needed for settings persistence\n\t\tTitle:   \"Walk Settings Example\",\n\t\tMinSize: Size{800, 600},\n\t\tLayout:  VBox{MarginsZero: true},\n\t\tChildren: []Widget{\n\t\t\tTableView{\n\t\t\t\tName:             \"tableView\", // Name is needed for settings persistence\n\t\t\t\tAlternatingRowBG: true,\n\t\t\t\tColumnsOrderable: true,\n\t\t\t\tColumns: []TableViewColumn{\n\t\t\t\t\t// Name is needed for settings persistence\n\t\t\t\t\t{Name: \"#\", DataMember: \"Index\"}, // Use DataMember, if names differ\n\t\t\t\t\t{Name: \"Bar\"},\n\t\t\t\t\t{Name: \"Baz\", Format: \"%.2f\", Alignment: AlignFar},\n\t\t\t\t\t{Name: \"Quux\", Format: \"2006-01-02 15:04:05\", Width: 150},\n\t\t\t\t},\n\t\t\t\tModel: NewFooModel(),\n\t\t\t}},\n\t}.Run()); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc NewFooModel() *FooModel {\n\tnow := time.Now()\n\n\trand.Seed(now.UnixNano())\n\n\tm := &FooModel{items: make([]*Foo, 1000)}\n\n\tfor i := range m.items {\n\t\tm.items[i] = &Foo{\n\t\t\tIndex: i,\n\t\t\tBar:   strings.Repeat(\"*\", rand.Intn(5)+1),\n\t\t\tBaz:   rand.Float64() * 1000,\n\t\t\tQuux:  time.Unix(rand.Int63n(now.Unix()), 0),\n\t\t}\n\t}\n\n\treturn m\n}\n\ntype FooModel struct {\n\twalk.SortedReflectTableModelBase\n\titems []*Foo\n}\n\nfunc (m *FooModel) Items() interface{} {\n\treturn m.items\n}\n\ntype Foo struct {\n\tIndex int\n\tBar   string\n\tBaz   float64\n\tQuux  time.Time\n}\n"
  },
  {
    "path": "examples/slider/slider.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/slider/slider.go",
    "content": "// Copyright 2016 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tvar slv, slh *walk.Slider\n\tvar maxEdit, minEdit, valueEdit *walk.NumberEdit\n\n\tdata := struct{ Min, Max, Value int }{0, 100, 30}\n\n\tMainWindow{\n\t\tTitle:   \"Walk Slider Example\",\n\t\tMinSize: Size{320, 240},\n\t\tLayout:  HBox{},\n\t\tChildren: []Widget{\n\t\t\tSlider{\n\t\t\t\tAssignTo:    &slv,\n\t\t\t\tMinValue:    data.Min,\n\t\t\t\tMaxValue:    data.Max,\n\t\t\t\tValue:       data.Value,\n\t\t\t\tOrientation: Vertical,\n\t\t\t\tOnValueChanged: func() {\n\t\t\t\t\tdata.Value = slv.Value()\n\t\t\t\t\tvalueEdit.SetValue(float64(data.Value))\n\n\t\t\t\t},\n\t\t\t},\n\t\t\tComposite{\n\t\t\t\tLayout:        Grid{Columns: 3},\n\t\t\t\tStretchFactor: 4,\n\t\t\t\tChildren: []Widget{\n\t\t\t\t\tLabel{Text: \"Min value\"},\n\t\t\t\t\tLabel{Text: \"Value\"},\n\t\t\t\t\tLabel{Text: \"Max value\"},\n\t\t\t\t\tNumberEdit{\n\t\t\t\t\t\tAssignTo: &minEdit,\n\t\t\t\t\t\tValue:    float64(data.Min),\n\t\t\t\t\t\tOnValueChanged: func() {\n\t\t\t\t\t\t\tdata.Min = int(minEdit.Value())\n\t\t\t\t\t\t\tslh.SetRange(data.Min, data.Max)\n\t\t\t\t\t\t\tslv.SetRange(data.Min, data.Max)\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tNumberEdit{\n\t\t\t\t\t\tAssignTo: &valueEdit,\n\t\t\t\t\t\tValue:    float64(data.Value),\n\t\t\t\t\t\tOnValueChanged: func() {\n\t\t\t\t\t\t\tdata.Value = int(valueEdit.Value())\n\t\t\t\t\t\t\tslh.SetValue(data.Value)\n\t\t\t\t\t\t\tslv.SetValue(data.Value)\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tNumberEdit{\n\t\t\t\t\t\tAssignTo: &maxEdit,\n\t\t\t\t\t\tValue:    float64(data.Max),\n\t\t\t\t\t\tOnValueChanged: func() {\n\t\t\t\t\t\t\tdata.Max = int(maxEdit.Value())\n\t\t\t\t\t\t\tslh.SetRange(data.Min, data.Max)\n\t\t\t\t\t\t\tslv.SetRange(data.Min, data.Max)\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tSlider{\n\t\t\t\t\t\tColumnSpan: 3,\n\t\t\t\t\t\tAssignTo:   &slh,\n\t\t\t\t\t\tMinValue:   data.Min,\n\t\t\t\t\t\tMaxValue:   data.Max,\n\t\t\t\t\t\tValue:      data.Value,\n\t\t\t\t\t\tOnValueChanged: func() {\n\t\t\t\t\t\t\tdata.Value = slh.Value()\n\t\t\t\t\t\t\tvalueEdit.SetValue(float64(data.Value))\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tVSpacer{},\n\t\t\t\t\tPushButton{\n\t\t\t\t\t\tColumnSpan: 3,\n\t\t\t\t\t\tText:       \"Print state\",\n\t\t\t\t\t\tOnClicked: func() {\n\t\t\t\t\t\t\tlog.Printf(\"H: < %d | %d | %d >\\n\", slh.MinValue(), slh.Value(), slh.MaxValue())\n\t\t\t\t\t\t\tlog.Printf(\"V: < %d | %d | %d >\\n\", slv.MinValue(), slv.Value(), slv.MaxValue())\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}.Run()\n}\n"
  },
  {
    "path": "examples/statusbar/statusbar.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/statusbar/statusbar.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// This example demonstrates the status bar, including a size gripper\n// attached to the bottom of the main window.\n// The status bar has two items, one is dynamically updated and one includes an icon.\npackage main\n\nimport (\n\t\"log\"\n\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\ticon1, err := walk.NewIconFromFile(\"../img/check.ico\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\ticon2, err := walk.NewIconFromFile(\"../img/stop.ico\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tvar sbi *walk.StatusBarItem\n\n\tMainWindow{\n\t\tTitle:   \"Walk Statusbar Example\",\n\t\tMinSize: Size{600, 200},\n\t\tLayout:  VBox{MarginsZero: true},\n\t\tStatusBarItems: []StatusBarItem{\n\t\t\tStatusBarItem{\n\t\t\t\tAssignTo: &sbi,\n\t\t\t\tIcon:     icon1,\n\t\t\t\tText:     \"click\",\n\t\t\t\tWidth:    80,\n\t\t\t\tOnClicked: func() {\n\t\t\t\t\tif sbi.Text() == \"click\" {\n\t\t\t\t\t\tsbi.SetText(\"again\")\n\t\t\t\t\t\tsbi.SetIcon(icon2)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsbi.SetText(\"click\")\n\t\t\t\t\t\tsbi.SetIcon(icon1)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\tStatusBarItem{\n\t\t\t\tText:        \"left\",\n\t\t\t\tToolTipText: \"no tooltip for me\",\n\t\t\t},\n\t\t\tStatusBarItem{\n\t\t\t\tText: \"\\tcenter\",\n\t\t\t},\n\t\t\tStatusBarItem{\n\t\t\t\tText: \"\\t\\tright\",\n\t\t\t},\n\t\t\tStatusBarItem{\n\t\t\t\tIcon:        icon1,\n\t\t\t\tToolTipText: \"An icon with a tooltip\",\n\t\t\t},\n\t\t},\n\t}.Run()\n}\n"
  },
  {
    "path": "examples/tableview/tableview.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/tableview/tableview.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n)\n\nimport (\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\ntype Foo struct {\n\tIndex   int\n\tBar     string\n\tBaz     float64\n\tQuux    time.Time\n\tchecked bool\n}\n\ntype FooModel struct {\n\twalk.TableModelBase\n\twalk.SorterBase\n\tsortColumn int\n\tsortOrder  walk.SortOrder\n\titems      []*Foo\n}\n\nfunc NewFooModel() *FooModel {\n\tm := new(FooModel)\n\tm.ResetRows()\n\treturn m\n}\n\n// Called by the TableView from SetModel and every time the model publishes a\n// RowsReset event.\nfunc (m *FooModel) RowCount() int {\n\treturn len(m.items)\n}\n\n// Called by the TableView when it needs the text to display for a given cell.\nfunc (m *FooModel) Value(row, col int) interface{} {\n\titem := m.items[row]\n\n\tswitch col {\n\tcase 0:\n\t\treturn item.Index\n\n\tcase 1:\n\t\treturn item.Bar\n\n\tcase 2:\n\t\treturn item.Baz\n\n\tcase 3:\n\t\treturn item.Quux\n\t}\n\n\tpanic(\"unexpected col\")\n}\n\n// Called by the TableView to retrieve if a given row is checked.\nfunc (m *FooModel) Checked(row int) bool {\n\treturn m.items[row].checked\n}\n\n// Called by the TableView when the user toggled the check box of a given row.\nfunc (m *FooModel) SetChecked(row int, checked bool) error {\n\tm.items[row].checked = checked\n\n\treturn nil\n}\n\n// Called by the TableView to sort the model.\nfunc (m *FooModel) Sort(col int, order walk.SortOrder) error {\n\tm.sortColumn, m.sortOrder = col, order\n\n\tsort.SliceStable(m.items, func(i, j int) bool {\n\t\ta, b := m.items[i], m.items[j]\n\n\t\tc := func(ls bool) bool {\n\t\t\tif m.sortOrder == walk.SortAscending {\n\t\t\t\treturn ls\n\t\t\t}\n\n\t\t\treturn !ls\n\t\t}\n\n\t\tswitch m.sortColumn {\n\t\tcase 0:\n\t\t\treturn c(a.Index < b.Index)\n\n\t\tcase 1:\n\t\t\treturn c(a.Bar < b.Bar)\n\n\t\tcase 2:\n\t\t\treturn c(a.Baz < b.Baz)\n\n\t\tcase 3:\n\t\t\treturn c(a.Quux.Before(b.Quux))\n\t\t}\n\n\t\tpanic(\"unreachable\")\n\t})\n\n\treturn m.SorterBase.Sort(col, order)\n}\n\nfunc (m *FooModel) ResetRows() {\n\t// Create some random data.\n\tm.items = make([]*Foo, rand.Intn(50000))\n\n\tnow := time.Now()\n\n\tfor i := range m.items {\n\t\tm.items[i] = &Foo{\n\t\t\tIndex: i,\n\t\t\tBar:   strings.Repeat(\"*\", rand.Intn(5)+1),\n\t\t\tBaz:   rand.Float64() * 1000,\n\t\t\tQuux:  time.Unix(rand.Int63n(now.Unix()), 0),\n\t\t}\n\t}\n\n\t// Notify TableView and other interested parties about the reset.\n\tm.PublishRowsReset()\n\n\tm.Sort(m.sortColumn, m.sortOrder)\n}\n\nfunc main() {\n\trand.Seed(time.Now().UnixNano())\n\n\tboldFont, _ := walk.NewFont(\"Segoe UI\", 9, walk.FontBold)\n\tgoodIcon, _ := walk.Resources.Icon(\"../img/check.ico\")\n\tbadIcon, _ := walk.Resources.Icon(\"../img/stop.ico\")\n\n\tbarBitmap, err := walk.NewBitmap(walk.Size{100, 1})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer barBitmap.Dispose()\n\n\tcanvas, err := walk.NewCanvasFromImage(barBitmap)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer barBitmap.Dispose()\n\n\tcanvas.GradientFillRectangle(walk.RGB(255, 0, 0), walk.RGB(0, 255, 0), walk.Horizontal, walk.Rectangle{0, 0, 100, 1})\n\n\tcanvas.Dispose()\n\n\tmodel := NewFooModel()\n\n\tvar tv *walk.TableView\n\n\tMainWindow{\n\t\tTitle:  \"Walk TableView Example\",\n\t\tSize:   Size{800, 600},\n\t\tLayout: VBox{MarginsZero: true},\n\t\tChildren: []Widget{\n\t\t\tPushButton{\n\t\t\t\tText:      \"Reset Rows\",\n\t\t\t\tOnClicked: model.ResetRows,\n\t\t\t},\n\t\t\tPushButton{\n\t\t\t\tText: \"Select first 5 even Rows\",\n\t\t\t\tOnClicked: func() {\n\t\t\t\t\ttv.SetSelectedIndexes([]int{0, 2, 4, 6, 8})\n\t\t\t\t},\n\t\t\t},\n\t\t\tTableView{\n\t\t\t\tAssignTo:         &tv,\n\t\t\t\tAlternatingRowBG: true,\n\t\t\t\tCheckBoxes:       true,\n\t\t\t\tColumnsOrderable: true,\n\t\t\t\tMultiSelection:   true,\n\t\t\t\tColumns: []TableViewColumn{\n\t\t\t\t\t{Title: \"#\"},\n\t\t\t\t\t{Title: \"Bar\"},\n\t\t\t\t\t{Title: \"Baz\", Alignment: AlignFar},\n\t\t\t\t\t{Title: \"Quux\", Format: \"2006-01-02 15:04:05\", Width: 150},\n\t\t\t\t},\n\t\t\t\tStyleCell: func(style *walk.CellStyle) {\n\t\t\t\t\titem := model.items[style.Row()]\n\n\t\t\t\t\tif item.checked {\n\t\t\t\t\t\tif style.Row()%2 == 0 {\n\t\t\t\t\t\t\tstyle.BackgroundColor = walk.RGB(159, 215, 255)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tstyle.BackgroundColor = walk.RGB(143, 199, 239)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch style.Col() {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tif canvas := style.Canvas(); canvas != nil {\n\t\t\t\t\t\t\tbounds := style.Bounds()\n\t\t\t\t\t\t\tbounds.X += 2\n\t\t\t\t\t\t\tbounds.Y += 2\n\t\t\t\t\t\t\tbounds.Width = int((float64(bounds.Width) - 4) / 5 * float64(len(item.Bar)))\n\t\t\t\t\t\t\tbounds.Height -= 4\n\t\t\t\t\t\t\tcanvas.DrawBitmapPartWithOpacity(barBitmap, bounds, walk.Rectangle{0, 0, 100 / 5 * len(item.Bar), 1}, 127)\n\n\t\t\t\t\t\t\tbounds.X += 4\n\t\t\t\t\t\t\tbounds.Y += 2\n\t\t\t\t\t\t\tcanvas.DrawText(item.Bar, tv.Font(), 0, bounds, walk.TextLeft)\n\t\t\t\t\t\t}\n\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\tif item.Baz >= 900.0 {\n\t\t\t\t\t\t\tstyle.TextColor = walk.RGB(0, 191, 0)\n\t\t\t\t\t\t\tstyle.Image = goodIcon\n\t\t\t\t\t\t} else if item.Baz < 100.0 {\n\t\t\t\t\t\t\tstyle.TextColor = walk.RGB(255, 0, 0)\n\t\t\t\t\t\t\tstyle.Image = badIcon\n\t\t\t\t\t\t}\n\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\tif item.Quux.After(time.Now().Add(-365 * 24 * time.Hour)) {\n\t\t\t\t\t\t\tstyle.Font = boldFont\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tModel: model,\n\t\t\t\tOnSelectedIndexesChanged: func() {\n\t\t\t\t\tfmt.Printf(\"SelectedIndexes: %v\\n\", tv.SelectedIndexes())\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}.Run()\n}\n"
  },
  {
    "path": "examples/webview/webview.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/webview/webview.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"strings\"\n\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\nfunc main() {\n\tvar le *walk.LineEdit\n\tvar wv *walk.WebView\n\n\tMainWindow{\n\t\tIcon:    Bind(\"'../img/' + icon(wv.URL) + '.ico'\"),\n\t\tTitle:   \"Walk WebView Example'\",\n\t\tMinSize: Size{800, 600},\n\t\tLayout:  VBox{MarginsZero: true},\n\t\tChildren: []Widget{\n\t\t\tLineEdit{\n\t\t\t\tAssignTo: &le,\n\t\t\t\tText:     Bind(\"wv.URL\"),\n\t\t\t\tOnKeyDown: func(key walk.Key) {\n\t\t\t\t\tif key == walk.KeyReturn {\n\t\t\t\t\t\twv.SetURL(le.Text())\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\tWebView{\n\t\t\t\tAssignTo: &wv,\n\t\t\t\tName:     \"wv\",\n\t\t\t\tURL:      \"https://github.com/lxn/walk\",\n\t\t\t},\n\t\t},\n\t\tFunctions: map[string]func(args ...interface{}) (interface{}, error){\n\t\t\t\"icon\": func(args ...interface{}) (interface{}, error) {\n\t\t\t\tif strings.HasPrefix(args[0].(string), \"https\") {\n\t\t\t\t\treturn \"check\", nil\n\t\t\t\t}\n\n\t\t\t\treturn \"stop\", nil\n\t\t\t},\n\t\t},\n\t}.Run()\n}\n"
  },
  {
    "path": "examples/webview_events/webview_events.exe.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n\t<assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"*\" name=\"SomeFunkyNameHere\" type=\"win32\"/>\n\t<dependency>\n\t\t<dependentAssembly>\n\t\t\t<assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"*\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"/>\n\t\t</dependentAssembly>\n\t</dependency>\n\t<application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n\t\t<windowsSettings>\n\t\t\t<dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness>\n\t\t\t<dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True</dpiAware>\n\t\t</windowsSettings>\n\t</application>\n</assembly>\n"
  },
  {
    "path": "examples/webview_events/webview_events.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/lxn/walk\"\n\t. \"github.com/lxn/walk/declarative\"\n)\n\ntype MainWin struct {\n\t*walk.MainWindow\n\tle *walk.LineEdit\n\twv *walk.WebView\n}\n\nfunc main() {\n\tmainWin, err := NewMainWin()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tmainWin.Run()\n}\n\nfunc NewMainWin() (*MainWin, error) {\n\tmainWin := new(MainWin)\n\n\terr := MainWindow{\n\t\tAssignTo: &mainWin.MainWindow,\n\t\tIcon:     Bind(\"'../img/' + icon(mainWin.wv.URL) + '.ico'\"),\n\t\tTitle:    \"Walk WebView Example (With Events Printing)\",\n\t\tMinSize:  Size{800, 600},\n\t\tLayout:   VBox{MarginsZero: true},\n\t\tChildren: []Widget{\n\t\t\tLineEdit{\n\t\t\t\tAssignTo: &mainWin.le,\n\t\t\t\tText:     Bind(\"wv.URL\"),\n\t\t\t\tOnKeyDown: func(key walk.Key) {\n\t\t\t\t\tif key == walk.KeyReturn {\n\t\t\t\t\t\tmainWin.wv.SetURL(mainWin.le.Text())\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\tWebView{\n\t\t\t\tAssignTo:                  &mainWin.wv,\n\t\t\t\tName:                      \"wv\",\n\t\t\t\tURL:                       \"https://github.com/lxn/walk\",\n\t\t\t\tShortcutsEnabled:          true,\n\t\t\t\tNativeContextMenuEnabled:  true,\n\t\t\t\tOnNavigating:              mainWin.webView_OnNavigating,\n\t\t\t\tOnNavigated:               mainWin.webView_OnNavigated,\n\t\t\t\tOnDownloading:             mainWin.webView_OnDownloading,\n\t\t\t\tOnDownloaded:              mainWin.webView_OnDownloaded,\n\t\t\t\tOnDocumentCompleted:       mainWin.webView_OnDocumentCompleted,\n\t\t\t\tOnNavigatedError:          mainWin.webView_OnNavigatedError,\n\t\t\t\tOnNewWindow:               mainWin.webView_OnNewWindow,\n\t\t\t\tOnQuitting:                mainWin.webView_OnQuitting,\n\t\t\t\tOnWindowClosing:           mainWin.webView_OnWindowClosing,\n\t\t\t\tOnStatusBarVisibleChanged: mainWin.webView_OnStatusBarVisibleChanged,\n\t\t\t\tOnTheaterModeChanged:      mainWin.webView_OnTheaterModeChanged,\n\t\t\t\tOnToolBarVisibleChanged:   mainWin.webView_OnToolBarVisibleChanged,\n\t\t\t\tOnBrowserVisibleChanged:   mainWin.webView_OnBrowserVisibleChanged,\n\t\t\t\tOnCanGoBackChanged:        mainWin.webView_OnCanGoBackChanged,\n\t\t\t\tOnCanGoForwardChanged:     mainWin.webView_OnCanGoForwardChanged,\n\t\t\t\tOnToolBarEnabledChanged:   mainWin.webView_OnToolBarEnabledChanged,\n\t\t\t\tOnProgressChanged:         mainWin.webView_OnProgressChanged,\n\t\t\t\tOnStatusTextChanged:       mainWin.webView_OnStatusTextChanged,\n\t\t\t\tOnDocumentTitleChanged:    mainWin.webView_OnDocumentTitleChanged,\n\t\t\t},\n\t\t},\n\t\tFunctions: map[string]func(args ...interface{}) (interface{}, error){\n\t\t\t\"icon\": func(args ...interface{}) (interface{}, error) {\n\t\t\t\tif strings.HasPrefix(args[0].(string), \"https\") {\n\t\t\t\t\treturn \"check\", nil\n\t\t\t\t}\n\n\t\t\t\treturn \"stop\", nil\n\t\t\t},\n\t\t},\n\t}.Create()\n\n\treturn mainWin, err\n}\n\nfunc (mainWin *MainWin) webView_OnNavigating(eventData *walk.WebViewNavigatingEventData) {\n\tfmt.Printf(\"webView_OnNavigating\\r\\n\")\n\tfmt.Printf(\"Url = %+v\\r\\n\", eventData.Url())\n\tfmt.Printf(\"Flags = %+v\\r\\n\", eventData.Flags())\n\tfmt.Printf(\"PostData = %+v\\r\\n\", eventData.PostData())\n\tfmt.Printf(\"Headers = %+v\\r\\n\", eventData.Headers())\n\tfmt.Printf(\"TargetFrameName = %+v\\r\\n\", eventData.TargetFrameName())\n\tfmt.Printf(\"Canceled = %+v\\r\\n\", eventData.Canceled())\n\t// if you want to cancel\n\t//eventData.SetCanceled(true)\n}\n\nfunc (mainWin *MainWin) webView_OnNavigated(url string) {\n\tfmt.Printf(\"webView_OnNavigated\\r\\n\")\n\tfmt.Printf(\"url = %+v\\r\\n\", url)\n}\n\nfunc (mainWin *MainWin) webView_OnDownloading() {\n\tfmt.Printf(\"webView_OnDownloading\\r\\n\")\n}\n\nfunc (mainWin *MainWin) webView_OnDownloaded() {\n\tfmt.Printf(\"webView_OnDownloaded\\r\\n\")\n}\n\nfunc (mainWin *MainWin) webView_OnDocumentCompleted(url string) {\n\tfmt.Printf(\"webView_OnDocumentCompleted\\r\\n\")\n\tfmt.Printf(\"url = %+v\\r\\n\", url)\n}\n\nfunc (mainWin *MainWin) webView_OnNavigatedError(eventData *walk.WebViewNavigatedErrorEventData) {\n\tfmt.Printf(\"webView_OnNavigatedError\\r\\n\")\n\tfmt.Printf(\"Url = %+v\\r\\n\", eventData.Url())\n\tfmt.Printf(\"TargetFrameName = %+v\\r\\n\", eventData.TargetFrameName())\n\tfmt.Printf(\"StatusCode = %+v\\r\\n\", eventData.StatusCode())\n\tfmt.Printf(\"Canceled = %+v\\r\\n\", eventData.Canceled())\n\t// if you want to cancel\n\t//eventData.SetCanceled(true)\n}\n\nfunc (mainWin *MainWin) webView_OnNewWindow(eventData *walk.WebViewNewWindowEventData) {\n\tfmt.Printf(\"webView_OnNewWindow\\r\\n\")\n\tfmt.Printf(\"Canceled = %+v\\r\\n\", eventData.Canceled())\n\tfmt.Printf(\"Flags = %+v\\r\\n\", eventData.Flags())\n\tfmt.Printf(\"UrlContext = %+v\\r\\n\", eventData.UrlContext())\n\tfmt.Printf(\"Url = %+v\\r\\n\", eventData.Url())\n\t// if you want to cancel\n\t//eventData.SetCancel(true)\n}\n\nfunc (mainWin *MainWin) webView_OnQuitting() {\n\tfmt.Printf(\"webView_OnQuitting\\r\\n\")\n}\n\nfunc (mainWin *MainWin) webView_OnWindowClosing(eventData *walk.WebViewWindowClosingEventData) {\n\tfmt.Printf(\"webView_OnWindowClosing\\r\\n\")\n\tfmt.Printf(\"IsChildWindow = %+v\\r\\n\", eventData.IsChildWindow())\n\tfmt.Printf(\"Canceled = %+v\\r\\n\", eventData.Canceled())\n\t// if you want to cancel\n\t//eventData.SetCancel(true)\n}\n\nfunc (mainWin *MainWin) webView_OnStatusBarVisibleChanged() {\n\tfmt.Printf(\"webView_OnStatusBarVisibleChanged\\r\\n\")\n\tfmt.Printf(\"StatusBarVisible = %+v\\r\\n\", mainWin.wv.StatusBarVisible())\n}\n\nfunc (mainWin *MainWin) webView_OnTheaterModeChanged() {\n\tfmt.Printf(\"webView_OnTheaterModeChanged\\r\\n\")\n\tfmt.Printf(\"IsTheaterMode = %+v\\r\\n\", mainWin.wv.IsTheaterMode())\n}\n\nfunc (mainWin *MainWin) webView_OnToolBarVisibleChanged() {\n\tfmt.Printf(\"webView_OnToolBarVisibleChanged\\r\\n\")\n\tfmt.Printf(\"ToolBarVisible = %+v\\r\\n\", mainWin.wv.ToolBarVisible())\n}\n\nfunc (mainWin *MainWin) webView_OnBrowserVisibleChanged() {\n\tfmt.Printf(\"webView_OnBrowserVisibleChanged\\r\\n\")\n\tfmt.Printf(\"BrowserVisible = %+v\\r\\n\", mainWin.wv.BrowserVisible())\n}\n\nfunc (mainWin *MainWin) webView_OnCanGoBackChanged() {\n\tfmt.Printf(\"webView_OnCanGoBackChanged\\r\\n\")\n\tfmt.Printf(\"CanGoBack = %+v\\r\\n\", mainWin.wv.CanGoBack())\n}\n\nfunc (mainWin *MainWin) webView_OnCanGoForwardChanged() {\n\tfmt.Printf(\"webView_OnCanGoForwardChanged\\r\\n\")\n\tfmt.Printf(\"CanGoForward = %+v\\r\\n\", mainWin.wv.CanGoForward())\n}\n\nfunc (mainWin *MainWin) webView_OnToolBarEnabledChanged() {\n\tfmt.Printf(\"webView_OnToolBarEnabledChanged\\r\\n\")\n\tfmt.Printf(\"ToolBarEnabled = %+v\\r\\n\", mainWin.wv.ToolBarEnabled())\n}\n\nfunc (mainWin *MainWin) webView_OnProgressChanged() {\n\tfmt.Printf(\"webView_OnProgressChanged\\r\\n\")\n\tfmt.Printf(\"ProgressValue = %+v\\r\\n\", mainWin.wv.ProgressValue())\n\tfmt.Printf(\"ProgressMax = %+v\\r\\n\", mainWin.wv.ProgressMax())\n}\n\nfunc (mainWin *MainWin) webView_OnStatusTextChanged() {\n\tfmt.Printf(\"webView_OnStatusTextChanged\\r\\n\")\n\tfmt.Printf(\"StatusText = %+v\\r\\n\", mainWin.wv.StatusText())\n}\n\nfunc (mainWin *MainWin) webView_OnDocumentTitleChanged() {\n\tfmt.Printf(\"webView_OnDocumentTitleChanged\\r\\n\")\n\tfmt.Printf(\"DocumentTitle = %+v\\r\\n\", mainWin.wv.DocumentTitle())\n}\n"
  },
  {
    "path": "expression.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"log\"\n\t\"reflect\"\n)\n\nimport _ \"gopkg.in/Knetic/govaluate.v3\"\n\ntype Expression interface {\n\tValue() interface{}\n\tChanged() *Event\n}\n\ntype reflectExpression struct {\n\troot Expression\n\tpath string\n}\n\nfunc NewReflectExpression(root Expression, path string) Expression {\n\treturn &reflectExpression{root: root, path: path}\n}\n\nfunc (re *reflectExpression) Value() interface{} {\n\trootVal := re.root.Value()\n\tif rootVal == nil {\n\t\treturn nil\n\t}\n\n\t_, val, err := reflectValueFromPath(reflect.ValueOf(rootVal), re.path)\n\tif err != nil {\n\t\tlog.Print(\"walk - reflectExpression.Value - Error: \", err.Error())\n\t}\n\n\tif !val.IsValid() {\n\t\treturn nil\n\t}\n\n\treturn val.Interface()\n}\n\nfunc (re *reflectExpression) Changed() *Event {\n\treturn re.root.Changed()\n}\n"
  },
  {
    "path": "flowlayout.go",
    "content": "// Copyright 2018 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype FlowLayout struct {\n\tLayoutBase\n\thwnd2StretchFactor map[win.HWND]int\n}\n\nfunc NewFlowLayout() *FlowLayout {\n\tl := &FlowLayout{\n\t\tLayoutBase: LayoutBase{\n\t\t\tmargins96dpi: Margins{9, 9, 9, 9},\n\t\t\tspacing96dpi: 6,\n\t\t},\n\t\thwnd2StretchFactor: make(map[win.HWND]int),\n\t}\n\tl.layout = l\n\n\treturn l\n}\n\nfunc (l *FlowLayout) StretchFactor(widget Widget) int {\n\tif factor, ok := l.hwnd2StretchFactor[widget.Handle()]; ok {\n\t\treturn factor\n\t}\n\n\treturn 1\n}\n\nfunc (l *FlowLayout) SetStretchFactor(widget Widget, factor int) error {\n\tif factor != l.StretchFactor(widget) {\n\t\tif l.container == nil {\n\t\t\treturn newError(\"container required\")\n\t\t}\n\n\t\thandle := widget.Handle()\n\n\t\tif !l.container.Children().containsHandle(handle) {\n\t\t\treturn newError(\"unknown widget\")\n\t\t}\n\t\tif factor < 1 {\n\t\t\treturn newError(\"factor must be >= 1\")\n\t\t}\n\n\t\tl.hwnd2StretchFactor[handle] = factor\n\n\t\tl.container.RequestLayout()\n\t}\n\n\treturn nil\n}\n\nfunc (l *FlowLayout) CreateLayoutItem(ctx *LayoutContext) ContainerLayoutItem {\n\tli := &flowLayoutItem{\n\t\tsize2MinSize:       make(map[Size]Size),\n\t\thwnd2StretchFactor: make(map[win.HWND]int),\n\t}\n\n\tfor hwnd, sf := range l.hwnd2StretchFactor {\n\t\tli.hwnd2StretchFactor[hwnd] = sf\n\t}\n\n\treturn li\n}\n\ntype flowLayoutItem struct {\n\tContainerLayoutItemBase\n\tsize2MinSize       map[Size]Size // in native pixels\n\thwnd2StretchFactor map[win.HWND]int\n}\n\ntype flowLayoutSection struct {\n\titems            []flowLayoutSectionItem\n\tprimarySpaceLeft int // in native pixels\n\tsecondaryMinSize int // in native pixels\n}\n\ntype flowLayoutSectionItem struct {\n\titem    LayoutItem\n\tminSize Size // in native pixels\n}\n\nfunc (*flowLayoutItem) LayoutFlags() LayoutFlags {\n\treturn ShrinkableHorz | ShrinkableVert | GrowableHorz | GrowableVert | GreedyHorz | GreedyVert\n}\n\nfunc (li *flowLayoutItem) MinSize() Size {\n\treturn li.MinSizeForSize(li.geometry.ClientSize)\n}\n\nfunc (li *flowLayoutItem) HeightForWidth(width int) int {\n\treturn li.MinSizeForSize(Size{width, li.geometry.ClientSize.Height}).Height\n}\n\nfunc (li *flowLayoutItem) MinSizeForSize(size Size) Size {\n\tif min, ok := li.size2MinSize[size]; ok {\n\t\treturn min\n\t}\n\n\tspacing := IntFrom96DPI(li.spacing96dpi, li.ctx.dpi)\n\tmargins := MarginsFrom96DPI(li.margins96dpi, li.ctx.dpi)\n\n\tbounds := Rectangle{Width: size.Width}\n\n\tsections := li.sectionsForPrimarySize(size.Width)\n\n\tvar s Size\n\tvar maxPrimary int\n\n\tfor i, section := range sections {\n\t\tvar items []LayoutItem\n\t\tvar sectionMinWidth int\n\t\tfor _, sectionItem := range section.items {\n\t\t\titems = append(items, sectionItem.item)\n\n\t\t\tsectionMinWidth += sectionItem.minSize.Width\n\t\t}\n\t\tsectionMinWidth += (len(section.items) - 1) * spacing\n\t\tmaxPrimary = maxi(maxPrimary, sectionMinWidth)\n\n\t\tbounds.Height = section.secondaryMinSize\n\n\t\tmargins96dpi := li.margins96dpi\n\t\tif i > 0 {\n\t\t\tmargins96dpi.VNear = 0\n\t\t}\n\t\tif i < len(sections)-1 {\n\t\t\tmargins96dpi.VFar = 0\n\t\t}\n\n\t\tlayoutItems := boxLayoutItems(li, items, Horizontal, li.alignment, bounds, margins96dpi, li.spacing96dpi, li.hwnd2StretchFactor)\n\n\t\tvar maxSecondary int\n\n\t\tfor _, item := range layoutItems {\n\t\t\tif hfw, ok := item.Item.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\t\t\titem.Bounds.Height = hfw.HeightForWidth(item.Bounds.Width)\n\t\t\t} else {\n\t\t\t\tmin := li.MinSizeEffectiveForChild(item.Item)\n\t\t\t\titem.Bounds.Height = min.Height\n\t\t\t}\n\n\t\t\tmaxSecondary = maxi(maxSecondary, item.Bounds.Height)\n\t\t}\n\n\t\ts.Height += maxSecondary\n\n\t\tbounds.Y += maxSecondary + spacing\n\t}\n\n\ts.Width = maxPrimary\n\n\ts.Width += margins.HNear + margins.HFar\n\ts.Height += margins.VNear + margins.VFar + (len(sections)-1)*spacing\n\n\tif s.Width > 0 && s.Height > 0 {\n\t\tli.size2MinSize[size] = s\n\t}\n\n\treturn s\n}\n\nfunc (li *flowLayoutItem) PerformLayout() []LayoutResultItem {\n\tspacing := IntFrom96DPI(li.spacing96dpi, li.ctx.dpi)\n\tbounds := Rectangle{Width: li.geometry.ClientSize.Width, Height: li.geometry.ClientSize.Height}\n\n\tsections := li.sectionsForPrimarySize(bounds.Width)\n\n\tvar resultItems []LayoutResultItem\n\n\tfor i, section := range sections {\n\t\tvar items []LayoutItem\n\t\tfor _, sectionItem := range section.items {\n\t\t\titems = append(items, sectionItem.item)\n\t\t}\n\n\t\tbounds.Height = section.secondaryMinSize\n\n\t\tmargins96dpi := li.margins96dpi\n\t\tif i > 0 {\n\t\t\tmargins96dpi.VNear = 0\n\t\t}\n\t\tif i < len(sections)-1 {\n\t\t\tmargins96dpi.VFar = 0\n\t\t}\n\n\t\tlayoutItems := boxLayoutItems(li, items, Horizontal, li.alignment, bounds, margins96dpi, li.spacing96dpi, li.hwnd2StretchFactor)\n\n\t\tmargins := MarginsFrom96DPI(margins96dpi, li.ctx.dpi)\n\n\t\tvar maxSecondary int\n\n\t\tfor _, item := range layoutItems {\n\t\t\tif hfw, ok := item.Item.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\t\t\titem.Bounds.Height = hfw.HeightForWidth(item.Bounds.Width)\n\t\t\t} else {\n\t\t\t\titem.Bounds.Height = li.MinSizeEffectiveForChild(item.Item).Height\n\t\t\t}\n\n\t\t\tmaxSecondary = maxi(maxSecondary, item.Bounds.Height)\n\t\t}\n\n\t\tbounds.Height = maxSecondary + margins.VNear + margins.VFar\n\n\t\tresultItems = append(resultItems, boxLayoutItems(li, items, Horizontal, li.alignment, bounds, margins96dpi, li.spacing96dpi, li.hwnd2StretchFactor)...)\n\n\t\tbounds.Y += bounds.Height + spacing\n\t}\n\n\treturn resultItems\n}\n\n// sectionsForPrimarySize calculates sections for primary width in native pixels.\nfunc (li *flowLayoutItem) sectionsForPrimarySize(primarySize int) []flowLayoutSection {\n\tmargins := MarginsFrom96DPI(li.margins96dpi, li.ctx.dpi)\n\tspacing := IntFrom96DPI(li.spacing96dpi, li.ctx.dpi)\n\n\tvar sections []flowLayoutSection\n\n\tsection := flowLayoutSection{\n\t\tprimarySpaceLeft: primarySize - margins.HNear - margins.HFar,\n\t}\n\n\taddSection := func() {\n\t\tsections = append(sections, section)\n\t\tsection.items = nil\n\t\tsection.primarySpaceLeft = primarySize - margins.HNear - margins.HFar\n\t\tsection.secondaryMinSize = 0\n\t}\n\n\tfor _, item := range li.children {\n\t\tvar sectionItem flowLayoutSectionItem\n\n\t\tsectionItem.item = item\n\n\t\tif !shouldLayoutItem(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\tsectionItem.minSize = li.MinSizeEffectiveForChild(item)\n\n\t\taddItem := func() {\n\t\t\tsection.items = append(section.items, sectionItem)\n\t\t\tif len(section.items) > 1 {\n\t\t\t\tsection.primarySpaceLeft -= spacing\n\t\t\t}\n\t\t\tsection.primarySpaceLeft -= sectionItem.minSize.Width\n\n\t\t\tsection.secondaryMinSize = maxi(section.secondaryMinSize, sectionItem.minSize.Height)\n\t\t}\n\n\t\tif section.primarySpaceLeft < sectionItem.minSize.Width && len(section.items) == 0 {\n\t\t\taddItem()\n\t\t\taddSection()\n\t\t} else if section.primarySpaceLeft < spacing+sectionItem.minSize.Width && len(section.items) > 0 {\n\t\t\taddSection()\n\t\t\taddItem()\n\t\t} else {\n\t\t\taddItem()\n\t\t}\n\t}\n\n\tif len(section.items) > 0 {\n\t\taddSection()\n\t}\n\n\tif len(sections) > 0 {\n\t\tsections[0].secondaryMinSize += margins.VNear\n\t\tsections[len(sections)-1].secondaryMinSize += margins.VFar\n\t}\n\n\treturn sections\n}\n"
  },
  {
    "path": "font.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype FontStyle byte\n\n// Font style flags\nconst (\n\tFontBold      FontStyle = 0x01\n\tFontItalic    FontStyle = 0x02\n\tFontUnderline FontStyle = 0x04\n\tFontStrikeOut FontStyle = 0x08\n)\n\nvar (\n\tdefaultFont *Font\n\tknownFonts  = make(map[fontInfo]*Font)\n)\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\t// Initialize default font\n\t\tvar err error\n\t\tif defaultFont, err = NewFont(\"MS Shell Dlg 2\", 8, 0); err != nil {\n\t\t\tpanic(\"failed to create default font\")\n\t\t}\n\t})\n}\n\ntype fontInfo struct {\n\tfamily    string\n\tpointSize int\n\tstyle     FontStyle\n}\n\n// Font represents a typographic typeface that is used for text drawing\n// operations and on many GUI widgets.\ntype Font struct {\n\tdpi2hFont map[int]win.HFONT\n\tfamily    string\n\tpointSize int\n\tstyle     FontStyle\n}\n\n// NewFont returns a new Font with the specified attributes.\nfunc NewFont(family string, pointSize int, style FontStyle) (*Font, error) {\n\tif style > FontBold|FontItalic|FontUnderline|FontStrikeOut {\n\t\treturn nil, newError(\"invalid style\")\n\t}\n\n\tfi := fontInfo{\n\t\tfamily:    family,\n\t\tpointSize: pointSize,\n\t\tstyle:     style,\n\t}\n\n\tif font, ok := knownFonts[fi]; ok {\n\t\treturn font, nil\n\t}\n\n\tfont := &Font{\n\t\tfamily:    family,\n\t\tpointSize: pointSize,\n\t\tstyle:     style,\n\t}\n\n\tknownFonts[fi] = font\n\n\treturn font, nil\n}\n\nfunc newFontFromLOGFONT(lf *win.LOGFONT, dpi int) (*Font, error) {\n\tif lf == nil {\n\t\treturn nil, newError(\"lf cannot be nil\")\n\t}\n\n\tfamily := win.UTF16PtrToString(&lf.LfFaceName[0])\n\tpointSize := int(win.MulDiv(lf.LfHeight, 72, int32(dpi)))\n\tif pointSize < 0 {\n\t\tpointSize = -pointSize\n\t}\n\n\tvar style FontStyle\n\tif lf.LfWeight > win.FW_NORMAL {\n\t\tstyle |= FontBold\n\t}\n\tif lf.LfItalic == win.TRUE {\n\t\tstyle |= FontItalic\n\t}\n\tif lf.LfUnderline == win.TRUE {\n\t\tstyle |= FontUnderline\n\t}\n\tif lf.LfStrikeOut == win.TRUE {\n\t\tstyle |= FontStrikeOut\n\t}\n\n\treturn NewFont(family, pointSize, style)\n}\n\nfunc (f *Font) createForDPI(dpi int) (win.HFONT, error) {\n\tvar lf win.LOGFONT\n\n\tlf.LfHeight = -win.MulDiv(int32(f.pointSize), int32(dpi), 72)\n\tif f.style&FontBold > 0 {\n\t\tlf.LfWeight = win.FW_BOLD\n\t} else {\n\t\tlf.LfWeight = win.FW_NORMAL\n\t}\n\tif f.style&FontItalic > 0 {\n\t\tlf.LfItalic = 1\n\t}\n\tif f.style&FontUnderline > 0 {\n\t\tlf.LfUnderline = 1\n\t}\n\tif f.style&FontStrikeOut > 0 {\n\t\tlf.LfStrikeOut = 1\n\t}\n\tlf.LfCharSet = win.DEFAULT_CHARSET\n\tlf.LfOutPrecision = win.OUT_TT_PRECIS\n\tlf.LfClipPrecision = win.CLIP_DEFAULT_PRECIS\n\tlf.LfQuality = win.CLEARTYPE_QUALITY\n\tlf.LfPitchAndFamily = win.VARIABLE_PITCH | win.FF_SWISS\n\n\tsrc := syscall.StringToUTF16(f.family)\n\tdest := lf.LfFaceName[:]\n\tcopy(dest, src)\n\n\thFont := win.CreateFontIndirect(&lf)\n\tif hFont == 0 {\n\t\treturn 0, newError(\"CreateFontIndirect failed\")\n\t}\n\n\treturn hFont, nil\n}\n\n// Bold returns if text drawn using the Font appears with\n// greater weight than normal.\nfunc (f *Font) Bold() bool {\n\treturn f.style&FontBold > 0\n}\n\n// Dispose releases the os resources that were allocated for the Font.\n//\n// The Font can no longer be used for drawing operations or with GUI widgets\n// after calling this method. It is safe to call Dispose multiple times.\nfunc (f *Font) Dispose() {\n\tif len(f.dpi2hFont) == 0 {\n\t\treturn\n\t}\n\n\tfor dpi, hFont := range f.dpi2hFont {\n\t\twin.DeleteObject(win.HGDIOBJ(hFont))\n\t\tdelete(f.dpi2hFont, dpi)\n\t}\n}\n\n// Family returns the family name of the Font.\nfunc (f *Font) Family() string {\n\treturn f.family\n}\n\n// Italic returns if text drawn using the Font appears slanted.\nfunc (f *Font) Italic() bool {\n\treturn f.style&FontItalic > 0\n}\n\n// HandleForDPI returns the os resource handle of the font for the specified\n// DPI value.\nfunc (f *Font) handleForDPI(dpi int) win.HFONT {\n\tif f.dpi2hFont == nil {\n\t\tf.dpi2hFont = make(map[int]win.HFONT)\n\t} else if handle, ok := f.dpi2hFont[dpi]; ok {\n\t\treturn handle\n\t}\n\n\thFont, err := f.createForDPI(dpi)\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\tf.dpi2hFont[dpi] = hFont\n\n\treturn hFont\n}\n\n// StrikeOut returns if text drawn using the Font appears striked out.\nfunc (f *Font) StrikeOut() bool {\n\treturn f.style&FontStrikeOut > 0\n}\n\n// Style returns the combination of style flags of the Font.\nfunc (f *Font) Style() FontStyle {\n\treturn f.style\n}\n\n// Underline returns if text drawn using the font appears underlined.\nfunc (f *Font) Underline() bool {\n\treturn f.style&FontUnderline > 0\n}\n\n// PointSize returns the size of the Font in point units.\nfunc (f *Font) PointSize() int {\n\treturn f.pointSize\n}\n\nfunc screenDPI() int {\n\thDC := win.GetDC(0)\n\tdefer win.ReleaseDC(0, hDC)\n\treturn int(win.GetDeviceCaps(hDC, win.LOGPIXELSY))\n}\n"
  },
  {
    "path": "fontresource.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n\t\"syscall\"\n)\n\n// FontMemResource represents a font resource loaded into memory from\n// the application's resources.\ntype FontMemResource struct {\n\thFontResource win.HANDLE\n}\n\nfunc newFontMemResource(resourceName *uint16) (*FontMemResource, error) {\n\thModule := win.HMODULE(win.GetModuleHandle(nil))\n\tif hModule == win.HMODULE(0) {\n\t\treturn nil, lastError(\"GetModuleHandle\")\n\t}\n\n\thres := win.FindResource(hModule, resourceName, win.MAKEINTRESOURCE(8) /*RT_FONT*/)\n\tif hres == win.HRSRC(0) {\n\t\treturn nil, lastError(\"FindResource\")\n\t}\n\n\tsize := win.SizeofResource(hModule, hres)\n\tif size == 0 {\n\t\treturn nil, lastError(\"SizeofResource\")\n\t}\n\n\thResLoad := win.LoadResource(hModule, hres)\n\tif hResLoad == win.HGLOBAL(0) {\n\t\treturn nil, lastError(\"LoadResource\")\n\t}\n\n\tptr := win.LockResource(hResLoad)\n\tif ptr == 0 {\n\t\treturn nil, lastError(\"LockResource\")\n\t}\n\n\tnumFonts := uint32(0)\n\thFontResource := win.AddFontMemResourceEx(ptr, size, nil, &numFonts)\n\n\tif hFontResource == win.HANDLE(0) || numFonts == 0 {\n\t\treturn nil, lastError(\"AddFontMemResource\")\n\t}\n\n\treturn &FontMemResource{hFontResource: hFontResource}, nil\n}\n\n// NewFontMemResourceByName function loads a font resource from the executable's resources\n// using the resource name.\n// The font must be embedded into resources using corresponding operator in the\n// application's RC script.\nfunc NewFontMemResourceByName(name string) (*FontMemResource, error) {\n\tlpstr, err := syscall.UTF16PtrFromString(name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn newFontMemResource(lpstr)\n}\n\n// NewFontMemResourceById function loads a font resource from the executable's resources\n// using the resource ID.\n// The font must be embedded into resources using corresponding operator in the\n// application's RC script.\nfunc NewFontMemResourceById(id int) (*FontMemResource, error) {\n\treturn newFontMemResource(win.MAKEINTRESOURCE(uintptr(id)))\n}\n\n// Dispose removes the font resource from memory\nfunc (fmr *FontMemResource) Dispose() {\n\tif fmr.hFontResource != 0 {\n\t\twin.RemoveFontMemResourceEx(fmr.hFontResource)\n\t\tfmr.hFontResource = 0\n\t}\n}\n"
  },
  {
    "path": "form.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype CloseReason byte\n\nconst (\n\tCloseReasonUnknown CloseReason = iota\n\tCloseReasonUser\n)\n\nvar (\n\tsyncFuncs struct {\n\t\tm     sync.Mutex\n\t\tfuncs []func()\n\t}\n\n\tsyncMsgId                 uint32\n\ttaskbarButtonCreatedMsgId uint32\n\ttaskbarCreatedMsgId       uint32\n)\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tsyncMsgId = win.RegisterWindowMessage(syscall.StringToUTF16Ptr(\"WalkSync\"))\n\t\ttaskbarButtonCreatedMsgId = win.RegisterWindowMessage(syscall.StringToUTF16Ptr(\"TaskbarButtonCreated\"))\n\t\ttaskbarCreatedMsgId = win.RegisterWindowMessage(syscall.StringToUTF16Ptr(\"TaskbarCreated\"))\n\t})\n}\n\ntype Form interface {\n\tContainer\n\tAsFormBase() *FormBase\n\tRun() int\n\tStarting() *Event\n\tClosing() *CloseEvent\n\tActivating() *Event\n\tDeactivating() *Event\n\tActivate() error\n\tShow()\n\tHide()\n\tTitle() string\n\tSetTitle(title string) error\n\tTitleChanged() *Event\n\tIcon() Image\n\tSetIcon(icon Image) error\n\tIconChanged() *Event\n\tOwner() Form\n\tSetOwner(owner Form) error\n\tProgressIndicator() *ProgressIndicator\n\n\t// RightToLeftLayout returns whether coordinates on the x axis of the\n\t// Form increase from right to left.\n\tRightToLeftLayout() bool\n\n\t// SetRightToLeftLayout sets whether coordinates on the x axis of the\n\t// Form increase from right to left.\n\tSetRightToLeftLayout(rtl bool) error\n}\n\ntype FormBase struct {\n\tWindowBase\n\tclientComposite             *Composite\n\towner                       Form\n\tstopwatch                   *stopwatch\n\tinProgressEventCount        int\n\tperformLayout               chan ContainerLayoutItem\n\tlayoutResults               chan []LayoutResult\n\tinSizeLoop                  chan bool\n\tupdateStopwatch             chan *stopwatch\n\tquitLayoutPerformer         chan struct{}\n\tclosingPublisher            CloseEventPublisher\n\tactivatingPublisher         EventPublisher\n\tdeactivatingPublisher       EventPublisher\n\tstartingPublisher           EventPublisher\n\ttitleChangedPublisher       EventPublisher\n\ticonChangedPublisher        EventPublisher\n\tprogressIndicator           *ProgressIndicator\n\ticon                        Image\n\tprevFocusHWnd               win.HWND\n\tproposedSize                Size // in native pixels\n\tcloseReason                 CloseReason\n\tinSizingLoop                bool\n\tstartingLayoutViaSizingLoop bool\n\tisInRestoreState            bool\n\tstarted                     bool\n\tlayoutScheduled             bool\n}\n\nfunc (fb *FormBase) init(form Form) error {\n\tvar err error\n\tif fb.clientComposite, err = NewComposite(form); err != nil {\n\t\treturn err\n\t}\n\tfb.clientComposite.SetName(\"clientComposite\")\n\tfb.clientComposite.background = nil\n\n\tfb.clientComposite.children.observer = form.AsFormBase()\n\n\tfb.MustRegisterProperty(\"Icon\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn fb.Icon()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\ticon, err := IconFrom(v, fb.DPI())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tvar img Image\n\t\t\tif icon != nil {\n\t\t\t\timg = icon\n\t\t\t}\n\n\t\t\tfb.SetIcon(img)\n\n\t\t\treturn nil\n\t\t},\n\t\tfb.iconChangedPublisher.Event()))\n\n\tfb.MustRegisterProperty(\"Title\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn fb.Title()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn fb.SetTitle(assertStringOr(v, \"\"))\n\t\t},\n\t\tfb.titleChangedPublisher.Event()))\n\n\tversion := win.GetVersion()\n\tif (version&0xFF) > 6 || ((version&0xFF) == 6 && (version&0xFF00>>8) > 0) {\n\t\twin.ChangeWindowMessageFilterEx(fb.hWnd, taskbarButtonCreatedMsgId, win.MSGFLT_ALLOW, nil)\n\t}\n\n\tfb.performLayout, fb.layoutResults, fb.inSizeLoop, fb.updateStopwatch, fb.quitLayoutPerformer = startLayoutPerformer(fb)\n\n\treturn nil\n}\n\nfunc (fb *FormBase) Dispose() {\n\tif fb.hWnd != 0 {\n\t\tfb.quitLayoutPerformer <- struct{}{}\n\t}\n\n\tfb.WindowBase.Dispose()\n}\n\nfunc (fb *FormBase) AsContainerBase() *ContainerBase {\n\tif fb.clientComposite == nil {\n\t\treturn nil\n\t}\n\n\treturn fb.clientComposite.AsContainerBase()\n}\n\nfunc (fb *FormBase) AsFormBase() *FormBase {\n\treturn fb\n}\n\nfunc (fb *FormBase) Children() *WidgetList {\n\tif fb.clientComposite == nil {\n\t\treturn nil\n\t}\n\n\treturn fb.clientComposite.Children()\n}\n\nfunc (fb *FormBase) Layout() Layout {\n\tif fb.clientComposite == nil {\n\t\treturn nil\n\t}\n\n\treturn fb.clientComposite.Layout()\n}\n\nfunc (fb *FormBase) SetLayout(value Layout) error {\n\tif fb.clientComposite == nil {\n\t\treturn newError(\"clientComposite not initialized\")\n\t}\n\n\treturn fb.clientComposite.SetLayout(value)\n}\n\nfunc (fb *FormBase) SetBoundsPixels(bounds Rectangle) error {\n\tif layout := fb.Layout(); layout != nil {\n\t\tlayoutItem := CreateLayoutItemsForContainer(fb)\n\t\tminSize := fb.sizeFromClientSizePixels(layoutItem.MinSizeForSize(bounds.Size()))\n\t\tminSize = fb.sizeFromClientSizePixels(layoutItem.MinSizeForSize(minSize))\n\n\t\tif bounds.Width < minSize.Width {\n\t\t\tbounds.Width = minSize.Width\n\t\t}\n\t\tif bounds.Height < minSize.Height {\n\t\t\tbounds.Height = minSize.Height\n\t\t}\n\t}\n\n\tif err := fb.WindowBase.SetBoundsPixels(bounds); err != nil {\n\t\treturn err\n\t}\n\n\tfb.proposedSize = bounds.Size()\n\n\treturn nil\n}\n\nfunc (fb *FormBase) fixedSize() bool {\n\treturn !fb.hasStyleBits(win.WS_THICKFRAME)\n}\n\nfunc (fb *FormBase) DataBinder() *DataBinder {\n\treturn fb.clientComposite.DataBinder()\n}\n\nfunc (fb *FormBase) SetDataBinder(db *DataBinder) {\n\tfb.clientComposite.SetDataBinder(db)\n}\n\nfunc (fb *FormBase) SetSuspended(suspended bool) {\n\tif suspended == fb.suspended {\n\t\treturn\n\t}\n\n\tfb.suspended = suspended\n\n\tif fb.clientComposite != nil {\n\t\tfb.clientComposite.SetSuspended(suspended)\n\t}\n}\n\nfunc (fb *FormBase) MouseDown() *MouseEvent {\n\treturn fb.clientComposite.MouseDown()\n}\n\nfunc (fb *FormBase) MouseMove() *MouseEvent {\n\treturn fb.clientComposite.MouseMove()\n}\n\nfunc (fb *FormBase) MouseUp() *MouseEvent {\n\treturn fb.clientComposite.MouseUp()\n}\n\nfunc (fb *FormBase) onInsertingWidget(index int, widget Widget) error {\n\treturn fb.clientComposite.onInsertingWidget(index, widget)\n}\n\nfunc (fb *FormBase) onInsertedWidget(index int, widget Widget) error {\n\treturn fb.clientComposite.onInsertedWidget(index, widget)\n}\n\nfunc (fb *FormBase) onRemovingWidget(index int, widget Widget) error {\n\treturn fb.clientComposite.onRemovingWidget(index, widget)\n}\n\nfunc (fb *FormBase) onRemovedWidget(index int, widget Widget) error {\n\treturn fb.clientComposite.onRemovedWidget(index, widget)\n}\n\nfunc (fb *FormBase) onClearingWidgets() error {\n\treturn fb.clientComposite.onClearingWidgets()\n}\n\nfunc (fb *FormBase) onClearedWidgets() error {\n\treturn fb.clientComposite.onClearedWidgets()\n}\n\nfunc (fb *FormBase) ContextMenu() *Menu {\n\treturn fb.clientComposite.ContextMenu()\n}\n\nfunc (fb *FormBase) SetContextMenu(contextMenu *Menu) {\n\tfb.clientComposite.SetContextMenu(contextMenu)\n}\n\nfunc (fb *FormBase) ContextMenuLocation() Point {\n\treturn fb.clientComposite.ContextMenuLocation()\n}\n\nfunc (fb *FormBase) applyEnabled(enabled bool) {\n\tfb.WindowBase.applyEnabled(enabled)\n\n\tfb.clientComposite.applyEnabled(enabled)\n}\n\nfunc (fb *FormBase) applyFont(font *Font) {\n\tfb.WindowBase.applyFont(font)\n\n\tfb.clientComposite.applyFont(font)\n}\n\nfunc (fb *FormBase) ApplySysColors() {\n\tfb.WindowBase.ApplySysColors()\n\tfb.clientComposite.ApplySysColors()\n}\n\nfunc (fb *FormBase) Background() Brush {\n\treturn fb.clientComposite.Background()\n}\n\nfunc (fb *FormBase) SetBackground(background Brush) {\n\tfb.clientComposite.SetBackground(background)\n}\n\nfunc (fb *FormBase) Title() string {\n\treturn fb.text()\n}\n\nfunc (fb *FormBase) SetTitle(value string) error {\n\treturn fb.setText(value)\n}\n\nfunc (fb *FormBase) TitleChanged() *Event {\n\treturn fb.titleChangedPublisher.Event()\n}\n\n// RightToLeftLayout returns whether coordinates on the x axis of the\n// FormBase increase from right to left.\nfunc (fb *FormBase) RightToLeftLayout() bool {\n\treturn fb.hasExtendedStyleBits(win.WS_EX_LAYOUTRTL)\n}\n\n// SetRightToLeftLayout sets whether coordinates on the x axis of the\n// FormBase increase from right to left.\nfunc (fb *FormBase) SetRightToLeftLayout(rtl bool) error {\n\treturn fb.ensureExtendedStyleBits(win.WS_EX_LAYOUTRTL, rtl)\n}\n\nfunc (fb *FormBase) Run() int {\n\tif fb.owner != nil {\n\t\twin.EnableWindow(fb.owner.Handle(), false)\n\n\t\tinvalidateDescendentBorders := func() {\n\t\t\twalkDescendants(fb.owner, func(wnd Window) bool {\n\t\t\t\tif widget, ok := wnd.(Widget); ok {\n\t\t\t\t\twidget.AsWidgetBase().invalidateBorderInParent()\n\t\t\t\t}\n\n\t\t\t\treturn true\n\t\t\t})\n\t\t}\n\n\t\tinvalidateDescendentBorders()\n\t\tdefer invalidateDescendentBorders()\n\t}\n\n\tfb.started = true\n\tfb.startingPublisher.Publish()\n\n\tfb.SetBoundsPixels(fb.BoundsPixels())\n\n\tif fb.proposedSize == (Size{}) {\n\t\tfb.proposedSize = maxSize(SizeFrom96DPI(fb.minSize96dpi, fb.DPI()), fb.SizePixels())\n\t\tif !fb.Suspended() {\n\t\t\tfb.startLayout()\n\t\t}\n\t}\n\n\tfb.SetSuspended(false)\n\n\treturn fb.mainLoop()\n}\n\nfunc (fb *FormBase) handleKeyDown(msg *win.MSG) bool {\n\tret := false\n\n\tkey, mods := Key(msg.WParam), ModifiersDown()\n\n\t// Tabbing\n\tif key == KeyTab && (mods&ModControl) != 0 {\n\t\tdoTabbing := func(tw *TabWidget) {\n\t\t\tindex := tw.CurrentIndex()\n\t\t\tif (mods & ModShift) != 0 {\n\t\t\t\tindex--\n\t\t\t\tif index < 0 {\n\t\t\t\t\tindex = tw.Pages().Len() - 1\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tindex++\n\t\t\t\tif index >= tw.Pages().Len() {\n\t\t\t\t\tindex = 0\n\t\t\t\t}\n\t\t\t}\n\t\t\ttw.SetCurrentIndex(index)\n\t\t}\n\n\t\thwnd := win.GetFocus()\n\n\tLOOP:\n\t\tfor hwnd != 0 {\n\t\t\twindow := windowFromHandle(hwnd)\n\n\t\t\tswitch widget := window.(type) {\n\t\t\tcase nil:\n\n\t\t\tcase *TabWidget:\n\t\t\t\tdoTabbing(widget)\n\t\t\t\treturn true\n\n\t\t\tcase Widget:\n\n\t\t\tdefault:\n\t\t\t\tbreak LOOP\n\t\t\t}\n\n\t\t\thwnd = win.GetParent(hwnd)\n\t\t}\n\n\t\twalkDescendants(fb.window, func(w Window) bool {\n\t\t\tif tw, ok := w.(*TabWidget); ok {\n\t\t\t\tdoTabbing(tw)\n\t\t\t\tret = true\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\t\tif ret {\n\t\t\treturn true\n\t\t}\n\t}\n\n\t// Shortcut actions\n\thwnd := msg.HWnd\n\tfor hwnd != 0 {\n\t\tif window := windowFromHandle(hwnd); window != nil {\n\t\t\twb := window.AsWindowBase()\n\n\t\t\tif wb.shortcutActions != nil {\n\t\t\t\tfor _, action := range wb.shortcutActions.actions {\n\t\t\t\t\tif action.shortcut.Key == key && action.shortcut.Modifiers == mods && action.Visible() && action.Enabled() {\n\t\t\t\t\t\taction.raiseTriggered()\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\thwnd = win.GetParent(hwnd)\n\t}\n\n\t// WebView\n\twalkDescendants(fb.window, func(w Window) bool {\n\t\tif webView, ok := w.(*WebView); ok {\n\t\t\twebViewHWnd := webView.Handle()\n\t\t\tif webViewHWnd == msg.HWnd || win.IsChild(webViewHWnd, msg.HWnd) {\n\t\t\t\t_ret := webView.translateAccelerator(msg)\n\t\t\t\tif _ret {\n\t\t\t\t\tret = _ret\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n\treturn ret\n}\n\nfunc (fb *FormBase) Starting() *Event {\n\treturn fb.startingPublisher.Event()\n}\n\nfunc (fb *FormBase) Activating() *Event {\n\treturn fb.activatingPublisher.Event()\n}\n\nfunc (fb *FormBase) Deactivating() *Event {\n\treturn fb.deactivatingPublisher.Event()\n}\n\nfunc (fb *FormBase) Activate() error {\n\tif hwndPrevActive := win.SetActiveWindow(fb.hWnd); hwndPrevActive == 0 {\n\t\treturn lastError(\"SetActiveWindow\")\n\t}\n\n\treturn nil\n}\n\nfunc (fb *FormBase) Owner() Form {\n\treturn fb.owner\n}\n\nfunc (fb *FormBase) SetOwner(value Form) error {\n\tfb.owner = value\n\n\tvar ownerHWnd win.HWND\n\tif value != nil {\n\t\townerHWnd = value.Handle()\n\t}\n\n\twin.SetLastError(0)\n\tif 0 == win.SetWindowLong(\n\t\tfb.hWnd,\n\t\twin.GWL_HWNDPARENT,\n\t\tint32(ownerHWnd)) && win.GetLastError() != 0 {\n\n\t\treturn lastError(\"SetWindowLong\")\n\t}\n\n\treturn nil\n}\n\nfunc (fb *FormBase) Icon() Image {\n\treturn fb.icon\n}\n\nfunc (fb *FormBase) SetIcon(icon Image) error {\n\tvar hIconSmall, hIconBig uintptr\n\n\tif icon != nil {\n\t\tdpi := fb.DPI()\n\t\tsize96dpi := icon.Size()\n\n\t\tsmallHeight := int(win.GetSystemMetricsForDpi(win.SM_CYSMICON, uint32(dpi)))\n\t\tsmallDPI := int(math.Round(float64(smallHeight) / float64(size96dpi.Height) * 96.0))\n\t\tsmallIcon, err := iconCache.Icon(icon, smallDPI)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\thIconSmall = uintptr(smallIcon.handleForDPI(smallDPI))\n\n\t\tbigHeight := int(win.GetSystemMetricsForDpi(win.SM_CYICON, uint32(dpi)))\n\t\tbigDPI := int(math.Round(float64(bigHeight) / float64(size96dpi.Height) * 96.0))\n\t\tbigIcon, err := iconCache.Icon(icon, bigDPI)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\thIconBig = uintptr(bigIcon.handleForDPI(bigDPI))\n\t}\n\n\tfb.SendMessage(win.WM_SETICON, 0, hIconSmall)\n\tfb.SendMessage(win.WM_SETICON, 1, hIconBig)\n\n\tfb.icon = icon\n\n\tfb.iconChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (fb *FormBase) IconChanged() *Event {\n\treturn fb.iconChangedPublisher.Event()\n}\n\nfunc (fb *FormBase) Hide() {\n\tfb.window.SetVisible(false)\n}\n\nfunc (fb *FormBase) Show() {\n\tfb.proposedSize = maxSize(SizeFrom96DPI(fb.minSize96dpi, fb.DPI()), fb.SizePixels())\n\n\tif p, ok := fb.window.(Persistable); ok && p.Persistent() && App().Settings() != nil {\n\t\tp.RestoreState()\n\t}\n\n\tfb.window.SetVisible(true)\n}\n\nfunc (fb *FormBase) close() error {\n\tif p, ok := fb.window.(Persistable); ok && p.Persistent() && App().Settings() != nil {\n\t\tp.SaveState()\n\t}\n\n\tfb.window.Dispose()\n\n\treturn nil\n}\n\nfunc (fb *FormBase) Close() error {\n\tfb.SendMessage(win.WM_CLOSE, 0, 0)\n\n\treturn nil\n}\n\nfunc (fb *FormBase) Persistent() bool {\n\treturn fb.clientComposite.persistent\n}\n\nfunc (fb *FormBase) SetPersistent(value bool) {\n\tfb.clientComposite.persistent = value\n}\n\nfunc (fb *FormBase) SaveState() error {\n\tif err := fb.clientComposite.SaveState(); err != nil {\n\t\treturn err\n\t}\n\n\tvar wp win.WINDOWPLACEMENT\n\n\twp.Length = uint32(unsafe.Sizeof(wp))\n\n\tif !win.GetWindowPlacement(fb.hWnd, &wp) {\n\t\treturn lastError(\"GetWindowPlacement\")\n\t}\n\n\tstate := fmt.Sprint(\n\t\twp.Flags, wp.ShowCmd,\n\t\twp.PtMinPosition.X, wp.PtMinPosition.Y,\n\t\twp.PtMaxPosition.X, wp.PtMaxPosition.Y,\n\t\twp.RcNormalPosition.Left, wp.RcNormalPosition.Top,\n\t\twp.RcNormalPosition.Right, wp.RcNormalPosition.Bottom)\n\n\tif err := fb.WriteState(state); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (fb *FormBase) RestoreState() error {\n\tif fb.isInRestoreState {\n\t\treturn nil\n\t}\n\tfb.isInRestoreState = true\n\tdefer func() {\n\t\tfb.isInRestoreState = false\n\t}()\n\n\tstate, err := fb.ReadState()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif state == \"\" {\n\t\treturn nil\n\t}\n\n\tvar wp win.WINDOWPLACEMENT\n\n\tif _, err := fmt.Sscan(state,\n\t\t&wp.Flags, &wp.ShowCmd,\n\t\t&wp.PtMinPosition.X, &wp.PtMinPosition.Y,\n\t\t&wp.PtMaxPosition.X, &wp.PtMaxPosition.Y,\n\t\t&wp.RcNormalPosition.Left, &wp.RcNormalPosition.Top,\n\t\t&wp.RcNormalPosition.Right, &wp.RcNormalPosition.Bottom); err != nil {\n\t\treturn err\n\t}\n\n\twp.Length = uint32(unsafe.Sizeof(wp))\n\n\tif layout := fb.Layout(); layout != nil && fb.fixedSize() {\n\t\tlayoutItem := CreateLayoutItemsForContainer(fb)\n\t\tminSize := fb.sizeFromClientSizePixels(layoutItem.MinSize())\n\n\t\twp.RcNormalPosition.Right = wp.RcNormalPosition.Left + int32(minSize.Width) - 1\n\t\twp.RcNormalPosition.Bottom = wp.RcNormalPosition.Top + int32(minSize.Height) - 1\n\t}\n\n\tif !win.SetWindowPlacement(fb.hWnd, &wp) {\n\t\treturn lastError(\"SetWindowPlacement\")\n\t}\n\n\treturn fb.clientComposite.RestoreState()\n}\n\nfunc (fb *FormBase) Closing() *CloseEvent {\n\treturn fb.closingPublisher.Event()\n}\n\nfunc (fb *FormBase) ProgressIndicator() *ProgressIndicator {\n\treturn fb.progressIndicator\n}\n\nfunc (fb *FormBase) setStopwatch(sw *stopwatch) {\n\tfb.stopwatch = sw\n\n\tfb.updateStopwatch <- sw\n}\n\nfunc (fb *FormBase) startLayout() bool {\n\tif fb.performLayout == nil || fb.inSizingLoop && !fb.startingLayoutViaSizingLoop {\n\t\treturn false\n\t}\n\n\tcs := fb.clientSizeFromSizePixels(fb.proposedSize)\n\tmin := CreateLayoutItemsForContainer(fb.clientComposite).MinSizeForSize(fb.proposedSize)\n\n\tif cs.Width < min.Width || cs.Height < min.Height {\n\t\tcs = maxSize(cs, min)\n\t\tsize := fb.sizeFromClientSizePixels(cs)\n\t\tfb.SetSizePixels(size)\n\t\tfb.Invalidate()\n\t}\n\n\tcbp := fb.window.ClientBoundsPixels()\n\n\tfb.clientComposite.SetBoundsPixels(Rectangle{Y: cbp.Y, Width: cs.Width, Height: cs.Height})\n\n\tcli := CreateLayoutItemsForContainer(fb)\n\tcli.Geometry().ClientSize = cs\n\n\tfb.performLayout <- cli\n\n\treturn true\n}\n\nfunc (fb *FormBase) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_ACTIVATE:\n\t\tswitch win.LOWORD(uint32(wParam)) {\n\t\tcase win.WA_ACTIVE, win.WA_CLICKACTIVE:\n\t\t\tif fb.prevFocusHWnd != 0 {\n\t\t\t\twin.SetFocus(fb.prevFocusHWnd)\n\t\t\t}\n\n\t\t\tfb.group.SetActiveForm(fb.window.(Form))\n\n\t\t\tfb.activatingPublisher.Publish()\n\n\t\tcase win.WA_INACTIVE:\n\t\t\tfb.prevFocusHWnd = win.GetFocus()\n\n\t\t\tfb.group.SetActiveForm(nil)\n\n\t\t\tfb.deactivatingPublisher.Publish()\n\t\t}\n\n\t\treturn 0\n\n\tcase win.WM_CLOSE:\n\t\tfb.closeReason = CloseReasonUnknown\n\t\tvar canceled bool\n\t\tfb.closingPublisher.Publish(&canceled, fb.closeReason)\n\t\tif !canceled {\n\t\t\tif fb.owner != nil {\n\t\t\t\twin.EnableWindow(fb.owner.Handle(), true)\n\t\t\t\tif !win.SetWindowPos(fb.owner.Handle(), win.HWND_NOTOPMOST, 0, 0, 0, 0, win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_SHOWWINDOW) {\n\t\t\t\t\tlastError(\"SetWindowPos\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfb.close()\n\t\t}\n\t\treturn 0\n\n\tcase win.WM_COMMAND:\n\t\treturn fb.clientComposite.WndProc(hwnd, msg, wParam, lParam)\n\n\tcase win.WM_GETMINMAXINFO:\n\t\tif fb.Suspended() || fb.proposedSize == (Size{}) {\n\t\t\tbreak\n\t\t}\n\n\t\tmmi := (*win.MINMAXINFO)(unsafe.Pointer(lParam))\n\n\t\tvar min Size\n\t\tif layout := fb.clientComposite.layout; layout != nil {\n\t\t\tsize := fb.clientSizeFromSizePixels(fb.proposedSize)\n\t\t\tlayoutItem := CreateLayoutItemsForContainer(fb)\n\t\t\tmin = fb.sizeFromClientSizePixels(layoutItem.MinSizeForSize(size))\n\n\t\t\tif fb.proposedSize.Width < min.Width {\n\t\t\t\tmin = fb.sizeFromClientSizePixels(layoutItem.MinSizeForSize(min))\n\t\t\t}\n\t\t}\n\n\t\tminSize := SizeFrom96DPI(fb.minSize96dpi, fb.DPI())\n\n\t\tmmi.PtMinTrackSize = Point{\n\t\t\tmaxi(min.Width, minSize.Width),\n\t\t\tmaxi(min.Height, minSize.Height),\n\t\t}.toPOINT()\n\t\treturn 0\n\n\tcase win.WM_NOTIFY:\n\t\treturn fb.clientComposite.WndProc(hwnd, msg, wParam, lParam)\n\n\tcase win.WM_SETTEXT:\n\t\tfb.titleChangedPublisher.Publish()\n\n\tcase win.WM_ENTERSIZEMOVE:\n\t\tfb.inSizingLoop = true\n\t\tfb.inSizeLoop <- true\n\n\tcase win.WM_EXITSIZEMOVE:\n\t\tfb.inSizingLoop = false\n\t\tfb.inSizeLoop <- false\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_SHOWWINDOW != 0 {\n\t\t\tfb.startLayout()\n\t\t}\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 || fb.Layout() == nil || fb.Suspended() {\n\t\t\tbreak\n\t\t}\n\n\t\tfb.proposedSize = Size{int(wp.Cx), int(wp.Cy)}\n\n\t\tconst performingLayoutSubject = \"*FormBase.WndProc - WM_WINDOWPOSCHANGED - full layout from sizing loop\"\n\n\t\tif fb.inSizingLoop {\n\t\t\tfb.startingLayoutViaSizingLoop = true\n\n\t\t\tif fb.stopwatch != nil {\n\t\t\t\tfb.stopwatch.Start(performingLayoutSubject)\n\t\t\t}\n\t\t}\n\n\t\tif fb.startLayout() {\n\t\t\tif fb.inSizingLoop {\n\t\t\t\tfb.startingLayoutViaSizingLoop = false\n\n\t\t\t\tapplyLayoutResults(<-fb.layoutResults, fb.stopwatch)\n\n\t\t\t\tif fb.stopwatch != nil {\n\t\t\t\t\tfb.stopwatch.Stop(performingLayoutSubject)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tcase win.WM_SYSCOLORCHANGE:\n\t\tfb.ApplySysColors()\n\n\tcase win.WM_DPICHANGED:\n\t\twasSuspended := fb.Suspended()\n\t\tfb.SetSuspended(true)\n\t\tdefer fb.SetSuspended(wasSuspended)\n\n\t\tdpi := int(win.HIWORD(uint32(wParam)))\n\n\t\tseenInApplyFontToDescendantsDuringDPIChange = make(map[*WindowBase]bool)\n\t\tseenInApplyDPIToDescendantsDuringDPIChange = make(map[*WindowBase]bool)\n\t\tdefer func() {\n\t\t\tseenInApplyFontToDescendantsDuringDPIChange = nil\n\t\t\tseenInApplyDPIToDescendantsDuringDPIChange = nil\n\t\t}()\n\n\t\tfb.clientComposite.ApplyDPI(dpi)\n\t\tfb.ApplyDPI(dpi)\n\t\tif fb.progressIndicator != nil {\n\t\t\tfb.progressIndicator.SetOverlayIcon(fb.progressIndicator.overlayIcon, fb.progressIndicator.overlayIconDescription)\n\t\t}\n\t\tapplyDPIToDescendants(fb.window, dpi)\n\n\t\tfb.SetSuspended(wasSuspended)\n\n\t\trc := (*win.RECT)(unsafe.Pointer(lParam))\n\t\tbounds := rectangleFromRECT(*rc)\n\t\tfb.proposedSize = bounds.Size()\n\t\tfb.window.SetBoundsPixels(bounds)\n\n\t\tfb.SetIcon(fb.icon)\n\n\t\ttime.AfterFunc(time.Second, func() {\n\t\t\tif fb.hWnd == 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tfb.Synchronize(func() {\n\t\t\t\tfor ni := range notifyIcons {\n\t\t\t\t\t// We do this on all NotifyIcons, not just ones attached to this form or descendents, because\n\t\t\t\t\t// the notify icon might be on a different screen, and since it can't get notifications itself\n\t\t\t\t\t// we hope that one of the forms did for it. We also have to delay it by a second, because the\n\t\t\t\t\t// tray usually gets resized sometime after us. This is a nasty hack!\n\t\t\t\t\tni.applyDPI()\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\n\tcase win.WM_SYSCOMMAND:\n\t\tif wParam == win.SC_CLOSE {\n\t\t\tfb.closeReason = CloseReasonUser\n\t\t}\n\n\tcase taskbarButtonCreatedMsgId:\n\t\tversion := win.GetVersion()\n\t\tmajor := version & 0xFF\n\t\tminor := version & 0xFF00 >> 8\n\t\t// Check that the OS is Win 7 or later (Win 7 is v6.1).\n\t\tif fb.progressIndicator == nil && (major > 6 || (major == 6 && minor > 0)) {\n\t\t\tfb.progressIndicator, _ = newTaskbarList3(fb.hWnd)\n\t\t}\n\n\tcase taskbarCreatedMsgId:\n\t\tfor ni := range notifyIcons {\n\t\t\tni.readdToTaskbar()\n\t\t}\n\t}\n\n\treturn fb.WindowBase.WndProc(hwnd, msg, wParam, lParam)\n}\n"
  },
  {
    "path": "gradientcomposite.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype GradientComposite struct {\n\t*Composite\n\tvertical                 bool\n\tcolor1                   Color\n\tcolor2                   Color\n\tverticalChangedPublisher EventPublisher\n\tcolor1ChangedPublisher   EventPublisher\n\tcolor2ChangedPublisher   EventPublisher\n\tbrush                    *BitmapBrush\n}\n\nfunc NewGradientComposite(parent Container) (*GradientComposite, error) {\n\treturn NewGradientCompositeWithStyle(parent, 0)\n}\n\nfunc NewGradientCompositeWithStyle(parent Container, style uint32) (*GradientComposite, error) {\n\tcomposite, err := NewCompositeWithStyle(parent, style)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgc := &GradientComposite{Composite: composite}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tgc.Dispose()\n\t\t}\n\t}()\n\n\tif err := InitWrapperWindow(gc); err != nil {\n\t\treturn nil, err\n\t}\n\n\tgc.MustRegisterProperty(\"Vertical\", NewBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn gc.Vertical()\n\t\t},\n\t\tfunc(b bool) error {\n\t\t\tgc.SetVertical(b)\n\t\t\treturn nil\n\t\t},\n\t\tgc.verticalChangedPublisher.Event()))\n\n\tgc.MustRegisterProperty(\"Color1\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn float64(uint32(gc.Color1()))\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\tvar c Color\n\n\t\t\tswitch v := v.(type) {\n\t\t\tcase Color:\n\t\t\t\tc = v\n\n\t\t\tcase uint32:\n\t\t\t\tc = Color(v)\n\n\t\t\tcase float64:\n\t\t\t\tc = Color(uint32(v))\n\n\t\t\tdefault:\n\t\t\t\treturn ErrInvalidType\n\t\t\t}\n\n\t\t\treturn gc.SetColor1(c)\n\t\t},\n\t\tgc.color1ChangedPublisher.Event()))\n\n\tgc.MustRegisterProperty(\"Color2\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn float64(uint32(gc.Color2()))\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\tvar c Color\n\n\t\t\tswitch v := v.(type) {\n\t\t\tcase Color:\n\t\t\t\tc = v\n\n\t\t\tcase uint32:\n\t\t\t\tc = Color(v)\n\n\t\t\tcase float64:\n\t\t\t\tc = Color(uint32(v))\n\n\t\t\tdefault:\n\t\t\t\treturn ErrInvalidType\n\t\t\t}\n\n\t\t\treturn gc.SetColor2(c)\n\t\t},\n\t\tgc.color2ChangedPublisher.Event()))\n\n\tsucceeded = true\n\n\treturn gc, nil\n}\n\nfunc (gc *GradientComposite) Vertical() bool {\n\treturn gc.vertical\n}\n\nfunc (gc *GradientComposite) SetVertical(vertical bool) (err error) {\n\tif vertical == gc.vertical {\n\t\treturn nil\n\t}\n\n\told := gc.vertical\n\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tgc.vertical = old\n\t\t}\n\t}()\n\n\tgc.vertical = vertical\n\n\tif err = gc.updateBackground(); err != nil {\n\t\treturn\n\t}\n\n\tgc.verticalChangedPublisher.Publish()\n\n\treturn\n}\n\nfunc (gc *GradientComposite) Color1() Color {\n\treturn gc.color1\n}\n\nfunc (gc *GradientComposite) SetColor1(c Color) (err error) {\n\tif c == gc.color1 {\n\t\treturn nil\n\t}\n\n\told := gc.color1\n\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tgc.color1 = old\n\t\t}\n\t}()\n\n\tgc.color1 = c\n\n\tif err = gc.updateBackground(); err != nil {\n\t\treturn\n\t}\n\n\tgc.color1ChangedPublisher.Publish()\n\n\treturn\n}\n\nfunc (gc *GradientComposite) Color2() Color {\n\treturn gc.color2\n}\n\nfunc (gc *GradientComposite) SetColor2(c Color) (err error) {\n\tif c == gc.color2 {\n\t\treturn nil\n\t}\n\n\told := gc.color2\n\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tgc.color2 = old\n\t\t}\n\t}()\n\n\tgc.color2 = c\n\n\tif err = gc.updateBackground(); err != nil {\n\t\treturn\n\t}\n\n\tgc.color2ChangedPublisher.Publish()\n\n\treturn\n}\n\nfunc (gc *GradientComposite) updateBackground() error {\n\tbounds := gc.ClientBoundsPixels()\n\tif bounds.Width < 1 || bounds.Height < 1 {\n\t\treturn nil\n\t}\n\n\tif gc.brush != nil {\n\t\tgc.brush.Dispose()\n\t\tgc.brush.Bitmap().Dispose()\n\t\tgc.brush = nil\n\t}\n\n\tif gc.vertical {\n\t\tbounds.Width = 1\n\t} else {\n\t\tbounds.Height = 1\n\t}\n\n\tbmp, err := NewBitmapForDPI(bounds.Size(), gc.DPI())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tif gc.brush == nil {\n\t\t\tbmp.Dispose()\n\t\t}\n\t}()\n\n\tcanvas, err := NewCanvasFromImage(bmp)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer canvas.Dispose()\n\n\tvar orientation Orientation\n\tif gc.vertical {\n\t\torientation = Vertical\n\t} else {\n\t\torientation = Horizontal\n\t}\n\n\tif err := canvas.GradientFillRectanglePixels(gc.color1, gc.color2, orientation, bounds); err != nil {\n\t\treturn err\n\t}\n\n\tgc.brush, err = NewBitmapBrush(bmp)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tgc.SetBackground(gc.brush)\n\n\treturn nil\n}\n\nfunc (gc *GradientComposite) Dispose() {\n\tif gc.brush != nil {\n\t\tgc.SetBackground(nil)\n\t\tgc.brush.Dispose()\n\t\tgc.brush.Bitmap().Dispose()\n\t\tgc.brush = nil\n\t}\n\n\tgc.Composite.Dispose()\n}\n\nfunc (gc *GradientComposite) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tsize := gc.ClientBoundsPixels().Size()\n\t\tif gc.brush != nil && gc.brush.bitmap.size == size {\n\t\t\tbreak\n\t\t}\n\n\t\tgc.updateBackground()\n\t}\n\n\treturn gc.Composite.WndProc(hwnd, msg, wParam, lParam)\n}\n"
  },
  {
    "path": "graphicseffects.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport \"math\"\n\nvar (\n\tborderGlowAlpha = []float64{0.2, 0.1, 0.075, 0.05, 0.075}\n\n\tInteractionEffect WidgetGraphicsEffect\n\tFocusEffect       WidgetGraphicsEffect\n)\n\ntype WidgetGraphicsEffect interface {\n\tDraw(widget Widget, canvas *Canvas) error\n}\n\ntype widgetGraphicsEffectBase struct {\n\tcolor      Color\n\tdpi2Bitmap map[int]*Bitmap\n}\n\nfunc (wgeb *widgetGraphicsEffectBase) create(color Color) error {\n\twgeb.color = color\n\treturn nil\n}\n\nfunc (wgeb *widgetGraphicsEffectBase) Dispose() {\n\tif len(wgeb.dpi2Bitmap) == 0 {\n\t\treturn\n\t}\n\n\tfor dpi, bitmap := range wgeb.dpi2Bitmap {\n\t\tbitmap.Dispose()\n\t\tdelete(wgeb.dpi2Bitmap, dpi)\n\t}\n}\n\nfunc (wgeb *widgetGraphicsEffectBase) bitmapForDPI(dpi int) (*Bitmap, error) {\n\tif wgeb.dpi2Bitmap == nil {\n\t\twgeb.dpi2Bitmap = make(map[int]*Bitmap)\n\t} else if bitmap, ok := wgeb.dpi2Bitmap[dpi]; ok {\n\t\treturn bitmap, nil\n\t}\n\n\tvar disposables Disposables\n\tdefer disposables.Treat()\n\n\tbitmap, err := NewBitmapWithTransparentPixelsForDPI(SizeFrom96DPI(Size{12, 12}, dpi), dpi)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdisposables.Add(bitmap)\n\n\tcanvas, err := NewCanvasFromImage(bitmap)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer canvas.Dispose()\n\n\tfor i := 1; i <= 5; i++ {\n\t\tsize := SizeFrom96DPI(Size{i*2 + 2, i*2 + 2}, dpi)\n\n\t\tbmp, err := NewBitmapWithTransparentPixelsForDPI(size, dpi)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdefer bmp.Dispose()\n\n\t\tbmpCanvas, err := NewCanvasFromImage(bmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdefer bmpCanvas.Dispose()\n\n\t\tcolor := RGB(\n\t\t\tbyte(math.Min(1.0, float64(wgeb.color.R())/255.0-0.1+0.1*float64(i))*255.0),\n\t\t\tbyte(math.Min(1.0, float64(wgeb.color.G())/255.0-0.1+0.1*float64(i))*255.0),\n\t\t\tbyte(math.Min(1.0, float64(wgeb.color.B())/255.0-0.1+0.1*float64(i))*255.0),\n\t\t)\n\n\t\tbrush, err := NewSolidColorBrush(color)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdefer brush.Dispose()\n\n\t\tellipseSize := SizeFrom96DPI(Size{i * 2, i * 2}, dpi)\n\t\tif err := bmpCanvas.FillRoundedRectanglePixels(brush, Rectangle{0, 0, size.Width, size.Height}, ellipseSize); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tbmpCanvas.Dispose()\n\n\t\topacity := byte(borderGlowAlpha[i-1] * 255.0)\n\n\t\toffset := PointFrom96DPI(Point{5 - i, 5 - i}, dpi)\n\t\tcanvas.DrawBitmapWithOpacityPixels(bmp, Rectangle{offset.X, offset.Y, size.Width, size.Height}, opacity)\n\t}\n\n\tdisposables.Spare()\n\n\twgeb.dpi2Bitmap[dpi] = bitmap\n\n\treturn bitmap, nil\n}\n\ntype BorderGlowEffect struct {\n\twidgetGraphicsEffectBase\n}\n\nfunc NewBorderGlowEffect(color Color) (*BorderGlowEffect, error) {\n\tbge := new(BorderGlowEffect)\n\n\tif err := bge.create(color); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn bge, nil\n}\n\nfunc (bge *BorderGlowEffect) Draw(widget Widget, canvas *Canvas) error {\n\tb := widget.BoundsPixels()\n\n\tdpi := canvas.DPI()\n\tbitmap, err := bge.bitmapForDPI(dpi)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toff1 := IntFrom96DPI(1, dpi)\n\toff2 := IntFrom96DPI(2, dpi)\n\toff5 := IntFrom96DPI(5, dpi)\n\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X - off5, b.Y - off5, off5, off5}, Rectangle{0, 0, off5, off5})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X, b.Y - off5, b.Width, off5}, Rectangle{off5 + off1, 0, off1, off5})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y - off5, off5, off5}, Rectangle{off5 + off2, 0, off5, off5})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y, off5, b.Height}, Rectangle{off5 + off2, off5 + off1, off5, off1})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y + b.Height, off5, off5}, Rectangle{off5 + off2, off5 + off2, off5, off5})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X, b.Y + b.Height, b.Width, off5}, Rectangle{off5 + off1, off5 + off2, off1, off5})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X - off5, b.Y + b.Height, off5, off5}, Rectangle{0, off5 + off2, off5, off5})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X - off5, b.Y, off5, b.Height}, Rectangle{0, off5 + off1, off5, off1})\n\n\treturn nil\n}\n\ntype DropShadowEffect struct {\n\twidgetGraphicsEffectBase\n}\n\nfunc NewDropShadowEffect(color Color) (*DropShadowEffect, error) {\n\tdse := new(DropShadowEffect)\n\n\tif err := dse.create(color); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn dse, nil\n}\n\nfunc (dse *DropShadowEffect) Draw(widget Widget, canvas *Canvas) error {\n\tb := widget.BoundsPixels()\n\n\tdpi := canvas.DPI()\n\tbitmap, err := dse.bitmapForDPI(dpi)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toff1 := IntFrom96DPI(1, dpi)\n\toff2 := IntFrom96DPI(2, dpi)\n\toff5 := IntFrom96DPI(5, dpi)\n\toff10 := IntFrom96DPI(10, dpi)\n\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y + off10 - off5, off5, off5}, Rectangle{off5 + off2, 0, off5, off5})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y + off10, off5, b.Height - off10}, Rectangle{off5 + off2, off5 + off1, off5, off1})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X + b.Width, b.Y + b.Height, off5, off5}, Rectangle{off5 + off2, off5 + off2, off5, off5})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X + off10, b.Y + b.Height, b.Width - off10, off5}, Rectangle{off5 + off1, off5 + off2, off1, off5})\n\tcanvas.DrawBitmapPart(bitmap, Rectangle{b.X + off10 - off5, b.Y + b.Height, off5, off5}, Rectangle{0, off5 + off2, off5, off5})\n\n\treturn nil\n}\n\ntype widgetGraphicsEffectListObserver interface {\n\tonInsertedGraphicsEffect(index int, effect WidgetGraphicsEffect) error\n\tonRemovedGraphicsEffect(index int, effect WidgetGraphicsEffect) error\n\tonClearedGraphicsEffects() error\n}\n\ntype WidgetGraphicsEffectList struct {\n\titems    []WidgetGraphicsEffect\n\tobserver widgetGraphicsEffectListObserver\n}\n\nfunc newWidgetGraphicsEffectList(observer widgetGraphicsEffectListObserver) *WidgetGraphicsEffectList {\n\treturn &WidgetGraphicsEffectList{observer: observer}\n}\n\nfunc (l *WidgetGraphicsEffectList) Add(effect WidgetGraphicsEffect) error {\n\tif effect == nil {\n\t\treturn newError(\"effect == nil\")\n\t}\n\n\treturn l.Insert(len(l.items), effect)\n}\n\nfunc (l *WidgetGraphicsEffectList) At(index int) WidgetGraphicsEffect {\n\treturn l.items[index]\n}\n\nfunc (l *WidgetGraphicsEffectList) Clear() error {\n\tobserver := l.observer\n\toldItems := l.items\n\tl.items = l.items[:0]\n\n\tif observer != nil {\n\t\tif err := observer.onClearedGraphicsEffects(); err != nil {\n\t\t\tl.items = oldItems\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (l *WidgetGraphicsEffectList) Index(effect WidgetGraphicsEffect) int {\n\tfor i, item := range l.items {\n\t\tif item == effect {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (l *WidgetGraphicsEffectList) Contains(effect WidgetGraphicsEffect) bool {\n\treturn l.Index(effect) > -1\n}\n\nfunc (l *WidgetGraphicsEffectList) insertIntoSlice(index int, effect WidgetGraphicsEffect) {\n\tl.items = append(l.items, nil)\n\tcopy(l.items[index+1:], l.items[index:])\n\tl.items[index] = effect\n}\n\nfunc (l *WidgetGraphicsEffectList) Insert(index int, effect WidgetGraphicsEffect) error {\n\tobserver := l.observer\n\n\tl.insertIntoSlice(index, effect)\n\n\tif observer != nil {\n\t\tif err := observer.onInsertedGraphicsEffect(index, effect); err != nil {\n\t\t\tl.items = append(l.items[:index], l.items[index+1:]...)\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (l *WidgetGraphicsEffectList) Len() int {\n\treturn len(l.items)\n}\n\nfunc (l *WidgetGraphicsEffectList) Remove(effect WidgetGraphicsEffect) error {\n\tindex := l.Index(effect)\n\tif index == -1 {\n\t\treturn nil\n\t}\n\n\treturn l.RemoveAt(index)\n}\n\nfunc (l *WidgetGraphicsEffectList) RemoveAt(index int) error {\n\tobserver := l.observer\n\titem := l.items[index]\n\n\tl.items = append(l.items[:index], l.items[index+1:]...)\n\n\tif observer != nil {\n\t\tif err := observer.onRemovedGraphicsEffect(index, item); err != nil {\n\t\t\tl.insertIntoSlice(index, item)\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "gridlayout.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"sort\"\n\t\"sync\"\n)\n\ntype gridLayoutCell struct {\n\trow        int\n\tcolumn     int\n\twidgetBase *WidgetBase\n}\n\ntype gridLayoutSection struct {\n\tgreedyNonSpacerCount int\n\tgreedySpacerCount    int\n}\n\ntype gridLayoutWidgetInfo struct {\n\tcell     *gridLayoutCell\n\tspanHorz int\n\tspanVert int\n\tminSize  Size // in native pixels\n}\n\ntype GridLayout struct {\n\tLayoutBase\n\trowStretchFactors    []int\n\tcolumnStretchFactors []int\n\twidgetBase2Info      map[*WidgetBase]*gridLayoutWidgetInfo\n\tcells                [][]gridLayoutCell\n}\n\nfunc NewGridLayout() *GridLayout {\n\tl := &GridLayout{\n\t\tLayoutBase: LayoutBase{\n\t\t\tmargins96dpi: Margins{9, 9, 9, 9},\n\t\t\tspacing96dpi: 6,\n\t\t},\n\t\twidgetBase2Info: make(map[*WidgetBase]*gridLayoutWidgetInfo),\n\t}\n\tl.layout = l\n\n\treturn l\n}\n\nfunc (l *GridLayout) sufficientStretchFactors(stretchFactors []int, required int) []int {\n\toldLen := len(stretchFactors)\n\tif oldLen < required {\n\t\tif cap(stretchFactors) < required {\n\t\t\ttemp := make([]int, required, maxi(required, len(stretchFactors)*2))\n\t\t\tcopy(temp, stretchFactors)\n\t\t\tstretchFactors = temp\n\t\t} else {\n\t\t\tstretchFactors = stretchFactors[:required]\n\t\t}\n\n\t\tfor i := oldLen; i < len(stretchFactors); i++ {\n\t\t\tstretchFactors[i] = 1\n\t\t}\n\t}\n\n\treturn stretchFactors\n}\n\nfunc (l *GridLayout) ensureSufficientSize(rows, columns int) {\n\tl.rowStretchFactors = l.sufficientStretchFactors(l.rowStretchFactors, rows)\n\tl.columnStretchFactors = l.sufficientStretchFactors(l.columnStretchFactors, columns)\n\n\tif len(l.cells) < len(l.rowStretchFactors) {\n\t\tif cap(l.cells) < cap(l.rowStretchFactors) {\n\t\t\ttemp := make([][]gridLayoutCell, len(l.rowStretchFactors), cap(l.rowStretchFactors))\n\t\t\tcopy(temp, l.cells)\n\t\t\tl.cells = temp\n\t\t} else {\n\t\t\tl.cells = l.cells[:len(l.rowStretchFactors)]\n\t\t}\n\t}\n\n\tfor i := 0; i < len(l.cells); i++ {\n\t\tif len(l.cells[i]) < len(l.columnStretchFactors) {\n\t\t\tif cap(l.cells[i]) < cap(l.columnStretchFactors) {\n\t\t\t\ttemp := make([]gridLayoutCell, len(l.columnStretchFactors))\n\t\t\t\tcopy(temp, l.cells[i])\n\t\t\t\tl.cells[i] = temp\n\t\t\t} else {\n\t\t\t\tl.cells[i] = l.cells[i][:len(l.columnStretchFactors)]\n\t\t\t}\n\t\t}\n\t}\n\n\t// FIXME: Not sure if this works.\n\tfor wb, info := range l.widgetBase2Info {\n\t\tl.widgetBase2Info[wb].cell = &l.cells[info.cell.row][info.cell.column]\n\t}\n}\n\nfunc (l *GridLayout) RowStretchFactor(row int) int {\n\tif row < 0 {\n\t\t// FIXME: Should we rather return an error?\n\t\treturn -1\n\t}\n\n\tif row >= len(l.rowStretchFactors) {\n\t\treturn 1\n\t}\n\n\treturn l.rowStretchFactors[row]\n}\n\nfunc (l *GridLayout) SetRowStretchFactor(row, factor int) error {\n\tif row < 0 {\n\t\treturn newError(\"row must be >= 0\")\n\t}\n\n\tif factor != l.RowStretchFactor(row) {\n\t\tif l.container == nil {\n\t\t\treturn newError(\"container required\")\n\t\t}\n\t\tif factor < 1 {\n\t\t\treturn newError(\"factor must be >= 1\")\n\t\t}\n\n\t\tl.ensureSufficientSize(row+1, len(l.columnStretchFactors))\n\n\t\tl.rowStretchFactors[row] = factor\n\n\t\tl.container.RequestLayout()\n\t}\n\n\treturn nil\n}\n\nfunc (l *GridLayout) ColumnStretchFactor(column int) int {\n\tif column < 0 {\n\t\t// FIXME: Should we rather return an error?\n\t\treturn -1\n\t}\n\n\tif column >= len(l.columnStretchFactors) {\n\t\treturn 1\n\t}\n\n\treturn l.columnStretchFactors[column]\n}\n\nfunc (l *GridLayout) SetColumnStretchFactor(column, factor int) error {\n\tif column < 0 {\n\t\treturn newError(\"column must be >= 0\")\n\t}\n\n\tif factor != l.ColumnStretchFactor(column) {\n\t\tif l.container == nil {\n\t\t\treturn newError(\"container required\")\n\t\t}\n\t\tif factor < 1 {\n\t\t\treturn newError(\"factor must be >= 1\")\n\t\t}\n\n\t\tl.ensureSufficientSize(len(l.rowStretchFactors), column+1)\n\n\t\tl.columnStretchFactors[column] = factor\n\n\t\tl.container.RequestLayout()\n\t}\n\n\treturn nil\n}\n\nfunc rangeFromGridLayoutWidgetInfo(info *gridLayoutWidgetInfo) Rectangle {\n\treturn Rectangle{\n\t\tX:      info.cell.column,\n\t\tY:      info.cell.row,\n\t\tWidth:  info.spanHorz,\n\t\tHeight: info.spanVert,\n\t}\n}\n\nfunc (l *GridLayout) setWidgetOnCells(widget Widget, r Rectangle) {\n\tvar wb *WidgetBase\n\tif widget != nil {\n\t\twb = widget.AsWidgetBase()\n\t}\n\n\tfor row := r.Y; row < r.Y+r.Height; row++ {\n\t\tfor col := r.X; col < r.X+r.Width; col++ {\n\t\t\tl.cells[row][col].widgetBase = wb\n\t\t}\n\t}\n}\n\nfunc (l *GridLayout) Range(widget Widget) (r Rectangle, ok bool) {\n\tif widget == nil {\n\t\treturn Rectangle{}, false\n\t}\n\n\tinfo := l.widgetBase2Info[widget.AsWidgetBase()]\n\n\tif info == nil ||\n\t\tl.container == nil ||\n\t\t!l.container.Children().containsHandle(widget.Handle()) {\n\t\treturn Rectangle{}, false\n\t}\n\n\treturn rangeFromGridLayoutWidgetInfo(info), true\n}\n\nfunc (l *GridLayout) SetRange(widget Widget, r Rectangle) error {\n\tif widget == nil {\n\t\treturn newError(\"widget required\")\n\t}\n\tif l.container == nil {\n\t\treturn newError(\"container required\")\n\t}\n\tif !l.container.Children().containsHandle(widget.Handle()) {\n\t\treturn newError(\"widget must be child of container\")\n\t}\n\tif r.X < 0 || r.Y < 0 {\n\t\treturn newError(\"range.X and range.Y must be >= 0\")\n\t}\n\tif r.Width < 1 || r.Height < 1 {\n\t\treturn newError(\"range.Width and range.Height must be >= 1\")\n\t}\n\n\twb := widget.AsWidgetBase()\n\n\tinfo := l.widgetBase2Info[wb]\n\tif info == nil {\n\t\tinfo = new(gridLayoutWidgetInfo)\n\t} else {\n\t\tl.setWidgetOnCells(nil, rangeFromGridLayoutWidgetInfo(info))\n\t}\n\n\tl.ensureSufficientSize(r.Y+r.Height, r.X+r.Width)\n\n\tcell := &l.cells[r.Y][r.X]\n\tcell.row = r.Y\n\tcell.column = r.X\n\n\tif info.cell == nil {\n\t\t// We have to do this _after_ calling ensureSufficientSize().\n\t\tl.widgetBase2Info[wb] = info\n\t}\n\n\tinfo.cell = cell\n\tinfo.spanHorz = r.Width\n\tinfo.spanVert = r.Height\n\n\tl.setWidgetOnCells(widget, r)\n\n\treturn nil\n}\n\nfunc (l *GridLayout) CreateLayoutItem(ctx *LayoutContext) ContainerLayoutItem {\n\twb2Item := make(map[*WidgetBase]LayoutItem)\n\n\tvar children []LayoutItem\n\n\tcells := make([][]gridLayoutItemCell, len(l.cells))\n\tfor row, srcCols := range l.cells {\n\t\tdstCols := make([]gridLayoutItemCell, len(srcCols))\n\t\tcells[row] = dstCols\n\n\t\tfor col, srcCell := range srcCols {\n\t\t\tdstCell := &dstCols[col]\n\n\t\t\tdstCell.row = row\n\t\t\tdstCell.column = col\n\t\t\tif srcCell.widgetBase != nil {\n\t\t\t\titem, ok := wb2Item[srcCell.widgetBase]\n\t\t\t\tif !ok {\n\t\t\t\t\titem = createLayoutItemForWidgetWithContext(srcCell.widgetBase.window.(Widget), ctx)\n\t\t\t\t\tchildren = append(children, item)\n\t\t\t\t\twb2Item[srcCell.widgetBase] = item\n\n\t\t\t\t}\n\t\t\t\tdstCell.item = item\n\t\t\t}\n\t\t}\n\t}\n\n\titem2Info := make(map[LayoutItem]*gridLayoutItemInfo, len(l.widgetBase2Info))\n\tfor wb, info := range l.widgetBase2Info {\n\t\titem := wb2Item[wb]\n\t\tvar cell *gridLayoutItemCell\n\t\tif info.cell != nil {\n\t\t\tcell = &cells[info.cell.row][info.cell.column]\n\t\t}\n\t\titem2Info[item] = &gridLayoutItemInfo{\n\t\t\tcell:     cell,\n\t\t\tspanHorz: info.spanHorz,\n\t\t\tspanVert: info.spanVert,\n\t\t\tminSize:  info.minSize,\n\t\t}\n\t}\n\n\treturn &gridLayoutItem{\n\t\tContainerLayoutItemBase: ContainerLayoutItemBase{\n\t\t\tchildren: children,\n\t\t},\n\t\tsize2MinSize:         make(map[Size]Size),\n\t\trowStretchFactors:    append([]int(nil), l.rowStretchFactors...),\n\t\tcolumnStretchFactors: append([]int(nil), l.columnStretchFactors...),\n\t\titem2Info:            item2Info,\n\t\tcells:                cells,\n\t}\n}\n\ntype gridLayoutItem struct {\n\tContainerLayoutItemBase\n\tmutex                sync.Mutex\n\tsize2MinSize         map[Size]Size // in native pixels\n\trowStretchFactors    []int\n\tcolumnStretchFactors []int\n\titem2Info            map[LayoutItem]*gridLayoutItemInfo\n\tcells                [][]gridLayoutItemCell\n\tminSize              Size // in native pixels\n}\n\ntype gridLayoutItemInfo struct {\n\tcell     *gridLayoutItemCell\n\tspanHorz int\n\tspanVert int\n\tminSize  Size // in native pixels\n}\n\ntype gridLayoutItemCell struct {\n\trow    int\n\tcolumn int\n\titem   LayoutItem\n}\n\nfunc (*gridLayoutItem) stretchFactorsTotal(stretchFactors []int) int {\n\ttotal := 0\n\n\tfor _, v := range stretchFactors {\n\t\ttotal += maxi(1, v)\n\t}\n\n\treturn total\n}\n\nfunc (li *gridLayoutItem) LayoutFlags() LayoutFlags {\n\tvar flags LayoutFlags\n\n\tif len(li.children) == 0 {\n\t\treturn ShrinkableHorz | ShrinkableVert | GrowableHorz | GrowableVert\n\t} else {\n\t\tfor _, item := range li.children {\n\t\t\tif s, ok := item.(*spacerLayoutItem); ok && s.greedyLocallyOnly || !shouldLayoutItem(item) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\twf := item.LayoutFlags()\n\n\t\t\tif wf&GreedyHorz != 0 && item.Geometry().MaxSize.Width > 0 {\n\t\t\t\twf &^= GreedyHorz\n\t\t\t}\n\t\t\tif wf&GreedyVert != 0 && item.Geometry().MaxSize.Height > 0 {\n\t\t\t\twf &^= GreedyVert\n\t\t\t}\n\n\t\t\tflags |= wf\n\t\t}\n\t}\n\n\treturn flags\n}\n\nfunc (li *gridLayoutItem) IdealSize() Size {\n\treturn li.MinSize()\n}\n\nfunc (li *gridLayoutItem) MinSize() Size {\n\tif len(li.cells) == 0 {\n\t\treturn Size{}\n\t}\n\n\treturn li.MinSizeForSize(li.geometry.ClientSize)\n}\n\nfunc (li *gridLayoutItem) HeightForWidth(width int) int {\n\treturn li.MinSizeForSize(Size{width, li.geometry.ClientSize.Height}).Height\n}\n\nfunc (li *gridLayoutItem) MinSizeForSize(size Size) Size {\n\tif len(li.cells) == 0 {\n\t\treturn Size{}\n\t}\n\n\tli.mutex.Lock()\n\tdefer li.mutex.Unlock()\n\n\tif min, ok := li.size2MinSize[size]; ok {\n\t\treturn min\n\t}\n\n\tws := make([]int, len(li.cells[0]))\n\n\tfor row := 0; row < len(li.cells); row++ {\n\t\tfor col := 0; col < len(ws); col++ {\n\t\t\titem := li.cells[row][col].item\n\t\t\tif item == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !shouldLayoutItem(item) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tmin := li.MinSizeEffectiveForChild(item)\n\t\t\tinfo := li.item2Info[item]\n\n\t\t\tif info.spanHorz == 1 {\n\t\t\t\tws[col] = maxi(ws[col], min.Width)\n\t\t\t}\n\t\t}\n\t}\n\n\twidths := li.sectionSizesForSpace(Horizontal, size.Width, nil)\n\theights := li.sectionSizesForSpace(Vertical, size.Height, widths)\n\n\tfor row := range heights {\n\t\tvar wg sync.WaitGroup\n\t\tvar mutex sync.Mutex\n\t\tvar maxHeight int\n\n\t\tfor col := range widths {\n\t\t\titem := li.cells[row][col].item\n\t\t\tif item == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !shouldLayoutItem(item) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif info := li.item2Info[item]; info.spanVert == 1 {\n\t\t\t\tif hfw, ok := item.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\t\t\t\twg.Add(1)\n\n\t\t\t\t\tgo func() {\n\t\t\t\t\t\theight := hfw.HeightForWidth(li.spannedWidth(info, widths))\n\n\t\t\t\t\t\tmutex.Lock()\n\t\t\t\t\t\tmaxHeight = maxi(maxHeight, height)\n\t\t\t\t\t\tmutex.Unlock()\n\n\t\t\t\t\t\twg.Done()\n\t\t\t\t\t}()\n\t\t\t\t} else {\n\t\t\t\t\theight := li.MinSizeEffectiveForChild(item).Height\n\n\t\t\t\t\tmutex.Lock()\n\t\t\t\t\tmaxHeight = maxi(maxHeight, height)\n\t\t\t\t\tmutex.Unlock()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\twg.Wait()\n\n\t\theights[row] = maxHeight\n\t}\n\n\tmargins := MarginsFrom96DPI(li.margins96dpi, li.ctx.dpi)\n\tspacing := IntFrom96DPI(li.spacing96dpi, li.ctx.dpi)\n\n\twidth := margins.HNear + margins.HFar\n\theight := margins.VNear + margins.VFar\n\n\tfor i, w := range ws {\n\t\tif w > 0 {\n\t\t\tif i > 0 {\n\t\t\t\twidth += spacing\n\t\t\t}\n\t\t\twidth += w\n\t\t}\n\t}\n\tfor i, h := range heights {\n\t\tif h > 0 {\n\t\t\tif i > 0 {\n\t\t\t\theight += spacing\n\t\t\t}\n\t\t\theight += h\n\t\t}\n\t}\n\n\tif width > 0 && height > 0 {\n\t\tli.size2MinSize[size] = Size{width, height}\n\t}\n\n\treturn Size{width, height}\n}\n\n// spannedWidth returns spanned width in native pixels.\nfunc (li *gridLayoutItem) spannedWidth(info *gridLayoutItemInfo, widths []int) int {\n\tspacing := IntFrom96DPI(li.spacing96dpi, li.ctx.dpi)\n\n\tvar width int\n\n\tfor i := info.cell.column; i < info.cell.column+info.spanHorz; i++ {\n\t\tif w := widths[i]; w > 0 {\n\t\t\twidth += w\n\t\t\tif i > info.cell.column {\n\t\t\t\twidth += spacing\n\t\t\t}\n\t\t}\n\t}\n\n\treturn width\n}\n\n// spannedHeight returns spanned height in native pixels.\nfunc (li *gridLayoutItem) spannedHeight(info *gridLayoutItemInfo, heights []int) int {\n\tspacing := IntFrom96DPI(li.spacing96dpi, li.ctx.dpi)\n\n\tvar height int\n\n\tfor i := info.cell.row; i < info.cell.row+info.spanVert; i++ {\n\t\tif h := heights[i]; h > 0 {\n\t\t\theight += h\n\t\t\tif i > info.cell.row {\n\t\t\t\theight += spacing\n\t\t\t}\n\t\t}\n\t}\n\n\treturn height\n}\n\ntype gridLayoutSectionInfo struct {\n\tindex              int\n\tminSize            int // in native pixels\n\tmaxSize            int // in native pixels\n\tstretch            int\n\thasGreedyNonSpacer bool\n\thasGreedySpacer    bool\n}\n\ntype gridLayoutSectionInfoList []gridLayoutSectionInfo\n\nfunc (l gridLayoutSectionInfoList) Len() int {\n\treturn len(l)\n}\n\nfunc (l gridLayoutSectionInfoList) Less(i, j int) bool {\n\tif l[i].hasGreedyNonSpacer == l[j].hasGreedyNonSpacer {\n\t\tif l[i].hasGreedySpacer == l[j].hasGreedySpacer {\n\t\t\tminDiff := l[i].minSize - l[j].minSize\n\n\t\t\tif minDiff == 0 {\n\t\t\t\treturn l[i].maxSize/l[i].stretch < l[j].maxSize/l[j].stretch\n\t\t\t}\n\n\t\t\treturn minDiff > 0\n\t\t}\n\n\t\treturn l[i].hasGreedySpacer\n\t}\n\n\treturn l[i].hasGreedyNonSpacer\n}\n\nfunc (l gridLayoutSectionInfoList) Swap(i, j int) {\n\tl[i], l[j] = l[j], l[i]\n}\n\nfunc (li *gridLayoutItem) PerformLayout() []LayoutResultItem {\n\twidths := li.sectionSizesForSpace(Horizontal, li.geometry.ClientSize.Width, nil)\n\theights := li.sectionSizesForSpace(Vertical, li.geometry.ClientSize.Height, widths)\n\n\titems := make([]LayoutResultItem, 0, len(li.item2Info))\n\n\tmargins := MarginsFrom96DPI(li.margins96dpi, li.ctx.dpi)\n\tspacing := IntFrom96DPI(li.spacing96dpi, li.ctx.dpi)\n\n\tfor item, info := range li.item2Info {\n\t\tif !shouldLayoutItem(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\tx := margins.HNear\n\t\tfor i := 0; i < info.cell.column; i++ {\n\t\t\tif w := widths[i]; w > 0 {\n\t\t\t\tx += w + spacing\n\t\t\t}\n\t\t}\n\n\t\ty := margins.VNear\n\t\tfor i := 0; i < info.cell.row; i++ {\n\t\t\tif h := heights[i]; h > 0 {\n\t\t\t\ty += h + spacing\n\t\t\t}\n\t\t}\n\n\t\twidth := li.spannedWidth(info, widths)\n\t\theight := li.spannedHeight(info, heights)\n\n\t\tw := width\n\t\th := height\n\n\t\tif lf := item.LayoutFlags(); lf&GrowableHorz == 0 || lf&GrowableVert == 0 {\n\t\t\tvar s Size\n\t\t\tif hfw, ok := item.(HeightForWidther); !ok || !hfw.HasHeightForWidth() {\n\t\t\t\tif is, ok := item.(IdealSizer); ok {\n\t\t\t\t\ts = is.IdealSize()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmax := item.Geometry().MaxSize\n\t\t\tif max.Width > 0 && s.Width > max.Width {\n\t\t\t\ts.Width = max.Width\n\t\t\t}\n\t\t\tif lf&GrowableHorz == 0 {\n\t\t\t\tw = s.Width\n\t\t\t}\n\t\t\tw = mini(w, width)\n\n\t\t\tif hfw, ok := item.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\t\t\th = hfw.HeightForWidth(w)\n\t\t\t} else {\n\t\t\t\tif max.Height > 0 && s.Height > max.Height {\n\t\t\t\t\ts.Height = max.Height\n\t\t\t\t}\n\t\t\t\tif lf&GrowableVert == 0 {\n\t\t\t\t\th = s.Height\n\t\t\t\t}\n\t\t\t}\n\t\t\th = mini(h, height)\n\t\t}\n\n\t\talignment := item.Geometry().Alignment\n\t\tif alignment == AlignHVDefault {\n\t\t\talignment = li.alignment\n\t\t}\n\n\t\tif w != width {\n\t\t\tswitch alignment {\n\t\t\tcase AlignHCenterVNear, AlignHCenterVCenter, AlignHCenterVFar:\n\t\t\t\tx += (width - w) / 2\n\n\t\t\tcase AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar:\n\t\t\t\tx += width - w\n\t\t\t}\n\t\t}\n\n\t\tif h != height {\n\t\t\tswitch alignment {\n\t\t\tcase AlignHNearVCenter, AlignHCenterVCenter, AlignHFarVCenter:\n\t\t\t\ty += (height - h) / 2\n\n\t\t\tcase AlignHNearVFar, AlignHCenterVFar, AlignHFarVFar:\n\t\t\t\ty += height - h\n\t\t\t}\n\t\t}\n\n\t\titems = append(items, LayoutResultItem{Item: item, Bounds: Rectangle{X: x, Y: y, Width: w, Height: h}})\n\t}\n\n\treturn items\n}\n\n// sectionSizesForSpace returns section sizes. Input and outpus is measured in native pixels.\nfunc (li *gridLayoutItem) sectionSizesForSpace(orientation Orientation, space int, widths []int) []int {\n\tvar stretchFactors []int\n\tif orientation == Horizontal {\n\t\tstretchFactors = li.columnStretchFactors\n\t} else {\n\t\tstretchFactors = li.rowStretchFactors\n\t}\n\n\tvar sectionCountWithGreedyNonSpacer int\n\tvar sectionCountWithGreedySpacer int\n\tvar stretchFactorsTotal [3]int\n\tvar minSizesRemaining int\n\tminSizes := make([]int, len(stretchFactors))\n\tmaxSizes := make([]int, len(stretchFactors))\n\tsizes := make([]int, len(stretchFactors))\n\tsortedSections := gridLayoutSectionInfoList(make([]gridLayoutSectionInfo, len(stretchFactors)))\n\n\tfor i := 0; i < len(stretchFactors); i++ {\n\t\tvar otherAxisCount int\n\t\tif orientation == Horizontal {\n\t\t\totherAxisCount = len(li.rowStretchFactors)\n\t\t} else {\n\t\t\totherAxisCount = len(li.columnStretchFactors)\n\t\t}\n\n\t\tfor j := 0; j < otherAxisCount; j++ {\n\t\t\tvar item LayoutItem\n\t\t\tif orientation == Horizontal {\n\t\t\t\titem = li.cells[j][i].item\n\t\t\t} else {\n\t\t\t\titem = li.cells[i][j].item\n\t\t\t}\n\n\t\t\tif item == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !shouldLayoutItem(item) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tinfo := li.item2Info[item]\n\t\t\tflags := item.LayoutFlags()\n\n\t\t\tmax := item.Geometry().MaxSize\n\n\t\t\tvar pref Size\n\t\t\tif hfw, ok := item.(HeightForWidther); !ok || !hfw.HasHeightForWidth() {\n\t\t\t\tif is, ok := item.(IdealSizer); ok {\n\t\t\t\t\tpref = is.IdealSize()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif orientation == Horizontal {\n\t\t\t\tif info.spanHorz == 1 {\n\t\t\t\t\tminSizes[i] = maxi(minSizes[i], li.MinSizeEffectiveForChild(item).Width)\n\t\t\t\t}\n\n\t\t\t\tif max.Width > 0 {\n\t\t\t\t\tmaxSizes[i] = maxi(maxSizes[i], max.Width)\n\t\t\t\t} else if pref.Width > 0 && flags&GrowableHorz == 0 {\n\t\t\t\t\tmaxSizes[i] = maxi(maxSizes[i], pref.Width)\n\t\t\t\t} else {\n\t\t\t\t\tmaxSizes[i] = 32768\n\t\t\t\t}\n\n\t\t\t\tif info.spanHorz == 1 && flags&GreedyHorz > 0 {\n\t\t\t\t\tif _, isSpacer := item.(*spacerLayoutItem); isSpacer {\n\t\t\t\t\t\tsortedSections[i].hasGreedySpacer = true\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsortedSections[i].hasGreedyNonSpacer = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif info.spanVert == 1 {\n\t\t\t\t\tif hfw, ok := item.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\t\t\t\t\tminSizes[i] = maxi(minSizes[i], hfw.HeightForWidth(li.spannedWidth(info, widths)))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tminSizes[i] = maxi(minSizes[i], li.MinSizeEffectiveForChild(item).Height)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif max.Height > 0 {\n\t\t\t\t\tmaxSizes[i] = maxi(maxSizes[i], max.Height)\n\t\t\t\t} else if hfw, ok := item.(HeightForWidther); ok && flags&GrowableVert == 0 && hfw.HasHeightForWidth() {\n\t\t\t\t\tmaxSizes[i] = minSizes[i]\n\t\t\t\t} else if pref.Height > 0 && flags&GrowableVert == 0 {\n\t\t\t\t\tmaxSizes[i] = maxi(maxSizes[i], pref.Height)\n\t\t\t\t} else {\n\t\t\t\t\tmaxSizes[i] = 32768\n\t\t\t\t}\n\n\t\t\t\tif info.spanVert == 1 && flags&GreedyVert > 0 {\n\t\t\t\t\tif _, isSpacer := item.(*spacerLayoutItem); isSpacer {\n\t\t\t\t\t\tsortedSections[i].hasGreedySpacer = true\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsortedSections[i].hasGreedyNonSpacer = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsortedSections[i].index = i\n\t\tsortedSections[i].minSize = minSizes[i]\n\t\tsortedSections[i].maxSize = maxSizes[i]\n\t\tsortedSections[i].stretch = maxi(1, stretchFactors[i])\n\n\t\tminSizesRemaining += minSizes[i]\n\n\t\tif sortedSections[i].hasGreedyNonSpacer {\n\t\t\tsectionCountWithGreedyNonSpacer++\n\t\t\tstretchFactorsTotal[0] += stretchFactors[i]\n\t\t} else if sortedSections[i].hasGreedySpacer {\n\t\t\tsectionCountWithGreedySpacer++\n\t\t\tstretchFactorsTotal[1] += stretchFactors[i]\n\t\t} else {\n\t\t\tstretchFactorsTotal[2] += stretchFactors[i]\n\t\t}\n\t}\n\n\tsort.Stable(sortedSections)\n\n\tmargins := MarginsFrom96DPI(li.margins96dpi, li.ctx.dpi)\n\tspacing := IntFrom96DPI(li.spacing96dpi, li.ctx.dpi)\n\n\tif orientation == Horizontal {\n\t\tspace -= margins.HNear + margins.HFar\n\t} else {\n\t\tspace -= margins.VNear + margins.VFar\n\t}\n\n\tvar spacingRemaining int\n\tfor _, max := range maxSizes {\n\t\tif max > 0 {\n\t\t\tspacingRemaining += spacing\n\t\t}\n\t}\n\tif spacingRemaining > 0 {\n\t\tspacingRemaining -= spacing\n\t}\n\n\toffsets := [3]int{0, sectionCountWithGreedyNonSpacer, sectionCountWithGreedyNonSpacer + sectionCountWithGreedySpacer}\n\tcounts := [3]int{sectionCountWithGreedyNonSpacer, sectionCountWithGreedySpacer, len(stretchFactors) - sectionCountWithGreedyNonSpacer - sectionCountWithGreedySpacer}\n\n\tfor i := 0; i < 3; i++ {\n\t\tstretchFactorsRemaining := stretchFactorsTotal[i]\n\n\t\tfor j := 0; j < counts[i]; j++ {\n\t\t\tinfo := sortedSections[offsets[i]+j]\n\t\t\tk := info.index\n\n\t\t\tstretch := stretchFactors[k]\n\t\t\tmin := info.minSize\n\t\t\tmax := info.maxSize\n\t\t\tsize := min\n\n\t\t\tif min < max {\n\t\t\t\texcessSpace := float64(space - minSizesRemaining - spacingRemaining)\n\n\t\t\t\tsize += int(excessSpace * float64(stretch) / float64(stretchFactorsRemaining))\n\t\t\t\tif size < min {\n\t\t\t\t\tsize = min\n\t\t\t\t} else if size > max {\n\t\t\t\t\tsize = max\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsizes[k] = size\n\n\t\t\tminSizesRemaining -= min\n\t\t\tstretchFactorsRemaining -= stretch\n\n\t\t\tspace -= (size + spacing)\n\t\t\tspacingRemaining -= spacing\n\t\t}\n\t}\n\n\treturn sizes\n}\n"
  },
  {
    "path": "groupbox.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst groupBoxWindowClass = `\\o/ Walk_GroupBox_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(groupBoxWindowClass)\n\t})\n}\n\ntype GroupBox struct {\n\tWidgetBase\n\thWndGroupBox          win.HWND\n\tcheckBox              *CheckBox\n\tcomposite             *Composite\n\theaderHeight          int // in native pixels\n\ttitleChangedPublisher EventPublisher\n}\n\nfunc NewGroupBox(parent Container) (*GroupBox, error) {\n\tgb := new(GroupBox)\n\n\tif err := InitWidget(\n\t\tgb,\n\t\tparent,\n\t\tgroupBoxWindowClass,\n\t\twin.WS_VISIBLE,\n\t\twin.WS_EX_CONTROLPARENT); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tgb.Dispose()\n\t\t}\n\t}()\n\n\tgb.hWndGroupBox = win.CreateWindowEx(\n\t\t0, syscall.StringToUTF16Ptr(\"BUTTON\"), nil,\n\t\twin.WS_CHILD|win.WS_VISIBLE|win.BS_GROUPBOX,\n\t\t0, 0, 80, 24, gb.hWnd, 0, 0, nil)\n\tif gb.hWndGroupBox == 0 {\n\t\treturn nil, lastError(\"CreateWindowEx(BUTTON)\")\n\t}\n\twin.SetWindowLong(gb.hWndGroupBox, win.GWL_ID, 1)\n\n\tgb.applyFont(gb.Font())\n\tgb.updateHeaderHeight()\n\n\tvar err error\n\n\tgb.checkBox, err = NewCheckBox(gb)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\twin.SetWindowLong(gb.checkBox.hWnd, win.GWL_ID, 2)\n\n\tgb.SetCheckable(false)\n\tgb.checkBox.SetChecked(true)\n\n\tgb.checkBox.CheckedChanged().Attach(func() {\n\t\tgb.applyEnabledFromCheckBox(gb.checkBox.Checked())\n\t})\n\n\tsetWindowVisible(gb.checkBox.hWnd, false)\n\n\tgb.composite, err = NewComposite(gb)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\twin.SetWindowLong(gb.composite.hWnd, win.GWL_ID, 3)\n\tgb.composite.name = \"composite\"\n\n\twin.SetWindowPos(gb.checkBox.hWnd, win.HWND_TOP, 0, 0, 0, 0, win.SWP_NOMOVE|win.SWP_NOSIZE)\n\n\tgb.SetBackground(NullBrush())\n\n\tgb.MustRegisterProperty(\"Title\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn gb.Title()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn gb.SetTitle(assertStringOr(v, \"\"))\n\t\t},\n\t\tgb.titleChangedPublisher.Event()))\n\n\tgb.MustRegisterProperty(\"Checked\", NewBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn gb.Checked()\n\t\t},\n\t\tfunc(v bool) error {\n\t\t\tgb.SetChecked(v)\n\t\t\treturn nil\n\t\t},\n\t\tgb.CheckedChanged()))\n\n\tsucceeded = true\n\n\treturn gb, nil\n}\n\nfunc (gb *GroupBox) AsContainerBase() *ContainerBase {\n\tif gb.composite == nil {\n\t\treturn nil\n\t}\n\n\treturn gb.composite.AsContainerBase()\n}\n\nfunc (gb *GroupBox) ClientBoundsPixels() Rectangle {\n\tcb := windowClientBounds(gb.hWndGroupBox)\n\n\tif gb.Layout() == nil {\n\t\treturn cb\n\t}\n\n\tif gb.Checkable() {\n\t\ts := createLayoutItemForWidget(gb.checkBox).(MinSizer).MinSize()\n\n\t\tcb.Y += s.Height\n\t\tcb.Height -= s.Height\n\t}\n\n\tpadding := gb.IntFrom96DPI(1)\n\treturn Rectangle{cb.X + padding, cb.Y + gb.headerHeight, cb.Width - 2*padding, cb.Height - gb.headerHeight - 2*padding}\n}\n\nfunc (gb *GroupBox) updateHeaderHeight() {\n\tgb.headerHeight = gb.calculateTextSizeImpl(\"gM\").Height\n}\n\nfunc (gb *GroupBox) Persistent() bool {\n\treturn gb.composite.Persistent()\n}\n\nfunc (gb *GroupBox) SetPersistent(value bool) {\n\tgb.composite.SetPersistent(value)\n}\n\nfunc (gb *GroupBox) SaveState() error {\n\treturn gb.composite.SaveState()\n}\n\nfunc (gb *GroupBox) RestoreState() error {\n\treturn gb.composite.RestoreState()\n}\n\nfunc (gb *GroupBox) applyEnabled(enabled bool) {\n\tgb.WidgetBase.applyEnabled(enabled)\n\n\tif gb.hWndGroupBox != 0 {\n\t\tsetWindowEnabled(gb.hWndGroupBox, enabled)\n\t}\n\n\tif gb.checkBox != nil {\n\t\tgb.checkBox.applyEnabled(enabled)\n\t}\n\n\tif gb.composite != nil {\n\t\tgb.composite.applyEnabled(enabled)\n\t}\n}\n\nfunc (gb *GroupBox) applyEnabledFromCheckBox(enabled bool) {\n\tif gb.hWndGroupBox != 0 {\n\t\tsetWindowEnabled(gb.hWndGroupBox, enabled)\n\t}\n\n\tif gb.composite != nil {\n\t\tgb.composite.applyEnabled(enabled)\n\t}\n}\n\nfunc (gb *GroupBox) applyFont(font *Font) {\n\tgb.WidgetBase.applyFont(font)\n\n\tif gb.checkBox != nil {\n\t\tgb.checkBox.applyFont(font)\n\t}\n\n\tif gb.hWndGroupBox != 0 {\n\t\tSetWindowFont(gb.hWndGroupBox, font)\n\t}\n\n\tif gb.composite != nil {\n\t\tgb.composite.applyFont(font)\n\t}\n\n\tgb.updateHeaderHeight()\n}\n\nfunc (gb *GroupBox) SetSuspended(suspend bool) {\n\tgb.composite.SetSuspended(suspend)\n\tgb.WidgetBase.SetSuspended(suspend)\n\tgb.Invalidate()\n}\n\nfunc (gb *GroupBox) DataBinder() *DataBinder {\n\treturn gb.composite.dataBinder\n}\n\nfunc (gb *GroupBox) SetDataBinder(dataBinder *DataBinder) {\n\tgb.composite.SetDataBinder(dataBinder)\n}\n\nfunc (gb *GroupBox) Title() string {\n\tif gb.Checkable() {\n\t\treturn gb.checkBox.Text()\n\t}\n\n\treturn windowText(gb.hWndGroupBox)\n}\n\nfunc (gb *GroupBox) SetTitle(title string) error {\n\tif gb.Checkable() {\n\t\tif err := setWindowText(gb.hWndGroupBox, \"\"); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn gb.checkBox.SetText(title)\n\t}\n\n\treturn setWindowText(gb.hWndGroupBox, title)\n}\n\nfunc (gb *GroupBox) Checkable() bool {\n\treturn gb.checkBox.visible\n}\n\nfunc (gb *GroupBox) SetCheckable(checkable bool) {\n\ttitle := gb.Title()\n\n\tgb.checkBox.SetVisible(checkable)\n\n\tgb.SetTitle(title)\n\n\tgb.RequestLayout()\n}\n\nfunc (gb *GroupBox) Checked() bool {\n\treturn gb.checkBox.Checked()\n}\n\nfunc (gb *GroupBox) SetChecked(checked bool) {\n\tgb.checkBox.SetChecked(checked)\n}\n\nfunc (gb *GroupBox) CheckedChanged() *Event {\n\treturn gb.checkBox.CheckedChanged()\n}\n\nfunc (gb *GroupBox) ApplyDPI(dpi int) {\n\tgb.WidgetBase.ApplyDPI(dpi)\n\tif gb.checkBox != nil {\n\t\tgb.checkBox.ApplyDPI(dpi)\n\t}\n\tif gb.composite != nil {\n\t\tgb.composite.ApplyDPI(dpi)\n\t}\n}\n\nfunc (gb *GroupBox) Children() *WidgetList {\n\tif gb.composite == nil {\n\t\t// Without this we would get into trouble in NewComposite.\n\t\treturn nil\n\t}\n\n\treturn gb.composite.Children()\n}\n\nfunc (gb *GroupBox) Layout() Layout {\n\tif gb.composite == nil {\n\t\t// Without this we would get into trouble through the call to\n\t\t// SetCheckable in NewGroupBox.\n\t\treturn nil\n\t}\n\n\treturn gb.composite.Layout()\n}\n\nfunc (gb *GroupBox) SetLayout(value Layout) error {\n\treturn gb.composite.SetLayout(value)\n}\n\nfunc (gb *GroupBox) MouseDown() *MouseEvent {\n\treturn gb.composite.MouseDown()\n}\n\nfunc (gb *GroupBox) MouseMove() *MouseEvent {\n\treturn gb.composite.MouseMove()\n}\n\nfunc (gb *GroupBox) MouseUp() *MouseEvent {\n\treturn gb.composite.MouseUp()\n}\n\nfunc (gb *GroupBox) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tif gb.composite != nil {\n\t\tswitch msg {\n\t\tcase win.WM_CTLCOLORSTATIC:\n\t\t\tif hBrush := gb.handleWMCTLCOLOR(wParam, lParam); hBrush != 0 {\n\t\t\t\treturn hBrush\n\t\t\t}\n\n\t\tcase win.WM_COMMAND:\n\t\t\thwndSrc := win.GetDlgItem(gb.hWnd, int32(win.LOWORD(uint32(wParam))))\n\n\t\t\tif window := windowFromHandle(hwndSrc); window != nil {\n\t\t\t\twindow.WndProc(hwnd, msg, wParam, lParam)\n\t\t\t}\n\n\t\tcase win.WM_NOTIFY:\n\t\t\tgb.composite.WndProc(hwnd, msg, wParam, lParam)\n\n\t\tcase win.WM_SETTEXT:\n\t\t\tgb.titleChangedPublisher.Publish()\n\n\t\tcase win.WM_PAINT:\n\t\t\twin.UpdateWindow(gb.checkBox.hWnd)\n\n\t\tcase win.WM_WINDOWPOSCHANGED:\n\t\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\twbcb := gb.WidgetBase.ClientBoundsPixels()\n\t\t\tif !win.MoveWindow(\n\t\t\t\tgb.hWndGroupBox,\n\t\t\t\tint32(wbcb.X),\n\t\t\t\tint32(wbcb.Y),\n\t\t\t\tint32(wbcb.Width),\n\t\t\t\tint32(wbcb.Height),\n\t\t\t\ttrue) {\n\n\t\t\t\tlastError(\"MoveWindow\")\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif gb.Checkable() {\n\t\t\t\ts := createLayoutItemForWidget(gb.checkBox).(MinSizer).MinSize()\n\t\t\t\tvar x int\n\t\t\t\tif l := gb.Layout(); l != nil {\n\t\t\t\t\tx = gb.IntFrom96DPI(l.Margins().HNear)\n\t\t\t\t} else {\n\t\t\t\t\tx = gb.headerHeight * 2 / 3\n\t\t\t\t}\n\t\t\t\tgb.checkBox.SetBoundsPixels(Rectangle{x, gb.headerHeight, s.Width, s.Height})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn gb.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (gb *GroupBox) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tcompositePos := Point{gb.IntFrom96DPI(1), gb.headerHeight}\n\tif gb.Checkable() {\n\t\tidealSize := gb.checkBox.idealSize()\n\n\t\tcompositePos.Y += idealSize.Height\n\t}\n\n\tli := &groupBoxLayoutItem{\n\t\tcompositePos: compositePos,\n\t}\n\n\tgbli := CreateLayoutItemsForContainerWithContext(gb.composite, ctx)\n\tgbli.AsLayoutItemBase().parent = li\n\n\tli.children = append(li.children, gbli)\n\n\treturn li\n}\n\ntype groupBoxLayoutItem struct {\n\tContainerLayoutItemBase\n\tcompositePos Point // in native pixels\n}\n\nfunc (li *groupBoxLayoutItem) LayoutFlags() LayoutFlags {\n\treturn li.children[0].LayoutFlags()\n}\n\nfunc (li *groupBoxLayoutItem) MinSize() Size {\n\tmin := li.children[0].(MinSizer).MinSize()\n\tmin.Width += li.compositePos.X * 2\n\tmin.Height += li.compositePos.Y + 2\n\n\treturn min\n}\n\nfunc (li *groupBoxLayoutItem) MinSizeForSize(size Size) Size {\n\treturn li.MinSize()\n}\n\nfunc (li *groupBoxLayoutItem) HasHeightForWidth() bool {\n\treturn li.children[0].(HeightForWidther).HasHeightForWidth()\n}\n\nfunc (li *groupBoxLayoutItem) HeightForWidth(width int) int {\n\treturn li.children[0].(HeightForWidther).HeightForWidth(width-li.compositePos.X*2) + li.compositePos.Y\n}\n\nfunc (li *groupBoxLayoutItem) IdealSize() Size {\n\tsize := li.children[0].(IdealSizer).IdealSize()\n\tsize.Height += li.compositePos.Y\n\treturn size\n}\n\nfunc (li *groupBoxLayoutItem) PerformLayout() []LayoutResultItem {\n\treturn []LayoutResultItem{\n\t\t{\n\t\t\tItem:   li.children[0],\n\t\t\tBounds: Rectangle{X: li.compositePos.X, Y: li.compositePos.Y, Width: li.geometry.Size.Width - li.compositePos.X*2, Height: li.geometry.Size.Height - li.compositePos.Y - 4},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "icon.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"image\"\n\t\"path/filepath\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\n\t\"github.com/lxn/win\"\n)\n\n// Icon is a bitmap that supports transparency and combining multiple\n// variants of an image in different resolutions.\ntype Icon struct {\n\tfilePath  string\n\tindex     int\n\tres       *uint16\n\tdpi2hIcon map[int]win.HICON\n\tsize96dpi Size\n\tisStock   bool\n\thasIndex  bool\n}\n\ntype ExtractableIcon interface {\n\tFilePath_() string\n\tIndex_() int\n\tSize_() int\n}\n\nfunc IconFrom(src interface{}, dpi int) (*Icon, error) {\n\tif src == nil {\n\t\treturn nil, nil\n\t}\n\n\timg, err := ImageFrom(src)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn iconCache.Icon(img, dpi)\n}\n\nfunc IconApplication() *Icon {\n\treturn stockIcon(win.IDI_APPLICATION)\n}\n\nfunc IconError() *Icon {\n\treturn stockIcon(win.IDI_ERROR)\n}\n\nfunc IconQuestion() *Icon {\n\treturn stockIcon(win.IDI_QUESTION)\n}\n\nfunc IconWarning() *Icon {\n\treturn stockIcon(win.IDI_WARNING)\n}\n\nfunc IconInformation() *Icon {\n\treturn stockIcon(win.IDI_INFORMATION)\n}\n\nfunc IconWinLogo() *Icon {\n\treturn stockIcon(win.IDI_WINLOGO)\n}\n\nfunc IconShield() *Icon {\n\treturn stockIcon(win.IDI_SHIELD)\n}\n\nfunc stockIcon(id uintptr) *Icon {\n\treturn &Icon{res: win.MAKEINTRESOURCE(id), size96dpi: defaultIconSize(), isStock: true}\n}\n\n// NewIconFromFile returns a new Icon, using the specified icon image file and default size.\nfunc NewIconFromFile(filePath string) (*Icon, error) {\n\treturn NewIconFromFileWithSize(filePath, Size{})\n}\n\n// NewIconFromFileWithSize returns a new Icon, using the specified icon image file and size.\nfunc NewIconFromFileWithSize(filePath string, size Size) (*Icon, error) {\n\tif size.Width == 0 || size.Height == 0 {\n\t\tsize = defaultIconSize()\n\t}\n\n\treturn checkNewIcon(&Icon{filePath: filePath, size96dpi: size})\n}\n\n// NewIconFromResource returns a new Icon of default size, using the specified icon resource.\nfunc NewIconFromResource(name string) (*Icon, error) {\n\treturn NewIconFromResourceWithSize(name, Size{})\n}\n\n// NewIconFromResourceWithSize returns a new Icon of size size, using the specified icon resource.\nfunc NewIconFromResourceWithSize(name string, size Size) (*Icon, error) {\n\treturn newIconFromResource(syscall.StringToUTF16Ptr(name), size)\n}\n\n// NewIconFromResourceId returns a new Icon of default size, using the specified icon resource.\nfunc NewIconFromResourceId(id int) (*Icon, error) {\n\treturn NewIconFromResourceIdWithSize(id, Size{})\n}\n\n// NewIconFromResourceIdWithSize returns a new Icon of size size, using the specified icon resource.\nfunc NewIconFromResourceIdWithSize(id int, size Size) (*Icon, error) {\n\treturn newIconFromResource(win.MAKEINTRESOURCE(uintptr(id)), size)\n}\n\nfunc newIconFromResource(res *uint16, size Size) (*Icon, error) {\n\tif size.Width == 0 || size.Height == 0 {\n\t\tsize = defaultIconSize()\n\t}\n\n\treturn checkNewIcon(&Icon{res: res, size96dpi: size})\n}\n\n// NewIconFromSysDLL returns a new Icon, as identified by index of\n// size 16x16 from the system DLL identified by dllBaseName.\nfunc NewIconFromSysDLL(dllBaseName string, index int) (*Icon, error) {\n\treturn NewIconFromSysDLLWithSize(dllBaseName, index, 16)\n}\n\n// NewIconFromSysDLLWithSize returns a new Icon, as identified by\n// index of the desired size from the system DLL identified by dllBaseName.\nfunc NewIconFromSysDLLWithSize(dllBaseName string, index, size int) (*Icon, error) {\n\tsystem32, err := windows.GetSystemDirectory()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn checkNewIcon(&Icon{filePath: filepath.Join(system32, dllBaseName+\".dll\"), index: index, hasIndex: true, size96dpi: Size{size, size}})\n}\n\n// NewIconExtractedFromFile returns a new Icon, as identified by index of size 16x16 from filePath.\nfunc NewIconExtractedFromFile(filePath string, index, _ int) (*Icon, error) {\n\treturn checkNewIcon(&Icon{filePath: filePath, index: index, hasIndex: true, size96dpi: Size{16, 16}})\n}\n\n// NewIconExtractedFromFileWithSize returns a new Icon, as identified by index of the desired size from filePath.\nfunc NewIconExtractedFromFileWithSize(filePath string, index, size int) (*Icon, error) {\n\treturn checkNewIcon(&Icon{filePath: filePath, index: index, hasIndex: true, size96dpi: Size{size, size}})\n}\n\n// NewIconFromImage returns a new Icon at 96dpi, using the specified image.Image as source.\n//\n// Deprecated: Newer applications should use NewIconFromImageForDPI.\nfunc NewIconFromImage(im image.Image) (ic *Icon, err error) {\n\treturn NewIconFromImageForDPI(im, 96)\n}\n\n// NewIconFromImageForDPI returns a new Icon at given DPI, using the specified image.Image as source.\nfunc NewIconFromImageForDPI(im image.Image, dpi int) (ic *Icon, err error) {\n\thIcon, err := createAlphaCursorOrIconFromImage(im, image.Pt(0, 0), true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tb := im.Bounds()\n\treturn newIconFromHICONAndSize(hIcon, SizeTo96DPI(Size{b.Dx(), b.Dy()}, dpi), dpi), nil\n}\n\n// NewIconFromImageWithSize returns a new Icon of the given size in native pixels, using the\n// specified Image as source.\nfunc NewIconFromImageWithSize(image Image, size Size) (*Icon, error) {\n\tbmp, err := NewBitmapFromImageWithSize(image, size)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn NewIconFromBitmap(bmp)\n}\n\nfunc newIconFromImageForDPI(image Image, dpi int) (*Icon, error) {\n\tsize96dpi := image.Size()\n\tsize := SizeFrom96DPI(size96dpi, dpi)\n\n\tbmp, err := NewBitmapFromImageWithSize(image, size)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\thIcon, err := createAlphaCursorOrIconFromBitmap(bmp, Point{}, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Icon{dpi2hIcon: map[int]win.HICON{dpi: hIcon}, size96dpi: size96dpi}, nil\n}\n\n// NewIconFromBitmap returns a new Icon, using the specified Bitmap as source.\nfunc NewIconFromBitmap(bmp *Bitmap) (ic *Icon, err error) {\n\thIcon, err := createAlphaCursorOrIconFromBitmap(bmp, Point{}, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn newIconFromHICONAndSize(hIcon, bmp.Size(), bmp.dpi), nil\n}\n\n// NewIconFromHICON returns a new Icon at 96dpi, using the specified win.HICON as source.\n//\n// Deprecated: Newer applications should use NewIconFromHICONForDPI.\nfunc NewIconFromHICON(hIcon win.HICON) (ic *Icon, err error) {\n\treturn NewIconFromHICONForDPI(hIcon, 96)\n}\n\n// NewIconFromHICONForDPI returns a new Icon at given DPI, using the specified win.HICON as source.\nfunc NewIconFromHICONForDPI(hIcon win.HICON, dpi int) (ic *Icon, err error) {\n\ts, err := sizeFromHICON(hIcon)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn newIconFromHICONAndSize(hIcon, SizeTo96DPI(s, dpi), dpi), nil\n}\n\nfunc newIconFromHICONAndSize(hIcon win.HICON, size Size, dpi int) *Icon {\n\treturn &Icon{dpi2hIcon: map[int]win.HICON{dpi: hIcon}, size96dpi: size}\n}\n\nfunc checkNewIcon(icon *Icon) (*Icon, error) {\n\tif _, err := icon.handleForDPIWithError(96); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn icon, nil\n}\n\nfunc (i *Icon) handleForDPI(dpi int) win.HICON {\n\thIcon, _ := i.handleForDPIWithError(dpi)\n\treturn hIcon\n}\n\nfunc (i *Icon) handleForDPIWithError(dpi int) (win.HICON, error) {\n\tif i.dpi2hIcon == nil {\n\t\ti.dpi2hIcon = make(map[int]win.HICON)\n\t} else if handle, ok := i.dpi2hIcon[dpi]; ok {\n\t\treturn handle, nil\n\t}\n\n\tvar hInst win.HINSTANCE\n\tvar name *uint16\n\tif i.filePath != \"\" {\n\t\tabsFilePath, err := filepath.Abs(i.filePath)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tname = syscall.StringToUTF16Ptr(absFilePath)\n\t} else {\n\t\tif !i.isStock {\n\t\t\tif hInst = win.GetModuleHandle(nil); hInst == 0 {\n\t\t\t\treturn 0, lastError(\"GetModuleHandle\")\n\t\t\t}\n\t\t}\n\n\t\tname = i.res\n\t}\n\n\tvar size Size\n\tif i.size96dpi.Width == 0 || i.size96dpi.Height == 0 {\n\t\tsize = SizeFrom96DPI(defaultIconSize(), dpi)\n\t} else {\n\t\tsize = SizeFrom96DPI(i.size96dpi, dpi)\n\t}\n\n\tvar hIcon win.HICON\n\n\tif i.hasIndex {\n\t\twin.SHDefExtractIcon(\n\t\t\tname,\n\t\t\tint32(i.index),\n\t\t\t0,\n\t\t\tnil,\n\t\t\t&hIcon,\n\t\t\twin.MAKELONG(0, uint16(size.Width)))\n\t\tif hIcon == 0 {\n\t\t\treturn 0, newError(\"SHDefExtractIcon\")\n\t\t}\n\t} else {\n\t\thr := win.HICON(win.LoadIconWithScaleDown(\n\t\t\thInst,\n\t\t\tname,\n\t\t\tint32(size.Width),\n\t\t\tint32(size.Height),\n\t\t\t&hIcon))\n\t\tif hr < 0 || hIcon == 0 {\n\t\t\treturn 0, lastError(\"LoadIconWithScaleDown\")\n\t\t}\n\t}\n\n\ti.dpi2hIcon[dpi] = hIcon\n\n\treturn hIcon, nil\n}\n\n// Dispose releases the operating system resources associated with the Icon.\nfunc (i *Icon) Dispose() {\n\tif i.isStock || len(i.dpi2hIcon) == 0 {\n\t\treturn\n\t}\n\n\tfor dpi, hIcon := range i.dpi2hIcon {\n\t\twin.DestroyIcon(hIcon)\n\t\tdelete(i.dpi2hIcon, dpi)\n\t}\n}\n\nfunc (i *Icon) draw(hdc win.HDC, location Point) error {\n\tdpi := dpiForHDC(hdc)\n\tsize := SizeFrom96DPI(i.size96dpi, dpi)\n\n\treturn i.drawStretched(hdc, Rectangle{location.X, location.Y, size.Width, size.Height})\n}\n\nfunc (i *Icon) drawStretched(hdc win.HDC, bounds Rectangle) error {\n\tdpi := int(float64(bounds.Width) / float64(i.size96dpi.Width) * 96.0)\n\n\thIcon := i.handleForDPI(dpi)\n\tif hIcon == 0 {\n\t\tvar dpiAvailMax int\n\t\tfor dpiAvail, handle := range i.dpi2hIcon {\n\t\t\tif dpiAvail > dpiAvailMax {\n\t\t\t\thIcon = handle\n\t\t\t\tdpiAvailMax = dpiAvail\n\t\t\t}\n\t\t\tif dpiAvail > dpi {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif !win.DrawIconEx(hdc, int32(bounds.X), int32(bounds.Y), hIcon, int32(bounds.Width), int32(bounds.Height), 0, 0, win.DI_NORMAL) {\n\t\treturn lastError(\"DrawIconEx\")\n\t}\n\n\treturn nil\n}\n\n// Size returns icon size in 1/96\" units.\nfunc (i *Icon) Size() Size {\n\treturn i.size96dpi\n}\n\n// create an Alpha Icon or Cursor from an Image\n// http://support.microsoft.com/kb/318876\nfunc createAlphaCursorOrIconFromImage(im image.Image, hotspot image.Point, fIcon bool) (win.HICON, error) {\n\tbmp, err := NewBitmapFromImage(im)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer bmp.Dispose()\n\n\treturn createAlphaCursorOrIconFromBitmap(bmp, Point{hotspot.X, hotspot.Y}, fIcon)\n}\n\n// createAlphaCursorOrIconFromBitmap creates a cursor/icon from a bitmap. hotspot coordinates are in native pixels.\nfunc createAlphaCursorOrIconFromBitmap(bmp *Bitmap, hotspot Point, fIcon bool) (win.HICON, error) {\n\t// Create an empty mask bitmap.\n\thMonoBitmap := win.CreateBitmap(int32(bmp.size.Width), int32(bmp.size.Height), 1, 1, nil)\n\tif hMonoBitmap == 0 {\n\t\treturn 0, newError(\"CreateBitmap failed\")\n\t}\n\tdefer win.DeleteObject(win.HGDIOBJ(hMonoBitmap))\n\n\tvar ii win.ICONINFO\n\tif fIcon {\n\t\tii.FIcon = win.TRUE\n\t}\n\tii.XHotspot = uint32(hotspot.X)\n\tii.YHotspot = uint32(hotspot.Y)\n\tii.HbmMask = hMonoBitmap\n\tii.HbmColor = bmp.hBmp\n\n\t// Create the alpha cursor with the alpha DIB section.\n\thIconOrCursor := win.CreateIconIndirect(&ii)\n\n\treturn hIconOrCursor, nil\n}\n\n// sizeFromHICON returns icon size in native pixels.\nfunc sizeFromHICON(hIcon win.HICON) (Size, error) {\n\tvar ii win.ICONINFO\n\tvar bi win.BITMAPINFO\n\n\tif !win.GetIconInfo(hIcon, &ii) {\n\t\treturn Size{}, lastError(\"GetIconInfo\")\n\t}\n\tdefer win.DeleteObject(win.HGDIOBJ(ii.HbmMask))\n\n\tvar hBmp win.HBITMAP\n\tif ii.HbmColor != 0 {\n\t\thBmp = ii.HbmColor\n\n\t\tdefer win.DeleteObject(win.HGDIOBJ(ii.HbmColor))\n\t} else {\n\t\thBmp = ii.HbmMask\n\t}\n\n\tif 0 == win.GetObject(win.HGDIOBJ(hBmp), unsafe.Sizeof(bi), unsafe.Pointer(&bi)) {\n\t\treturn Size{}, newError(\"GetObject\")\n\t}\n\n\treturn Size{int(bi.BmiHeader.BiWidth), int(bi.BmiHeader.BiHeight)}, nil\n}\n\n// defaultIconSize returns default small icon size in 1/92\" units.\nfunc defaultIconSize() Size {\n\treturn Size{int(win.GetSystemMetricsForDpi(win.SM_CXSMICON, 96)), int(win.GetSystemMetricsForDpi(win.SM_CYSMICON, 96))}\n}\n"
  },
  {
    "path": "iconcache.go",
    "content": "// Copyright 2019 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nvar iconCache *IconCache\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\ticonCache = NewIconCache()\n\t})\n}\n\ntype IconCache struct {\n\timageAndDPI2Bitmap map[imageAndDPI]*Bitmap\n\timageAndDPI2Icon   map[imageAndDPI]*Icon\n}\n\ntype imageAndDPI struct {\n\timage Image\n\tdpi   int\n}\n\nfunc NewIconCache() *IconCache {\n\treturn &IconCache{\n\t\timageAndDPI2Bitmap: make(map[imageAndDPI]*Bitmap),\n\t\timageAndDPI2Icon:   make(map[imageAndDPI]*Icon),\n\t}\n}\n\nfunc (ic *IconCache) Clear() {\n\tfor key, bmp := range ic.imageAndDPI2Bitmap {\n\t\tbmp.Dispose()\n\t\tdelete(ic.imageAndDPI2Bitmap, key)\n\t}\n\tfor key, ico := range ic.imageAndDPI2Icon {\n\t\tico.Dispose()\n\t\tdelete(ic.imageAndDPI2Icon, key)\n\t}\n}\n\nfunc (ic *IconCache) Dispose() {\n\tic.Clear()\n}\n\nfunc (ic *IconCache) Bitmap(image Image, dpi int) (*Bitmap, error) {\n\tkey := imageAndDPI{image, dpi}\n\n\tif bmp, ok := ic.imageAndDPI2Bitmap[key]; ok {\n\t\treturn bmp, nil\n\t}\n\n\tsize := SizeFrom96DPI(image.Size(), dpi)\n\n\tbmp, err := NewBitmapFromImageWithSize(image, size)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tic.imageAndDPI2Bitmap[key] = bmp\n\n\treturn bmp, nil\n}\n\nfunc (ic *IconCache) Icon(image Image, dpi int) (*Icon, error) {\n\tkey := imageAndDPI{image, dpi}\n\n\tif ico, ok := ic.imageAndDPI2Icon[key]; ok {\n\t\treturn ico, nil\n\t}\n\n\tif ico, ok := image.(*Icon); ok {\n\t\tif ico.handleForDPI(dpi) != 0 {\n\t\t\tic.imageAndDPI2Icon[key] = ico\n\t\t\treturn ico, nil\n\t\t}\n\t}\n\n\tico, err := newIconFromImageForDPI(image, dpi)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tic.imageAndDPI2Icon[key] = ico\n\n\treturn ico, nil\n}\n"
  },
  {
    "path": "image.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype Image interface {\n\t// draw draws image at location (upper left) in native pixels unstreched.\n\tdraw(hdc win.HDC, location Point) error\n\n\t// drawStretched draws image streched to given bounds in native pixels.\n\tdrawStretched(hdc win.HDC, bounds Rectangle) error\n\n\tDispose()\n\n\t// Size returns image size in 1/96\" units.\n\tSize() Size\n}\n\nfunc ImageFrom(src interface{}) (img Image, err error) {\n\tswitch src := src.(type) {\n\tcase nil:\n\t\t// nop\n\n\tcase Image:\n\t\timg = src\n\n\tcase ExtractableIcon:\n\t\timg, err = NewIconExtractedFromFileWithSize(src.FilePath_(), src.Index_(), src.Size_())\n\n\tcase int:\n\t\timg, err = Resources.Image(strconv.Itoa(src))\n\n\tcase string:\n\t\timg, err = Resources.Image(src)\n\n\tdefault:\n\t\terr = ErrInvalidType\n\t}\n\n\treturn\n}\n\n// NewImageFromFile loads image from file at 96dpi. Supported types are .ico, .emf, .bmp, .png...\n//\n// Deprecated: Newer applications should use NewImageFromFileForDPI.\nfunc NewImageFromFile(filePath string) (Image, error) {\n\treturn NewImageFromFileForDPI(filePath, 96)\n}\n\n// NewImageFromFileForDPI loads image from file at given DPI. Supported types are .ico, .emf,\n// .bmp, .png...\nfunc NewImageFromFileForDPI(filePath string, dpi int) (Image, error) {\n\tif strings.HasSuffix(filePath, \".ico\") {\n\t\treturn NewIconFromFile(filePath)\n\t} else if strings.HasSuffix(filePath, \".emf\") {\n\t\treturn NewMetafileFromFile(filePath)\n\t}\n\n\treturn NewBitmapFromFileForDPI(filePath, dpi)\n}\n\ntype PaintFuncImage struct {\n\tsize96dpi   Size\n\tpaint       PaintFunc // in 1/96\" units\n\tpaintPixels PaintFunc // in native pixels\n\tdispose     func()\n}\n\n// NewPaintFuncImage creates new PaintFuncImage struct. size parameter and paint function bounds\n// parameter are specified in 1/96\" units.\nfunc NewPaintFuncImage(size Size, paint func(canvas *Canvas, bounds Rectangle) error) *PaintFuncImage {\n\treturn &PaintFuncImage{size96dpi: size, paint: paint}\n}\n\n// NewPaintFuncImagePixels creates new PaintFuncImage struct. size parameter is specified in 1/96\"\n// units. paint function bounds parameter is specified in native pixels.\nfunc NewPaintFuncImagePixels(size Size, paint func(canvas *Canvas, bounds Rectangle) error) *PaintFuncImage {\n\treturn &PaintFuncImage{size96dpi: size, paintPixels: paint}\n}\n\n// NewPaintFuncImageWithDispose creates new PaintFuncImage struct. size parameter and paint\n// function bounds parameter are specified in 1/96\" units.\nfunc NewPaintFuncImageWithDispose(size Size, paint func(canvas *Canvas, bounds Rectangle) error, dispose func()) *PaintFuncImage {\n\treturn &PaintFuncImage{size96dpi: size, paint: paint, dispose: dispose}\n}\n\n// NewPaintFuncImagePixelsWithDispose creates new PaintFuncImage struct. size parameter is\n// specified in 1/96\" units. paint function bounds parameter is specified in native pixels.\nfunc NewPaintFuncImagePixelsWithDispose(size Size, paint func(canvas *Canvas, bounds Rectangle) error, dispose func()) *PaintFuncImage {\n\treturn &PaintFuncImage{size96dpi: size, paintPixels: paint, dispose: dispose}\n}\n\nfunc (pfi *PaintFuncImage) draw(hdc win.HDC, location Point) error {\n\tdpi := dpiForHDC(hdc)\n\tsize := SizeFrom96DPI(pfi.size96dpi, dpi)\n\n\treturn pfi.drawStretched(hdc, Rectangle{location.X, location.Y, size.Width, size.Height})\n}\n\nfunc (pfi *PaintFuncImage) drawStretched(hdc win.HDC, bounds Rectangle) error {\n\tcanvas, err := newCanvasFromHDC(hdc)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer canvas.Dispose()\n\n\treturn pfi.drawStretchedOnCanvasPixels(canvas, bounds)\n}\n\nfunc (pfi *PaintFuncImage) drawStretchedOnCanvasPixels(canvas *Canvas, bounds Rectangle) error {\n\tif pfi.paintPixels != nil {\n\t\treturn pfi.paintPixels(canvas, bounds)\n\t}\n\tif pfi.paint != nil {\n\t\treturn pfi.paint(canvas, RectangleTo96DPI(bounds, canvas.DPI()))\n\t}\n\n\treturn newError(\"paint(Pixels) func is nil\")\n}\n\nfunc (pfi *PaintFuncImage) Dispose() {\n\tif pfi.dispose != nil {\n\t\tpfi.dispose()\n\t\tpfi.dispose = nil\n\t}\n}\n\n// Size returns image size in 1/96\" units.\nfunc (pfi *PaintFuncImage) Size() Size {\n\treturn pfi.size96dpi\n}\n"
  },
  {
    "path": "imagelist.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype ImageList struct {\n\thIml                     win.HIMAGELIST\n\tdpi                      int\n\tmaskColor                Color\n\timageSize96dpi           Size\n\tcolorMaskedBitmap2Index  map[*Bitmap]int\n\tbitmapMaskedBitmap2Index map[bitmapMaskedBitmap]int\n\ticon2Index               map[*Icon]int32\n}\n\ntype bitmapMaskedBitmap struct {\n\tbitmap *Bitmap\n\tmask   *Bitmap\n}\n\n// NewImageList creates an empty image list at 96dpi. imageSize parameter is specified in 1/96\"\n// units.\n//\n// Deprecated: Newer applications should use NewImageListForDPI.\nfunc NewImageList(imageSize Size, maskColor Color) (*ImageList, error) {\n\treturn NewImageListForDPI(SizeFrom96DPI(imageSize, 96), maskColor, 96)\n}\n\n// NewImageListForDPI creates an empty image list for image size at given DPI. imageSize is\n// specified in native pixels.\nfunc NewImageListForDPI(imageSize Size, maskColor Color, dpi int) (*ImageList, error) {\n\thIml := win.ImageList_Create(\n\t\tint32(imageSize.Width),\n\t\tint32(imageSize.Height),\n\t\twin.ILC_MASK|win.ILC_COLOR32,\n\t\t8,\n\t\t8)\n\tif hIml == 0 {\n\t\treturn nil, newError(\"ImageList_Create failed\")\n\t}\n\n\treturn &ImageList{\n\t\thIml:                     hIml,\n\t\tdpi:                      dpi,\n\t\tmaskColor:                maskColor,\n\t\timageSize96dpi:           SizeTo96DPI(imageSize, dpi),\n\t\tcolorMaskedBitmap2Index:  make(map[*Bitmap]int),\n\t\tbitmapMaskedBitmap2Index: make(map[bitmapMaskedBitmap]int),\n\t\ticon2Index:               make(map[*Icon]int32),\n\t}, nil\n}\n\nfunc (il *ImageList) Handle() win.HIMAGELIST {\n\treturn il.hIml\n}\n\nfunc (il *ImageList) Add(bitmap, maskBitmap *Bitmap) (int, error) {\n\tif bitmap == nil {\n\t\treturn 0, newError(\"bitmap cannot be nil\")\n\t}\n\n\tkey := bitmapMaskedBitmap{bitmap: bitmap, mask: maskBitmap}\n\n\tif index, ok := il.bitmapMaskedBitmap2Index[key]; ok {\n\t\treturn index, nil\n\t}\n\n\tvar maskHandle win.HBITMAP\n\tif maskBitmap != nil {\n\t\tmaskHandle = maskBitmap.handle()\n\t}\n\n\tindex := int(win.ImageList_Add(il.hIml, bitmap.handle(), maskHandle))\n\tif index == -1 {\n\t\treturn 0, newError(\"ImageList_Add failed\")\n\t}\n\n\til.bitmapMaskedBitmap2Index[key] = index\n\n\treturn index, nil\n}\n\nfunc (il *ImageList) AddMasked(bitmap *Bitmap) (int32, error) {\n\tif bitmap == nil {\n\t\treturn 0, newError(\"bitmap cannot be nil\")\n\t}\n\n\tif index, ok := il.colorMaskedBitmap2Index[bitmap]; ok {\n\t\treturn int32(index), nil\n\t}\n\n\tindex := win.ImageList_AddMasked(\n\t\til.hIml,\n\t\tbitmap.handle(),\n\t\twin.COLORREF(il.maskColor))\n\tif index == -1 {\n\t\treturn 0, newError(\"ImageList_AddMasked failed\")\n\t}\n\n\til.colorMaskedBitmap2Index[bitmap] = int(index)\n\n\treturn index, nil\n}\n\nfunc (il *ImageList) AddIcon(icon *Icon) (int32, error) {\n\tif icon == nil {\n\t\treturn 0, newError(\"icon cannot be nil\")\n\t}\n\n\tif index, ok := il.icon2Index[icon]; ok {\n\t\treturn index, nil\n\t}\n\n\tindex := win.ImageList_ReplaceIcon(il.hIml, -1, icon.handleForDPI(il.dpi))\n\tif index == -1 {\n\t\treturn 0, newError(\"ImageList_ReplaceIcon failed\")\n\t}\n\n\til.icon2Index[icon] = index\n\n\treturn index, nil\n}\n\nfunc (il *ImageList) AddImage(image interface{}) (int32, error) {\n\tswitch image.(type) {\n\tcase ExtractableIcon, *Icon:\n\t\ticon, err := IconFrom(image, il.dpi)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\treturn il.AddIcon(icon)\n\n\tdefault:\n\t\tbmp, err := BitmapFrom(image, il.dpi)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\treturn il.AddMasked(bmp)\n\t}\n}\n\nfunc (il *ImageList) DrawPixels(canvas *Canvas, index int, bounds Rectangle) error {\n\tif !win.ImageList_DrawEx(il.hIml, int32(index), canvas.hdc, int32(bounds.X), int32(bounds.Y), int32(bounds.Width), int32(bounds.Height), win.CLR_DEFAULT, win.CLR_DEFAULT, win.ILD_NORMAL) {\n\t\treturn newError(\"ImageList_DrawEx\")\n\t}\n\n\treturn nil\n}\n\nfunc (il *ImageList) Dispose() {\n\tif il.hIml != 0 {\n\t\twin.ImageList_Destroy(il.hIml)\n\t\til.hIml = 0\n\t}\n}\n\nfunc (il *ImageList) MaskColor() Color {\n\treturn il.maskColor\n}\n\nfunc imageListForImage(image interface{}, dpi int) (hIml win.HIMAGELIST, isSysIml bool, err error) {\n\tif name, ok := image.(string); ok {\n\t\tif img, err := Resources.Image(name); err == nil {\n\t\t\timage = img\n\t\t}\n\t}\n\n\tif filePath, ok := image.(string); ok {\n\t\t_, hIml = iconIndexAndHImlForFilePath(filePath)\n\t\tisSysIml = hIml != 0\n\t} else {\n\t\tw := int32(win.GetSystemMetricsForDpi(win.SM_CXSMICON, uint32(dpi)))\n\t\th := int32(win.GetSystemMetricsForDpi(win.SM_CYSMICON, uint32(dpi)))\n\n\t\thIml = win.ImageList_Create(w, h, win.ILC_MASK|win.ILC_COLOR32, 8, 8)\n\t\tif hIml == 0 {\n\t\t\treturn 0, false, newError(\"ImageList_Create failed\")\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc iconIndexAndHImlForFilePath(filePath string) (int32, win.HIMAGELIST) {\n\tvar shfi win.SHFILEINFO\n\n\tif hIml := win.HIMAGELIST(win.SHGetFileInfo(\n\t\tsyscall.StringToUTF16Ptr(filePath),\n\t\t0,\n\t\t&shfi,\n\t\tuint32(unsafe.Sizeof(shfi)),\n\t\twin.SHGFI_SYSICONINDEX|win.SHGFI_SMALLICON)); hIml != 0 {\n\n\t\treturn shfi.IIcon, hIml\n\t}\n\n\treturn -1, 0\n}\n\nfunc imageIndexMaybeAdd(image interface{}, hIml win.HIMAGELIST, isSysIml bool, imageUintptr2Index map[uintptr]int32, filePath2IconIndex map[string]int32, dpi int) int32 {\n\tif !isSysIml {\n\t\treturn imageIndexAddIfNotExists(image, hIml, imageUintptr2Index, dpi)\n\t} else if filePath, ok := image.(string); ok {\n\t\tif iIcon, ok := filePath2IconIndex[filePath]; ok {\n\t\t\treturn iIcon\n\t\t}\n\n\t\tif iIcon, _ := iconIndexAndHImlForFilePath(filePath); iIcon != -1 {\n\t\t\tfilePath2IconIndex[filePath] = iIcon\n\t\t\treturn iIcon\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc imageIndexAddIfNotExists(image interface{}, hIml win.HIMAGELIST, imageUintptr2Index map[uintptr]int32, dpi int) int32 {\n\timageIndex := int32(-1)\n\n\tif image != nil {\n\t\tif name, ok := image.(string); ok {\n\t\t\timage, _ = Resources.Image(name)\n\t\t}\n\n\t\tvar ptr uintptr\n\t\tswitch img := image.(type) {\n\t\tcase *Bitmap:\n\t\t\tptr = uintptr(unsafe.Pointer(img))\n\n\t\tcase *Icon:\n\t\t\tptr = uintptr(unsafe.Pointer(img))\n\t\t}\n\n\t\tif ptr == 0 {\n\t\t\treturn -1\n\t\t}\n\n\t\tif imageIndex, ok := imageUintptr2Index[ptr]; ok {\n\t\t\treturn imageIndex\n\t\t}\n\n\t\tswitch img := image.(type) {\n\t\tcase *Bitmap:\n\t\t\timageIndex = win.ImageList_AddMasked(hIml, img.hBmp, 0)\n\n\t\tcase *Icon:\n\t\t\timageIndex = win.ImageList_ReplaceIcon(hIml, -1, img.handleForDPI(dpi))\n\t\t}\n\n\t\tif imageIndex > -1 {\n\t\t\timageUintptr2Index[ptr] = imageIndex\n\t\t}\n\t}\n\n\treturn imageIndex\n}\n"
  },
  {
    "path": "imageview.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"math\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype ImageViewMode int\n\nconst (\n\tImageViewModeIdeal ImageViewMode = iota\n\tImageViewModeCorner\n\tImageViewModeCenter\n\tImageViewModeShrink\n\tImageViewModeZoom\n\tImageViewModeStretch\n)\n\ntype ImageView struct {\n\t*CustomWidget\n\timage                  Image\n\timageChangedPublisher  EventPublisher\n\tmargin96dpi            int\n\tmarginChangedPublisher EventPublisher\n\tmode                   ImageViewMode\n}\n\nfunc NewImageView(parent Container) (*ImageView, error) {\n\tiv := new(ImageView)\n\n\tcw, err := NewCustomWidgetPixels(parent, 0, func(canvas *Canvas, updateBounds Rectangle) error {\n\t\treturn iv.drawImage(canvas, updateBounds)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tiv.CustomWidget = cw\n\n\tif err := InitWrapperWindow(iv); err != nil {\n\t\tiv.Dispose()\n\t\treturn nil, err\n\t}\n\n\tiv.SetInvalidatesOnResize(true)\n\n\tiv.SetBackground(NullBrush())\n\n\tiv.MustRegisterProperty(\"Image\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn iv.Image()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\timg, err := ImageFrom(v)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn iv.SetImage(img)\n\t\t},\n\t\tiv.imageChangedPublisher.Event()))\n\n\tiv.MustRegisterProperty(\"Margin\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn iv.Margin()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn iv.SetMargin(assertIntOr(v, 0))\n\t\t},\n\t\tiv.MarginChanged()))\n\n\treturn iv, nil\n}\n\nfunc (iv *ImageView) Mode() ImageViewMode {\n\treturn iv.mode\n}\n\nfunc (iv *ImageView) SetMode(mode ImageViewMode) {\n\tif mode == iv.mode {\n\t\treturn\n\t}\n\n\tiv.mode = mode\n\n\tiv.Invalidate()\n\n\tiv.RequestLayout()\n}\n\nfunc (iv *ImageView) applyDPI(dpi int) {\n\tiv.CustomWidget.ApplyDPI(dpi)\n\n\tiv.Invalidate()\n\n\tiv.RequestLayout()\n}\n\nfunc (iv *ImageView) Image() Image {\n\treturn iv.image\n}\n\nfunc (iv *ImageView) SetImage(image Image) error {\n\tif image == iv.image {\n\t\treturn nil\n\t}\n\n\tvar oldSize, newSize Size // in 1/96\" units\n\tif iv.image != nil {\n\t\toldSize = iv.image.Size()\n\t}\n\tif image != nil {\n\t\tnewSize = image.Size()\n\t}\n\n\tiv.image = image\n\n\t_, isMetafile := image.(*Metafile)\n\tiv.SetClearsBackground(isMetafile)\n\n\terr := iv.Invalidate()\n\n\tif iv.mode == ImageViewModeIdeal && newSize != oldSize {\n\t\tiv.RequestLayout()\n\t}\n\n\tiv.imageChangedPublisher.Publish()\n\n\treturn err\n}\n\nfunc (iv *ImageView) ImageChanged() *Event {\n\treturn iv.imageChangedPublisher.Event()\n}\n\nfunc (iv *ImageView) Margin() int {\n\treturn iv.margin96dpi\n}\n\nfunc (iv *ImageView) SetMargin(margin int) error {\n\tif margin == iv.margin96dpi {\n\t\treturn nil\n\t}\n\n\tiv.margin96dpi = margin\n\n\terr := iv.Invalidate()\n\n\tif iv.mode == ImageViewModeIdeal {\n\t\tiv.RequestLayout()\n\t}\n\n\tiv.marginChangedPublisher.Publish()\n\n\treturn err\n}\n\nfunc (iv *ImageView) MarginChanged() *Event {\n\treturn iv.marginChangedPublisher.Event()\n}\n\nfunc (iv *ImageView) drawImage(canvas *Canvas, _ Rectangle) error {\n\tif iv.image == nil {\n\t\treturn nil\n\t}\n\n\tcb := iv.ClientBoundsPixels()\n\n\tdpi := iv.DPI()\n\tmargin := IntFrom96DPI(iv.margin96dpi, dpi)\n\n\tcb.Width -= margin * 2\n\tcb.Height -= margin * 2\n\n\ts := SizeFrom96DPI(iv.image.Size(), dpi)\n\n\tswitch iv.mode {\n\tcase ImageViewModeShrink, ImageViewModeZoom, ImageViewModeStretch:\n\t\tvar bounds Rectangle\n\n\t\tif iv.mode == ImageViewModeStretch {\n\t\t\tbounds.X = margin\n\t\t\tbounds.Y = margin\n\t\t\tbounds.Width = cb.Width\n\t\t\tbounds.Height = cb.Height\n\t\t} else {\n\t\t\tvar scale float64\n\t\t\tif iv.mode == ImageViewModeZoom || s.Width > cb.Width || s.Height > cb.Height {\n\t\t\t\tsx := float64(cb.Width) / float64(s.Width)\n\t\t\t\tsy := float64(cb.Height) / float64(s.Height)\n\n\t\t\t\tscale = math.Min(sx, sy)\n\t\t\t} else {\n\t\t\t\tscale = 1.0\n\t\t\t}\n\n\t\t\tbounds.Width = int(float64(s.Width) * scale)\n\t\t\tbounds.Height = int(float64(s.Height) * scale)\n\t\t\tbounds.X = margin + (cb.Width-bounds.Width)/2\n\t\t\tbounds.Y = margin + (cb.Height-bounds.Height)/2\n\t\t}\n\n\t\treturn canvas.DrawImageStretchedPixels(iv.image, bounds)\n\n\tcase ImageViewModeCorner, ImageViewModeCenter:\n\t\twin.IntersectClipRect(canvas.hdc, int32(margin), int32(margin), int32(cb.Width+margin), int32(cb.Height+margin))\n\t}\n\n\tvar bounds Rectangle\n\n\tswitch iv.mode {\n\tcase ImageViewModeIdeal, ImageViewModeCorner:\n\t\tbounds.X = margin\n\t\tbounds.Y = margin\n\n\tcase ImageViewModeCenter:\n\t\tbounds.X = margin + (cb.Width-s.Width)/2\n\t\tbounds.Y = margin + (cb.Height-s.Height)/2\n\t}\n\tbounds.Width = s.Width\n\tbounds.Height = s.Height\n\n\treturn canvas.DrawImageStretchedPixels(iv.image, bounds)\n}\n\nfunc (iv *ImageView) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tvar layoutFlags LayoutFlags\n\tif iv.mode != ImageViewModeIdeal {\n\t\tlayoutFlags = ShrinkableHorz | ShrinkableVert | GrowableHorz | GrowableVert | GreedyHorz | GreedyVert\n\t}\n\n\tdpi := iv.DPI()\n\tidealSize := SizeFrom96DPI(Size{100, 100}, dpi)\n\n\tvar minSize Size\n\tif iv.mode == ImageViewModeIdeal {\n\t\tif iv.image != nil {\n\t\t\tidealSize = SizeFrom96DPI(iv.image.Size(), dpi)\n\t\t\tmargin2 := IntFrom96DPI(iv.margin96dpi, dpi) * 2\n\t\t\tidealSize.Width += margin2\n\t\t\tidealSize.Height += margin2\n\t\t}\n\n\t\tminSize = idealSize\n\t} else {\n\t\ts := IntFrom96DPI(iv.margin96dpi, dpi)*2 + 1\n\t\tminSize = Size{s, s}\n\t}\n\n\treturn &imageViewLayoutItem{\n\t\tlayoutFlags: layoutFlags,\n\t\tidealSize:   idealSize,\n\t\tminSize:     minSize,\n\t}\n}\n\ntype imageViewLayoutItem struct {\n\tLayoutItemBase\n\tlayoutFlags LayoutFlags\n\tidealSize   Size // in native pixels\n\tminSize     Size // in native pixels\n}\n\nfunc (li *imageViewLayoutItem) LayoutFlags() LayoutFlags {\n\treturn li.layoutFlags\n}\n\nfunc (li *imageViewLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *imageViewLayoutItem) MinSize() Size {\n\treturn li.minSize\n}\n"
  },
  {
    "path": "inifilesettings.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"bufio\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst iniFileTimeStampFormat = \"2006-01-02\"\n\ntype IniFileSettings struct {\n\tfileName       string\n\tkey2Record     map[string]iniFileRecord\n\texpireDuration time.Duration\n\tportable       bool\n}\n\ntype iniFileRecord struct {\n\tvalue     string\n\ttimestamp time.Time\n}\n\nfunc NewIniFileSettings(fileName string) *IniFileSettings {\n\treturn &IniFileSettings{\n\t\tfileName:   fileName,\n\t\tkey2Record: make(map[string]iniFileRecord),\n\t}\n}\n\nfunc (ifs *IniFileSettings) Get(key string) (string, bool) {\n\trecord, ok := ifs.key2Record[key]\n\treturn record.value, ok\n}\n\nfunc (ifs *IniFileSettings) Timestamp(key string) (time.Time, bool) {\n\trecord, ok := ifs.key2Record[key]\n\treturn record.timestamp, ok\n}\n\nfunc (ifs *IniFileSettings) Put(key, value string) error {\n\treturn ifs.put(key, value, false)\n}\n\nfunc (ifs *IniFileSettings) PutExpiring(key, value string) error {\n\treturn ifs.put(key, value, true)\n}\n\nfunc (ifs *IniFileSettings) put(key, value string, expiring bool) error {\n\tif key == \"\" {\n\t\treturn newError(\"key must not be empty\")\n\t}\n\tif strings.IndexAny(key, \"|=\\r\\n\") > -1 {\n\t\treturn newError(\"key contains at least one of the invalid characters '|=\\\\r\\\\n'\")\n\t}\n\tif strings.IndexAny(value, \"\\r\\n\") > -1 {\n\t\treturn newError(\"value contains at least one of the invalid characters '\\\\r\\\\n'\")\n\t}\n\n\tvar timestamp time.Time\n\tif expiring {\n\t\ttimestamp = time.Now()\n\t}\n\n\tifs.key2Record[key] = iniFileRecord{value, timestamp}\n\n\treturn nil\n}\n\nfunc (ifs *IniFileSettings) Remove(key string) error {\n\tdelete(ifs.key2Record, key)\n\n\treturn nil\n}\n\nfunc (ifs *IniFileSettings) ExpireDuration() time.Duration {\n\treturn ifs.expireDuration\n}\n\nfunc (ifs *IniFileSettings) SetExpireDuration(expireDuration time.Duration) {\n\tifs.expireDuration = expireDuration\n}\n\nfunc (ifs *IniFileSettings) Portable() bool {\n\treturn ifs.portable\n}\n\nfunc (ifs *IniFileSettings) SetPortable(portable bool) {\n\tifs.portable = portable\n}\n\nfunc (ifs *IniFileSettings) FilePath() string {\n\tif ifs.portable {\n\t\tabsPath, err := filepath.Abs(ifs.fileName)\n\t\tif err != nil {\n\t\t\treturn \"\"\n\t\t}\n\n\t\treturn absPath\n\t}\n\n\tappDataPath, err := AppDataPath()\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\treturn filepath.Join(\n\t\tappDataPath,\n\t\tApp().OrganizationName(),\n\t\tApp().ProductName(),\n\t\tifs.fileName)\n}\n\nfunc (ifs *IniFileSettings) fileExists() (bool, error) {\n\tfilePath := ifs.FilePath()\n\n\tif _, err := os.Stat(filePath); err != nil {\n\t\t// FIXME: Not necessarily a file does not exist error.\n\t\treturn false, nil\n\t}\n\n\treturn true, nil\n}\n\nfunc (ifs *IniFileSettings) withFile(flags int, f func(file *os.File) error) error {\n\tfilePath := ifs.FilePath()\n\n\tdirPath, _ := filepath.Split(filePath)\n\tif err := os.MkdirAll(dirPath, 0644); err != nil {\n\t\treturn wrapError(err)\n\t}\n\n\tfile, err := os.OpenFile(filePath, flags, 0644)\n\tif err != nil {\n\t\treturn wrapError(err)\n\t}\n\tdefer file.Close()\n\n\treturn f(file)\n}\n\nfunc (ifs *IniFileSettings) Load() error {\n\texists, err := ifs.fileExists()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !exists {\n\t\treturn nil\n\t}\n\n\treturn ifs.withFile(os.O_RDONLY, func(file *os.File) error {\n\t\tscanner := bufio.NewScanner(file)\n\n\t\tfor scanner.Scan() {\n\t\t\tline := scanner.Text()\n\n\t\t\tassignIndex := strings.Index(line, \"=\")\n\t\t\tif assignIndex == -1 {\n\t\t\t\treturn newError(\"bad line format: missing '='\")\n\t\t\t}\n\n\t\t\tkey := strings.TrimSpace(line[:assignIndex])\n\n\t\t\tvar ts time.Time\n\t\t\tif parts := strings.Split(key, \"|\"); len(parts) > 1 {\n\t\t\t\tkey = parts[0]\n\t\t\t\tif ts, _ = time.Parse(iniFileTimeStampFormat, parts[1]); ts.IsZero() {\n\t\t\t\t\tts = time.Now()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvalue := strings.TrimSpace(line[assignIndex+1:])\n\n\t\t\tifs.key2Record[key] = iniFileRecord{value, ts}\n\t\t}\n\n\t\treturn scanner.Err()\n\t})\n}\n\nfunc (ifs *IniFileSettings) Save() error {\n\treturn ifs.withFile(os.O_CREATE|os.O_TRUNC|os.O_WRONLY, func(file *os.File) error {\n\t\tbufWriter := bufio.NewWriter(file)\n\n\t\tkeys := make([]string, 0, len(ifs.key2Record))\n\n\t\tfor key, record := range ifs.key2Record {\n\t\t\tif ifs.expireDuration <= 0 || record.timestamp.IsZero() || time.Since(record.timestamp) < ifs.expireDuration {\n\t\t\t\tkeys = append(keys, key)\n\t\t\t}\n\t\t}\n\n\t\tsort.Strings(keys)\n\n\t\tfor _, key := range keys {\n\t\t\trecord := ifs.key2Record[key]\n\n\t\t\tif _, err := bufWriter.WriteString(key); err != nil {\n\t\t\t\treturn wrapError(err)\n\t\t\t}\n\t\t\tif !record.timestamp.IsZero() {\n\t\t\t\tif _, err := bufWriter.WriteString(\"|\"); err != nil {\n\t\t\t\t\treturn wrapError(err)\n\t\t\t\t}\n\t\t\t\tif _, err := bufWriter.WriteString(record.timestamp.Format(iniFileTimeStampFormat)); err != nil {\n\t\t\t\t\treturn wrapError(err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif _, err := bufWriter.WriteString(\"=\"); err != nil {\n\t\t\t\treturn wrapError(err)\n\t\t\t}\n\t\t\tif _, err := bufWriter.WriteString(record.value); err != nil {\n\t\t\t\treturn wrapError(err)\n\t\t\t}\n\t\t\tif _, err := bufWriter.WriteString(\"\\r\\n\"); err != nil {\n\t\t\t\treturn wrapError(err)\n\t\t\t}\n\t\t}\n\n\t\treturn bufWriter.Flush()\n\t})\n}\n"
  },
  {
    "path": "intevent.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype intEventHandlerInfo struct {\n\thandler IntEventHandler\n\tonce    bool\n}\n\ntype IntEventHandler func(n int)\n\ntype IntEvent struct {\n\thandlers []intEventHandlerInfo\n}\n\nfunc (e *IntEvent) Attach(handler IntEventHandler) int {\n\thandlerInfo := intEventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *IntEvent) Detach(handle int) {\n\te.handlers[handle].handler = nil\n}\n\nfunc (e *IntEvent) Once(handler IntEventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype IntEventPublisher struct {\n\tevent IntEvent\n}\n\nfunc (p *IntEventPublisher) Event() *IntEvent {\n\treturn &p.event\n}\n\nfunc (p *IntEventPublisher) Publish(n int) {\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler(n)\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "intrangeevent.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype intRangeEventHandlerInfo struct {\n\thandler IntRangeEventHandler\n\tonce    bool\n}\n\ntype IntRangeEventHandler func(from, to int)\n\ntype IntRangeEvent struct {\n\thandlers []intRangeEventHandlerInfo\n}\n\nfunc (e *IntRangeEvent) Attach(handler IntRangeEventHandler) int {\n\thandlerInfo := intRangeEventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *IntRangeEvent) Detach(handle int) {\n\te.handlers[handle].handler = nil\n}\n\nfunc (e *IntRangeEvent) Once(handler IntRangeEventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype IntRangeEventPublisher struct {\n\tevent IntRangeEvent\n}\n\nfunc (p *IntRangeEventPublisher) Event() *IntRangeEvent {\n\treturn &p.event\n}\n\nfunc (p *IntRangeEventPublisher) Publish(from, to int) {\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler(from, to)\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "keyboard.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"bytes\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype Key uint16\n\nfunc (k Key) String() string {\n\treturn key2string[k]\n}\n\nconst (\n\tKeyLButton           Key = win.VK_LBUTTON\n\tKeyRButton           Key = win.VK_RBUTTON\n\tKeyCancel            Key = win.VK_CANCEL\n\tKeyMButton           Key = win.VK_MBUTTON\n\tKeyXButton1          Key = win.VK_XBUTTON1\n\tKeyXButton2          Key = win.VK_XBUTTON2\n\tKeyBack              Key = win.VK_BACK\n\tKeyTab               Key = win.VK_TAB\n\tKeyClear             Key = win.VK_CLEAR\n\tKeyReturn            Key = win.VK_RETURN\n\tKeyShift             Key = win.VK_SHIFT\n\tKeyControl           Key = win.VK_CONTROL\n\tKeyAlt               Key = win.VK_MENU\n\tKeyMenu              Key = win.VK_MENU\n\tKeyPause             Key = win.VK_PAUSE\n\tKeyCapital           Key = win.VK_CAPITAL\n\tKeyKana              Key = win.VK_KANA\n\tKeyHangul            Key = win.VK_HANGUL\n\tKeyJunja             Key = win.VK_JUNJA\n\tKeyFinal             Key = win.VK_FINAL\n\tKeyHanja             Key = win.VK_HANJA\n\tKeyKanji             Key = win.VK_KANJI\n\tKeyEscape            Key = win.VK_ESCAPE\n\tKeyConvert           Key = win.VK_CONVERT\n\tKeyNonconvert        Key = win.VK_NONCONVERT\n\tKeyAccept            Key = win.VK_ACCEPT\n\tKeyModeChange        Key = win.VK_MODECHANGE\n\tKeySpace             Key = win.VK_SPACE\n\tKeyPrior             Key = win.VK_PRIOR\n\tKeyNext              Key = win.VK_NEXT\n\tKeyEnd               Key = win.VK_END\n\tKeyHome              Key = win.VK_HOME\n\tKeyLeft              Key = win.VK_LEFT\n\tKeyUp                Key = win.VK_UP\n\tKeyRight             Key = win.VK_RIGHT\n\tKeyDown              Key = win.VK_DOWN\n\tKeySelect            Key = win.VK_SELECT\n\tKeyPrint             Key = win.VK_PRINT\n\tKeyExecute           Key = win.VK_EXECUTE\n\tKeySnapshot          Key = win.VK_SNAPSHOT\n\tKeyInsert            Key = win.VK_INSERT\n\tKeyDelete            Key = win.VK_DELETE\n\tKeyHelp              Key = win.VK_HELP\n\tKey0                 Key = 0x30\n\tKey1                 Key = 0x31\n\tKey2                 Key = 0x32\n\tKey3                 Key = 0x33\n\tKey4                 Key = 0x34\n\tKey5                 Key = 0x35\n\tKey6                 Key = 0x36\n\tKey7                 Key = 0x37\n\tKey8                 Key = 0x38\n\tKey9                 Key = 0x39\n\tKeyA                 Key = 0x41\n\tKeyB                 Key = 0x42\n\tKeyC                 Key = 0x43\n\tKeyD                 Key = 0x44\n\tKeyE                 Key = 0x45\n\tKeyF                 Key = 0x46\n\tKeyG                 Key = 0x47\n\tKeyH                 Key = 0x48\n\tKeyI                 Key = 0x49\n\tKeyJ                 Key = 0x4A\n\tKeyK                 Key = 0x4B\n\tKeyL                 Key = 0x4C\n\tKeyM                 Key = 0x4D\n\tKeyN                 Key = 0x4E\n\tKeyO                 Key = 0x4F\n\tKeyP                 Key = 0x50\n\tKeyQ                 Key = 0x51\n\tKeyR                 Key = 0x52\n\tKeyS                 Key = 0x53\n\tKeyT                 Key = 0x54\n\tKeyU                 Key = 0x55\n\tKeyV                 Key = 0x56\n\tKeyW                 Key = 0x57\n\tKeyX                 Key = 0x58\n\tKeyY                 Key = 0x59\n\tKeyZ                 Key = 0x5A\n\tKeyLWin              Key = win.VK_LWIN\n\tKeyRWin              Key = win.VK_RWIN\n\tKeyApps              Key = win.VK_APPS\n\tKeySleep             Key = win.VK_SLEEP\n\tKeyNumpad0           Key = win.VK_NUMPAD0\n\tKeyNumpad1           Key = win.VK_NUMPAD1\n\tKeyNumpad2           Key = win.VK_NUMPAD2\n\tKeyNumpad3           Key = win.VK_NUMPAD3\n\tKeyNumpad4           Key = win.VK_NUMPAD4\n\tKeyNumpad5           Key = win.VK_NUMPAD5\n\tKeyNumpad6           Key = win.VK_NUMPAD6\n\tKeyNumpad7           Key = win.VK_NUMPAD7\n\tKeyNumpad8           Key = win.VK_NUMPAD8\n\tKeyNumpad9           Key = win.VK_NUMPAD9\n\tKeyMultiply          Key = win.VK_MULTIPLY\n\tKeyAdd               Key = win.VK_ADD\n\tKeySeparator         Key = win.VK_SEPARATOR\n\tKeySubtract          Key = win.VK_SUBTRACT\n\tKeyDecimal           Key = win.VK_DECIMAL\n\tKeyDivide            Key = win.VK_DIVIDE\n\tKeyF1                Key = win.VK_F1\n\tKeyF2                Key = win.VK_F2\n\tKeyF3                Key = win.VK_F3\n\tKeyF4                Key = win.VK_F4\n\tKeyF5                Key = win.VK_F5\n\tKeyF6                Key = win.VK_F6\n\tKeyF7                Key = win.VK_F7\n\tKeyF8                Key = win.VK_F8\n\tKeyF9                Key = win.VK_F9\n\tKeyF10               Key = win.VK_F10\n\tKeyF11               Key = win.VK_F11\n\tKeyF12               Key = win.VK_F12\n\tKeyF13               Key = win.VK_F13\n\tKeyF14               Key = win.VK_F14\n\tKeyF15               Key = win.VK_F15\n\tKeyF16               Key = win.VK_F16\n\tKeyF17               Key = win.VK_F17\n\tKeyF18               Key = win.VK_F18\n\tKeyF19               Key = win.VK_F19\n\tKeyF20               Key = win.VK_F20\n\tKeyF21               Key = win.VK_F21\n\tKeyF22               Key = win.VK_F22\n\tKeyF23               Key = win.VK_F23\n\tKeyF24               Key = win.VK_F24\n\tKeyNumlock           Key = win.VK_NUMLOCK\n\tKeyScroll            Key = win.VK_SCROLL\n\tKeyLShift            Key = win.VK_LSHIFT\n\tKeyRShift            Key = win.VK_RSHIFT\n\tKeyLControl          Key = win.VK_LCONTROL\n\tKeyRControl          Key = win.VK_RCONTROL\n\tKeyLAlt              Key = win.VK_LMENU\n\tKeyLMenu             Key = win.VK_LMENU\n\tKeyRAlt              Key = win.VK_RMENU\n\tKeyRMenu             Key = win.VK_RMENU\n\tKeyBrowserBack       Key = win.VK_BROWSER_BACK\n\tKeyBrowserForward    Key = win.VK_BROWSER_FORWARD\n\tKeyBrowserRefresh    Key = win.VK_BROWSER_REFRESH\n\tKeyBrowserStop       Key = win.VK_BROWSER_STOP\n\tKeyBrowserSearch     Key = win.VK_BROWSER_SEARCH\n\tKeyBrowserFavorites  Key = win.VK_BROWSER_FAVORITES\n\tKeyBrowserHome       Key = win.VK_BROWSER_HOME\n\tKeyVolumeMute        Key = win.VK_VOLUME_MUTE\n\tKeyVolumeDown        Key = win.VK_VOLUME_DOWN\n\tKeyVolumeUp          Key = win.VK_VOLUME_UP\n\tKeyMediaNextTrack    Key = win.VK_MEDIA_NEXT_TRACK\n\tKeyMediaPrevTrack    Key = win.VK_MEDIA_PREV_TRACK\n\tKeyMediaStop         Key = win.VK_MEDIA_STOP\n\tKeyMediaPlayPause    Key = win.VK_MEDIA_PLAY_PAUSE\n\tKeyLaunchMail        Key = win.VK_LAUNCH_MAIL\n\tKeyLaunchMediaSelect Key = win.VK_LAUNCH_MEDIA_SELECT\n\tKeyLaunchApp1        Key = win.VK_LAUNCH_APP1\n\tKeyLaunchApp2        Key = win.VK_LAUNCH_APP2\n\tKeyOEM1              Key = win.VK_OEM_1\n\tKeyOEMPlus           Key = win.VK_OEM_PLUS\n\tKeyOEMComma          Key = win.VK_OEM_COMMA\n\tKeyOEMMinus          Key = win.VK_OEM_MINUS\n\tKeyOEMPeriod         Key = win.VK_OEM_PERIOD\n\tKeyOEM2              Key = win.VK_OEM_2\n\tKeyOEM3              Key = win.VK_OEM_3\n\tKeyOEM4              Key = win.VK_OEM_4\n\tKeyOEM5              Key = win.VK_OEM_5\n\tKeyOEM6              Key = win.VK_OEM_6\n\tKeyOEM7              Key = win.VK_OEM_7\n\tKeyOEM8              Key = win.VK_OEM_8\n\tKeyOEM102            Key = win.VK_OEM_102\n\tKeyProcessKey        Key = win.VK_PROCESSKEY\n\tKeyPacket            Key = win.VK_PACKET\n\tKeyAttn              Key = win.VK_ATTN\n\tKeyCRSel             Key = win.VK_CRSEL\n\tKeyEXSel             Key = win.VK_EXSEL\n\tKeyErEOF             Key = win.VK_EREOF\n\tKeyPlay              Key = win.VK_PLAY\n\tKeyZoom              Key = win.VK_ZOOM\n\tKeyNoName            Key = win.VK_NONAME\n\tKeyPA1               Key = win.VK_PA1\n\tKeyOEMClear          Key = win.VK_OEM_CLEAR\n)\n\nvar key2string = map[Key]string{\n\tKeyLButton:           \"LButton\",\n\tKeyRButton:           \"RButton\",\n\tKeyCancel:            \"Cancel\",\n\tKeyMButton:           \"MButton\",\n\tKeyXButton1:          \"XButton1\",\n\tKeyXButton2:          \"XButton2\",\n\tKeyBack:              \"Back\",\n\tKeyTab:               \"Tab\",\n\tKeyClear:             \"Clear\",\n\tKeyReturn:            \"Return\",\n\tKeyShift:             \"Shift\",\n\tKeyControl:           \"Control\",\n\tKeyAlt:               \"Alt / Menu\",\n\tKeyPause:             \"Pause\",\n\tKeyCapital:           \"Capital\",\n\tKeyKana:              \"Kana / Hangul\",\n\tKeyJunja:             \"Junja\",\n\tKeyFinal:             \"Final\",\n\tKeyHanja:             \"Hanja / Kanji\",\n\tKeyEscape:            \"Escape\",\n\tKeyConvert:           \"Convert\",\n\tKeyNonconvert:        \"Nonconvert\",\n\tKeyAccept:            \"Accept\",\n\tKeyModeChange:        \"ModeChange\",\n\tKeySpace:             \"Space\",\n\tKeyPrior:             \"Prior\",\n\tKeyNext:              \"Next\",\n\tKeyEnd:               \"End\",\n\tKeyHome:              \"Home\",\n\tKeyLeft:              \"Left\",\n\tKeyUp:                \"Up\",\n\tKeyRight:             \"Right\",\n\tKeyDown:              \"Down\",\n\tKeySelect:            \"Select\",\n\tKeyPrint:             \"Print\",\n\tKeyExecute:           \"Execute\",\n\tKeySnapshot:          \"Snapshot\",\n\tKeyInsert:            \"Insert\",\n\tKeyDelete:            \"Delete\",\n\tKeyHelp:              \"Help\",\n\tKey0:                 \"0\",\n\tKey1:                 \"1\",\n\tKey2:                 \"2\",\n\tKey3:                 \"3\",\n\tKey4:                 \"4\",\n\tKey5:                 \"5\",\n\tKey6:                 \"6\",\n\tKey7:                 \"7\",\n\tKey8:                 \"8\",\n\tKey9:                 \"9\",\n\tKeyA:                 \"A\",\n\tKeyB:                 \"B\",\n\tKeyC:                 \"C\",\n\tKeyD:                 \"D\",\n\tKeyE:                 \"E\",\n\tKeyF:                 \"F\",\n\tKeyG:                 \"G\",\n\tKeyH:                 \"H\",\n\tKeyI:                 \"I\",\n\tKeyJ:                 \"J\",\n\tKeyK:                 \"K\",\n\tKeyL:                 \"L\",\n\tKeyM:                 \"M\",\n\tKeyN:                 \"N\",\n\tKeyO:                 \"O\",\n\tKeyP:                 \"P\",\n\tKeyQ:                 \"Q\",\n\tKeyR:                 \"R\",\n\tKeyS:                 \"S\",\n\tKeyT:                 \"T\",\n\tKeyU:                 \"U\",\n\tKeyV:                 \"V\",\n\tKeyW:                 \"W\",\n\tKeyX:                 \"X\",\n\tKeyY:                 \"Y\",\n\tKeyZ:                 \"Z\",\n\tKeyLWin:              \"LWin\",\n\tKeyRWin:              \"RWin\",\n\tKeyApps:              \"Apps\",\n\tKeySleep:             \"Sleep\",\n\tKeyNumpad0:           \"Numpad0\",\n\tKeyNumpad1:           \"Numpad1\",\n\tKeyNumpad2:           \"Numpad2\",\n\tKeyNumpad3:           \"Numpad3\",\n\tKeyNumpad4:           \"Numpad4\",\n\tKeyNumpad5:           \"Numpad5\",\n\tKeyNumpad6:           \"Numpad6\",\n\tKeyNumpad7:           \"Numpad7\",\n\tKeyNumpad8:           \"Numpad8\",\n\tKeyNumpad9:           \"Numpad9\",\n\tKeyMultiply:          \"Multiply\",\n\tKeyAdd:               \"Add\",\n\tKeySeparator:         \"Separator\",\n\tKeySubtract:          \"Subtract\",\n\tKeyDecimal:           \"Decimal\",\n\tKeyDivide:            \"Divide\",\n\tKeyF1:                \"F1\",\n\tKeyF2:                \"F2\",\n\tKeyF3:                \"F3\",\n\tKeyF4:                \"F4\",\n\tKeyF5:                \"F5\",\n\tKeyF6:                \"F6\",\n\tKeyF7:                \"F7\",\n\tKeyF8:                \"F8\",\n\tKeyF9:                \"F9\",\n\tKeyF10:               \"F10\",\n\tKeyF11:               \"F11\",\n\tKeyF12:               \"F12\",\n\tKeyF13:               \"F13\",\n\tKeyF14:               \"F14\",\n\tKeyF15:               \"F15\",\n\tKeyF16:               \"F16\",\n\tKeyF17:               \"F17\",\n\tKeyF18:               \"F18\",\n\tKeyF19:               \"F19\",\n\tKeyF20:               \"F20\",\n\tKeyF21:               \"F21\",\n\tKeyF22:               \"F22\",\n\tKeyF23:               \"F23\",\n\tKeyF24:               \"F24\",\n\tKeyNumlock:           \"Numlock\",\n\tKeyScroll:            \"Scroll\",\n\tKeyLShift:            \"LShift\",\n\tKeyRShift:            \"RShift\",\n\tKeyLControl:          \"LControl\",\n\tKeyRControl:          \"RControl\",\n\tKeyLMenu:             \"LMenu\",\n\tKeyRMenu:             \"RMenu\",\n\tKeyBrowserBack:       \"BrowserBack\",\n\tKeyBrowserForward:    \"BrowserForward\",\n\tKeyBrowserRefresh:    \"BrowserRefresh\",\n\tKeyBrowserStop:       \"BrowserStop\",\n\tKeyBrowserSearch:     \"BrowserSearch\",\n\tKeyBrowserFavorites:  \"BrowserFavorites\",\n\tKeyBrowserHome:       \"BrowserHome\",\n\tKeyVolumeMute:        \"VolumeMute\",\n\tKeyVolumeDown:        \"VolumeDown\",\n\tKeyVolumeUp:          \"VolumeUp\",\n\tKeyMediaNextTrack:    \"MediaNextTrack\",\n\tKeyMediaPrevTrack:    \"MediaPrevTrack\",\n\tKeyMediaStop:         \"MediaStop\",\n\tKeyMediaPlayPause:    \"MediaPlayPause\",\n\tKeyLaunchMail:        \"LaunchMail\",\n\tKeyLaunchMediaSelect: \"LaunchMediaSelect\",\n\tKeyLaunchApp1:        \"LaunchApp1\",\n\tKeyLaunchApp2:        \"LaunchApp2\",\n\tKeyOEM1:              \"OEM1\",\n\tKeyOEMPlus:           \"OEMPlus\",\n\tKeyOEMComma:          \"OEMComma\",\n\tKeyOEMMinus:          \"OEMMinus\",\n\tKeyOEMPeriod:         \"OEMPeriod\",\n\tKeyOEM2:              \"OEM2\",\n\tKeyOEM3:              \"OEM3\",\n\tKeyOEM4:              \"OEM4\",\n\tKeyOEM5:              \"OEM5\",\n\tKeyOEM6:              \"OEM6\",\n\tKeyOEM7:              \"OEM7\",\n\tKeyOEM8:              \"OEM8\",\n\tKeyOEM102:            \"OEM102\",\n\tKeyProcessKey:        \"ProcessKey\",\n\tKeyPacket:            \"Packet\",\n\tKeyAttn:              \"Attn\",\n\tKeyCRSel:             \"CRSel\",\n\tKeyEXSel:             \"EXSel\",\n\tKeyErEOF:             \"ErEOF\",\n\tKeyPlay:              \"Play\",\n\tKeyZoom:              \"Zoom\",\n\tKeyNoName:            \"NoName\",\n\tKeyPA1:               \"PA1\",\n\tKeyOEMClear:          \"OEMClear\",\n}\n\ntype Modifiers byte\n\nfunc (m Modifiers) String() string {\n\treturn modifiers2string[m]\n}\n\nvar modifiers2string = map[Modifiers]string{\n\tModShift:                       \"Shift\",\n\tModControl:                     \"Ctrl\",\n\tModControl | ModShift:          \"Ctrl+Shift\",\n\tModAlt:                         \"Alt\",\n\tModAlt | ModShift:              \"Alt+Shift\",\n\tModAlt | ModControl:            \"Alt+Ctrl\",\n\tModAlt | ModControl | ModShift: \"Alt+Ctrl+Shift\",\n}\n\nconst (\n\tModShift Modifiers = 1 << iota\n\tModControl\n\tModAlt\n)\n\nfunc ModifiersDown() Modifiers {\n\tvar m Modifiers\n\n\tif ShiftDown() {\n\t\tm |= ModShift\n\t}\n\tif ControlDown() {\n\t\tm |= ModControl\n\t}\n\tif AltDown() {\n\t\tm |= ModAlt\n\t}\n\n\treturn m\n}\n\ntype Shortcut struct {\n\tModifiers Modifiers\n\tKey       Key\n}\n\nfunc (s Shortcut) String() string {\n\tm := s.Modifiers.String()\n\tif m == \"\" {\n\t\treturn s.Key.String()\n\t}\n\n\tb := new(bytes.Buffer)\n\n\tb.WriteString(m)\n\tb.WriteRune('+')\n\tb.WriteString(s.Key.String())\n\n\treturn b.String()\n}\n\nfunc AltDown() bool {\n\treturn win.GetKeyState(int32(KeyAlt))>>15 != 0\n}\n\nfunc ControlDown() bool {\n\treturn win.GetKeyState(int32(KeyControl))>>15 != 0\n}\n\nfunc ShiftDown() bool {\n\treturn win.GetKeyState(int32(KeyShift))>>15 != 0\n}\n"
  },
  {
    "path": "keyevent.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype keyEventHandlerInfo struct {\n\thandler KeyEventHandler\n\tonce    bool\n}\n\ntype KeyEventHandler func(key Key)\n\ntype KeyEvent struct {\n\thandlers []keyEventHandlerInfo\n}\n\nfunc (e *KeyEvent) Attach(handler KeyEventHandler) int {\n\thandlerInfo := keyEventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *KeyEvent) Detach(handle int) {\n\te.handlers[handle].handler = nil\n}\n\nfunc (e *KeyEvent) Once(handler KeyEventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype KeyEventPublisher struct {\n\tevent KeyEvent\n}\n\nfunc (p *KeyEventPublisher) Event() *KeyEvent {\n\treturn &p.event\n}\n\nfunc (p *KeyEventPublisher) Publish(key Key) {\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler(key)\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "l10n/update.bat",
    "content": "polyglot -name=\"walk\" -dir=\"..\" -locales=\"de,fr,ko\"\n"
  },
  {
    "path": "l10n/walk-de.tr",
    "content": "{\"Messages\":[{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"148\"}],\"Source\":\"Please select one of the provided options.\",\"Context\":[\"walk\"],\"Translation\":\"Bitte wählen Sie eine der angebotenen Optionen.\"},{\"Locations\":[{\"File\":\"../declarative/radiobuttongroup.go\",\"Line\":\"93\"}],\"Source\":\"A selection is required.\",\"Context\":[\"walk\"],\"Translation\":\"Eine Auswahl wird benötigt.\"},{\"Locations\":[{\"File\":\"../tooltiperrorpresenter.go\",\"Line\":\"107\"}],\"Source\":\"Invalid Input\",\"Context\":null,\"Translation\":\"Ungültige Eingabe\"},{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"80\"}],\"Source\":\"Please enter a number from %.f to %.f.\",\"Context\":[\"walk\"],\"Translation\":\"Bitte geben Sie eine Zahl von %.f bis %.f ein.\"},{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"83\"}],\"Source\":\"Please enter a number from %s to %s.\",\"Context\":[\"walk\"],\"Translation\":\"Bitte geben Sie eine Zahl von %s bis %s ein.\"},{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"87\"}],\"Source\":\"Number out of allowed range\",\"Context\":[\"walk\"],\"Translation\":\"Zahl außerhalb des gültigen Bereichs\"},{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"128\"}],\"Source\":\"The text does not match the required pattern.\",\"Context\":[\"walk\"],\"Translation\":\"Der Text entspricht nicht dem erforderlichen Muster.\"},{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"147\"}],\"Source\":\"Selection Required\",\"Context\":[\"walk\"],\"Translation\":\"Auswahl benötigt\"}]}\n"
  },
  {
    "path": "l10n/walk-ko.tr",
    "content": "{\"Messages\":[{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"87\"}],\"Source\":\"Number out of allowed range\",\"Context\":[\"walk\"],\"Translation\":\"허용 범위 초과\"},{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"128\"}],\"Source\":\"The text does not match the required pattern.\",\"Context\":[\"walk\"],\"Translation\":\"문자열이 요구되는 형식에 맞지 않습니다.\"},{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"147\"}],\"Source\":\"Selection Required\",\"Context\":[\"walk\"],\"Translation\":\"선택 필요\"},{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"148\"}],\"Source\":\"Please select one of the provided options.\",\"Context\":[\"walk\"],\"Translation\":\"옵션 중 하나를 선택하십시오\"},{\"Locations\":[{\"File\":\"../tooltiperrorpresenter.go\",\"Line\":\"107\"}],\"Source\":\"Invalid Input\",\"Context\":null,\"Translation\":\"잘못된 입력\"},{\"Locations\":[{\"File\":\"../declarative/radiobuttongroup.go\",\"Line\":\"93\"}],\"Source\":\"A selection is required.\",\"Context\":[\"walk\"],\"Translation\":\"항목 선택이 필요합니다.\"},{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"80\"}],\"Source\":\"Please enter a number from %.f to %.f.\",\"Context\":[\"walk\"],\"Translation\":\"%.f에서 %.f 사이의 숫자를 입력하십시오.\"},{\"Locations\":[{\"File\":\"../validators.go\",\"Line\":\"83\"}],\"Source\":\"Please enter a number from %s to %s.\",\"Context\":[\"walk\"],\"Translation\":\"%s에서 %s 사이의 숫자를 입력하십시오.\"}]}"
  },
  {
    "path": "label.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport \"github.com/lxn/win\"\n\ntype EllipsisMode int\n\nconst (\n\tEllipsisNone EllipsisMode = 0\n\tEllipsisEnd               = EllipsisMode(win.SS_ENDELLIPSIS)\n\tEllipsisPath              = EllipsisMode(win.SS_PATHELLIPSIS)\n)\n\ntype Label struct {\n\tstatic\n\ttextChangedPublisher EventPublisher\n}\n\nfunc NewLabel(parent Container) (*Label, error) {\n\treturn NewLabelWithStyle(parent, 0)\n}\n\nfunc NewLabelWithStyle(parent Container, style uint32) (*Label, error) {\n\tl := new(Label)\n\n\tif err := l.init(l, parent, style); err != nil {\n\t\treturn nil, err\n\t}\n\n\tl.SetTextAlignment(AlignNear)\n\n\tl.MustRegisterProperty(\"Text\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn l.Text()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn l.SetText(assertStringOr(v, \"\"))\n\t\t},\n\t\tl.textChangedPublisher.Event()))\n\n\treturn l, nil\n}\n\nfunc (l *Label) asStatic() *static {\n\treturn &l.static\n}\n\nfunc (l *Label) EllipsisMode() EllipsisMode {\n\treturn EllipsisMode(win.GetWindowLong(l.hwndStatic, win.GWL_STYLE) & (win.SS_ENDELLIPSIS | win.SS_PATHELLIPSIS))\n}\n\nfunc (l *Label) SetEllipsisMode(mode EllipsisMode) error {\n\toldMode := l.EllipsisMode()\n\n\tif mode == oldMode {\n\t\treturn nil\n\t}\n\n\tif err := setAndClearWindowLongBits(l.hwndStatic, win.GWL_STYLE, uint32(mode), uint32(oldMode)); err != nil {\n\t\treturn err\n\t}\n\n\tl.RequestLayout()\n\n\treturn nil\n}\n\nfunc (l *Label) TextAlignment() Alignment1D {\n\treturn l.textAlignment1D()\n}\n\nfunc (l *Label) SetTextAlignment(alignment Alignment1D) error {\n\tif alignment == AlignDefault {\n\t\talignment = AlignNear\n\t}\n\n\treturn l.setTextAlignment1D(alignment)\n}\n\nfunc (l *Label) Text() string {\n\treturn l.text()\n}\n\nfunc (l *Label) SetText(text string) error {\n\tif changed, err := l.setText(text); err != nil {\n\t\treturn err\n\t} else if !changed {\n\t\treturn nil\n\t}\n\n\tl.textChangedPublisher.Publish()\n\n\treturn nil\n}\n"
  },
  {
    "path": "layout.go",
    "content": "// Copyright 2019 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"sync\"\n\n\t\"github.com/lxn/win\"\n)\n\nfunc createLayoutItemForWidget(widget Widget) LayoutItem {\n\tctx := newLayoutContext(widget.Handle())\n\n\treturn createLayoutItemForWidgetWithContext(widget, ctx)\n}\n\nfunc createLayoutItemForWidgetWithContext(widget Widget, ctx *LayoutContext) LayoutItem {\n\tvar item LayoutItem\n\n\tif container, ok := widget.(Container); ok {\n\t\tif container.Layout() == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\titem = CreateLayoutItemsForContainerWithContext(container, ctx)\n\t} else {\n\t\titem = widget.CreateLayoutItem(ctx)\n\t}\n\n\tlib := item.AsLayoutItemBase()\n\tlib.ctx = ctx\n\tlib.handle = widget.Handle()\n\tlib.visible = widget.AsWidgetBase().visible\n\tlib.geometry = widget.AsWidgetBase().geometry\n\tlib.geometry.Alignment = widget.Alignment()\n\tlib.geometry.MinSize = widget.MinSizePixels()\n\tlib.geometry.MaxSize = widget.MaxSizePixels()\n\tlib.geometry.ConsumingSpaceWhenInvisible = widget.AlwaysConsumeSpace()\n\n\treturn item\n}\n\nfunc CreateLayoutItemsForContainer(container Container) ContainerLayoutItem {\n\tctx := newLayoutContext(container.Handle())\n\n\treturn CreateLayoutItemsForContainerWithContext(container, ctx)\n}\n\nfunc CreateLayoutItemsForContainerWithContext(container Container, ctx *LayoutContext) ContainerLayoutItem {\n\tvar containerItem ContainerLayoutItem\n\tvar clib *ContainerLayoutItemBase\n\n\tlayout := container.Layout()\n\tif layout == nil || container.Children().Len() == 0 {\n\t\tlayout = NewHBoxLayout()\n\t\tlayout.SetMargins(Margins{})\n\t}\n\n\tif widget, ok := container.(Widget); ok {\n\t\tcontainerItem = widget.CreateLayoutItem(ctx).(ContainerLayoutItem)\n\t} else {\n\t\tcontainerItem = layout.CreateLayoutItem(ctx)\n\t}\n\n\tclib = containerItem.AsContainerLayoutItemBase()\n\tclib.ctx = ctx\n\tclib.handle = container.Handle()\n\tcb := container.AsContainerBase()\n\tclib.visible = cb.visible\n\tclib.geometry = cb.geometry\n\tclib.geometry.ConsumingSpaceWhenInvisible = cb.AlwaysConsumeSpace()\n\n\tif lb := layout.asLayoutBase(); lb != nil {\n\t\tclib.alignment = lb.alignment\n\t\tclib.margins96dpi = lb.margins96dpi\n\t\tclib.spacing96dpi = lb.spacing96dpi\n\t}\n\n\tif len(clib.children) == 0 {\n\t\tchildren := container.Children()\n\t\tcount := children.Len()\n\n\t\tfor i := 0; i < count; i++ {\n\t\t\titem := createLayoutItemForWidgetWithContext(children.At(i), ctx)\n\t\t\tif item != nil {\n\t\t\t\tlib := item.AsLayoutItemBase()\n\t\t\t\tlib.ctx = ctx\n\t\t\t\tlib.parent = containerItem\n\n\t\t\t\tclib.children = append(clib.children, item)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn containerItem\n}\n\nfunc startLayoutPerformer(form Form) (performLayout chan ContainerLayoutItem, layoutResults chan []LayoutResult, inSizeLoop chan bool, updateStopwatch chan *stopwatch, quit chan struct{}) {\n\tperformLayout = make(chan ContainerLayoutItem)\n\tlayoutResults = make(chan []LayoutResult)\n\tinSizeLoop = make(chan bool)\n\tupdateStopwatch = make(chan *stopwatch)\n\tquit = make(chan struct{})\n\n\tvar stopwatch *stopwatch\n\n\tgo func() {\n\t\tsizing := false\n\t\tbusy := false\n\t\tvar cancel chan struct{}\n\t\tdone := make(chan []LayoutResult)\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase root := <-performLayout:\n\t\t\t\tif busy {\n\t\t\t\t\tclose(cancel)\n\t\t\t\t}\n\n\t\t\t\tbusy = true\n\t\t\t\tcancel = make(chan struct{})\n\n\t\t\t\tgo layoutTree(root, root.Geometry().ClientSize, cancel, done, stopwatch)\n\n\t\t\tcase results := <-done:\n\t\t\t\tbusy = false\n\t\t\t\tif cancel != nil {\n\t\t\t\t\tclose(cancel)\n\t\t\t\t\tcancel = nil\n\t\t\t\t}\n\n\t\t\t\tif sizing {\n\t\t\t\t\tlayoutResults <- results\n\t\t\t\t} else {\n\t\t\t\t\tform.AsFormBase().synchronizeLayout(&formLayoutResult{form, stopwatch, results})\n\t\t\t\t}\n\n\t\t\tcase sizing = <-inSizeLoop:\n\n\t\t\tcase stopwatch = <-updateStopwatch:\n\n\t\t\tcase <-quit:\n\t\t\t\tclose(performLayout)\n\t\t\t\tclose(layoutResults)\n\t\t\t\tclose(inSizeLoop)\n\t\t\t\tclose(updateStopwatch)\n\t\t\t\tif cancel != nil {\n\t\t\t\t\tclose(cancel)\n\t\t\t\t}\n\t\t\t\tclose(done)\n\t\t\t\tclose(quit)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn\n}\n\n// layoutTree lays out tree. size parameter is in native pixels.\nfunc layoutTree(root ContainerLayoutItem, size Size, cancel chan struct{}, done chan []LayoutResult, stopwatch *stopwatch) {\n\tconst minSizeCacheSubject = \"layoutTree - populating min size cache\"\n\n\tif stopwatch != nil {\n\t\tstopwatch.Start(minSizeCacheSubject)\n\t}\n\n\t// Populate some caches now, so we later need only read access to them from multiple goroutines.\n\tctx := root.Context()\n\n\tpopulateContextForItem := func(item LayoutItem) {\n\t\tctx.layoutItem2MinSizeEffective[item] = minSizeEffective(item)\n\t}\n\n\tvar populateContextForContainer func(container ContainerLayoutItem)\n\tpopulateContextForContainer = func(container ContainerLayoutItem) {\n\t\tfor _, child := range container.AsContainerLayoutItemBase().children {\n\t\t\tif cli, ok := child.(ContainerLayoutItem); ok {\n\t\t\t\tpopulateContextForContainer(cli)\n\t\t\t} else {\n\t\t\t\tpopulateContextForItem(child)\n\t\t\t}\n\t\t}\n\n\t\tpopulateContextForItem(container)\n\t}\n\n\tpopulateContextForContainer(root)\n\n\tif stopwatch != nil {\n\t\tstopwatch.Stop(minSizeCacheSubject)\n\t}\n\n\tconst layoutSubject = \"layoutTree - computing layout\"\n\n\tif stopwatch != nil {\n\t\tstopwatch.Start(layoutSubject)\n\t}\n\n\tresults := make(chan LayoutResult)\n\tfinished := make(chan struct{})\n\n\tgo func() {\n\t\tdefer func() {\n\t\t\tclose(results)\n\t\t\tclose(finished)\n\t\t}()\n\n\t\tvar wg sync.WaitGroup\n\n\t\tvar layoutSubtree func(container ContainerLayoutItem, size Size)\n\t\tlayoutSubtree = func(container ContainerLayoutItem, size Size) {\n\t\t\twg.Add(1)\n\n\t\t\tgo func() {\n\t\t\t\tdefer wg.Done()\n\n\t\t\t\tclib := container.AsContainerLayoutItemBase()\n\n\t\t\t\tclib.geometry.ClientSize = size\n\n\t\t\t\titems := container.PerformLayout()\n\n\t\t\t\tselect {\n\t\t\t\tcase <-cancel:\n\t\t\t\t\treturn\n\n\t\t\t\tcase results <- LayoutResult{container, items}:\n\t\t\t\t}\n\n\t\t\t\tfor _, item := range items {\n\t\t\t\t\tselect {\n\t\t\t\t\tcase <-cancel:\n\t\t\t\t\t\treturn\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t}\n\n\t\t\t\t\titem.Item.Geometry().Size = item.Bounds.Size()\n\n\t\t\t\t\tif childContainer, ok := item.Item.(ContainerLayoutItem); ok {\n\t\t\t\t\t\tlayoutSubtree(childContainer, item.Bounds.Size())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\n\t\tlayoutSubtree(root, size)\n\n\t\twg.Wait()\n\n\t\tselect {\n\t\tcase <-cancel:\n\t\t\treturn\n\n\t\tcase finished <- struct{}{}:\n\t\t}\n\t}()\n\n\tvar layoutResults []LayoutResult\n\n\tfor {\n\t\tselect {\n\t\tcase result := <-results:\n\t\t\tlayoutResults = append(layoutResults, result)\n\n\t\tcase <-finished:\n\t\t\tif stopwatch != nil {\n\t\t\t\tstopwatch.Stop(layoutSubject)\n\t\t\t}\n\n\t\t\tdone <- layoutResults\n\t\t\treturn\n\n\t\tcase <-cancel:\n\t\t\tif stopwatch != nil {\n\t\t\t\tstopwatch.Cancel(layoutSubject)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc applyLayoutResults(results []LayoutResult, stopwatch *stopwatch) error {\n\tif stopwatch != nil {\n\t\tconst subject = \"applyLayoutResults\"\n\t\tstopwatch.Start(subject)\n\t\tdefer stopwatch.Stop(subject)\n\t}\n\n\tvar form Form\n\n\tfor _, result := range results {\n\t\tif len(result.items) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\thdwp := win.BeginDeferWindowPos(int32(len(result.items)))\n\t\tif hdwp == 0 {\n\t\t\treturn lastError(\"BeginDeferWindowPos\")\n\t\t}\n\n\t\tvar maybeInvalidate bool\n\t\tif wnd := windowFromHandle(result.container.Handle()); wnd != nil {\n\t\t\tif ctr, ok := wnd.(Container); ok {\n\t\t\t\tif cb := ctr.AsContainerBase(); cb != nil {\n\t\t\t\t\tmaybeInvalidate = cb.hasComplexBackground()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor _, ri := range result.items {\n\t\t\tif ri.Item.Handle() != 0 {\n\t\t\t\twindow := windowFromHandle(ri.Item.Handle())\n\t\t\t\tif window == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif form == nil {\n\t\t\t\t\tif form = window.Form(); form != nil {\n\t\t\t\t\t\tdefer func() {\n\t\t\t\t\t\t\thwndFocused := win.GetFocus()\n\t\t\t\t\t\t\thwndForm := win.GetAncestor(hwndFocused, win.GA_ROOT)\n\t\t\t\t\t\t\tactiveForm, _ := windowFromHandle(hwndForm).(Form)\n\n\t\t\t\t\t\t\tif hwndFocused == 0 || form.Handle() == hwndFocused || activeForm != window.Form() {\n\t\t\t\t\t\t\t\tform.AsFormBase().clientComposite.focusFirstCandidateDescendant()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twidget := window.(Widget)\n\n\t\t\t\toldBounds := widget.BoundsPixels()\n\n\t\t\t\tif ri.Bounds == oldBounds {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif ri.Bounds.X == oldBounds.X && ri.Bounds.Y == oldBounds.Y && ri.Bounds.Width == oldBounds.Width {\n\t\t\t\t\tif _, ok := widget.(*ComboBox); ok {\n\t\t\t\t\t\tif ri.Bounds.Height == oldBounds.Height+1 {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if ri.Bounds.Height == oldBounds.Height {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif maybeInvalidate {\n\t\t\t\t\tif ri.Bounds.Width == oldBounds.Width && ri.Bounds.Height == oldBounds.Height && (ri.Bounds.X != oldBounds.X || ri.Bounds.Y != oldBounds.Y) {\n\t\t\t\t\t\twidget.Invalidate()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif hdwp = win.DeferWindowPos(\n\t\t\t\t\thdwp,\n\t\t\t\t\tri.Item.Handle(),\n\t\t\t\t\t0,\n\t\t\t\t\tint32(ri.Bounds.X),\n\t\t\t\t\tint32(ri.Bounds.Y),\n\t\t\t\t\tint32(ri.Bounds.Width),\n\t\t\t\t\tint32(ri.Bounds.Height),\n\t\t\t\t\twin.SWP_NOACTIVATE|win.SWP_NOOWNERZORDER|win.SWP_NOZORDER); hdwp == 0 {\n\n\t\t\t\t\treturn lastError(\"DeferWindowPos\")\n\t\t\t\t}\n\n\t\t\t\tif widget.GraphicsEffects().Len() == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\twidget.AsWidgetBase().invalidateBorderInParent()\n\t\t\t}\n\t\t}\n\n\t\tif !win.EndDeferWindowPos(hdwp) {\n\t\t\treturn lastError(\"EndDeferWindowPos\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Margins define margins in 1/96\" units or native pixels.\ntype Margins struct {\n\tHNear, VNear, HFar, VFar int\n}\n\nfunc (m Margins) isZero() bool {\n\treturn m.HNear == 0 && m.HFar == 0 && m.VNear == 0 && m.VFar == 0\n}\n\ntype Layout interface {\n\tContainer() Container\n\tSetContainer(value Container)\n\tMargins() Margins\n\tSetMargins(value Margins) error\n\tSpacing() int\n\tSetSpacing(value int) error\n\tCreateLayoutItem(ctx *LayoutContext) ContainerLayoutItem\n\tasLayoutBase() *LayoutBase\n}\n\ntype LayoutBase struct {\n\tlayout       Layout\n\tcontainer    Container\n\tmargins96dpi Margins\n\tmargins      Margins // in native pixels\n\tspacing96dpi int\n\tspacing      int // in native pixels\n\talignment    Alignment2D\n\tresetNeeded  bool\n\tdirty        bool\n}\n\nfunc (l *LayoutBase) asLayoutBase() *LayoutBase {\n\treturn l\n}\n\nfunc (l *LayoutBase) Container() Container {\n\treturn l.container\n}\n\nfunc (l *LayoutBase) SetContainer(value Container) {\n\tif value == l.container {\n\t\treturn\n\t}\n\n\tif l.container != nil {\n\t\tl.container.SetLayout(nil)\n\t}\n\n\tl.container = value\n\n\tif value != nil && value.Layout() != l.layout {\n\t\tvalue.SetLayout(l.layout)\n\t}\n\n\tl.updateMargins()\n\tl.updateSpacing()\n\n\tif l.container != nil {\n\t\tl.container.RequestLayout()\n\t}\n}\n\nfunc (l *LayoutBase) Margins() Margins {\n\treturn l.margins96dpi\n}\n\nfunc (l *LayoutBase) SetMargins(value Margins) error {\n\tif value == l.margins96dpi {\n\t\treturn nil\n\t}\n\n\tif value.HNear < 0 || value.VNear < 0 || value.HFar < 0 || value.VFar < 0 {\n\t\treturn newError(\"margins must be positive\")\n\t}\n\n\tl.margins96dpi = value\n\n\tl.updateMargins()\n\n\tif l.container != nil {\n\t\tl.container.RequestLayout()\n\t}\n\n\treturn nil\n}\n\nfunc (l *LayoutBase) Spacing() int {\n\treturn l.spacing96dpi\n}\n\nfunc (l *LayoutBase) SetSpacing(value int) error {\n\tif value == l.spacing96dpi {\n\t\treturn nil\n\t}\n\n\tif value < 0 {\n\t\treturn newError(\"spacing cannot be negative\")\n\t}\n\n\tl.spacing96dpi = value\n\n\tl.updateSpacing()\n\n\tif l.container != nil {\n\t\tl.container.RequestLayout()\n\t}\n\n\treturn nil\n}\n\nfunc (l *LayoutBase) updateMargins() {\n\tif l.container != nil {\n\t\tl.margins = MarginsFrom96DPI(l.margins96dpi, l.container.AsWindowBase().DPI())\n\t}\n}\n\nfunc (l *LayoutBase) updateSpacing() {\n\tif l.container != nil {\n\t\tl.spacing = IntFrom96DPI(l.spacing96dpi, l.container.AsWindowBase().DPI())\n\t}\n}\n\nfunc (l *LayoutBase) Alignment() Alignment2D {\n\treturn l.alignment\n}\n\nfunc (l *LayoutBase) SetAlignment(alignment Alignment2D) error {\n\tif alignment != l.alignment {\n\t\tif alignment < AlignHVDefault || alignment > AlignHFarVFar {\n\t\t\treturn newError(\"invalid Alignment value\")\n\t\t}\n\n\t\tl.alignment = alignment\n\n\t\tif l.container != nil {\n\t\t\tl.container.RequestLayout()\n\t\t}\n\t}\n\n\treturn nil\n}\n\ntype IdealSizer interface {\n\t// IdealSize returns ideal window size in native pixels.\n\tIdealSize() Size\n}\n\ntype MinSizer interface {\n\t// MinSize returns minimum window size in native pixels.\n\tMinSize() Size\n}\n\ntype MinSizeForSizer interface {\n\t// MinSize returns minimum window size for given size. Both sizes are in native pixels.\n\tMinSizeForSize(size Size) Size\n}\n\ntype HeightForWidther interface {\n\tHasHeightForWidth() bool\n\n\t// HeightForWidth returns appropriate height if element has given width. width parameter and\n\t// return value are in native pixels.\n\tHeightForWidth(width int) int\n}\n\ntype LayoutContext struct {\n\tlayoutItem2MinSizeEffective map[LayoutItem]Size // in native pixels\n\tdpi                         int\n}\n\nfunc (ctx *LayoutContext) DPI() int {\n\treturn ctx.dpi\n}\n\nfunc newLayoutContext(handle win.HWND) *LayoutContext {\n\treturn &LayoutContext{\n\t\tlayoutItem2MinSizeEffective: make(map[LayoutItem]Size),\n\t\tdpi:                         int(win.GetDpiForWindow(handle)),\n\t}\n}\n\ntype LayoutItem interface {\n\tAsLayoutItemBase() *LayoutItemBase\n\tContext() *LayoutContext\n\tHandle() win.HWND\n\tGeometry() *Geometry\n\tParent() ContainerLayoutItem\n\tVisible() bool\n\tLayoutFlags() LayoutFlags\n}\n\ntype ContainerLayoutItem interface {\n\tLayoutItem\n\tMinSizer\n\tMinSizeForSizer\n\tHeightForWidther\n\tAsContainerLayoutItemBase() *ContainerLayoutItemBase\n\n\t// MinSizeEffectiveForChild returns minimum effective size for a child in native pixels.\n\tMinSizeEffectiveForChild(child LayoutItem) Size\n\n\tPerformLayout() []LayoutResultItem\n\tChildren() []LayoutItem\n\tcontainsHandle(handle win.HWND) bool\n}\n\ntype LayoutItemBase struct {\n\tctx      *LayoutContext\n\thandle   win.HWND\n\tgeometry Geometry\n\tparent   ContainerLayoutItem\n\tvisible  bool\n}\n\nfunc (lib *LayoutItemBase) AsLayoutItemBase() *LayoutItemBase {\n\treturn lib\n}\n\nfunc (lib *LayoutItemBase) Context() *LayoutContext {\n\treturn lib.ctx\n}\n\nfunc (lib *LayoutItemBase) Handle() win.HWND {\n\treturn lib.handle\n}\n\nfunc (lib *LayoutItemBase) Geometry() *Geometry {\n\treturn &lib.geometry\n}\n\nfunc (lib *LayoutItemBase) Parent() ContainerLayoutItem {\n\treturn lib.parent\n}\n\nfunc (lib *LayoutItemBase) Visible() bool {\n\treturn lib.visible\n}\n\ntype ContainerLayoutItemBase struct {\n\tLayoutItemBase\n\tchildren     []LayoutItem\n\tmargins96dpi Margins\n\tspacing96dpi int\n\talignment    Alignment2D\n}\n\nfunc (clib *ContainerLayoutItemBase) AsContainerLayoutItemBase() *ContainerLayoutItemBase {\n\treturn clib\n}\n\nvar clibMinSizeEffectiveForChildMutex sync.Mutex\n\nfunc (clib *ContainerLayoutItemBase) MinSizeEffectiveForChild(child LayoutItem) Size {\n\t// NOTE: This map is pre-populated in startLayoutTree before performing layout.\n\t// For other usages it is not pre-populated and we assume this method will then\n\t// be called from the main goroutine exclusively.\n\t// If we want to do concurrent size measurement, we will need to pre-populate also.\n\n\t// FIXME: There seems to be a bug in pre-population, so we use a mutex for now.\n\n\tclibMinSizeEffectiveForChildMutex.Lock()\n\n\tif clib.ctx != nil {\n\t\tif size, ok := clib.ctx.layoutItem2MinSizeEffective[child]; ok {\n\t\t\tclibMinSizeEffectiveForChildMutex.Unlock()\n\t\t\treturn size\n\t\t}\n\t}\n\n\tif clib.ctx == nil {\n\t\tif clib.parent == nil {\n\t\t\tclib.ctx = newLayoutContext(clib.Handle())\n\t\t} else {\n\t\t\tclib.ctx = clib.parent.Context()\n\t\t}\n\t}\n\n\tchild.AsLayoutItemBase().ctx = clib.ctx\n\n\tclibMinSizeEffectiveForChildMutex.Unlock()\n\n\tsize := minSizeEffective(child)\n\n\tclibMinSizeEffectiveForChildMutex.Lock()\n\n\tif clib.ctx != nil {\n\t\tclib.ctx.layoutItem2MinSizeEffective[child] = size\n\t}\n\n\tclibMinSizeEffectiveForChildMutex.Unlock()\n\n\treturn size\n}\n\nfunc (clib *ContainerLayoutItemBase) Children() []LayoutItem {\n\treturn clib.children\n}\n\nfunc (clib *ContainerLayoutItemBase) SetChildren(children []LayoutItem) {\n\tclib.children = children\n}\n\nfunc (clib *ContainerLayoutItemBase) containsHandle(handle win.HWND) bool {\n\tfor _, item := range clib.children {\n\t\tif item.Handle() == handle {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (clib *ContainerLayoutItemBase) HasHeightForWidth() bool {\n\tfor _, child := range clib.children {\n\t\tif hfw, ok := child.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\ntype greedyLayoutItem struct {\n\tLayoutItemBase\n}\n\nfunc NewGreedyLayoutItem() LayoutItem {\n\treturn new(greedyLayoutItem)\n}\n\nfunc (*greedyLayoutItem) LayoutFlags() LayoutFlags {\n\treturn ShrinkableHorz | GrowableHorz | GreedyHorz | ShrinkableVert | GrowableVert | GreedyVert\n}\n\nfunc (li *greedyLayoutItem) IdealSize() Size {\n\treturn SizeFrom96DPI(Size{100, 100}, li.ctx.dpi)\n}\n\nfunc (li *greedyLayoutItem) MinSize() Size {\n\treturn SizeFrom96DPI(Size{50, 50}, li.ctx.dpi)\n}\n\ntype Geometry struct {\n\tAlignment                   Alignment2D\n\tMinSize                     Size // in native pixels\n\tMaxSize                     Size // in native pixels\n\tIdealSize                   Size // in native pixels\n\tSize                        Size // in native pixels\n\tClientSize                  Size // in native pixels\n\tConsumingSpaceWhenInvisible bool\n}\n\ntype formLayoutResult struct {\n\tform      Form\n\tstopwatch *stopwatch\n\tresults   []LayoutResult\n}\n\ntype LayoutResult struct {\n\tcontainer ContainerLayoutItem\n\titems     []LayoutResultItem\n}\n\ntype LayoutResultItem struct {\n\tItem   LayoutItem\n\tBounds Rectangle // in native pixels\n}\n\nfunc shouldLayoutItem(item LayoutItem) bool {\n\tif item == nil {\n\t\treturn false\n\t}\n\n\t_, isSpacer := item.(*spacerLayoutItem)\n\n\treturn isSpacer || item.Visible() || item.Geometry().ConsumingSpaceWhenInvisible\n}\n\nfunc itemsToLayout(allItems []LayoutItem) []LayoutItem {\n\tfilteredItems := make([]LayoutItem, 0, len(allItems))\n\n\tfor i := 0; i < cap(filteredItems); i++ {\n\t\titem := allItems[i]\n\n\t\tif !shouldLayoutItem(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar idealSize Size\n\t\tif hfw, ok := item.(HeightForWidther); !ok || !hfw.HasHeightForWidth() {\n\t\t\tif is, ok := item.(IdealSizer); ok {\n\t\t\t\tidealSize = is.IdealSize()\n\t\t\t}\n\t\t}\n\t\tif idealSize.Width == 0 && idealSize.Height == 0 && item.LayoutFlags() == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfilteredItems = append(filteredItems, item)\n\t}\n\n\treturn filteredItems\n}\n\nfunc anyVisibleItemInHierarchy(item LayoutItem) bool {\n\tif item == nil || !item.Visible() {\n\t\treturn false\n\t}\n\n\tif cli, ok := item.(ContainerLayoutItem); ok {\n\t\tfor _, child := range cli.AsContainerLayoutItemBase().children {\n\t\t\tif anyVisibleItemInHierarchy(child) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t} else if _, ok := item.(*spacerLayoutItem); !ok {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// minSizeEffective returns minimum effective size in native pixels\nfunc minSizeEffective(item LayoutItem) Size {\n\tgeometry := item.Geometry()\n\n\tvar s Size\n\tif msh, ok := item.(MinSizer); ok {\n\t\ts = msh.MinSize()\n\t} else if is, ok := item.(IdealSizer); ok {\n\t\ts = is.IdealSize()\n\t}\n\n\tsize := maxSize(geometry.MinSize, s)\n\n\tmax := geometry.MaxSize\n\tif max.Width > 0 && size.Width > max.Width {\n\t\tsize.Width = max.Width\n\t}\n\tif max.Height > 0 && size.Height > max.Height {\n\t\tsize.Height = max.Height\n\t}\n\n\treturn size\n}\n"
  },
  {
    "path": "lineedit.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype CaseMode uint32\n\nconst (\n\tCaseModeMixed CaseMode = iota\n\tCaseModeUpper\n\tCaseModeLower\n)\n\nconst (\n\tlineEditMinChars    = 1  // 10 // number of characters needed to make a LineEdit usable\n\tlineEditGreedyLimit = 29 // 80 // fields with MaxLength larger than this will be greedy (default length is 32767)\n)\n\ntype LineEdit struct {\n\tWidgetBase\n\teditingFinishedPublisher EventPublisher\n\treadOnlyChangedPublisher EventPublisher\n\ttextChangedPublisher     EventPublisher\n\tcharWidthFont            *Font\n\tcharWidth                int // in native pixels\n\ttextColor                Color\n}\n\nfunc newLineEdit(parent Window) (*LineEdit, error) {\n\tle := new(LineEdit)\n\n\tif err := InitWindow(\n\t\tle,\n\t\tparent,\n\t\t\"EDIT\",\n\t\twin.WS_CHILD|win.WS_TABSTOP|win.WS_VISIBLE|win.ES_AUTOHSCROLL,\n\t\twin.WS_EX_CLIENTEDGE); err != nil {\n\t\treturn nil, err\n\t}\n\n\tle.GraphicsEffects().Add(InteractionEffect)\n\tle.GraphicsEffects().Add(FocusEffect)\n\n\tle.MustRegisterProperty(\"ReadOnly\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn le.ReadOnly()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn le.SetReadOnly(v.(bool))\n\t\t},\n\t\tle.readOnlyChangedPublisher.Event()))\n\n\tle.MustRegisterProperty(\"Text\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn le.Text()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn le.SetText(assertStringOr(v, \"\"))\n\t\t},\n\t\tle.textChangedPublisher.Event()))\n\n\treturn le, nil\n}\n\nfunc NewLineEdit(parent Container) (*LineEdit, error) {\n\tif parent == nil {\n\t\treturn nil, newError(\"parent cannot be nil\")\n\t}\n\n\tle, err := newLineEdit(parent)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar succeeded bool\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tle.Dispose()\n\t\t}\n\t}()\n\n\tle.parent = parent\n\tif err = parent.Children().Add(le); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded = true\n\n\treturn le, nil\n}\n\nfunc (le *LineEdit) CueBanner() string {\n\tbuf := make([]uint16, 128)\n\tif win.FALSE == le.SendMessage(win.EM_GETCUEBANNER, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf))) {\n\t\tnewError(\"EM_GETCUEBANNER failed\")\n\t\treturn \"\"\n\t}\n\n\treturn syscall.UTF16ToString(buf)\n}\n\nfunc (le *LineEdit) SetCueBanner(value string) error {\n\tif win.FALSE == le.SendMessage(win.EM_SETCUEBANNER, win.FALSE, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value)))) {\n\t\treturn newError(\"EM_SETCUEBANNER failed\")\n\t}\n\n\treturn nil\n}\n\nfunc (le *LineEdit) MaxLength() int {\n\treturn int(le.SendMessage(win.EM_GETLIMITTEXT, 0, 0))\n}\n\nfunc (le *LineEdit) SetMaxLength(value int) {\n\tle.SendMessage(win.EM_LIMITTEXT, uintptr(value), 0)\n}\n\nfunc (le *LineEdit) Text() string {\n\treturn le.text()\n}\n\nfunc (le *LineEdit) SetText(value string) error {\n\treturn le.setText(value)\n}\n\nfunc (le *LineEdit) TextSelection() (start, end int) {\n\tle.SendMessage(win.EM_GETSEL, uintptr(unsafe.Pointer(&start)), uintptr(unsafe.Pointer(&end)))\n\treturn\n}\n\nfunc (le *LineEdit) SetTextSelection(start, end int) {\n\tle.SendMessage(win.EM_SETSEL, uintptr(start), uintptr(end))\n}\n\nfunc (le *LineEdit) TextAlignment() Alignment1D {\n\tswitch win.GetWindowLong(le.hWnd, win.GWL_STYLE) & (win.ES_LEFT | win.ES_CENTER | win.ES_RIGHT) {\n\tcase win.ES_CENTER:\n\t\treturn AlignCenter\n\n\tcase win.ES_RIGHT:\n\t\treturn AlignFar\n\t}\n\n\treturn AlignNear\n}\n\nfunc (le *LineEdit) SetTextAlignment(alignment Alignment1D) error {\n\tif alignment == AlignDefault {\n\t\talignment = AlignNear\n\t}\n\n\tvar bit uint32\n\n\tswitch alignment {\n\tcase AlignCenter:\n\t\tbit = win.ES_CENTER\n\n\tcase AlignFar:\n\t\tbit = win.ES_RIGHT\n\n\tdefault:\n\t\tbit = win.ES_LEFT\n\t}\n\n\treturn le.setAndClearStyleBits(bit, win.ES_LEFT|win.ES_CENTER|win.ES_RIGHT)\n}\n\nfunc (le *LineEdit) CaseMode() CaseMode {\n\tstyle := uint32(win.GetWindowLong(le.hWnd, win.GWL_STYLE))\n\n\tif style&win.ES_UPPERCASE != 0 {\n\t\treturn CaseModeUpper\n\t} else if style&win.ES_LOWERCASE != 0 {\n\t\treturn CaseModeLower\n\t} else {\n\t\treturn CaseModeMixed\n\t}\n}\n\nfunc (le *LineEdit) SetCaseMode(mode CaseMode) error {\n\tvar set, clear uint32\n\n\tswitch mode {\n\tcase CaseModeMixed:\n\t\tclear = win.ES_UPPERCASE | win.ES_LOWERCASE\n\n\tcase CaseModeUpper:\n\t\tset = win.ES_UPPERCASE\n\t\tclear = win.ES_LOWERCASE\n\n\tcase CaseModeLower:\n\t\tset = win.ES_LOWERCASE\n\t\tclear = win.ES_UPPERCASE\n\n\tdefault:\n\t\tpanic(\"invalid CaseMode\")\n\t}\n\n\treturn le.setAndClearStyleBits(set, clear)\n}\n\nfunc (le *LineEdit) PasswordMode() bool {\n\treturn le.SendMessage(win.EM_GETPASSWORDCHAR, 0, 0) != 0\n}\n\nfunc (le *LineEdit) SetPasswordMode(value bool) {\n\tvar c uintptr\n\tif value {\n\t\tc = uintptr('*')\n\t}\n\n\tle.SendMessage(win.EM_SETPASSWORDCHAR, c, 0)\n}\n\nfunc (le *LineEdit) ReadOnly() bool {\n\treturn le.hasStyleBits(win.ES_READONLY)\n}\n\nfunc (le *LineEdit) SetReadOnly(readOnly bool) error {\n\tif 0 == le.SendMessage(win.EM_SETREADONLY, uintptr(win.BoolToBOOL(readOnly)), 0) {\n\t\treturn newError(\"SendMessage(EM_SETREADONLY)\")\n\t}\n\n\tif readOnly != le.ReadOnly() {\n\t\tle.invalidateBorderInParent()\n\t}\n\n\tle.readOnlyChangedPublisher.Publish()\n\n\treturn nil\n}\n\n// sizeHintForLimit returns size hint for given limit in native pixels\nfunc (le *LineEdit) sizeHintForLimit(limit int) (size Size) {\n\tsize = le.dialogBaseUnitsToPixels(Size{50, 12})\n\tle.initCharWidth()\n\tn := le.MaxLength()\n\tif n > limit {\n\t\tn = limit\n\t}\n\tsize.Width = le.charWidth * (n + 1)\n\treturn\n}\n\nfunc (le *LineEdit) initCharWidth() {\n\tfont := le.Font()\n\tif font == le.charWidthFont {\n\t\treturn\n\t}\n\tle.charWidthFont = font\n\tle.charWidth = 8\n\n\thdc := win.GetDC(le.hWnd)\n\tif hdc == 0 {\n\t\tnewError(\"GetDC failed\")\n\t\treturn\n\t}\n\tdefer win.ReleaseDC(le.hWnd, hdc)\n\n\tdefer win.SelectObject(hdc, win.SelectObject(hdc, win.HGDIOBJ(font.handleForDPI(le.DPI()))))\n\n\tbuf := []uint16{'M'}\n\n\tvar s win.SIZE\n\tif !win.GetTextExtentPoint32(hdc, &buf[0], int32(len(buf)), &s) {\n\t\tnewError(\"GetTextExtentPoint32 failed\")\n\t\treturn\n\t}\n\tle.charWidth = int(s.CX)\n}\n\nfunc (le *LineEdit) EditingFinished() *Event {\n\treturn le.editingFinishedPublisher.Event()\n}\n\nfunc (le *LineEdit) TextChanged() *Event {\n\treturn le.textChangedPublisher.Event()\n}\n\nfunc (le *LineEdit) TextColor() Color {\n\treturn le.textColor\n}\n\nfunc (le *LineEdit) SetTextColor(c Color) {\n\tle.textColor = c\n\n\tle.Invalidate()\n}\n\nfunc (*LineEdit) NeedsWmSize() bool {\n\treturn true\n}\n\nfunc (le *LineEdit) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_COMMAND:\n\t\tswitch win.HIWORD(uint32(wParam)) {\n\t\tcase win.EN_CHANGE:\n\t\t\tle.textChangedPublisher.Publish()\n\t\t}\n\n\tcase win.WM_GETDLGCODE:\n\t\tif form := ancestor(le); form != nil {\n\t\t\tif dlg, ok := form.(dialogish); ok {\n\t\t\t\tif dlg.DefaultButton() != nil {\n\t\t\t\t\t// If the LineEdit lives in a Dialog that has a DefaultButton,\n\t\t\t\t\t// we won't swallow the return key.\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif wParam == win.VK_RETURN {\n\t\t\treturn win.DLGC_WANTALLKEYS\n\t\t}\n\n\tcase win.WM_KEYDOWN:\n\t\tswitch Key(wParam) {\n\t\tcase KeyA:\n\t\t\tif ControlDown() {\n\t\t\t\tle.SetTextSelection(0, -1)\n\t\t\t}\n\n\t\tcase KeyReturn:\n\t\t\tle.editingFinishedPublisher.Publish()\n\t\t}\n\n\tcase win.WM_KILLFOCUS:\n\t\t// FIXME: This may be dangerous, see remarks section:\n\t\t// http://msdn.microsoft.com/en-us/library/ms646282(v=vs.85).aspx\n\t\tle.editingFinishedPublisher.Publish()\n\t}\n\n\treturn le.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (le *LineEdit) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tlf := ShrinkableHorz | GrowableHorz\n\tif le.MaxLength() > lineEditGreedyLimit {\n\t\tlf |= GreedyHorz\n\t}\n\n\treturn &lineEditLayoutItem{\n\t\tlayoutFlags: lf,\n\t\tidealSize:   le.sizeHintForLimit(lineEditGreedyLimit),\n\t\tminSize:     le.sizeHintForLimit(lineEditMinChars),\n\t}\n}\n\ntype lineEditLayoutItem struct {\n\tLayoutItemBase\n\tlayoutFlags LayoutFlags\n\tidealSize   Size // in native pixels\n\tminSize     Size // in native pixels\n}\n\nfunc (li *lineEditLayoutItem) LayoutFlags() LayoutFlags {\n\treturn li.layoutFlags\n}\n\nfunc (li *lineEditLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *lineEditLayoutItem) MinSize() Size {\n\treturn li.minSize\n}\n"
  },
  {
    "path": "linklabel.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype LinkLabel struct {\n\tWidgetBase\n\ttextChangedPublisher   EventPublisher\n\tlinkActivatedPublisher LinkLabelLinkEventPublisher\n}\n\nfunc NewLinkLabel(parent Container) (*LinkLabel, error) {\n\tll := new(LinkLabel)\n\n\tif err := InitWidget(\n\t\tll,\n\t\tparent,\n\t\t\"SysLink\",\n\t\twin.WS_TABSTOP|win.WS_VISIBLE,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tll.SetBackground(nullBrushSingleton)\n\n\tll.MustRegisterProperty(\"Text\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn ll.Text()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn ll.SetText(assertStringOr(v, \"\"))\n\t\t},\n\t\tll.textChangedPublisher.Event()))\n\n\treturn ll, nil\n}\n\nfunc (ll *LinkLabel) Text() string {\n\treturn ll.text()\n}\n\nfunc (ll *LinkLabel) SetText(value string) error {\n\tif value == ll.Text() {\n\t\treturn nil\n\t}\n\n\tif err := ll.setText(value); err != nil {\n\t\treturn err\n\t}\n\n\tll.RequestLayout()\n\n\treturn nil\n}\n\nfunc (ll *LinkLabel) LinkActivated() *LinkLabelLinkEvent {\n\treturn ll.linkActivatedPublisher.Event()\n}\n\nfunc (ll *LinkLabel) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_NOTIFY:\n\t\tnml := (*win.NMLINK)(unsafe.Pointer(lParam))\n\n\t\tswitch nml.Hdr.Code {\n\t\tcase win.NM_CLICK, win.NM_RETURN:\n\t\t\tlink := &LinkLabelLink{\n\t\t\t\tll:    ll,\n\t\t\t\tindex: int(nml.Item.ILink),\n\t\t\t\tid:    syscall.UTF16ToString(nml.Item.SzID[:]),\n\t\t\t\turl:   syscall.UTF16ToString(nml.Item.SzUrl[:]),\n\t\t\t}\n\n\t\t\tll.linkActivatedPublisher.Publish(link)\n\t\t}\n\n\tcase win.WM_KILLFOCUS:\n\t\tll.ensureStyleBits(win.WS_TABSTOP, true)\n\n\tcase win.WM_SETTEXT:\n\t\tll.textChangedPublisher.Publish()\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tll.Invalidate()\n\t}\n\n\treturn ll.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\ntype LinkLabelLinkEventHandler func(link *LinkLabelLink)\n\ntype LinkLabelLinkEvent struct {\n\thandlers []LinkLabelLinkEventHandler\n}\n\nfunc (e *LinkLabelLinkEvent) Attach(handler LinkLabelLinkEventHandler) int {\n\tfor i, h := range e.handlers {\n\t\tif h == nil {\n\t\t\te.handlers[i] = handler\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handler)\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *LinkLabelLinkEvent) Detach(handle int) {\n\te.handlers[handle] = nil\n}\n\ntype LinkLabelLinkEventPublisher struct {\n\tevent LinkLabelLinkEvent\n}\n\nfunc (p *LinkLabelLinkEventPublisher) Event() *LinkLabelLinkEvent {\n\treturn &p.event\n}\n\nfunc (p *LinkLabelLinkEventPublisher) Publish(link *LinkLabelLink) {\n\tfor _, handler := range p.event.handlers {\n\t\tif handler != nil {\n\t\t\thandler(link)\n\t\t}\n\t}\n}\n\ntype LinkLabelLink struct {\n\tll    *LinkLabel\n\tindex int\n\tid    string\n\turl   string\n}\n\nfunc (lll *LinkLabelLink) Index() int {\n\treturn lll.index\n}\n\nfunc (lll *LinkLabelLink) Id() string {\n\treturn lll.id\n}\n\nfunc (lll *LinkLabelLink) URL() string {\n\treturn lll.url\n}\n\nfunc (lll *LinkLabelLink) Enabled() (bool, error) {\n\treturn lll.hasState(win.LIS_ENABLED)\n}\n\nfunc (lll *LinkLabelLink) SetEnabled(enabled bool) error {\n\treturn lll.setState(win.LIS_ENABLED, enabled)\n}\n\nfunc (lll *LinkLabelLink) Focused() (bool, error) {\n\treturn lll.hasState(win.LIS_FOCUSED)\n}\n\nfunc (lll *LinkLabelLink) SetFocused(focused bool) error {\n\treturn lll.setState(win.LIS_FOCUSED, focused)\n}\n\nfunc (lll *LinkLabelLink) Visited() (bool, error) {\n\treturn lll.hasState(win.LIS_VISITED)\n}\n\nfunc (lll *LinkLabelLink) SetVisited(visited bool) error {\n\treturn lll.setState(win.LIS_VISITED, visited)\n}\n\nfunc (lll *LinkLabelLink) hasState(state uint32) (bool, error) {\n\tli := win.LITEM{\n\t\tILink:     int32(lll.index),\n\t\tMask:      win.LIF_ITEMINDEX | win.LIF_STATE,\n\t\tStateMask: state,\n\t}\n\n\tif win.TRUE != lll.ll.SendMessage(win.LM_GETITEM, 0, uintptr(unsafe.Pointer(&li))) {\n\t\treturn false, newError(\"LM_GETITEM\")\n\t}\n\n\treturn li.State&state == state, nil\n}\n\nfunc (lll *LinkLabelLink) setState(state uint32, set bool) error {\n\tli := win.LITEM{\n\t\tMask:      win.LIF_STATE,\n\t\tStateMask: state,\n\t}\n\n\tif set {\n\t\tli.State = state\n\t}\n\n\tli.Mask |= win.LIF_ITEMINDEX\n\tli.ILink = int32(lll.index)\n\n\tif win.TRUE != lll.ll.SendMessage(win.LM_SETITEM, 0, uintptr(unsafe.Pointer(&li))) {\n\t\treturn newError(\"LM_SETITEM\")\n\t}\n\n\treturn nil\n}\n\nfunc (ll *LinkLabel) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tvar s win.SIZE\n\tll.SendMessage(win.LM_GETIDEALSIZE, uintptr(ll.IntFrom96DPI(ll.maxSize96dpi.Width)), uintptr(unsafe.Pointer(&s)))\n\n\treturn &linkLabelLayoutItem{\n\t\tidealSize: sizeFromSIZE(s),\n\t}\n}\n\ntype linkLabelLayoutItem struct {\n\tLayoutItemBase\n\tidealSize Size // in native pixels\n}\n\nfunc (*linkLabelLayoutItem) LayoutFlags() LayoutFlags {\n\treturn 0\n}\n\nfunc (li *linkLabelLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *linkLabelLayoutItem) MinSize() Size {\n\treturn li.idealSize\n}\n"
  },
  {
    "path": "listbox.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of lb source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\t\"reflect\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype ListBox struct {\n\tWidgetBase\n\tbindingValueProvider            BindingValueProvider\n\tmodel                           ListModel\n\tprovidedModel                   interface{}\n\tstyler                          ListItemStyler\n\tstyle                           ListItemStyle\n\tbindingMember                   string\n\tdisplayMember                   string\n\tformat                          string\n\tprecision                       int\n\tprevCurIndex                    int\n\tcurrentValue                    interface{}\n\titemsResetHandlerHandle         int\n\titemChangedHandlerHandle        int\n\titemsInsertedHandlerHandle      int\n\titemsRemovedHandlerHandle       int\n\tmaxItemTextWidth                int   // in native pixels\n\tlastWidth                       int   // in native pixels\n\tlastWidthsMeasuredFor           []int // in native pixels\n\tcurrentIndexChangedPublisher    EventPublisher\n\tselectedIndexesChangedPublisher EventPublisher\n\titemActivatedPublisher          EventPublisher\n\tthemeNormalBGColor              Color\n\tthemeNormalTextColor            Color\n\tthemeSelectedBGColor            Color\n\tthemeSelectedTextColor          Color\n\tthemeSelectedNotFocusedBGColor  Color\n\ttrackingMouseEvent              bool\n}\n\nfunc NewListBox(parent Container) (*ListBox, error) {\n\treturn NewListBoxWithStyle(parent, 0)\n}\n\nfunc NewListBoxWithStyle(parent Container, style uint32) (*ListBox, error) {\n\tlb := new(ListBox)\n\n\terr := InitWidget(\n\t\tlb,\n\t\tparent,\n\t\t\"LISTBOX\",\n\t\twin.WS_BORDER|win.WS_TABSTOP|win.WS_VISIBLE|win.WS_VSCROLL|win.WS_HSCROLL|win.LBS_NOINTEGRALHEIGHT|win.LBS_NOTIFY|style,\n\t\t0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tlb.Dispose()\n\t\t}\n\t}()\n\n\tlb.setTheme(\"Explorer\")\n\n\tlb.style.dpi = lb.DPI()\n\n\tlb.ApplySysColors()\n\n\tlb.GraphicsEffects().Add(InteractionEffect)\n\tlb.GraphicsEffects().Add(FocusEffect)\n\n\tlb.MustRegisterProperty(\"CurrentIndex\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn lb.CurrentIndex()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn lb.SetCurrentIndex(assertIntOr(v, -1))\n\t\t},\n\t\tlb.CurrentIndexChanged()))\n\n\tlb.MustRegisterProperty(\"CurrentItem\", NewReadOnlyProperty(\n\t\tfunc() interface{} {\n\t\t\tif i := lb.CurrentIndex(); i > -1 {\n\t\t\t\tif rm, ok := lb.providedModel.(reflectModel); ok {\n\t\t\t\t\treturn reflect.ValueOf(rm.Items()).Index(i).Interface()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\tlb.CurrentIndexChanged()))\n\n\tlb.MustRegisterProperty(\"HasCurrentItem\", NewReadOnlyBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn lb.CurrentIndex() != -1\n\t\t},\n\t\tlb.CurrentIndexChanged()))\n\n\tlb.MustRegisterProperty(\"Value\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\tindex := lb.CurrentIndex()\n\n\t\t\tif lb.bindingValueProvider == nil || index == -1 {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn lb.bindingValueProvider.BindingValue(index)\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\tif lb.bindingValueProvider == nil {\n\t\t\t\tif lb.model == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t} else {\n\t\t\t\t\treturn newError(\"Data binding is only supported using a model that implements BindingValueProvider.\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tindex := -1\n\n\t\t\tcount := lb.model.ItemCount()\n\t\t\tfor i := 0; i < count; i++ {\n\t\t\t\tif lb.bindingValueProvider.BindingValue(i) == v {\n\t\t\t\t\tindex = i\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn lb.SetCurrentIndex(index)\n\t\t},\n\t\tlb.CurrentIndexChanged()))\n\n\tsucceeded = true\n\n\treturn lb, nil\n}\n\nfunc (*ListBox) LayoutFlags() LayoutFlags {\n\treturn ShrinkableHorz | ShrinkableVert | GrowableHorz | GrowableVert | GreedyHorz | GreedyVert\n}\n\nfunc (lb *ListBox) ItemStyler() ListItemStyler {\n\treturn lb.styler\n}\n\nfunc (lb *ListBox) SetItemStyler(styler ListItemStyler) {\n\tlb.styler = styler\n}\n\nfunc (lb *ListBox) ApplySysColors() {\n\tlb.WidgetBase.ApplySysColors()\n\n\tvar hc win.HIGHCONTRAST\n\thc.CbSize = uint32(unsafe.Sizeof(hc))\n\tif win.SystemParametersInfo(win.SPI_GETHIGHCONTRAST, hc.CbSize, unsafe.Pointer(&hc), 0) {\n\t\tlb.style.highContrastActive = hc.DwFlags&win.HCF_HIGHCONTRASTON != 0\n\t}\n\n\tlb.themeNormalBGColor = Color(win.GetSysColor(win.COLOR_WINDOW))\n\tlb.themeNormalTextColor = Color(win.GetSysColor(win.COLOR_WINDOWTEXT))\n\tlb.themeSelectedBGColor = Color(win.GetSysColor(win.COLOR_HIGHLIGHT))\n\tlb.themeSelectedTextColor = Color(win.GetSysColor(win.COLOR_HIGHLIGHTTEXT))\n\tlb.themeSelectedNotFocusedBGColor = Color(win.GetSysColor(win.COLOR_BTNFACE))\n}\n\nfunc (lb *ListBox) ApplyDPI(dpi int) {\n\tlb.style.dpi = dpi\n\n\tlb.WidgetBase.ApplyDPI(dpi)\n}\n\nfunc (lb *ListBox) applyFont(font *Font) {\n\tlb.WidgetBase.applyFont(font)\n\n\tfor i := range lb.lastWidthsMeasuredFor {\n\t\tlb.lastWidthsMeasuredFor[i] = 0\n\t}\n}\n\nfunc (lb *ListBox) itemString(index int) string {\n\tswitch val := lb.model.Value(index).(type) {\n\tcase string:\n\t\treturn val\n\n\tcase time.Time:\n\t\treturn val.Format(lb.format)\n\n\tcase *big.Rat:\n\t\treturn val.FloatString(lb.precision)\n\n\tdefault:\n\t\treturn fmt.Sprintf(lb.format, val)\n\t}\n}\n\n//insert one item from list model\nfunc (lb *ListBox) insertItemAt(index int) error {\n\tstr := lb.itemString(index)\n\tlp := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(str)))\n\tret := int(lb.SendMessage(win.LB_INSERTSTRING, uintptr(index), lp))\n\tif ret == win.LB_ERRSPACE || ret == win.LB_ERR {\n\t\treturn newError(\"SendMessage(LB_INSERTSTRING)\")\n\t}\n\treturn nil\n}\n\nfunc (lb *ListBox) removeItem(index int) error {\n\tif win.LB_ERR == int(lb.SendMessage(win.LB_DELETESTRING, uintptr(index), 0)) {\n\t\treturn newError(\"SendMessage(LB_DELETESTRING)\")\n\t}\n\n\treturn nil\n}\n\n// reread all the items from list model\nfunc (lb *ListBox) resetItems() error {\n\tlb.SetSuspended(true)\n\tdefer lb.SetSuspended(false)\n\n\tlb.SendMessage(win.LB_RESETCONTENT, 0, 0)\n\n\tlb.maxItemTextWidth = 0\n\n\toldValue := lb.currentValue\n\n\tif lb.model == nil {\n\t\tlb.SetCurrentIndex(-1)\n\t\treturn nil\n\t}\n\n\tcount := lb.model.ItemCount()\n\n\tlb.lastWidthsMeasuredFor = make([]int, count)\n\n\tfor i := 0; i < count; i++ {\n\t\tif err := lb.insertItemAt(i); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif oldValue != nil {\n\t\tlb.Property(\"Value\").Set(oldValue)\n\t} else {\n\t\tlb.SetCurrentIndex(-1)\n\t}\n\n\tif lb.styler == nil {\n\t\t// Update the listbox width (this sets the correct horizontal scrollbar).\n\t\tsh := lb.idealSize()\n\t\tlb.SendMessage(win.LB_SETHORIZONTALEXTENT, uintptr(sh.Width), 0)\n\t}\n\n\treturn nil\n}\n\nfunc (lb *ListBox) ensureVisibleItemsHeightUpToDate() error {\n\tif lb.styler == nil {\n\t\treturn nil\n\t}\n\n\tif !lb.Suspended() {\n\t\tlb.SetSuspended(true)\n\t\tdefer lb.SetSuspended(false)\n\t}\n\n\ttopIndex := int(lb.SendMessage(win.LB_GETTOPINDEX, 0, 0))\n\toffset := maxi(0, topIndex-10)\n\tcount := lb.model.ItemCount()\n\tvar rc win.RECT\n\tlb.SendMessage(win.LB_GETITEMRECT, uintptr(offset), uintptr(unsafe.Pointer(&rc)))\n\twidth := int(rc.Right - rc.Left)\n\toffsetTop := int(rc.Top)\n\tlbHeight := lb.HeightPixels()\n\n\tvar pastBottomCount int\n\tfor i := offset; i >= 0 && i < count; i++ {\n\t\tif lb.lastWidthsMeasuredFor[i] == lb.lastWidth {\n\t\t\tcontinue\n\t\t}\n\n\t\tlb.SendMessage(win.LB_GETITEMRECT, uintptr(i), uintptr(unsafe.Pointer(&rc)))\n\n\t\tif int(rc.Top)-offsetTop > lbHeight {\n\t\t\tif pastBottomCount++; pastBottomCount > 10 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\theight := lb.styler.ItemHeight(i, width)\n\n\t\tlb.SendMessage(win.LB_SETITEMHEIGHT, uintptr(i), uintptr(height))\n\n\t\tlb.lastWidthsMeasuredFor[i] = lb.lastWidth\n\t}\n\n\tlb.EnsureItemVisible(topIndex)\n\n\treturn nil\n}\n\nfunc (lb *ListBox) attachModel() {\n\titemsResetHandler := func() {\n\t\tlb.resetItems()\n\t}\n\tlb.itemsResetHandlerHandle = lb.model.ItemsReset().Attach(itemsResetHandler)\n\n\titemChangedHandler := func(index int) {\n\t\tif win.CB_ERR == lb.SendMessage(win.LB_DELETESTRING, uintptr(index), 0) {\n\t\t\tnewError(\"SendMessage(CB_DELETESTRING)\")\n\t\t}\n\n\t\tlb.insertItemAt(index)\n\n\t\tif lb.styler != nil {\n\t\t\tvar rc win.RECT\n\t\t\tlb.SendMessage(win.LB_GETITEMRECT, uintptr(index), uintptr(unsafe.Pointer(&rc)))\n\t\t\twidth := int(rc.Right - rc.Left)\n\t\t\theight := lb.styler.ItemHeight(index, width)\n\n\t\t\tlb.SendMessage(win.LB_SETITEMHEIGHT, uintptr(index), uintptr(height))\n\n\t\t\tlb.lastWidthsMeasuredFor[index] = lb.lastWidth\n\t\t}\n\n\t\tlb.SetCurrentIndex(lb.prevCurIndex)\n\t}\n\tlb.itemChangedHandlerHandle = lb.model.ItemChanged().Attach(itemChangedHandler)\n\n\tlb.itemsInsertedHandlerHandle = lb.model.ItemsInserted().Attach(func(from, to int) {\n\t\tif !lb.Suspended() {\n\t\t\tlb.SetSuspended(true)\n\t\t\tdefer lb.SetSuspended(false)\n\t\t}\n\n\t\tfor i := from; i <= to; i++ {\n\t\t\tlb.insertItemAt(i)\n\t\t}\n\n\t\tlb.lastWidthsMeasuredFor = append(lb.lastWidthsMeasuredFor[:from], append(make([]int, to-from+1), lb.lastWidthsMeasuredFor[from:]...)...)\n\n\t\tlb.ensureVisibleItemsHeightUpToDate()\n\t})\n\n\tlb.itemsRemovedHandlerHandle = lb.model.ItemsRemoved().Attach(func(from, to int) {\n\t\tif !lb.Suspended() {\n\t\t\tlb.SetSuspended(true)\n\t\t\tdefer lb.SetSuspended(false)\n\t\t}\n\n\t\tfor i := to; i >= from; i-- {\n\t\t\tlb.removeItem(i)\n\t\t}\n\n\t\tlb.lastWidthsMeasuredFor = append(lb.lastWidthsMeasuredFor[:from], lb.lastWidthsMeasuredFor[to:]...)\n\n\t\tlb.ensureVisibleItemsHeightUpToDate()\n\t})\n}\n\nfunc (lb *ListBox) detachModel() {\n\tlb.model.ItemsReset().Detach(lb.itemsResetHandlerHandle)\n\tlb.model.ItemChanged().Detach(lb.itemChangedHandlerHandle)\n\tlb.model.ItemsInserted().Detach(lb.itemsInsertedHandlerHandle)\n\tlb.model.ItemsRemoved().Detach(lb.itemsRemovedHandlerHandle)\n}\n\n// Model returns the model of the ListBox.\nfunc (lb *ListBox) Model() interface{} {\n\treturn lb.providedModel\n}\n\n// SetModel sets the model of the ListBox.\n//\n// It is required that mdl either implements walk.ListModel or\n// walk.ReflectListModel or be a slice of pointers to struct or a []string.\nfunc (lb *ListBox) SetModel(mdl interface{}) error {\n\tmodel, ok := mdl.(ListModel)\n\tif !ok && mdl != nil {\n\t\tvar err error\n\t\tif model, err = newReflectListModel(mdl); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif _, ok := mdl.([]string); !ok {\n\t\t\tif badms, ok := model.(bindingAndDisplayMemberSetter); ok {\n\t\t\t\tbadms.setBindingMember(lb.bindingMember)\n\t\t\t\tbadms.setDisplayMember(lb.displayMember)\n\t\t\t}\n\t\t}\n\t}\n\tlb.providedModel = mdl\n\n\tif lb.model != nil {\n\t\tlb.detachModel()\n\t}\n\n\tlb.model = model\n\tlb.bindingValueProvider, _ = model.(BindingValueProvider)\n\n\tif model != nil {\n\t\tlb.attachModel()\n\t}\n\n\tif err := lb.resetItems(); err != nil {\n\t\treturn err\n\t}\n\n\treturn lb.ensureVisibleItemsHeightUpToDate()\n}\n\n// BindingMember returns the member from the model of the ListBox that is bound\n// to a field of the data source managed by an associated DataBinder.\n//\n// This is only applicable to walk.ReflectListModel models and simple slices of\n// pointers to struct.\nfunc (lb *ListBox) BindingMember() string {\n\treturn lb.bindingMember\n}\n\n// SetBindingMember sets the member from the model of the ListBox that is bound\n// to a field of the data source managed by an associated DataBinder.\n//\n// This is only applicable to walk.ReflectListModel models and simple slices of\n// pointers to struct.\n//\n// For a model consisting of items of type S, data source field of type T and\n// bindingMember \"Foo\", this can be one of the following:\n//\n//\tA field\t\tFoo T\n//\tA method\tfunc (s S) Foo() T\n//\tA method\tfunc (s S) Foo() (T, error)\n//\n// If bindingMember is not a simple member name like \"Foo\", but a path to a\n// member like \"A.B.Foo\", members \"A\" and \"B\" both must be one of the options\n// mentioned above, but with T having type pointer to struct.\nfunc (lb *ListBox) SetBindingMember(bindingMember string) error {\n\tif bindingMember != \"\" {\n\t\tif _, ok := lb.providedModel.([]string); ok {\n\t\t\treturn newError(\"invalid for []string model\")\n\t\t}\n\t}\n\n\tlb.bindingMember = bindingMember\n\n\tif badms, ok := lb.model.(bindingAndDisplayMemberSetter); ok {\n\t\tbadms.setBindingMember(bindingMember)\n\t}\n\n\treturn nil\n}\n\n// DisplayMember returns the member from the model of the ListBox that is\n// displayed in the ListBox.\n//\n// This is only applicable to walk.ReflectListModel models and simple slices of\n// pointers to struct.\nfunc (lb *ListBox) DisplayMember() string {\n\treturn lb.displayMember\n}\n\n// SetDisplayMember sets the member from the model of the ListBox that is\n// displayed in the ListBox.\n//\n// This is only applicable to walk.ReflectListModel models and simple slices of\n// pointers to struct.\n//\n// For a model consisting of items of type S, the type of the specified member T\n// and displayMember \"Foo\", this can be one of the following:\n//\n//\tA field\t\tFoo T\n//\tA method\tfunc (s S) Foo() T\n//\tA method\tfunc (s S) Foo() (T, error)\n//\n// If displayMember is not a simple member name like \"Foo\", but a path to a\n// member like \"A.B.Foo\", members \"A\" and \"B\" both must be one of the options\n// mentioned above, but with T having type pointer to struct.\nfunc (lb *ListBox) SetDisplayMember(displayMember string) error {\n\tif displayMember != \"\" {\n\t\tif _, ok := lb.providedModel.([]string); ok {\n\t\t\treturn newError(\"invalid for []string model\")\n\t\t}\n\t}\n\n\tlb.displayMember = displayMember\n\n\tif badms, ok := lb.model.(bindingAndDisplayMemberSetter); ok {\n\t\tbadms.setDisplayMember(displayMember)\n\t}\n\n\treturn nil\n}\n\nfunc (lb *ListBox) Format() string {\n\treturn lb.format\n}\n\nfunc (lb *ListBox) SetFormat(value string) {\n\tlb.format = value\n}\n\nfunc (lb *ListBox) Precision() int {\n\treturn lb.precision\n}\n\nfunc (lb *ListBox) SetPrecision(value int) {\n\tlb.precision = value\n}\n\n// calculateMaxItemTextWidth returns maximum item text width in native pixels.\nfunc (lb *ListBox) calculateMaxItemTextWidth() int {\n\thdc := win.GetDC(lb.hWnd)\n\tif hdc == 0 {\n\t\tnewError(\"GetDC failed\")\n\t\treturn -1\n\t}\n\tdefer win.ReleaseDC(lb.hWnd, hdc)\n\n\thFontOld := win.SelectObject(hdc, win.HGDIOBJ(lb.Font().handleForDPI(lb.DPI())))\n\tdefer win.SelectObject(hdc, hFontOld)\n\n\tvar maxWidth int\n\n\tif lb.model == nil {\n\t\treturn -1\n\t}\n\tcount := lb.model.ItemCount()\n\tfor i := 0; i < count; i++ {\n\t\titem := lb.itemString(i)\n\t\tvar s win.SIZE\n\t\tstr := syscall.StringToUTF16(item)\n\n\t\tif !win.GetTextExtentPoint32(hdc, &str[0], int32(len(str)-1), &s) {\n\t\t\tnewError(\"GetTextExtentPoint32 failed\")\n\t\t\treturn -1\n\t\t}\n\n\t\tmaxWidth = maxi(maxWidth, int(s.CX))\n\t}\n\n\treturn maxWidth\n}\n\n// idealSize returns listbox ideal size in native pixels.\nfunc (lb *ListBox) idealSize() Size {\n\tdefaultSize := lb.dialogBaseUnitsToPixels(Size{50, 12})\n\n\tif lb.maxItemTextWidth <= 0 {\n\t\tlb.maxItemTextWidth = lb.calculateMaxItemTextWidth()\n\t}\n\n\t// FIXME: Use GetThemePartSize instead of guessing\n\tw := maxi(defaultSize.Width, lb.maxItemTextWidth+IntFrom96DPI(24, lb.DPI()))\n\th := defaultSize.Height + 1\n\n\treturn Size{w, h}\n}\n\nfunc (lb *ListBox) ItemVisible(index int) bool {\n\ttopIndex := int(lb.SendMessage(win.LB_GETTOPINDEX, 0, 0))\n\tvar rc win.RECT\n\tlb.SendMessage(win.LB_GETITEMRECT, uintptr(index), uintptr(unsafe.Pointer(&rc)))\n\n\treturn index >= topIndex && int(rc.Top) < lb.HeightPixels()\n}\n\nfunc (lb *ListBox) EnsureItemVisible(index int) {\n\tlb.SendMessage(win.LB_SETTOPINDEX, uintptr(index), 0)\n}\n\nfunc (lb *ListBox) CurrentIndex() int {\n\treturn int(int32(lb.SendMessage(win.LB_GETCURSEL, 0, 0)))\n}\n\nfunc (lb *ListBox) SetCurrentIndex(value int) error {\n\tif value > -1 && win.LB_ERR == int(int32(lb.SendMessage(win.LB_SETCURSEL, uintptr(value), 0))) {\n\t\treturn newError(\"Invalid index or ensure lb is single-selection listbox\")\n\t}\n\n\tif value != lb.prevCurIndex {\n\t\tif value == -1 {\n\t\t\tlb.currentValue = nil\n\t\t} else {\n\t\t\tlb.currentValue = lb.Property(\"Value\").Get()\n\t\t}\n\n\t\tlb.prevCurIndex = value\n\t\tlb.currentIndexChangedPublisher.Publish()\n\t}\n\n\treturn nil\n}\n\nfunc (lb *ListBox) SelectedIndexes() []int {\n\tcount := int(int32(lb.SendMessage(win.LB_GETCOUNT, 0, 0)))\n\tif count < 1 {\n\t\treturn nil\n\t}\n\tindex32 := make([]int32, count)\n\tif n := int(int32(lb.SendMessage(win.LB_GETSELITEMS, uintptr(count), uintptr(unsafe.Pointer(&index32[0]))))); n == win.LB_ERR {\n\t\treturn nil\n\t} else {\n\t\tindexes := make([]int, n)\n\t\tfor i := 0; i < n; i++ {\n\t\t\tindexes[i] = int(index32[i])\n\t\t}\n\t\treturn indexes\n\t}\n}\n\nfunc (lb *ListBox) SetSelectedIndexes(indexes []int) {\n\tvar m int32 = -1\n\tlb.SendMessage(win.LB_SETSEL, win.FALSE, uintptr(m))\n\tfor _, v := range indexes {\n\t\tlb.SendMessage(win.LB_SETSEL, win.TRUE, uintptr(uint32(v)))\n\t}\n\tlb.selectedIndexesChangedPublisher.Publish()\n}\n\nfunc (lb *ListBox) CurrentIndexChanged() *Event {\n\treturn lb.currentIndexChangedPublisher.Event()\n}\n\nfunc (lb *ListBox) SelectedIndexesChanged() *Event {\n\treturn lb.selectedIndexesChangedPublisher.Event()\n}\n\nfunc (lb *ListBox) ItemActivated() *Event {\n\treturn lb.itemActivatedPublisher.Event()\n}\n\nfunc (lb *ListBox) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_MEASUREITEM:\n\t\tif lb.styler == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tmis := (*win.MEASUREITEMSTRUCT)(unsafe.Pointer(lParam))\n\n\t\tmis.ItemHeight = uint32(lb.styler.DefaultItemHeight())\n\n\t\treturn win.TRUE\n\n\tcase win.WM_DRAWITEM:\n\t\tdis := (*win.DRAWITEMSTRUCT)(unsafe.Pointer(lParam))\n\n\t\tif lb.styler == nil || dis.ItemID < 0 || dis.ItemAction != win.ODA_DRAWENTIRE {\n\t\t\treturn win.TRUE\n\t\t}\n\n\t\tlb.style.index = int(dis.ItemID)\n\t\tlb.style.rc = dis.RcItem\n\t\tlb.style.bounds = rectangleFromRECT(dis.RcItem)\n\t\tlb.style.dpi = lb.DPI()\n\t\tlb.style.state = dis.ItemState\n\t\tlb.style.hwnd = lb.hWnd\n\t\tlb.style.hdc = dis.HDC\n\t\tlb.style.Font = lb.Font()\n\n\t\tif dis.ItemAction == win.ODA_FOCUS {\n\t\t\treturn win.TRUE\n\t\t}\n\n\t\tvar hTheme win.HTHEME\n\t\tif !lb.style.highContrastActive {\n\t\t\tif hTheme = win.OpenThemeData(lb.hWnd, syscall.StringToUTF16Ptr(\"Listview\")); hTheme != 0 {\n\t\t\t\tdefer win.CloseThemeData(hTheme)\n\t\t\t}\n\t\t}\n\t\tlb.style.hTheme = hTheme\n\n\t\tif dis.ItemState&win.ODS_CHECKED != 0 {\n\t\t\tif lb.style.highContrastActive || lb.Focused() {\n\t\t\t\tlb.style.BackgroundColor = lb.themeSelectedBGColor\n\t\t\t\tlb.style.TextColor = lb.themeSelectedTextColor\n\t\t\t} else {\n\t\t\t\tlb.style.BackgroundColor = lb.themeSelectedNotFocusedBGColor\n\t\t\t\tlb.style.TextColor = lb.themeNormalTextColor\n\t\t\t}\n\t\t} else if int(dis.ItemID) == lb.style.hoverIndex {\n\t\t\tif hTheme == 0 {\n\t\t\t\tlb.style.BackgroundColor = lb.themeNormalBGColor\n\t\t\t} else {\n\t\t\t\tlb.style.BackgroundColor = lb.themeSelectedBGColor\n\t\t\t}\n\t\t\tlb.style.TextColor = lb.themeNormalTextColor\n\t\t} else {\n\t\t\tlb.style.BackgroundColor = lb.themeNormalBGColor\n\t\t\tlb.style.TextColor = lb.themeNormalTextColor\n\t\t}\n\t\tif lb.themeNormalTextColor == RGB(0, 0, 0) {\n\t\t\tlb.style.LineColor = RGB(0, 0, 0)\n\t\t} else {\n\t\t\tlb.style.LineColor = RGB(255, 255, 255)\n\t\t}\n\t\tlb.style.defaultTextColor = lb.style.TextColor\n\n\t\tlb.style.DrawBackground()\n\n\t\tlb.styler.StyleItem(&lb.style)\n\n\t\tdefer func() {\n\t\t\tlb.style.bounds = Rectangle{}\n\t\t\tif lb.style.canvas != nil {\n\t\t\t\tlb.style.canvas.Dispose()\n\t\t\t\tlb.style.canvas = nil\n\t\t\t}\n\t\t\tlb.style.hdc = 0\n\t\t}()\n\n\t\treturn win.TRUE\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif lb.styler != nil && lb.styler.ItemHeightDependsOnWidth() {\n\t\t\twidth := lb.WidthPixels()\n\t\t\tif width != lb.lastWidth {\n\t\t\t\tlb.lastWidth = width\n\t\t\t\tlb.lastWidthsMeasuredFor = make([]int, lb.model.ItemCount())\n\t\t\t}\n\t\t}\n\n\t\tlb.ensureVisibleItemsHeightUpToDate()\n\n\t\treturn win.CallWindowProc(lb.origWndProcPtr, hwnd, msg, wParam, lParam)\n\n\tcase win.WM_VSCROLL:\n\t\tlb.ensureVisibleItemsHeightUpToDate()\n\n\tcase win.WM_MOUSEWHEEL:\n\t\tlb.ensureVisibleItemsHeightUpToDate()\n\n\tcase win.WM_LBUTTONDOWN:\n\t\tlb.Invalidate()\n\n\tcase win.WM_MOUSEMOVE:\n\t\tif lb.styler == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tif !lb.trackingMouseEvent {\n\t\t\tvar tme win.TRACKMOUSEEVENT\n\t\t\ttme.CbSize = uint32(unsafe.Sizeof(tme))\n\t\t\ttme.DwFlags = win.TME_LEAVE\n\t\t\ttme.HwndTrack = lb.hWnd\n\n\t\t\tlb.trackingMouseEvent = win.TrackMouseEvent(&tme)\n\t\t}\n\n\t\toldHoverIndex := lb.style.hoverIndex\n\n\t\tresult := uint32(lb.SendMessage(win.LB_ITEMFROMPOINT, 0, lParam))\n\t\tif win.HIWORD(result) == 0 {\n\t\t\tindex := int(win.LOWORD(result))\n\n\t\t\tvar rc win.RECT\n\t\t\tlb.SendMessage(win.LB_GETITEMRECT, uintptr(index), uintptr(unsafe.Pointer(&rc)))\n\n\t\t\tlp := uint32(lParam)\n\t\t\tx := int32(win.LOWORD(lp))\n\t\t\ty := int32(win.HIWORD(lp))\n\n\t\t\tif x >= rc.Left && x <= rc.Right && y >= rc.Top && y <= rc.Bottom {\n\t\t\t\tlb.style.hoverIndex = index\n\n\t\t\t\twin.InvalidateRect(lb.hWnd, &rc, true)\n\t\t\t}\n\t\t}\n\n\t\tif lb.style.hoverIndex != oldHoverIndex {\n\t\t\tif wParam&win.MK_LBUTTON != 0 {\n\t\t\t\tlb.Invalidate()\n\t\t\t} else {\n\t\t\t\tlb.invalidateItem(oldHoverIndex)\n\t\t\t\tlb.invalidateItem(lb.style.hoverIndex)\n\t\t\t}\n\t\t}\n\n\tcase win.WM_MOUSELEAVE:\n\t\tif lb.styler == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tlb.trackingMouseEvent = false\n\n\t\tindex := lb.style.hoverIndex\n\n\t\tlb.style.hoverIndex = -1\n\n\t\tlb.invalidateItem(index)\n\n\tcase win.WM_COMMAND:\n\t\tswitch win.HIWORD(uint32(wParam)) {\n\t\tcase win.LBN_SELCHANGE:\n\t\t\tlb.ensureVisibleItemsHeightUpToDate()\n\t\t\tlb.prevCurIndex = lb.CurrentIndex()\n\t\t\tlb.currentValue = lb.Property(\"Value\").Get()\n\t\t\tlb.currentIndexChangedPublisher.Publish()\n\t\t\tlb.selectedIndexesChangedPublisher.Publish()\n\n\t\tcase win.LBN_DBLCLK:\n\t\t\tlb.itemActivatedPublisher.Publish()\n\t\t}\n\n\tcase win.WM_GETDLGCODE:\n\t\tif form := ancestor(lb); form != nil {\n\t\t\tif dlg, ok := form.(dialogish); ok {\n\t\t\t\tif dlg.DefaultButton() != nil {\n\t\t\t\t\t// If the ListBox lives in a Dialog that has a DefaultButton,\n\t\t\t\t\t// we won't swallow the return key.\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif wParam == win.VK_RETURN {\n\t\t\treturn win.DLGC_WANTALLKEYS\n\t\t}\n\n\tcase win.WM_KEYDOWN:\n\t\tif uint32(lParam)>>30 == 0 && Key(wParam) == KeyReturn && lb.CurrentIndex() > -1 {\n\t\t\tlb.itemActivatedPublisher.Publish()\n\t\t}\n\t}\n\n\treturn lb.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (lb *ListBox) invalidateItem(index int) {\n\tvar rc win.RECT\n\tlb.SendMessage(win.LB_GETITEMRECT, uintptr(index), uintptr(unsafe.Pointer(&rc)))\n\n\twin.InvalidateRect(lb.hWnd, &rc, true)\n}\n\nfunc (lb *ListBox) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn NewGreedyLayoutItem()\n}\n"
  },
  {
    "path": "mainloop_cgo.go",
    "content": "// Copyright 2019 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows,walk_use_cgo\n\npackage walk\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\n// #include <windows.h>\n//\n// extern void shimRunSynchronized(uintptr_t fb);\n// extern unsigned char shimHandleKeyDown(uintptr_t fb, uintptr_t m);\n//\n// static int mainloop(uintptr_t handle_ptr, uintptr_t fb_ptr)\n// {\n//     HANDLE *hwnd = (HANDLE *)handle_ptr;\n//     MSG m;\n//     int r;\n//\n//     while (*hwnd) {\n//         r = GetMessage(&m, NULL, 0, 0);\n//         if (!r)\n//             return m.wParam;\n//         else if (r < 0)\n//             return -1;\n//         if (m.message == WM_KEYDOWN && shimHandleKeyDown(fb_ptr, (uintptr_t)&m))\n//             continue;\n//         if (!IsDialogMessage(*hwnd, &m)) {\n//             TranslateMessage(&m);\n//             DispatchMessage(&m);\n//         }\n//         shimRunSynchronized(fb_ptr);\n//     }\n//     return 0;\n// }\nimport \"C\"\n\n//export shimHandleKeyDown\nfunc shimHandleKeyDown(fb uintptr, msg uintptr) bool {\n\treturn (*FormBase)(unsafe.Pointer(fb)).handleKeyDown((*win.MSG)(unsafe.Pointer(msg)))\n}\n\n//export shimRunSynchronized\nfunc shimRunSynchronized(fb uintptr) {\n\t(*FormBase)(unsafe.Pointer(fb)).group.RunSynchronized()\n}\n\nfunc (fb *FormBase) mainLoop() int {\n\treturn int(C.mainloop(C.uintptr_t(uintptr(unsafe.Pointer(&fb.hWnd))), C.uintptr_t(uintptr(unsafe.Pointer(fb)))))\n}\n"
  },
  {
    "path": "mainloop_default.go",
    "content": "// Copyright 2019 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows,!walk_use_cgo\n\npackage walk\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nfunc (fb *FormBase) mainLoop() int {\n\tmsg := (*win.MSG)(unsafe.Pointer(win.GlobalAlloc(0, unsafe.Sizeof(win.MSG{}))))\n\tdefer win.GlobalFree(win.HGLOBAL(unsafe.Pointer(msg)))\n\n\tfor fb.hWnd != 0 {\n\t\tswitch win.GetMessage(msg, 0, 0, 0) {\n\t\tcase 0:\n\t\t\treturn int(msg.WParam)\n\n\t\tcase -1:\n\t\t\treturn -1\n\t\t}\n\n\t\tswitch msg.Message {\n\t\tcase win.WM_KEYDOWN:\n\t\t\tif fb.handleKeyDown(msg) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif !win.IsDialogMessage(fb.hWnd, msg) {\n\t\t\twin.TranslateMessage(msg)\n\t\t\twin.DispatchMessage(msg)\n\t\t}\n\n\t\tfb.group.RunSynchronized()\n\t}\n\n\treturn 0\n}\n"
  },
  {
    "path": "mainwindow.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst mainWindowWindowClass = `\\o/ Walk_MainWindow_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(mainWindowWindowClass)\n\t})\n}\n\ntype MainWindowCfg struct {\n\tName   string\n\tBounds Rectangle\n}\n\ntype MainWindow struct {\n\tFormBase\n\twindowPlacement *win.WINDOWPLACEMENT\n\tmenu            *Menu\n\ttoolBar         *ToolBar\n\tstatusBar       *StatusBar\n}\n\nfunc NewMainWindow() (*MainWindow, error) {\n\treturn NewMainWindowWithName(\"\")\n}\n\nfunc NewMainWindowWithName(name string) (*MainWindow, error) {\n\treturn NewMainWindowWithCfg(&MainWindowCfg{Name: name})\n}\n\nfunc NewMainWindowWithCfg(cfg *MainWindowCfg) (*MainWindow, error) {\n\tmw := new(MainWindow)\n\tmw.SetName(cfg.Name)\n\n\tif err := initWindowWithCfg(&windowCfg{\n\t\tWindow:    mw,\n\t\tClassName: mainWindowWindowClass,\n\t\tStyle:     win.WS_OVERLAPPEDWINDOW,\n\t\tExStyle:   win.WS_EX_CONTROLPARENT,\n\t\tBounds:    cfg.Bounds,\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tmw.Dispose()\n\t\t}\n\t}()\n\n\tmw.SetPersistent(true)\n\n\tvar err error\n\n\tif mw.menu, err = newMenuBar(mw); err != nil {\n\t\treturn nil, err\n\t}\n\tif !win.SetMenu(mw.hWnd, mw.menu.hMenu) {\n\t\treturn nil, lastError(\"SetMenu\")\n\t}\n\n\ttb, err := NewToolBar(mw)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmw.SetToolBar(tb)\n\n\tif mw.statusBar, err = NewStatusBar(mw); err != nil {\n\t\treturn nil, err\n\t}\n\tmw.statusBar.parent = nil\n\tmw.Children().Remove(mw.statusBar)\n\tmw.statusBar.parent = mw\n\twin.SetParent(mw.statusBar.hWnd, mw.hWnd)\n\tmw.statusBar.visibleChangedPublisher.event.Attach(func() {\n\t\tmw.SetBoundsPixels(mw.BoundsPixels())\n\t})\n\n\tsucceeded = true\n\n\treturn mw, nil\n}\n\nfunc (mw *MainWindow) Menu() *Menu {\n\treturn mw.menu\n}\n\nfunc (mw *MainWindow) ToolBar() *ToolBar {\n\treturn mw.toolBar\n}\n\nfunc (mw *MainWindow) SetToolBar(tb *ToolBar) {\n\tif mw.toolBar != nil {\n\t\twin.SetParent(mw.toolBar.hWnd, 0)\n\t}\n\n\tif tb != nil {\n\t\tparent := tb.parent\n\t\ttb.parent = nil\n\t\tparent.Children().Remove(tb)\n\t\ttb.parent = mw\n\t\twin.SetParent(tb.hWnd, mw.hWnd)\n\t}\n\n\tmw.toolBar = tb\n}\n\nfunc (mw *MainWindow) StatusBar() *StatusBar {\n\treturn mw.statusBar\n}\n\nfunc (mw *MainWindow) ClientBoundsPixels() Rectangle {\n\tbounds := mw.FormBase.ClientBoundsPixels()\n\n\tif mw.toolBar != nil && mw.toolBar.Actions().Len() > 0 {\n\t\ttlbBounds := mw.toolBar.BoundsPixels()\n\n\t\tbounds.Y += tlbBounds.Height\n\t\tbounds.Height -= tlbBounds.Height\n\t}\n\n\tif mw.statusBar.Visible() {\n\t\tbounds.Height -= mw.statusBar.HeightPixels()\n\t}\n\n\treturn bounds\n}\n\nfunc (mw *MainWindow) SetVisible(visible bool) {\n\tif visible {\n\t\twin.DrawMenuBar(mw.hWnd)\n\n\t\tmw.clientComposite.RequestLayout()\n\t}\n\n\tmw.FormBase.SetVisible(visible)\n}\n\nfunc (mw *MainWindow) applyFont(font *Font) {\n\tmw.FormBase.applyFont(font)\n\n\tif mw.toolBar != nil {\n\t\tmw.toolBar.applyFont(font)\n\t}\n\n\tif mw.statusBar != nil {\n\t\tmw.statusBar.applyFont(font)\n\t}\n}\n\nfunc (mw *MainWindow) Fullscreen() bool {\n\treturn win.GetWindowLong(mw.hWnd, win.GWL_STYLE)&win.WS_OVERLAPPEDWINDOW == 0\n}\n\nfunc (mw *MainWindow) SetFullscreen(fullscreen bool) error {\n\tif fullscreen == mw.Fullscreen() {\n\t\treturn nil\n\t}\n\n\tif fullscreen {\n\t\tvar mi win.MONITORINFO\n\t\tmi.CbSize = uint32(unsafe.Sizeof(mi))\n\n\t\tif mw.windowPlacement == nil {\n\t\t\tmw.windowPlacement = new(win.WINDOWPLACEMENT)\n\t\t}\n\n\t\tif !win.GetWindowPlacement(mw.hWnd, mw.windowPlacement) {\n\t\t\treturn lastError(\"GetWindowPlacement\")\n\t\t}\n\t\tif !win.GetMonitorInfo(win.MonitorFromWindow(\n\t\t\tmw.hWnd, win.MONITOR_DEFAULTTOPRIMARY), &mi) {\n\n\t\t\treturn newError(\"GetMonitorInfo\")\n\t\t}\n\n\t\tif err := mw.ensureStyleBits(win.WS_OVERLAPPEDWINDOW, false); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif r := mi.RcMonitor; !win.SetWindowPos(\n\t\t\tmw.hWnd, win.HWND_TOP,\n\t\t\tr.Left, r.Top, r.Right-r.Left, r.Bottom-r.Top,\n\t\t\twin.SWP_FRAMECHANGED|win.SWP_NOOWNERZORDER) {\n\n\t\t\treturn lastError(\"SetWindowPos\")\n\t\t}\n\t} else {\n\t\tif err := mw.ensureStyleBits(win.WS_OVERLAPPEDWINDOW, true); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !win.SetWindowPlacement(mw.hWnd, mw.windowPlacement) {\n\t\t\treturn lastError(\"SetWindowPlacement\")\n\t\t}\n\n\t\tif !win.SetWindowPos(mw.hWnd, 0, 0, 0, 0, 0, win.SWP_FRAMECHANGED|win.SWP_NOMOVE|\n\t\t\twin.SWP_NOOWNERZORDER|win.SWP_NOSIZE|win.SWP_NOZORDER) {\n\n\t\t\treturn lastError(\"SetWindowPos\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (mw *MainWindow) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_WINDOWPOSCHANGED, win.WM_SIZE:\n\t\tif win.WM_WINDOWPOSCHANGED == msg {\n\t\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\t\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tcb := mw.ClientBoundsPixels()\n\n\t\tif mw.toolBar != nil {\n\t\t\tbounds := Rectangle{0, 0, cb.Width, mw.toolBar.HeightPixels()}\n\t\t\tif mw.toolBar.BoundsPixels() != bounds {\n\t\t\t\tmw.toolBar.SetBoundsPixels(bounds)\n\t\t\t}\n\t\t}\n\n\t\tbounds := Rectangle{0, cb.Y + cb.Height, cb.Width, mw.statusBar.HeightPixels()}\n\t\tif mw.statusBar.BoundsPixels() != bounds {\n\t\t\tmw.statusBar.SetBoundsPixels(bounds)\n\t\t}\n\n\tcase win.WM_INITMENUPOPUP:\n\t\tmw.menu.updateItemsWithImageForWindow(mw)\n\t}\n\n\treturn mw.FormBase.WndProc(hwnd, msg, wParam, lParam)\n}\n"
  },
  {
    "path": "maptablemodel.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"sort\"\n)\n\ntype mapTableModel struct {\n\tTableModelBase\n\tSorterBase\n\tdataMembers []string\n\tdataSource  interface{}\n\titems       []map[string]interface{}\n}\n\nfunc newMapTableModel(dataSource interface{}) (TableModel, error) {\n\titems, ok := dataSource.([]map[string]interface{})\n\tif !ok {\n\t\treturn nil, newError(\"dataSource must be assignable to []map[string]interface{}\")\n\t}\n\n\treturn &mapTableModel{dataSource: dataSource, items: items}, nil\n}\n\nfunc (m *mapTableModel) setDataMembers(dataMembers []string) {\n\tm.dataMembers = dataMembers\n}\n\nfunc (m *mapTableModel) RowCount() int {\n\treturn len(m.items)\n}\n\nfunc (m *mapTableModel) Value(row, col int) interface{} {\n\tif m.items[row] == nil {\n\t\tif populator, ok := m.dataSource.(Populator); ok {\n\t\t\tif err := populator.Populate(row); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif m.items[row] == nil {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn m.items[row][m.dataMembers[col]]\n}\n\nfunc (m *mapTableModel) Sort(col int, order SortOrder) error {\n\tm.col, m.order = col, order\n\n\tsort.Stable(m)\n\n\tm.changedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (m *mapTableModel) Len() int {\n\treturn m.RowCount()\n}\n\nfunc (m *mapTableModel) Less(i, j int) bool {\n\tcol := m.SortedColumn()\n\n\treturn less(m.Value(i, col), m.Value(j, col), m.SortOrder())\n}\n\nfunc (m *mapTableModel) Swap(i, j int) {\n\tm.items[i], m.items[j] = m.items[j], m.items[i]\n}\n"
  },
  {
    "path": "menu.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype Menu struct {\n\thMenu   win.HMENU\n\twindow  Window\n\tactions *ActionList\n\tgetDPI  func() int\n}\n\nfunc newMenuBar(window Window) (*Menu, error) {\n\thMenu := win.CreateMenu()\n\tif hMenu == 0 {\n\t\treturn nil, lastError(\"CreateMenu\")\n\t}\n\n\tm := &Menu{\n\t\thMenu:  hMenu,\n\t\twindow: window,\n\t}\n\tm.actions = newActionList(m)\n\n\treturn m, nil\n}\n\nfunc NewMenu() (*Menu, error) {\n\thMenu := win.CreatePopupMenu()\n\tif hMenu == 0 {\n\t\treturn nil, lastError(\"CreatePopupMenu\")\n\t}\n\n\tvar mi win.MENUINFO\n\tmi.CbSize = uint32(unsafe.Sizeof(mi))\n\n\tif !win.GetMenuInfo(hMenu, &mi) {\n\t\treturn nil, lastError(\"GetMenuInfo\")\n\t}\n\n\tmi.FMask |= win.MIM_STYLE\n\tmi.DwStyle = win.MNS_CHECKORBMP\n\n\tif !win.SetMenuInfo(hMenu, &mi) {\n\t\treturn nil, lastError(\"SetMenuInfo\")\n\t}\n\n\tm := &Menu{\n\t\thMenu: hMenu,\n\t}\n\tm.actions = newActionList(m)\n\n\treturn m, nil\n}\n\nfunc (m *Menu) Dispose() {\n\tm.actions.Clear()\n\n\tif m.hMenu != 0 {\n\t\twin.DestroyMenu(m.hMenu)\n\t\tm.hMenu = 0\n\t}\n}\n\nfunc (m *Menu) IsDisposed() bool {\n\treturn m.hMenu == 0\n}\n\nfunc (m *Menu) Actions() *ActionList {\n\treturn m.actions\n}\n\nfunc (m *Menu) updateItemsWithImageForWindow(window Window) {\n\tif m.window == nil {\n\t\tm.window = window\n\t\tdefer func() {\n\t\t\tm.window = nil\n\t\t}()\n\t}\n\n\tfor _, action := range m.actions.actions {\n\t\tif action.image != nil {\n\t\t\tm.onActionChanged(action)\n\t\t}\n\t\tif action.menu != nil {\n\t\t\taction.menu.updateItemsWithImageForWindow(window)\n\t\t}\n\t}\n}\n\nfunc (m *Menu) initMenuItemInfoFromAction(mii *win.MENUITEMINFO, action *Action) {\n\tmii.CbSize = uint32(unsafe.Sizeof(*mii))\n\tmii.FMask = win.MIIM_FTYPE | win.MIIM_ID | win.MIIM_STATE | win.MIIM_STRING\n\tif action.image != nil {\n\t\tmii.FMask |= win.MIIM_BITMAP\n\t\tdpi := 96\n\t\tif m.getDPI != nil {\n\t\t\tdpi = m.getDPI()\n\t\t} else if m.window != nil {\n\t\t\tdpi = m.window.DPI()\n\t\t} else {\n\t\t\tdpi = screenDPI()\n\t\t}\n\t\tif bmp, err := iconCache.Bitmap(action.image, dpi); err == nil {\n\t\t\tmii.HbmpItem = bmp.hBmp\n\t\t}\n\t}\n\tif action.IsSeparator() {\n\t\tmii.FType |= win.MFT_SEPARATOR\n\t} else {\n\t\tmii.FType |= win.MFT_STRING\n\t\tvar text string\n\t\tif s := action.shortcut; s.Key != 0 {\n\t\t\ttext = fmt.Sprintf(\"%s\\t%s\", action.text, s.String())\n\t\t} else {\n\t\t\ttext = action.text\n\t\t}\n\t\tmii.DwTypeData = syscall.StringToUTF16Ptr(text)\n\t\tmii.Cch = uint32(len([]rune(action.text)))\n\t}\n\tmii.WID = uint32(action.id)\n\n\tif action.Enabled() {\n\t\tmii.FState &^= win.MFS_DISABLED\n\t} else {\n\t\tmii.FState |= win.MFS_DISABLED\n\t}\n\n\tif action.Checkable() {\n\t\tmii.FMask |= win.MIIM_CHECKMARKS\n\t}\n\tif action.Checked() {\n\t\tmii.FState |= win.MFS_CHECKED\n\t}\n\tif action.Exclusive() {\n\t\tmii.FType |= win.MFT_RADIOCHECK\n\t}\n\n\tmenu := action.menu\n\tif menu != nil {\n\t\tmii.FMask |= win.MIIM_SUBMENU\n\t\tmii.HSubMenu = menu.hMenu\n\t}\n}\n\nfunc (m *Menu) handleDefaultState(action *Action) {\n\tif action.Default() {\n\t\t// Unset other default actions before we set this one. Otherwise insertion fails.\n\t\twin.SetMenuDefaultItem(m.hMenu, ^uint32(0), false)\n\t\tfor _, otherAction := range m.actions.actions {\n\t\t\tif otherAction != action {\n\t\t\t\totherAction.SetDefault(false)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (m *Menu) onActionChanged(action *Action) error {\n\tm.handleDefaultState(action)\n\n\tif !action.Visible() {\n\t\treturn nil\n\t}\n\n\tvar mii win.MENUITEMINFO\n\n\tm.initMenuItemInfoFromAction(&mii, action)\n\n\tif !win.SetMenuItemInfo(m.hMenu, uint32(m.actions.indexInObserver(action)), true, &mii) {\n\t\treturn newError(\"SetMenuItemInfo failed\")\n\t}\n\n\tif action.Default() {\n\t\twin.SetMenuDefaultItem(m.hMenu, uint32(m.actions.indexInObserver(action)), true)\n\t}\n\n\tif action.Exclusive() && action.Checked() {\n\t\tvar first, last int\n\n\t\tindex := m.actions.Index(action)\n\n\t\tfor i := index; i >= 0; i-- {\n\t\t\tfirst = i\n\t\t\tif !m.actions.At(i).Exclusive() {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tfor i := index; i < m.actions.Len(); i++ {\n\t\t\tlast = i\n\t\t\tif !m.actions.At(i).Exclusive() {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !win.CheckMenuRadioItem(m.hMenu, uint32(first), uint32(last), uint32(index), win.MF_BYPOSITION) {\n\t\t\treturn newError(\"CheckMenuRadioItem failed\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (m *Menu) onActionVisibleChanged(action *Action) error {\n\tif !action.IsSeparator() {\n\t\tdefer m.actions.updateSeparatorVisibility()\n\t}\n\n\tif action.Visible() {\n\t\treturn m.insertAction(action, true)\n\t}\n\n\treturn m.removeAction(action, true)\n}\n\nfunc (m *Menu) insertAction(action *Action, visibleChanged bool) (err error) {\n\tm.handleDefaultState(action)\n\n\tif !visibleChanged {\n\t\taction.addChangedHandler(m)\n\t\tdefer func() {\n\t\t\tif err != nil {\n\t\t\t\taction.removeChangedHandler(m)\n\t\t\t}\n\t\t}()\n\t}\n\n\tif !action.Visible() {\n\t\treturn\n\t}\n\n\tindex := m.actions.indexInObserver(action)\n\n\tvar mii win.MENUITEMINFO\n\n\tm.initMenuItemInfoFromAction(&mii, action)\n\n\tif !win.InsertMenuItem(m.hMenu, uint32(index), true, &mii) {\n\t\treturn newError(\"InsertMenuItem failed\")\n\t}\n\n\tif action.Default() {\n\t\twin.SetMenuDefaultItem(m.hMenu, uint32(m.actions.indexInObserver(action)), true)\n\t}\n\n\tmenu := action.menu\n\tif menu != nil {\n\t\tmenu.window = m.window\n\t}\n\n\tm.ensureMenuBarRedrawn()\n\n\treturn\n}\n\nfunc (m *Menu) removeAction(action *Action, visibleChanged bool) error {\n\tindex := m.actions.indexInObserver(action)\n\n\tif !win.RemoveMenu(m.hMenu, uint32(index), win.MF_BYPOSITION) {\n\t\treturn lastError(\"RemoveMenu\")\n\t}\n\n\tif !visibleChanged {\n\t\taction.removeChangedHandler(m)\n\t}\n\n\tm.ensureMenuBarRedrawn()\n\n\treturn nil\n}\n\nfunc (m *Menu) ensureMenuBarRedrawn() {\n\tif m.window != nil {\n\t\tif mw, ok := m.window.(*MainWindow); ok && mw != nil {\n\t\t\twin.DrawMenuBar(mw.Handle())\n\t\t}\n\t}\n}\n\nfunc (m *Menu) onInsertedAction(action *Action) error {\n\treturn m.insertAction(action, false)\n}\n\nfunc (m *Menu) onRemovingAction(action *Action) error {\n\treturn m.removeAction(action, false)\n}\n\nfunc (m *Menu) onClearingActions() error {\n\tfor i := m.actions.Len() - 1; i >= 0; i-- {\n\t\tif action := m.actions.At(i); action.Visible() {\n\t\t\tif err := m.onRemovingAction(action); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "messagebox.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"strings\"\n\t\"syscall\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype MsgBoxStyle uint\n\nconst (\n\tMsgBoxOK                  MsgBoxStyle = win.MB_OK\n\tMsgBoxOKCancel            MsgBoxStyle = win.MB_OKCANCEL\n\tMsgBoxAbortRetryIgnore    MsgBoxStyle = win.MB_ABORTRETRYIGNORE\n\tMsgBoxYesNoCancel         MsgBoxStyle = win.MB_YESNOCANCEL\n\tMsgBoxYesNo               MsgBoxStyle = win.MB_YESNO\n\tMsgBoxRetryCancel         MsgBoxStyle = win.MB_RETRYCANCEL\n\tMsgBoxCancelTryContinue   MsgBoxStyle = win.MB_CANCELTRYCONTINUE\n\tMsgBoxIconHand            MsgBoxStyle = win.MB_ICONHAND\n\tMsgBoxIconQuestion        MsgBoxStyle = win.MB_ICONQUESTION\n\tMsgBoxIconExclamation     MsgBoxStyle = win.MB_ICONEXCLAMATION\n\tMsgBoxIconAsterisk        MsgBoxStyle = win.MB_ICONASTERISK\n\tMsgBoxUserIcon            MsgBoxStyle = win.MB_USERICON\n\tMsgBoxIconWarning         MsgBoxStyle = win.MB_ICONWARNING\n\tMsgBoxIconError           MsgBoxStyle = win.MB_ICONERROR\n\tMsgBoxIconInformation     MsgBoxStyle = win.MB_ICONINFORMATION\n\tMsgBoxIconStop            MsgBoxStyle = win.MB_ICONSTOP\n\tMsgBoxDefButton1          MsgBoxStyle = win.MB_DEFBUTTON1\n\tMsgBoxDefButton2          MsgBoxStyle = win.MB_DEFBUTTON2\n\tMsgBoxDefButton3          MsgBoxStyle = win.MB_DEFBUTTON3\n\tMsgBoxDefButton4          MsgBoxStyle = win.MB_DEFBUTTON4\n\tMsgBoxApplModal           MsgBoxStyle = win.MB_APPLMODAL\n\tMsgBoxSystemModal         MsgBoxStyle = win.MB_SYSTEMMODAL\n\tMsgBoxTaskModal           MsgBoxStyle = win.MB_TASKMODAL\n\tMsgBoxHelp                MsgBoxStyle = win.MB_HELP\n\tMsgBoxSetForeground       MsgBoxStyle = win.MB_SETFOREGROUND\n\tMsgBoxDefaultDesktopOnly  MsgBoxStyle = win.MB_DEFAULT_DESKTOP_ONLY\n\tMsgBoxTopMost             MsgBoxStyle = win.MB_TOPMOST\n\tMsgBoxRight               MsgBoxStyle = win.MB_RIGHT\n\tMsgBoxRTLReading          MsgBoxStyle = win.MB_RTLREADING\n\tMsgBoxServiceNotification MsgBoxStyle = win.MB_SERVICE_NOTIFICATION\n)\n\nfunc MsgBox(owner Form, title, message string, style MsgBoxStyle) int {\n\tvar ownerHWnd win.HWND\n\n\tif owner != nil {\n\t\townerHWnd = owner.Handle()\n\t}\n\n\treturn int(win.MessageBox(\n\t\townerHWnd,\n\t\tsyscall.StringToUTF16Ptr(strings.ReplaceAll(message, \"\\x00\", \"␀\")),\n\t\tsyscall.StringToUTF16Ptr(strings.ReplaceAll(title, \"\\x00\", \"␀\")),\n\t\tuint32(style)))\n}\n"
  },
  {
    "path": "metafile.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"math\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst milimeterPerMeter float64 = 1000.0\n\ntype Metafile struct {\n\thdc  win.HDC\n\themf win.HENHMETAFILE\n\tsize Size // in native pixels\n\tdpi  Size\n}\n\nfunc NewMetafile(referenceCanvas *Canvas) (*Metafile, error) {\n\thdc := win.CreateEnhMetaFile(referenceCanvas.hdc, nil, nil, nil)\n\tif hdc == 0 {\n\t\treturn nil, newError(\"CreateEnhMetaFile failed\")\n\t}\n\n\treturn &Metafile{hdc: hdc}, nil\n}\n\nfunc NewMetafileFromFile(filePath string) (*Metafile, error) {\n\themf := win.GetEnhMetaFile(syscall.StringToUTF16Ptr(filePath))\n\tif hemf == 0 {\n\t\treturn nil, newError(\"GetEnhMetaFile failed\")\n\t}\n\n\tmf := &Metafile{hemf: hemf}\n\n\terr := mf.readSizeFromHeader()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn mf, nil\n}\n\nfunc (mf *Metafile) Dispose() {\n\tmf.ensureFinished()\n\n\tif mf.hemf != 0 {\n\t\twin.DeleteEnhMetaFile(mf.hemf)\n\n\t\tmf.hemf = 0\n\t}\n}\n\nfunc (mf *Metafile) Save(filePath string) error {\n\themf := win.CopyEnhMetaFile(mf.hemf, syscall.StringToUTF16Ptr(filePath))\n\tif hemf == 0 {\n\t\treturn newError(\"CopyEnhMetaFile failed\")\n\t}\n\n\twin.DeleteEnhMetaFile(hemf)\n\n\treturn nil\n}\n\nfunc (mf *Metafile) readSizeFromHeader() error {\n\tvar hdr win.ENHMETAHEADER\n\n\tif win.GetEnhMetaFileHeader(mf.hemf, uint32(unsafe.Sizeof(hdr)), &hdr) == 0 {\n\t\treturn newError(\"GetEnhMetaFileHeader failed\")\n\t}\n\n\tmf.size = sizeFromRECT(hdr.RclBounds)\n\tscale := milimeterPerMeter / inchesPerMeter\n\tmf.dpi = Size{\n\t\tint(math.Round(float64(hdr.SzlDevice.CX) / float64(hdr.SzlMillimeters.CX) * scale)),\n\t\tint(math.Round(float64(hdr.SzlDevice.CY) / float64(hdr.SzlMillimeters.CY) * scale)),\n\t}\n\n\treturn nil\n}\n\nfunc (mf *Metafile) ensureFinished() error {\n\tif mf.hdc == 0 {\n\t\tif mf.hemf == 0 {\n\t\t\treturn newError(\"already disposed\")\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tmf.hemf = win.CloseEnhMetaFile(mf.hdc)\n\tif mf.hemf == 0 {\n\t\treturn newError(\"CloseEnhMetaFile failed\")\n\t}\n\n\tmf.hdc = 0\n\n\treturn mf.readSizeFromHeader()\n}\n\n// Size returns image size in 1/96\" units.\nfunc (mf *Metafile) Size() Size {\n\treturn Size{\n\t\tWidth:  scaleInt(mf.size.Width, 96.0/float64(mf.dpi.Width)),\n\t\tHeight: scaleInt(mf.size.Height, 96.0/float64(mf.dpi.Height)),\n\t}\n}\n\nfunc (mf *Metafile) draw(hdc win.HDC, location Point) error {\n\treturn mf.drawStretched(hdc, Rectangle{location.X, location.Y, mf.size.Width, mf.size.Height})\n}\n\nfunc (mf *Metafile) drawStretched(hdc win.HDC, bounds Rectangle) error {\n\trc := bounds.toRECT()\n\n\tif !win.PlayEnhMetaFile(hdc, mf.hemf, &rc) {\n\t\treturn newError(\"PlayEnhMetaFile failed\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "models.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\n\t\"github.com/lxn/win\"\n)\n\n// BindingValueProvider is the interface that a model must implement to support\n// data binding with widgets like ComboBox.\ntype BindingValueProvider interface {\n\tBindingValue(index int) interface{}\n}\n\n// ListModel is the interface that a model must implement to support widgets\n// like ComboBox.\ntype ListModel interface {\n\t// ItemCount returns the number of items in the model.\n\tItemCount() int\n\n\t// Value returns the value that should be displayed for the given index.\n\tValue(index int) interface{}\n\n\t// ItemsReset returns the event that the model should publish when the\n\t// number of its items changes.\n\tItemsReset() *Event\n\n\t// ItemChanged returns the event that the model should publish when an item\n\t// was changed.\n\tItemChanged() *IntEvent\n\n\t// ItemsInserted returns the event that the model should publish when a\n\t// contiguous range of items was inserted.\n\tItemsInserted() *IntRangeEvent\n\n\t// ItemsRemoved returns the event that the model should publish when a\n\t// contiguous range of items was removed.\n\tItemsRemoved() *IntRangeEvent\n}\n\n// ListModelBase implements the ItemsReset and ItemChanged methods of the\n// ListModel interface.\ntype ListModelBase struct {\n\titemsResetPublisher    EventPublisher\n\titemChangedPublisher   IntEventPublisher\n\titemsInsertedPublisher IntRangeEventPublisher\n\titemsRemovedPublisher  IntRangeEventPublisher\n}\n\nfunc (lmb *ListModelBase) ItemsReset() *Event {\n\treturn lmb.itemsResetPublisher.Event()\n}\n\nfunc (lmb *ListModelBase) ItemChanged() *IntEvent {\n\treturn lmb.itemChangedPublisher.Event()\n}\n\nfunc (lmb *ListModelBase) ItemsInserted() *IntRangeEvent {\n\treturn lmb.itemsInsertedPublisher.Event()\n}\n\nfunc (lmb *ListModelBase) ItemsRemoved() *IntRangeEvent {\n\treturn lmb.itemsRemovedPublisher.Event()\n}\n\nfunc (lmb *ListModelBase) PublishItemsReset() {\n\tlmb.itemsResetPublisher.Publish()\n}\n\nfunc (lmb *ListModelBase) PublishItemChanged(index int) {\n\tlmb.itemChangedPublisher.Publish(index)\n}\n\nfunc (lmb *ListModelBase) PublishItemsInserted(from, to int) {\n\tlmb.itemsInsertedPublisher.Publish(from, to)\n}\n\nfunc (lmb *ListModelBase) PublishItemsRemoved(from, to int) {\n\tlmb.itemsRemovedPublisher.Publish(from, to)\n}\n\n// ReflectListModel provides an alternative to the ListModel interface. It\n// uses reflection to obtain data.\ntype ReflectListModel interface {\n\t// Items returns the model data, which must be a slice of pointer to struct.\n\tItems() interface{}\n\n\t// ItemsReset returns the event that the model should publish when the\n\t// number of its items changes.\n\tItemsReset() *Event\n\n\t// ItemChanged returns the event that the model should publish when an item\n\t// was changed.\n\tItemChanged() *IntEvent\n\n\t// ItemsInserted returns the event that the model should publish when a\n\t// contiguous range of items was inserted.\n\tItemsInserted() *IntRangeEvent\n\n\t// ItemsRemoved returns the event that the model should publish when a\n\t// contiguous range of items was removed.\n\tItemsRemoved() *IntRangeEvent\n\n\tsetValueFunc(value func(index int) interface{})\n}\n\n// ReflectListModelBase implements the ItemsReset and ItemChanged methods of\n// the ReflectListModel interface.\ntype ReflectListModelBase struct {\n\tListModelBase\n\tvalue func(index int) interface{}\n}\n\nfunc (rlmb *ReflectListModelBase) setValueFunc(value func(index int) interface{}) {\n\trlmb.value = value\n}\n\nfunc (rlmb *ReflectListModelBase) Value(index int) interface{} {\n\treturn rlmb.value(index)\n}\n\n// TableModel is the interface that a model must implement to support widgets\n// like TableView.\ntype TableModel interface {\n\t// RowCount returns the number of rows in the model.\n\tRowCount() int\n\n\t// Value returns the value that should be displayed for the given cell.\n\tValue(row, col int) interface{}\n\n\t// RowsReset returns the event that the model should publish when the number\n\t// of its rows changes.\n\tRowsReset() *Event\n\n\t// RowChanged returns the event that the model should publish when a row was\n\t// changed.\n\tRowChanged() *IntEvent\n\n\t// RowsChanged returns the event that the model should publish when a\n\t// contiguous range of items was changed.\n\tRowsChanged() *IntRangeEvent\n\n\t// RowsInserted returns the event that the model should publish when a\n\t// contiguous range of items was inserted. If the model supports sorting, it\n\t// is assumed to be sorted before the model publishes the event.\n\tRowsInserted() *IntRangeEvent\n\n\t// RowsRemoved returns the event that the model should publish when a\n\t// contiguous range of items was removed.\n\tRowsRemoved() *IntRangeEvent\n}\n\n// TableModelBase implements the RowsReset and RowChanged methods of the\n// TableModel interface.\ntype TableModelBase struct {\n\trowsResetPublisher    EventPublisher\n\trowChangedPublisher   IntEventPublisher\n\trowsChangedPublisher  IntRangeEventPublisher\n\trowsInsertedPublisher IntRangeEventPublisher\n\trowsRemovedPublisher  IntRangeEventPublisher\n}\n\nfunc (tmb *TableModelBase) RowsReset() *Event {\n\treturn tmb.rowsResetPublisher.Event()\n}\n\nfunc (tmb *TableModelBase) RowChanged() *IntEvent {\n\treturn tmb.rowChangedPublisher.Event()\n}\n\nfunc (tmb *TableModelBase) RowsChanged() *IntRangeEvent {\n\treturn tmb.rowsChangedPublisher.Event()\n}\n\nfunc (tmb *TableModelBase) RowsInserted() *IntRangeEvent {\n\treturn tmb.rowsInsertedPublisher.Event()\n}\n\nfunc (tmb *TableModelBase) RowsRemoved() *IntRangeEvent {\n\treturn tmb.rowsRemovedPublisher.Event()\n}\n\nfunc (tmb *TableModelBase) PublishRowsReset() {\n\ttmb.rowsResetPublisher.Publish()\n}\n\nfunc (tmb *TableModelBase) PublishRowChanged(row int) {\n\ttmb.rowChangedPublisher.Publish(row)\n}\n\nfunc (tmb *TableModelBase) PublishRowsChanged(from, to int) {\n\ttmb.rowsChangedPublisher.Publish(from, to)\n}\n\nfunc (tmb *TableModelBase) PublishRowsInserted(from, to int) {\n\ttmb.rowsInsertedPublisher.Publish(from, to)\n}\n\nfunc (tmb *TableModelBase) PublishRowsRemoved(from, to int) {\n\ttmb.rowsRemovedPublisher.Publish(from, to)\n}\n\n// ReflectTableModel provides an alternative to the TableModel interface. It\n// uses reflection to obtain data.\ntype ReflectTableModel interface {\n\t// Items returns the model data, which must be a slice of pointer to struct.\n\tItems() interface{}\n\n\t// RowsReset returns the event that the model should publish when the\n\t// number of its items changes.\n\tRowsReset() *Event\n\n\t// RowChanged returns the event that the model should publish when an item\n\t// was changed.\n\tRowChanged() *IntEvent\n\n\t// RowsChanged returns the event that the model should publish when a\n\t// contiguous range of items was changed.\n\tRowsChanged() *IntRangeEvent\n\n\t// RowsInserted returns the event that the model should publish when a\n\t// contiguous range of items was inserted. If the model supports sorting, it\n\t// is assumed to be sorted before the model publishes the event.\n\tRowsInserted() *IntRangeEvent\n\n\t// RowsRemoved returns the event that the model should publish when a\n\t// contiguous range of items was removed.\n\tRowsRemoved() *IntRangeEvent\n\n\tsetValueFunc(value func(row, col int) interface{})\n}\n\n// ReflectTableModelBase implements the ItemsReset and ItemChanged methods of\n// the ReflectTableModel interface.\ntype ReflectTableModelBase struct {\n\tTableModelBase\n\tvalue func(row, col int) interface{}\n}\n\nfunc (rtmb *ReflectTableModelBase) setValueFunc(value func(row, col int) interface{}) {\n\trtmb.value = value\n}\n\nfunc (rtmb *ReflectTableModelBase) Value(row, col int) interface{} {\n\treturn rtmb.value(row, col)\n}\n\ntype interceptedSorter interface {\n\tsorterBase() *SorterBase\n\tsetSortFunc(sort func(col int, order SortOrder) error)\n}\n\n// SortedReflectTableModelBase implements the RowsReset and RowChanged methods\n// of the ReflectTableModel interface as well as the Sorter interface for\n// pre-implemented in-memory sorting.\ntype SortedReflectTableModelBase struct {\n\tReflectTableModelBase\n\tSorterBase\n\tsort func(col int, order SortOrder) error\n}\n\nfunc (srtmb *SortedReflectTableModelBase) setSortFunc(sort func(col int, order SortOrder) error) {\n\tsrtmb.sort = sort\n}\n\nfunc (srtmb *SortedReflectTableModelBase) sorterBase() *SorterBase {\n\treturn &srtmb.SorterBase\n}\n\nfunc (srtmb *SortedReflectTableModelBase) Sort(col int, order SortOrder) error {\n\tif srtmb.sort != nil {\n\t\treturn srtmb.sort(col, order)\n\t}\n\n\treturn srtmb.SorterBase.Sort(col, order)\n}\n\n// Populator is an interface that can be implemented by Reflect*Models and slice\n// types to populate themselves on demand.\n//\n// Widgets like TableView, ListBox and ComboBox support lazy population of a\n// Reflect*Model or slice, if it implements this interface.\ntype Populator interface {\n\t// Populate initializes the slot specified by index.\n\t//\n\t// For best performance it is probably a good idea to populate more than a\n\t// single slot of the slice at once.\n\tPopulate(index int) error\n}\n\n// ImageProvider is the interface that a model must implement to support\n// displaying an item image.\ntype ImageProvider interface {\n\t// Image returns the image to display for the item at index index.\n\t//\n\t// Supported types are *walk.Bitmap, *walk.Icon and string. A string will be\n\t// interpreted as a file path and the icon associated with the file will be\n\t// used. It is not supported to use strings together with the other options\n\t// in the same model instance.\n\tImage(index int) interface{}\n}\n\n// CellStyler is the interface that must be implemented to provide a tabular\n// widget like TableView with cell display style information.\ntype CellStyler interface {\n\t// StyleCell is called for each cell to pick up cell style information.\n\tStyleCell(style *CellStyle)\n}\n\n// CellStyle carries information about the display style of a cell in a tabular widget\n// like TableView.\ntype CellStyle struct {\n\trow             int\n\tcol             int\n\tbounds          Rectangle // in native pixels\n\thdc             win.HDC\n\tdpi             int\n\tcanvas          *Canvas\n\tBackgroundColor Color\n\tTextColor       Color\n\tFont            *Font\n\n\t// Image is the image to display in the cell.\n\t//\n\t// Supported types are *walk.Bitmap, *walk.Icon and string. A string will be\n\t// interpreted as a file path and the icon associated with the file will be\n\t// used. It is not supported to use strings together with the other options\n\t// in the same model instance.\n\tImage interface{}\n}\n\nfunc (cs *CellStyle) Row() int {\n\treturn cs.row\n}\n\nfunc (cs *CellStyle) Col() int {\n\treturn cs.col\n}\n\nfunc (cs *CellStyle) Bounds() Rectangle {\n\treturn RectangleTo96DPI(cs.bounds, cs.dpi)\n}\n\nfunc (cs *CellStyle) BoundsPixels() Rectangle {\n\treturn cs.bounds\n}\n\nfunc (cs *CellStyle) Canvas() *Canvas {\n\tif cs.canvas != nil {\n\t\tcs.canvas.dpi = cs.dpi\n\t\treturn cs.canvas\n\t}\n\n\tif cs.hdc != 0 {\n\t\tcs.canvas, _ = newCanvasFromHDC(cs.hdc)\n\t\tcs.canvas.dpi = cs.dpi\n\t}\n\n\treturn cs.canvas\n}\n\n// IDProvider is the interface that must be implemented by models to enable\n// widgets like TableView to attempt keeping the current item when the model\n// publishes a reset event.\ntype IDProvider interface {\n\tID(index int) interface{}\n}\n\n// ListItemStyler is the interface that must be implemented to provide a list\n// widget like ListBox with item display style information.\ntype ListItemStyler interface {\n\t// ItemHeightDependsOnWidth returns whether item height depends on width.\n\tItemHeightDependsOnWidth() bool\n\n\t// DefaultItemHeight returns the initial height in native pixels for any item.\n\tDefaultItemHeight() int\n\n\t// ItemHeight is called for each item to retrieve the height of the item. width parameter and\n\t// return value are specified in native pixels.\n\tItemHeight(index int, width int) int\n\n\t// StyleItem is called for each item to pick up item style information.\n\tStyleItem(style *ListItemStyle)\n}\n\n// ListItemStyle carries information about the display style of an item in a list widget\n// like ListBox.\ntype ListItemStyle struct {\n\tBackgroundColor    Color\n\tTextColor          Color\n\tdefaultTextColor   Color\n\tLineColor          Color\n\tFont               *Font\n\tindex              int\n\thoverIndex         int\n\trc                 win.RECT\n\tbounds             Rectangle // in native pixels\n\tstate              uint32\n\thTheme             win.HTHEME\n\thwnd               win.HWND\n\thdc                win.HDC\n\tdpi                int\n\tcanvas             *Canvas\n\thighContrastActive bool\n}\n\nfunc (lis *ListItemStyle) Index() int {\n\treturn lis.index\n}\n\nfunc (lis *ListItemStyle) Bounds() Rectangle {\n\treturn RectangleTo96DPI(lis.bounds, lis.dpi)\n}\n\nfunc (lis *ListItemStyle) BoundsPixels() Rectangle {\n\treturn lis.bounds\n}\n\nfunc (lis *ListItemStyle) Canvas() *Canvas {\n\tif lis.canvas != nil {\n\t\tlis.canvas.dpi = lis.dpi\n\t\treturn lis.canvas\n\t}\n\n\tif lis.hdc != 0 {\n\t\tlis.canvas, _ = newCanvasFromHDC(lis.hdc)\n\t\tlis.canvas.dpi = lis.dpi\n\t}\n\n\treturn lis.canvas\n}\n\nfunc (lis *ListItemStyle) DrawBackground() error {\n\tcanvas := lis.Canvas()\n\tif canvas == nil {\n\t\treturn nil\n\t}\n\n\tstateID := lis.stateID()\n\n\tif lis.hTheme != 0 && stateID != win.LISS_NORMAL {\n\t\tif win.FAILED(win.DrawThemeBackground(lis.hTheme, lis.hdc, win.LVP_LISTITEM, stateID, &lis.rc, nil)) {\n\t\t\treturn newError(\"DrawThemeBackground failed\")\n\t\t}\n\t} else {\n\t\tbrush, err := NewSolidColorBrush(lis.BackgroundColor)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer brush.Dispose()\n\n\t\tif err := canvas.FillRectanglePixels(brush, lis.bounds); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif lis.highContrastActive && (lis.index == lis.hoverIndex || stateID != win.LISS_NORMAL) {\n\t\t\tpen, err := NewCosmeticPen(PenSolid, lis.LineColor)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer pen.Dispose()\n\n\t\t\tif err := canvas.DrawRectanglePixels(pen, lis.bounds); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// DrawText draws text inside given bounds specified in native pixels.\nfunc (lis *ListItemStyle) DrawText(text string, bounds Rectangle, format DrawTextFormat) error {\n\tif lis.hTheme != 0 && lis.TextColor == lis.defaultTextColor {\n\t\tif lis.Font != nil {\n\t\t\thFontOld := win.SelectObject(lis.hdc, win.HGDIOBJ(lis.Font.handleForDPI(lis.dpi)))\n\t\t\tdefer win.SelectObject(lis.hdc, hFontOld)\n\t\t}\n\t\trc := bounds.toRECT()\n\n\t\tif win.FAILED(win.DrawThemeTextEx(lis.hTheme, lis.hdc, win.LVP_LISTITEM, lis.stateID(), syscall.StringToUTF16Ptr(text), int32(len(([]rune)(text))), uint32(format), &rc, nil)) {\n\t\t\treturn newError(\"DrawThemeTextEx failed\")\n\t\t}\n\t} else {\n\t\tif canvas := lis.Canvas(); canvas != nil {\n\t\t\tif err := canvas.DrawTextPixels(text, lis.Font, lis.TextColor, bounds, format); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (lis *ListItemStyle) stateID() int32 {\n\tif lis.state&win.ODS_CHECKED != 0 {\n\t\tif win.GetFocus() == lis.hwnd {\n\t\t\tif lis.index == lis.hoverIndex {\n\t\t\t\treturn win.LISS_HOTSELECTED\n\t\t\t} else {\n\t\t\t\treturn win.LISS_SELECTED\n\t\t\t}\n\t\t} else {\n\t\t\treturn win.LISS_SELECTEDNOTFOCUS\n\t\t}\n\t} else if lis.index == lis.hoverIndex {\n\t\treturn win.LISS_HOT\n\t}\n\n\treturn win.LISS_NORMAL\n}\n\n// ItemChecker is the interface that a model must implement to support check\n// boxes in a widget like TableView.\ntype ItemChecker interface {\n\t// Checked returns if the specified item is checked.\n\tChecked(index int) bool\n\n\t// SetChecked sets if the specified item is checked.\n\tSetChecked(index int, checked bool) error\n}\n\n// SortOrder specifies the order by which items are sorted.\ntype SortOrder int\n\nconst (\n\t// SortAscending specifies ascending sort order.\n\tSortAscending SortOrder = iota\n\n\t// SortDescending specifies descending sort order.\n\tSortDescending\n)\n\n// Sorter is the interface that a model must implement to support sorting with a\n// widget like TableView.\ntype Sorter interface {\n\t// ColumnSortable returns whether column col is sortable.\n\tColumnSortable(col int) bool\n\n\t// Sort sorts column col in order order.\n\t//\n\t// If col is -1 then no column is to be sorted. Sort must publish the event\n\t// returned from SortChanged() after sorting.\n\tSort(col int, order SortOrder) error\n\n\t// SortChanged returns an event that is published after sorting.\n\tSortChanged() *Event\n\n\t// SortedColumn returns the index of the currently sorted column, or -1 if\n\t// no column is currently sorted.\n\tSortedColumn() int\n\n\t// SortOrder returns the current sort order.\n\tSortOrder() SortOrder\n}\n\n// SorterBase implements the Sorter interface.\n//\n// You still need to provide your own implementation of at least the Sort method\n// to actually sort and reset the model. Your Sort method should call the\n// SorterBase implementation so the SortChanged event, that e.g. a TableView\n// widget depends on, is published.\ntype SorterBase struct {\n\tchangedPublisher EventPublisher\n\tcol              int\n\torder            SortOrder\n}\n\nfunc (sb *SorterBase) ColumnSortable(col int) bool {\n\treturn true\n}\n\nfunc (sb *SorterBase) Sort(col int, order SortOrder) error {\n\tsb.col, sb.order = col, order\n\n\tsb.changedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (sb *SorterBase) SortChanged() *Event {\n\treturn sb.changedPublisher.Event()\n}\n\nfunc (sb *SorterBase) SortedColumn() int {\n\treturn sb.col\n}\n\nfunc (sb *SorterBase) SortOrder() SortOrder {\n\treturn sb.order\n}\n\n// Imager provides access to an image of objects like tree items.\ntype Imager interface {\n\t// Image returns the image to display for an item.\n\t//\n\t// Supported types are *walk.Bitmap, *walk.Icon and string. A string will be\n\t// interpreted as a file path and the icon associated with the file will be\n\t// used. It is not supported to use strings together with the other options\n\t// in the same model instance.\n\tImage() interface{}\n}\n\n// TreeItem represents an item in a TreeView widget.\ntype TreeItem interface {\n\t// Text returns the text of the item.\n\tText() string\n\n\t// Parent returns the parent of the item.\n\tParent() TreeItem\n\n\t// ChildCount returns the number of children of the item.\n\tChildCount() int\n\n\t// ChildAt returns the child at the specified index.\n\tChildAt(index int) TreeItem\n}\n\n// HasChilder enables widgets like TreeView to determine if an item has any\n// child, without enforcing to fully count all children.\ntype HasChilder interface {\n\tHasChild() bool\n}\n\n// TreeModel provides widgets like TreeView with item data.\ntype TreeModel interface {\n\t// LazyPopulation returns if the model prefers on-demand population.\n\t//\n\t// This is useful for models that potentially contain huge amounts of items,\n\t// e.g. a model that represents a file system.\n\tLazyPopulation() bool\n\n\t// RootCount returns the number of root items.\n\tRootCount() int\n\n\t// RootAt returns the root item at the specified index.\n\tRootAt(index int) TreeItem\n\n\t// ItemsReset returns the event that the model should publish when the\n\t// descendants of the specified item, or all items if no item is specified,\n\t// are reset.\n\tItemsReset() *TreeItemEvent\n\n\t// ItemChanged returns the event that the model should publish when an item\n\t// was changed.\n\tItemChanged() *TreeItemEvent\n\n\t// ItemInserted returns the event that the model should publish when an item\n\t// was inserted into the model.\n\tItemInserted() *TreeItemEvent\n\n\t// ItemRemoved returns the event that the model should publish when an item\n\t// was removed from the model.\n\tItemRemoved() *TreeItemEvent\n}\n\n// TreeModelBase partially implements the TreeModel interface.\n//\n// You still need to provide your own implementation of at least the\n// RootCount and RootAt methods. If your model needs lazy population,\n// you will also have to implement LazyPopulation.\ntype TreeModelBase struct {\n\titemsResetPublisher   TreeItemEventPublisher\n\titemChangedPublisher  TreeItemEventPublisher\n\titemInsertedPublisher TreeItemEventPublisher\n\titemRemovedPublisher  TreeItemEventPublisher\n}\n\nfunc (tmb *TreeModelBase) LazyPopulation() bool {\n\treturn false\n}\n\nfunc (tmb *TreeModelBase) ItemsReset() *TreeItemEvent {\n\treturn tmb.itemsResetPublisher.Event()\n}\n\nfunc (tmb *TreeModelBase) ItemChanged() *TreeItemEvent {\n\treturn tmb.itemChangedPublisher.Event()\n}\n\nfunc (tmb *TreeModelBase) ItemInserted() *TreeItemEvent {\n\treturn tmb.itemInsertedPublisher.Event()\n}\n\nfunc (tmb *TreeModelBase) ItemRemoved() *TreeItemEvent {\n\treturn tmb.itemRemovedPublisher.Event()\n}\n\nfunc (tmb *TreeModelBase) PublishItemsReset(parent TreeItem) {\n\ttmb.itemsResetPublisher.Publish(parent)\n}\n\nfunc (tmb *TreeModelBase) PublishItemChanged(item TreeItem) {\n\ttmb.itemChangedPublisher.Publish(item)\n}\n\nfunc (tmb *TreeModelBase) PublishItemInserted(item TreeItem) {\n\ttmb.itemInsertedPublisher.Publish(item)\n}\n\nfunc (tmb *TreeModelBase) PublishItemRemoved(item TreeItem) {\n\ttmb.itemRemovedPublisher.Publish(item)\n}\n"
  },
  {
    "path": "mouseevent.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype MouseButton int\n\nconst (\n\tLeftButton   MouseButton = win.MK_LBUTTON\n\tRightButton  MouseButton = win.MK_RBUTTON\n\tMiddleButton MouseButton = win.MK_MBUTTON\n)\n\ntype mouseEventHandlerInfo struct {\n\thandler MouseEventHandler\n\tonce    bool\n}\n\n// MouseEventHandler is called for mouse events. x and y are measured in native pixels.\ntype MouseEventHandler func(x, y int, button MouseButton)\n\ntype MouseEvent struct {\n\thandlers []mouseEventHandlerInfo\n}\n\nfunc (e *MouseEvent) Attach(handler MouseEventHandler) int {\n\thandlerInfo := mouseEventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *MouseEvent) Detach(handle int) {\n\te.handlers[handle].handler = nil\n}\n\nfunc (e *MouseEvent) Once(handler MouseEventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype MouseEventPublisher struct {\n\tevent MouseEvent\n}\n\nfunc (p *MouseEventPublisher) Event() *MouseEvent {\n\treturn &p.event\n}\n\n// Publish publishes mouse event. x and y are measured in native pixels.\nfunc (p *MouseEventPublisher) Publish(x, y int, button MouseButton) {\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler(x, y, button)\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc MouseWheelEventDelta(button MouseButton) int {\n\treturn int(int32(button) >> 16)\n}\n\nfunc MouseWheelEventKeyState(button MouseButton) int {\n\treturn int(int32(button) & 0xFFFF)\n}\n"
  },
  {
    "path": "notifyicon.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nvar notifyIcons = make(map[*NotifyIcon]bool)\n\nfunc notifyIconWndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) (result uintptr) {\n\t// Retrieve our *NotifyIcon from the message window.\n\tptr := win.GetWindowLongPtr(hwnd, win.GWLP_USERDATA)\n\tni := (*NotifyIcon)(unsafe.Pointer(ptr))\n\n\tswitch lParam {\n\tcase win.WM_LBUTTONDOWN:\n\t\tni.publishMouseEvent(&ni.mouseDownPublisher, LeftButton)\n\n\tcase win.WM_LBUTTONUP:\n\t\tni.publishMouseEvent(&ni.mouseUpPublisher, LeftButton)\n\n\tcase win.WM_RBUTTONDOWN:\n\t\tni.publishMouseEvent(&ni.mouseDownPublisher, RightButton)\n\n\tcase win.WM_RBUTTONUP:\n\t\tni.publishMouseEvent(&ni.mouseUpPublisher, RightButton)\n\n\t\twin.SendMessage(hwnd, msg, wParam, win.WM_CONTEXTMENU)\n\n\tcase win.WM_CONTEXTMENU:\n\t\tif ni.contextMenu.Actions().Len() == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\twin.SetForegroundWindow(hwnd)\n\n\t\tvar p win.POINT\n\t\tif !win.GetCursorPos(&p) {\n\t\t\tlastError(\"GetCursorPos\")\n\t\t}\n\n\t\tni.applyDPI()\n\n\t\tactionId := uint16(win.TrackPopupMenuEx(\n\t\t\tni.contextMenu.hMenu,\n\t\t\twin.TPM_NOANIMATION|win.TPM_RETURNCMD,\n\t\t\tp.X,\n\t\t\tp.Y,\n\t\t\thwnd,\n\t\t\tnil))\n\t\tif actionId != 0 {\n\t\t\tif action, ok := actionsById[actionId]; ok {\n\t\t\t\taction.raiseTriggered()\n\t\t\t}\n\t\t}\n\n\t\treturn 0\n\tcase win.NIN_BALLOONUSERCLICK:\n\t\tni.messageClickedPublisher.Publish()\n\t}\n\n\treturn win.DefWindowProc(hwnd, msg, wParam, lParam)\n}\n\n// NotifyIcon represents an icon in the taskbar notification area.\ntype NotifyIcon struct {\n\tid                      uint32\n\thWnd                    win.HWND\n\tlastDPI                 int\n\tcontextMenu             *Menu\n\ticon                    Image\n\ttoolTip                 string\n\tvisible                 bool\n\tmouseDownPublisher      MouseEventPublisher\n\tmouseUpPublisher        MouseEventPublisher\n\tmessageClickedPublisher EventPublisher\n}\n\n// NewNotifyIcon creates and returns a new NotifyIcon.\n//\n// The NotifyIcon is initially not visible.\nfunc NewNotifyIcon(form Form) (*NotifyIcon, error) {\n\tfb := form.AsFormBase()\n\t// Add our notify icon to the status area and make sure it is hidden.\n\tnid := win.NOTIFYICONDATA{\n\t\tHWnd:             fb.hWnd,\n\t\tUFlags:           win.NIF_MESSAGE | win.NIF_STATE,\n\t\tDwState:          win.NIS_HIDDEN,\n\t\tDwStateMask:      win.NIS_HIDDEN,\n\t\tUCallbackMessage: notifyIconMessageId,\n\t}\n\tnid.CbSize = uint32(unsafe.Sizeof(nid) - unsafe.Sizeof(win.HICON(0)))\n\n\tif !win.Shell_NotifyIcon(win.NIM_ADD, &nid) {\n\t\treturn nil, newError(\"Shell_NotifyIcon\")\n\t}\n\n\t// We want XP-compatible message behavior.\n\tnid.UVersion = win.NOTIFYICON_VERSION\n\n\tif !win.Shell_NotifyIcon(win.NIM_SETVERSION, &nid) {\n\t\treturn nil, newError(\"Shell_NotifyIcon\")\n\t}\n\n\t// Create and initialize the NotifyIcon already.\n\tmenu, err := NewMenu()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmenu.window = form\n\n\tni := &NotifyIcon{\n\t\tid:          nid.UID,\n\t\thWnd:        fb.hWnd,\n\t\tcontextMenu: menu,\n\t}\n\n\tmenu.getDPI = ni.DPI\n\n\t// Set our *NotifyIcon as user data for the message window.\n\twin.SetWindowLongPtr(fb.hWnd, win.GWLP_USERDATA, uintptr(unsafe.Pointer(ni)))\n\n\tnotifyIcons[ni] = true\n\treturn ni, nil\n}\n\nfunc (ni *NotifyIcon) DPI() int {\n\tfakeWb := WindowBase{hWnd: win.FindWindow(syscall.StringToUTF16Ptr(\"Shell_TrayWnd\"), syscall.StringToUTF16Ptr(\"\"))}\n\treturn fakeWb.DPI()\n}\n\nfunc (ni *NotifyIcon) readdToTaskbar() error {\n\tnid := win.NOTIFYICONDATA{\n\t\tHWnd:             ni.hWnd,\n\t\tUFlags:           win.NIF_MESSAGE | win.NIF_STATE,\n\t\tDwState:          win.NIS_HIDDEN,\n\t\tDwStateMask:      win.NIS_HIDDEN,\n\t\tUCallbackMessage: notifyIconMessageId,\n\t}\n\tnid.CbSize = uint32(unsafe.Sizeof(nid) - unsafe.Sizeof(win.HICON(0)))\n\n\tif !win.Shell_NotifyIcon(win.NIM_ADD, &nid) {\n\t\treturn newError(\"Shell_NotifyIcon\")\n\t}\n\n\t// We want XP-compatible message behavior.\n\tnid.UVersion = win.NOTIFYICON_VERSION\n\n\tif !win.Shell_NotifyIcon(win.NIM_SETVERSION, &nid) {\n\t\treturn newError(\"Shell_NotifyIcon\")\n\t}\n\n\ticon := ni.icon\n\tni.icon = nil\n\terr := ni.SetIcon(icon)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvisible := ni.visible\n\tni.visible = false\n\terr = ni.SetVisible(visible)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttooltip := ni.toolTip\n\tni.toolTip = \"\"\n\terr = ni.SetToolTip(tooltip)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (ni *NotifyIcon) applyDPI() {\n\tdpi := ni.DPI()\n\tif dpi == ni.lastDPI {\n\t\treturn\n\t}\n\tni.lastDPI = dpi\n\tfor _, action := range ni.contextMenu.actions.actions {\n\t\tif action.image != nil {\n\t\t\tni.contextMenu.onActionChanged(action)\n\t\t}\n\t}\n\ticon := ni.icon\n\tni.icon = nil\n\tif icon != nil {\n\t\tni.SetIcon(icon)\n\t}\n}\n\nfunc (ni *NotifyIcon) notifyIconData() *win.NOTIFYICONDATA {\n\tnid := &win.NOTIFYICONDATA{\n\t\tUID:  ni.id,\n\t\tHWnd: ni.hWnd,\n\t}\n\tnid.CbSize = uint32(unsafe.Sizeof(*nid) - unsafe.Sizeof(win.HICON(0)))\n\n\treturn nid\n}\n\n// Dispose releases the operating system resources associated with the\n// NotifyIcon.\n//\n// The associated Icon is not disposed of.\nfunc (ni *NotifyIcon) Dispose() error {\n\tif ni.hWnd == 0 {\n\t\treturn nil\n\t}\n\tdelete(notifyIcons, ni)\n\n\tnid := ni.notifyIconData()\n\n\tif !win.Shell_NotifyIcon(win.NIM_DELETE, nid) {\n\t\treturn newError(\"Shell_NotifyIcon\")\n\t}\n\n\tni.hWnd = 0\n\n\treturn nil\n}\n\nfunc (ni *NotifyIcon) showMessage(title, info string, iconType uint32, icon Image) error {\n\tnid := ni.notifyIconData()\n\tnid.UFlags = win.NIF_INFO\n\tnid.DwInfoFlags = iconType\n\tvar oldIcon Image\n\tif iconType == win.NIIF_USER && icon != nil {\n\t\toldIcon = ni.icon\n\t\tif err := ni.setNIDIcon(nid, icon); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tnid.UFlags |= win.NIF_ICON\n\t}\n\tif title16, err := syscall.UTF16FromString(title); err == nil {\n\t\tcopy(nid.SzInfoTitle[:], title16)\n\t}\n\tif info16, err := syscall.UTF16FromString(info); err == nil {\n\t\tcopy(nid.SzInfo[:], info16)\n\t}\n\tif !win.Shell_NotifyIcon(win.NIM_MODIFY, nid) {\n\t\treturn newError(\"Shell_NotifyIcon\")\n\t}\n\tif oldIcon != nil {\n\t\tni.icon = nil\n\t\tni.SetIcon(oldIcon)\n\t}\n\n\treturn nil\n}\n\n// ShowMessage displays a neutral message balloon above the NotifyIcon.\n//\n// The NotifyIcon must be visible before calling this method.\nfunc (ni *NotifyIcon) ShowMessage(title, info string) error {\n\treturn ni.showMessage(title, info, win.NIIF_NONE, nil)\n}\n\n// ShowInfo displays an info message balloon above the NotifyIcon.\n//\n// The NotifyIcon must be visible before calling this method.\nfunc (ni *NotifyIcon) ShowInfo(title, info string) error {\n\treturn ni.showMessage(title, info, win.NIIF_INFO, nil)\n}\n\n// ShowWarning displays a warning message balloon above the NotifyIcon.\n//\n// The NotifyIcon must be visible before calling this method.\nfunc (ni *NotifyIcon) ShowWarning(title, info string) error {\n\treturn ni.showMessage(title, info, win.NIIF_WARNING, nil)\n}\n\n// ShowError displays an error message balloon above the NotifyIcon.\n//\n// The NotifyIcon must be visible before calling this method.\nfunc (ni *NotifyIcon) ShowError(title, info string) error {\n\treturn ni.showMessage(title, info, win.NIIF_ERROR, nil)\n}\n\n// ShowCustom displays a custom icon message balloon above the NotifyIcon.\n// If icon is nil, the main notification icon is used instead of a custom one.\n//\n// The NotifyIcon must be visible before calling this method.\nfunc (ni *NotifyIcon) ShowCustom(title, info string, icon Image) error {\n\treturn ni.showMessage(title, info, win.NIIF_USER, icon)\n}\n\n// ContextMenu returns the context menu of the NotifyIcon.\nfunc (ni *NotifyIcon) ContextMenu() *Menu {\n\treturn ni.contextMenu\n}\n\n// Icon returns the Icon of the NotifyIcon.\nfunc (ni *NotifyIcon) Icon() Image {\n\treturn ni.icon\n}\n\n// SetIcon sets the Icon of the NotifyIcon.\nfunc (ni *NotifyIcon) SetIcon(icon Image) error {\n\tif icon == ni.icon {\n\t\treturn nil\n\t}\n\n\tnid := ni.notifyIconData()\n\tnid.UFlags = win.NIF_ICON\n\tif icon == nil {\n\t\tnid.HIcon = 0\n\t} else {\n\t\tif err := ni.setNIDIcon(nid, icon); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif !win.Shell_NotifyIcon(win.NIM_MODIFY, nid) {\n\t\treturn newError(\"Shell_NotifyIcon\")\n\t}\n\n\tni.icon = icon\n\n\treturn nil\n}\n\nfunc (ni *NotifyIcon) setNIDIcon(nid *win.NOTIFYICONDATA, icon Image) error {\n\tdpi := ni.DPI()\n\tic, err := iconCache.Icon(icon, dpi)\n\tif err != nil {\n\t\treturn err\n\t}\n\tnid.HIcon = ic.handleForDPI(dpi)\n\n\treturn nil\n}\n\n// ToolTip returns the tool tip text of the NotifyIcon.\nfunc (ni *NotifyIcon) ToolTip() string {\n\treturn ni.toolTip\n}\n\n// SetToolTip sets the tool tip text of the NotifyIcon.\nfunc (ni *NotifyIcon) SetToolTip(toolTip string) error {\n\tif toolTip == ni.toolTip {\n\t\treturn nil\n\t}\n\n\tnid := ni.notifyIconData()\n\tnid.UFlags = win.NIF_TIP\n\tcopy(nid.SzTip[:], syscall.StringToUTF16(toolTip))\n\n\tif !win.Shell_NotifyIcon(win.NIM_MODIFY, nid) {\n\t\treturn newError(\"Shell_NotifyIcon\")\n\t}\n\n\tni.toolTip = toolTip\n\n\treturn nil\n}\n\n// Visible returns if the NotifyIcon is visible.\nfunc (ni *NotifyIcon) Visible() bool {\n\treturn ni.visible\n}\n\n// SetVisible sets if the NotifyIcon is visible.\nfunc (ni *NotifyIcon) SetVisible(visible bool) error {\n\tif visible == ni.visible {\n\t\treturn nil\n\t}\n\n\tnid := ni.notifyIconData()\n\tnid.UFlags = win.NIF_STATE\n\tnid.DwStateMask = win.NIS_HIDDEN\n\tif !visible {\n\t\tnid.DwState = win.NIS_HIDDEN\n\t}\n\n\tif !win.Shell_NotifyIcon(win.NIM_MODIFY, nid) {\n\t\treturn newError(\"Shell_NotifyIcon\")\n\t}\n\n\tni.visible = visible\n\n\treturn nil\n}\n\nfunc (ni *NotifyIcon) publishMouseEvent(publisher *MouseEventPublisher, button MouseButton) {\n\tvar p win.POINT\n\tif !win.GetCursorPos(&p) {\n\t\tlastError(\"GetCursorPos\")\n\t}\n\n\tpublisher.Publish(int(p.X), int(p.Y), button)\n}\n\n// MouseDown returns the event that is published when a mouse button is pressed\n// while the cursor is over the NotifyIcon.\nfunc (ni *NotifyIcon) MouseDown() *MouseEvent {\n\treturn ni.mouseDownPublisher.Event()\n}\n\n// MouseDown returns the event that is published when a mouse button is released\n// while the cursor is over the NotifyIcon.\nfunc (ni *NotifyIcon) MouseUp() *MouseEvent {\n\treturn ni.mouseUpPublisher.Event()\n}\n\n// MessageClicked occurs when the user clicks a message shown with ShowMessage or\n// one of its iconed variants.\nfunc (ni *NotifyIcon) MessageClicked() *Event {\n\treturn ni.messageClickedPublisher.Event()\n}\n"
  },
  {
    "path": "numberedit.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst numberEditWindowClass = `\\o/ Walk_NumberEdit_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(numberEditWindowClass)\n\t})\n}\n\n// NumberEdit is a widget that is suited to edit numeric values.\ntype NumberEdit struct {\n\tWidgetBase\n\tedit                     *numberLineEdit\n\thWndUpDown               win.HWND\n\tmaxValueChangedPublisher EventPublisher\n\tminValueChangedPublisher EventPublisher\n\tprefixChangedPublisher   EventPublisher\n\tsuffixChangedPublisher   EventPublisher\n}\n\n// NewNumberEdit returns a new NumberEdit widget as child of parent.\nfunc NewNumberEdit(parent Container) (*NumberEdit, error) {\n\tne := new(NumberEdit)\n\n\tif err := InitWidget(\n\t\tne,\n\t\tparent,\n\t\tnumberEditWindowClass,\n\t\twin.WS_VISIBLE,\n\t\twin.WS_EX_CONTROLPARENT); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar succeeded bool\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tne.Dispose()\n\t\t}\n\t}()\n\n\tvar err error\n\tif ne.edit, err = newNumberLineEdit(ne); err != nil {\n\t\treturn nil, err\n\t}\n\n\tne.edit.applyFont(ne.Font())\n\n\tne.SetRange(-math.MaxFloat64, math.MaxFloat64)\n\n\tif err = ne.SetValue(0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tne.GraphicsEffects().Add(InteractionEffect)\n\tne.GraphicsEffects().Add(FocusEffect)\n\n\tne.MustRegisterProperty(\"MaxValue\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn ne.MaxValue()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn ne.SetRange(ne.MinValue(), assertFloat64Or(v, 0.0))\n\t\t},\n\t\tne.minValueChangedPublisher.Event()))\n\n\tne.MustRegisterProperty(\"MinValue\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn ne.MinValue()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn ne.SetRange(assertFloat64Or(v, 0.0), ne.MaxValue())\n\t\t},\n\t\tne.maxValueChangedPublisher.Event()))\n\n\tne.MustRegisterProperty(\"Prefix\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn ne.Prefix()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn ne.SetPrefix(assertStringOr(v, \"\"))\n\t\t},\n\t\tne.prefixChangedPublisher.Event()))\n\n\tne.MustRegisterProperty(\"ReadOnly\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn ne.ReadOnly()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn ne.SetReadOnly(v.(bool))\n\t\t},\n\t\tne.edit.readOnlyChangedPublisher.Event()))\n\n\tne.MustRegisterProperty(\"Suffix\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn ne.Suffix()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn ne.SetSuffix(assertStringOr(v, \"\"))\n\t\t},\n\t\tne.suffixChangedPublisher.Event()))\n\n\tne.MustRegisterProperty(\"Value\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn ne.Value()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn ne.SetValue(assertFloat64Or(v, 0.0))\n\t\t},\n\t\tne.edit.valueChangedPublisher.Event()))\n\n\tsucceeded = true\n\n\treturn ne, nil\n}\n\nfunc (ne *NumberEdit) applyEnabled(enabled bool) {\n\tne.WidgetBase.applyEnabled(enabled)\n\n\tif ne.edit == nil {\n\t\treturn\n\t}\n\n\tne.edit.applyEnabled(enabled)\n}\n\nfunc (ne *NumberEdit) applyFont(font *Font) {\n\tne.WidgetBase.applyFont(font)\n\n\tif ne.edit == nil {\n\t\treturn\n\t}\n\n\tne.edit.applyFont(font)\n}\n\n// Decimals returns the number of decimal places in the NumberEdit.\nfunc (ne *NumberEdit) Decimals() int {\n\treturn ne.edit.decimals\n}\n\n// SetDecimals sets the number of decimal places in the NumberEdit.\nfunc (ne *NumberEdit) SetDecimals(decimals int) error {\n\tif decimals < 0 || decimals > 8 {\n\t\treturn newError(\"decimals must >= 0 && <= 8\")\n\t}\n\n\tne.edit.decimals = decimals\n\n\treturn ne.SetValue(ne.edit.value)\n}\n\n// Prefix returns the text that appears in the NumberEdit before the number.\nfunc (ne *NumberEdit) Prefix() string {\n\treturn syscall.UTF16ToString(ne.edit.prefix)\n}\n\n// SetPrefix sets the text that appears in the NumberEdit before the number.\nfunc (ne *NumberEdit) SetPrefix(prefix string) error {\n\tif prefix == ne.Prefix() {\n\t\treturn nil\n\t}\n\n\tp, err := syscall.UTF16FromString(prefix)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\told := ne.edit.prefix\n\tne.edit.prefix = p[:len(p)-1]\n\n\tif err := ne.edit.setTextFromValue(ne.edit.value); err != nil {\n\t\tne.edit.prefix = old\n\t\treturn err\n\t}\n\n\tne.prefixChangedPublisher.Publish()\n\n\treturn nil\n}\n\n// PrefixChanged returns the event that is published when the prefix changed.\nfunc (ne *NumberEdit) PrefixChanged() *Event {\n\treturn ne.prefixChangedPublisher.Event()\n}\n\n// Suffix returns the text that appears in the NumberEdit after the number.\nfunc (ne *NumberEdit) Suffix() string {\n\treturn syscall.UTF16ToString(ne.edit.suffix)\n}\n\n// SetSuffix sets the text that appears in the NumberEdit after the number.\nfunc (ne *NumberEdit) SetSuffix(suffix string) error {\n\tif suffix == ne.Suffix() {\n\t\treturn nil\n\t}\n\n\ts, err := syscall.UTF16FromString(suffix)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\told := ne.edit.suffix\n\tne.edit.suffix = s[:len(s)-1]\n\n\tif err := ne.edit.setTextFromValue(ne.edit.value); err != nil {\n\t\tne.edit.suffix = old\n\t\treturn err\n\t}\n\n\tne.suffixChangedPublisher.Publish()\n\n\treturn nil\n}\n\n// SuffixChanged returns the event that is published when the suffix changed.\nfunc (ne *NumberEdit) SuffixChanged() *Event {\n\treturn ne.suffixChangedPublisher.Event()\n}\n\n// Increment returns the amount by which the NumberEdit increments or decrements\n// its value, when the user presses the KeyDown or KeyUp keys, or when the mouse\n// wheel is rotated.\nfunc (ne *NumberEdit) Increment() float64 {\n\treturn ne.edit.increment\n}\n\n// SetIncrement sets the amount by which the NumberEdit increments or decrements\n// its value, when the user presses the KeyDown or KeyUp keys, or when the mouse\n// wheel is rotated.\nfunc (ne *NumberEdit) SetIncrement(increment float64) error {\n\tne.edit.increment = increment\n\n\treturn nil\n}\n\n// MinValue returns the minimum value the NumberEdit will accept.\nfunc (ne *NumberEdit) MinValue() float64 {\n\treturn ne.edit.minValue\n}\n\n// MinValue returns the maximum value the NumberEdit will accept.\nfunc (ne *NumberEdit) MaxValue() float64 {\n\treturn ne.edit.maxValue\n}\n\n// SetRange sets the minimum and maximum values the NumberEdit will accept.\n//\n// If the current value is out of this range, it will be adjusted.\nfunc (ne *NumberEdit) SetRange(min, max float64) error {\n\tif min > max {\n\t\treturn newError(fmt.Sprintf(\"invalid range - min: %f, max: %f\", min, max))\n\t}\n\n\tminChanged := min != ne.edit.minValue\n\tmaxChanged := max != ne.edit.maxValue\n\n\tne.edit.minValue = min\n\tne.edit.maxValue = max\n\tif min != max {\n\t\tif ne.edit.value < min {\n\t\t\tif err := ne.edit.setValue(min, true); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if ne.edit.value > max {\n\t\t\tif err := ne.edit.setValue(max, true); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tif minChanged {\n\t\tne.minValueChangedPublisher.Publish()\n\t}\n\tif maxChanged {\n\t\tne.maxValueChangedPublisher.Publish()\n\t}\n\n\treturn nil\n}\n\n// Value returns the value of the NumberEdit.\nfunc (ne *NumberEdit) Value() float64 {\n\treturn ne.edit.value\n}\n\n// SetValue sets the value of the NumberEdit.\nfunc (ne *NumberEdit) SetValue(value float64) error {\n\tif ne.edit.minValue != ne.edit.maxValue &&\n\t\t(value < ne.edit.minValue || value > ne.edit.maxValue) {\n\n\t\treturn newError(\"value out of range\")\n\t}\n\n\treturn ne.edit.setValue(value, true)\n}\n\n// ValueChanged returns an Event that can be used to track changes to Value.\nfunc (ne *NumberEdit) ValueChanged() *Event {\n\treturn ne.edit.valueChangedPublisher.Event()\n}\n\n// SetFocus sets the keyboard input focus to the NumberEdit.\nfunc (ne *NumberEdit) SetFocus() error {\n\tif win.SetFocus(ne.edit.hWnd) == 0 {\n\t\treturn lastError(\"SetFocus\")\n\t}\n\n\treturn nil\n}\n\n// TextSelection returns the range of the current text selection of the\n// NumberEdit.\nfunc (ne *NumberEdit) TextSelection() (start, end int) {\n\treturn ne.edit.TextSelection()\n}\n\n// SetTextSelection sets the range of the current text selection of the\n// NumberEdit.\nfunc (ne *NumberEdit) SetTextSelection(start, end int) {\n\tne.edit.SetTextSelection(start, end)\n}\n\n// ReadOnly returns whether the NumberEdit is in read-only mode.\nfunc (ne *NumberEdit) ReadOnly() bool {\n\treturn ne.edit.ReadOnly()\n}\n\n// SetReadOnly sets whether the NumberEdit is in read-only mode.\nfunc (ne *NumberEdit) SetReadOnly(readOnly bool) error {\n\tif readOnly != ne.ReadOnly() {\n\t\tne.invalidateBorderInParent()\n\t}\n\n\treturn ne.edit.SetReadOnly(readOnly)\n}\n\n// SpinButtonsVisible returns whether the NumberEdit appears with spin buttons.\nfunc (ne *NumberEdit) SpinButtonsVisible() bool {\n\treturn ne.hWndUpDown != 0\n}\n\n// SetSpinButtonsVisible sets whether the NumberEdit appears with spin buttons.\nfunc (ne *NumberEdit) SetSpinButtonsVisible(visible bool) error {\n\tif visible == ne.SpinButtonsVisible() {\n\t\treturn nil\n\t}\n\n\tif visible {\n\t\tne.hWndUpDown = win.CreateWindowEx(\n\t\t\t0,\n\t\t\tsyscall.StringToUTF16Ptr(\"msctls_updown32\"),\n\t\t\tnil,\n\t\t\twin.WS_CHILD|win.WS_VISIBLE|win.UDS_ALIGNRIGHT|win.UDS_ARROWKEYS|win.UDS_HOTTRACK,\n\t\t\t0,\n\t\t\t0,\n\t\t\t16,\n\t\t\t20,\n\t\t\tne.hWnd,\n\t\t\t0,\n\t\t\t0,\n\t\t\tnil)\n\t\tif ne.hWndUpDown == 0 {\n\t\t\treturn lastError(\"CreateWindowEx\")\n\t\t}\n\n\t\twin.SendMessage(ne.hWndUpDown, win.UDM_SETBUDDY, uintptr(ne.edit.hWnd), 0)\n\t} else {\n\t\tif !win.DestroyWindow(ne.hWndUpDown) {\n\t\t\treturn lastError(\"DestroyWindow\")\n\t\t}\n\n\t\tne.hWndUpDown = 0\n\t}\n\n\treturn nil\n}\n\n// Background returns the background Brush of the NumberEdit.\n//\n// By default this is nil.\nfunc (ne *NumberEdit) Background() Brush {\n\treturn ne.edit.Background()\n}\n\n// SetBackground sets the background Brush of the NumberEdit.\nfunc (ne *NumberEdit) SetBackground(bg Brush) {\n\tne.edit.SetBackground(bg)\n}\n\n// TextColor returns the Color used to draw the text of the NumberEdit.\nfunc (ne *NumberEdit) TextColor() Color {\n\treturn ne.edit.TextColor()\n}\n\n// TextColor sets the Color used to draw the text of the NumberEdit.\nfunc (ne *NumberEdit) SetTextColor(c Color) {\n\tne.edit.SetTextColor(c)\n}\n\nfunc (*NumberEdit) NeedsWmSize() bool {\n\treturn true\n}\n\n// WndProc is the window procedure of the NumberEdit.\n//\n// When implementing your own WndProc to add or modify behavior, call the\n// WndProc of the embedded NumberEdit for messages you don't handle yourself.\nfunc (ne *NumberEdit) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_NOTIFY:\n\t\tswitch ((*win.NMHDR)(unsafe.Pointer(lParam))).Code {\n\t\tcase win.UDN_DELTAPOS:\n\t\t\tnmud := (*win.NMUPDOWN)(unsafe.Pointer(lParam))\n\t\t\tne.edit.incrementValue(-float64(nmud.IDelta) * ne.edit.increment)\n\t\t}\n\n\tcase win.WM_CTLCOLOREDIT, win.WM_CTLCOLORSTATIC:\n\t\tif hBrush := ne.handleWMCTLCOLOR(wParam, lParam); hBrush != 0 {\n\t\t\treturn hBrush\n\t\t}\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif ne.edit == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tcb := ne.ClientBoundsPixels()\n\t\tif err := ne.edit.SetBoundsPixels(cb); err != nil {\n\t\t\tbreak\n\t\t}\n\n\t\tif ne.hWndUpDown != 0 {\n\t\t\twin.SendMessage(ne.hWndUpDown, win.UDM_SETBUDDY, uintptr(ne.edit.hWnd), 0)\n\t\t}\n\t}\n\n\treturn ne.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (ne *NumberEdit) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn &numberEditLayoutItem{\n\t\tidealSize: ne.dialogBaseUnitsToPixels(Size{50, 12}),\n\t\tminSize:   ne.dialogBaseUnitsToPixels(Size{20, 12}),\n\t}\n}\n\ntype numberEditLayoutItem struct {\n\tLayoutItemBase\n\tidealSize Size // in native pixels\n\tminSize   Size // in native pixels\n}\n\nfunc (*numberEditLayoutItem) LayoutFlags() LayoutFlags {\n\treturn ShrinkableHorz | GrowableHorz\n}\n\nfunc (li *numberEditLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *numberEditLayoutItem) MinSize() Size {\n\treturn li.minSize\n}\n\ntype numberLineEdit struct {\n\t*LineEdit\n\tbuf                   *bytes.Buffer\n\tprefix                []uint16\n\tsuffix                []uint16\n\tvalue                 float64\n\tminValue              float64\n\tmaxValue              float64\n\tincrement             float64\n\tdecimals              int\n\tvalueChangedPublisher EventPublisher\n\tinEditMode            bool\n}\n\nfunc newNumberLineEdit(parent Widget) (*numberLineEdit, error) {\n\tnle := &numberLineEdit{\n\t\tbuf:       new(bytes.Buffer),\n\t\tincrement: 1,\n\t}\n\n\tvar err error\n\tif nle.LineEdit, err = newLineEdit(parent); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tnle.Dispose()\n\t\t}\n\t}()\n\n\tif err := nle.LineEdit.setAndClearStyleBits(win.ES_RIGHT, win.ES_LEFT|win.ES_CENTER); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := InitWrapperWindow(nle); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded = true\n\n\treturn nle, nil\n}\n\nfunc (nle *numberLineEdit) TextColor() Color {\n\treturn nle.LineEdit.TextColor()\n}\n\nfunc (nle *numberLineEdit) SetTextColor(c Color) {\n\tnle.LineEdit.SetTextColor(c)\n}\n\nfunc (nle *numberLineEdit) setValue(value float64, setText bool) error {\n\tif setText {\n\t\tif err := nle.setTextFromValue(value); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif value == nle.value {\n\t\treturn nil\n\t}\n\n\tnle.value = value\n\n\tnle.valueChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (nle *numberLineEdit) setTextFromValue(value float64) error {\n\tnle.buf.Reset()\n\n\tnle.buf.WriteString(syscall.UTF16ToString(nle.prefix))\n\n\tif nle.decimals > 0 {\n\t\tnle.buf.WriteString(FormatFloatGrouped(value, nle.decimals))\n\t} else {\n\t\tnle.buf.WriteString(FormatFloat(value, nle.decimals))\n\t}\n\n\tnle.buf.WriteString(syscall.UTF16ToString(nle.suffix))\n\n\treturn nle.SetText(nle.buf.String())\n}\n\nfunc (nle *numberLineEdit) endEdit() error {\n\tif err := nle.setTextFromValue(nle.value); err != nil {\n\t\treturn err\n\t}\n\n\tnle.inEditMode = false\n\n\treturn nil\n}\n\nfunc (nle *numberLineEdit) processChar(text []uint16, start, end int, key Key, char uint16) {\n\thadSelection := start != end\n\n\tif !nle.inEditMode {\n\t\tvar groupSepsBeforeStart int\n\t\tif nle.decimals > 0 {\n\t\t\tgroupSepsBeforeStart = uint16CountUint16(text[:start], groupSepUint16)\n\t\t}\n\n\t\tif hadSelection {\n\t\t\ttext = append(text[:start], text[end:]...)\n\t\t}\n\n\t\tif nle.decimals > 0 {\n\t\t\ttext = uint16RemoveUint16(text, groupSepUint16)\n\t\t\tstart -= groupSepsBeforeStart\n\t\t}\n\n\t\tnle.inEditMode = true\n\t} else {\n\t\tif hadSelection {\n\t\t\ttext = append(text[:start], text[end:]...)\n\t\t}\n\t}\n\n\tend = start\n\n\tswitch key {\n\tcase KeyBack:\n\t\tif !hadSelection && start > 0 {\n\t\t\tstart -= 1\n\t\t\ttext = append(text[:start], text[start+1:]...)\n\t\t}\n\n\tcase KeyDelete:\n\t\tif !hadSelection && start < len(text) {\n\t\t\ttext = append(text[:start], text[start+1:]...)\n\t\t}\n\n\tdefault:\n\t\tt := make([]uint16, len(text[:start]), len(text)+1)\n\t\tcopy(t, text[:start])\n\t\tt = append(t, char)\n\t\ttext = append(t, text[start:]...)\n\t\tstart += 1\n\t}\n\n\tnle.buf.Reset()\n\n\tstr := syscall.UTF16ToString(text)\n\n\tnle.buf.WriteString(syscall.UTF16ToString(nle.prefix))\n\tnle.buf.WriteString(str)\n\tnle.buf.WriteString(syscall.UTF16ToString(nle.suffix))\n\n\tnle.SetText(nle.buf.String())\n\n\tstart += len(nle.prefix)\n\tnle.SetTextSelection(start, start)\n\n\tnle.tryUpdateValue(false)\n}\n\nfunc (nle *numberLineEdit) tryUpdateValue(setText bool) bool {\n\tt := nle.textUTF16()\n\tt = t[len(nle.prefix) : len(t)-len(nle.suffix)]\n\n\ttext := strings.Replace(syscall.UTF16ToString(t), decimalSepS, \".\", 1)\n\n\tswitch text {\n\tcase \"\", \".\":\n\t\ttext = \"0\"\n\t}\n\n\tif value, err := strconv.ParseFloat(text, 64); err == nil {\n\t\tif nle.minValue == nle.maxValue || value >= nle.minValue && value <= nle.maxValue {\n\t\t\treturn nle.setValue(value, setText) == nil\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (nle *numberLineEdit) selectNumber() {\n\tnle.SetTextSelection(len(nle.prefix), len(nle.textUTF16())-len(nle.suffix))\n}\n\nfunc (nle *numberLineEdit) textUTF16() []uint16 {\n\ttextLength := nle.SendMessage(win.WM_GETTEXTLENGTH, 0, 0)\n\tbuf := make([]uint16, textLength+1)\n\tnle.SendMessage(win.WM_GETTEXT, uintptr(textLength+1), uintptr(unsafe.Pointer(&buf[0])))\n\n\treturn buf[:len(buf)-1]\n}\n\nfunc (nle *numberLineEdit) incrementValue(delta float64) {\n\tvalue := nle.value + delta\n\n\tif nle.minValue != nle.maxValue {\n\t\tif value < nle.minValue {\n\t\t\tvalue = nle.minValue\n\t\t} else if value > nle.maxValue {\n\t\t\tvalue = nle.maxValue\n\t\t}\n\t}\n\n\tnle.setValue(value, true)\n\tnle.selectNumber()\n}\n\nfunc (nle *numberLineEdit) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_CHAR:\n\t\tif nle.ReadOnly() {\n\t\t\tbreak\n\t\t}\n\n\t\tif AltDown() {\n\t\t\treturn 0\n\t\t}\n\n\t\tif ControlDown() {\n\t\t\tif wParam == 1 {\n\t\t\t\t// Ctrl+A\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tchar := uint16(wParam)\n\n\t\ttext := nle.textUTF16()\n\t\ttext = text[len(nle.prefix) : len(text)-len(nle.suffix)]\n\t\tstart, end := nle.TextSelection()\n\t\tstart -= len(nle.prefix)\n\t\tend -= len(nle.prefix)\n\n\t\tif Key(wParam) == KeyBack {\n\t\t\tnle.processChar(text, start, end, KeyBack, 0)\n\t\t\treturn 0\n\t\t}\n\n\t\tswitch char {\n\t\tcase uint16('0'), uint16('1'), uint16('2'), uint16('3'), uint16('4'), uint16('5'), uint16('6'), uint16('7'), uint16('8'), uint16('9'):\n\t\t\tif start == end && nle.decimals > 0 {\n\t\t\t\tif i := uint16IndexUint16(text, decimalSepUint16); i > -1 && i < len(text)-nle.decimals && start > i {\n\t\t\t\t\treturn 0\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnle.processChar(text, start, end, 0, char)\n\t\t\treturn 0\n\n\t\tcase uint16('-'):\n\t\t\tif nle.minValue != nle.maxValue && nle.minValue >= 0 {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tif start > 0 || uint16ContainsUint16(text, uint16('-')) && end == 0 {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tnle.processChar(text, start, end, 0, char)\n\t\t\treturn 0\n\n\t\tcase decimalSepUint16:\n\t\t\tif nle.decimals == 0 {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tif start == 0 && end == 0 && len(text) > 0 && text[0] == '-' {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tif end < len(text)-nle.decimals {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tif i := uint16IndexUint16(text, decimalSepUint16); i > -1 && i <= start || i > end {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tnle.processChar(text, start, end, 0, char)\n\t\t\treturn 0\n\n\t\tdefault:\n\t\t\treturn 0\n\t\t}\n\n\tcase win.WM_KEYDOWN:\n\t\tswitch Key(wParam) {\n\t\tcase KeyA:\n\t\t\tif ControlDown() {\n\t\t\t\tnle.selectNumber()\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\tcase KeyDelete:\n\t\t\tif nle.ReadOnly() {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ttext := nle.textUTF16()\n\t\t\ttext = text[len(nle.prefix) : len(text)-len(nle.suffix)]\n\t\t\tstart, end := nle.TextSelection()\n\t\t\tstart -= len(nle.prefix)\n\t\t\tend -= len(nle.prefix)\n\n\t\t\tnle.processChar(text, start, end, KeyDelete, 0)\n\t\t\treturn 0\n\n\t\tcase KeyDown:\n\t\t\tif nle.ReadOnly() || nle.increment <= 0 {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tnle.incrementValue(-nle.increment)\n\t\t\treturn 0\n\n\t\tcase KeyEnd:\n\t\t\tstart, end := nle.TextSelection()\n\t\t\tend = len(nle.textUTF16()) - len(nle.suffix)\n\t\t\tif !ShiftDown() {\n\t\t\t\tstart = end\n\t\t\t}\n\t\t\tnle.SetTextSelection(start, end)\n\t\t\treturn 0\n\n\t\tcase KeyHome:\n\t\t\tstart, end := nle.TextSelection()\n\t\t\tstart = len(nle.prefix)\n\t\t\tif !ShiftDown() {\n\t\t\t\tend = start\n\t\t\t}\n\t\t\tnle.SetTextSelection(start, end)\n\t\t\treturn 0\n\n\t\tcase KeyLeft:\n\t\t\tvar pos win.POINT\n\t\t\twin.GetCaretPos(&pos)\n\n\t\t\tlParam := uintptr(win.MAKELONG(uint16(pos.X), uint16(pos.Y)))\n\t\t\ti := int(win.LOWORD(uint32(nle.SendMessage(win.EM_CHARFROMPOS, 0, lParam))))\n\n\t\t\tif min := len(nle.prefix); i <= min {\n\t\t\t\tif !ShiftDown() {\n\t\t\t\t\tnle.SetTextSelection(min, min)\n\t\t\t\t}\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\tcase KeyReturn:\n\t\t\tif nle.ReadOnly() {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif nle.inEditMode {\n\t\t\t\tnle.endEdit()\n\t\t\t\tnle.selectNumber()\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\tcase KeyRight:\n\t\t\tvar pos win.POINT\n\t\t\twin.GetCaretPos(&pos)\n\n\t\t\tlParam := uintptr(win.MAKELONG(uint16(pos.X), uint16(pos.Y)))\n\t\t\ti := int(win.LOWORD(uint32(nle.SendMessage(win.EM_CHARFROMPOS, 0, lParam))))\n\n\t\t\tif max := len(nle.textUTF16()) - len(nle.suffix); i >= max {\n\t\t\t\tif !ShiftDown() {\n\t\t\t\t\tnle.SetTextSelection(max, max)\n\t\t\t\t}\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\tcase KeyUp:\n\t\t\tif nle.ReadOnly() || nle.increment <= 0 {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tnle.incrementValue(nle.increment)\n\t\t\treturn 0\n\t\t}\n\n\tcase win.WM_GETDLGCODE:\n\t\tif !nle.inEditMode {\n\t\t\tif form := ancestor(nle); form != nil {\n\t\t\t\tif dlg, ok := form.(dialogish); ok {\n\t\t\t\t\tif dlg.DefaultButton() != nil {\n\t\t\t\t\t\t// If the NumberEdit lives in a Dialog that has a\n\t\t\t\t\t\t// DefaultButton, we won't swallow the return key.\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif wParam == win.VK_RETURN {\n\t\t\treturn win.DLGC_WANTALLKEYS\n\t\t}\n\n\tcase win.WM_KILLFOCUS:\n\t\tnle.onFocusChanged()\n\t\tnle.endEdit()\n\n\tcase win.WM_LBUTTONDOWN:\n\t\ti := int(win.LOWORD(uint32(nle.SendMessage(win.EM_CHARFROMPOS, 0, lParam))))\n\n\t\tif min := len(nle.prefix); i < min {\n\t\t\tnle.SetFocus()\n\t\t\tnle.SetTextSelection(min, min)\n\t\t\treturn 0\n\t\t}\n\t\tif max := len(nle.textUTF16()) - len(nle.suffix); i > max {\n\t\t\tnle.SetFocus()\n\t\t\tnle.SetTextSelection(max, max)\n\t\t\treturn 0\n\t\t}\n\n\tcase win.WM_LBUTTONDBLCLK:\n\t\tnle.selectNumber()\n\t\treturn 0\n\n\tcase win.WM_MOUSEMOVE:\n\t\ti := int(win.LOWORD(uint32(nle.SendMessage(win.EM_CHARFROMPOS, 0, lParam))))\n\n\t\tif min := len(nle.prefix); i < min {\n\t\t\treturn 0\n\t\t}\n\t\tif max := len(nle.textUTF16()) - len(nle.suffix); i > max {\n\t\t\treturn 0\n\t\t}\n\n\tcase win.WM_MOUSEWHEEL:\n\t\tif nle.ReadOnly() || nle.increment <= 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tdelta := float64(int16(win.HIWORD(uint32(wParam))))\n\t\tnle.incrementValue(delta / 120 * nle.increment)\n\t\treturn 0\n\n\tcase win.WM_PASTE:\n\t\tif nle.ReadOnly() {\n\t\t\tbreak\n\t\t}\n\n\t\tret := nle.LineEdit.WndProc(hwnd, msg, wParam, lParam)\n\t\tif !nle.tryUpdateValue(true) {\n\t\t\tnle.setTextFromValue(nle.value)\n\t\t}\n\t\tnle.selectNumber()\n\t\treturn ret\n\n\tcase win.WM_SETFOCUS:\n\t\tnle.onFocusChanged()\n\t\tnle.selectNumber()\n\n\tcase win.EM_SETSEL:\n\t\tstart := int(wParam)\n\t\tend := int(lParam)\n\t\tadjusted := false\n\t\tif min := len(nle.prefix); start < min {\n\t\t\tstart = min\n\t\t\tadjusted = true\n\t\t}\n\t\tif max := len(nle.textUTF16()) - len(nle.suffix); end < 0 || end > max {\n\t\t\tend = max\n\t\t\tadjusted = true\n\t\t}\n\n\t\tif adjusted {\n\t\t\tnle.SetTextSelection(start, end)\n\t\t\treturn 0\n\t\t}\n\t}\n\n\treturn nle.LineEdit.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (nle *numberLineEdit) onFocusChanged() {\n\tif ne := windowFromHandle(win.GetParent(nle.hWnd)); ne != nil {\n\t\tif wnd := windowFromHandle(win.GetParent(ne.Handle())); wnd != nil {\n\t\t\tif _, ok := wnd.(Container); ok {\n\t\t\t\tne.(Widget).AsWidgetBase().invalidateBorderInParent()\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (ne *NumberEdit) SetToolTipText(s string) error {\n\treturn ne.edit.SetToolTipText(s)\n}\n"
  },
  {
    "path": "numberlabel.go",
    "content": "// Copyright 2018 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"strings\"\n)\n\ntype NumberLabel struct {\n\tstatic\n\tdecimals                 int\n\tdecimalsChangedPublisher EventPublisher\n\tsuffix                   string\n\tsuffixChangedPublisher   EventPublisher\n\tvalue                    float64\n\tvalueChangedPublisher    EventPublisher\n}\n\nfunc NewNumberLabel(parent Container) (*NumberLabel, error) {\n\tnl := new(NumberLabel)\n\n\tif err := nl.init(nl, parent, 0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tnl.SetTextAlignment(AlignFar)\n\tif _, err := nl.updateText(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tnl.MustRegisterProperty(\"Decimals\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn nl.Decimals()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn nl.SetDecimals(assertIntOr(v, 0))\n\t\t},\n\t\tnl.decimalsChangedPublisher.Event()))\n\n\tnl.MustRegisterProperty(\"Suffix\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn nl.Suffix()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn nl.SetSuffix(assertStringOr(v, \"\"))\n\t\t},\n\t\tnl.suffixChangedPublisher.Event()))\n\n\tnl.MustRegisterProperty(\"Value\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn nl.Value()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn nl.SetValue(assertFloat64Or(v, 0.0))\n\t\t},\n\t\tnl.valueChangedPublisher.Event()))\n\n\treturn nl, nil\n}\n\nfunc (nl *NumberLabel) asStatic() *static {\n\treturn &nl.static\n}\n\nfunc (nl *NumberLabel) TextAlignment() Alignment1D {\n\treturn nl.textAlignment1D()\n}\n\nfunc (nl *NumberLabel) SetTextAlignment(alignment Alignment1D) error {\n\tif alignment == AlignDefault {\n\t\talignment = AlignFar\n\t}\n\n\treturn nl.setTextAlignment1D(alignment)\n}\n\nfunc (nl *NumberLabel) Decimals() int {\n\treturn nl.decimals\n}\n\nfunc (nl *NumberLabel) SetDecimals(decimals int) error {\n\tif decimals == nl.decimals {\n\t\treturn nil\n\t}\n\n\told := nl.decimals\n\n\tnl.decimals = decimals\n\n\tif _, err := nl.updateText(); err != nil {\n\t\tnl.decimals = old\n\t\treturn err\n\t}\n\n\tnl.decimalsChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (nl *NumberLabel) Suffix() string {\n\treturn nl.suffix\n}\n\nfunc (nl *NumberLabel) SetSuffix(suffix string) error {\n\tif suffix == nl.suffix {\n\t\treturn nil\n\t}\n\n\told := nl.suffix\n\n\tnl.suffix = suffix\n\n\tif _, err := nl.updateText(); err != nil {\n\t\tnl.suffix = old\n\t\treturn err\n\t}\n\n\tnl.suffixChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (nl *NumberLabel) Value() float64 {\n\treturn nl.value\n}\n\nfunc (nl *NumberLabel) SetValue(value float64) error {\n\tif value == nl.value {\n\t\treturn nil\n\t}\n\n\told := nl.value\n\n\tnl.value = value\n\n\tif _, err := nl.updateText(); err != nil {\n\t\tnl.value = old\n\t\treturn err\n\t}\n\n\tnl.valueChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (nl *NumberLabel) updateText() (changed bool, err error) {\n\tvar sb strings.Builder\n\n\tsb.WriteString(FormatFloatGrouped(nl.value, nl.decimals))\n\n\tif nl.suffix != \"\" {\n\t\tsb.WriteString(nl.suffix)\n\t}\n\n\treturn nl.setText(sb.String())\n}\n"
  },
  {
    "path": "path.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\n\t\"github.com/lxn/win\"\n)\n\nfunc knownFolderPath(id win.CSIDL) (string, error) {\n\tvar buf [win.MAX_PATH]uint16\n\n\tif !win.SHGetSpecialFolderPath(0, &buf[0], id, false) {\n\t\treturn \"\", newError(\"SHGetSpecialFolderPath failed\")\n\t}\n\n\treturn syscall.UTF16ToString(buf[0:]), nil\n}\n\nfunc AppDataPath() (string, error) {\n\treturn knownFolderPath(win.CSIDL_APPDATA)\n}\n\nfunc CommonAppDataPath() (string, error) {\n\treturn knownFolderPath(win.CSIDL_COMMON_APPDATA)\n}\n\nfunc LocalAppDataPath() (string, error) {\n\treturn knownFolderPath(win.CSIDL_LOCAL_APPDATA)\n}\n\nfunc PersonalPath() (string, error) {\n\treturn knownFolderPath(win.CSIDL_PERSONAL)\n}\n\nfunc SystemPath() (string, error) {\n\treturn knownFolderPath(win.CSIDL_SYSTEM)\n}\n\nfunc DriveNames() ([]string, error) {\n\tbufLen := win.GetLogicalDriveStrings(0, nil)\n\tif bufLen == 0 {\n\t\treturn nil, lastError(\"GetLogicalDriveStrings\")\n\t}\n\tbuf := make([]uint16, bufLen+1)\n\n\tbufLen = win.GetLogicalDriveStrings(bufLen+1, &buf[0])\n\tif bufLen == 0 {\n\t\treturn nil, lastError(\"GetLogicalDriveStrings\")\n\t}\n\n\tvar names []string\n\n\tfor i := 0; i < len(buf)-2; {\n\t\tname := syscall.UTF16ToString(buf[i:])\n\t\tnames = append(names, name)\n\t\ti += len(name) + 1\n\t}\n\n\treturn names, nil\n}\n"
  },
  {
    "path": "pen.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype PenStyle int\n\n// Pen styles\nconst (\n\tPenSolid       PenStyle = win.PS_SOLID\n\tPenDash        PenStyle = win.PS_DASH\n\tPenDot         PenStyle = win.PS_DOT\n\tPenDashDot     PenStyle = win.PS_DASHDOT\n\tPenDashDotDot  PenStyle = win.PS_DASHDOTDOT\n\tPenNull        PenStyle = win.PS_NULL\n\tPenInsideFrame PenStyle = win.PS_INSIDEFRAME\n\tPenUserStyle   PenStyle = win.PS_USERSTYLE\n\tPenAlternate   PenStyle = win.PS_ALTERNATE\n)\n\n// Pen cap styles (geometric pens only)\nconst (\n\tPenCapRound  PenStyle = win.PS_ENDCAP_ROUND\n\tPenCapSquare PenStyle = win.PS_ENDCAP_SQUARE\n\tPenCapFlat   PenStyle = win.PS_ENDCAP_FLAT\n)\n\n// Pen join styles (geometric pens only)\nconst (\n\tPenJoinBevel PenStyle = win.PS_JOIN_BEVEL\n\tPenJoinMiter PenStyle = win.PS_JOIN_MITER\n\tPenJoinRound PenStyle = win.PS_JOIN_ROUND\n)\n\ntype Pen interface {\n\thandleForDPI(dpi int) win.HPEN\n\tDispose()\n\tStyle() PenStyle\n\n\t// Width returns pen width in 1/96\" units.\n\tWidth() int\n}\n\ntype nullPen struct {\n\thPen win.HPEN\n}\n\nfunc newNullPen() *nullPen {\n\tlb := &win.LOGBRUSH{LbStyle: win.BS_NULL}\n\n\thPen := win.ExtCreatePen(win.PS_COSMETIC|win.PS_NULL, 1, lb, 0, nil)\n\tif hPen == 0 {\n\t\tpanic(\"failed to create null brush\")\n\t}\n\n\treturn &nullPen{hPen: hPen}\n}\n\nfunc (p *nullPen) Dispose() {\n\tif p.hPen != 0 {\n\t\twin.DeleteObject(win.HGDIOBJ(p.hPen))\n\n\t\tp.hPen = 0\n\t}\n}\n\nfunc (p *nullPen) handleForDPI(dpi int) win.HPEN {\n\treturn p.hPen\n}\n\nfunc (p *nullPen) Style() PenStyle {\n\treturn PenNull\n}\n\nfunc (p *nullPen) Width() int {\n\treturn 0\n}\n\nvar nullPenSingleton Pen\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tnullPenSingleton = newNullPen()\n\t})\n}\n\nfunc NullPen() Pen {\n\treturn nullPenSingleton\n}\n\ntype CosmeticPen struct {\n\thPen  win.HPEN\n\tstyle PenStyle\n\tcolor Color\n}\n\nfunc NewCosmeticPen(style PenStyle, color Color) (*CosmeticPen, error) {\n\tlb := &win.LOGBRUSH{LbStyle: win.BS_SOLID, LbColor: win.COLORREF(color)}\n\n\tstyle |= win.PS_COSMETIC\n\n\thPen := win.ExtCreatePen(uint32(style), 1, lb, 0, nil)\n\tif hPen == 0 {\n\t\treturn nil, newError(\"ExtCreatePen failed\")\n\t}\n\n\treturn &CosmeticPen{hPen: hPen, style: style, color: color}, nil\n}\n\nfunc (p *CosmeticPen) Dispose() {\n\tif p.hPen != 0 {\n\t\twin.DeleteObject(win.HGDIOBJ(p.hPen))\n\n\t\tp.hPen = 0\n\t}\n}\n\nfunc (p *CosmeticPen) handleForDPI(dpi int) win.HPEN {\n\treturn p.hPen\n}\n\nfunc (p *CosmeticPen) Style() PenStyle {\n\treturn p.style\n}\n\nfunc (p *CosmeticPen) Color() Color {\n\treturn p.color\n}\n\nfunc (p *CosmeticPen) Width() int {\n\treturn 1\n}\n\ntype GeometricPen struct {\n\tdpi2hPen   map[int]win.HPEN\n\tstyle      PenStyle\n\tbrush      Brush\n\twidth96dpi int\n}\n\n// NewGeometricPen prepares new geometric pen. width parameter is specified in 1/96\" units.\nfunc NewGeometricPen(style PenStyle, width int, brush Brush) (*GeometricPen, error) {\n\tif brush == nil {\n\t\treturn nil, newError(\"brush cannot be nil\")\n\t}\n\n\tstyle |= win.PS_GEOMETRIC\n\n\treturn &GeometricPen{\n\t\tstyle:      style,\n\t\twidth96dpi: width,\n\t\tbrush:      brush,\n\t}, nil\n}\n\nfunc (p *GeometricPen) Dispose() {\n\tif len(p.dpi2hPen) == 0 {\n\t\treturn\n\t}\n\n\tfor dpi, hPen := range p.dpi2hPen {\n\t\twin.DeleteObject(win.HGDIOBJ(hPen))\n\t\tdelete(p.dpi2hPen, dpi)\n\t}\n}\n\nfunc (p *GeometricPen) handleForDPI(dpi int) win.HPEN {\n\thPen, _ := p.handleForDPIWithError(dpi)\n\treturn hPen\n}\n\nfunc (p *GeometricPen) handleForDPIWithError(dpi int) (win.HPEN, error) {\n\tif p.dpi2hPen == nil {\n\t\tp.dpi2hPen = make(map[int]win.HPEN)\n\t} else if handle, ok := p.dpi2hPen[dpi]; ok {\n\t\treturn handle, nil\n\t}\n\n\thPen := win.ExtCreatePen(\n\t\tuint32(p.style),\n\t\tuint32(IntFrom96DPI(p.width96dpi, dpi)),\n\t\tp.brush.logbrush(), 0, nil)\n\tif hPen == 0 {\n\t\treturn 0, newError(\"ExtCreatePen failed\")\n\t}\n\n\tp.dpi2hPen[dpi] = hPen\n\n\treturn hPen, nil\n}\n\nfunc (p *GeometricPen) Style() PenStyle {\n\treturn p.style\n}\n\n// Width returns pen width in 1/96\" units.\nfunc (p *GeometricPen) Width() int {\n\treturn p.width96dpi\n}\n\nfunc (p *GeometricPen) Brush() Brush {\n\treturn p.brush\n}\n"
  },
  {
    "path": "point.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport \"github.com/lxn/win\"\n\n// Point defines 2D coordinate in 1/96\" units ot native pixels.\ntype Point struct {\n\tX, Y int\n}\n\nfunc (p Point) toPOINT() win.POINT {\n\treturn win.POINT{\n\t\tX: int32(p.X),\n\t\tY: int32(p.Y),\n\t}\n}\n\nfunc pointPixelsFromPOINT(p win.POINT) Point {\n\treturn Point{\n\t\tX: int(p.X),\n\t\tY: int(p.Y),\n\t}\n}\n"
  },
  {
    "path": "progressbar.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype ProgressBar struct {\n\tWidgetBase\n}\n\nfunc NewProgressBar(parent Container) (*ProgressBar, error) {\n\tpb := new(ProgressBar)\n\n\tif err := InitWidget(\n\t\tpb,\n\t\tparent,\n\t\t\"msctls_progress32\",\n\t\twin.WS_VISIBLE,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn pb, nil\n}\n\nfunc (pb *ProgressBar) MinValue() int {\n\treturn int(pb.SendMessage(win.PBM_GETRANGE, 1, 0))\n}\n\nfunc (pb *ProgressBar) MaxValue() int {\n\treturn int(pb.SendMessage(win.PBM_GETRANGE, 0, 0))\n}\n\nfunc (pb *ProgressBar) SetRange(min, max int) {\n\tpb.SendMessage(win.PBM_SETRANGE32, uintptr(min), uintptr(max))\n}\n\nfunc (pb *ProgressBar) Value() int {\n\treturn int(pb.SendMessage(win.PBM_GETPOS, 0, 0))\n}\n\nfunc (pb *ProgressBar) SetValue(value int) {\n\tpb.SendMessage(win.PBM_SETPOS, uintptr(value), 0)\n}\n\nfunc (pb *ProgressBar) MarqueeMode() bool {\n\treturn pb.hasStyleBits(win.PBS_MARQUEE)\n}\n\nfunc (pb *ProgressBar) SetMarqueeMode(marqueeMode bool) error {\n\tif err := pb.ensureStyleBits(win.PBS_MARQUEE, marqueeMode); err != nil {\n\t\treturn err\n\t}\n\n\tpb.SendMessage(win.PBM_SETMARQUEE, uintptr(win.BoolToBOOL(marqueeMode)), 0)\n\n\treturn nil\n}\n\nfunc (pb *ProgressBar) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn &progressBarLayoutItem{\n\t\tidealSize: pb.dialogBaseUnitsToPixels(Size{50, 14}),\n\t\tminSize:   pb.dialogBaseUnitsToPixels(Size{10, 14}),\n\t}\n}\n\ntype progressBarLayoutItem struct {\n\tLayoutItemBase\n\tidealSize Size // in native pixels\n\tminSize   Size // in native pixels\n}\n\nfunc (*progressBarLayoutItem) LayoutFlags() LayoutFlags {\n\treturn ShrinkableHorz | GrowableHorz | GreedyHorz\n}\n\nfunc (li *progressBarLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *progressBarLayoutItem) MinSize() Size {\n\treturn li.minSize\n}\n"
  },
  {
    "path": "progressindicator.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n\t\"syscall\"\n)\n\ntype ProgressIndicator struct {\n\thwnd                   win.HWND\n\ttaskbarList3           *win.ITaskbarList3\n\tcompleted              uint32\n\ttotal                  uint32\n\tstate                  PIState\n\toverlayIcon            *Icon\n\toverlayIconDescription string\n}\n\ntype PIState int\n\nconst (\n\tPINoProgress    PIState = win.TBPF_NOPROGRESS\n\tPIIndeterminate PIState = win.TBPF_INDETERMINATE\n\tPINormal        PIState = win.TBPF_NORMAL\n\tPIError         PIState = win.TBPF_ERROR\n\tPIPaused        PIState = win.TBPF_PAUSED\n)\n\n//newTaskbarList3 precondition: Windows version is at least 6.1 (yes, Win 7 is version 6.1).\nfunc newTaskbarList3(hwnd win.HWND) (*ProgressIndicator, error) {\n\tvar classFactoryPtr unsafe.Pointer\n\tif hr := win.CoGetClassObject(&win.CLSID_TaskbarList, win.CLSCTX_ALL, nil, &win.IID_IClassFactory, &classFactoryPtr); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"CoGetClassObject\", hr)\n\t}\n\n\tvar taskbarList3ObjectPtr unsafe.Pointer\n\tclassFactory := (*win.IClassFactory)(classFactoryPtr)\n\tdefer classFactory.Release()\n\n\tif hr := classFactory.CreateInstance(nil, &win.IID_ITaskbarList3, &taskbarList3ObjectPtr); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"IClassFactory.CreateInstance\", hr)\n\t}\n\n\treturn &ProgressIndicator{taskbarList3: (*win.ITaskbarList3)(taskbarList3ObjectPtr), hwnd: hwnd}, nil\n}\n\nfunc (pi *ProgressIndicator) SetState(state PIState) error {\n\tif hr := pi.taskbarList3.SetProgressState(pi.hwnd, (int)(state)); win.FAILED(hr) {\n\t\treturn errorFromHRESULT(\"ITaskbarList3.setprogressState\", hr)\n\t}\n\tpi.state = state\n\treturn nil\n}\n\nfunc (pi *ProgressIndicator) State() PIState {\n\treturn pi.state\n}\n\nfunc (pi *ProgressIndicator) SetTotal(total uint32) {\n\tpi.total = total\n}\n\nfunc (pi *ProgressIndicator) Total() uint32 {\n\treturn pi.total\n}\n\nfunc (pi *ProgressIndicator) SetCompleted(completed uint32) error {\n\tif hr := pi.taskbarList3.SetProgressValue(pi.hwnd, completed, pi.total); win.FAILED(hr) {\n\t\treturn errorFromHRESULT(\"ITaskbarList3.SetProgressValue\", hr)\n\t}\n\tpi.completed = completed\n\treturn nil\n}\n\nfunc (pi *ProgressIndicator) Completed() uint32 {\n\treturn pi.completed\n}\n\nfunc (pi *ProgressIndicator) SetOverlayIcon(icon *Icon, description string) error {\n\thandle := win.HICON(0)\n\tif icon != nil {\n\t\thandle = icon.handleForDPI(int(win.GetDpiForWindow(pi.hwnd)))\n\t}\n\tdescription16, err := syscall.UTF16PtrFromString(description)\n\tif err != nil {\n\t\tdescription16 = &[]uint16{0}[0]\n\t}\n\tif hr := pi.taskbarList3.SetOverlayIcon(pi.hwnd, handle, description16); win.FAILED(hr) {\n\t\treturn errorFromHRESULT(\"ITaskbarList3.SetOverlayIcon\", hr)\n\t}\n\tpi.overlayIcon = icon\n\tpi.overlayIconDescription = description\n\treturn nil\n}\n"
  },
  {
    "path": "property.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nvar (\n\tErrPropertyReadOnly       = errors.New(\"read-only property\")\n\tErrPropertyNotValidatable = errors.New(\"property not validatable\")\n)\n\ntype Property interface {\n\tExpression\n\tReadOnly() bool\n\tGet() interface{}\n\tSet(value interface{}) error\n\tSource() interface{}\n\tSetSource(source interface{}) error\n\tValidatable() bool\n\tValidator() Validator\n\tSetValidator(validator Validator) error\n}\n\ntype property struct {\n\tget                 func() interface{}\n\tset                 func(v interface{}) error\n\tchanged             *Event\n\tsource              interface{}\n\tsourceChangedHandle int\n\tvalidator           Validator\n}\n\nfunc NewProperty(get func() interface{}, set func(v interface{}) error, changed *Event) Property {\n\treturn &property{get: get, set: set, changed: changed}\n}\n\nfunc (p *property) ReadOnly() bool {\n\treturn p.set == nil\n}\n\nfunc (p *property) Value() interface{} {\n\treturn p.get()\n}\n\nfunc (p *property) Get() interface{} {\n\treturn p.get()\n}\n\nfunc (p *property) Set(value interface{}) error {\n\tif p.ReadOnly() {\n\t\treturn ErrPropertyReadOnly\n\t}\n\n\tif oldValue := p.get(); value == oldValue {\n\t\treturn nil\n\t}\n\n\treturn p.set(value)\n}\n\nfunc (p *property) Changed() *Event {\n\treturn p.changed\n}\n\nfunc (p *property) Source() interface{} {\n\treturn p.source\n}\n\nfunc (p *property) SetSource(source interface{}) error {\n\tif p.ReadOnly() {\n\t\treturn ErrPropertyReadOnly\n\t}\n\n\tif source != nil {\n\t\tswitch source := source.(type) {\n\t\tcase string:\n\t\t\t// nop\n\n\t\tcase Property:\n\t\t\tif err := checkPropertySource(p, source); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif source != nil {\n\t\t\t\tp.Set(source.Get())\n\n\t\t\t\tp.sourceChangedHandle = source.Changed().Attach(func() {\n\t\t\t\t\tp.Set(source.Get())\n\t\t\t\t})\n\t\t\t}\n\n\t\tcase Expression:\n\t\t\tp.Set(source.Value())\n\n\t\t\tp.sourceChangedHandle = source.Changed().Attach(func() {\n\t\t\t\tp.Set(source.Value())\n\t\t\t})\n\n\t\tdefault:\n\t\t\treturn newError(\"invalid source type\")\n\t\t}\n\t}\n\n\tif oldProp, ok := p.source.(Property); ok {\n\t\toldProp.Changed().Detach(p.sourceChangedHandle)\n\t}\n\n\tp.source = source\n\n\treturn nil\n}\n\nfunc (p *property) Validatable() bool {\n\treturn true\n}\n\nfunc (p *property) Validator() Validator {\n\treturn p.validator\n}\n\nfunc (p *property) SetValidator(validator Validator) error {\n\tif p.ReadOnly() {\n\t\treturn ErrPropertyReadOnly\n\t}\n\n\tp.validator = validator\n\n\treturn nil\n}\n\ntype readOnlyProperty struct {\n\tget     func() interface{}\n\tchanged *Event\n}\n\nfunc NewReadOnlyProperty(get func() interface{}, changed *Event) Property {\n\treturn &readOnlyProperty{get: get, changed: changed}\n}\n\nfunc (*readOnlyProperty) ReadOnly() bool {\n\treturn true\n}\n\nfunc (rop *readOnlyProperty) Value() interface{} {\n\treturn rop.get()\n}\n\nfunc (rop *readOnlyProperty) Get() interface{} {\n\treturn rop.get()\n}\n\nfunc (*readOnlyProperty) Set(value interface{}) error {\n\treturn ErrPropertyReadOnly\n}\n\nfunc (rop *readOnlyProperty) Changed() *Event {\n\treturn rop.changed\n}\n\nfunc (*readOnlyProperty) Source() interface{} {\n\treturn nil\n}\n\nfunc (*readOnlyProperty) SetSource(source interface{}) error {\n\treturn ErrPropertyReadOnly\n}\n\nfunc (*readOnlyProperty) Validatable() bool {\n\treturn false\n}\n\nfunc (*readOnlyProperty) Validator() Validator {\n\treturn nil\n}\n\nfunc (*readOnlyProperty) SetValidator(validator Validator) error {\n\treturn ErrPropertyReadOnly\n}\n\ntype boolProperty struct {\n\tget                 func() bool\n\tset                 func(v bool) error\n\tchanged             *Event\n\tsource              interface{}\n\tsourceChangedHandle int\n}\n\nfunc NewBoolProperty(get func() bool, set func(b bool) error, changed *Event) Property {\n\treturn &boolProperty{get: get, set: set, changed: changed}\n}\n\nfunc (bp *boolProperty) ReadOnly() bool {\n\treturn bp.set == nil\n}\n\nfunc (bp *boolProperty) Value() interface{} {\n\treturn bp.get()\n}\n\nfunc (bp *boolProperty) Get() interface{} {\n\treturn bp.get()\n}\n\nfunc (bp *boolProperty) Set(value interface{}) error {\n\tif bp.ReadOnly() {\n\t\treturn ErrPropertyReadOnly\n\t}\n\n\t/* FIXME: Visible property doesn't like this.\n\tif oldValue := bp.get(); value == oldValue {\n\t\treturn nil\n\t}*/\n\n\treturn bp.set(value.(bool))\n}\n\nfunc (bp *boolProperty) Changed() *Event {\n\treturn bp.changed\n}\n\nfunc (bp *boolProperty) Source() interface{} {\n\treturn bp.source\n}\n\nfunc (bp *boolProperty) SetSource(source interface{}) error {\n\tif bp.ReadOnly() {\n\t\treturn ErrPropertyReadOnly\n\t}\n\n\tif source != nil {\n\t\tswitch source := source.(type) {\n\t\tcase string:\n\t\t\t// nop\n\n\t\tcase Condition:\n\t\t\tif err := checkPropertySource(bp, source); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := bp.Set(source.Satisfied()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tbp.sourceChangedHandle = source.Changed().Attach(func() {\n\t\t\t\tbp.Set(source.Satisfied())\n\t\t\t})\n\n\t\tcase Expression:\n\t\t\tif err := checkPropertySource(bp, source); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif satisfied, ok := source.Value().(bool); ok {\n\t\t\t\tif err := bp.Set(satisfied); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbp.sourceChangedHandle = source.Changed().Attach(func() {\n\t\t\t\tif satisfied, ok := source.Value().(bool); ok {\n\t\t\t\t\tbp.Set(satisfied)\n\t\t\t\t}\n\t\t\t})\n\n\t\tdefault:\n\t\t\treturn newError(fmt.Sprintf(`invalid source: \"%s\" of type %T`, source, source))\n\t\t}\n\t}\n\n\tif oldCond, ok := bp.source.(Condition); ok {\n\t\toldCond.Changed().Detach(bp.sourceChangedHandle)\n\t}\n\n\tbp.source = source\n\n\treturn nil\n}\n\nfunc (bp *boolProperty) Validatable() bool {\n\treturn false\n}\n\nfunc (*boolProperty) Validator() Validator {\n\treturn nil\n}\n\nfunc (*boolProperty) SetValidator(validator Validator) error {\n\treturn ErrPropertyNotValidatable\n}\n\nfunc (bp *boolProperty) Satisfied() bool {\n\treturn bp.get()\n}\n\ntype readOnlyBoolProperty struct {\n\tget     func() bool\n\tchanged *Event\n}\n\nfunc NewReadOnlyBoolProperty(get func() bool, changed *Event) Property {\n\treturn &readOnlyBoolProperty{get: get, changed: changed}\n}\n\nfunc (*readOnlyBoolProperty) ReadOnly() bool {\n\treturn true\n}\n\nfunc (robp *readOnlyBoolProperty) Value() interface{} {\n\treturn robp.get()\n}\n\nfunc (robp *readOnlyBoolProperty) Get() interface{} {\n\treturn robp.get()\n}\n\nfunc (*readOnlyBoolProperty) Set(value interface{}) error {\n\treturn ErrPropertyReadOnly\n}\n\nfunc (robp *readOnlyBoolProperty) Changed() *Event {\n\treturn robp.changed\n}\n\nfunc (*readOnlyBoolProperty) Source() interface{} {\n\treturn nil\n}\n\nfunc (*readOnlyBoolProperty) SetSource(source interface{}) error {\n\treturn ErrPropertyReadOnly\n}\n\nfunc (*readOnlyBoolProperty) Validatable() bool {\n\treturn false\n}\n\nfunc (*readOnlyBoolProperty) Validator() Validator {\n\treturn nil\n}\n\nfunc (*readOnlyBoolProperty) SetValidator(validator Validator) error {\n\treturn ErrPropertyNotValidatable\n}\n\nfunc (robp *readOnlyBoolProperty) Satisfied() bool {\n\treturn robp.get()\n}\n\nfunc checkPropertySource(prop Property, source interface{}) error {\n\tswitch source := source.(type) {\n\tcase Property:\n\t\tfor cur := source; cur != nil; cur, _ = cur.Source().(Property) {\n\t\t\tif cur == prop {\n\t\t\t\treturn newError(\"source cycle\")\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pushbutton.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype PushButton struct {\n\tButton\n}\n\nfunc NewPushButton(parent Container) (*PushButton, error) {\n\tpb := new(PushButton)\n\n\tif err := InitWidget(\n\t\tpb,\n\t\tparent,\n\t\t\"BUTTON\",\n\t\twin.WS_TABSTOP|win.WS_VISIBLE|win.BS_PUSHBUTTON,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tpb.Button.init()\n\n\tpb.GraphicsEffects().Add(InteractionEffect)\n\tpb.GraphicsEffects().Add(FocusEffect)\n\n\treturn pb, nil\n}\n\nfunc (pb *PushButton) ImageAboveText() bool {\n\treturn pb.hasStyleBits(win.BS_TOP)\n}\n\nfunc (pb *PushButton) SetImageAboveText(value bool) error {\n\tif err := pb.ensureStyleBits(win.BS_TOP, value); err != nil {\n\t\treturn err\n\t}\n\n\t// We need to set the image again, or Windows will fail to calculate the\n\t// button control size correctly.\n\treturn pb.SetImage(pb.image)\n}\n\nfunc (pb *PushButton) ensureProperDialogDefaultButton(hwndFocus win.HWND) {\n\twidget := windowFromHandle(hwndFocus)\n\tif widget == nil {\n\t\treturn\n\t}\n\n\tif _, ok := widget.(*PushButton); ok {\n\t\treturn\n\t}\n\n\tform := ancestor(pb)\n\tif form == nil {\n\t\treturn\n\t}\n\n\tdlg, ok := form.(dialogish)\n\tif !ok {\n\t\treturn\n\t}\n\n\tdefBtn := dlg.DefaultButton()\n\tif defBtn == nil {\n\t\treturn\n\t}\n\n\tif err := defBtn.setAndClearStyleBits(win.BS_DEFPUSHBUTTON, win.BS_PUSHBUTTON); err != nil {\n\t\treturn\n\t}\n\n\tif err := defBtn.Invalidate(); err != nil {\n\t\treturn\n\t}\n}\n\nfunc (pb *PushButton) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_GETDLGCODE:\n\t\thwndFocus := win.GetFocus()\n\t\tif hwndFocus == pb.hWnd {\n\t\t\tform := ancestor(pb)\n\t\t\tif form == nil {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tdlg, ok := form.(dialogish)\n\t\t\tif !ok {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tdefBtn := dlg.DefaultButton()\n\t\t\tif defBtn == pb {\n\t\t\t\tpb.setAndClearStyleBits(win.BS_DEFPUSHBUTTON, win.BS_PUSHBUTTON)\n\t\t\t\treturn win.DLGC_BUTTON | win.DLGC_DEFPUSHBUTTON\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\n\t\tpb.ensureProperDialogDefaultButton(hwndFocus)\n\n\tcase win.WM_KILLFOCUS:\n\t\tpb.ensureProperDialogDefaultButton(win.HWND(wParam))\n\t}\n\n\treturn pb.Button.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (pb *PushButton) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn &pushButtonLayoutItem{\n\t\tbuttonLayoutItem: buttonLayoutItem{\n\t\t\tidealSize: pb.idealSize(),\n\t\t},\n\t}\n}\n\ntype pushButtonLayoutItem struct {\n\tbuttonLayoutItem\n}\n\nfunc (*pushButtonLayoutItem) LayoutFlags() LayoutFlags {\n\treturn GrowableHorz\n}\n"
  },
  {
    "path": "radiobutton.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype RadioButtonGroup struct {\n\tbuttons       []*RadioButton\n\tcheckedButton *RadioButton\n}\n\nfunc (rbg *RadioButtonGroup) Buttons() []*RadioButton {\n\tbuttons := make([]*RadioButton, len(rbg.buttons))\n\tcopy(buttons, rbg.buttons)\n\treturn buttons\n}\n\nfunc (rbg *RadioButtonGroup) CheckedButton() *RadioButton {\n\treturn rbg.checkedButton\n}\n\ntype radioButtonish interface {\n\tradioButton() *RadioButton\n}\n\ntype RadioButton struct {\n\tButton\n\tgroup *RadioButtonGroup\n\tvalue interface{}\n}\n\nfunc NewRadioButton(parent Container) (*RadioButton, error) {\n\trb := new(RadioButton)\n\n\tif count := parent.Children().Len(); count > 0 {\n\t\tif prevRB, ok := parent.Children().At(count - 1).(radioButtonish); ok {\n\t\t\trb.group = prevRB.radioButton().group\n\t\t}\n\t}\n\tvar groupBit uint32\n\tif rb.group == nil {\n\t\tgroupBit = win.WS_GROUP\n\t\trb.group = new(RadioButtonGroup)\n\t}\n\n\tif err := InitWidget(\n\t\trb,\n\t\tparent,\n\t\t\"BUTTON\",\n\t\tgroupBit|win.WS_TABSTOP|win.WS_VISIBLE|win.BS_AUTORADIOBUTTON,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\trb.Button.init()\n\n\trb.SetBackground(nullBrushSingleton)\n\n\trb.GraphicsEffects().Add(InteractionEffect)\n\trb.GraphicsEffects().Add(FocusEffect)\n\n\trb.MustRegisterProperty(\"CheckedValue\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\tif rb.Checked() {\n\t\t\t\treturn rb.value\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\tchecked := v == rb.value\n\t\t\tif checked {\n\t\t\t\trb.group.checkedButton = rb\n\t\t\t}\n\t\t\trb.SetChecked(checked)\n\n\t\t\treturn nil\n\t\t},\n\t\trb.CheckedChanged()))\n\n\trb.group.buttons = append(rb.group.buttons, rb)\n\n\treturn rb, nil\n}\n\nfunc (rb *RadioButton) radioButton() *RadioButton {\n\treturn rb\n}\n\nfunc (rb *RadioButton) TextOnLeftSide() bool {\n\treturn rb.hasStyleBits(win.BS_LEFTTEXT)\n}\n\nfunc (rb *RadioButton) SetTextOnLeftSide(textLeft bool) error {\n\treturn rb.ensureStyleBits(win.BS_LEFTTEXT, textLeft)\n}\n\nfunc (rb *RadioButton) Group() *RadioButtonGroup {\n\treturn rb.group\n}\n\nfunc (rb *RadioButton) Value() interface{} {\n\treturn rb.value\n}\n\nfunc (rb *RadioButton) SetValue(value interface{}) {\n\trb.value = value\n}\n\nfunc (rb *RadioButton) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_COMMAND:\n\t\tswitch win.HIWORD(uint32(wParam)) {\n\t\tcase win.BN_CLICKED:\n\t\t\tprevChecked := rb.group.checkedButton\n\t\t\trb.group.checkedButton = rb\n\n\t\t\tif prevChecked != rb {\n\t\t\t\tif prevChecked != nil {\n\t\t\t\t\tprevChecked.setChecked(false)\n\t\t\t\t}\n\n\t\t\t\trb.setChecked(true)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn rb.Button.WndProc(hwnd, msg, wParam, lParam)\n}\n"
  },
  {
    "path": "rectangle.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\n// Rectangle defines upper left corner with width and height region in 1/96\" units, or native\n// pixels, or grid rows and columns.\ntype Rectangle struct {\n\tX, Y, Width, Height int\n}\n\nfunc (r Rectangle) IsZero() bool {\n\treturn r.X == 0 && r.Y == 0 && r.Width == 0 && r.Height == 0\n}\n\nfunc rectangleFromRECT(r win.RECT) Rectangle {\n\treturn Rectangle{\n\t\tX:      int(r.Left),\n\t\tY:      int(r.Top),\n\t\tWidth:  int(r.Right - r.Left),\n\t\tHeight: int(r.Bottom - r.Top),\n\t}\n}\n\nfunc (r Rectangle) Left() int {\n\treturn r.X\n}\n\nfunc (r Rectangle) Top() int {\n\treturn r.Y\n}\n\nfunc (r Rectangle) Right() int {\n\treturn r.X + r.Width - 1\n}\n\nfunc (r Rectangle) Bottom() int {\n\treturn r.Y + r.Height - 1\n}\n\nfunc (r Rectangle) Location() Point {\n\treturn Point{r.X, r.Y}\n}\n\nfunc (r *Rectangle) SetLocation(p Point) Rectangle {\n\tr.X = p.X\n\tr.Y = p.Y\n\n\treturn *r\n}\n\nfunc (r Rectangle) Size() Size {\n\treturn Size{r.Width, r.Height}\n}\n\nfunc (r *Rectangle) SetSize(s Size) Rectangle {\n\tr.Width = s.Width\n\tr.Height = s.Height\n\n\treturn *r\n}\n\nfunc (r Rectangle) toRECT() win.RECT {\n\treturn win.RECT{\n\t\tint32(r.X),\n\t\tint32(r.Y),\n\t\tint32(r.X + r.Width),\n\t\tint32(r.Y + r.Height),\n\t}\n}\n"
  },
  {
    "path": "reflectmodels.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"sort\"\n)\n\ntype reflectModel interface {\n\tItems() interface{}\n}\n\ntype bindingAndDisplayMemberSetter interface {\n\tsetBindingMember(member string)\n\tsetDisplayMember(member string)\n}\n\ntype reflectListModel struct {\n\tListModelBase\n\tbindingMember string\n\tdisplayMember string\n\tdataSource    interface{}\n\titems         interface{}\n\tvalue         reflect.Value\n}\n\nfunc newReflectListModel(dataSource interface{}) (ListModel, error) {\n\titems, err := itemsFromReflectModelDataSource(dataSource, \"ReflectListModel\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tm := &reflectListModel{\n\t\tdataSource: dataSource,\n\t\titems:      items,\n\t\tvalue:      reflect.ValueOf(items),\n\t}\n\n\tif rlm, ok := dataSource.(ReflectListModel); ok {\n\t\trlm.setValueFunc(func(index int) interface{} {\n\t\t\treturn m.Value(index)\n\t\t})\n\n\t\trlm.ItemChanged().Attach(func(index int) {\n\t\t\tm.PublishItemChanged(index)\n\t\t})\n\n\t\trlm.ItemsReset().Attach(func() {\n\t\t\tm.items = rlm.Items()\n\t\t\tm.value = reflect.ValueOf(m.items)\n\n\t\t\tm.PublishItemsReset()\n\t\t})\n\n\t\trlm.ItemsInserted().Attach(func(from, to int) {\n\t\t\tm.items = rlm.Items()\n\t\t\tm.value = reflect.ValueOf(m.items)\n\n\t\t\tm.PublishItemsInserted(from, to)\n\t\t})\n\n\t\trlm.ItemsRemoved().Attach(func(from, to int) {\n\t\t\tm.items = rlm.Items()\n\t\t\tm.value = reflect.ValueOf(m.items)\n\n\t\t\tm.PublishItemsRemoved(from, to)\n\t\t})\n\t}\n\n\treturn m, nil\n}\n\nfunc (m *reflectListModel) setBindingMember(member string) {\n\tm.bindingMember = member\n}\n\nfunc (m *reflectListModel) setDisplayMember(member string) {\n\tm.displayMember = member\n}\n\nfunc (m *reflectListModel) ItemCount() int {\n\treturn m.value.Len()\n}\n\nfunc (m *reflectListModel) BindingValue(index int) interface{} {\n\treturn valueFromSlice(m.dataSource, m.value, m.bindingMember, index)\n}\n\nfunc (m *reflectListModel) Value(index int) interface{} {\n\treturn valueFromSlice(m.dataSource, m.value, m.displayMember, index)\n}\n\ntype lessFuncsSetter interface {\n\tsetLessFuncs(lessFuncs []func(i, j int) bool)\n}\n\ntype dataMembersSetter interface {\n\tsetDataMembers(dataMembers []string)\n}\n\ntype reflectTableModel struct {\n\tTableModelBase\n\tsorterBase  *SorterBase\n\tlessFuncs   []func(i, j int) bool\n\tdataMembers []string\n\tdataSource  interface{}\n\titems       interface{}\n\tvalue       reflect.Value\n}\n\nfunc newReflectTableModel(dataSource interface{}) (TableModel, error) {\n\titems, err := itemsFromReflectModelDataSource(dataSource, \"ReflectTableModel\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tm := &reflectTableModel{\n\t\tdataSource: dataSource,\n\t\titems:      items,\n\t\tvalue:      reflect.ValueOf(items),\n\t}\n\n\tif rtm, ok := dataSource.(ReflectTableModel); ok {\n\t\trtm.setValueFunc(func(row, col int) interface{} {\n\t\t\treturn m.Value(row, col)\n\t\t})\n\n\t\trtm.RowChanged().Attach(func(index int) {\n\t\t\tm.PublishRowChanged(index)\n\t\t})\n\n\t\trtm.RowsReset().Attach(func() {\n\t\t\tm.items = rtm.Items()\n\t\t\tm.value = reflect.ValueOf(m.items)\n\n\t\t\tm.PublishRowsReset()\n\n\t\t\tif is, ok := dataSource.(interceptedSorter); ok {\n\t\t\t\tsb := is.sorterBase()\n\t\t\t\tm.sort(sb.SortedColumn(), sb.SortOrder())\n\t\t\t}\n\t\t})\n\n\t\trtm.RowsChanged().Attach(func(from, to int) {\n\t\t\tm.PublishRowsChanged(from, to)\n\t\t})\n\n\t\trtm.RowsInserted().Attach(func(from, to int) {\n\t\t\tm.items = rtm.Items()\n\t\t\tm.value = reflect.ValueOf(m.items)\n\n\t\t\tm.PublishRowsInserted(from, to)\n\t\t})\n\n\t\trtm.RowsRemoved().Attach(func(from, to int) {\n\t\t\tm.items = rtm.Items()\n\t\t\tm.value = reflect.ValueOf(m.items)\n\n\t\t\tm.PublishRowsRemoved(from, to)\n\t\t})\n\t} else {\n\t\tm.sorterBase = new(SorterBase)\n\t}\n\n\tif is, ok := dataSource.(interceptedSorter); ok {\n\t\tm.sorterBase = is.sorterBase()\n\t\tis.setSortFunc(func(col int, order SortOrder) error {\n\t\t\treturn m.sort(col, order)\n\t\t})\n\t}\n\n\t_, isImageProvider := dataSource.(ImageProvider)\n\t_, isSortable := dataSource.(Sorter)\n\tif !isSortable {\n\t\tisSortable = m.sorterBase != nil\n\t}\n\tif isImageProvider {\n\t\tif isSortable {\n\t\t\treturn &sortedImageReflectTableModel{reflectTableModel: m}, nil\n\t\t} else {\n\t\t\treturn &imageReflectTableModel{reflectTableModel: m}, nil\n\t\t}\n\t} else if isSortable {\n\t\treturn &sortedReflectTableModel{reflectTableModel: m}, nil\n\t}\n\n\treturn m, nil\n}\n\nfunc (m *reflectTableModel) setLessFuncs(lessFuncs []func(i, j int) bool) {\n\tm.lessFuncs = lessFuncs\n}\n\nfunc (m *reflectTableModel) setDataMembers(dataMembers []string) {\n\tm.dataMembers = dataMembers\n}\n\nfunc (m *reflectTableModel) RowCount() int {\n\treturn m.value.Len()\n}\n\nfunc (m *reflectTableModel) Value(row, col int) interface{} {\n\treturn valueFromSlice(m.dataSource, m.value, m.dataMembers[col], row)\n}\n\nfunc (m *reflectTableModel) Checked(row int) bool {\n\tif m.value.Index(row).IsNil() {\n\t\treturn false\n\t}\n\n\tif checker, ok := m.dataSource.(ItemChecker); ok {\n\t\treturn checker.Checked(row)\n\t}\n\n\treturn false\n}\n\nfunc (m *reflectTableModel) SetChecked(row int, checked bool) error {\n\tif m.value.Index(row).IsNil() {\n\t\treturn nil\n\t}\n\n\tif checker, ok := m.dataSource.(ItemChecker); ok {\n\t\treturn checker.SetChecked(row, checked)\n\t}\n\n\treturn nil\n}\n\nfunc (m *reflectTableModel) ColumnSortable(col int) bool {\n\tif sorter, ok := m.dataSource.(Sorter); ok {\n\t\treturn sorter.ColumnSortable(col)\n\t}\n\n\treturn true\n}\n\nfunc (m *reflectTableModel) SortChanged() *Event {\n\tif sorter, ok := m.dataSource.(Sorter); ok {\n\t\treturn sorter.SortChanged()\n\t}\n\n\tif m.sorterBase != nil {\n\t\treturn m.sorterBase.SortChanged()\n\t}\n\n\treturn nil\n}\n\nfunc (m *reflectTableModel) SortedColumn() int {\n\tif sorter, ok := m.dataSource.(Sorter); ok {\n\t\treturn sorter.SortedColumn()\n\t}\n\n\tif m.sorterBase != nil {\n\t\treturn m.sorterBase.SortedColumn()\n\t}\n\n\treturn -1\n}\n\nfunc (m *reflectTableModel) SortOrder() SortOrder {\n\tif sorter, ok := m.dataSource.(Sorter); ok {\n\t\treturn sorter.SortOrder()\n\t}\n\n\tif m.sorterBase != nil {\n\t\treturn m.sorterBase.SortOrder()\n\t}\n\n\treturn SortAscending\n}\n\nfunc (m *reflectTableModel) sort(col int, order SortOrder) error {\n\tif sb := m.sorterBase; sb != nil {\n\t\tsb.col, sb.order = col, order\n\n\t\tsort.Stable(m)\n\n\t\tsb.changedPublisher.Publish()\n\n\t\treturn nil\n\t}\n\n\tif sorter, ok := m.dataSource.(Sorter); ok {\n\t\treturn sorter.Sort(col, order)\n\t}\n\n\treturn nil\n}\n\nfunc (m *reflectTableModel) Len() int {\n\treturn m.RowCount()\n}\n\nfunc (m *reflectTableModel) Less(i, j int) bool {\n\tcol := m.SortedColumn()\n\n\tif lt := m.lessFuncs[col]; lt != nil {\n\t\tls := lt(i, j)\n\n\t\tif m.SortOrder() == SortAscending {\n\t\t\treturn ls\n\t\t} else {\n\t\t\treturn !ls\n\t\t}\n\t}\n\n\treturn less(m.Value(i, col), m.Value(j, col), m.SortOrder())\n}\n\nfunc (m *reflectTableModel) Swap(i, j int) {\n\tvi := m.value.Index(i)\n\tvj := m.value.Index(j)\n\n\tviv := vi.Interface()\n\tvjv := vj.Interface()\n\n\tvi.Set(reflect.ValueOf(vjv))\n\tvj.Set(reflect.ValueOf(viv))\n}\n\ntype imageReflectTableModel struct {\n\t*reflectTableModel\n}\n\nfunc (m *imageReflectTableModel) Image(index int) interface{} {\n\tif m.value.Index(index).IsNil() {\n\t\treturn nil\n\t}\n\n\treturn m.dataSource.(ImageProvider).Image(index)\n}\n\ntype sortedReflectTableModel struct {\n\t*reflectTableModel\n}\n\nfunc (m *sortedReflectTableModel) Sort(col int, order SortOrder) error {\n\treturn m.reflectTableModel.sort(col, order)\n}\n\ntype sortedImageReflectTableModel struct {\n\t*reflectTableModel\n}\n\nfunc (m *sortedImageReflectTableModel) Sort(col int, order SortOrder) error {\n\treturn m.reflectTableModel.sort(col, order)\n}\n\nfunc (m *sortedImageReflectTableModel) Image(index int) interface{} {\n\tif m.value.Index(index).IsNil() {\n\t\treturn nil\n\t}\n\n\treturn m.dataSource.(ImageProvider).Image(index)\n}\n\nfunc itemsFromReflectModelDataSource(dataSource interface{}, requiredInterfaceName string) (interface{}, error) {\n\tvar items interface{}\n\tif rm, ok := dataSource.(reflectModel); ok {\n\t\titems = rm.Items()\n\t} else {\n\t\titems = dataSource\n\t}\n\n\tif requiredInterfaceName == \"ReflectListModel\" {\n\t\tif _, ok := dataSource.([]string); ok {\n\t\t\treturn items, nil\n\t\t}\n\t}\n\n\tif t := reflect.TypeOf(items); t != nil &&\n\t\tt.Kind() == reflect.Slice &&\n\t\t(t.Elem().Kind() == reflect.Struct ||\n\t\t\t(t.Elem().Kind() == reflect.Interface || t.Elem().Kind() == reflect.Ptr) &&\n\t\t\t\tt.Elem().Elem().Kind() == reflect.Struct) {\n\n\t\treturn items, nil\n\t}\n\n\treturn nil, newError(fmt.Sprintf(\"dataSource must be a slice of struct or interface or pointer to struct or must implement %s.\", requiredInterfaceName))\n}\n\nfunc valueFromSlice(dataSource interface{}, itemsValue reflect.Value, member string, index int) interface{} {\n\tif member == \"\" {\n\t\tif strs, ok := dataSource.([]string); ok {\n\t\t\treturn strs[index]\n\t\t}\n\n\t\treturn \"\"\n\t}\n\n\tv := itemsValue.Index(index)\n\n\tif v.Kind() == reflect.Ptr && v.IsNil() {\n\t\tif populator, ok := dataSource.(Populator); ok {\n\t\t\tif err := populator.Populate(index); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif v.IsNil() {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t_, vv, err := reflectValueFromPath(v, member)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn vv.Interface()\n}\n"
  },
  {
    "path": "registry.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype RegistryKey struct {\n\thKey win.HKEY\n}\n\nfunc ClassesRootKey() *RegistryKey {\n\treturn &RegistryKey{win.HKEY_CLASSES_ROOT}\n}\n\nfunc CurrentUserKey() *RegistryKey {\n\treturn &RegistryKey{win.HKEY_CURRENT_USER}\n}\n\nfunc LocalMachineKey() *RegistryKey {\n\treturn &RegistryKey{win.HKEY_LOCAL_MACHINE}\n}\n\nfunc RegistryKeyString(rootKey *RegistryKey, subKeyPath, valueName string) (value string, err error) {\n\tvar hKey win.HKEY\n\tif win.RegOpenKeyEx(\n\t\trootKey.hKey,\n\t\tsyscall.StringToUTF16Ptr(subKeyPath),\n\t\t0,\n\t\twin.KEY_READ,\n\t\t&hKey) != win.ERROR_SUCCESS {\n\n\t\treturn \"\", newError(\"RegistryKeyString: Failed to open subkey.\")\n\t}\n\tdefer win.RegCloseKey(hKey)\n\n\tvar typ uint32\n\tvar data []uint16\n\tvar bufSize uint32\n\n\tif win.ERROR_SUCCESS != win.RegQueryValueEx(\n\t\thKey,\n\t\tsyscall.StringToUTF16Ptr(valueName),\n\t\tnil,\n\t\t&typ,\n\t\tnil,\n\t\t&bufSize) {\n\n\t\treturn \"\", newError(\"RegQueryValueEx #1\")\n\t}\n\n\tdata = make([]uint16, bufSize/2+1)\n\n\tif win.ERROR_SUCCESS != win.RegQueryValueEx(\n\t\thKey,\n\t\tsyscall.StringToUTF16Ptr(valueName),\n\t\tnil,\n\t\t&typ,\n\t\t(*byte)(unsafe.Pointer(&data[0])),\n\t\t&bufSize) {\n\n\t\treturn \"\", newError(\"RegQueryValueEx #2\")\n\t}\n\n\treturn syscall.UTF16ToString(data), nil\n}\n\nfunc RegistryKeyUint32(rootKey *RegistryKey, subKeyPath, valueName string) (value uint32, err error) {\n\tvar hKey win.HKEY\n\tif win.RegOpenKeyEx(\n\t\trootKey.hKey,\n\t\tsyscall.StringToUTF16Ptr(subKeyPath),\n\t\t0,\n\t\twin.KEY_READ,\n\t\t&hKey) != win.ERROR_SUCCESS {\n\n\t\treturn 0, newError(\"RegistryKeyUint32: Failed to open subkey.\")\n\t}\n\tdefer win.RegCloseKey(hKey)\n\n\tbufSize := uint32(4)\n\n\tif win.ERROR_SUCCESS != win.RegQueryValueEx(\n\t\thKey,\n\t\tsyscall.StringToUTF16Ptr(valueName),\n\t\tnil,\n\t\tnil,\n\t\t(*byte)(unsafe.Pointer(&value)),\n\t\t&bufSize) {\n\n\t\treturn 0, newError(\"RegQueryValueEx\")\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "resourcemanager.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n)\n\nfunc init() {\n\tResources.rootDirPath, _ = os.Getwd()\n\tResources.bitmaps = make(map[string]*Bitmap)\n\tResources.icons = make(map[string]*Icon)\n}\n\n// Resources is the singleton instance of ResourceManager.\nvar Resources ResourceManager\n\n// ResourceManager is a cache for sharing resources like bitmaps and icons.\n// The resources can be either embedded in the running executable\n// file or located below a specified root directory in the file system.\ntype ResourceManager struct {\n\trootDirPath string\n\tbitmaps     map[string]*Bitmap\n\ticons       map[string]*Icon\n}\n\n// RootDirPath returns the root directory path where resources are to be loaded from.\nfunc (rm *ResourceManager) RootDirPath() string {\n\treturn rm.rootDirPath\n}\n\n// SetRootDirPath sets the root directory path where resources are to be loaded from.\nfunc (rm *ResourceManager) SetRootDirPath(rootDirPath string) error {\n\tpath, err := filepath.Abs(rootDirPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trm.rootDirPath = path\n\n\treturn nil\n}\n\n// Bitmap loads a bitmap from file or resource identified by name, or an error if it could not be\n// found. When bitmap is loaded, 96dpi is assumed.\n//\n// Deprecated: Newer applications should use BitmapForDPI.\nfunc (rm *ResourceManager) Bitmap(name string) (*Bitmap, error) {\n\treturn rm.BitmapForDPI(name, 96)\n}\n\n// BitmapForDPI loads a bitmap from file or resource identified by name, or an error if it could\n// not be found. When bitmap is loaded, given DPI is assumed.\nfunc (rm *ResourceManager) BitmapForDPI(name string, dpi int) (*Bitmap, error) {\n\tif bm := rm.bitmaps[name]; bm != nil {\n\t\treturn bm, nil\n\t}\n\n\tif bm, err := NewBitmapFromFileForDPI(filepath.Join(rm.rootDirPath, name), dpi); err == nil {\n\t\trm.bitmaps[name] = bm\n\t\treturn bm, nil\n\t}\n\n\tif bm, err := NewBitmapFromResourceForDPI(name, dpi); err == nil {\n\t\trm.bitmaps[name] = bm\n\t\treturn bm, nil\n\t}\n\n\tif id, err := strconv.Atoi(name); err == nil {\n\t\tif bm, err := NewBitmapFromResourceIdForDPI(id, dpi); err == nil {\n\t\t\trm.bitmaps[name] = bm\n\t\t\treturn bm, nil\n\t\t}\n\t}\n\n\treturn nil, rm.notFoundErr(\"bitmap\", name)\n}\n\n// Icon returns the Icon identified by name, or an error if it could not be found.\nfunc (rm *ResourceManager) Icon(name string) (*Icon, error) {\n\tif icon := rm.icons[name]; icon != nil {\n\t\treturn icon, nil\n\t}\n\n\tif icon, err := NewIconFromFile(filepath.Join(rm.rootDirPath, name)); err == nil {\n\t\trm.icons[name] = icon\n\t\treturn icon, nil\n\t}\n\n\tif icon, err := NewIconFromResource(name); err == nil {\n\t\trm.icons[name] = icon\n\t\treturn icon, nil\n\t}\n\n\tif id, err := strconv.Atoi(name); err == nil {\n\t\tif icon, err := NewIconFromResourceId(id); err == nil {\n\t\t\trm.icons[name] = icon\n\t\t\treturn icon, nil\n\t\t}\n\t}\n\n\treturn nil, rm.notFoundErr(\"icon\", name)\n}\n\n// Image returns the Image identified by name, or an error if it could not be found.\nfunc (rm *ResourceManager) Image(name string) (Image, error) {\n\tif icon, err := rm.Icon(name); err == nil {\n\t\treturn icon, nil\n\t}\n\n\tif bm, err := rm.Bitmap(name); err == nil {\n\t\treturn bm, nil\n\t}\n\n\treturn nil, rm.notFoundErr(\"image\", name)\n}\n\nfunc (rm *ResourceManager) notFoundErr(typ, name string) error {\n\tpath := filepath.Clean(filepath.Join(rm.rootDirPath, name))\n\n\treturn newError(fmt.Sprintf(\"neither %s resource '%s' nor file '%s' could be found or the image format is not supported\", typ, name, path))\n}\n"
  },
  {
    "path": "scrollview.go",
    "content": "// Copyright 2014 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst scrollViewWindowClass = `\\o/ Walk_ScrollView_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(scrollViewWindowClass)\n\t})\n}\n\ntype ScrollView struct {\n\tWidgetBase\n\tcomposite  *Composite\n\thorizontal bool\n\tvertical   bool\n}\n\nfunc NewScrollView(parent Container) (*ScrollView, error) {\n\tsv := &ScrollView{horizontal: true, vertical: true}\n\n\tif err := InitWidget(\n\t\tsv,\n\t\tparent,\n\t\tscrollViewWindowClass,\n\t\twin.WS_CHILD|win.WS_HSCROLL|win.WS_VISIBLE|win.WS_VSCROLL,\n\t\twin.WS_EX_CONTROLPARENT); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tsv.Dispose()\n\t\t}\n\t}()\n\n\tvar err error\n\tif sv.composite, err = NewComposite(sv); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsv.composite.SizeChanged().Attach(func() {\n\t\tsv.updateScrollBars()\n\t})\n\n\tsv.SetBackground(NullBrush())\n\n\tsucceeded = true\n\n\treturn sv, nil\n}\n\nfunc (sv *ScrollView) AsContainerBase() *ContainerBase {\n\tif sv.composite == nil {\n\t\treturn nil\n\t}\n\n\treturn sv.composite.AsContainerBase()\n}\n\nfunc (sv *ScrollView) ApplyDPI(dpi int) {\n\tsv.WidgetBase.ApplyDPI(dpi)\n\tsv.composite.ApplyDPI(dpi)\n}\n\nfunc (sv *ScrollView) Scrollbars() (horizontal, vertical bool) {\n\thorizontal = sv.horizontal\n\tvertical = sv.vertical\n\n\treturn\n}\n\nfunc (sv *ScrollView) SetScrollbars(horizontal, vertical bool) {\n\tsv.horizontal = horizontal\n\tsv.vertical = vertical\n\n\tsv.ensureStyleBits(win.WS_HSCROLL, horizontal)\n\tsv.ensureStyleBits(win.WS_VSCROLL, vertical)\n}\n\nfunc (sv *ScrollView) SetSuspended(suspend bool) {\n\tsv.composite.SetSuspended(suspend)\n\tsv.WidgetBase.SetSuspended(suspend)\n\tsv.Invalidate()\n}\n\nfunc (sv *ScrollView) DataBinder() *DataBinder {\n\treturn sv.composite.dataBinder\n}\n\nfunc (sv *ScrollView) SetDataBinder(dataBinder *DataBinder) {\n\tsv.composite.SetDataBinder(dataBinder)\n}\n\nfunc (sv *ScrollView) Children() *WidgetList {\n\tif sv.composite == nil {\n\t\t// Without this we would get into trouble in NewComposite.\n\t\treturn nil\n\t}\n\n\treturn sv.composite.Children()\n}\n\nfunc (sv *ScrollView) Layout() Layout {\n\tif sv.composite == nil {\n\t\treturn nil\n\t}\n\n\treturn sv.composite.Layout()\n}\n\nfunc (sv *ScrollView) SetLayout(value Layout) error {\n\treturn sv.composite.SetLayout(value)\n}\n\nfunc (sv *ScrollView) Name() string {\n\tif sv.composite == nil {\n\t\treturn \"\"\n\t}\n\n\treturn sv.composite.Name()\n}\n\nfunc (sv *ScrollView) SetName(name string) {\n\tsv.composite.SetName(name)\n}\n\nfunc (sv *ScrollView) Persistent() bool {\n\treturn sv.composite.Persistent()\n}\n\nfunc (sv *ScrollView) SetPersistent(value bool) {\n\tsv.composite.SetPersistent(value)\n}\n\nfunc (sv *ScrollView) SaveState() error {\n\treturn sv.composite.SaveState()\n}\n\nfunc (sv *ScrollView) RestoreState() error {\n\treturn sv.composite.RestoreState()\n}\n\nfunc (sv *ScrollView) MouseDown() *MouseEvent {\n\treturn sv.composite.MouseDown()\n}\n\nfunc (sv *ScrollView) MouseMove() *MouseEvent {\n\treturn sv.composite.MouseMove()\n}\n\nfunc (sv *ScrollView) MouseUp() *MouseEvent {\n\treturn sv.composite.MouseUp()\n}\n\nfunc (sv *ScrollView) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tif sv.composite != nil {\n\t\tavoidBGArtifacts := func() {\n\t\t\tif sv.hasComplexBackground() {\n\t\t\t\tsv.composite.Invalidate()\n\t\t\t}\n\t\t}\n\n\t\tswitch msg {\n\t\tcase win.WM_HSCROLL:\n\t\t\tsv.composite.SetXPixels(sv.scroll(win.SB_HORZ, win.LOWORD(uint32(wParam))))\n\t\t\tif wParam == win.SB_ENDSCROLL {\n\t\t\t\tavoidBGArtifacts()\n\t\t\t}\n\n\t\tcase win.WM_VSCROLL:\n\t\t\tsv.composite.SetYPixels(sv.scroll(win.SB_VERT, win.LOWORD(uint32(wParam))))\n\t\t\tif wParam == win.SB_ENDSCROLL {\n\t\t\t\tavoidBGArtifacts()\n\t\t\t}\n\n\t\tcase win.WM_MOUSEWHEEL:\n\t\t\tif win.GetWindowLong(sv.hWnd, win.GWL_STYLE)&win.WS_VSCROLL == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tvar cmd uint16\n\t\t\tif delta := int16(win.HIWORD(uint32(wParam))); delta < 0 {\n\t\t\t\tcmd = win.SB_LINEDOWN\n\t\t\t} else {\n\t\t\t\tcmd = win.SB_LINEUP\n\t\t\t}\n\n\t\t\tsv.composite.SetYPixels(sv.scroll(win.SB_VERT, cmd))\n\t\t\tavoidBGArtifacts()\n\n\t\t\treturn 0\n\n\t\tcase win.WM_COMMAND, win.WM_NOTIFY:\n\t\t\tsv.composite.WndProc(hwnd, msg, wParam, lParam)\n\n\t\tcase win.WM_WINDOWPOSCHANGED:\n\t\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsv.updateScrollBars()\n\n\t\t\tif h, v := sv.Scrollbars(); !h || !v {\n\t\t\t\tsv.RequestLayout()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn sv.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (sv *ScrollView) updateScrollBars() {\n\tsize := sv.SizePixels()\n\tcompositeSize := sv.composite.SizePixels()\n\n\tvar si win.SCROLLINFO\n\tsi.CbSize = uint32(unsafe.Sizeof(si))\n\tsi.FMask = win.SIF_PAGE | win.SIF_RANGE\n\n\tnewCompositeBounds := Rectangle{Width: compositeSize.Width, Height: compositeSize.Height}\n\n\tif size != compositeSize {\n\t\tdpi := uint32(sv.DPI())\n\n\t\tvsbw := int(win.GetSystemMetricsForDpi(win.SM_CXVSCROLL, dpi))\n\t\thsbh := int(win.GetSystemMetricsForDpi(win.SM_CYHSCROLL, dpi))\n\n\t\tif size.Width < compositeSize.Width && size.Height < compositeSize.Height {\n\t\t\tsize.Width -= vsbw\n\t\t\tsize.Height -= hsbh\n\t\t}\n\t}\n\n\tsi.NMax = int32(compositeSize.Width - 1)\n\tsi.NPage = uint32(size.Width)\n\twin.SetScrollInfo(sv.hWnd, win.SB_HORZ, &si, false)\n\tnewCompositeBounds.X = sv.scroll(win.SB_HORZ, win.SB_THUMBPOSITION)\n\n\tsi.NMax = int32(compositeSize.Height - 1)\n\tsi.NPage = uint32(size.Height)\n\twin.SetScrollInfo(sv.hWnd, win.SB_VERT, &si, false)\n\tnewCompositeBounds.Y = sv.scroll(win.SB_VERT, win.SB_THUMBPOSITION)\n\n\tsv.composite.SetBoundsPixels(newCompositeBounds)\n}\n\n// scroll scrolls and returns new position in native pixels.\nfunc (sv *ScrollView) scroll(sb int32, cmd uint16) int {\n\tvar pos int32\n\tvar si win.SCROLLINFO\n\tsi.CbSize = uint32(unsafe.Sizeof(si))\n\tsi.FMask = win.SIF_PAGE | win.SIF_POS | win.SIF_RANGE | win.SIF_TRACKPOS\n\n\twin.GetScrollInfo(sv.hWnd, sb, &si)\n\n\tpos = si.NPos\n\n\tswitch cmd {\n\tcase win.SB_LINELEFT: // == win.SB_LINEUP\n\t\tpos -= int32(sv.IntFrom96DPI(20))\n\n\tcase win.SB_LINERIGHT: // == win.SB_LINEDOWN\n\t\tpos += int32(sv.IntFrom96DPI(20))\n\n\tcase win.SB_PAGELEFT: // == win.SB_PAGEUP\n\t\tpos -= int32(si.NPage)\n\n\tcase win.SB_PAGERIGHT: // == win.SB_PAGEDOWN\n\t\tpos += int32(si.NPage)\n\n\tcase win.SB_THUMBTRACK:\n\t\tpos = si.NTrackPos\n\t}\n\n\tif pos < 0 {\n\t\tpos = 0\n\t}\n\tif pos > si.NMax+1-int32(si.NPage) {\n\t\tpos = si.NMax + 1 - int32(si.NPage)\n\t}\n\n\tsi.FMask = win.SIF_POS\n\tsi.NPos = pos\n\twin.SetScrollInfo(sv.hWnd, sb, &si, true)\n\n\treturn -int(pos)\n}\n\nfunc (sv *ScrollView) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tsvli := new(scrollViewLayoutItem)\n\tsvli.ctx = ctx\n\tcli := CreateLayoutItemsForContainerWithContext(sv.composite, ctx)\n\tcli.AsLayoutItemBase().parent = svli\n\tsvli.children = append(svli.children, cli)\n\n\tif box, ok := cli.(*boxLayoutItem); ok {\n\t\tif len(box.children) > 0 {\n\t\t\tif _, ok := box.children[len(box.children)-1].(*spacerLayoutItem); !ok {\n\t\t\t\t// To retain the previous behavior with box layouts, we add a fake spacer at the end.\n\t\t\t\t// Maybe this should just be an option.\n\t\t\t\tbox.children = append(box.children, &spacerLayoutItem{\n\t\t\t\t\tLayoutItemBase: LayoutItemBase{ctx: ctx},\n\t\t\t\t\tlayoutFlags:    ShrinkableHorz | ShrinkableVert | GrowableVert | GreedyVert,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tsvli.idealSize = cli.MinSize()\n\n\th, v := sv.Scrollbars()\n\n\tif h {\n\t\tsvli.layoutFlags |= ShrinkableHorz | GrowableHorz | GreedyHorz\n\n\t\tif !v {\n\t\t\tmaxSize := SizeFrom96DPI(sv.maxSize96dpi, ctx.dpi)\n\t\t\tif svli.idealSize.Width > sv.geometry.ClientSize.Width && sv.geometry.ClientSize.Width > 0 && maxSize.Width == 0 ||\n\t\t\t\tsvli.idealSize.Width > maxSize.Width && maxSize.Width > 0 {\n\t\t\t\tsvli.sbSize.Height = int(win.GetSystemMetricsForDpi(win.SM_CYHSCROLL, uint32(ctx.dpi)))\n\t\t\t\tsvli.idealSize.Height += svli.sbSize.Height\n\t\t\t}\n\n\t\t\tsvli.minSize.Height = svli.idealSize.Height\n\t\t}\n\t}\n\n\tif v {\n\t\tsvli.layoutFlags |= GreedyVert | GrowableVert | ShrinkableVert\n\n\t\tif !h {\n\t\t\tmaxSize := SizeFrom96DPI(sv.maxSize96dpi, ctx.dpi)\n\t\t\tif svli.idealSize.Height > sv.geometry.ClientSize.Height && sv.geometry.ClientSize.Height > 0 && maxSize.Height == 0 ||\n\t\t\t\tsvli.idealSize.Height > maxSize.Height && maxSize.Height > 0 {\n\t\t\t\tsvli.sbSize.Width = int(win.GetSystemMetricsForDpi(win.SM_CXVSCROLL, uint32(ctx.dpi)))\n\t\t\t\tsvli.idealSize.Width += svli.sbSize.Width\n\t\t\t}\n\n\t\t\tsvli.minSize.Width = svli.idealSize.Width\n\t\t}\n\t}\n\n\tvar si win.SCROLLINFO\n\tsi.CbSize = uint32(unsafe.Sizeof(si))\n\tsi.FMask = win.SIF_POS | win.SIF_RANGE\n\n\twin.GetScrollInfo(sv.hWnd, win.SB_HORZ, &si)\n\tsvli.scrollX = float64(si.NPos) / float64(si.NMax)\n\n\twin.GetScrollInfo(sv.hWnd, win.SB_VERT, &si)\n\tsvli.scrollY = float64(si.NPos) / float64(si.NMax)\n\n\treturn svli\n}\n\ntype scrollViewLayoutItem struct {\n\tContainerLayoutItemBase\n\tidealSize   Size // in native pixels\n\tminSize     Size // in native pixels\n\tsbSize      Size // in native pixels\n\tlayoutFlags LayoutFlags\n\tscrollX     float64\n\tscrollY     float64\n}\n\nfunc (li *scrollViewLayoutItem) LayoutFlags() LayoutFlags {\n\treturn li.layoutFlags\n}\n\nfunc (li *scrollViewLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *scrollViewLayoutItem) MinSize() Size {\n\treturn li.minSize\n}\n\nfunc (li *scrollViewLayoutItem) MinSizeForSize(size Size) Size {\n\treturn li.MinSize()\n}\n\nfunc (li *scrollViewLayoutItem) HasHeightForWidth() bool {\n\treturn false\n}\n\nfunc (li *scrollViewLayoutItem) HeightForWidth(width int) int {\n\treturn 0\n}\n\nfunc (li *scrollViewLayoutItem) PerformLayout() []LayoutResultItem {\n\tcomposite := li.children[0]\n\n\tclientSize := li.geometry.Size\n\tclientSize.Width -= li.sbSize.Width\n\tclientSize.Height -= li.sbSize.Height\n\n\tminSize := composite.(MinSizeForSizer).MinSizeForSize(clientSize)\n\tif hfw, ok := composite.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\tif minSize.Height > clientSize.Height {\n\t\t\tif minSize.Width > clientSize.Width {\n\t\t\t\tclientSize.Width = minSize.Width\n\t\t\t\tminSize = composite.(MinSizeForSizer).MinSizeForSize(clientSize)\n\t\t\t} else {\n\t\t\t\tclientSize.Width -= int(win.GetSystemMetricsForDpi(win.SM_CXVSCROLL, uint32(li.ctx.dpi)))\n\t\t\t\tminSize = composite.(MinSizeForSizer).MinSizeForSize(clientSize)\n\t\t\t\tif minSize.Width > clientSize.Width {\n\t\t\t\t\tclientSize.Width = minSize.Width\n\t\t\t\t\tminSize = composite.(MinSizeForSizer).MinSizeForSize(clientSize)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\ts := maxSize(minSize, clientSize)\n\n\tvar x, y int\n\tif clientSize.Width < minSize.Width {\n\t\tx = -int(float64(minSize.Width) * li.scrollX)\n\t}\n\tif clientSize.Height < minSize.Height {\n\t\ty = -int(float64(minSize.Height) * li.scrollY)\n\t}\n\n\treturn []LayoutResultItem{\n\t\t{\n\t\t\tItem:   composite,\n\t\t\tBounds: Rectangle{x, y, s.Width, s.Height},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "separator.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype Separator struct {\n\tWidgetBase\n\tvertical bool\n}\n\nfunc NewHSeparator(parent Container) (*Separator, error) {\n\treturn newSeparator(parent, false)\n}\n\nfunc NewVSeparator(parent Container) (*Separator, error) {\n\treturn newSeparator(parent, true)\n}\n\nfunc newSeparator(parent Container, vertical bool) (*Separator, error) {\n\ts := &Separator{vertical: vertical}\n\n\tif err := InitWidget(\n\t\ts,\n\t\tparent,\n\t\t\"STATIC\",\n\t\twin.WS_VISIBLE|win.SS_ETCHEDHORZ,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn s, nil\n}\n\nfunc (s *Separator) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tvar layoutFlags LayoutFlags\n\tif s.vertical {\n\t\tlayoutFlags = GrowableHorz | GreedyHorz\n\t} else {\n\t\tlayoutFlags = GrowableVert | GreedyVert\n\t}\n\n\treturn &separatorLayoutItem{\n\t\tlayoutFlags: layoutFlags,\n\t}\n}\n\ntype separatorLayoutItem struct {\n\tLayoutItemBase\n\tlayoutFlags LayoutFlags\n}\n\nfunc (li *separatorLayoutItem) LayoutFlags() LayoutFlags {\n\treturn li.layoutFlags\n}\n\nfunc (li *separatorLayoutItem) IdealSize() Size {\n\treturn li.MinSize()\n}\n\nfunc (li *separatorLayoutItem) MinSize() Size {\n\treturn SizeFrom96DPI(Size{2, 2}, li.ctx.dpi)\n}\n"
  },
  {
    "path": "simpletypes.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype Alignment1D uint\n\nconst (\n\tAlignDefault Alignment1D = iota\n\tAlignNear\n\tAlignCenter\n\tAlignFar\n)\n\ntype Alignment2D uint\n\nconst (\n\tAlignHVDefault Alignment2D = iota\n\tAlignHNearVNear\n\tAlignHCenterVNear\n\tAlignHFarVNear\n\tAlignHNearVCenter\n\tAlignHCenterVCenter\n\tAlignHFarVCenter\n\tAlignHNearVFar\n\tAlignHCenterVFar\n\tAlignHFarVFar\n)\n"
  },
  {
    "path": "size.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport \"github.com/lxn/win\"\n\n// Size defines width and height in 1/96\" units or native pixels, or dialog base units.\n//\n// When Size is used for DPI metrics, it defines a 1\"x1\" rectangle in native pixels.\ntype Size struct {\n\tWidth, Height int\n}\n\nfunc (s Size) IsZero() bool {\n\treturn s.Width == 0 && s.Height == 0\n}\n\nfunc (s Size) toSIZE() win.SIZE {\n\treturn win.SIZE{\n\t\tCX: int32(s.Width),\n\t\tCY: int32(s.Height),\n\t}\n}\n\nfunc minSize(a, b Size) Size {\n\tvar s Size\n\n\tif a.Width < b.Width {\n\t\ts.Width = a.Width\n\t} else {\n\t\ts.Width = b.Width\n\t}\n\n\tif a.Height < b.Height {\n\t\ts.Height = a.Height\n\t} else {\n\t\ts.Height = b.Height\n\t}\n\n\treturn s\n}\n\nfunc maxSize(a, b Size) Size {\n\tvar s Size\n\n\tif a.Width > b.Width {\n\t\ts.Width = a.Width\n\t} else {\n\t\ts.Width = b.Width\n\t}\n\n\tif a.Height > b.Height {\n\t\ts.Height = a.Height\n\t} else {\n\t\ts.Height = b.Height\n\t}\n\n\treturn s\n}\n\nfunc sizeFromSIZE(s win.SIZE) Size {\n\treturn Size{\n\t\tWidth:  int(s.CX),\n\t\tHeight: int(s.CY),\n\t}\n}\n\nfunc sizeFromRECT(r win.RECT) Size {\n\treturn Size{\n\t\tWidth:  int(r.Right - r.Left),\n\t\tHeight: int(r.Bottom - r.Top),\n\t}\n}\n"
  },
  {
    "path": "slider.go",
    "content": "// Copyright 2016 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype Slider struct {\n\tWidgetBase\n\tvalueChangedPublisher EventPublisher\n\tlayoutFlags           LayoutFlags\n\ttracking              bool\n\tpersistent            bool\n}\n\ntype SliderCfg struct {\n\tOrientation    Orientation\n\tToolTipsHidden bool\n}\n\nfunc NewSlider(parent Container) (*Slider, error) {\n\treturn NewSliderWithOrientation(parent, Horizontal)\n}\n\nfunc NewSliderWithOrientation(parent Container, orientation Orientation) (*Slider, error) {\n\treturn NewSliderWithCfg(parent, &SliderCfg{Orientation: orientation})\n}\n\nfunc NewSliderWithCfg(parent Container, cfg *SliderCfg) (*Slider, error) {\n\tsl := new(Slider)\n\n\tvar style uint32 = win.WS_TABSTOP | win.WS_VISIBLE\n\tif cfg.Orientation == Vertical {\n\t\tstyle |= win.TBS_VERT\n\t\tsl.layoutFlags = ShrinkableVert | GrowableVert\n\t} else {\n\t\tsl.layoutFlags = ShrinkableHorz | GrowableHorz\n\t}\n\tif !cfg.ToolTipsHidden {\n\t\tstyle |= win.TBS_TOOLTIPS\n\t}\n\n\tif err := InitWidget(\n\t\tsl,\n\t\tparent,\n\t\t\"msctls_trackbar32\",\n\t\tstyle,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsl.SetBackground(nullBrushSingleton)\n\n\tsl.GraphicsEffects().Add(InteractionEffect)\n\tsl.GraphicsEffects().Add(FocusEffect)\n\n\tsl.MustRegisterProperty(\"Value\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn sl.Value()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\tsl.SetValue(assertIntOr(v, 0))\n\t\t\treturn nil\n\t\t},\n\t\tsl.valueChangedPublisher.Event()))\n\n\treturn sl, nil\n}\n\nfunc (sl *Slider) MinValue() int {\n\treturn int(sl.SendMessage(win.TBM_GETRANGEMIN, 0, 0))\n}\n\nfunc (sl *Slider) MaxValue() int {\n\treturn int(sl.SendMessage(win.TBM_GETRANGEMAX, 0, 0))\n}\n\nfunc (sl *Slider) SetRange(min, max int) {\n\tsl.SendMessage(win.TBM_SETRANGEMIN, 0, uintptr(min))\n\tsl.SendMessage(win.TBM_SETRANGEMAX, 1, uintptr(max))\n}\n\nfunc (sl *Slider) Value() int {\n\treturn int(sl.SendMessage(win.TBM_GETPOS, 0, 0))\n}\n\nfunc (sl *Slider) SetValue(value int) {\n\tsl.SendMessage(win.TBM_SETPOS, 1, uintptr(value))\n\tsl.valueChangedPublisher.Publish()\n}\n\n// ValueChanged returns an Event that can be used to track changes to Value.\nfunc (sl *Slider) ValueChanged() *Event {\n\treturn sl.valueChangedPublisher.Event()\n}\n\nfunc (sl *Slider) Persistent() bool {\n\treturn sl.persistent\n}\n\nfunc (sl *Slider) SetPersistent(value bool) {\n\tsl.persistent = value\n}\n\nfunc (sl *Slider) SaveState() error {\n\treturn sl.WriteState(strconv.Itoa(sl.Value()))\n}\n\nfunc (sl *Slider) RestoreState() error {\n\ts, err := sl.ReadState()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvalue, err := strconv.Atoi(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsl.SetValue(value)\n\n\treturn nil\n}\n\nfunc (sl *Slider) LineSize() int {\n\treturn int(sl.SendMessage(win.TBM_GETLINESIZE, 0, 0))\n}\n\nfunc (sl *Slider) SetLineSize(lineSize int) {\n\tsl.SendMessage(win.TBM_SETLINESIZE, 0, uintptr(lineSize))\n}\n\nfunc (sl *Slider) PageSize() int {\n\treturn int(sl.SendMessage(win.TBM_GETPAGESIZE, 0, 0))\n}\n\nfunc (sl *Slider) SetPageSize(pageSize int) {\n\tsl.SendMessage(win.TBM_SETPAGESIZE, 0, uintptr(pageSize))\n}\n\nfunc (sl *Slider) Tracking() bool {\n\treturn sl.tracking\n}\n\nfunc (sl *Slider) SetTracking(tracking bool) {\n\tsl.tracking = tracking\n}\n\nfunc (sl *Slider) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_HSCROLL, win.WM_VSCROLL:\n\t\tswitch win.LOWORD(uint32(wParam)) {\n\t\tcase win.TB_THUMBPOSITION, win.TB_ENDTRACK:\n\t\t\tsl.valueChangedPublisher.Publish()\n\n\t\tcase win.TB_THUMBTRACK:\n\t\t\tif sl.tracking {\n\t\t\t\tsl.valueChangedPublisher.Publish()\n\t\t\t}\n\t\t}\n\t\treturn 0\n\t}\n\treturn sl.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (*Slider) NeedsWmSize() bool {\n\treturn true\n}\n\nfunc (sl *Slider) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn &sliderLayoutItem{\n\t\tlayoutFlags: sl.layoutFlags,\n\t\tidealSize:   sl.dialogBaseUnitsToPixels(Size{15, 15}),\n\t}\n}\n\ntype sliderLayoutItem struct {\n\tLayoutItemBase\n\tlayoutFlags LayoutFlags\n\tidealSize   Size // in native pixels\n}\n\nfunc (li *sliderLayoutItem) LayoutFlags() LayoutFlags {\n\treturn li.layoutFlags\n}\n\nfunc (li *sliderLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *sliderLayoutItem) MinSize() Size {\n\treturn li.idealSize\n}\n"
  },
  {
    "path": "spacer.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nconst spacerWindowClass = `\\o/ Walk_Spacer_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(spacerWindowClass)\n\t})\n}\n\ntype Spacer struct {\n\tWidgetBase\n\tsizeHint96dpi     Size\n\tlayoutFlags       LayoutFlags\n\tgreedyLocallyOnly bool\n}\n\ntype SpacerCfg struct {\n\tLayoutFlags       LayoutFlags\n\tSizeHint          Size // in 1/96\" units\n\tGreedyLocallyOnly bool\n}\n\nfunc NewSpacerWithCfg(parent Container, cfg *SpacerCfg) (*Spacer, error) {\n\treturn newSpacer(parent, cfg.LayoutFlags, cfg.SizeHint, cfg.GreedyLocallyOnly)\n}\n\nfunc newSpacer(parent Container, layoutFlags LayoutFlags, sizeHint96dpi Size, greedyLocallyOnly bool) (*Spacer, error) {\n\ts := &Spacer{\n\t\tlayoutFlags:       layoutFlags,\n\t\tsizeHint96dpi:     sizeHint96dpi,\n\t\tgreedyLocallyOnly: greedyLocallyOnly,\n\t}\n\n\tif err := InitWidget(\n\t\ts,\n\t\tparent,\n\t\tspacerWindowClass,\n\t\t0,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn s, nil\n}\n\nfunc NewHSpacer(parent Container) (*Spacer, error) {\n\treturn newSpacer(parent, ShrinkableHorz|ShrinkableVert|GrowableHorz|GreedyHorz, Size{}, false)\n}\n\nfunc NewHSpacerFixed(parent Container, width int) (*Spacer, error) {\n\treturn newSpacer(parent, 0, Size{width, 0}, false)\n}\n\nfunc NewVSpacer(parent Container) (*Spacer, error) {\n\treturn newSpacer(parent, ShrinkableHorz|ShrinkableVert|GrowableVert|GreedyVert, Size{}, false)\n}\n\nfunc NewVSpacerFixed(parent Container, height int) (*Spacer, error) {\n\treturn newSpacer(parent, 0, Size{0, height}, false)\n}\n\nfunc (s *Spacer) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn &spacerLayoutItem{\n\t\tidealSize96dpi:    s.sizeHint96dpi,\n\t\tlayoutFlags:       s.layoutFlags,\n\t\tgreedyLocallyOnly: s.greedyLocallyOnly,\n\t}\n}\n\ntype spacerLayoutItem struct {\n\tLayoutItemBase\n\tidealSize96dpi    Size\n\tlayoutFlags       LayoutFlags\n\tgreedyLocallyOnly bool\n}\n\nfunc (li *spacerLayoutItem) LayoutFlags() LayoutFlags {\n\treturn li.layoutFlags\n}\n\nfunc (li *spacerLayoutItem) IdealSize() Size {\n\treturn SizeFrom96DPI(li.idealSize96dpi, li.ctx.dpi)\n}\n\nfunc (li *spacerLayoutItem) MinSize() Size {\n\treturn SizeFrom96DPI(li.idealSize96dpi, li.ctx.dpi)\n}\n"
  },
  {
    "path": "splitbutton.go",
    "content": "// Copyright 2016 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype SplitButton struct {\n\tButton\n\tmenu *Menu\n}\n\nfunc NewSplitButton(parent Container) (*SplitButton, error) {\n\tsb := new(SplitButton)\n\n\tvar disposables Disposables\n\tdefer disposables.Treat()\n\n\tif err := InitWidget(\n\t\tsb,\n\t\tparent,\n\t\t\"BUTTON\",\n\t\twin.WS_TABSTOP|win.WS_VISIBLE|win.BS_SPLITBUTTON,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\tdisposables.Add(sb)\n\n\tsb.Button.init()\n\n\tmenu, err := NewMenu()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdisposables.Add(menu)\n\tmenu.window = sb\n\tsb.menu = menu\n\n\tsb.GraphicsEffects().Add(InteractionEffect)\n\tsb.GraphicsEffects().Add(FocusEffect)\n\n\tdisposables.Spare()\n\n\treturn sb, nil\n}\n\nfunc (sb *SplitButton) Dispose() {\n\tsb.Button.Dispose()\n\n\tsb.menu.Dispose()\n}\n\nfunc (sb *SplitButton) ImageAboveText() bool {\n\treturn sb.hasStyleBits(win.BS_TOP)\n}\n\nfunc (sb *SplitButton) SetImageAboveText(value bool) error {\n\tif err := sb.ensureStyleBits(win.BS_TOP, value); err != nil {\n\t\treturn err\n\t}\n\n\t// We need to set the image again, or Windows will fail to calculate the\n\t// button control size correctly.\n\treturn sb.SetImage(sb.image)\n}\n\nfunc (sb *SplitButton) Menu() *Menu {\n\treturn sb.menu\n}\n\nfunc (sb *SplitButton) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_NOTIFY:\n\t\tswitch ((*win.NMHDR)(unsafe.Pointer(lParam))).Code {\n\t\tcase win.BCN_DROPDOWN:\n\t\t\tdd := (*win.NMBCDROPDOWN)(unsafe.Pointer(lParam))\n\n\t\t\tp := win.POINT{dd.RcButton.Left, dd.RcButton.Bottom}\n\n\t\t\twin.ClientToScreen(sb.hWnd, &p)\n\n\t\t\twin.TrackPopupMenuEx(\n\t\t\t\tsb.menu.hMenu,\n\t\t\t\twin.TPM_NOANIMATION,\n\t\t\t\tp.X,\n\t\t\t\tp.Y,\n\t\t\t\tsb.hWnd,\n\t\t\t\tnil)\n\t\t\treturn 0\n\t\t}\n\t}\n\n\treturn sb.Button.WndProc(hwnd, msg, wParam, lParam)\n}\n"
  },
  {
    "path": "splitter.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"bytes\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst splitterWindowClass = `\\o/ Walk_Splitter_Class \\o/`\n\nvar splitterHandleDraggingBrush *SolidColorBrush\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(splitterWindowClass)\n\n\t\tsplitterHandleDraggingBrush, _ = NewSolidColorBrush(Color(win.GetSysColor(win.COLOR_BTNSHADOW)))\n\t\tsplitterHandleDraggingBrush.wb2info = map[*WindowBase]*windowBrushInfo{nil: nil}\n\t})\n}\n\ntype Splitter struct {\n\tContainerBase\n\thandleWidth   int\n\tmouseDownPos  Point // in native pixels\n\tdraggedHandle *splitterHandle\n\tpersistent    bool\n\tremoving      bool\n}\n\nfunc newSplitter(parent Container, orientation Orientation) (*Splitter, error) {\n\tlayout := newSplitterLayout(Horizontal)\n\ts := &Splitter{\n\t\tContainerBase: ContainerBase{\n\t\t\tlayout: layout,\n\t\t},\n\t\thandleWidth: 5,\n\t}\n\ts.children = newWidgetList(s)\n\tlayout.container = s\n\n\tif err := InitWidget(\n\t\ts,\n\t\tparent,\n\t\tsplitterWindowClass,\n\t\twin.WS_VISIBLE,\n\t\twin.WS_EX_CONTROLPARENT); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar succeeded bool\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\ts.Dispose()\n\t\t}\n\t}()\n\n\ts.SetBackground(NullBrush())\n\n\tif err := s.setOrientation(orientation); err != nil {\n\t\treturn nil, err\n\t}\n\n\ts.SetPersistent(true)\n\n\tsucceeded = true\n\n\treturn s, nil\n}\n\nfunc NewHSplitter(parent Container) (*Splitter, error) {\n\treturn newSplitter(parent, Horizontal)\n}\n\nfunc NewVSplitter(parent Container) (*Splitter, error) {\n\treturn newSplitter(parent, Vertical)\n}\n\nfunc (s *Splitter) SetLayout(value Layout) error {\n\treturn newError(\"not supported\")\n}\n\nfunc (s *Splitter) HandleWidth() int {\n\treturn s.handleWidth\n}\n\nfunc (s *Splitter) SetHandleWidth(value int) error {\n\tif value == s.handleWidth {\n\t\treturn nil\n\t}\n\n\tif value < 1 {\n\t\treturn newError(\"invalid handle width\")\n\t}\n\n\ts.handleWidth = value\n\n\ts.RequestLayout()\n\n\treturn nil\n}\n\nfunc (s *Splitter) Orientation() Orientation {\n\tlayout := s.layout.(*splitterLayout)\n\treturn layout.Orientation()\n}\n\nfunc (s *Splitter) setOrientation(value Orientation) error {\n\tvar cursor Cursor\n\tif value == Horizontal {\n\t\tcursor = CursorSizeWE()\n\t} else {\n\t\tcursor = CursorSizeNS()\n\t}\n\n\tfor i, wb := range s.Children().items {\n\t\tif i%2 == 1 {\n\t\t\twb.window.SetCursor(cursor)\n\t\t}\n\t}\n\n\tlayout := s.layout.(*splitterLayout)\n\treturn layout.SetOrientation(value)\n}\n\nfunc (s *Splitter) updateMarginsForFocusEffect() {\n\tvar margins Margins\n\tvar parentLayout Layout\n\n\tif s.parent != nil {\n\t\tif parentLayout = s.parent.Layout(); parentLayout != nil {\n\t\t\tif m := parentLayout.Margins(); m.HNear < 9 || m.HFar < 9 || m.VNear < 9 || m.VFar < 9 {\n\t\t\t\tparentLayout = nil\n\t\t\t}\n\t\t}\n\t}\n\n\tvar affected bool\n\tif FocusEffect != nil {\n\t\tfor _, wb := range s.children.items {\n\t\t\tif wb.window.(Widget).GraphicsEffects().Contains(FocusEffect) {\n\t\t\t\taffected = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif affected {\n\t\tvar marginsNeeded bool\n\t\tfor _, wb := range s.children.items {\n\t\t\tswitch wb.window.(type) {\n\t\t\tcase *splitterHandle, *TabWidget, Container:\n\n\t\t\tdefault:\n\t\t\t\tmarginsNeeded = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif marginsNeeded {\n\t\t\tmargins = Margins{5, 5, 5, 5}\n\t\t}\n\t}\n\n\tif parentLayout != nil {\n\t\tparentLayout.SetMargins(Margins{9 - margins.HNear, 9 - margins.VNear, 9 - margins.HFar, 9 - margins.VFar})\n\t}\n\n\ts.layout.SetMargins(margins)\n}\n\nfunc (s *Splitter) Persistent() bool {\n\treturn s.persistent\n}\n\nfunc (s *Splitter) SetPersistent(value bool) {\n\ts.persistent = value\n}\n\nfunc (s *Splitter) SaveState() error {\n\tbuf := bytes.NewBuffer(nil)\n\n\tcount := s.children.Len()\n\tlayout := s.Layout().(*splitterLayout)\n\n\tfor i := 0; i < count; i += 2 {\n\t\tif i > 0 {\n\t\t\tbuf.WriteString(\" \")\n\t\t}\n\n\t\titem := layout.hwnd2Item[s.children.At(i).Handle()]\n\t\tsize := item.oldExplicitSize\n\t\tif size == 0 {\n\t\t\tsize = item.size\n\t\t}\n\t\tbuf.WriteString(strconv.FormatInt(int64(size), 10))\n\t}\n\n\ts.WriteState(buf.String())\n\n\tfor _, wb := range s.children.items {\n\t\tif persistable, ok := wb.window.(Persistable); ok {\n\t\t\tif err := persistable.SaveState(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *Splitter) RestoreState() error {\n\tchildCount := s.children.Len()/2 + 1\n\tif childCount == 0 {\n\t\treturn nil\n\t}\n\n\tstate, err := s.ReadState()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif state == \"\" {\n\t\treturn nil\n\t}\n\n\tsizeStrs := strings.Split(state, \" \")\n\n\t// FIXME: Solve this in a better way.\n\tif len(sizeStrs) != childCount {\n\t\tlog.Print(\"*Splitter.RestoreState: failed due to unexpected child count (FIXME!)\")\n\t\treturn nil\n\t}\n\n\tlayout := s.layout.(*splitterLayout)\n\n\ts.SetSuspended(true)\n\tlayout.suspended = true\n\tdefer func() {\n\t\tlayout.suspended = false\n\t\ts.SetSuspended(false)\n\t}()\n\n\tvar space int\n\tsize := s.ClientBoundsPixels().Size()\n\tif s.Orientation() == Horizontal {\n\t\tspace = size.Width\n\t} else {\n\t\tspace = size.Height\n\t}\n\tregularSpace := space - layout.spaceUnavailableToRegularWidgets()\n\n\tfor i, wb := range s.children.items {\n\t\twidget := wb.window.(Widget)\n\n\t\tif i%2 == 0 {\n\t\t\tj := i/2 + i%2\n\t\t\ts := sizeStrs[j]\n\n\t\t\tsize, err := strconv.Atoi(s)\n\t\t\tif err != nil {\n\t\t\t\t// OK, we probably got old style settings which were stored as fractions.\n\t\t\t\tfraction, err := strconv.ParseFloat(s, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tsize = int(float64(regularSpace) * fraction)\n\t\t\t}\n\n\t\t\titem := layout.hwnd2Item[widget.Handle()]\n\t\t\titem.size = size\n\t\t\titem.oldExplicitSize = size\n\t\t}\n\t}\n\n\tfor _, wb := range s.children.items {\n\t\tif persistable, ok := wb.window.(Persistable); ok {\n\t\t\tif err := persistable.RestoreState(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *Splitter) Fixed(widget Widget) bool {\n\treturn s.layout.(*splitterLayout).Fixed(widget)\n}\n\nfunc (s *Splitter) SetFixed(widget Widget, fixed bool) error {\n\titem := s.layout.(*splitterLayout).hwnd2Item[widget.Handle()]\n\tif item == nil {\n\t\treturn newError(\"unknown widget\")\n\t}\n\n\titem.fixed = fixed\n\n\tif b := widget.BoundsPixels(); fixed && item.size == 0 && (b.Width == 0 || b.Height == 0) {\n\t\tb.Width, b.Height = 100, 100\n\t\twidget.SetBoundsPixels(b)\n\t\titem.size = 100\n\t}\n\n\treturn nil\n}\n\nfunc (s *Splitter) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tlayout := s.layout.(*splitterLayout)\n\t\tlayout.resetNeeded = false\n\t\tfor _, item := range layout.hwnd2Item {\n\t\t\titem.oldExplicitSize = 0\n\t\t}\n\t}\n\n\treturn s.ContainerBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (s *Splitter) onInsertingWidget(index int, widget Widget) (err error) {\n\treturn s.ContainerBase.onInsertingWidget(index, widget)\n}\n\nfunc (s *Splitter) onInsertedWidget(index int, widget Widget) (err error) {\n\tdefer func() {\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\ts.updateMarginsForFocusEffect()\n\t}()\n\n\t_, isHandle := widget.(*splitterHandle)\n\tif isHandle {\n\t\tif s.Orientation() == Horizontal {\n\t\t\twidget.SetCursor(CursorSizeWE())\n\t\t} else {\n\t\t\twidget.SetCursor(CursorSizeNS())\n\t\t}\n\t} else {\n\t\tlayout := s.Layout().(*splitterLayout)\n\t\titem := &splitterLayoutItem{stretchFactor: 1, wasVisible: true}\n\t\tlayout.hwnd2Item[widget.Handle()] = item\n\n\t\tlayout.resetNeeded = true\n\t\tif !layout.suspended && widget.AsWidgetBase().visible {\n\t\t\ts.RequestLayout()\n\t\t}\n\n\t\titem.visibleChangedHandle = widget.VisibleChanged().Attach(func() {\n\t\t\tif !layout.suspended && widget.AsWidgetBase().visible != item.wasVisible {\n\t\t\t\tlayout.resetNeeded = true\n\t\t\t\ts.RequestLayout()\n\t\t\t}\n\t\t})\n\n\t\tif s.children.Len()%2 == 0 {\n\t\t\tdefer func() {\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tvar handle *splitterHandle\n\t\t\t\thandle, err = newSplitterHandle(s)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tclosestVisibleWidget := func(offset, direction int) Widget {\n\t\t\t\t\tindex := offset + direction\n\n\t\t\t\t\tfor index >= 0 && index < len(s.children.items) {\n\t\t\t\t\t\tif wb := s.children.items[index]; wb.visible {\n\t\t\t\t\t\t\treturn wb.window.(Widget)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tindex += direction\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\thandleIndex := index + 1 - index%2\n\t\t\t\terr = s.children.Insert(handleIndex, handle)\n\t\t\t\tif err == nil {\n\t\t\t\t\t// FIXME: These handlers will be leaked, if widgets get removed.\n\t\t\t\t\thandle.MouseDown().Attach(func(x, y int, button MouseButton) {\n\t\t\t\t\t\tif button != LeftButton {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ts.draggedHandle = handle\n\t\t\t\t\t\ts.mouseDownPos = Point{x, y}\n\t\t\t\t\t\thandle.SetBackground(splitterHandleDraggingBrush)\n\t\t\t\t\t})\n\n\t\t\t\t\thandle.MouseMove().Attach(func(x, y int, button MouseButton) {\n\t\t\t\t\t\tif s.draggedHandle == nil {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\thandleIndex := s.children.Index(s.draggedHandle)\n\t\t\t\t\t\tbh := s.draggedHandle.BoundsPixels()\n\n\t\t\t\t\t\tprev := closestVisibleWidget(handleIndex, -1)\n\t\t\t\t\t\tbp := prev.BoundsPixels()\n\t\t\t\t\t\tmsep := minSizeEffective(createLayoutItemForWidget(prev))\n\n\t\t\t\t\t\tnext := closestVisibleWidget(handleIndex, 1)\n\t\t\t\t\t\tbn := next.BoundsPixels()\n\t\t\t\t\t\tmsen := minSizeEffective(createLayoutItemForWidget(next))\n\n\t\t\t\t\t\tdpi := s.draggedHandle.DPI()\n\t\t\t\t\t\thandleWidth := IntFrom96DPI(s.handleWidth, dpi)\n\n\t\t\t\t\t\tif s.Orientation() == Horizontal {\n\t\t\t\t\t\t\txh := s.draggedHandle.XPixels()\n\n\t\t\t\t\t\t\txnew := xh + x - s.mouseDownPos.X\n\t\t\t\t\t\t\tif xnew < bp.X+msep.Width {\n\t\t\t\t\t\t\t\txnew = bp.X + msep.Width\n\t\t\t\t\t\t\t} else if xnew >= bn.X+bn.Width-msen.Width-handleWidth {\n\t\t\t\t\t\t\t\txnew = bn.X + bn.Width - msen.Width - handleWidth\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif e := s.draggedHandle.SetXPixels(xnew); e != nil {\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tyh := s.draggedHandle.YPixels()\n\n\t\t\t\t\t\t\tynew := yh + y - s.mouseDownPos.Y\n\t\t\t\t\t\t\tif ynew < bp.Y+msep.Height {\n\t\t\t\t\t\t\t\tynew = bp.Y + msep.Height\n\t\t\t\t\t\t\t} else if ynew >= bn.Y+bn.Height-msen.Height-handleWidth {\n\t\t\t\t\t\t\t\tynew = bn.Y + bn.Height - msen.Height - handleWidth\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif e := s.draggedHandle.SetYPixels(ynew); e != nil {\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trc := bh.toRECT()\n\t\t\t\t\t\tif s.Orientation() == Horizontal {\n\t\t\t\t\t\t\trc.Left -= int32(bp.X)\n\t\t\t\t\t\t\trc.Right -= int32(bp.X)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trc.Top -= int32(bp.Y)\n\t\t\t\t\t\t\trc.Bottom -= int32(bp.Y)\n\t\t\t\t\t\t}\n\t\t\t\t\t\twin.InvalidateRect(prev.Handle(), &rc, true)\n\n\t\t\t\t\t\trc = bh.toRECT()\n\t\t\t\t\t\tif s.Orientation() == Horizontal {\n\t\t\t\t\t\t\trc.Left -= int32(bn.X)\n\t\t\t\t\t\t\trc.Right -= int32(bn.X)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trc.Top -= int32(bn.Y)\n\t\t\t\t\t\t\trc.Bottom -= int32(bn.Y)\n\t\t\t\t\t\t}\n\t\t\t\t\t\twin.InvalidateRect(next.Handle(), &rc, true)\n\n\t\t\t\t\t\ts.draggedHandle.Invalidate()\n\t\t\t\t\t})\n\n\t\t\t\t\thandle.MouseUp().Attach(func(x, y int, button MouseButton) {\n\t\t\t\t\t\tif s.draggedHandle == nil {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdefer s.RequestLayout()\n\n\t\t\t\t\t\tdragHandle := s.draggedHandle\n\n\t\t\t\t\t\thandleIndex := s.children.Index(dragHandle)\n\t\t\t\t\t\tprev := closestVisibleWidget(handleIndex, -1)\n\t\t\t\t\t\tnext := closestVisibleWidget(handleIndex, 1)\n\n\t\t\t\t\t\ts.draggedHandle = nil\n\t\t\t\t\t\tdragHandle.SetBackground(NullBrush())\n\t\t\t\t\t\tprev.AsWidgetBase().invalidateBorderInParent()\n\t\t\t\t\t\tnext.AsWidgetBase().invalidateBorderInParent()\n\n\t\t\t\t\t\tprev.SetSuspended(true)\n\t\t\t\t\t\tdefer prev.Invalidate()\n\t\t\t\t\t\tdefer prev.SetSuspended(false)\n\t\t\t\t\t\tnext.SetSuspended(true)\n\t\t\t\t\t\tdefer next.Invalidate()\n\t\t\t\t\t\tdefer next.SetSuspended(false)\n\n\t\t\t\t\t\tbh := dragHandle.BoundsPixels()\n\t\t\t\t\t\tbp := prev.BoundsPixels()\n\t\t\t\t\t\tbn := next.BoundsPixels()\n\n\t\t\t\t\t\tvar sizePrev int\n\t\t\t\t\t\tvar sizeNext int\n\n\t\t\t\t\t\tif s.Orientation() == Horizontal {\n\t\t\t\t\t\t\tbp.Width = bh.X - bp.X\n\t\t\t\t\t\t\tbn.Width -= (bh.X + bh.Width) - bn.X\n\t\t\t\t\t\t\tbn.X = bh.X + bh.Width\n\t\t\t\t\t\t\tsizePrev = bp.Width\n\t\t\t\t\t\t\tsizeNext = bn.Width\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbp.Height = bh.Y - bp.Y\n\t\t\t\t\t\t\tbn.Height -= (bh.Y + bh.Height) - bn.Y\n\t\t\t\t\t\t\tbn.Y = bh.Y + bh.Height\n\t\t\t\t\t\t\tsizePrev = bp.Height\n\t\t\t\t\t\t\tsizeNext = bn.Height\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlayout := s.Layout().(*splitterLayout)\n\n\t\t\t\t\t\tprevItem := layout.hwnd2Item[prev.Handle()]\n\t\t\t\t\t\tprevItem.size = sizePrev\n\t\t\t\t\t\tprevItem.oldExplicitSize = sizePrev\n\n\t\t\t\t\t\tnextItem := layout.hwnd2Item[next.Handle()]\n\t\t\t\t\t\tnextItem.size = sizeNext\n\t\t\t\t\t\tnextItem.oldExplicitSize = sizeNext\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}\n\n\treturn s.ContainerBase.onInsertedWidget(index, widget)\n}\n\nfunc (s *Splitter) onRemovingWidget(index int, widget Widget) (err error) {\n\treturn s.ContainerBase.onRemovingWidget(index, widget)\n}\n\nfunc (s *Splitter) onRemovedWidget(index int, widget Widget) (err error) {\n\tdefer func() {\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\ts.updateMarginsForFocusEffect()\n\t}()\n\n\t_, isHandle := widget.(*splitterHandle)\n\tif !s.removing && isHandle && s.children.Len()%2 == 1 {\n\t\treturn newError(\"cannot remove splitter handle\")\n\t}\n\n\tif !isHandle {\n\t\tsl := s.layout.(*splitterLayout)\n\t\twidget.AsWidgetBase().Property(\"Visible\").Changed().Detach(sl.hwnd2Item[widget.Handle()].visibleChangedHandle)\n\t}\n\n\tif !isHandle && s.children.Len() > 1 {\n\t\tdefer func() {\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tvar handleIndex int\n\t\t\tif index == 0 {\n\t\t\t\thandleIndex = 0\n\t\t\t} else {\n\t\t\t\thandleIndex = index - 1\n\t\t\t}\n\n\t\t\ts.removing = true\n\t\t\thandle := s.children.items[handleIndex].window.(*splitterHandle)\n\n\t\t\tif err = handle.SetParent(nil); err == nil {\n\t\t\t\tsl := s.layout.(*splitterLayout)\n\n\t\t\t\tfor _, item := range sl.hwnd2Item {\n\t\t\t\t\titem.oldExplicitSize = 0\n\t\t\t\t\titem.keepSize = false\n\t\t\t\t}\n\n\t\t\t\tsl.resetNeeded = true\n\t\t\t\ts.RequestLayout()\n\n\t\t\t\thandle.Dispose()\n\t\t\t}\n\n\t\t\ts.removing = false\n\t\t}()\n\t}\n\n\terr = s.ContainerBase.onRemovedWidget(index, widget)\n\n\treturn\n}\n\nfunc (s *Splitter) onClearingWidgets() (err error) {\n\tpanic(\"not implemented\")\n}\n\nfunc (s *Splitter) onClearedWidgets() (err error) {\n\tpanic(\"not implemented\")\n}\n\nfunc (s *Splitter) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn s.layout.CreateLayoutItem(ctx)\n}\n"
  },
  {
    "path": "splitterhandle.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\nconst splitterHandleWindowClass = `\\o/ Walk_SplitterHandle_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(splitterHandleWindowClass)\n\t})\n}\n\ntype splitterHandle struct {\n\tWidgetBase\n}\n\nfunc newSplitterHandle(splitter *Splitter) (*splitterHandle, error) {\n\tif splitter == nil {\n\t\treturn nil, newError(\"splitter cannot be nil\")\n\t}\n\n\tsh := new(splitterHandle)\n\tsh.parent = splitter\n\n\tif err := InitWindow(\n\t\tsh,\n\t\tsplitter,\n\t\tsplitterHandleWindowClass,\n\t\twin.WS_CHILD|win.WS_VISIBLE,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsh.SetBackground(NullBrush())\n\n\tif err := sh.setAndClearStyleBits(0, win.WS_CLIPSIBLINGS); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn sh, nil\n}\n\nfunc (sh *splitterHandle) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_ERASEBKGND:\n\t\tif sh.Background() == nullBrushSingleton {\n\t\t\treturn 1\n\t\t}\n\n\tcase win.WM_PAINT:\n\t\tif sh.Background() == nullBrushSingleton {\n\t\t\tvar ps win.PAINTSTRUCT\n\n\t\t\twin.BeginPaint(hwnd, &ps)\n\t\t\tdefer win.EndPaint(hwnd, &ps)\n\n\t\t\treturn 0\n\t\t}\n\t}\n\n\treturn sh.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (sh *splitterHandle) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tvar orientation Orientation\n\tvar handleWidth int\n\n\tif splitter, ok := sh.Parent().(*Splitter); ok {\n\t\torientation = splitter.Orientation()\n\t\thandleWidth = splitter.HandleWidth()\n\t}\n\n\treturn &splitterHandleLayoutItem{\n\t\torientation: orientation,\n\t\thandleWidth: handleWidth,\n\t}\n}\n\ntype splitterHandleLayoutItem struct {\n\tLayoutItemBase\n\torientation Orientation\n\thandleWidth int\n}\n\nfunc (li *splitterHandleLayoutItem) LayoutFlags() LayoutFlags {\n\tif li.orientation == Horizontal {\n\t\treturn ShrinkableVert | GrowableVert | GreedyVert\n\t}\n\n\treturn ShrinkableHorz | GrowableHorz | GreedyHorz\n}\n\nfunc (li *splitterHandleLayoutItem) IdealSize() Size {\n\tvar size Size\n\tdpi := int(win.GetDpiForWindow(li.handle))\n\n\tif li.orientation == Horizontal {\n\t\tsize.Width = IntFrom96DPI(li.handleWidth, dpi)\n\t} else {\n\t\tsize.Height = IntFrom96DPI(li.handleWidth, dpi)\n\t}\n\n\treturn size\n}\n\nfunc (li *splitterHandleLayoutItem) MinSize() Size {\n\treturn li.IdealSize()\n}\n"
  },
  {
    "path": "splitterlayout.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"sort\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype splitterLayout struct {\n\tcontainer    Container\n\torientation  Orientation\n\tmargins96dpi Margins\n\thwnd2Item    map[win.HWND]*splitterLayoutItem\n\tresetNeeded  bool\n\tsuspended    bool\n}\n\ntype splitterLayoutItem struct {\n\tsize                 int // in native pixels\n\toldExplicitSize      int // in native pixels\n\tstretchFactor        int\n\tgrowth               int\n\tvisibleChangedHandle int\n\tfixed                bool\n\tkeepSize             bool\n\twasVisible           bool\n}\n\nfunc newSplitterLayout(orientation Orientation) *splitterLayout {\n\treturn &splitterLayout{\n\t\torientation: orientation,\n\t\thwnd2Item:   make(map[win.HWND]*splitterLayoutItem),\n\t}\n}\n\nfunc (l *splitterLayout) asLayoutBase() *LayoutBase {\n\treturn nil\n}\n\nfunc (l *splitterLayout) Container() Container {\n\treturn l.container\n}\n\nfunc (l *splitterLayout) SetContainer(value Container) {\n\tif value != l.container {\n\t\tif l.container != nil {\n\t\t\tl.container.SetLayout(nil)\n\t\t}\n\n\t\tl.container = value\n\n\t\tif value != nil && value.Layout() != Layout(l) {\n\t\t\tvalue.SetLayout(l)\n\n\t\t\tl.container.RequestLayout()\n\t\t}\n\t}\n}\n\nfunc (l *splitterLayout) Margins() Margins {\n\treturn l.margins96dpi\n}\n\nfunc (l *splitterLayout) SetMargins(value Margins) error {\n\tl.margins96dpi = value\n\n\tl.container.RequestLayout()\n\n\treturn nil\n}\n\nfunc (l *splitterLayout) Spacing() int {\n\treturn l.container.(*Splitter).handleWidth\n}\n\nfunc (l *splitterLayout) SetSpacing(value int) error {\n\treturn newError(\"not supported\")\n}\n\nfunc (l *splitterLayout) Orientation() Orientation {\n\treturn l.orientation\n}\n\nfunc (l *splitterLayout) SetOrientation(value Orientation) error {\n\tif value != l.orientation {\n\t\tswitch value {\n\t\tcase Horizontal, Vertical:\n\n\t\tdefault:\n\t\t\treturn newError(\"invalid Orientation value\")\n\t\t}\n\n\t\tl.orientation = value\n\n\t\tl.container.RequestLayout()\n\t}\n\n\treturn nil\n}\n\nfunc (l *splitterLayout) Fixed(widget Widget) bool {\n\titem := l.hwnd2Item[widget.Handle()]\n\treturn item != nil && item.fixed\n}\n\nfunc (l *splitterLayout) StretchFactor(widget Widget) int {\n\titem := l.hwnd2Item[widget.Handle()]\n\tif item == nil || item.stretchFactor == 0 {\n\t\treturn 1\n\t}\n\n\treturn item.stretchFactor\n}\n\nfunc (l *splitterLayout) SetStretchFactor(widget Widget, factor int) error {\n\tif factor != l.StretchFactor(widget) {\n\t\tif factor < 1 {\n\t\t\treturn newError(\"factor must be >= 1\")\n\t\t}\n\n\t\tif l.container == nil {\n\t\t\treturn newError(\"container required\")\n\t\t}\n\n\t\titem := l.hwnd2Item[widget.Handle()]\n\t\tif item == nil {\n\t\t\titem = new(splitterLayoutItem)\n\t\t\tl.hwnd2Item[widget.Handle()] = item\n\t\t}\n\n\t\titem.stretchFactor = factor\n\n\t\tl.container.RequestLayout()\n\t}\n\n\treturn nil\n}\n\nfunc (l *splitterLayout) anyNonFixed() bool {\n\tfor i, widget := range l.container.Children().items {\n\t\tif i%2 == 0 && widget.visible && !l.Fixed(widget.window.(Widget)) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// spaceUnavailableToRegularWidgets returns amount of space unavailable to regular widgets in native pixels.\nfunc (l *splitterLayout) spaceUnavailableToRegularWidgets() int {\n\tsplitter := l.container.(*Splitter)\n\n\tvar space int\n\n\tfor _, widget := range l.container.Children().items {\n\t\tif _, isHandle := widget.window.(*splitterHandle); isHandle && widget.visible {\n\t\t\tspace += splitter.handleWidth\n\t\t}\n\t}\n\n\treturn IntFrom96DPI(space, splitter.DPI())\n}\n\nfunc (l *splitterLayout) CreateLayoutItem(ctx *LayoutContext) ContainerLayoutItem {\n\tsplitter := l.container.(*Splitter)\n\n\thwnd2Item := make(map[win.HWND]*splitterLayoutItem, len(l.hwnd2Item))\n\tfor hwnd, sli := range l.hwnd2Item {\n\t\thwnd2Item[hwnd] = sli\n\t}\n\n\tli := &splitterContainerLayoutItem{\n\t\torientation:                    l.orientation,\n\t\thwnd2Item:                      hwnd2Item,\n\t\tspaceUnavailableToRegularItems: l.spaceUnavailableToRegularWidgets(),\n\t\thandleWidth96dpi:               splitter.HandleWidth(),\n\t\tanyNonFixed:                    l.anyNonFixed(),\n\t\tresetNeeded:                    l.resetNeeded,\n\t}\n\n\tli.margins96dpi = l.margins96dpi\n\n\treturn li\n}\n\ntype splitterContainerLayoutItem struct {\n\tContainerLayoutItemBase\n\torientation                    Orientation\n\thwnd2Item                      map[win.HWND]*splitterLayoutItem\n\tspaceUnavailableToRegularItems int // in native pixels\n\thandleWidth96dpi               int\n\tanyNonFixed                    bool\n\tresetNeeded                    bool\n}\n\nfunc (li *splitterContainerLayoutItem) StretchFactor(item LayoutItem) int {\n\tsli := li.hwnd2Item[item.Handle()]\n\tif sli == nil || sli.stretchFactor == 0 {\n\t\treturn 1\n\t}\n\n\treturn sli.stretchFactor\n}\n\nfunc (li *splitterContainerLayoutItem) LayoutFlags() LayoutFlags {\n\treturn boxLayoutFlags(li.orientation, li.children)\n}\n\nfunc (li *splitterContainerLayoutItem) MinSize() Size {\n\treturn li.MinSizeForSize(li.geometry.ClientSize)\n}\n\nfunc (li *splitterContainerLayoutItem) HeightForWidth(width int) int {\n\treturn li.MinSizeForSize(Size{width, li.geometry.ClientSize.Height}).Height\n}\n\nfunc (li *splitterContainerLayoutItem) MinSizeForSize(size Size) Size {\n\tmarginsPixels := MarginsFrom96DPI(li.margins96dpi, li.ctx.dpi)\n\tmargins := Size{marginsPixels.HNear + marginsPixels.HFar, marginsPixels.VNear + marginsPixels.VFar}\n\ts := margins\n\n\tfor _, item := range li.children {\n\t\tif !anyVisibleItemInHierarchy(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar cur Size\n\n\t\tif sli, ok := li.hwnd2Item[item.Handle()]; ok && li.anyNonFixed && sli.fixed {\n\t\t\tcur = item.Geometry().Size\n\n\t\t\tif li.orientation == Horizontal {\n\t\t\t\tcur.Height = 0\n\t\t\t} else {\n\t\t\t\tcur.Width = 0\n\t\t\t}\n\t\t} else {\n\t\t\tcur = li.MinSizeEffectiveForChild(item)\n\t\t}\n\n\t\tif li.orientation == Horizontal {\n\t\t\ts.Width += cur.Width\n\t\t\ts.Height = maxi(s.Height, margins.Height+cur.Height)\n\t\t} else {\n\t\t\ts.Height += cur.Height\n\t\t\ts.Width = maxi(s.Width, margins.Width+cur.Width)\n\t\t}\n\t}\n\n\treturn s\n}\n\nfunc (li *splitterContainerLayoutItem) PerformLayout() []LayoutResultItem {\n\tif li.resetNeeded {\n\t\tli.reset()\n\t}\n\n\tmargins := MarginsFrom96DPI(li.margins96dpi, li.ctx.dpi)\n\thandleWidthPixels := IntFrom96DPI(li.handleWidth96dpi, li.ctx.dpi)\n\tsizes := make([]int, len(li.children))\n\tcb := Rectangle{Width: li.geometry.ClientSize.Width, Height: li.geometry.ClientSize.Height}\n\tcb.X += margins.HNear\n\tcb.Y += margins.HFar\n\tcb.Width -= margins.HNear + margins.HFar\n\tcb.Height -= margins.VNear + margins.VFar\n\n\tvar space1, space2 int\n\tif li.orientation == Horizontal {\n\t\tspace1 = cb.Width - li.spaceUnavailableToRegularItems\n\t\tspace2 = cb.Height\n\t} else {\n\t\tspace1 = cb.Height - li.spaceUnavailableToRegularItems\n\t\tspace2 = cb.Width\n\t}\n\n\ttype WidgetItem struct {\n\t\titem       *splitterLayoutItem\n\t\tindex      int\n\t\tmin        int // in native pixels\n\t\tmax        int // in native pixels\n\t\tshrinkable bool\n\t\tgrowable   bool\n\t}\n\n\tvar wis []WidgetItem\n\n\tanyNonFixed := li.anyNonFixed\n\tvar totalRegularSize int\n\tfor i, item := range li.children {\n\t\tif !anyVisibleItemInHierarchy(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif i%2 == 0 {\n\t\t\tslItem := li.hwnd2Item[item.Handle()]\n\n\t\t\tvar wi *WidgetItem\n\n\t\t\tif !anyNonFixed || !slItem.fixed {\n\t\t\t\tvar min, max int\n\n\t\t\t\tminSize := li.MinSizeEffectiveForChild(item)\n\t\t\t\tmaxSize := item.Geometry().MaxSize\n\n\t\t\t\tif li.orientation == Horizontal {\n\t\t\t\t\tmin = minSize.Width\n\t\t\t\t\tmax = maxSize.Width\n\t\t\t\t} else {\n\t\t\t\t\tmin = minSize.Height\n\t\t\t\t\tmax = maxSize.Height\n\t\t\t\t}\n\n\t\t\t\twis = append(wis, WidgetItem{item: slItem, index: i, min: min, max: max})\n\n\t\t\t\twi = &wis[len(wis)-1]\n\t\t\t}\n\n\t\t\tsize := slItem.size\n\t\t\tvar idealSize Size\n\t\t\tif hfw, ok := item.(HeightForWidther); ok && li.orientation == Vertical && hfw.HasHeightForWidth() {\n\t\t\t\tidealSize.Height = hfw.HeightForWidth(space2)\n\t\t\t} else {\n\t\t\t\tswitch sizer := item.(type) {\n\t\t\t\tcase IdealSizer:\n\t\t\t\t\tidealSize = sizer.IdealSize()\n\n\t\t\t\tcase MinSizer:\n\t\t\t\t\tidealSize = sizer.MinSize()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif flags := item.LayoutFlags(); li.orientation == Horizontal {\n\t\t\t\tif flags&ShrinkableHorz == 0 {\n\t\t\t\t\tsize = maxi(size, idealSize.Width)\n\t\t\t\t\tif wi != nil {\n\t\t\t\t\t\twi.min = maxi(wi.min, size)\n\t\t\t\t\t}\n\t\t\t\t} else if wi != nil {\n\t\t\t\t\twi.shrinkable = true\n\t\t\t\t}\n\t\t\t\tif flags&GrowableHorz == 0 {\n\t\t\t\t\tsize = mini(size, idealSize.Width)\n\t\t\t\t\tif wi != nil {\n\t\t\t\t\t\twi.max = mini(wi.max, size)\n\t\t\t\t\t}\n\t\t\t\t} else if wi != nil {\n\t\t\t\t\twi.growable = true\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif flags&ShrinkableVert == 0 {\n\t\t\t\t\tsize = maxi(size, idealSize.Height)\n\t\t\t\t\tif wi != nil {\n\t\t\t\t\t\twi.min = maxi(wi.min, size)\n\t\t\t\t\t}\n\t\t\t\t} else if wi != nil {\n\t\t\t\t\twi.shrinkable = true\n\t\t\t\t}\n\t\t\t\tif flags&GrowableVert == 0 {\n\t\t\t\t\tsize = mini(size, idealSize.Height)\n\t\t\t\t\tif wi != nil {\n\t\t\t\t\t\twi.max = mini(wi.max, size)\n\t\t\t\t\t}\n\t\t\t\t} else if wi != nil {\n\t\t\t\t\twi.growable = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttotalRegularSize += size\n\t\t\tsizes[i] = size\n\t\t} else {\n\t\t\tsizes[i] = handleWidthPixels\n\t\t}\n\t}\n\n\tvar resultItems []LayoutResultItem\n\n\tdiff := space1 - totalRegularSize\n\n\tif diff != 0 && len(sizes) > 1 {\n\t\tfor diff != 0 {\n\t\t\tsort.SliceStable(wis, func(i, j int) bool {\n\t\t\t\ta := wis[i]\n\t\t\t\tb := wis[j]\n\n\t\t\t\tx := float64(a.item.growth) / float64(a.item.stretchFactor)\n\t\t\t\ty := float64(b.item.growth) / float64(b.item.stretchFactor)\n\n\t\t\t\tif diff > 0 {\n\t\t\t\t\treturn x < y && (a.max == 0 || a.max > a.item.size)\n\t\t\t\t} else {\n\t\t\t\t\treturn x > y && a.min < a.item.size\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tvar wi *WidgetItem\n\t\t\tfor _, wItem := range wis {\n\t\t\t\tif !wItem.item.keepSize && (diff < 0 && wItem.item.size > wItem.min || diff > 0 && (wItem.item.size < wItem.max || wItem.max == 0)) {\n\t\t\t\t\twi = &wItem\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif wi == nil {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif diff > 0 {\n\t\t\t\tsizes[wi.index]++\n\t\t\t\twi.item.size++\n\t\t\t\twi.item.growth++\n\t\t\t\tdiff--\n\t\t\t} else {\n\t\t\t\tsizes[wi.index]--\n\t\t\t\twi.item.size--\n\t\t\t\twi.item.growth--\n\t\t\t\tdiff++\n\t\t\t}\n\t\t}\n\t}\n\n\tvar p1 int\n\tif li.orientation == Horizontal {\n\t\tp1 = margins.HNear\n\t} else {\n\t\tp1 = margins.VNear\n\t}\n\tfor i, item := range li.children {\n\t\tif !anyVisibleItemInHierarchy(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\ts1 := sizes[i]\n\n\t\tvar x, y, w, h int\n\t\tif li.orientation == Horizontal {\n\t\t\tx, y, w, h = p1, margins.VNear, s1, space2\n\t\t} else {\n\t\t\tx, y, w, h = margins.HNear, p1, space2, s1\n\t\t}\n\n\t\tresultItems = append(resultItems, LayoutResultItem{Item: item, Bounds: Rectangle{x, y, w, h}})\n\n\t\tp1 += s1\n\t}\n\n\treturn resultItems\n}\n\nfunc (li *splitterContainerLayoutItem) reset() {\n\tvar anyVisible bool\n\n\tfor i, item := range li.children {\n\t\tsli := li.hwnd2Item[item.Handle()]\n\n\t\tvisible := anyVisibleItemInHierarchy(item)\n\t\tif !anyVisible && visible {\n\t\t\tanyVisible = true\n\t\t}\n\n\t\tif sli == nil || visible == sli.wasVisible {\n\t\t\tcontinue\n\t\t}\n\n\t\tsli.wasVisible = visible\n\n\t\tif _, isHandle := item.(*splitterHandleLayoutItem); !isHandle {\n\t\t\tvar handleIndex int\n\n\t\t\tif i == 0 {\n\t\t\t\tif len(li.children) > 1 {\n\t\t\t\t\thandleIndex = 1\n\t\t\t\t} else {\n\t\t\t\t\thandleIndex = -1\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\thandleIndex = i - 1\n\t\t\t}\n\n\t\t\tif handleIndex > -1 {\n\t\t\t\tli.children[handleIndex].AsLayoutItemBase().visible = visible\n\t\t\t}\n\t\t}\n\t}\n\n\tif li.Visible() != anyVisible {\n\t\tli.AsLayoutItemBase().visible = anyVisible\n\t}\n\n\tminSizes := make([]int, len(li.children))\n\tvar minSizesTotal int\n\tfor i, item := range li.children {\n\t\tif i%2 == 1 || !anyVisibleItemInHierarchy(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\tmin := li.MinSizeEffectiveForChild(item)\n\t\tif li.orientation == Horizontal {\n\t\t\tminSizes[i] = min.Width\n\t\t\tminSizesTotal += min.Width\n\t\t} else {\n\t\t\tminSizes[i] = min.Height\n\t\t\tminSizesTotal += min.Height\n\t\t}\n\t}\n\n\tvar regularSpace int\n\tif li.orientation == Horizontal {\n\t\tregularSpace = li.Geometry().ClientSize.Width - li.spaceUnavailableToRegularItems\n\t} else {\n\t\tregularSpace = li.Geometry().ClientSize.Height - li.spaceUnavailableToRegularItems\n\t}\n\n\tstretchTotal := 0\n\tfor i, item := range li.children {\n\t\tif i%2 == 1 || !anyVisibleItemInHierarchy(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif sli := li.hwnd2Item[item.Handle()]; sli == nil {\n\t\t\tli.hwnd2Item[item.Handle()] = &splitterLayoutItem{stretchFactor: 1}\n\t\t}\n\n\t\tstretchTotal += li.StretchFactor(item)\n\t}\n\n\tfor i, item := range li.children {\n\t\tif i%2 == 1 || !anyVisibleItemInHierarchy(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\tsli := li.hwnd2Item[item.Handle()]\n\t\tsli.growth = 0\n\t\tsli.keepSize = false\n\t\tif sli.oldExplicitSize > 0 {\n\t\t\tsli.size = sli.oldExplicitSize\n\t\t} else {\n\t\t\tsli.size = int(float64(li.StretchFactor(item)) / float64(stretchTotal) * float64(regularSpace))\n\t\t}\n\n\t\tmin := minSizes[i]\n\t\tif minSizesTotal <= regularSpace {\n\t\t\tif sli.size < min {\n\t\t\t\tsli.size = min\n\t\t\t}\n\t\t}\n\n\t\tif sli.size >= min {\n\t\t\tflags := item.LayoutFlags()\n\n\t\t\tif li.orientation == Horizontal && flags&GrowableHorz == 0 || li.orientation == Vertical && flags&GrowableVert == 0 {\n\t\t\t\tsli.size = min\n\t\t\t\tsli.keepSize = true\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "static.go",
    "content": "// Copyright 2018 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst staticWindowClass = `\\o/ Walk_Static_Class \\o/`\n\nvar staticWndProcPtr uintptr\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(staticWindowClass)\n\t\tstaticWndProcPtr = syscall.NewCallback(staticWndProc)\n\t})\n}\n\ntype static struct {\n\tWidgetBase\n\thwndStatic           win.HWND\n\torigStaticWndProcPtr uintptr\n\ttextAlignment        Alignment2D\n\ttextColor            Color\n}\n\nfunc (s *static) init(widget Widget, parent Container, style uint32) error {\n\tif err := InitWidget(\n\t\twidget,\n\t\tparent,\n\t\tstaticWindowClass,\n\t\twin.WS_VISIBLE|(style&win.WS_BORDER),\n\t\twin.WS_EX_CONTROLPARENT); err != nil {\n\t\treturn err\n\t}\n\n\tif s.hwndStatic = win.CreateWindowEx(\n\t\t0,\n\t\tsyscall.StringToUTF16Ptr(\"static\"),\n\t\tnil,\n\t\twin.WS_CHILD|win.WS_CLIPSIBLINGS|win.WS_VISIBLE|win.SS_LEFT|win.SS_NOTIFY|(style&^win.WS_BORDER),\n\t\twin.CW_USEDEFAULT,\n\t\twin.CW_USEDEFAULT,\n\t\twin.CW_USEDEFAULT,\n\t\twin.CW_USEDEFAULT,\n\t\ts.hWnd,\n\t\t0,\n\t\t0,\n\t\tnil,\n\t); s.hwndStatic == 0 {\n\t\treturn newError(\"creating static failed\")\n\t}\n\n\tif err := s.group.toolTip.AddTool(s); err != nil {\n\t\treturn err\n\t}\n\n\ts.origStaticWndProcPtr = win.SetWindowLongPtr(s.hwndStatic, win.GWLP_WNDPROC, staticWndProcPtr)\n\tif s.origStaticWndProcPtr == 0 {\n\t\treturn lastError(\"SetWindowLongPtr\")\n\t}\n\n\ts.applyFont(s.Font())\n\n\ts.SetBackground(nullBrushSingleton)\n\n\ts.SetAlignment(AlignHNearVCenter)\n\n\treturn nil\n}\n\nfunc (s *static) Dispose() {\n\tif s.hwndStatic != 0 {\n\t\twin.DestroyWindow(s.hwndStatic)\n\t\ts.hwndStatic = 0\n\t}\n\n\ts.WidgetBase.Dispose()\n}\n\nfunc (s *static) handleForToolTip() win.HWND {\n\treturn s.hwndStatic\n}\n\nfunc (s *static) applyEnabled(enabled bool) {\n\ts.WidgetBase.applyEnabled(enabled)\n\n\tsetWindowEnabled(s.hwndStatic, enabled)\n}\n\nfunc (s *static) applyFont(font *Font) {\n\ts.WidgetBase.applyFont(font)\n\n\tSetWindowFont(s.hwndStatic, font)\n}\n\nfunc (s *static) textAlignment1D() Alignment1D {\n\tswitch s.textAlignment {\n\tcase AlignHCenterVNear, AlignHCenterVCenter, AlignHCenterVFar:\n\t\treturn AlignCenter\n\n\tcase AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar:\n\t\treturn AlignFar\n\n\tdefault:\n\t\treturn AlignNear\n\t}\n}\n\nfunc (s *static) setTextAlignment1D(alignment Alignment1D) error {\n\tvar align Alignment2D\n\n\tswitch alignment {\n\tcase AlignCenter:\n\t\talign = AlignHCenterVCenter\n\n\tcase AlignFar:\n\t\talign = AlignHFarVCenter\n\n\tdefault:\n\t\talign = AlignHNearVCenter\n\t}\n\n\treturn s.setTextAlignment(align)\n}\n\nfunc (s *static) setTextAlignment(alignment Alignment2D) error {\n\tif alignment == s.textAlignment {\n\t\treturn nil\n\t}\n\n\tvar styleBit uint32\n\n\tswitch alignment {\n\tcase AlignHNearVNear, AlignHNearVCenter, AlignHNearVFar:\n\t\tstyleBit |= win.SS_LEFT\n\n\tcase AlignHCenterVNear, AlignHCenterVCenter, AlignHCenterVFar:\n\t\tstyleBit |= win.SS_CENTER\n\n\tcase AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar:\n\t\tstyleBit |= win.SS_RIGHT\n\t}\n\n\tif err := setAndClearWindowLongBits(s.hwndStatic, win.GWL_STYLE, styleBit, win.SS_LEFT|win.SS_CENTER|win.SS_RIGHT); err != nil {\n\t\treturn err\n\t}\n\n\ts.textAlignment = alignment\n\n\ts.Invalidate()\n\n\treturn nil\n}\n\nfunc (s *static) setText(text string) (changed bool, err error) {\n\tif text == s.text() {\n\t\treturn false, nil\n\t}\n\n\tif err := s.WidgetBase.setText(text); err != nil {\n\t\treturn false, err\n\t}\n\n\tif err := setWindowText(s.hwndStatic, text); err != nil {\n\t\treturn false, err\n\t}\n\n\ts.RequestLayout()\n\n\treturn true, nil\n}\n\nfunc (s *static) TextColor() Color {\n\treturn s.textColor\n}\n\nfunc (s *static) SetTextColor(c Color) {\n\ts.textColor = c\n\n\ts.Invalidate()\n}\n\nfunc (s *static) shrinkable() bool {\n\tif em, ok := s.window.(interface{ EllipsisMode() EllipsisMode }); ok {\n\t\treturn em.EllipsisMode() != EllipsisNone\n\t}\n\n\treturn false\n}\n\nfunc (s *static) updateStaticBounds() {\n\tvar format DrawTextFormat\n\n\tswitch s.textAlignment {\n\tcase AlignHNearVNear, AlignHNearVCenter, AlignHNearVFar:\n\t\tformat |= TextLeft\n\n\tcase AlignHCenterVNear, AlignHCenterVCenter, AlignHCenterVFar:\n\t\tformat |= TextCenter\n\n\tcase AlignHFarVNear, AlignHFarVCenter, AlignHFarVFar:\n\t\tformat |= TextRight\n\t}\n\n\tswitch s.textAlignment {\n\tcase AlignHNearVNear, AlignHCenterVNear, AlignHFarVNear:\n\t\tformat |= TextTop\n\n\tcase AlignHNearVCenter, AlignHCenterVCenter, AlignHFarVCenter:\n\t\tformat |= TextVCenter\n\n\tcase AlignHNearVFar, AlignHCenterVFar, AlignHFarVFar:\n\t\tformat |= TextBottom\n\t}\n\n\tcb := s.ClientBoundsPixels()\n\n\tif shrinkable := s.shrinkable(); shrinkable || format&TextVCenter != 0 || format&TextBottom != 0 {\n\t\tvar size Size\n\t\tif _, ok := s.window.(HeightForWidther); ok {\n\t\t\tsize = s.calculateTextSizeForWidth(cb.Width)\n\t\t} else {\n\t\t\tsize = s.calculateTextSize()\n\t\t}\n\n\t\tif shrinkable {\n\t\t\tvar text string\n\t\t\tif size.Width > cb.Width {\n\t\t\t\ttext = s.text()\n\t\t\t}\n\t\t\ts.SetToolTipText(text)\n\t\t}\n\n\t\tif format&TextVCenter != 0 || format&TextBottom != 0 {\n\t\t\tif format&TextVCenter != 0 {\n\t\t\t\tcb.Y += (cb.Height - size.Height) / 2\n\t\t\t} else {\n\t\t\t\tcb.Y += cb.Height - size.Height\n\t\t\t}\n\n\t\t\tcb.Height = size.Height\n\t\t}\n\t}\n\n\twin.MoveWindow(s.hwndStatic, int32(cb.X), int32(cb.Y), int32(cb.Width), int32(cb.Height), true)\n\n\ts.Invalidate()\n}\n\nfunc (s *static) WndProc(hwnd win.HWND, msg uint32, wp, lp uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_CTLCOLORSTATIC:\n\t\tif hBrush := s.handleWMCTLCOLOR(wp, uintptr(s.hWnd)); hBrush != 0 {\n\t\t\treturn hBrush\n\t\t}\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lp))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\ts.updateStaticBounds()\n\t}\n\n\treturn s.WidgetBase.WndProc(hwnd, msg, wp, lp)\n}\n\nfunc staticWndProc(hwnd win.HWND, msg uint32, wp, lp uintptr) uintptr {\n\tas, ok := windowFromHandle(win.GetParent(hwnd)).(interface{ asStatic() *static })\n\tif !ok {\n\t\treturn 0\n\t}\n\n\ts := as.asStatic()\n\n\tswitch msg {\n\tcase win.WM_NCHITTEST:\n\t\treturn win.HTCLIENT\n\n\tcase win.WM_MOUSEMOVE, win.WM_LBUTTONDOWN, win.WM_LBUTTONUP, win.WM_MBUTTONDOWN, win.WM_MBUTTONUP, win.WM_RBUTTONDOWN, win.WM_RBUTTONUP:\n\t\tm := win.MSG{\n\t\t\tHWnd:    hwnd,\n\t\t\tMessage: msg,\n\t\t\tWParam:  wp,\n\t\t\tLParam:  lp,\n\t\t\tPt:      win.POINT{int32(win.GET_X_LPARAM(lp)), int32(win.GET_Y_LPARAM(lp))},\n\t\t}\n\n\t\treturn s.group.toolTip.SendMessage(win.TTM_RELAYEVENT, 0, uintptr(unsafe.Pointer(&m)))\n\t}\n\n\treturn win.CallWindowProc(s.origStaticWndProcPtr, hwnd, msg, wp, lp)\n}\n\nfunc (s *static) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tvar layoutFlags LayoutFlags\n\tif s.textAlignment1D() != AlignNear {\n\t\tlayoutFlags = GrowableHorz\n\t} else if s.shrinkable() {\n\t\tlayoutFlags = ShrinkableHorz\n\t}\n\n\tidealSize := s.calculateTextSize()\n\tif s.hasStyleBits(win.WS_BORDER) {\n\t\tborder := s.IntFrom96DPI(1) * 2\n\t\tidealSize.Width += border\n\t\tidealSize.Height += border * 2\n\t}\n\n\treturn &staticLayoutItem{\n\t\tlayoutFlags: layoutFlags,\n\t\tidealSize:   idealSize,\n\t}\n}\n\ntype staticLayoutItem struct {\n\tLayoutItemBase\n\tlayoutFlags LayoutFlags\n\tidealSize   Size // in native pixels\n}\n\nfunc (li *staticLayoutItem) LayoutFlags() LayoutFlags {\n\treturn li.layoutFlags\n}\n\nfunc (li *staticLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *staticLayoutItem) MinSize() Size {\n\tif li.layoutFlags&ShrinkableHorz != 0 {\n\t\treturn Size{Height: li.idealSize.Height}\n\t}\n\n\treturn li.idealSize\n}\n"
  },
  {
    "path": "statusbar.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\n// StatusBar is a widget that displays status messages.\ntype StatusBar struct {\n\tWidgetBase\n\titems *StatusBarItemList\n}\n\n// NewStatusBar returns a new StatusBar as child of container parent.\nfunc NewStatusBar(parent Container) (*StatusBar, error) {\n\tsb := new(StatusBar)\n\n\tif err := InitWidget(\n\t\tsb,\n\t\tparent,\n\t\t\"msctls_statusbar32\",\n\t\twin.SBARS_SIZEGRIP|win.SBARS_TOOLTIPS,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsb.items = newStatusBarItemList(sb)\n\n\treturn sb, nil\n}\n\n// Items returns the list of items in the StatusBar.\nfunc (sb *StatusBar) Items() *StatusBarItemList {\n\treturn sb.items\n}\n\n// SetVisible sets whether the StatusBar is visible.\nfunc (sb *StatusBar) SetVisible(visible bool) {\n\tsb.WidgetBase.SetVisible(visible)\n\n\tsb.RequestLayout()\n}\n\nfunc (sb *StatusBar) ApplyDPI(dpi int) {\n\tsb.WidgetBase.ApplyDPI(dpi)\n\n\tsb.update()\n}\n\nfunc (sb *StatusBar) update() error {\n\tif err := sb.updateParts(); err != nil {\n\t\treturn err\n\t}\n\n\tfor i, item := range sb.items.items {\n\t\tif err := item.update(i); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tsb.SetVisible(sb.items.Len() > 0)\n\n\treturn nil\n}\n\nfunc (sb *StatusBar) updateParts() error {\n\titems := sb.items.items\n\n\tdpi := sb.DPI()\n\n\trightEdges := make([]int32, len(items))\n\tvar right int32\n\tfor i, item := range items {\n\t\tright += int32(IntFrom96DPI(item.width, dpi))\n\t\trightEdges[i] = right\n\t}\n\tvar rep *int32\n\tif len(rightEdges) > 0 {\n\t\trep = &rightEdges[0]\n\t}\n\n\tif len(rightEdges) == 1 {\n\t\trightEdges[0] = -1\n\t}\n\n\tif 0 == sb.SendMessage(\n\t\twin.SB_SETPARTS,\n\t\tuintptr(len(items)),\n\t\tuintptr(unsafe.Pointer(rep))) {\n\n\t\treturn newError(\"SB_SETPARTS\")\n\t}\n\n\treturn nil\n}\n\nfunc (sb *StatusBar) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_NOTIFY:\n\t\tnmhdr := (*win.NMHDR)(unsafe.Pointer(lParam))\n\n\t\tswitch nmhdr.Code {\n\t\tcase win.NM_CLICK:\n\t\t\tlpnm := (*win.NMMOUSE)(unsafe.Pointer(lParam))\n\t\t\tif n := int(lpnm.DwItemSpec); n >= 0 && n < sb.items.Len() {\n\t\t\t\tsb.items.At(n).raiseClicked()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn sb.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (*StatusBar) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn new(statusBarLayoutItem)\n}\n\ntype statusBarLayoutItem struct {\n\tLayoutItemBase\n}\n\nfunc (*statusBarLayoutItem) LayoutFlags() LayoutFlags {\n\treturn 0\n}\n\nfunc (*statusBarLayoutItem) IdealSize() Size {\n\treturn Size{}\n}\n\n// StatusBarItem represents a section of a StatusBar that can have its own icon,\n// text, tool tip text and width.\ntype StatusBarItem struct {\n\tsb               *StatusBar\n\ticon             *Icon\n\ttext             string\n\ttoolTipText      string\n\twidth            int\n\tclickedPublisher EventPublisher\n}\n\n// NewStatusBarItem returns a new StatusBarItem.\nfunc NewStatusBarItem() *StatusBarItem {\n\treturn &StatusBarItem{width: 100}\n}\n\n// Icon returns the Icon of the StatusBarItem.\nfunc (sbi *StatusBarItem) Icon() *Icon {\n\treturn sbi.icon\n}\n\n// SetIcon sets the Icon of the StatusBarItem.\nfunc (sbi *StatusBarItem) SetIcon(icon *Icon) error {\n\tif icon == sbi.icon {\n\t\treturn nil\n\t}\n\n\told := sbi.icon\n\tsbi.icon = icon\n\n\treturn sbi.maybeTry(sbi.updateIcon, func() { sbi.icon = old })\n}\n\n// Text returns the text of the StatusBarItem.\nfunc (sbi *StatusBarItem) Text() string {\n\treturn sbi.text\n}\n\n// SetText sets the text of the StatusBarItem.\nfunc (sbi *StatusBarItem) SetText(text string) error {\n\tif text == sbi.text {\n\t\treturn nil\n\t}\n\n\told := sbi.text\n\tsbi.text = text\n\n\treturn sbi.maybeTry(sbi.updateText, func() { sbi.text = old })\n}\n\n// ToolTipText returns the tool tip text of the StatusBarItem.\nfunc (sbi *StatusBarItem) ToolTipText() string {\n\treturn sbi.toolTipText\n}\n\n// SetToolTipText sets the tool tip text of the StatusBarItem.\nfunc (sbi *StatusBarItem) SetToolTipText(toolTipText string) error {\n\tif toolTipText == sbi.toolTipText {\n\t\treturn nil\n\t}\n\n\told := sbi.toolTipText\n\tsbi.toolTipText = toolTipText\n\n\treturn sbi.maybeTry(sbi.updateToolTipText, func() { sbi.toolTipText = old })\n}\n\n// Width returns the width of the StatusBarItem.\nfunc (sbi *StatusBarItem) Width() int {\n\treturn sbi.width\n}\n\n// SetWidth sets the width of the StatusBarItem.\nfunc (sbi *StatusBarItem) SetWidth(width int) error {\n\tif width == sbi.width {\n\t\treturn nil\n\t}\n\n\told := sbi.width\n\tsbi.width = width\n\n\tif sbi.sb != nil {\n\t\tsucceeded := false\n\t\tdefer func() {\n\t\t\tif !succeeded {\n\t\t\t\tsbi.width = old\n\t\t\t}\n\t\t}()\n\n\t\tif err := sbi.sb.updateParts(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tsucceeded = true\n\t}\n\n\treturn nil\n}\n\nfunc (sbi *StatusBarItem) Clicked() *Event {\n\treturn sbi.clickedPublisher.Event()\n}\n\nfunc (sbi *StatusBarItem) raiseClicked() {\n\tsbi.clickedPublisher.Publish()\n}\n\nfunc (sbi *StatusBarItem) maybeTry(f func(index int) error, rollback func()) error {\n\tif sbi.sb != nil {\n\t\tsucceeded := false\n\t\tdefer func() {\n\t\t\tif !succeeded {\n\t\t\t\trollback()\n\t\t\t}\n\t\t}()\n\n\t\tif err := f(sbi.sb.items.Index(sbi)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tsucceeded = true\n\t}\n\n\treturn nil\n}\n\nfunc (sbi *StatusBarItem) update(index int) error {\n\tif err := sbi.updateIcon(index); err != nil {\n\t\treturn err\n\t}\n\tif err := sbi.updateText(index); err != nil {\n\t\treturn err\n\t}\n\tif err := sbi.updateToolTipText(index); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (sbi *StatusBarItem) updateIcon(index int) error {\n\tvar hIcon win.HICON\n\tif sbi.icon != nil {\n\t\thIcon = sbi.icon.handleForDPI(sbi.sb.DPI())\n\t}\n\n\tif 0 == sbi.sb.SendMessage(\n\t\twin.SB_SETICON,\n\t\tuintptr(index),\n\t\tuintptr(hIcon)) {\n\n\t\treturn newError(\"SB_SETICON\")\n\t}\n\n\treturn nil\n}\n\nfunc (sbi *StatusBarItem) updateText(index int) error {\n\tutf16, err := syscall.UTF16PtrFromString(sbi.text)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif 0 == sbi.sb.SendMessage(\n\t\twin.SB_SETTEXT,\n\t\tuintptr(win.MAKEWORD(byte(index), 0)),\n\t\tuintptr(unsafe.Pointer(utf16))) {\n\n\t\treturn newError(\"SB_SETTEXT\")\n\t}\n\n\treturn nil\n}\n\nfunc (sbi *StatusBarItem) updateToolTipText(index int) error {\n\tutf16, err := syscall.UTF16PtrFromString(sbi.toolTipText)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsbi.sb.SendMessage(\n\t\twin.SB_SETTIPTEXT,\n\t\tuintptr(index),\n\t\tuintptr(unsafe.Pointer(utf16)))\n\n\treturn nil\n}\n\ntype StatusBarItemList struct {\n\tsb    *StatusBar\n\titems []*StatusBarItem\n}\n\nfunc newStatusBarItemList(statusBar *StatusBar) *StatusBarItemList {\n\treturn &StatusBarItemList{sb: statusBar}\n}\n\nfunc (l *StatusBarItemList) Add(item *StatusBarItem) error {\n\treturn l.Insert(len(l.items), item)\n}\n\nfunc (l *StatusBarItemList) At(index int) *StatusBarItem {\n\treturn l.items[index]\n}\n\nfunc (l *StatusBarItemList) Clear() error {\n\told := l.items\n\tl.items = l.items[:0]\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tl.items = old\n\n\t\t\tl.sb.update()\n\t\t}\n\t}()\n\n\tif err := l.sb.update(); err != nil {\n\t\treturn err\n\t}\n\n\tsucceeded = true\n\n\treturn nil\n}\n\nfunc (l *StatusBarItemList) Index(item *StatusBarItem) int {\n\tfor i, it := range l.items {\n\t\tif it == item {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (l *StatusBarItemList) Contains(item *StatusBarItem) bool {\n\treturn l.Index(item) > -1\n}\n\nfunc (l *StatusBarItemList) Insert(index int, item *StatusBarItem) error {\n\tif item.sb != nil {\n\t\treturn newError(\"item already contained in a StatusBar\")\n\t}\n\n\tl.items = append(l.items, nil)\n\tcopy(l.items[index+1:], l.items[index:])\n\tl.items[index] = item\n\n\titem.sb = l.sb\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\titem.sb = nil\n\t\t\tl.items = append(l.items[:index], l.items[index+1:]...)\n\n\t\t\tl.sb.update()\n\t\t}\n\t}()\n\n\tif err := l.sb.update(); err != nil {\n\t\treturn err\n\t}\n\n\tsucceeded = true\n\n\treturn nil\n}\n\nfunc (l *StatusBarItemList) Len() int {\n\treturn len(l.items)\n}\n\nfunc (l *StatusBarItemList) Remove(item *StatusBarItem) error {\n\tindex := l.Index(item)\n\tif index == -1 {\n\t\treturn nil\n\t}\n\n\treturn l.RemoveAt(index)\n}\n\nfunc (l *StatusBarItemList) RemoveAt(index int) error {\n\titem := l.items[index]\n\titem.sb = nil\n\n\tl.items = append(l.items[:index], l.items[index+1:]...)\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\tl.items = append(l.items, nil)\n\t\t\tcopy(l.items[index+1:], l.items[index:])\n\t\t\tl.items[index] = item\n\n\t\t\titem.sb = l.sb\n\n\t\t\tl.sb.update()\n\t\t}\n\t}()\n\n\tif err := l.sb.update(); err != nil {\n\t\treturn err\n\t}\n\n\tsucceeded = true\n\n\treturn nil\n}\n"
  },
  {
    "path": "stopwatch.go",
    "content": "// Copyright 2019 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"sort\"\n\t\"sync\"\n\t\"text/tabwriter\"\n\t\"time\"\n)\n\ntype stopwatchItem struct {\n\tstopwatchStats\n\tsubject     string\n\tstartedTime time.Time\n}\n\ntype stopwatchStats struct {\n\tcount int64\n\tmin   time.Duration\n\tmax   time.Duration\n\ttotal time.Duration\n}\n\nfunc (sws *stopwatchStats) Average() time.Duration {\n\tif sws.count == 0 {\n\t\treturn 0\n\t}\n\n\treturn time.Nanosecond * time.Duration(sws.total.Nanoseconds()/sws.count)\n}\n\ntype stopwatch struct {\n\tmutex        sync.Mutex\n\tsubject2item map[string]*stopwatchItem\n}\n\nfunc newStopwatch() *stopwatch {\n\treturn &stopwatch{\n\t\tsubject2item: make(map[string]*stopwatchItem),\n\t}\n}\n\nfunc (sw *stopwatch) Start(subject string) time.Time {\n\tsw.mutex.Lock()\n\tdefer sw.mutex.Unlock()\n\n\titem, ok := sw.subject2item[subject]\n\tif !ok {\n\t\titem = &stopwatchItem{subject: subject}\n\t\tsw.subject2item[subject] = item\n\t}\n\n\titem.startedTime = time.Now()\n\n\treturn item.startedTime\n}\n\nfunc (sw *stopwatch) Stop(subject string) time.Duration {\n\tsw.mutex.Lock()\n\tdefer sw.mutex.Unlock()\n\n\titem, ok := sw.subject2item[subject]\n\tif !ok || item.startedTime.IsZero() {\n\t\treturn 0\n\t}\n\n\tduration := time.Now().Sub(item.startedTime)\n\n\titem.count++\n\tif duration < item.min || item.min == 0 {\n\t\titem.min = duration\n\t}\n\tif duration > item.max {\n\t\titem.max = duration\n\t}\n\titem.total += duration\n\titem.startedTime = time.Time{}\n\n\treturn duration\n}\n\nfunc (sw *stopwatch) Cancel(subject string) {\n\tsw.mutex.Lock()\n\tdefer sw.mutex.Unlock()\n\n\titem, ok := sw.subject2item[subject]\n\tif !ok {\n\t\treturn\n\t}\n\n\titem.startedTime = time.Time{}\n}\n\nfunc (sw *stopwatch) Clear() {\n\tsw.mutex.Lock()\n\tdefer sw.mutex.Unlock()\n\n\tfor key := range sw.subject2item {\n\t\tdelete(sw.subject2item, key)\n\t}\n}\n\nfunc (sw *stopwatch) Print() {\n\tsw.mutex.Lock()\n\n\titems := make([]*stopwatchItem, 0, len(sw.subject2item))\n\tfor _, item := range sw.subject2item {\n\t\titems = append(items, item)\n\t}\n\n\tsw.mutex.Unlock()\n\n\tsort.Slice(items, func(i, j int) bool {\n\t\treturn items[i].total > items[j].total\n\t})\n\n\tvar buf bytes.Buffer\n\n\twriter := tabwriter.NewWriter(&buf, 0, 8, 2, ' ', tabwriter.AlignRight)\n\n\tfmt.Fprintln(writer, \"#\\tSubject\\tAverage\\tTotal\\tMin\\tMax\\t\\tCount\")\n\n\tfor i, item := range items {\n\t\tfmt.Fprintf(writer, \"%d\\t%s\\t%s\\t%s\\t%s\\t%s\\t\\t%d\\n\", i+1, item.subject, item.Average(), item.total, item.min, item.max, item.count)\n\t}\n\n\twriter.Flush()\n\n\tfmt.Print(buf.String())\n}\n"
  },
  {
    "path": "stringevent.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype stringEventHandlerInfo struct {\n\thandler StringEventHandler\n\tonce    bool\n}\n\ntype StringEventHandler func(s string)\n\ntype StringEvent struct {\n\thandlers []stringEventHandlerInfo\n}\n\nfunc (e *StringEvent) Attach(handler StringEventHandler) int {\n\thandlerInfo := stringEventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *StringEvent) Detach(handle int) {\n\te.handlers[handle].handler = nil\n}\n\nfunc (e *StringEvent) Once(handler StringEventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype StringEventPublisher struct {\n\tevent StringEvent\n}\n\nfunc (p *StringEventPublisher) Event() *StringEvent {\n\treturn &p.event\n}\n\nfunc (p *StringEventPublisher) Publish(s string) {\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler(s)\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "tableview.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"reflect\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst tableViewWindowClass = `\\o/ Walk_TableView_Class \\o/`\n\nvar (\n\twhite                       = win.COLORREF(RGB(255, 255, 255))\n\tcheckmark                   = string([]byte{0xE2, 0x9C, 0x94})\n\ttableViewFrozenLVWndProcPtr uintptr\n\ttableViewNormalLVWndProcPtr uintptr\n\ttableViewHdrWndProcPtr      uintptr\n)\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(tableViewWindowClass)\n\t\ttableViewFrozenLVWndProcPtr = syscall.NewCallback(tableViewFrozenLVWndProc)\n\t\ttableViewNormalLVWndProcPtr = syscall.NewCallback(tableViewNormalLVWndProc)\n\t\ttableViewHdrWndProcPtr = syscall.NewCallback(tableViewHdrWndProc)\n\t})\n}\n\nconst (\n\ttableViewCurrentIndexChangedTimerId = 1 + iota\n\ttableViewSelectedIndexesChangedTimerId\n)\n\ntype TableViewCfg struct {\n\tStyle              uint32\n\tCustomHeaderHeight int // in native pixels?\n\tCustomRowHeight    int // in native pixels?\n}\n\n// TableView is a model based widget for record centric, tabular data.\n//\n// TableView is implemented as a virtual mode list view to support quite large\n// amounts of data.\ntype TableView struct {\n\tWidgetBase\n\thwndFrozenLV                       win.HWND\n\thwndFrozenHdr                      win.HWND\n\tfrozenLVOrigWndProcPtr             uintptr\n\tfrozenHdrOrigWndProcPtr            uintptr\n\thwndNormalLV                       win.HWND\n\thwndNormalHdr                      win.HWND\n\tnormalLVOrigWndProcPtr             uintptr\n\tnormalHdrOrigWndProcPtr            uintptr\n\tstate                              *tableViewState\n\tcolumns                            *TableViewColumnList\n\tmodel                              TableModel\n\tprovidedModel                      interface{}\n\titemChecker                        ItemChecker\n\timageProvider                      ImageProvider\n\tstyler                             CellStyler\n\tstyle                              CellStyle\n\titemFont                           *Font\n\thIml                               win.HIMAGELIST\n\tusingSysIml                        bool\n\timageUintptr2Index                 map[uintptr]int32\n\tfilePath2IconIndex                 map[string]int32\n\trowsResetHandlerHandle             int\n\trowChangedHandlerHandle            int\n\trowsChangedHandlerHandle           int\n\trowsInsertedHandlerHandle          int\n\trowsRemovedHandlerHandle           int\n\tsortChangedHandlerHandle           int\n\tselectedIndexes                    []int\n\tprevIndex                          int\n\tcurrentIndex                       int\n\titemIndexOfLastMouseButtonDown     int\n\thwndItemChanged                    win.HWND\n\tcurrentIndexChangedPublisher       EventPublisher\n\tselectedIndexesChangedPublisher    EventPublisher\n\titemActivatedPublisher             EventPublisher\n\tcolumnClickedPublisher             IntEventPublisher\n\tcolumnsOrderableChangedPublisher   EventPublisher\n\tcolumnsSizableChangedPublisher     EventPublisher\n\titemCountChangedPublisher          EventPublisher\n\tpublishNextSelClear                bool\n\tinSetSelectedIndexes               bool\n\tlastColumnStretched                bool\n\tpersistent                         bool\n\titemStateChangedEventDelay         int\n\tthemeNormalBGColor                 Color\n\tthemeNormalTextColor               Color\n\tthemeSelectedBGColor               Color\n\tthemeSelectedTextColor             Color\n\tthemeSelectedNotFocusedBGColor     Color\n\titemBGColor                        Color\n\titemTextColor                      Color\n\talternatingRowBGColor              Color\n\talternatingRowTextColor            Color\n\talternatingRowBG                   bool\n\tdelayedCurrentIndexChangedCanceled bool\n\tsortedColumnIndex                  int\n\tsortOrder                          SortOrder\n\tformActivatingHandle               int\n\tcustomHeaderHeight                 int // in native pixels?\n\tcustomRowHeight                    int // in native pixels?\n\tdpiOfPrevStretchLastColumn         int\n\tscrolling                          bool\n\tinSetCurrentIndex                  bool\n\tinMouseEvent                       bool\n\thasFrozenColumn                    bool\n\tbusyStretchingLastColumn           bool\n\tfocused                            bool\n\tignoreNowhere                      bool\n\tupdateLVSizesNeedsSpecialCare      bool\n\tscrollbarOrientation               Orientation\n\tcurrentItemChangedPublisher        EventPublisher\n\tcurrentItemID                      interface{}\n\trestoringCurrentItemOnReset        bool\n}\n\n// NewTableView creates and returns a *TableView as child of the specified\n// Container.\nfunc NewTableView(parent Container) (*TableView, error) {\n\treturn NewTableViewWithStyle(parent, win.LVS_SHOWSELALWAYS)\n}\n\n// NewTableViewWithStyle creates and returns a *TableView as child of the specified\n// Container and with the provided additional style bits set.\nfunc NewTableViewWithStyle(parent Container, style uint32) (*TableView, error) {\n\treturn NewTableViewWithCfg(parent, &TableViewCfg{Style: style})\n}\n\n// NewTableViewWithCfg creates and returns a *TableView as child of the specified\n// Container and with the provided additional configuration.\nfunc NewTableViewWithCfg(parent Container, cfg *TableViewCfg) (*TableView, error) {\n\ttv := &TableView{\n\t\timageUintptr2Index:          make(map[uintptr]int32),\n\t\tfilePath2IconIndex:          make(map[string]int32),\n\t\tformActivatingHandle:        -1,\n\t\tcustomHeaderHeight:          cfg.CustomHeaderHeight,\n\t\tcustomRowHeight:             cfg.CustomRowHeight,\n\t\tscrollbarOrientation:        Horizontal | Vertical,\n\t\trestoringCurrentItemOnReset: true,\n\t}\n\n\ttv.columns = newTableViewColumnList(tv)\n\n\tif err := InitWidget(\n\t\ttv,\n\t\tparent,\n\t\ttableViewWindowClass,\n\t\twin.WS_BORDER|win.WS_VISIBLE,\n\t\twin.WS_EX_CONTROLPARENT); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\ttv.Dispose()\n\t\t}\n\t}()\n\n\tvar rowHeightStyle uint32\n\tif cfg.CustomRowHeight > 0 {\n\t\trowHeightStyle = win.LVS_OWNERDRAWFIXED\n\t}\n\n\tif tv.hwndFrozenLV = win.CreateWindowEx(\n\t\t0,\n\t\tsyscall.StringToUTF16Ptr(\"SysListView32\"),\n\t\tnil,\n\t\twin.WS_CHILD|win.WS_CLIPSIBLINGS|win.WS_TABSTOP|win.WS_VISIBLE|win.LVS_OWNERDATA|win.LVS_REPORT|cfg.Style|rowHeightStyle,\n\t\twin.CW_USEDEFAULT,\n\t\twin.CW_USEDEFAULT,\n\t\twin.CW_USEDEFAULT,\n\t\twin.CW_USEDEFAULT,\n\t\ttv.hWnd,\n\t\t0,\n\t\t0,\n\t\tnil,\n\t); tv.hwndFrozenLV == 0 {\n\t\treturn nil, newError(\"creating frozen lv failed\")\n\t}\n\n\ttv.frozenLVOrigWndProcPtr = win.SetWindowLongPtr(tv.hwndFrozenLV, win.GWLP_WNDPROC, tableViewFrozenLVWndProcPtr)\n\tif tv.frozenLVOrigWndProcPtr == 0 {\n\t\treturn nil, lastError(\"SetWindowLongPtr\")\n\t}\n\n\ttv.hwndFrozenHdr = win.HWND(win.SendMessage(tv.hwndFrozenLV, win.LVM_GETHEADER, 0, 0))\n\ttv.frozenHdrOrigWndProcPtr = win.SetWindowLongPtr(tv.hwndFrozenHdr, win.GWLP_WNDPROC, tableViewHdrWndProcPtr)\n\tif tv.frozenHdrOrigWndProcPtr == 0 {\n\t\treturn nil, lastError(\"SetWindowLongPtr\")\n\t}\n\n\tif tv.hwndNormalLV = win.CreateWindowEx(\n\t\t0,\n\t\tsyscall.StringToUTF16Ptr(\"SysListView32\"),\n\t\tnil,\n\t\twin.WS_CHILD|win.WS_CLIPSIBLINGS|win.WS_TABSTOP|win.WS_VISIBLE|win.LVS_OWNERDATA|win.LVS_REPORT|cfg.Style|rowHeightStyle,\n\t\twin.CW_USEDEFAULT,\n\t\twin.CW_USEDEFAULT,\n\t\twin.CW_USEDEFAULT,\n\t\twin.CW_USEDEFAULT,\n\t\ttv.hWnd,\n\t\t0,\n\t\t0,\n\t\tnil,\n\t); tv.hwndNormalLV == 0 {\n\t\treturn nil, newError(\"creating normal lv failed\")\n\t}\n\n\ttv.normalLVOrigWndProcPtr = win.SetWindowLongPtr(tv.hwndNormalLV, win.GWLP_WNDPROC, tableViewNormalLVWndProcPtr)\n\tif tv.normalLVOrigWndProcPtr == 0 {\n\t\treturn nil, lastError(\"SetWindowLongPtr\")\n\t}\n\n\ttv.hwndNormalHdr = win.HWND(win.SendMessage(tv.hwndNormalLV, win.LVM_GETHEADER, 0, 0))\n\ttv.normalHdrOrigWndProcPtr = win.SetWindowLongPtr(tv.hwndNormalHdr, win.GWLP_WNDPROC, tableViewHdrWndProcPtr)\n\tif tv.normalHdrOrigWndProcPtr == 0 {\n\t\treturn nil, lastError(\"SetWindowLongPtr\")\n\t}\n\n\ttv.SetPersistent(true)\n\n\texStyle := win.SendMessage(tv.hwndFrozenLV, win.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)\n\texStyle |= win.LVS_EX_DOUBLEBUFFER | win.LVS_EX_FULLROWSELECT | win.LVS_EX_HEADERDRAGDROP | win.LVS_EX_LABELTIP | win.LVS_EX_SUBITEMIMAGES\n\twin.SendMessage(tv.hwndFrozenLV, win.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle)\n\twin.SendMessage(tv.hwndNormalLV, win.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle)\n\n\tif hr := win.SetWindowTheme(tv.hwndFrozenLV, syscall.StringToUTF16Ptr(\"Explorer\"), nil); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"SetWindowTheme\", hr)\n\t}\n\tif hr := win.SetWindowTheme(tv.hwndNormalLV, syscall.StringToUTF16Ptr(\"Explorer\"), nil); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"SetWindowTheme\", hr)\n\t}\n\n\twin.SendMessage(tv.hwndFrozenLV, win.WM_CHANGEUISTATE, uintptr(win.MAKELONG(win.UIS_SET, win.UISF_HIDEFOCUS)), 0)\n\twin.SendMessage(tv.hwndNormalLV, win.WM_CHANGEUISTATE, uintptr(win.MAKELONG(win.UIS_SET, win.UISF_HIDEFOCUS)), 0)\n\n\ttv.group.toolTip.addTool(tv.hwndFrozenHdr, false)\n\ttv.group.toolTip.addTool(tv.hwndNormalHdr, false)\n\n\ttv.applyFont(parent.Font())\n\n\ttv.style.dpi = tv.DPI()\n\ttv.ApplySysColors()\n\n\ttv.currentIndex = -1\n\n\ttv.GraphicsEffects().Add(InteractionEffect)\n\ttv.GraphicsEffects().Add(FocusEffect)\n\n\ttv.MustRegisterProperty(\"ColumnsOrderable\", NewBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn tv.ColumnsOrderable()\n\t\t},\n\t\tfunc(b bool) error {\n\t\t\ttv.SetColumnsOrderable(b)\n\t\t\treturn nil\n\t\t},\n\t\ttv.columnsOrderableChangedPublisher.Event()))\n\n\ttv.MustRegisterProperty(\"ColumnsSizable\", NewBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn tv.ColumnsSizable()\n\t\t},\n\t\tfunc(b bool) error {\n\t\t\treturn tv.SetColumnsSizable(b)\n\t\t},\n\t\ttv.columnsSizableChangedPublisher.Event()))\n\n\ttv.MustRegisterProperty(\"CurrentIndex\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn tv.CurrentIndex()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn tv.SetCurrentIndex(assertIntOr(v, -1))\n\t\t},\n\t\ttv.CurrentIndexChanged()))\n\n\ttv.MustRegisterProperty(\"CurrentItem\", NewReadOnlyProperty(\n\t\tfunc() interface{} {\n\t\t\tif i := tv.CurrentIndex(); i > -1 {\n\t\t\t\tif rm, ok := tv.providedModel.(reflectModel); ok {\n\t\t\t\t\treturn reflect.ValueOf(rm.Items()).Index(i).Interface()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\ttv.CurrentIndexChanged()))\n\n\ttv.MustRegisterProperty(\"HasCurrentItem\", NewReadOnlyBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn tv.CurrentIndex() != -1\n\t\t},\n\t\ttv.CurrentIndexChanged()))\n\n\ttv.MustRegisterProperty(\"ItemCount\", NewReadOnlyProperty(\n\t\tfunc() interface{} {\n\t\t\tif tv.model == nil {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn tv.model.RowCount()\n\t\t},\n\t\ttv.itemCountChangedPublisher.Event()))\n\n\ttv.MustRegisterProperty(\"SelectedCount\", NewReadOnlyProperty(\n\t\tfunc() interface{} {\n\t\t\treturn len(tv.selectedIndexes)\n\t\t},\n\t\ttv.SelectedIndexesChanged()))\n\n\tsucceeded = true\n\n\treturn tv, nil\n}\n\nfunc (tv *TableView) asTableView() *TableView {\n\treturn tv\n}\n\n// Dispose releases the operating system resources, associated with the\n// *TableView.\nfunc (tv *TableView) Dispose() {\n\ttv.columns.unsetColumnsTV()\n\n\ttv.disposeImageListAndCaches()\n\n\tif tv.hWnd != 0 {\n\t\tif !win.KillTimer(tv.hWnd, tableViewCurrentIndexChangedTimerId) {\n\t\t\tlastError(\"KillTimer\")\n\t\t}\n\t\tif !win.KillTimer(tv.hWnd, tableViewSelectedIndexesChangedTimerId) {\n\t\t\tlastError(\"KillTimer\")\n\t\t}\n\t}\n\n\tif tv.hwndFrozenLV != 0 {\n\t\ttv.group.toolTip.removeTool(tv.hwndFrozenHdr)\n\t\twin.DestroyWindow(tv.hwndFrozenLV)\n\t\ttv.hwndFrozenLV = 0\n\t}\n\n\tif tv.hwndNormalLV != 0 {\n\t\ttv.group.toolTip.removeTool(tv.hwndNormalHdr)\n\t\twin.DestroyWindow(tv.hwndNormalLV)\n\t\ttv.hwndNormalLV = 0\n\t}\n\n\tif tv.formActivatingHandle > -1 {\n\t\tif form := tv.Form(); form != nil {\n\t\t\tform.Activating().Detach(tv.formActivatingHandle)\n\t\t}\n\t\ttv.formActivatingHandle = -1\n\t}\n\n\ttv.WidgetBase.Dispose()\n}\n\nfunc (tv *TableView) applyEnabled(enabled bool) {\n\ttv.WidgetBase.applyEnabled(enabled)\n\n\twin.EnableWindow(tv.hwndFrozenLV, enabled)\n\twin.EnableWindow(tv.hwndNormalLV, enabled)\n}\n\nfunc (tv *TableView) applyFont(font *Font) {\n\tif tv.customHeaderHeight > 0 || tv.customRowHeight > 0 {\n\t\treturn\n\t}\n\n\ttv.WidgetBase.applyFont(font)\n\n\thFont := uintptr(font.handleForDPI(tv.DPI()))\n\n\twin.SendMessage(tv.hwndFrozenLV, win.WM_SETFONT, hFont, 0)\n\twin.SendMessage(tv.hwndNormalLV, win.WM_SETFONT, hFont, 0)\n}\n\nfunc (tv *TableView) ApplyDPI(dpi int) {\n\ttv.style.dpi = dpi\n\tif tv.style.canvas != nil {\n\t\ttv.style.canvas.dpi = dpi\n\t}\n\n\ttv.WidgetBase.ApplyDPI(dpi)\n\n\tfor _, column := range tv.columns.items {\n\t\tcolumn.update()\n\t}\n\n\tif tv.hIml != 0 {\n\t\ttv.disposeImageListAndCaches()\n\n\t\tif bmp, err := NewBitmapForDPI(SizeFrom96DPI(Size{16, 16}, dpi), dpi); err == nil {\n\t\t\ttv.applyImageListForImage(bmp)\n\t\t\tbmp.Dispose()\n\t\t}\n\t}\n}\n\nfunc (tv *TableView) ApplySysColors() {\n\ttv.WidgetBase.ApplySysColors()\n\n\t// As some combinations of property and state may be invalid for any theme,\n\t// we set some defaults here.\n\ttv.themeNormalBGColor = Color(win.GetSysColor(win.COLOR_WINDOW))\n\ttv.themeNormalTextColor = Color(win.GetSysColor(win.COLOR_WINDOWTEXT))\n\ttv.themeSelectedBGColor = tv.themeNormalBGColor\n\ttv.themeSelectedTextColor = tv.themeNormalTextColor\n\ttv.themeSelectedNotFocusedBGColor = tv.themeNormalBGColor\n\ttv.alternatingRowBGColor = Color(win.GetSysColor(win.COLOR_BTNFACE))\n\ttv.alternatingRowTextColor = Color(win.GetSysColor(win.COLOR_BTNTEXT))\n\n\ttype item struct {\n\t\tstateID    int32\n\t\tpropertyID int32\n\t\tcolor      *Color\n\t}\n\n\tgetThemeColor := func(theme win.HTHEME, partId int32, items []item) {\n\t\tfor _, item := range items {\n\t\t\tvar c win.COLORREF\n\t\t\tif result := win.GetThemeColor(theme, partId, item.stateID, item.propertyID, &c); !win.FAILED(result) {\n\t\t\t\t(*item.color) = Color(c)\n\t\t\t}\n\t\t}\n\t}\n\n\tif hThemeListView := win.OpenThemeData(tv.hwndNormalLV, syscall.StringToUTF16Ptr(\"Listview\")); hThemeListView != 0 {\n\t\tdefer win.CloseThemeData(hThemeListView)\n\n\t\tgetThemeColor(hThemeListView, win.LVP_LISTITEM, []item{\n\t\t\t{win.LISS_NORMAL, win.TMT_FILLCOLOR, &tv.themeNormalBGColor},\n\t\t\t{win.LISS_NORMAL, win.TMT_TEXTCOLOR, &tv.themeNormalTextColor},\n\t\t\t{win.LISS_SELECTED, win.TMT_FILLCOLOR, &tv.themeSelectedBGColor},\n\t\t\t{win.LISS_SELECTED, win.TMT_TEXTCOLOR, &tv.themeSelectedTextColor},\n\t\t\t{win.LISS_SELECTEDNOTFOCUS, win.TMT_FILLCOLOR, &tv.themeSelectedNotFocusedBGColor},\n\t\t})\n\t} else {\n\t\t// The others already have been retrieved above.\n\t\ttv.themeSelectedBGColor = Color(win.GetSysColor(win.COLOR_HIGHLIGHT))\n\t\ttv.themeSelectedTextColor = Color(win.GetSysColor(win.COLOR_HIGHLIGHTTEXT))\n\t\ttv.themeSelectedNotFocusedBGColor = Color(win.GetSysColor(win.COLOR_BTNFACE))\n\t}\n\n\tif hThemeButton := win.OpenThemeData(tv.hwndNormalLV, syscall.StringToUTF16Ptr(\"BUTTON\")); hThemeButton != 0 {\n\t\tdefer win.CloseThemeData(hThemeButton)\n\n\t\tgetThemeColor(hThemeButton, win.BP_PUSHBUTTON, []item{\n\t\t\t{win.PBS_NORMAL, win.TMT_FILLCOLOR, &tv.alternatingRowBGColor},\n\t\t\t{win.PBS_NORMAL, win.TMT_TEXTCOLOR, &tv.alternatingRowTextColor},\n\t\t})\n\t}\n\n\twin.SendMessage(tv.hwndNormalLV, win.LVM_SETBKCOLOR, 0, uintptr(tv.themeNormalBGColor))\n\twin.SendMessage(tv.hwndFrozenLV, win.LVM_SETBKCOLOR, 0, uintptr(tv.themeNormalBGColor))\n}\n\n// ColumnsOrderable returns if the user can reorder columns by dragging and\n// dropping column headers.\nfunc (tv *TableView) ColumnsOrderable() bool {\n\texStyle := win.SendMessage(tv.hwndNormalLV, win.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)\n\treturn exStyle&win.LVS_EX_HEADERDRAGDROP > 0\n}\n\n// SetColumnsOrderable sets if the user can reorder columns by dragging and\n// dropping column headers.\nfunc (tv *TableView) SetColumnsOrderable(enabled bool) {\n\tvar hwnd win.HWND\n\tif tv.hasFrozenColumn {\n\t\thwnd = tv.hwndFrozenLV\n\t} else {\n\t\thwnd = tv.hwndNormalLV\n\t}\n\n\texStyle := win.SendMessage(hwnd, win.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)\n\tif enabled {\n\t\texStyle |= win.LVS_EX_HEADERDRAGDROP\n\t} else {\n\t\texStyle &^= win.LVS_EX_HEADERDRAGDROP\n\t}\n\twin.SendMessage(tv.hwndFrozenLV, win.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle)\n\twin.SendMessage(tv.hwndNormalLV, win.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle)\n\n\ttv.columnsOrderableChangedPublisher.Publish()\n}\n\n// ColumnsSizable returns if the user can change column widths by dragging\n// dividers in the header.\nfunc (tv *TableView) ColumnsSizable() bool {\n\tstyle := win.GetWindowLong(tv.hwndNormalHdr, win.GWL_STYLE)\n\n\treturn style&win.HDS_NOSIZING == 0\n}\n\n// SetColumnsSizable sets if the user can change column widths by dragging\n// dividers in the header.\nfunc (tv *TableView) SetColumnsSizable(b bool) error {\n\tupdateStyle := func(headerHWnd win.HWND) error {\n\t\tstyle := win.GetWindowLong(headerHWnd, win.GWL_STYLE)\n\n\t\tif b {\n\t\t\tstyle &^= win.HDS_NOSIZING\n\t\t} else {\n\t\t\tstyle |= win.HDS_NOSIZING\n\t\t}\n\n\t\tif 0 == win.SetWindowLong(headerHWnd, win.GWL_STYLE, style) {\n\t\t\treturn lastError(\"SetWindowLong(GWL_STYLE)\")\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif err := updateStyle(tv.hwndFrozenHdr); err != nil {\n\t\treturn err\n\t}\n\tif err := updateStyle(tv.hwndNormalHdr); err != nil {\n\t\treturn err\n\t}\n\n\ttv.columnsSizableChangedPublisher.Publish()\n\n\treturn nil\n}\n\n// ContextMenuLocation returns selected item position in screen coordinates in native pixels.\nfunc (tv *TableView) ContextMenuLocation() Point {\n\tidx := win.SendMessage(tv.hwndNormalLV, win.LVM_GETSELECTIONMARK, 0, 0)\n\trc := win.RECT{Left: win.LVIR_BOUNDS}\n\tif 0 == win.SendMessage(tv.hwndNormalLV, win.LVM_GETITEMRECT, idx, uintptr(unsafe.Pointer(&rc))) {\n\t\treturn tv.WidgetBase.ContextMenuLocation()\n\t}\n\tvar pt win.POINT\n\tif tv.RightToLeftReading() {\n\t\tpt.X = rc.Right\n\t} else {\n\t\tpt.X = rc.Left\n\t}\n\tpt.X = rc.Bottom\n\twindowTrimToClientBounds(tv.hwndNormalLV, &pt)\n\twin.ClientToScreen(tv.hwndNormalLV, &pt)\n\treturn pointPixelsFromPOINT(pt)\n}\n\n// SortableByHeaderClick returns if the user can change sorting by clicking the header.\nfunc (tv *TableView) SortableByHeaderClick() bool {\n\treturn !hasWindowLongBits(tv.hwndFrozenLV, win.GWL_STYLE, win.LVS_NOSORTHEADER) ||\n\t\t!hasWindowLongBits(tv.hwndNormalLV, win.GWL_STYLE, win.LVS_NOSORTHEADER)\n}\n\n// HeaderHidden returns whether the column header is hidden.\nfunc (tv *TableView) HeaderHidden() bool {\n\tstyle := win.GetWindowLong(tv.hwndNormalLV, win.GWL_STYLE)\n\n\treturn style&win.LVS_NOCOLUMNHEADER != 0\n}\n\n// SetHeaderHidden sets whether the column header is hidden.\nfunc (tv *TableView) SetHeaderHidden(hidden bool) error {\n\tif err := ensureWindowLongBits(tv.hwndFrozenLV, win.GWL_STYLE, win.LVS_NOCOLUMNHEADER, hidden); err != nil {\n\t\treturn err\n\t}\n\n\treturn ensureWindowLongBits(tv.hwndNormalLV, win.GWL_STYLE, win.LVS_NOCOLUMNHEADER, hidden)\n}\n\n// AlternatingRowBG returns the alternating row background.\nfunc (tv *TableView) AlternatingRowBG() bool {\n\treturn tv.alternatingRowBG\n}\n\n// SetAlternatingRowBG sets the alternating row background.\nfunc (tv *TableView) SetAlternatingRowBG(enabled bool) {\n\ttv.alternatingRowBG = enabled\n\n\ttv.Invalidate()\n}\n\n// Gridlines returns if the rows are separated by grid lines.\nfunc (tv *TableView) Gridlines() bool {\n\texStyle := win.SendMessage(tv.hwndNormalLV, win.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)\n\treturn exStyle&win.LVS_EX_GRIDLINES > 0\n}\n\n// SetGridlines sets if the rows are separated by grid lines.\nfunc (tv *TableView) SetGridlines(enabled bool) {\n\tvar hwnd win.HWND\n\tif tv.hasFrozenColumn {\n\t\thwnd = tv.hwndFrozenLV\n\t} else {\n\t\thwnd = tv.hwndNormalLV\n\t}\n\n\texStyle := win.SendMessage(hwnd, win.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)\n\tif enabled {\n\t\texStyle |= win.LVS_EX_GRIDLINES\n\t} else {\n\t\texStyle &^= win.LVS_EX_GRIDLINES\n\t}\n\twin.SendMessage(tv.hwndFrozenLV, win.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle)\n\twin.SendMessage(tv.hwndNormalLV, win.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle)\n}\n\n// Columns returns the list of columns.\nfunc (tv *TableView) Columns() *TableViewColumnList {\n\treturn tv.columns\n}\n\n// VisibleColumnsInDisplayOrder returns a slice of visible columns in display\n// order.\nfunc (tv *TableView) VisibleColumnsInDisplayOrder() []*TableViewColumn {\n\tvisibleCols := tv.visibleColumns()\n\tindices := make([]int32, len(visibleCols))\n\n\tfrozenCount := tv.visibleFrozenColumnCount()\n\tnormalCount := len(visibleCols) - frozenCount\n\n\tif frozenCount > 0 {\n\t\tif win.FALSE == win.SendMessage(tv.hwndFrozenLV, win.LVM_GETCOLUMNORDERARRAY, uintptr(frozenCount), uintptr(unsafe.Pointer(&indices[0]))) {\n\t\t\tnewError(\"LVM_GETCOLUMNORDERARRAY\")\n\t\t\treturn nil\n\t\t}\n\t}\n\tif normalCount > 0 {\n\t\tif win.FALSE == win.SendMessage(tv.hwndNormalLV, win.LVM_GETCOLUMNORDERARRAY, uintptr(normalCount), uintptr(unsafe.Pointer(&indices[frozenCount]))) {\n\t\t\tnewError(\"LVM_GETCOLUMNORDERARRAY\")\n\t\t\treturn nil\n\t\t}\n\t}\n\n\torderedCols := make([]*TableViewColumn, len(visibleCols))\n\n\tfor i, j := range indices {\n\t\tif i >= frozenCount {\n\t\t\tj += int32(frozenCount)\n\t\t}\n\t\torderedCols[i] = visibleCols[j]\n\t}\n\n\treturn orderedCols\n}\n\n// RowsPerPage returns the number of fully visible rows.\nfunc (tv *TableView) RowsPerPage() int {\n\treturn int(win.SendMessage(tv.hwndNormalLV, win.LVM_GETCOUNTPERPAGE, 0, 0))\n}\n\nfunc (tv *TableView) Invalidate() error {\n\twin.InvalidateRect(tv.hwndFrozenLV, nil, true)\n\twin.InvalidateRect(tv.hwndNormalLV, nil, true)\n\n\treturn tv.WidgetBase.Invalidate()\n}\n\nfunc (tv *TableView) redrawItems() {\n\tfirst := win.SendMessage(tv.hwndNormalLV, win.LVM_GETTOPINDEX, 0, 0)\n\tlast := first + win.SendMessage(tv.hwndNormalLV, win.LVM_GETCOUNTPERPAGE, 0, 0) + 1\n\twin.SendMessage(tv.hwndFrozenLV, win.LVM_REDRAWITEMS, first, last)\n\twin.SendMessage(tv.hwndNormalLV, win.LVM_REDRAWITEMS, first, last)\n}\n\n// UpdateItem ensures the item at index will be redrawn.\n//\n// If the model supports sorting, it will be resorted.\nfunc (tv *TableView) UpdateItem(index int) error {\n\tif s, ok := tv.model.(Sorter); ok {\n\t\tif err := s.Sort(s.SortedColumn(), s.SortOrder()); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tif win.FALSE == win.SendMessage(tv.hwndFrozenLV, win.LVM_UPDATE, uintptr(index), 0) {\n\t\t\treturn newError(\"LVM_UPDATE\")\n\t\t}\n\t\tif win.FALSE == win.SendMessage(tv.hwndNormalLV, win.LVM_UPDATE, uintptr(index), 0) {\n\t\t\treturn newError(\"LVM_UPDATE\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TableView) attachModel() {\n\trestoreCurrentItemOrFallbackToFirst := func(ip IDProvider) {\n\t\tif tv.itemStateChangedEventDelay == 0 {\n\t\t\tdefer tv.currentItemChangedPublisher.Publish()\n\t\t} else {\n\t\t\tif 0 == win.SetTimer(\n\t\t\t\ttv.hWnd,\n\t\t\t\ttableViewCurrentIndexChangedTimerId,\n\t\t\t\tuint32(tv.itemStateChangedEventDelay),\n\t\t\t\t0,\n\t\t\t) {\n\t\t\t\tlastError(\"SetTimer\")\n\t\t\t}\n\t\t}\n\n\t\tcount := tv.model.RowCount()\n\t\tfor i := 0; i < count; i++ {\n\t\t\tif ip.ID(i) == tv.currentItemID {\n\t\t\t\ttv.SetCurrentIndex(i)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\ttv.SetCurrentIndex(0)\n\t}\n\n\ttv.rowsResetHandlerHandle = tv.model.RowsReset().Attach(func() {\n\t\ttv.setItemCount()\n\n\t\tif ip, ok := tv.providedModel.(IDProvider); ok && tv.restoringCurrentItemOnReset {\n\t\t\tif _, ok := tv.model.(Sorter); !ok {\n\t\t\t\trestoreCurrentItemOrFallbackToFirst(ip)\n\t\t\t}\n\t\t} else {\n\t\t\ttv.SetCurrentIndex(-1)\n\t\t}\n\n\t\ttv.itemCountChangedPublisher.Publish()\n\t})\n\n\ttv.rowChangedHandlerHandle = tv.model.RowChanged().Attach(func(row int) {\n\t\ttv.UpdateItem(row)\n\t})\n\n\ttv.rowsChangedHandlerHandle = tv.model.RowsChanged().Attach(func(from, to int) {\n\t\tif s, ok := tv.model.(Sorter); ok {\n\t\t\ts.Sort(s.SortedColumn(), s.SortOrder())\n\t\t} else {\n\t\t\tfirst, last := uintptr(from), uintptr(to)\n\t\t\twin.SendMessage(tv.hwndFrozenLV, win.LVM_REDRAWITEMS, first, last)\n\t\t\twin.SendMessage(tv.hwndNormalLV, win.LVM_REDRAWITEMS, first, last)\n\t\t}\n\t})\n\n\ttv.rowsInsertedHandlerHandle = tv.model.RowsInserted().Attach(func(from, to int) {\n\t\ti := tv.currentIndex\n\n\t\ttv.setItemCount()\n\n\t\tif from <= i {\n\t\t\ti += 1 + to - from\n\n\t\t\ttv.SetCurrentIndex(i)\n\t\t}\n\n\t\ttv.itemCountChangedPublisher.Publish()\n\t})\n\n\ttv.rowsRemovedHandlerHandle = tv.model.RowsRemoved().Attach(func(from, to int) {\n\t\ti := tv.currentIndex\n\n\t\ttv.setItemCount()\n\n\t\tindex := i\n\n\t\tif from <= i && i <= to {\n\t\t\tindex = -1\n\t\t} else if from < i {\n\t\t\tindex -= 1 + to - from\n\t\t}\n\n\t\tif index != i {\n\t\t\ttv.SetCurrentIndex(index)\n\t\t}\n\n\t\ttv.itemCountChangedPublisher.Publish()\n\t})\n\n\tif sorter, ok := tv.model.(Sorter); ok {\n\t\ttv.sortChangedHandlerHandle = sorter.SortChanged().Attach(func() {\n\t\t\tif ip, ok := tv.providedModel.(IDProvider); ok && tv.restoringCurrentItemOnReset {\n\t\t\t\trestoreCurrentItemOrFallbackToFirst(ip)\n\t\t\t}\n\n\t\t\tcol := sorter.SortedColumn()\n\t\t\ttv.setSortIcon(col, sorter.SortOrder())\n\n\t\t\ttv.redrawItems()\n\t\t})\n\t}\n}\n\nfunc (tv *TableView) detachModel() {\n\ttv.model.RowsReset().Detach(tv.rowsResetHandlerHandle)\n\ttv.model.RowChanged().Detach(tv.rowChangedHandlerHandle)\n\ttv.model.RowsInserted().Detach(tv.rowsInsertedHandlerHandle)\n\ttv.model.RowsRemoved().Detach(tv.rowsRemovedHandlerHandle)\n\tif sorter, ok := tv.model.(Sorter); ok {\n\t\tsorter.SortChanged().Detach(tv.sortChangedHandlerHandle)\n\t}\n}\n\n// ItemCountChanged returns the event that is published when the number of items\n// in the model of the TableView changed.\nfunc (tv *TableView) ItemCountChanged() *Event {\n\treturn tv.itemCountChangedPublisher.Event()\n}\n\n// Model returns the model of the TableView.\nfunc (tv *TableView) Model() interface{} {\n\treturn tv.providedModel\n}\n\n// SetModel sets the model of the TableView.\n//\n// It is required that mdl either implements walk.TableModel,\n// walk.ReflectTableModel or be a slice of pointers to struct or a\n// []map[string]interface{}. A walk.TableModel implementation must also\n// implement walk.Sorter to support sorting, all other options get sorting for\n// free. To support item check boxes and icons, mdl must implement\n// walk.ItemChecker and walk.ImageProvider, respectively. On-demand model\n// population for a walk.ReflectTableModel or slice requires mdl to implement\n// walk.Populator.\nfunc (tv *TableView) SetModel(mdl interface{}) error {\n\tmodel, ok := mdl.(TableModel)\n\tif !ok && mdl != nil {\n\t\tvar err error\n\t\tif model, err = newReflectTableModel(mdl); err != nil {\n\t\t\tif model, err = newMapTableModel(mdl); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\ttv.SetSuspended(true)\n\tdefer tv.SetSuspended(false)\n\n\tif tv.model != nil {\n\t\ttv.detachModel()\n\n\t\ttv.disposeImageListAndCaches()\n\t}\n\n\toldProvidedModelStyler, _ := tv.providedModel.(CellStyler)\n\tif styler, ok := mdl.(CellStyler); ok || tv.styler == oldProvidedModelStyler {\n\t\ttv.styler = styler\n\t}\n\n\ttv.providedModel = mdl\n\ttv.model = model\n\n\ttv.itemChecker, _ = model.(ItemChecker)\n\ttv.imageProvider, _ = model.(ImageProvider)\n\n\tif model != nil {\n\t\ttv.attachModel()\n\n\t\tif dms, ok := model.(dataMembersSetter); ok {\n\t\t\t// FIXME: This depends on columns to be initialized before\n\t\t\t// calling this method.\n\t\t\tdataMembers := make([]string, len(tv.columns.items))\n\n\t\t\tfor i, col := range tv.columns.items {\n\t\t\t\tdataMembers[i] = col.DataMemberEffective()\n\t\t\t}\n\n\t\t\tdms.setDataMembers(dataMembers)\n\t\t}\n\n\t\tif lfs, ok := model.(lessFuncsSetter); ok {\n\t\t\tlessFuncs := make([]func(i, j int) bool, tv.columns.Len())\n\t\t\tfor i, c := range tv.columns.items {\n\t\t\t\tlessFuncs[i] = c.lessFunc\n\t\t\t}\n\t\t\tlfs.setLessFuncs(lessFuncs)\n\t\t}\n\n\t\tif sorter, ok := tv.model.(Sorter); ok {\n\t\t\tif tv.sortedColumnIndex >= tv.visibleColumnCount() {\n\t\t\t\ttv.sortedColumnIndex = maxi(-1, mini(0, tv.visibleColumnCount()-1))\n\t\t\t\ttv.sortOrder = SortAscending\n\t\t\t}\n\n\t\t\tsorter.Sort(tv.sortedColumnIndex, tv.sortOrder)\n\t\t}\n\t}\n\n\ttv.SetCurrentIndex(-1)\n\n\ttv.setItemCount()\n\n\ttv.itemCountChangedPublisher.Publish()\n\n\treturn nil\n}\n\n// TableModel returns the TableModel of the TableView.\nfunc (tv *TableView) TableModel() TableModel {\n\treturn tv.model\n}\n\n// ItemChecker returns the ItemChecker of the TableView.\nfunc (tv *TableView) ItemChecker() ItemChecker {\n\treturn tv.itemChecker\n}\n\n// SetItemChecker sets the ItemChecker of the TableView.\nfunc (tv *TableView) SetItemChecker(itemChecker ItemChecker) {\n\ttv.itemChecker = itemChecker\n}\n\n// CellStyler returns the CellStyler of the TableView.\nfunc (tv *TableView) CellStyler() CellStyler {\n\treturn tv.styler\n}\n\n// SetCellStyler sets the CellStyler of the TableView.\nfunc (tv *TableView) SetCellStyler(styler CellStyler) {\n\ttv.styler = styler\n}\n\nfunc (tv *TableView) setItemCount() error {\n\tvar count int\n\n\tif tv.model != nil {\n\t\tcount = tv.model.RowCount()\n\t}\n\n\tif 0 == win.SendMessage(tv.hwndFrozenLV, win.LVM_SETITEMCOUNT, uintptr(count), win.LVSICF_NOINVALIDATEALL|win.LVSICF_NOSCROLL) {\n\t\treturn newError(\"SendMessage(LVM_SETITEMCOUNT)\")\n\t}\n\tif 0 == win.SendMessage(tv.hwndNormalLV, win.LVM_SETITEMCOUNT, uintptr(count), win.LVSICF_NOINVALIDATEALL|win.LVSICF_NOSCROLL) {\n\t\treturn newError(\"SendMessage(LVM_SETITEMCOUNT)\")\n\t}\n\n\treturn nil\n}\n\n// CheckBoxes returns if the *TableView has check boxes.\nfunc (tv *TableView) CheckBoxes() bool {\n\tvar hwnd win.HWND\n\tif tv.hasFrozenColumn {\n\t\thwnd = tv.hwndFrozenLV\n\t} else {\n\t\thwnd = tv.hwndNormalLV\n\t}\n\n\treturn win.SendMessage(hwnd, win.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)&win.LVS_EX_CHECKBOXES > 0\n}\n\n// SetCheckBoxes sets if the *TableView has check boxes.\nfunc (tv *TableView) SetCheckBoxes(checkBoxes bool) {\n\tvar hwnd, hwndOther win.HWND\n\tif tv.hasFrozenColumn {\n\t\thwnd, hwndOther = tv.hwndFrozenLV, tv.hwndNormalLV\n\t} else {\n\t\thwnd, hwndOther = tv.hwndNormalLV, tv.hwndFrozenLV\n\t}\n\n\texStyle := win.SendMessage(hwnd, win.LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)\n\toldStyle := exStyle\n\tif checkBoxes {\n\t\texStyle |= win.LVS_EX_CHECKBOXES\n\t} else {\n\t\texStyle &^= win.LVS_EX_CHECKBOXES\n\t}\n\tif exStyle != oldStyle {\n\t\twin.SendMessage(hwnd, win.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle)\n\t}\n\n\twin.SendMessage(hwndOther, win.LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle&^win.LVS_EX_CHECKBOXES)\n\n\tmask := win.SendMessage(hwnd, win.LVM_GETCALLBACKMASK, 0, 0)\n\n\tif checkBoxes {\n\t\tmask |= win.LVIS_STATEIMAGEMASK\n\t} else {\n\t\tmask &^= win.LVIS_STATEIMAGEMASK\n\t}\n\n\tif win.FALSE == win.SendMessage(hwnd, win.LVM_SETCALLBACKMASK, mask, 0) {\n\t\tnewError(\"SendMessage(LVM_SETCALLBACKMASK)\")\n\t}\n}\n\nfunc (tv *TableView) fromLVColIdx(frozen bool, index int32) int {\n\tvar idx int32\n\n\tfor i, tvc := range tv.columns.items {\n\t\tif frozen == tvc.frozen && tvc.visible {\n\t\t\tif idx == index {\n\t\t\t\treturn i\n\t\t\t}\n\n\t\t\tidx++\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (tv *TableView) toLVColIdx(index int) int32 {\n\tvar idx int32\n\n\tfor i, tvc := range tv.columns.items {\n\t\tif tvc.visible {\n\t\t\tif i == index {\n\t\t\t\treturn idx\n\t\t\t}\n\n\t\t\tidx++\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (tv *TableView) visibleFrozenColumnCount() int {\n\tvar count int\n\n\tfor _, tvc := range tv.columns.items {\n\t\tif tvc.frozen && tvc.visible {\n\t\t\tcount++\n\t\t}\n\t}\n\n\treturn count\n}\n\nfunc (tv *TableView) visibleColumnCount() int {\n\tvar count int\n\n\tfor _, tvc := range tv.columns.items {\n\t\tif tvc.visible {\n\t\t\tcount++\n\t\t}\n\t}\n\n\treturn count\n}\n\nfunc (tv *TableView) visibleColumns() []*TableViewColumn {\n\tvar cols []*TableViewColumn\n\n\tfor _, tvc := range tv.columns.items {\n\t\tif tvc.visible {\n\t\t\tcols = append(cols, tvc)\n\t\t}\n\t}\n\n\treturn cols\n}\n\n/*func (tv *TableView) selectedColumnIndex() int {\n\treturn tv.fromLVColIdx(tv.SendMessage(LVM_GETSELECTEDCOLUMN, 0, 0))\n}*/\n\n// func (tv *TableView) setSelectedColumnIndex(index int) {\n// \ttv.SendMessage(win.LVM_SETSELECTEDCOLUMN, uintptr(tv.toLVColIdx(index)), 0)\n// }\n\nfunc (tv *TableView) setSortIcon(index int, order SortOrder) error {\n\tidx := int(tv.toLVColIdx(index))\n\n\tfrozenCount := tv.visibleFrozenColumnCount()\n\n\tfor i, col := range tv.visibleColumns() {\n\t\titem := win.HDITEM{\n\t\t\tMask: win.HDI_FORMAT,\n\t\t}\n\n\t\tvar headerHwnd win.HWND\n\t\tvar offset int\n\t\tif col.frozen {\n\t\t\theaderHwnd = tv.hwndFrozenHdr\n\t\t} else {\n\t\t\theaderHwnd = tv.hwndNormalHdr\n\t\t\toffset = -frozenCount\n\t\t}\n\n\t\tiPtr := uintptr(offset + i)\n\t\titemPtr := uintptr(unsafe.Pointer(&item))\n\n\t\tif win.SendMessage(headerHwnd, win.HDM_GETITEM, iPtr, itemPtr) == 0 {\n\t\t\treturn newError(\"SendMessage(HDM_GETITEM)\")\n\t\t}\n\n\t\tif i == idx {\n\t\t\tswitch order {\n\t\t\tcase SortAscending:\n\t\t\t\titem.Fmt &^= win.HDF_SORTDOWN\n\t\t\t\titem.Fmt |= win.HDF_SORTUP\n\n\t\t\tcase SortDescending:\n\t\t\t\titem.Fmt &^= win.HDF_SORTUP\n\t\t\t\titem.Fmt |= win.HDF_SORTDOWN\n\t\t\t}\n\t\t} else {\n\t\t\titem.Fmt &^= win.HDF_SORTDOWN | win.HDF_SORTUP\n\t\t}\n\n\t\tif win.SendMessage(headerHwnd, win.HDM_SETITEM, iPtr, itemPtr) == 0 {\n\t\t\treturn newError(\"SendMessage(HDM_SETITEM)\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ColumnClicked returns the event that is published after a column header was\n// clicked.\nfunc (tv *TableView) ColumnClicked() *IntEvent {\n\treturn tv.columnClickedPublisher.Event()\n}\n\n// ItemActivated returns the event that is published after an item was\n// activated.\n//\n// An item is activated when it is double clicked or the enter key is pressed\n// when the item is selected.\nfunc (tv *TableView) ItemActivated() *Event {\n\treturn tv.itemActivatedPublisher.Event()\n}\n\n// RestoringCurrentItemOnReset returns whether the TableView after its model\n// has been reset should attempt to restore CurrentIndex to the item that was\n// current before the reset.\n//\n// For this to work, the model must implement the IDProvider interface.\nfunc (tv *TableView) RestoringCurrentItemOnReset() bool {\n\treturn tv.restoringCurrentItemOnReset\n}\n\n// SetRestoringCurrentItemOnReset sets whether the TableView after its model\n// has been reset should attempt to restore CurrentIndex to the item that was\n// current before the reset.\n//\n// For this to work, the model must implement the IDProvider interface.\nfunc (tv *TableView) SetRestoringCurrentItemOnReset(restoring bool) {\n\ttv.restoringCurrentItemOnReset = restoring\n}\n\n// CurrentItemChanged returns the event that is published after the current\n// item has changed.\n//\n// For this to work, the model must implement the IDProvider interface.\nfunc (tv *TableView) CurrentItemChanged() *Event {\n\treturn tv.currentItemChangedPublisher.Event()\n}\n\n// CurrentIndex returns the index of the current item, or -1 if there is no\n// current item.\nfunc (tv *TableView) CurrentIndex() int {\n\treturn tv.currentIndex\n}\n\n// SetCurrentIndex sets the index of the current item.\n//\n// Call this with a value of -1 to have no current item.\nfunc (tv *TableView) SetCurrentIndex(index int) error {\n\tif tv.inSetCurrentIndex {\n\t\treturn nil\n\t}\n\ttv.inSetCurrentIndex = true\n\tdefer func() {\n\t\ttv.inSetCurrentIndex = false\n\t}()\n\n\tvar lvi win.LVITEM\n\n\tlvi.StateMask = win.LVIS_FOCUSED | win.LVIS_SELECTED\n\n\tif tv.MultiSelection() {\n\t\tif win.FALSE == win.SendMessage(tv.hwndFrozenLV, win.LVM_SETITEMSTATE, ^uintptr(0), uintptr(unsafe.Pointer(&lvi))) {\n\t\t\treturn newError(\"SendMessage(LVM_SETITEMSTATE)\")\n\t\t}\n\t\tif win.FALSE == win.SendMessage(tv.hwndNormalLV, win.LVM_SETITEMSTATE, ^uintptr(0), uintptr(unsafe.Pointer(&lvi))) {\n\t\t\treturn newError(\"SendMessage(LVM_SETITEMSTATE)\")\n\t\t}\n\t}\n\n\tif index > -1 {\n\t\tlvi.State = win.LVIS_FOCUSED | win.LVIS_SELECTED\n\t}\n\n\tif win.FALSE == win.SendMessage(tv.hwndFrozenLV, win.LVM_SETITEMSTATE, uintptr(index), uintptr(unsafe.Pointer(&lvi))) {\n\t\treturn newError(\"SendMessage(LVM_SETITEMSTATE)\")\n\t}\n\tif win.FALSE == win.SendMessage(tv.hwndNormalLV, win.LVM_SETITEMSTATE, uintptr(index), uintptr(unsafe.Pointer(&lvi))) {\n\t\treturn newError(\"SendMessage(LVM_SETITEMSTATE)\")\n\t}\n\n\tif index > -1 {\n\t\tif win.FALSE == win.SendMessage(tv.hwndFrozenLV, win.LVM_ENSUREVISIBLE, uintptr(index), uintptr(0)) {\n\t\t\treturn newError(\"SendMessage(LVM_ENSUREVISIBLE)\")\n\t\t}\n\t\t// Windows bug? Sometimes a second LVM_ENSUREVISIBLE is required.\n\t\tif win.FALSE == win.SendMessage(tv.hwndFrozenLV, win.LVM_ENSUREVISIBLE, uintptr(index), uintptr(0)) {\n\t\t\treturn newError(\"SendMessage(LVM_ENSUREVISIBLE)\")\n\t\t}\n\t\tif win.FALSE == win.SendMessage(tv.hwndNormalLV, win.LVM_ENSUREVISIBLE, uintptr(index), uintptr(0)) {\n\t\t\treturn newError(\"SendMessage(LVM_ENSUREVISIBLE)\")\n\t\t}\n\t\t// Windows bug? Sometimes a second LVM_ENSUREVISIBLE is required.\n\t\tif win.FALSE == win.SendMessage(tv.hwndNormalLV, win.LVM_ENSUREVISIBLE, uintptr(index), uintptr(0)) {\n\t\t\treturn newError(\"SendMessage(LVM_ENSUREVISIBLE)\")\n\t\t}\n\n\t\tif ip, ok := tv.providedModel.(IDProvider); ok && tv.restoringCurrentItemOnReset {\n\t\t\tif id := ip.ID(index); id != tv.currentItemID {\n\t\t\t\ttv.currentItemID = id\n\t\t\t\tif tv.itemStateChangedEventDelay == 0 {\n\t\t\t\t\tdefer tv.currentItemChangedPublisher.Publish()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\ttv.currentItemID = nil\n\t\tif tv.itemStateChangedEventDelay == 0 {\n\t\t\tdefer tv.currentItemChangedPublisher.Publish()\n\t\t}\n\t}\n\n\ttv.currentIndex = index\n\n\tif index == -1 || tv.itemStateChangedEventDelay == 0 {\n\t\ttv.currentIndexChangedPublisher.Publish()\n\t}\n\n\tif tv.MultiSelection() {\n\t\ttv.updateSelectedIndexes()\n\t}\n\n\treturn nil\n}\n\n// CurrentIndexChanged is the event that is published after CurrentIndex has\n// changed.\nfunc (tv *TableView) CurrentIndexChanged() *Event {\n\treturn tv.currentIndexChangedPublisher.Event()\n}\n\n// IndexAt returns the item index at coordinates x, y of the\n// TableView or -1, if that point is not inside any item.\nfunc (tv *TableView) IndexAt(x, y int) int {\n\tvar hti win.LVHITTESTINFO\n\n\tvar rc win.RECT\n\tif !win.GetWindowRect(tv.hwndFrozenLV, &rc) {\n\t\treturn -1\n\t}\n\n\tvar hwnd win.HWND\n\tif x < int(rc.Right-rc.Left) {\n\t\thwnd = tv.hwndFrozenLV\n\t} else {\n\t\thwnd = tv.hwndNormalLV\n\t}\n\n\thti.Pt.X = int32(x)\n\thti.Pt.Y = int32(y)\n\n\twin.SendMessage(hwnd, win.LVM_HITTEST, 0, uintptr(unsafe.Pointer(&hti)))\n\n\treturn int(hti.IItem)\n}\n\n// ItemVisible returns whether the item at position index is visible.\nfunc (tv *TableView) ItemVisible(index int) bool {\n\treturn 0 != win.SendMessage(tv.hwndNormalLV, win.LVM_ISITEMVISIBLE, uintptr(index), 0)\n}\n\n// EnsureItemVisible ensures the item at position index is visible, scrolling if necessary.\nfunc (tv *TableView) EnsureItemVisible(index int) {\n\twin.SendMessage(tv.hwndNormalLV, win.LVM_ENSUREVISIBLE, uintptr(index), 0)\n}\n\n// SelectionHiddenWithoutFocus returns whether selection indicators are hidden\n// when the TableView does not have the keyboard input focus.\nfunc (tv *TableView) SelectionHiddenWithoutFocus() bool {\n\tstyle := uint(win.GetWindowLong(tv.hwndNormalLV, win.GWL_STYLE))\n\tif style == 0 {\n\t\tlastError(\"GetWindowLong\")\n\t\treturn false\n\t}\n\n\treturn style&win.LVS_SHOWSELALWAYS == 0\n}\n\n// SetSelectionHiddenWithoutFocus sets whether selection indicators are visible when the TableView does not have the keyboard input focus.\nfunc (tv *TableView) SetSelectionHiddenWithoutFocus(hidden bool) error {\n\tif err := ensureWindowLongBits(tv.hwndFrozenLV, win.GWL_STYLE, win.LVS_SHOWSELALWAYS, !hidden); err != nil {\n\t\treturn err\n\t}\n\n\treturn ensureWindowLongBits(tv.hwndNormalLV, win.GWL_STYLE, win.LVS_SHOWSELALWAYS, !hidden)\n}\n\n// MultiSelection returns whether multiple items can be selected at once.\n//\n// By default only a single item can be selected at once.\nfunc (tv *TableView) MultiSelection() bool {\n\tstyle := uint(win.GetWindowLong(tv.hwndNormalLV, win.GWL_STYLE))\n\tif style == 0 {\n\t\tlastError(\"GetWindowLong\")\n\t\treturn false\n\t}\n\n\treturn style&win.LVS_SINGLESEL == 0\n}\n\n// SetMultiSelection sets whether multiple items can be selected at once.\nfunc (tv *TableView) SetMultiSelection(multiSel bool) error {\n\tif err := ensureWindowLongBits(tv.hwndFrozenLV, win.GWL_STYLE, win.LVS_SINGLESEL, !multiSel); err != nil {\n\t\treturn err\n\t}\n\n\treturn ensureWindowLongBits(tv.hwndNormalLV, win.GWL_STYLE, win.LVS_SINGLESEL, !multiSel)\n}\n\n// SelectedIndexes returns the indexes of the currently selected items.\nfunc (tv *TableView) SelectedIndexes() []int {\n\tindexes := make([]int, len(tv.selectedIndexes))\n\n\tfor i, j := range tv.selectedIndexes {\n\t\tindexes[i] = j\n\t}\n\n\treturn indexes\n}\n\n// SetSelectedIndexes sets the indexes of the currently selected items.\nfunc (tv *TableView) SetSelectedIndexes(indexes []int) error {\n\ttv.inSetSelectedIndexes = true\n\tdefer func() {\n\t\ttv.inSetSelectedIndexes = false\n\t\ttv.publishSelectedIndexesChanged()\n\t}()\n\n\tlvi := &win.LVITEM{StateMask: win.LVIS_FOCUSED | win.LVIS_SELECTED}\n\tlp := uintptr(unsafe.Pointer(lvi))\n\n\tif win.FALSE == win.SendMessage(tv.hwndFrozenLV, win.LVM_SETITEMSTATE, ^uintptr(0), lp) {\n\t\treturn newError(\"SendMessage(LVM_SETITEMSTATE)\")\n\t}\n\tif win.FALSE == win.SendMessage(tv.hwndNormalLV, win.LVM_SETITEMSTATE, ^uintptr(0), lp) {\n\t\treturn newError(\"SendMessage(LVM_SETITEMSTATE)\")\n\t}\n\n\tselectAll := false\n\tlvi.State = win.LVIS_FOCUSED | win.LVIS_SELECTED\n\tfor _, i := range indexes {\n\t\tval := uintptr(i)\n\t\tif i == -1 {\n\t\t\tselectAll = true\n\t\t\tval = ^uintptr(0)\n\t\t}\n\t\tif win.FALSE == win.SendMessage(tv.hwndFrozenLV, win.LVM_SETITEMSTATE, val, lp) && i != -1 {\n\t\t\treturn newError(\"SendMessage(LVM_SETITEMSTATE)\")\n\t\t}\n\t\tif win.FALSE == win.SendMessage(tv.hwndNormalLV, win.LVM_SETITEMSTATE, val, lp) && i != -1 {\n\t\t\treturn newError(\"SendMessage(LVM_SETITEMSTATE)\")\n\t\t}\n\t}\n\n\tif !selectAll {\n\t\tidxs := make([]int, len(indexes))\n\n\t\tfor i, j := range indexes {\n\t\t\tidxs[i] = j\n\t\t}\n\n\t\ttv.selectedIndexes = idxs\n\t} else {\n\t\tcount := int(win.SendMessage(tv.hwndNormalLV, win.LVM_GETSELECTEDCOUNT, 0, 0))\n\t\tidxs := make([]int, count)\n\t\tfor i := range idxs {\n\t\t\tidxs[i] = i\n\t\t}\n\t\ttv.selectedIndexes = idxs\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TableView) updateSelectedIndexes() {\n\tcount := int(win.SendMessage(tv.hwndNormalLV, win.LVM_GETSELECTEDCOUNT, 0, 0))\n\tindexes := make([]int, count)\n\n\tj := -1\n\tfor i := 0; i < count; i++ {\n\t\tj = int(win.SendMessage(tv.hwndNormalLV, win.LVM_GETNEXTITEM, uintptr(j), win.LVNI_SELECTED))\n\t\tindexes[i] = j\n\t}\n\n\tchanged := len(indexes) != len(tv.selectedIndexes)\n\tif !changed {\n\t\tfor i := 0; i < len(indexes); i++ {\n\t\t\tif indexes[i] != tv.selectedIndexes[i] {\n\t\t\t\tchanged = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif changed {\n\t\ttv.selectedIndexes = indexes\n\t\ttv.publishSelectedIndexesChanged()\n\t}\n}\n\nfunc (tv *TableView) copySelectedIndexes(hwndTo, hwndFrom win.HWND) error {\n\tcount := int(win.SendMessage(hwndFrom, win.LVM_GETSELECTEDCOUNT, 0, 0))\n\n\tlvi := &win.LVITEM{StateMask: win.LVIS_FOCUSED | win.LVIS_SELECTED}\n\tlp := uintptr(unsafe.Pointer(lvi))\n\n\tif win.FALSE == win.SendMessage(hwndTo, win.LVM_SETITEMSTATE, ^uintptr(0), lp) {\n\t\treturn newError(\"SendMessage(LVM_SETITEMSTATE)\")\n\t}\n\n\tlvi.StateMask = win.LVIS_SELECTED\n\tlvi.State = win.LVIS_SELECTED\n\n\tj := -1\n\tfor i := 0; i < count; i++ {\n\t\tj = int(win.SendMessage(hwndFrom, win.LVM_GETNEXTITEM, uintptr(j), win.LVNI_SELECTED))\n\n\t\tif win.FALSE == win.SendMessage(hwndTo, win.LVM_SETITEMSTATE, uintptr(j), lp) {\n\t\t\treturn newError(\"SendMessage(LVM_SETITEMSTATE)\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ItemStateChangedEventDelay returns the delay in milliseconds, between the\n// moment the state of an item in the *TableView changes and the moment the\n// associated event is published.\n//\n// By default there is no delay.\nfunc (tv *TableView) ItemStateChangedEventDelay() int {\n\treturn tv.itemStateChangedEventDelay\n}\n\n// SetItemStateChangedEventDelay sets the delay in milliseconds, between the\n// moment the state of an item in the *TableView changes and the moment the\n// associated event is published.\n//\n// An example where this may be useful is a master-details scenario. If the\n// master TableView is configured to delay the event, you can avoid pointless\n// updates of the details TableView, if the user uses arrow keys to rapidly\n// navigate the master view.\nfunc (tv *TableView) SetItemStateChangedEventDelay(delay int) {\n\ttv.itemStateChangedEventDelay = delay\n}\n\n// SelectedIndexesChanged returns the event that is published when the list of\n// selected item indexes changed.\nfunc (tv *TableView) SelectedIndexesChanged() *Event {\n\treturn tv.selectedIndexesChangedPublisher.Event()\n}\n\nfunc (tv *TableView) publishSelectedIndexesChanged() {\n\tif tv.itemStateChangedEventDelay > 0 {\n\t\tif 0 == win.SetTimer(\n\t\t\ttv.hWnd,\n\t\t\ttableViewSelectedIndexesChangedTimerId,\n\t\t\tuint32(tv.itemStateChangedEventDelay),\n\t\t\t0) {\n\n\t\t\tlastError(\"SetTimer\")\n\t\t}\n\t} else {\n\t\ttv.selectedIndexesChangedPublisher.Publish()\n\t}\n}\n\n// LastColumnStretched returns if the last column should take up all remaining\n// horizontal space of the *TableView.\nfunc (tv *TableView) LastColumnStretched() bool {\n\treturn tv.lastColumnStretched\n}\n\n// SetLastColumnStretched sets if the last column should take up all remaining\n// horizontal space of the *TableView.\n//\n// The effect of setting this is persistent.\nfunc (tv *TableView) SetLastColumnStretched(value bool) error {\n\tif value {\n\t\tif err := tv.StretchLastColumn(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\ttv.lastColumnStretched = value\n\n\treturn nil\n}\n\n// StretchLastColumn makes the last column take up all remaining horizontal\n// space of the *TableView.\n//\n// The effect of this is not persistent.\nfunc (tv *TableView) StretchLastColumn() error {\n\tcolCount := tv.visibleColumnCount()\n\tif colCount == 0 {\n\t\treturn nil\n\t}\n\n\tvar hwnd win.HWND\n\tfrozenColCount := tv.visibleFrozenColumnCount()\n\tif colCount-frozenColCount == 0 {\n\t\thwnd = tv.hwndFrozenLV\n\t\tcolCount = frozenColCount\n\t} else {\n\t\thwnd = tv.hwndNormalLV\n\t\tcolCount -= frozenColCount\n\t}\n\n\tvar lp uintptr\n\tif tv.scrollbarOrientation&Horizontal != 0 {\n\t\tlp = win.LVSCW_AUTOSIZE_USEHEADER\n\t} else {\n\t\twidth := tv.ClientBoundsPixels().Width\n\n\t\tlastIndexInLV := -1\n\t\tvar lastIndexInLVWidth int\n\n\t\tfor _, tvc := range tv.columns.items {\n\t\t\tvar offset int\n\t\t\tif !tvc.Frozen() {\n\t\t\t\toffset = frozenColCount\n\t\t\t}\n\n\t\t\tcolWidth := tv.IntFrom96DPI(tvc.Width())\n\t\t\twidth -= colWidth\n\n\t\t\tif index := int32(offset) + tvc.indexInListView(); int(index) > lastIndexInLV {\n\t\t\t\tlastIndexInLV = int(index)\n\t\t\t\tlastIndexInLVWidth = colWidth\n\t\t\t}\n\t\t}\n\n\t\twidth += lastIndexInLVWidth\n\n\t\tif hasWindowLongBits(tv.hwndNormalLV, win.GWL_STYLE, win.WS_VSCROLL) {\n\t\t\twidth -= int(win.GetSystemMetricsForDpi(win.SM_CXVSCROLL, uint32(tv.DPI())))\n\t\t}\n\n\t\tlp = uintptr(maxi(0, width))\n\t}\n\n\tif lp > 0 {\n\t\tif 0 == win.SendMessage(hwnd, win.LVM_SETCOLUMNWIDTH, uintptr(colCount-1), lp) {\n\t\t\treturn newError(\"LVM_SETCOLUMNWIDTH failed\")\n\t\t}\n\n\t\tif dpi := tv.DPI(); dpi != tv.dpiOfPrevStretchLastColumn {\n\t\t\ttv.dpiOfPrevStretchLastColumn = dpi\n\n\t\t\ttv.Invalidate()\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Persistent returns if the *TableView should persist its UI state, like column\n// widths. See *App.Settings for details.\nfunc (tv *TableView) Persistent() bool {\n\treturn tv.persistent\n}\n\n// SetPersistent sets if the *TableView should persist its UI state, like column\n// widths. See *App.Settings for details.\nfunc (tv *TableView) SetPersistent(value bool) {\n\ttv.persistent = value\n}\n\n// IgnoreNowhere returns if the *TableView should ignore left mouse clicks in the\n// empty space. It forbids the user from unselecting the current index, or when\n// multi selection is enabled, disables click drag selection.\nfunc (tv *TableView) IgnoreNowhere() bool {\n\treturn tv.ignoreNowhere\n}\n\n// IgnoreNowhere sets if the *TableView should ignore left mouse clicks in the\n// empty space. It forbids the user from unselecting the current index, or when\n// multi selection is enabled, disables click drag selection.\nfunc (tv *TableView) SetIgnoreNowhere(value bool) {\n\ttv.ignoreNowhere = value\n}\n\ntype tableViewState struct {\n\tSortColumnName     string\n\tSortOrder          SortOrder\n\tColumnDisplayOrder []string\n\tColumns            []*tableViewColumnState\n}\n\ntype tableViewColumnState struct {\n\tName         string\n\tTitle        string\n\tWidth        int\n\tVisible      bool\n\tFrozen       bool\n\tLastSeenDate string\n}\n\n// SaveState writes the UI state of the *TableView to the settings.\nfunc (tv *TableView) SaveState() error {\n\tif tv.columns.Len() == 0 {\n\t\treturn nil\n\t}\n\n\tif tv.state == nil {\n\t\ttv.state = new(tableViewState)\n\t}\n\n\ttvs := tv.state\n\n\ttvs.SortColumnName = tv.columns.items[tv.sortedColumnIndex].name\n\ttvs.SortOrder = tv.sortOrder\n\n\t// tvs.Columns = make([]tableViewColumnState, tv.columns.Len())\n\n\tfor _, tvc := range tv.columns.items {\n\t\tvar tvcs *tableViewColumnState\n\t\tfor _, cur := range tvs.Columns {\n\t\t\tif cur.Name == tvc.name {\n\t\t\t\ttvcs = cur\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// tvcs := &tvs.Columns[i]\n\n\t\tif tvcs == nil {\n\t\t\ttvs.Columns = append(tvs.Columns, new(tableViewColumnState))\n\t\t\ttvcs = tvs.Columns[len(tvs.Columns)-1]\n\t\t}\n\n\t\ttvcs.Name = tvc.name\n\t\ttvcs.Title = tvc.titleOverride\n\t\ttvcs.Width = tvc.Width()\n\t\ttvcs.Visible = tvc.Visible()\n\t\ttvcs.Frozen = tvc.Frozen()\n\t\ttvcs.LastSeenDate = time.Now().Format(\"2006-01-02\")\n\t}\n\n\tvisibleCols := tv.visibleColumns()\n\tfrozenCount := tv.visibleFrozenColumnCount()\n\tnormalCount := len(visibleCols) - frozenCount\n\tindices := make([]int32, len(visibleCols))\n\tvar lp uintptr\n\tif frozenCount > 0 {\n\t\tlp = uintptr(unsafe.Pointer(&indices[0]))\n\n\t\tif 0 == win.SendMessage(tv.hwndFrozenLV, win.LVM_GETCOLUMNORDERARRAY, uintptr(frozenCount), lp) {\n\t\t\treturn newError(\"LVM_GETCOLUMNORDERARRAY\")\n\t\t}\n\t}\n\tif normalCount > 0 {\n\t\tlp = uintptr(unsafe.Pointer(&indices[frozenCount]))\n\n\t\tif 0 == win.SendMessage(tv.hwndNormalLV, win.LVM_GETCOLUMNORDERARRAY, uintptr(normalCount), lp) {\n\t\t\treturn newError(\"LVM_GETCOLUMNORDERARRAY\")\n\t\t}\n\t}\n\n\ttvs.ColumnDisplayOrder = make([]string, len(visibleCols))\n\tfor i, j := range indices {\n\t\tif i >= frozenCount {\n\t\t\tj += int32(frozenCount)\n\t\t}\n\t\ttvs.ColumnDisplayOrder[i] = visibleCols[j].name\n\t}\n\n\tstate, err := json.Marshal(tvs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn tv.WriteState(string(state))\n}\n\n// RestoreState restores the UI state of the *TableView from the settings.\nfunc (tv *TableView) RestoreState() error {\n\tstate, err := tv.ReadState()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif state == \"\" {\n\t\treturn nil\n\t}\n\n\ttv.SetSuspended(true)\n\tdefer tv.SetSuspended(false)\n\n\tif tv.state == nil {\n\t\ttv.state = new(tableViewState)\n\t}\n\n\ttvs := tv.state\n\n\tif err := json.Unmarshal(([]byte)(state), tvs); err != nil {\n\t\treturn err\n\t}\n\n\tname2tvc := make(map[string]*TableViewColumn)\n\n\tfor _, tvc := range tv.columns.items {\n\t\tname2tvc[tvc.name] = tvc\n\t}\n\n\tname2tvcs := make(map[string]*tableViewColumnState)\n\n\ttvcsRetained := make([]*tableViewColumnState, 0, len(tvs.Columns))\n\tfor _, tvcs := range tvs.Columns {\n\t\tif tvcs.LastSeenDate != \"\" {\n\t\t\tif lastSeen, err := time.Parse(\"2006-02-01\", tvcs.LastSeenDate); err != nil {\n\t\t\t\ttvcs.LastSeenDate = \"\"\n\t\t\t} else if name2tvc[tvcs.Name] == nil && lastSeen.Add(time.Hour*24*90).Before(time.Now()) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\ttvcsRetained = append(tvcsRetained, tvcs)\n\n\t\tname2tvcs[tvcs.Name] = tvcsRetained[len(tvcsRetained)-1]\n\n\t\tif tvc := name2tvc[tvcs.Name]; tvc != nil {\n\t\t\tif err := tvc.SetFrozen(tvcs.Frozen); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tvar visible bool\n\t\t\tfor _, name := range tvs.ColumnDisplayOrder {\n\t\t\t\tif name == tvc.name {\n\t\t\t\t\tvisible = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err := tvc.SetVisible(tvc.visible && (visible || tvcs.Visible)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := tvc.SetTitleOverride(tvcs.Title); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := tvc.SetWidth(tvcs.Width); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\ttvs.Columns = tvcsRetained\n\n\tvisibleCount := tv.visibleColumnCount()\n\tfrozenCount := tv.visibleFrozenColumnCount()\n\tnormalCount := visibleCount - frozenCount\n\n\tindices := make([]int32, visibleCount)\n\n\tknownNames := make(map[string]struct{})\n\n\tdisplayOrder := make([]string, 0, visibleCount)\n\tfor _, name := range tvs.ColumnDisplayOrder {\n\t\tknownNames[name] = struct{}{}\n\t\tif tvc, ok := name2tvc[name]; ok && tvc.visible {\n\t\t\tdisplayOrder = append(displayOrder, name)\n\t\t}\n\t}\n\tfor _, tvc := range tv.visibleColumns() {\n\t\tif _, ok := knownNames[tvc.name]; !ok {\n\t\t\tdisplayOrder = append(displayOrder, tvc.name)\n\t\t}\n\t}\n\n\tfor i, tvc := range tv.visibleColumns() {\n\t\tfor j, name := range displayOrder {\n\t\t\tif tvc.name == name && j < visibleCount {\n\t\t\t\tidx := i\n\t\t\t\tif j >= frozenCount {\n\t\t\t\t\tidx -= frozenCount\n\t\t\t\t}\n\t\t\t\tindices[j] = int32(idx)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tvar lp uintptr\n\tif frozenCount > 0 {\n\t\tlp = uintptr(unsafe.Pointer(&indices[0]))\n\n\t\tif 0 == win.SendMessage(tv.hwndFrozenLV, win.LVM_SETCOLUMNORDERARRAY, uintptr(frozenCount), lp) {\n\t\t\treturn newError(\"LVM_SETCOLUMNORDERARRAY\")\n\t\t}\n\t}\n\tif normalCount > 0 {\n\t\tlp = uintptr(unsafe.Pointer(&indices[frozenCount]))\n\n\t\tif 0 == win.SendMessage(tv.hwndNormalLV, win.LVM_SETCOLUMNORDERARRAY, uintptr(normalCount), lp) {\n\t\t\treturn newError(\"LVM_SETCOLUMNORDERARRAY\")\n\t\t}\n\t}\n\n\tfor i, c := range tvs.Columns {\n\t\tif c.Name == tvs.SortColumnName && i < visibleCount {\n\t\t\ttv.sortedColumnIndex = i\n\t\t\ttv.sortOrder = tvs.SortOrder\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif sorter, ok := tv.model.(Sorter); ok {\n\t\tif !sorter.ColumnSortable(tv.sortedColumnIndex) {\n\t\t\tfor i := range tvs.Columns {\n\t\t\t\tif sorter.ColumnSortable(i) {\n\t\t\t\t\ttv.sortedColumnIndex = i\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsorter.Sort(tv.sortedColumnIndex, tvs.SortOrder)\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TableView) toggleItemChecked(index int) error {\n\tchecked := tv.itemChecker.Checked(index)\n\n\tif err := tv.itemChecker.SetChecked(index, !checked); err != nil {\n\t\treturn wrapError(err)\n\t}\n\n\tif win.FALSE == win.SendMessage(tv.hwndFrozenLV, win.LVM_UPDATE, uintptr(index), 0) {\n\t\treturn newError(\"SendMessage(LVM_UPDATE)\")\n\t}\n\tif win.FALSE == win.SendMessage(tv.hwndNormalLV, win.LVM_UPDATE, uintptr(index), 0) {\n\t\treturn newError(\"SendMessage(LVM_UPDATE)\")\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TableView) applyImageListForImage(image interface{}) {\n\ttv.hIml, tv.usingSysIml, _ = imageListForImage(image, tv.DPI())\n\n\ttv.applyImageList()\n\n\ttv.imageUintptr2Index = make(map[uintptr]int32)\n\ttv.filePath2IconIndex = make(map[string]int32)\n}\n\nfunc (tv *TableView) applyImageList() {\n\twin.SendMessage(tv.hwndFrozenLV, win.LVM_SETIMAGELIST, win.LVSIL_SMALL, uintptr(tv.hIml))\n\twin.SendMessage(tv.hwndNormalLV, win.LVM_SETIMAGELIST, win.LVSIL_SMALL, uintptr(tv.hIml))\n}\n\nfunc (tv *TableView) disposeImageListAndCaches() {\n\tif tv.hIml != 0 && !tv.usingSysIml {\n\t\twin.SendMessage(tv.hwndFrozenLV, win.LVM_SETIMAGELIST, win.LVSIL_SMALL, 0)\n\t\twin.SendMessage(tv.hwndNormalLV, win.LVM_SETIMAGELIST, win.LVSIL_SMALL, 0)\n\n\t\twin.ImageList_Destroy(tv.hIml)\n\t}\n\ttv.hIml = 0\n\n\ttv.imageUintptr2Index = nil\n\ttv.filePath2IconIndex = nil\n}\n\nfunc (tv *TableView) Focused() bool {\n\tfocused := win.GetFocus()\n\n\treturn focused == tv.hwndFrozenLV || focused == tv.hwndNormalLV\n}\n\nfunc (tv *TableView) maybePublishFocusChanged(hwnd win.HWND, msg uint32, wp uintptr) {\n\tfocused := msg == win.WM_SETFOCUS\n\n\tif focused != tv.focused && wp != uintptr(tv.hwndFrozenLV) && wp != uintptr(tv.hwndNormalLV) {\n\t\ttv.focused = focused\n\t\ttv.focusedChangedPublisher.Publish()\n\t}\n}\n\nfunc tableViewFrozenLVWndProc(hwnd win.HWND, msg uint32, wp, lp uintptr) uintptr {\n\ttv := (*TableView)(unsafe.Pointer(windowFromHandle(win.GetParent(hwnd)).AsWindowBase()))\n\n\tswitch msg {\n\tcase win.WM_NCCALCSIZE:\n\t\tensureWindowLongBits(hwnd, win.GWL_STYLE, win.WS_HSCROLL|win.WS_VSCROLL, false)\n\n\tcase win.WM_SETFOCUS:\n\t\twin.SetFocus(tv.hwndNormalLV)\n\t\ttv.maybePublishFocusChanged(hwnd, msg, wp)\n\n\tcase win.WM_KILLFOCUS:\n\t\ttv.maybePublishFocusChanged(hwnd, msg, wp)\n\n\tcase win.WM_MOUSEWHEEL:\n\t\ttableViewNormalLVWndProc(tv.hwndNormalLV, msg, wp, lp)\n\t}\n\n\treturn tv.lvWndProc(tv.frozenLVOrigWndProcPtr, hwnd, msg, wp, lp)\n}\n\nfunc tableViewNormalLVWndProc(hwnd win.HWND, msg uint32, wp, lp uintptr) uintptr {\n\ttv := (*TableView)(unsafe.Pointer(windowFromHandle(win.GetParent(hwnd)).AsWindowBase()))\n\n\tswitch msg {\n\tcase win.WM_LBUTTONDOWN, win.WM_RBUTTONDOWN:\n\t\twin.SetFocus(tv.hwndFrozenLV)\n\n\tcase win.WM_SETFOCUS:\n\t\ttv.invalidateBorderInParent()\n\t\ttv.maybePublishFocusChanged(hwnd, msg, wp)\n\n\tcase win.WM_KILLFOCUS:\n\t\twin.SendMessage(tv.hwndFrozenLV, msg, wp, lp)\n\t\ttv.WndProc(tv.hWnd, msg, wp, lp)\n\t\ttv.maybePublishFocusChanged(hwnd, msg, wp)\n\t}\n\n\tresult := tv.lvWndProc(tv.normalLVOrigWndProcPtr, hwnd, msg, wp, lp)\n\n\tvar off uint32 = win.WS_HSCROLL | win.WS_VSCROLL\n\tif tv.scrollbarOrientation&Horizontal != 0 {\n\t\toff &^= win.WS_HSCROLL\n\t}\n\tif tv.scrollbarOrientation&Vertical != 0 {\n\t\toff &^= win.WS_VSCROLL\n\t}\n\tif off != 0 {\n\t\tensureWindowLongBits(hwnd, win.GWL_STYLE, off, false)\n\t}\n\n\treturn result\n}\n\nfunc (tv *TableView) lvWndProc(origWndProcPtr uintptr, hwnd win.HWND, msg uint32, wp, lp uintptr) uintptr {\n\tvar hwndOther win.HWND\n\tif hwnd == tv.hwndFrozenLV {\n\t\thwndOther = tv.hwndNormalLV\n\t} else {\n\t\thwndOther = tv.hwndFrozenLV\n\t}\n\n\tvar maybeStretchLastColumn bool\n\n\tswitch msg {\n\tcase win.WM_ERASEBKGND:\n\t\tmaybeStretchLastColumn = true\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lp))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tmaybeStretchLastColumn = int(wp.Cx) < tv.WidthPixels()\n\n\tcase win.WM_GETDLGCODE:\n\t\tif wp == win.VK_RETURN {\n\t\t\treturn win.DLGC_WANTALLKEYS\n\t\t}\n\n\tcase win.WM_LBUTTONDOWN, win.WM_RBUTTONDOWN, win.WM_LBUTTONDBLCLK, win.WM_RBUTTONDBLCLK:\n\t\tvar hti win.LVHITTESTINFO\n\t\thti.Pt = win.POINT{win.GET_X_LPARAM(lp), win.GET_Y_LPARAM(lp)}\n\t\twin.SendMessage(hwnd, win.LVM_HITTEST, 0, uintptr(unsafe.Pointer(&hti)))\n\n\t\ttv.itemIndexOfLastMouseButtonDown = int(hti.IItem)\n\n\t\tif hti.Flags == win.LVHT_NOWHERE {\n\t\t\tif tv.MultiSelection() {\n\t\t\t\ttv.publishNextSelClear = true\n\t\t\t} else {\n\t\t\t\tif tv.CheckBoxes() {\n\t\t\t\t\tif tv.currentIndex > -1 {\n\t\t\t\t\t\ttv.SetCurrentIndex(-1)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// We keep the current item, if in single item selection mode without check boxes.\n\t\t\t\t\twin.SetFocus(tv.hwndFrozenLV)\n\t\t\t\t\treturn 0\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif tv.IgnoreNowhere() {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t}\n\n\t\tswitch msg {\n\t\tcase win.WM_LBUTTONDOWN, win.WM_RBUTTONDOWN:\n\t\t\tif hti.Flags == win.LVHT_ONITEMSTATEICON &&\n\t\t\t\ttv.itemChecker != nil &&\n\t\t\t\ttv.CheckBoxes() {\n\n\t\t\t\ttv.toggleItemChecked(int(hti.IItem))\n\t\t\t}\n\n\t\tcase win.WM_LBUTTONDBLCLK, win.WM_RBUTTONDBLCLK:\n\t\t\tif tv.currentIndex != tv.prevIndex && tv.itemStateChangedEventDelay > 0 {\n\t\t\t\ttv.prevIndex = tv.currentIndex\n\t\t\t\ttv.currentIndexChangedPublisher.Publish()\n\t\t\t\ttv.currentItemChangedPublisher.Publish()\n\t\t\t}\n\t\t}\n\n\tcase win.WM_LBUTTONUP, win.WM_RBUTTONUP:\n\t\ttv.itemIndexOfLastMouseButtonDown = -1\n\n\tcase win.WM_MOUSEMOVE, win.WM_MOUSELEAVE:\n\t\tif tv.inMouseEvent {\n\t\t\tbreak\n\t\t}\n\t\ttv.inMouseEvent = true\n\t\tdefer func() {\n\t\t\ttv.inMouseEvent = false\n\t\t}()\n\n\t\tif msg == win.WM_MOUSEMOVE {\n\t\t\ty := int(win.GET_Y_LPARAM(lp))\n\t\t\tlp = uintptr(win.MAKELONG(0, uint16(y)))\n\t\t}\n\n\t\twin.SendMessage(hwndOther, msg, wp, lp)\n\n\tcase win.WM_KEYDOWN:\n\t\tif wp == win.VK_SPACE &&\n\t\t\ttv.currentIndex > -1 &&\n\t\t\ttv.itemChecker != nil &&\n\t\t\ttv.CheckBoxes() {\n\n\t\t\ttv.toggleItemChecked(tv.currentIndex)\n\t\t}\n\n\t\ttv.handleKeyDown(wp, lp)\n\n\tcase win.WM_KEYUP:\n\t\ttv.handleKeyUp(wp, lp)\n\n\tcase win.WM_NOTIFY:\n\t\tnmh := ((*win.NMHDR)(unsafe.Pointer(lp)))\n\t\tswitch nmh.HwndFrom {\n\t\tcase tv.hwndFrozenHdr, tv.hwndNormalHdr:\n\t\t\tif nmh.Code == win.NM_CUSTOMDRAW {\n\t\t\t\treturn tableViewHdrWndProc(nmh.HwndFrom, msg, wp, lp)\n\t\t\t}\n\t\t}\n\n\t\tswitch nmh.Code {\n\t\tcase win.LVN_GETDISPINFO:\n\t\t\tdi := (*win.NMLVDISPINFO)(unsafe.Pointer(lp))\n\n\t\t\trow := int(di.Item.IItem)\n\t\t\tcol := tv.fromLVColIdx(hwnd == tv.hwndFrozenLV, di.Item.ISubItem)\n\t\t\tif col == -1 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif di.Item.Mask&win.LVIF_TEXT > 0 {\n\t\t\t\tvalue := tv.model.Value(row, col)\n\t\t\t\tvar text string\n\t\t\t\tif format := tv.columns.items[col].formatFunc; format != nil {\n\t\t\t\t\ttext = format(value)\n\t\t\t\t} else {\n\t\t\t\t\tswitch val := value.(type) {\n\t\t\t\t\tcase string:\n\t\t\t\t\t\ttext = val\n\n\t\t\t\t\tcase float32:\n\t\t\t\t\t\tprec := tv.columns.items[col].precision\n\t\t\t\t\t\tif prec == 0 {\n\t\t\t\t\t\t\tprec = 2\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttext = FormatFloatGrouped(float64(val), prec)\n\n\t\t\t\t\tcase float64:\n\t\t\t\t\t\tprec := tv.columns.items[col].precision\n\t\t\t\t\t\tif prec == 0 {\n\t\t\t\t\t\t\tprec = 2\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttext = FormatFloatGrouped(val, prec)\n\n\t\t\t\t\tcase time.Time:\n\t\t\t\t\t\tif val.Year() > 1601 {\n\t\t\t\t\t\t\ttext = val.Format(tv.columns.items[col].format)\n\t\t\t\t\t\t}\n\n\t\t\t\t\tcase bool:\n\t\t\t\t\t\tif val {\n\t\t\t\t\t\t\ttext = checkmark\n\t\t\t\t\t\t}\n\n\t\t\t\t\tcase *big.Rat:\n\t\t\t\t\t\tprec := tv.columns.items[col].precision\n\t\t\t\t\t\tif prec == 0 {\n\t\t\t\t\t\t\tprec = 2\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttext = formatBigRatGrouped(val, prec)\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\ttext = fmt.Sprintf(tv.columns.items[col].format, val)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tutf16 := syscall.StringToUTF16(text)\n\t\t\t\tbuf := (*[264]uint16)(unsafe.Pointer(di.Item.PszText))\n\t\t\t\tmax := mini(len(utf16), int(di.Item.CchTextMax))\n\t\t\t\tcopy((*buf)[:], utf16[:max])\n\t\t\t\t(*buf)[max-1] = 0\n\t\t\t}\n\n\t\t\tif (tv.imageProvider != nil || tv.styler != nil) && di.Item.Mask&win.LVIF_IMAGE > 0 {\n\t\t\t\tvar image interface{}\n\t\t\t\tif di.Item.ISubItem == 0 {\n\t\t\t\t\tif ip := tv.imageProvider; ip != nil && image == nil {\n\t\t\t\t\t\timage = ip.Image(row)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif styler := tv.styler; styler != nil && image == nil {\n\t\t\t\t\ttv.style.row = row\n\t\t\t\t\ttv.style.col = col\n\t\t\t\t\ttv.style.bounds = Rectangle{}\n\t\t\t\t\ttv.style.dpi = tv.DPI()\n\t\t\t\t\ttv.style.Image = nil\n\n\t\t\t\t\tstyler.StyleCell(&tv.style)\n\n\t\t\t\t\timage = tv.style.Image\n\t\t\t\t}\n\n\t\t\t\tif image != nil {\n\t\t\t\t\tif tv.hIml == 0 {\n\t\t\t\t\t\ttv.applyImageListForImage(image)\n\t\t\t\t\t}\n\n\t\t\t\t\tdi.Item.IImage = imageIndexMaybeAdd(\n\t\t\t\t\t\timage,\n\t\t\t\t\t\ttv.hIml,\n\t\t\t\t\t\ttv.usingSysIml,\n\t\t\t\t\t\ttv.imageUintptr2Index,\n\t\t\t\t\t\ttv.filePath2IconIndex,\n\t\t\t\t\t\ttv.DPI())\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif di.Item.ISubItem == 0 && di.Item.StateMask&win.LVIS_STATEIMAGEMASK > 0 &&\n\t\t\t\ttv.itemChecker != nil {\n\t\t\t\tchecked := tv.itemChecker.Checked(row)\n\n\t\t\t\tif checked {\n\t\t\t\t\tdi.Item.State = 0x2000\n\t\t\t\t} else {\n\t\t\t\t\tdi.Item.State = 0x1000\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase win.NM_CUSTOMDRAW:\n\t\t\tnmlvcd := (*win.NMLVCUSTOMDRAW)(unsafe.Pointer(lp))\n\n\t\t\tif nmlvcd.IIconPhase == 0 {\n\t\t\t\trow := int(nmlvcd.Nmcd.DwItemSpec)\n\t\t\t\tcol := tv.fromLVColIdx(hwnd == tv.hwndFrozenLV, nmlvcd.ISubItem)\n\t\t\t\tif col == -1 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tapplyCellStyle := func() int {\n\t\t\t\t\tif tv.styler != nil {\n\t\t\t\t\t\tdpi := tv.DPI()\n\n\t\t\t\t\t\ttv.style.row = row\n\t\t\t\t\t\ttv.style.col = col\n\t\t\t\t\t\ttv.style.bounds = rectangleFromRECT(nmlvcd.Nmcd.Rc)\n\t\t\t\t\t\ttv.style.dpi = dpi\n\t\t\t\t\t\ttv.style.hdc = nmlvcd.Nmcd.Hdc\n\t\t\t\t\t\ttv.style.BackgroundColor = tv.itemBGColor\n\t\t\t\t\t\ttv.style.TextColor = tv.itemTextColor\n\t\t\t\t\t\ttv.style.Font = nil\n\t\t\t\t\t\ttv.style.Image = nil\n\n\t\t\t\t\t\ttv.styler.StyleCell(&tv.style)\n\n\t\t\t\t\t\tdefer func() {\n\t\t\t\t\t\t\ttv.style.bounds = Rectangle{}\n\t\t\t\t\t\t\tif tv.style.canvas != nil {\n\t\t\t\t\t\t\t\ttv.style.canvas.Dispose()\n\t\t\t\t\t\t\t\ttv.style.canvas = nil\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttv.style.hdc = 0\n\t\t\t\t\t\t}()\n\n\t\t\t\t\t\tif tv.style.canvas != nil {\n\t\t\t\t\t\t\treturn win.CDRF_SKIPDEFAULT\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tnmlvcd.ClrTextBk = win.COLORREF(tv.style.BackgroundColor)\n\t\t\t\t\t\tnmlvcd.ClrText = win.COLORREF(tv.style.TextColor)\n\n\t\t\t\t\t\tfont := tv.style.Font\n\t\t\t\t\t\tif font == nil {\n\t\t\t\t\t\t\tfont = tv.Font()\n\t\t\t\t\t\t}\n\t\t\t\t\t\twin.SelectObject(nmlvcd.Nmcd.Hdc, win.HGDIOBJ(font.handleForDPI(dpi)))\n\t\t\t\t\t}\n\n\t\t\t\t\treturn 0\n\t\t\t\t}\n\n\t\t\t\tswitch nmlvcd.Nmcd.DwDrawStage {\n\t\t\t\tcase win.CDDS_PREPAINT:\n\t\t\t\t\treturn win.CDRF_NOTIFYITEMDRAW\n\n\t\t\t\tcase win.CDDS_ITEMPREPAINT:\n\t\t\t\t\tvar selected bool\n\t\t\t\t\tif itemState := win.SendMessage(hwnd, win.LVM_GETITEMSTATE, nmlvcd.Nmcd.DwItemSpec, win.LVIS_SELECTED); itemState&win.LVIS_SELECTED != 0 {\n\t\t\t\t\t\tselected = true\n\n\t\t\t\t\t\ttv.itemBGColor = tv.themeSelectedBGColor\n\t\t\t\t\t\ttv.itemTextColor = tv.themeSelectedTextColor\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttv.itemBGColor = tv.themeNormalBGColor\n\t\t\t\t\t\ttv.itemTextColor = tv.themeNormalTextColor\n\t\t\t\t\t}\n\n\t\t\t\t\tif !selected && tv.alternatingRowBG && row%2 == 1 {\n\t\t\t\t\t\ttv.itemBGColor = tv.alternatingRowBGColor\n\t\t\t\t\t\ttv.itemTextColor = tv.alternatingRowTextColor\n\t\t\t\t\t}\n\n\t\t\t\t\ttv.style.BackgroundColor = tv.itemBGColor\n\t\t\t\t\ttv.style.TextColor = tv.itemTextColor\n\n\t\t\t\t\tif tv.styler != nil {\n\t\t\t\t\t\ttv.style.row = row\n\t\t\t\t\t\ttv.style.col = -1\n\t\t\t\t\t\ttv.style.bounds = rectangleFromRECT(nmlvcd.Nmcd.Rc)\n\t\t\t\t\t\ttv.style.dpi = tv.DPI()\n\t\t\t\t\t\ttv.style.hdc = 0\n\t\t\t\t\t\ttv.style.Font = nil\n\t\t\t\t\t\ttv.style.Image = nil\n\n\t\t\t\t\t\ttv.styler.StyleCell(&tv.style)\n\n\t\t\t\t\t\ttv.itemFont = tv.style.Font\n\t\t\t\t\t}\n\n\t\t\t\t\tif selected {\n\t\t\t\t\t\ttv.style.BackgroundColor = tv.itemBGColor\n\t\t\t\t\t\ttv.style.TextColor = tv.itemTextColor\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttv.itemBGColor = tv.style.BackgroundColor\n\t\t\t\t\t\ttv.itemTextColor = tv.style.TextColor\n\t\t\t\t\t}\n\n\t\t\t\t\tif tv.style.BackgroundColor != tv.themeNormalBGColor {\n\t\t\t\t\t\tvar color Color\n\t\t\t\t\t\tif selected && !tv.Focused() {\n\t\t\t\t\t\t\tcolor = tv.themeSelectedNotFocusedBGColor\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcolor = tv.style.BackgroundColor\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif brush, _ := NewSolidColorBrush(color); brush != nil {\n\t\t\t\t\t\t\tdefer brush.Dispose()\n\n\t\t\t\t\t\t\tcanvas, _ := newCanvasFromHDC(nmlvcd.Nmcd.Hdc)\n\t\t\t\t\t\t\tcanvas.FillRectanglePixels(brush, rectangleFromRECT(nmlvcd.Nmcd.Rc))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tnmlvcd.ClrText = win.COLORREF(tv.style.TextColor)\n\t\t\t\t\tnmlvcd.ClrTextBk = win.COLORREF(tv.style.BackgroundColor)\n\n\t\t\t\t\treturn win.CDRF_NOTIFYSUBITEMDRAW\n\n\t\t\t\tcase win.CDDS_ITEMPREPAINT | win.CDDS_SUBITEM:\n\t\t\t\t\tif tv.itemFont != nil {\n\t\t\t\t\t\twin.SelectObject(nmlvcd.Nmcd.Hdc, win.HGDIOBJ(tv.itemFont.handleForDPI(tv.DPI())))\n\t\t\t\t\t}\n\n\t\t\t\t\tif applyCellStyle() == win.CDRF_SKIPDEFAULT && win.IsAppThemed() {\n\t\t\t\t\t\treturn win.CDRF_SKIPDEFAULT\n\t\t\t\t\t}\n\n\t\t\t\t\treturn win.CDRF_NEWFONT | win.CDRF_SKIPPOSTPAINT | win.CDRF_NOTIFYPOSTPAINT\n\n\t\t\t\tcase win.CDDS_ITEMPOSTPAINT | win.CDDS_SUBITEM:\n\t\t\t\t\tif applyCellStyle() == win.CDRF_SKIPDEFAULT {\n\t\t\t\t\t\treturn win.CDRF_SKIPDEFAULT\n\t\t\t\t\t}\n\n\t\t\t\t\treturn win.CDRF_NEWFONT | win.CDRF_SKIPPOSTPAINT\n\t\t\t\t}\n\n\t\t\t\treturn win.CDRF_SKIPPOSTPAINT\n\t\t\t}\n\n\t\t\treturn win.CDRF_SKIPPOSTPAINT\n\n\t\tcase win.LVN_BEGINSCROLL:\n\t\t\tif tv.scrolling {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttv.scrolling = true\n\t\t\tdefer func() {\n\t\t\t\ttv.scrolling = false\n\t\t\t}()\n\n\t\t\tvar rc win.RECT\n\t\t\twin.SendMessage(hwnd, win.LVM_GETITEMRECT, 0, uintptr(unsafe.Pointer(&rc)))\n\n\t\t\tnmlvs := (*win.NMLVSCROLL)(unsafe.Pointer(lp))\n\t\t\twin.SendMessage(hwndOther, win.LVM_SCROLL, 0, uintptr(nmlvs.Dy*(rc.Bottom-rc.Top)))\n\n\t\tcase win.LVN_COLUMNCLICK:\n\t\t\tnmlv := (*win.NMLISTVIEW)(unsafe.Pointer(lp))\n\n\t\t\tcol := tv.fromLVColIdx(hwnd == tv.hwndFrozenLV, nmlv.ISubItem)\n\n\t\t\tif sorter, ok := tv.model.(Sorter); ok && sorter.ColumnSortable(col) {\n\t\t\t\tprevCol := sorter.SortedColumn()\n\t\t\t\tvar order SortOrder\n\t\t\t\tif col != prevCol || sorter.SortOrder() == SortDescending {\n\t\t\t\t\torder = SortAscending\n\t\t\t\t} else {\n\t\t\t\t\torder = SortDescending\n\t\t\t\t}\n\t\t\t\ttv.sortedColumnIndex = col\n\t\t\t\ttv.sortOrder = order\n\t\t\t\tsorter.Sort(col, order)\n\t\t\t}\n\n\t\t\ttv.columnClickedPublisher.Publish(col)\n\n\t\tcase win.LVN_ITEMCHANGED:\n\t\t\tnmlv := (*win.NMLISTVIEW)(unsafe.Pointer(lp))\n\n\t\t\tif tv.hwndItemChanged != 0 && tv.hwndItemChanged != hwnd {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttv.hwndItemChanged = hwnd\n\t\t\tdefer func() {\n\t\t\t\ttv.hwndItemChanged = 0\n\t\t\t}()\n\n\t\t\ttv.copySelectedIndexes(hwndOther, hwnd)\n\n\t\t\tif nmlv.IItem == -1 && !tv.publishNextSelClear {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttv.publishNextSelClear = false\n\n\t\t\tselectedNow := nmlv.UNewState&win.LVIS_SELECTED > 0\n\t\t\tselectedBefore := nmlv.UOldState&win.LVIS_SELECTED > 0\n\t\t\tif tv.itemIndexOfLastMouseButtonDown != -1 && selectedNow && !selectedBefore && ModifiersDown()&(ModControl|ModShift) == 0 {\n\t\t\t\ttv.prevIndex = tv.currentIndex\n\t\t\t\ttv.currentIndex = int(nmlv.IItem)\n\t\t\t\tif tv.itemStateChangedEventDelay > 0 {\n\t\t\t\t\ttv.delayedCurrentIndexChangedCanceled = false\n\t\t\t\t\tif 0 == win.SetTimer(\n\t\t\t\t\t\ttv.hWnd,\n\t\t\t\t\t\ttableViewCurrentIndexChangedTimerId,\n\t\t\t\t\t\tuint32(tv.itemStateChangedEventDelay),\n\t\t\t\t\t\t0) {\n\n\t\t\t\t\t\tlastError(\"SetTimer\")\n\t\t\t\t\t}\n\n\t\t\t\t\ttv.SetCurrentIndex(int(nmlv.IItem))\n\t\t\t\t} else {\n\t\t\t\t\ttv.SetCurrentIndex(int(nmlv.IItem))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif selectedNow != selectedBefore {\n\t\t\t\tif !tv.inSetSelectedIndexes && tv.MultiSelection() {\n\t\t\t\t\ttv.updateSelectedIndexes()\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase win.LVN_ODSTATECHANGED:\n\t\t\tif tv.hwndItemChanged != 0 && tv.hwndItemChanged != hwnd {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttv.hwndItemChanged = hwnd\n\t\t\tdefer func() {\n\t\t\t\ttv.hwndItemChanged = 0\n\t\t\t}()\n\n\t\t\ttv.copySelectedIndexes(hwndOther, hwnd)\n\n\t\t\ttv.updateSelectedIndexes()\n\n\t\tcase win.LVN_ITEMACTIVATE:\n\t\t\tnmia := (*win.NMITEMACTIVATE)(unsafe.Pointer(lp))\n\n\t\t\tif tv.itemStateChangedEventDelay > 0 {\n\t\t\t\ttv.delayedCurrentIndexChangedCanceled = true\n\t\t\t}\n\n\t\t\tif int(nmia.IItem) != tv.currentIndex {\n\t\t\t\ttv.SetCurrentIndex(int(nmia.IItem))\n\t\t\t\ttv.currentIndexChangedPublisher.Publish()\n\t\t\t\ttv.currentItemChangedPublisher.Publish()\n\t\t\t}\n\n\t\t\ttv.itemActivatedPublisher.Publish()\n\n\t\tcase win.HDN_ITEMCHANGING:\n\t\t\ttv.updateLVSizes()\n\t\t}\n\n\tcase win.WM_UPDATEUISTATE:\n\t\tswitch win.LOWORD(uint32(wp)) {\n\t\tcase win.UIS_SET:\n\t\t\twp |= win.UISF_HIDEFOCUS << 16\n\n\t\tcase win.UIS_CLEAR, win.UIS_INITIALIZE:\n\t\t\twp &^= ^uintptr(win.UISF_HIDEFOCUS << 16)\n\t\t}\n\t}\n\n\tlpFixed := lp\n\tfixXInLP := func() {\n\t\t// fmt.Printf(\"hwnd == tv.hwndNormalLV: %t, tv.hasFrozenColumn: %t\\n\", hwnd == tv.hwndNormalLV, tv.hasFrozenColumn)\n\t\tif hwnd == tv.hwndNormalLV && tv.hasFrozenColumn {\n\t\t\tvar rc win.RECT\n\t\t\tif win.GetWindowRect(tv.hwndFrozenLV, &rc) {\n\t\t\t\tx := int(win.GET_X_LPARAM(lp)) + int(rc.Right-rc.Left)\n\t\t\t\ty := int(win.GET_Y_LPARAM(lp))\n\n\t\t\t\tlpFixed = uintptr(win.MAKELONG(uint16(x), uint16(y)))\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch msg {\n\tcase win.WM_LBUTTONDOWN, win.WM_MBUTTONDOWN, win.WM_RBUTTONDOWN:\n\t\tfixXInLP()\n\t\ttv.publishMouseEvent(&tv.mouseDownPublisher, msg, wp, lpFixed)\n\n\tcase win.WM_LBUTTONUP, win.WM_MBUTTONUP, win.WM_RBUTTONUP:\n\t\tfixXInLP()\n\t\ttv.publishMouseEvent(&tv.mouseUpPublisher, msg, wp, lpFixed)\n\n\tcase win.WM_MOUSEMOVE:\n\t\tfixXInLP()\n\t\ttv.publishMouseEvent(&tv.mouseMovePublisher, msg, wp, lpFixed)\n\n\tcase win.WM_MOUSEWHEEL:\n\t\tfixXInLP()\n\t\ttv.publishMouseWheelEvent(&tv.mouseWheelPublisher, wp, lpFixed)\n\t}\n\n\tif maybeStretchLastColumn {\n\t\tif tv.lastColumnStretched && !tv.busyStretchingLastColumn {\n\t\t\tif normalVisColCount := tv.visibleColumnCount() - tv.visibleFrozenColumnCount(); normalVisColCount == 0 || normalVisColCount > 0 == (hwnd == tv.hwndNormalLV) {\n\t\t\t\ttv.busyStretchingLastColumn = true\n\t\t\t\tdefer func() {\n\t\t\t\t\ttv.busyStretchingLastColumn = false\n\t\t\t\t}()\n\t\t\t\ttv.StretchLastColumn()\n\t\t\t}\n\t\t}\n\n\t\tif msg == win.WM_ERASEBKGND {\n\t\t\treturn 1\n\t\t}\n\t}\n\n\treturn win.CallWindowProc(origWndProcPtr, hwnd, msg, wp, lp)\n}\n\nfunc tableViewHdrWndProc(hwnd win.HWND, msg uint32, wp, lp uintptr) uintptr {\n\ttv := (*TableView)(unsafe.Pointer(windowFromHandle(win.GetParent(win.GetParent(hwnd))).AsWindowBase()))\n\n\tvar origWndProcPtr uintptr\n\tif hwnd == tv.hwndFrozenHdr {\n\t\torigWndProcPtr = tv.frozenHdrOrigWndProcPtr\n\t} else {\n\t\torigWndProcPtr = tv.normalHdrOrigWndProcPtr\n\t}\n\n\tswitch msg {\n\tcase win.WM_NOTIFY:\n\t\tswitch ((*win.NMHDR)(unsafe.Pointer(lp))).Code {\n\t\tcase win.NM_CUSTOMDRAW:\n\t\t\tif tv.customHeaderHeight == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tnmcd := (*win.NMCUSTOMDRAW)(unsafe.Pointer(lp))\n\n\t\t\tswitch nmcd.DwDrawStage {\n\t\t\tcase win.CDDS_PREPAINT:\n\t\t\t\treturn win.CDRF_NOTIFYITEMDRAW\n\n\t\t\tcase win.CDDS_ITEMPREPAINT:\n\t\t\t\treturn win.CDRF_NOTIFYPOSTPAINT\n\n\t\t\tcase win.CDDS_ITEMPOSTPAINT:\n\t\t\t\tcol := tv.fromLVColIdx(hwnd == tv.hwndFrozenHdr, int32(nmcd.DwItemSpec))\n\t\t\t\tif tv.styler != nil && col > -1 {\n\t\t\t\t\ttv.style.row = -1\n\t\t\t\t\ttv.style.col = col\n\t\t\t\t\ttv.style.bounds = rectangleFromRECT(nmcd.Rc)\n\t\t\t\t\ttv.style.dpi = tv.DPI()\n\t\t\t\t\ttv.style.hdc = nmcd.Hdc\n\t\t\t\t\ttv.style.TextColor = tv.themeNormalTextColor\n\t\t\t\t\ttv.style.Font = nil\n\n\t\t\t\t\ttv.styler.StyleCell(&tv.style)\n\n\t\t\t\t\tdefer func() {\n\t\t\t\t\t\ttv.style.bounds = Rectangle{}\n\t\t\t\t\t\tif tv.style.canvas != nil {\n\t\t\t\t\t\t\ttv.style.canvas.Dispose()\n\t\t\t\t\t\t\ttv.style.canvas = nil\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttv.style.hdc = 0\n\t\t\t\t\t}()\n\t\t\t\t}\n\n\t\t\t\treturn win.CDRF_DODEFAULT\n\t\t\t}\n\n\t\t\treturn win.CDRF_DODEFAULT\n\t\t}\n\n\tcase win.HDM_LAYOUT:\n\t\tif tv.customHeaderHeight == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tresult := win.CallWindowProc(origWndProcPtr, hwnd, msg, wp, lp)\n\n\t\thdl := (*win.HDLAYOUT)(unsafe.Pointer(lp))\n\t\thdl.Prc.Top = int32(tv.customHeaderHeight)\n\t\thdl.Pwpos.Cy = int32(tv.customHeaderHeight)\n\n\t\treturn result\n\n\tcase win.WM_MOUSEMOVE, win.WM_LBUTTONDOWN, win.WM_LBUTTONUP, win.WM_MBUTTONDOWN, win.WM_MBUTTONUP, win.WM_RBUTTONDOWN, win.WM_RBUTTONUP:\n\t\thti := win.HDHITTESTINFO{Pt: win.POINT{int32(win.GET_X_LPARAM(lp)), int32(win.GET_Y_LPARAM(lp))}}\n\t\twin.SendMessage(hwnd, win.HDM_HITTEST, 0, uintptr(unsafe.Pointer(&hti)))\n\t\tif hti.IItem == -1 {\n\t\t\ttv.group.toolTip.setText(hwnd, \"\")\n\t\t\tbreak\n\t\t}\n\n\t\tcol := tv.fromLVColIdx(hwnd == tv.hwndFrozenHdr, hti.IItem)\n\t\ttext := tv.columns.At(col).TitleEffective()\n\n\t\tvar rc win.RECT\n\t\tif 0 == win.SendMessage(hwnd, win.HDM_GETITEMRECT, uintptr(hti.IItem), uintptr(unsafe.Pointer(&rc))) {\n\t\t\ttv.group.toolTip.setText(hwnd, \"\")\n\t\t\tbreak\n\t\t}\n\n\t\tsize := calculateTextSize(text, tv.Font(), tv.DPI(), 0, hwnd)\n\t\tif size.Width <= rectangleFromRECT(rc).Width-int(win.SendMessage(hwnd, win.HDM_GETBITMAPMARGIN, 0, 0)) {\n\t\t\ttv.group.toolTip.setText(hwnd, \"\")\n\t\t\tbreak\n\t\t}\n\n\t\tif tv.group.toolTip.text(hwnd) == text {\n\t\t\tbreak\n\t\t}\n\n\t\ttv.group.toolTip.setText(hwnd, text)\n\n\t\tm := win.MSG{\n\t\t\tHWnd:    hwnd,\n\t\t\tMessage: msg,\n\t\t\tWParam:  wp,\n\t\t\tLParam:  lp,\n\t\t\tPt:      hti.Pt,\n\t\t}\n\n\t\ttv.group.toolTip.SendMessage(win.TTM_RELAYEVENT, 0, uintptr(unsafe.Pointer(&m)))\n\t}\n\n\treturn win.CallWindowProc(origWndProcPtr, hwnd, msg, wp, lp)\n}\n\nfunc (tv *TableView) WndProc(hwnd win.HWND, msg uint32, wp, lp uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_NOTIFY:\n\t\tnmh := (*win.NMHDR)(unsafe.Pointer(lp))\n\t\tswitch nmh.HwndFrom {\n\t\tcase tv.hwndFrozenLV:\n\t\t\treturn tableViewFrozenLVWndProc(nmh.HwndFrom, msg, wp, lp)\n\n\t\tcase tv.hwndNormalLV:\n\t\t\treturn tableViewNormalLVWndProc(nmh.HwndFrom, msg, wp, lp)\n\t\t}\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lp))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif tv.formActivatingHandle == -1 {\n\t\t\tif form := tv.Form(); form != nil {\n\t\t\t\ttv.formActivatingHandle = form.Activating().Attach(func() {\n\t\t\t\t\tif tv.hwndNormalLV == win.GetFocus() {\n\t\t\t\t\t\twin.SetFocus(tv.hwndFrozenLV)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\ttv.updateLVSizes()\n\n\t\t// FIXME: The InvalidateRect and redrawItems calls below prevent\n\t\t// painting glitches on resize. Though this seems to work reasonably\n\t\t// well, in the long run we would like to find the root cause of this\n\t\t// issue and come up with a better fix.\n\t\tdpi := uint32(tv.DPI())\n\t\tvar rc win.RECT\n\n\t\tvsbWidth := win.GetSystemMetricsForDpi(win.SM_CXVSCROLL, dpi)\n\t\trc = win.RECT{wp.Cx - vsbWidth - 1, 0, wp.Cx, wp.Cy}\n\t\twin.InvalidateRect(tv.hWnd, &rc, true)\n\n\t\thsbHeight := win.GetSystemMetricsForDpi(win.SM_CYHSCROLL, dpi)\n\t\trc = win.RECT{0, wp.Cy - hsbHeight - 1, wp.Cx, wp.Cy}\n\t\twin.InvalidateRect(tv.hWnd, &rc, true)\n\n\t\ttv.redrawItems()\n\n\tcase win.WM_TIMER:\n\t\tif !win.KillTimer(tv.hWnd, wp) {\n\t\t\tlastError(\"KillTimer\")\n\t\t}\n\n\t\tswitch wp {\n\t\tcase tableViewCurrentIndexChangedTimerId:\n\t\t\tif !tv.delayedCurrentIndexChangedCanceled {\n\t\t\t\ttv.currentIndexChangedPublisher.Publish()\n\t\t\t\ttv.currentItemChangedPublisher.Publish()\n\t\t\t}\n\n\t\tcase tableViewSelectedIndexesChangedTimerId:\n\t\t\ttv.selectedIndexesChangedPublisher.Publish()\n\t\t}\n\n\tcase win.WM_MEASUREITEM:\n\t\tmis := (*win.MEASUREITEMSTRUCT)(unsafe.Pointer(lp))\n\t\tmis.ItemHeight = uint32(tv.customRowHeight)\n\n\t\tensureWindowLongBits(tv.hwndFrozenLV, win.GWL_STYLE, win.LVS_OWNERDRAWFIXED, false)\n\t\tensureWindowLongBits(tv.hwndNormalLV, win.GWL_STYLE, win.LVS_OWNERDRAWFIXED, false)\n\n\tcase win.WM_SETFOCUS:\n\t\twin.SetFocus(tv.hwndFrozenLV)\n\n\tcase win.WM_DESTROY:\n\t\t// As we subclass all windows of system classes, we prevented the\n\t\t// clean-up code in the WM_NCDESTROY handlers of some windows from\n\t\t// being called. To fix this, we restore the original window\n\t\t// procedures here.\n\t\tif tv.frozenHdrOrigWndProcPtr != 0 {\n\t\t\twin.SetWindowLongPtr(tv.hwndFrozenHdr, win.GWLP_WNDPROC, tv.frozenHdrOrigWndProcPtr)\n\t\t}\n\t\tif tv.frozenLVOrigWndProcPtr != 0 {\n\t\t\twin.SetWindowLongPtr(tv.hwndFrozenLV, win.GWLP_WNDPROC, tv.frozenLVOrigWndProcPtr)\n\t\t}\n\t\tif tv.normalHdrOrigWndProcPtr != 0 {\n\t\t\twin.SetWindowLongPtr(tv.hwndNormalHdr, win.GWLP_WNDPROC, tv.normalHdrOrigWndProcPtr)\n\t\t}\n\t\tif tv.normalLVOrigWndProcPtr != 0 {\n\t\t\twin.SetWindowLongPtr(tv.hwndNormalLV, win.GWLP_WNDPROC, tv.normalLVOrigWndProcPtr)\n\t\t}\n\t}\n\n\treturn tv.WidgetBase.WndProc(hwnd, msg, wp, lp)\n}\n\nfunc (tv *TableView) updateLVSizes() {\n\ttv.updateLVSizesWithSpecialCare(false)\n}\n\nfunc (tv *TableView) updateLVSizesWithSpecialCare(needSpecialCare bool) {\n\tvar width int\n\tfor i := tv.columns.Len() - 1; i >= 0; i-- {\n\t\tif col := tv.columns.At(i); col.frozen && col.visible {\n\t\t\twidth += col.Width()\n\t\t}\n\t}\n\n\tdpi := tv.DPI()\n\twidthPixels := IntFrom96DPI(width, dpi)\n\n\tcb := tv.ClientBoundsPixels()\n\n\twin.MoveWindow(tv.hwndNormalLV, int32(widthPixels), 0, int32(cb.Width-widthPixels), int32(cb.Height), true)\n\n\tvar sbh int\n\tif hasWindowLongBits(tv.hwndNormalLV, win.GWL_STYLE, win.WS_HSCROLL) {\n\t\tsbh = int(win.GetSystemMetricsForDpi(win.SM_CYHSCROLL, uint32(dpi)))\n\t}\n\n\twin.MoveWindow(tv.hwndFrozenLV, 0, 0, int32(widthPixels), int32(cb.Height-sbh), true)\n\n\tif needSpecialCare {\n\t\ttv.updateLVSizesNeedsSpecialCare = true\n\t}\n\n\tif tv.updateLVSizesNeedsSpecialCare {\n\t\twin.ShowWindow(tv.hwndNormalLV, win.SW_HIDE)\n\t\twin.ShowWindow(tv.hwndNormalLV, win.SW_SHOW)\n\t}\n\n\tif !needSpecialCare {\n\t\ttv.updateLVSizesNeedsSpecialCare = false\n\t}\n}\n\nfunc (*TableView) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn NewGreedyLayoutItem()\n}\n\nfunc (tv *TableView) SetScrollbarOrientation(orientation Orientation) {\n\ttv.scrollbarOrientation = orientation\n}\n\nfunc (tv *TableView) ScrollbarOrientation() Orientation {\n\treturn tv.scrollbarOrientation\n}\n"
  },
  {
    "path": "tableviewcolumn.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\n// TableViewColumn represents a column in a TableView.\ntype TableViewColumn struct {\n\ttv            *TableView\n\tname          string\n\tdataMember    string\n\talignment     Alignment1D\n\tformat        string\n\tprecision     int\n\ttitle         string\n\ttitleOverride string\n\twidth         int\n\tlessFunc      func(i, j int) bool\n\tformatFunc    func(value interface{}) string\n\tvisible       bool\n\tfrozen        bool\n}\n\n// NewTableViewColumn returns a new TableViewColumn.\nfunc NewTableViewColumn() *TableViewColumn {\n\treturn &TableViewColumn{\n\t\tformat:  \"%v\",\n\t\tvisible: true,\n\t\twidth:   50,\n\t}\n}\n\n// Alignment returns the alignment of the TableViewColumn.\nfunc (tvc *TableViewColumn) Alignment() Alignment1D {\n\treturn tvc.alignment\n}\n\n// SetAlignment sets the alignment of the TableViewColumn.\nfunc (tvc *TableViewColumn) SetAlignment(alignment Alignment1D) (err error) {\n\tif alignment == AlignDefault {\n\t\talignment = AlignNear\n\t}\n\n\tif alignment == tvc.alignment {\n\t\treturn nil\n\t}\n\n\told := tvc.alignment\n\tdefer func() {\n\t\tif err != nil {\n\t\t\ttvc.alignment = old\n\t\t}\n\t}()\n\n\ttvc.alignment = alignment\n\n\treturn tvc.update()\n}\n\n// DataMember returns the data member this TableViewColumn is bound against.\nfunc (tvc *TableViewColumn) DataMember() string {\n\treturn tvc.dataMember\n}\n\n// DataMemberEffective returns the effective data member this TableViewColumn is\n// bound against.\nfunc (tvc *TableViewColumn) DataMemberEffective() string {\n\tif tvc.dataMember != \"\" {\n\t\treturn tvc.dataMember\n\t}\n\n\treturn tvc.name\n}\n\n// SetDataMember sets the data member this TableViewColumn is bound against.\nfunc (tvc *TableViewColumn) SetDataMember(dataMember string) {\n\ttvc.dataMember = dataMember\n}\n\n// Format returns the format string for converting a value into a string.\nfunc (tvc *TableViewColumn) Format() string {\n\treturn tvc.format\n}\n\n// SetFormat sets the format string for converting a value into a string.\nfunc (tvc *TableViewColumn) SetFormat(format string) (err error) {\n\tif format == tvc.format {\n\t\treturn nil\n\t}\n\n\told := tvc.format\n\tdefer func() {\n\t\tif err != nil {\n\t\t\ttvc.format = old\n\t\t}\n\t}()\n\n\ttvc.format = format\n\n\tif tvc.tv == nil {\n\t\treturn nil\n\t}\n\n\treturn tvc.tv.Invalidate()\n}\n\n// Name returns the name of this TableViewColumn.\nfunc (tvc *TableViewColumn) Name() string {\n\treturn tvc.name\n}\n\n// SetName sets the name of this TableViewColumn.\nfunc (tvc *TableViewColumn) SetName(name string) {\n\ttvc.name = name\n}\n\n// Precision returns the number of decimal places for formatting float32,\n// float64 or big.Rat values.\nfunc (tvc *TableViewColumn) Precision() int {\n\treturn tvc.precision\n}\n\n// SetPrecision sets the number of decimal places for formatting float32,\n// float64 or big.Rat values.\nfunc (tvc *TableViewColumn) SetPrecision(precision int) (err error) {\n\tif precision == tvc.precision {\n\t\treturn nil\n\t}\n\n\told := tvc.precision\n\tdefer func() {\n\t\tif err != nil {\n\t\t\ttvc.precision = old\n\t\t}\n\t}()\n\n\ttvc.precision = precision\n\n\tif tvc.tv == nil {\n\t\treturn nil\n\t}\n\n\treturn tvc.tv.Invalidate()\n}\n\n// Title returns the (default) text to display in the column header.\nfunc (tvc *TableViewColumn) Title() string {\n\treturn tvc.title\n}\n\n// SetTitle sets the (default) text to display in the column header.\nfunc (tvc *TableViewColumn) SetTitle(title string) (err error) {\n\tif title == tvc.title {\n\t\treturn nil\n\t}\n\n\told := tvc.title\n\tdefer func() {\n\t\tif err != nil {\n\t\t\ttvc.title = old\n\t\t}\n\t}()\n\n\ttvc.title = title\n\n\treturn tvc.update()\n}\n\n// TitleOverride returns the (overridden by user) text to display in the column\n// header.\nfunc (tvc *TableViewColumn) TitleOverride() string {\n\treturn tvc.titleOverride\n}\n\n// SetTitleOverride sets the (overridden by user) text to display in the column\n// header.\nfunc (tvc *TableViewColumn) SetTitleOverride(titleOverride string) (err error) {\n\tif titleOverride == tvc.titleOverride {\n\t\treturn nil\n\t}\n\n\told := tvc.titleOverride\n\tdefer func() {\n\t\tif err != nil {\n\t\t\ttvc.titleOverride = old\n\t\t}\n\t}()\n\n\ttvc.titleOverride = titleOverride\n\n\treturn tvc.update()\n}\n\n// TitleEffective returns the effective text to display in the column header.\nfunc (tvc *TableViewColumn) TitleEffective() string {\n\tif tvc.titleOverride != \"\" {\n\t\treturn tvc.titleOverride\n\t}\n\n\tif tvc.title != \"\" {\n\t\treturn tvc.title\n\t}\n\n\treturn tvc.DataMemberEffective()\n}\n\n// Visible returns if the column is visible.\nfunc (tvc *TableViewColumn) Visible() bool {\n\treturn tvc.visible\n}\n\n// SetVisible sets if the column is visible.\nfunc (tvc *TableViewColumn) SetVisible(visible bool) (err error) {\n\tif visible == tvc.visible {\n\t\treturn nil\n\t}\n\n\told := tvc.visible\n\tdefer func() {\n\t\tif err != nil {\n\t\t\ttvc.visible = old\n\t\t}\n\t}()\n\n\ttvc.visible = visible\n\n\tif tvc.tv == nil {\n\t\treturn nil\n\t}\n\n\tif visible {\n\t\treturn tvc.create()\n\t}\n\n\treturn tvc.destroy()\n}\n\n// Frozen returns if the column is frozen.\nfunc (tvc *TableViewColumn) Frozen() bool {\n\treturn tvc.frozen\n}\n\n// SetFrozen sets if the column is frozen.\nfunc (tvc *TableViewColumn) SetFrozen(frozen bool) (err error) {\n\tif frozen == tvc.frozen {\n\t\treturn nil\n\t}\n\n\tvar checkBoxes bool\n\tif tvc.tv != nil {\n\t\tcheckBoxes = tvc.tv.CheckBoxes()\n\t}\n\n\told := tvc.frozen\n\tdefer func() {\n\t\tif err != nil {\n\t\t\ttvc.frozen = old\n\n\t\t\tif tvc.tv != nil {\n\t\t\t\ttvc.create()\n\t\t\t}\n\t\t}\n\n\t\tif tvc.tv != nil {\n\t\t\ttvc.tv.hasFrozenColumn = tvc.tv.visibleFrozenColumnCount() > 0\n\t\t\ttvc.tv.SetCheckBoxes(checkBoxes)\n\t\t\ttvc.tv.applyImageList()\n\t\t}\n\t}()\n\n\tif tvc.tv != nil && tvc.visible {\n\t\tif err = tvc.destroy(); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\ttvc.frozen = frozen\n\n\tif tvc.tv != nil && tvc.visible {\n\t\treturn tvc.create()\n\t}\n\n\treturn nil\n}\n\n// Width returns the width of the column in pixels.\nfunc (tvc *TableViewColumn) Width() int {\n\tif tvc.tv == nil || !tvc.visible {\n\t\treturn tvc.width\n\t}\n\n\t// We call win.SendMessage instead of tvc.sendMessage here, because some\n\t// call inside the latter interferes with scrolling via scroll bar button\n\t// when *TableViewColumn.Width is called from *TableView.StretchLastColumn.\n\tvar hwnd win.HWND\n\tif tvc.frozen {\n\t\thwnd = tvc.tv.hwndFrozenLV\n\t} else {\n\t\thwnd = tvc.tv.hwndNormalLV\n\t}\n\n\treturn tvc.tv.IntTo96DPI(int(win.SendMessage(hwnd, win.LVM_GETCOLUMNWIDTH, uintptr(tvc.indexInListView()), 0)))\n}\n\n// SetWidth sets the width of the column in pixels.\nfunc (tvc *TableViewColumn) SetWidth(width int) (err error) {\n\tif width == tvc.width {\n\t\treturn nil\n\t}\n\n\told := tvc.width\n\tdefer func() {\n\t\tif err != nil {\n\t\t\ttvc.width = old\n\t\t}\n\t}()\n\n\ttvc.width = width\n\n\treturn tvc.update()\n}\n\n// LessFunc returns the less func of this TableViewColumn.\n//\n// This function is used to provide custom sorting for models based on ReflectTableModel only.\nfunc (tvc *TableViewColumn) LessFunc() func(i, j int) bool {\n\treturn tvc.lessFunc\n}\n\n// SetLessFunc sets the less func of this TableViewColumn.\n//\n// This function is used to provide custom sorting for models based on ReflectTableModel only.\nfunc (tvc *TableViewColumn) SetLessFunc(lessFunc func(i, j int) bool) {\n\ttvc.lessFunc = lessFunc\n}\n\n// FormatFunc returns the custom format func of this TableViewColumn.\nfunc (tvc *TableViewColumn) FormatFunc() func(value interface{}) string {\n\treturn tvc.formatFunc\n}\n\n// FormatFunc sets the custom format func of this TableViewColumn.\nfunc (tvc *TableViewColumn) SetFormatFunc(formatFunc func(value interface{}) string) {\n\ttvc.formatFunc = formatFunc\n}\n\nfunc (tvc *TableViewColumn) indexInListView() int32 {\n\tif tvc.tv == nil {\n\t\treturn -1\n\t}\n\n\tvar idx int32\n\n\tfor _, c := range tvc.tv.columns.items {\n\t\tif c.frozen != tvc.frozen {\n\t\t\tcontinue\n\t\t}\n\n\t\tif c == tvc {\n\t\t\tbreak\n\t\t}\n\n\t\tif c.visible {\n\t\t\tidx++\n\t\t}\n\t}\n\n\treturn idx\n}\n\nfunc (tvc *TableViewColumn) create() error {\n\tvar lvc win.LVCOLUMN\n\n\tindex := tvc.indexInListView()\n\n\tdpi := tvc.tv.DPI()\n\tlvc.Mask = win.LVCF_FMT | win.LVCF_WIDTH | win.LVCF_TEXT | win.LVCF_SUBITEM\n\tlvc.ISubItem = index\n\tlvc.PszText = syscall.StringToUTF16Ptr(tvc.TitleEffective())\n\tif tvc.width > 0 {\n\t\tlvc.Cx = int32(IntFrom96DPI(tvc.width, dpi))\n\t} else {\n\t\tlvc.Cx = int32(IntFrom96DPI(100, dpi))\n\t}\n\n\tswitch tvc.alignment {\n\tcase AlignCenter:\n\t\tlvc.Fmt = 2\n\n\tcase AlignFar:\n\t\tlvc.Fmt = 1\n\t}\n\n\tif -1 == int(tvc.sendMessage(win.LVM_INSERTCOLUMN, uintptr(index), uintptr(unsafe.Pointer(&lvc)))) {\n\t\treturn newError(\"LVM_INSERTCOLUMN\")\n\t}\n\n\ttvc.tv.updateLVSizes()\n\n\treturn nil\n}\n\nfunc (tvc *TableViewColumn) destroy() error {\n\twidth := tvc.Width()\n\n\tif win.FALSE == tvc.sendMessage(win.LVM_DELETECOLUMN, uintptr(tvc.indexInListView()), 0) {\n\t\treturn newError(\"LVM_DELETECOLUMN\")\n\t}\n\n\ttvc.width = width\n\n\ttvc.tv.updateLVSizes()\n\n\treturn nil\n}\n\nfunc (tvc *TableViewColumn) update() error {\n\tif tvc.tv == nil || !tvc.visible {\n\t\treturn nil\n\t}\n\n\tlvc := tvc.getLVCOLUMN()\n\n\tif win.FALSE == tvc.sendMessage(win.LVM_SETCOLUMN, uintptr(tvc.indexInListView()), uintptr(unsafe.Pointer(lvc))) {\n\t\treturn newError(\"LVM_SETCOLUMN\")\n\t}\n\n\ttvc.tv.updateLVSizes()\n\n\treturn nil\n}\n\nfunc (tvc *TableViewColumn) getLVCOLUMN() *win.LVCOLUMN {\n\tvar lvc win.LVCOLUMN\n\n\tdpi := 96\n\tif tvc.tv != nil {\n\t\tdpi = tvc.tv.DPI()\n\t} else {\n\t\tdpi = screenDPI()\n\t}\n\twidth := IntFrom96DPI(tvc.width, dpi)\n\n\tlvc.Mask = win.LVCF_FMT | win.LVCF_WIDTH | win.LVCF_TEXT | win.LVCF_SUBITEM\n\tlvc.ISubItem = int32(tvc.indexInListView())\n\tlvc.PszText = syscall.StringToUTF16Ptr(tvc.TitleEffective())\n\tlvc.Cx = int32(width)\n\n\tswitch tvc.alignment {\n\tcase AlignCenter:\n\t\tlvc.Fmt = 2\n\n\tcase AlignFar:\n\t\tlvc.Fmt = 1\n\t}\n\n\treturn &lvc\n}\n\nfunc (tvc *TableViewColumn) sendMessage(msg uint32, wp, lp uintptr) uintptr {\n\tif tvc.tv == nil {\n\t\treturn 0\n\t}\n\n\ttvc.tv.hasFrozenColumn = tvc.tv.visibleFrozenColumnCount() > 0\n\ttvc.tv.SetCheckBoxes(tvc.tv.CheckBoxes())\n\ttvc.tv.applyImageList()\n\n\tvar hwnd win.HWND\n\tif tvc.frozen {\n\t\thwnd = tvc.tv.hwndFrozenLV\n\t} else {\n\t\thwnd = tvc.tv.hwndNormalLV\n\t}\n\n\treturn win.SendMessage(hwnd, msg, wp, lp)\n}\n"
  },
  {
    "path": "tableviewcolumnlist.go",
    "content": "// Copyright 2013 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype TableViewColumnList struct {\n\ttv    *TableView\n\titems []*TableViewColumn\n}\n\nfunc newTableViewColumnList(tv *TableView) *TableViewColumnList {\n\treturn &TableViewColumnList{tv: tv}\n}\n\n// Add adds a TableViewColumn to the end of the list.\nfunc (l *TableViewColumnList) Add(item *TableViewColumn) error {\n\treturn l.Insert(len(l.items), item)\n}\n\n// At returns the TableViewColumn as the specified index.\n//\n// Bounds are not checked.\nfunc (l *TableViewColumnList) At(index int) *TableViewColumn {\n\treturn l.items[index]\n}\n\n// ByName returns the TableViewColumn identified by name, or nil, if no column\n// of that name is contained in the TableViewColumnList.\nfunc (l *TableViewColumnList) ByName(name string) *TableViewColumn {\n\tfor _, tvc := range l.items {\n\t\tif tvc.name == name {\n\t\t\treturn tvc\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Clear removes all TableViewColumns from the list.\nfunc (l *TableViewColumnList) Clear() error {\n\tfor _ = range l.items {\n\t\tif err := l.RemoveAt(0); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Index returns the index of the specified TableViewColumn or -1 if it is not\n// found.\nfunc (l *TableViewColumnList) Index(item *TableViewColumn) int {\n\tfor i, lvi := range l.items {\n\t\tif lvi == item {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\n// Contains returns whether the specified TableViewColumn is found in the list.\nfunc (l *TableViewColumnList) Contains(item *TableViewColumn) bool {\n\treturn l.Index(item) > -1\n}\n\n// Insert inserts TableViewColumn item at position index.\n//\n// A TableViewColumn cannot be contained in multiple TableViewColumnLists at the\n// same time.\nfunc (l *TableViewColumnList) Insert(index int, item *TableViewColumn) error {\n\tif item.tv != nil {\n\t\treturn newError(\"duplicate insert\")\n\t}\n\n\titem.tv = l.tv\n\n\tif item.visible {\n\t\tif err := item.create(); err != nil {\n\t\t\titem.tv = nil\n\t\t\treturn err\n\t\t}\n\t}\n\n\tl.items = append(l.items, nil)\n\tcopy(l.items[index+1:], l.items[index:])\n\tl.items[index] = item\n\n\treturn nil\n}\n\n// Len returns the number of TableViewColumns in  the list.\nfunc (l *TableViewColumnList) Len() int {\n\treturn len(l.items)\n}\n\n// Remove removes the specified TableViewColumn from the list.\nfunc (l *TableViewColumnList) Remove(item *TableViewColumn) error {\n\tindex := l.Index(item)\n\tif index == -1 {\n\t\treturn nil\n\t}\n\n\treturn l.RemoveAt(index)\n}\n\n// RemoveAt removes the TableViewColumn at position index.\nfunc (l *TableViewColumnList) RemoveAt(index int) error {\n\ttvc := l.items[index]\n\n\tif err := tvc.destroy(); err != nil {\n\t\treturn err\n\t}\n\n\ttvc.tv = nil\n\n\tl.items = append(l.items[:index], l.items[index+1:]...)\n\n\treturn nil\n}\n\nfunc (l *TableViewColumnList) unsetColumnsTV() {\n\tfor _, tvc := range l.items {\n\t\ttvc.tv = nil\n\t}\n}\n"
  },
  {
    "path": "tabpage.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\nconst tabPageWindowClass = `\\o/ Walk_TabPage_Class \\o/`\n\nvar tabPageBackgroundBrush Brush\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(tabPageWindowClass)\n\n\t\ttabPageBackgroundBrush, _ = NewSystemColorBrush(win.COLOR_WINDOW)\n\t})\n}\n\ntype TabPage struct {\n\tContainerBase\n\timage                 Image\n\ttitle                 string\n\ttabWidget             *TabWidget\n\ttitleChangedPublisher EventPublisher\n\timageChangedPublisher EventPublisher\n}\n\nfunc NewTabPage() (*TabPage, error) {\n\ttp := new(TabPage)\n\n\tif err := InitWindow(\n\t\ttp,\n\t\tnil,\n\t\ttabPageWindowClass,\n\t\twin.WS_POPUP,\n\t\twin.WS_EX_CONTROLPARENT); err != nil {\n\t\treturn nil, err\n\t}\n\n\ttp.children = newWidgetList(tp)\n\n\ttp.MustRegisterProperty(\"Title\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn tp.Title()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn tp.SetTitle(assertStringOr(v, \"\"))\n\t\t},\n\t\ttp.titleChangedPublisher.Event()))\n\n\ttp.MustRegisterProperty(\"Image\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn tp.Image()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\timg, err := ImageFrom(v)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn tp.SetImage(img)\n\t\t},\n\t\ttp.imageChangedPublisher.Event()))\n\n\treturn tp, nil\n}\n\nfunc (tp *TabPage) Enabled() bool {\n\tif tp.tabWidget != nil {\n\t\treturn tp.tabWidget.Enabled() && tp.enabled\n\t}\n\n\treturn tp.enabled\n}\n\nfunc (tp *TabPage) Background() Brush {\n\tif tp.background != nil {\n\t\treturn tp.background\n\t} else if tp.tabWidget != nil && tp.tabWidget.background == nullBrushSingleton {\n\t\treturn nullBrushSingleton\n\t}\n\n\tif win.IsAppThemed() {\n\t\treturn tabPageBackgroundBrush\n\t}\n\n\treturn nil\n}\n\nfunc (tp *TabPage) Font() *Font {\n\tif tp.font != nil {\n\t\treturn tp.font\n\t} else if tp.tabWidget != nil {\n\t\treturn tp.tabWidget.Font()\n\t}\n\n\treturn defaultFont\n}\n\nfunc (tp *TabPage) Image() Image {\n\treturn tp.image\n}\n\nfunc (tp *TabPage) SetImage(value Image) error {\n\ttp.image = value\n\n\tif tp.tabWidget == nil {\n\t\treturn nil\n\t}\n\n\treturn tp.tabWidget.onPageChanged(tp)\n}\n\nfunc (tp *TabPage) Title() string {\n\treturn tp.title\n}\n\nfunc (tp *TabPage) SetTitle(value string) error {\n\ttp.title = value\n\n\ttp.titleChangedPublisher.Publish()\n\n\tif tp.tabWidget == nil {\n\t\treturn nil\n\t}\n\n\treturn tp.tabWidget.onPageChanged(tp)\n}\n"
  },
  {
    "path": "tabpagelist.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype tabPageListObserver interface {\n\tonInsertingPage(index int, page *TabPage) error\n\tonInsertedPage(index int, page *TabPage) error\n\tonRemovingPage(index int, page *TabPage) error\n\tonRemovedPage(index int, page *TabPage) error\n\tonClearingPages(pages []*TabPage) error\n\tonClearedPages(pages []*TabPage) error\n}\n\ntype TabPageList struct {\n\titems    []*TabPage\n\tobserver tabPageListObserver\n}\n\nfunc newTabPageList(observer tabPageListObserver) *TabPageList {\n\treturn &TabPageList{observer: observer}\n}\n\nfunc (l *TabPageList) Add(item *TabPage) error {\n\treturn l.Insert(len(l.items), item)\n}\n\nfunc (l *TabPageList) At(index int) *TabPage {\n\treturn l.items[index]\n}\n\nfunc (l *TabPageList) Clear() error {\n\tobserver := l.observer\n\tif observer != nil {\n\t\tif err := observer.onClearingPages(l.items); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\toldItems := l.items\n\tl.items = l.items[:0]\n\n\tif observer != nil {\n\t\tif err := observer.onClearedPages(oldItems); err != nil {\n\t\t\tl.items = oldItems\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (l *TabPageList) Index(item *TabPage) int {\n\tfor i, lvi := range l.items {\n\t\tif lvi == item {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (l *TabPageList) Contains(item *TabPage) bool {\n\treturn l.Index(item) > -1\n}\n\nfunc (l *TabPageList) indexHandle(handle win.HWND) int {\n\tfor i, page := range l.items {\n\t\tif page.Handle() == handle {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (l *TabPageList) containsHandle(handle win.HWND) bool {\n\treturn l.indexHandle(handle) > -1\n}\n\nfunc (l *TabPageList) insertIntoSlice(index int, item *TabPage) {\n\tl.items = append(l.items, nil)\n\tcopy(l.items[index+1:], l.items[index:])\n\tl.items[index] = item\n}\n\nfunc (l *TabPageList) Insert(index int, item *TabPage) error {\n\tobserver := l.observer\n\tif observer != nil {\n\t\tif err := observer.onInsertingPage(index, item); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tl.insertIntoSlice(index, item)\n\n\tif observer != nil {\n\t\tif err := observer.onInsertedPage(index, item); err != nil {\n\t\t\tl.items = append(l.items[:index], l.items[index+1:]...)\n\t\t\treturn err\n\t\t}\n\t}\n\n\titem.RequestLayout()\n\n\treturn nil\n}\n\nfunc (l *TabPageList) Len() int {\n\treturn len(l.items)\n}\n\nfunc (l *TabPageList) Remove(item *TabPage) error {\n\tindex := l.Index(item)\n\tif index == -1 {\n\t\treturn nil\n\t}\n\n\treturn l.RemoveAt(index)\n}\n\nfunc (l *TabPageList) RemoveAt(index int) error {\n\tobserver := l.observer\n\titem := l.items[index]\n\tif observer != nil {\n\t\tif err := observer.onRemovingPage(index, item); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tl.items = append(l.items[:index], l.items[index+1:]...)\n\n\tif observer != nil {\n\t\tif err := observer.onRemovedPage(index, item); err != nil {\n\t\t\tl.insertIntoSlice(index, item)\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "tabwidget.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"strconv\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\nconst tabWidgetWindowClass = `\\o/ Walk_TabWidget_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(tabWidgetWindowClass)\n\t\ttabWidgetTabWndProcPtr = syscall.NewCallback(tabWidgetTabWndProc)\n\t})\n}\n\ntype TabWidget struct {\n\tWidgetBase\n\thWndTab                      win.HWND\n\ttabOrigWndProcPtr            uintptr\n\timageList                    *ImageList\n\tpages                        *TabPageList\n\tcurrentIndex                 int\n\tcurrentIndexChangedPublisher EventPublisher\n\tnonClientSizePixels          Size\n\tpersistent                   bool\n}\n\nfunc NewTabWidget(parent Container) (*TabWidget, error) {\n\ttw := &TabWidget{currentIndex: -1}\n\ttw.pages = newTabPageList(tw)\n\n\tif err := InitWidget(\n\t\ttw,\n\t\tparent,\n\t\ttabWidgetWindowClass,\n\t\twin.WS_VISIBLE,\n\t\twin.WS_EX_CONTROLPARENT); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\ttw.Dispose()\n\t\t}\n\t}()\n\n\ttw.SetPersistent(true)\n\n\ttw.hWndTab = win.CreateWindowEx(\n\t\t0, syscall.StringToUTF16Ptr(\"SysTabControl32\"), nil,\n\t\twin.WS_CHILD|win.WS_CLIPSIBLINGS|win.WS_TABSTOP|win.WS_VISIBLE,\n\t\t0, 0, 0, 0, tw.hWnd, 0, 0, nil)\n\tif tw.hWndTab == 0 {\n\t\treturn nil, lastError(\"CreateWindowEx\")\n\t}\n\n\twin.SetWindowLongPtr(tw.hWndTab, win.GWLP_USERDATA, uintptr(unsafe.Pointer(tw)))\n\ttw.tabOrigWndProcPtr = win.SetWindowLongPtr(tw.hWndTab, win.GWLP_WNDPROC, tabWidgetTabWndProcPtr)\n\n\tdpi := int(win.GetDpiForWindow(tw.hWndTab))\n\twin.SendMessage(tw.hWndTab, win.WM_SETFONT, uintptr(defaultFont.handleForDPI(dpi)), 1)\n\n\ttw.applyFont(tw.Font())\n\n\ttw.MustRegisterProperty(\"HasCurrentPage\", NewReadOnlyBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn tw.CurrentIndex() != -1\n\t\t},\n\t\ttw.CurrentIndexChanged()))\n\n\ttw.MustRegisterProperty(\"CurrentIndex\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn tw.CurrentIndex()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn tw.SetCurrentIndex(assertIntOr(v, -1))\n\t\t},\n\t\ttw.CurrentIndexChanged()))\n\n\tsucceeded = true\n\n\treturn tw, nil\n}\n\nfunc (tw *TabWidget) Dispose() {\n\ttw.WidgetBase.Dispose()\n\n\tif tw.imageList != nil {\n\t\ttw.imageList.Dispose()\n\t\ttw.imageList = nil\n\t}\n}\n\nfunc (tw *TabWidget) applyEnabled(enabled bool) {\n\ttw.WidgetBase.applyEnabled(enabled)\n\n\tsetWindowEnabled(tw.hWndTab, enabled)\n\n\tapplyEnabledToDescendants(tw, enabled)\n}\n\nfunc (tw *TabWidget) applyFont(font *Font) {\n\ttw.WidgetBase.applyFont(font)\n\n\tSetWindowFont(tw.hWndTab, font)\n\n\t// FIXME: won't work with ApplyDPI\n\t// applyFontToDescendants(tw, font)\n}\n\nfunc (tw *TabWidget) ApplyDPI(dpi int) {\n\ttw.WidgetBase.ApplyDPI(dpi)\n\n\tvar maskColor Color\n\tvar size Size\n\tif tw.imageList != nil {\n\t\tmaskColor = tw.imageList.maskColor\n\t\tsize = SizeFrom96DPI(tw.imageList.imageSize96dpi, dpi)\n\t} else {\n\t\tsize = SizeFrom96DPI(Size{16, 16}, dpi)\n\t}\n\n\timl, err := NewImageListForDPI(size, maskColor, dpi)\n\tif err != nil {\n\t\treturn\n\t}\n\n\twin.SendMessage(tw.hWndTab, win.TCM_SETIMAGELIST, 0, uintptr(iml.hIml))\n\n\tif tw.imageList != nil {\n\t\ttw.imageList.Dispose()\n\t}\n\n\ttw.imageList = iml\n\n\tfor _, page := range tw.pages.items {\n\t\ttw.onPageChanged(page)\n\t}\n}\n\nfunc (tw *TabWidget) CurrentIndex() int {\n\treturn tw.currentIndex\n}\n\nfunc (tw *TabWidget) SetCurrentIndex(index int) error {\n\tif index == tw.currentIndex {\n\t\treturn nil\n\t}\n\n\tif index < 0 || index >= tw.pages.Len() {\n\t\treturn newError(\"invalid index\")\n\t}\n\n\tret := int(win.SendMessage(tw.hWndTab, win.TCM_SETCURSEL, uintptr(index), 0))\n\tif ret == -1 {\n\t\treturn newError(\"SendMessage(TCM_SETCURSEL) failed\")\n\t}\n\n\t// FIXME: The SendMessage(TCM_SETCURSEL) call above doesn't cause a\n\t// TCN_SELCHANGE notification, so we use this workaround.\n\ttw.onSelChange()\n\n\treturn nil\n}\n\nfunc (tw *TabWidget) CurrentIndexChanged() *Event {\n\treturn tw.currentIndexChangedPublisher.Event()\n}\n\nfunc (tw *TabWidget) Pages() *TabPageList {\n\treturn tw.pages\n}\n\nfunc (tw *TabWidget) Persistent() bool {\n\treturn tw.persistent\n}\n\nfunc (tw *TabWidget) SetPersistent(value bool) {\n\ttw.persistent = value\n}\n\nfunc (tw *TabWidget) SaveState() error {\n\ttw.WriteState(strconv.Itoa(tw.CurrentIndex()))\n\n\tfor _, page := range tw.pages.items {\n\t\tif err := page.SaveState(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (tw *TabWidget) RestoreState() error {\n\tstate, err := tw.ReadState()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif state == \"\" {\n\t\treturn nil\n\t}\n\n\tindex, err := strconv.Atoi(state)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif index >= 0 && index < tw.pages.Len() {\n\t\tif err := tw.SetCurrentIndex(index); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, page := range tw.pages.items {\n\t\tif err := page.RestoreState(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (tw *TabWidget) resizePages() {\n\tbounds := tw.pageBounds()\n\n\tfor _, page := range tw.pages.items {\n\t\tpage.SetBoundsPixels(bounds)\n\t}\n}\n\n// pageBounds returns page bounds in native pixels.\nfunc (tw *TabWidget) pageBounds() Rectangle {\n\tvar r win.RECT\n\tif !win.GetWindowRect(tw.hWndTab, &r) {\n\t\tlastError(\"GetWindowRect\")\n\t\treturn Rectangle{}\n\t}\n\n\tp := win.POINT{\n\t\tr.Left,\n\t\tr.Top,\n\t}\n\tif !win.ScreenToClient(tw.hWnd, &p) {\n\t\tnewError(\"ScreenToClient failed\")\n\t\treturn Rectangle{}\n\t}\n\n\tr = win.RECT{\n\t\tp.X,\n\t\tp.Y,\n\t\tr.Right - r.Left + p.X,\n\t\tr.Bottom - r.Top + p.Y,\n\t}\n\twin.SendMessage(tw.hWndTab, win.TCM_ADJUSTRECT, 0, uintptr(unsafe.Pointer(&r)))\n\n\tadjustment := 2 * int32(tw.IntFrom96DPI(1))\n\treturn Rectangle{\n\t\tint(r.Left - adjustment),\n\t\tint(r.Top),\n\t\tint(r.Right - r.Left + adjustment),\n\t\tint(r.Bottom - r.Top),\n\t}\n}\n\nfunc (tw *TabWidget) onResize(width, height int32) {\n\tif !win.MoveWindow(tw.hWndTab, 0, 0, width, height, true) {\n\t\tlastError(\"MoveWindow\")\n\t\treturn\n\t}\n\n\ttw.resizePages()\n}\n\nfunc (tw *TabWidget) onSelChange() {\n\tpageCount := tw.pages.Len()\n\n\tif tw.currentIndex > -1 && tw.currentIndex < pageCount {\n\t\tpage := tw.pages.At(tw.currentIndex)\n\t\tpage.SetVisible(false)\n\t}\n\n\ttw.currentIndex = int(int32(win.SendMessage(tw.hWndTab, win.TCM_GETCURSEL, 0, 0)))\n\n\tif tw.currentIndex > -1 && tw.currentIndex < pageCount {\n\t\tpage := tw.pages.At(tw.currentIndex)\n\t\tpage.SetVisible(true)\n\t\ttw.RequestLayout()\n\t\tpage.Invalidate()\n\n\t\tvar containsFocus bool\n\t\ttw.forEachDescendantRaw(uintptr(win.GetFocus()), func(hwnd win.HWND, lParam uintptr) bool {\n\t\t\tif hwnd == win.HWND(lParam) {\n\t\t\t\tcontainsFocus = true\n\t\t\t}\n\t\t\treturn !containsFocus\n\t\t})\n\t\tif containsFocus {\n\t\t\ttw.pages.At(tw.currentIndex).focusFirstCandidateDescendant()\n\t\t}\n\t}\n\n\ttw.Invalidate()\n\n\ttw.currentIndexChangedPublisher.Publish()\n}\n\nfunc (tw *TabWidget) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tif tw.hWndTab != 0 {\n\t\tswitch msg {\n\t\tcase win.WM_ERASEBKGND:\n\t\t\treturn 1\n\n\t\tcase win.WM_WINDOWPOSCHANGED:\n\t\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ttw.onResize(wp.Cx, wp.Cy)\n\n\t\tcase win.WM_NOTIFY:\n\t\t\tnmhdr := (*win.NMHDR)(unsafe.Pointer(lParam))\n\n\t\t\tswitch int32(nmhdr.Code) {\n\t\t\tcase win.TCN_SELCHANGE:\n\t\t\t\ttw.onSelChange()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn tw.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nvar tabWidgetTabWndProcPtr uintptr\n\nfunc tabWidgetTabWndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\ttw := (*TabWidget)(unsafe.Pointer(win.GetWindowLongPtr(hwnd, win.GWLP_USERDATA)))\n\n\tswitch msg {\n\tcase win.WM_MOUSEMOVE:\n\t\twin.InvalidateRect(hwnd, nil, true)\n\n\tcase win.WM_ERASEBKGND:\n\t\treturn 1\n\n\tcase win.WM_PAINT:\n\t\tvar ps win.PAINTSTRUCT\n\n\t\thdc := win.BeginPaint(hwnd, &ps)\n\t\tdefer win.EndPaint(hwnd, &ps)\n\n\t\tcb := tw.ClientBoundsPixels()\n\n\t\tdpi := tw.DPI()\n\t\tbitmap, err := NewBitmapForDPI(cb.Size(), dpi)\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\tdefer bitmap.Dispose()\n\n\t\tcanvas, err := NewCanvasFromImage(bitmap)\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\tdefer canvas.Dispose()\n\n\t\tthemed := win.IsAppThemed()\n\n\t\tif !themed {\n\t\t\tif err := canvas.FillRectanglePixels(sysColorBtnFaceBrush, cb); err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\twin.SendMessage(hwnd, win.WM_PRINTCLIENT, uintptr(canvas.hdc), uintptr(win.PRF_CLIENT|win.PRF_CHILDREN|win.PRF_ERASEBKGND))\n\n\t\tparent := tw.Parent()\n\t\tif parent == nil {\n\t\t\tbreak\n\t\t}\n\n\t\t// Draw background of free area not occupied by tab items.\n\t\tif bg, wnd := parent.AsWindowBase().backgroundEffective(); bg != nil {\n\t\t\ttw.prepareDCForBackground(canvas.hdc, hwnd, wnd)\n\n\t\t\thRgn := win.CreateRectRgn(0, 0, 0, 0)\n\t\t\tdefer win.DeleteObject(win.HGDIOBJ(hRgn))\n\n\t\t\tvar rc win.RECT\n\n\t\t\tadjustment := SizeFrom96DPI(Size{1, 1}, dpi).toSIZE()\n\t\t\tcount := tw.pages.Len()\n\t\t\tfor i := 0; i < count; i++ {\n\t\t\t\tif 0 == win.SendMessage(hwnd, win.TCM_GETITEMRECT, uintptr(i), uintptr(unsafe.Pointer(&rc))) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif i == tw.currentIndex {\n\t\t\t\t\trc.Left -= 2 * adjustment.CX\n\t\t\t\t\trc.Top -= 2 * adjustment.CY\n\t\t\t\t\trc.Right += 2 * adjustment.CX\n\t\t\t\t} else {\n\t\t\t\t\tif i == count-1 && themed {\n\t\t\t\t\t\trc.Right -= 2 * adjustment.CX\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\thRgnTab := win.CreateRectRgn(rc.Left, rc.Top, rc.Right, rc.Bottom)\n\t\t\t\twin.CombineRgn(hRgn, hRgn, hRgnTab, win.RGN_OR)\n\t\t\t\twin.DeleteObject(win.HGDIOBJ(hRgnTab))\n\t\t\t}\n\n\t\t\thRgnRC := win.CreateRectRgn(0, 0, int32(cb.Width), rc.Bottom)\n\t\t\twin.CombineRgn(hRgn, hRgnRC, hRgn, win.RGN_DIFF)\n\t\t\twin.DeleteObject(win.HGDIOBJ(hRgnRC))\n\n\t\t\tif !win.FillRgn(canvas.hdc, hRgn, bg.handle()) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// Draw current tab item.\n\t\tif tw.currentIndex != -1 {\n\t\t\tpage := tw.pages.At(tw.CurrentIndex())\n\n\t\t\tif bg, wnd := page.AsWindowBase().backgroundEffective(); bg != nil &&\n\t\t\t\tbg != tabPageBackgroundBrush &&\n\t\t\t\t(page.layout == nil || !page.layout.Margins().isZero()) {\n\n\t\t\t\ttw.prepareDCForBackground(canvas.hdc, hwnd, wnd)\n\n\t\t\t\tvar rc win.RECT\n\t\t\t\tif 0 == win.SendMessage(hwnd, win.TCM_GETITEMRECT, uintptr(tw.currentIndex), uintptr(unsafe.Pointer(&rc))) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tadjustment := SizeFrom96DPI(Size{6, 1}, dpi).toSIZE()\n\t\t\t\thRgn := win.CreateRectRgn(rc.Left, rc.Top, rc.Right, rc.Bottom+2*adjustment.CY)\n\t\t\t\tdefer win.DeleteObject(win.HGDIOBJ(hRgn))\n\t\t\t\tif !win.FillRgn(canvas.hdc, hRgn, bg.handle()) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif page.image != nil {\n\t\t\t\t\tx := rc.Left + adjustment.CX\n\t\t\t\t\ty := rc.Top\n\t\t\t\t\ts := int32(IntFrom96DPI(16, dpi))\n\n\t\t\t\t\tbmp, err := iconCache.Bitmap(page.image, dpi)\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\tif imageCanvas, err := NewCanvasFromImage(bmp); err == nil {\n\t\t\t\t\t\t\tdefer imageCanvas.Dispose()\n\n\t\t\t\t\t\t\tif !win.TransparentBlt(\n\t\t\t\t\t\t\t\tcanvas.hdc, x, y, s, s,\n\t\t\t\t\t\t\t\timageCanvas.hdc, 0, 0, int32(bmp.size.Width), int32(bmp.size.Height),\n\t\t\t\t\t\t\t\t0) {\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trc.Left += s + adjustment.CX\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trc.Left += adjustment.CX\n\t\t\t\trc.Top += adjustment.CY\n\n\t\t\t\ttitle := syscall.StringToUTF16(page.title)\n\n\t\t\t\tif themed {\n\t\t\t\t\thTheme := win.OpenThemeData(hwnd, syscall.StringToUTF16Ptr(\"tab\"))\n\t\t\t\t\tdefer win.CloseThemeData(hTheme)\n\n\t\t\t\t\toptions := win.DTTOPTS{DwFlags: win.DTT_GLOWSIZE, IGlowSize: int32(IntFrom96DPI(3, dpi))}\n\t\t\t\t\toptions.DwSize = uint32(unsafe.Sizeof(options))\n\t\t\t\t\tif hr := win.DrawThemeTextEx(hTheme, canvas.hdc, 0, win.TIS_SELECTED, &title[0], int32(len(title)), 0, &rc, &options); !win.SUCCEEDED(hr) {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif 0 == win.DrawTextEx(canvas.hdc, &title[0], int32(len(title)), &rc, 0, nil) {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif !win.BitBlt(hdc, 0, 0, int32(cb.Width), int32(cb.Height), canvas.hdc, 0, 0, win.SRCCOPY) {\n\t\t\tbreak\n\t\t}\n\n\t\treturn 0\n\t}\n\n\treturn win.CallWindowProc(tw.tabOrigWndProcPtr, hwnd, msg, wParam, lParam)\n}\n\nfunc (tw *TabWidget) onPageChanged(page *TabPage) (err error) {\n\tindex := tw.pages.Index(page)\n\titem := tw.tcitemFromPage(page)\n\n\tif 0 == win.SendMessage(tw.hWndTab, win.TCM_SETITEM, uintptr(index), uintptr(unsafe.Pointer(item))) {\n\t\treturn newError(\"SendMessage(TCM_SETITEM) failed\")\n\t}\n\n\ttw.updateNonClientSize()\n\n\treturn nil\n}\n\nfunc (tw *TabWidget) onInsertingPage(index int, page *TabPage) (err error) {\n\treturn nil\n}\n\nfunc (tw *TabWidget) onInsertedPage(index int, page *TabPage) (err error) {\n\titem := tw.tcitemFromPage(page)\n\n\tif idx := int(win.SendMessage(tw.hWndTab, win.TCM_INSERTITEM, uintptr(index), uintptr(unsafe.Pointer(item)))); idx == -1 {\n\t\treturn newError(\"SendMessage(TCM_INSERTITEM) failed\")\n\t}\n\n\tpage.SetVisible(false)\n\n\tstyle := uint32(win.GetWindowLong(page.hWnd, win.GWL_STYLE))\n\tif style == 0 {\n\t\treturn lastError(\"GetWindowLong\")\n\t}\n\n\tstyle |= win.WS_CHILD\n\tstyle &^= win.WS_POPUP\n\n\twin.SetLastError(0)\n\tif win.SetWindowLong(page.hWnd, win.GWL_STYLE, int32(style)) == 0 {\n\t\treturn lastError(\"SetWindowLong\")\n\t}\n\n\tif win.SetParent(page.hWnd, tw.hWnd) == 0 {\n\t\treturn lastError(\"SetParent\")\n\t}\n\n\tif tw.pages.Len() == 1 {\n\t\tpage.SetVisible(true)\n\t\ttw.SetCurrentIndex(0)\n\t}\n\n\ttw.resizePages()\n\n\tpage.tabWidget = tw\n\n\tpage.applyFont(tw.Font())\n\n\ttw.Invalidate()\n\n\treturn\n}\n\nfunc (tw *TabWidget) removePage(page *TabPage) (err error) {\n\tpage.SetVisible(false)\n\n\tstyle := uint32(win.GetWindowLong(page.hWnd, win.GWL_STYLE))\n\tif style == 0 {\n\t\treturn lastError(\"GetWindowLong\")\n\t}\n\n\tstyle &^= win.WS_CHILD\n\tstyle |= win.WS_POPUP\n\n\twin.SetLastError(0)\n\tif win.SetWindowLong(page.hWnd, win.GWL_STYLE, int32(style)) == 0 {\n\t\treturn lastError(\"SetWindowLong\")\n\t}\n\n\tpage.tabWidget = nil\n\n\treturn page.SetParent(nil)\n}\n\nfunc (tw *TabWidget) onRemovingPage(index int, page *TabPage) (err error) {\n\treturn nil\n}\n\nfunc (tw *TabWidget) onRemovedPage(index int, page *TabPage) (err error) {\n\terr = tw.removePage(page)\n\tif err != nil {\n\t\treturn\n\t}\n\n\twin.SendMessage(tw.hWndTab, win.TCM_DELETEITEM, uintptr(index), 0)\n\n\tif tw.pages.Len() > 0 {\n\t\ttw.currentIndex = 0\n\t\twin.SendMessage(tw.hWndTab, win.TCM_SETCURSEL, uintptr(tw.currentIndex), 0)\n\t} else {\n\t\ttw.currentIndex = -1\n\t}\n\ttw.onSelChange()\n\n\treturn\n\n\t// FIXME: Either make use of this unreachable code or remove it.\n\tif index == tw.currentIndex {\n\t\t// removal of current visible tabpage...\n\t\ttw.currentIndex = -1\n\n\t\t// select new tabpage if any :\n\t\tif tw.pages.Len() > 0 {\n\t\t\t// are we removing the rightmost page ?\n\t\t\tif index == tw.pages.Len()-1 {\n\t\t\t\t// If so, select the page on the left\n\t\t\t\tindex -= 1\n\t\t\t}\n\t\t}\n\t}\n\n\ttw.SetCurrentIndex(index)\n\n\ttw.Invalidate()\n\n\treturn\n}\n\nfunc (tw *TabWidget) onClearingPages(pages []*TabPage) (err error) {\n\treturn nil\n}\n\nfunc (tw *TabWidget) onClearedPages(pages []*TabPage) (err error) {\n\twin.SendMessage(tw.hWndTab, win.TCM_DELETEALLITEMS, 0, 0)\n\tfor _, page := range pages {\n\t\ttw.removePage(page)\n\t}\n\ttw.currentIndex = -1\n\n\ttw.Invalidate()\n\n\treturn nil\n}\n\nfunc (tw *TabWidget) tcitemFromPage(page *TabPage) *win.TCITEM {\n\tvar imageIndex int32 = -1\n\tif page.image != nil {\n\t\tif bmp, err := iconCache.Bitmap(page.image, tw.DPI()); err == nil {\n\t\t\timageIndex, _ = tw.imageIndex(bmp)\n\t\t}\n\t}\n\n\ttext := syscall.StringToUTF16(page.title)\n\n\titem := &win.TCITEM{\n\t\tMask:       win.TCIF_IMAGE | win.TCIF_TEXT,\n\t\tIImage:     imageIndex,\n\t\tPszText:    &text[0],\n\t\tCchTextMax: int32(len(text)),\n\t}\n\n\treturn item\n}\n\nfunc (tw *TabWidget) imageIndex(image *Bitmap) (index int32, err error) {\n\tindex = -1\n\tif image != nil {\n\t\tif tw.imageList == nil {\n\t\t\tdpi := tw.DPI()\n\t\t\tif tw.imageList, err = NewImageListForDPI(SizeFrom96DPI(Size{16, 16}, dpi), 0, dpi); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\twin.SendMessage(tw.hWndTab, win.TCM_SETIMAGELIST, 0, uintptr(tw.imageList.hIml))\n\t\t}\n\n\t\tif index, err = tw.imageList.AddMasked(image); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (tw *TabWidget) updateNonClientSize() {\n\trc := win.RECT{Right: 1000, Bottom: 1000}\n\n\twin.SendMessage(tw.hWndTab, win.TCM_ADJUSTRECT, 1, uintptr(unsafe.Pointer(&rc)))\n\n\ttw.nonClientSizePixels.Width = int(rc.Right-rc.Left) - 1000\n\ttw.nonClientSizePixels.Height = int(rc.Bottom-rc.Top) - 1000\n}\n\nfunc (tw *TabWidget) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tpages := make([]LayoutItem, tw.pages.Len())\n\n\tbounds := tw.pageBounds()\n\n\tli := &tabWidgetLayoutItem{\n\t\tpagePos:             bounds.Location(),\n\t\tcurrentIndex:        tw.CurrentIndex(),\n\t\tnonClientSizePixels: tw.nonClientSizePixels,\n\t}\n\n\tfor i := tw.pages.Len() - 1; i >= 0; i-- {\n\t\tvar page LayoutItem\n\t\tif p := tw.pages.At(i); p.Layout() != nil {\n\t\t\tpage = CreateLayoutItemsForContainerWithContext(p, ctx)\n\t\t} else {\n\t\t\tpage = NewGreedyLayoutItem()\n\t\t}\n\n\t\tlib := page.AsLayoutItemBase()\n\t\tlib.ctx = ctx\n\t\tlib.parent = li\n\t\tpages[i] = page\n\t}\n\n\tli.children = pages\n\n\treturn li\n}\n\ntype tabWidgetLayoutItem struct {\n\tContainerLayoutItemBase\n\tnonClientSizePixels Size\n\tpagePos             Point // in native pixels\n\tcurrentIndex        int\n}\n\nfunc (li *tabWidgetLayoutItem) LayoutFlags() LayoutFlags {\n\tif len(li.children) == 0 {\n\t\treturn ShrinkableHorz | ShrinkableVert | GrowableHorz | GrowableVert | GreedyHorz | GreedyVert\n\t}\n\n\tvar flags LayoutFlags\n\n\tfor _, page := range li.children {\n\t\tflags |= page.LayoutFlags()\n\t}\n\n\treturn flags\n}\n\nfunc (li *tabWidgetLayoutItem) MinSize() Size {\n\tif len(li.children) == 0 {\n\t\treturn Size{}\n\t}\n\n\tvar min Size\n\n\tfor _, page := range li.children {\n\t\tif ms, ok := page.(MinSizer); ok {\n\t\t\ts := ms.MinSize()\n\n\t\t\tmin.Width = maxi(min.Width, s.Width)\n\t\t\tmin.Height = maxi(min.Height, s.Height)\n\t\t}\n\t}\n\n\treturn Size{min.Width + li.nonClientSizePixels.Width, min.Height + li.nonClientSizePixels.Height}\n}\n\nfunc (li *tabWidgetLayoutItem) MinSizeForSize(size Size) Size {\n\treturn li.MinSize()\n}\n\nfunc (li *tabWidgetLayoutItem) HasHeightForWidth() bool {\n\tif len(li.children) == 0 {\n\t\treturn false\n\t}\n\n\tfor _, page := range li.children {\n\t\tif hfw, ok := page.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (li *tabWidgetLayoutItem) HeightForWidth(width int) int {\n\tif len(li.children) == 0 {\n\t\treturn 0\n\t}\n\n\tvar height int\n\tmargin := li.geometry.Size\n\tpageSize := li.children[0].Geometry().Size\n\n\tmargin.Width -= pageSize.Width\n\tmargin.Height -= pageSize.Height\n\n\tfor _, page := range li.children {\n\t\tif hfw, ok := page.(HeightForWidther); ok && hfw.HasHeightForWidth() {\n\t\t\th := hfw.HeightForWidth(width + margin.Width)\n\n\t\t\theight = maxi(height, h)\n\t\t}\n\t}\n\n\treturn height + margin.Height\n}\n\nfunc (li *tabWidgetLayoutItem) IdealSize() Size {\n\treturn li.MinSize()\n}\n\nfunc (li *tabWidgetLayoutItem) PerformLayout() []LayoutResultItem {\n\tif li.currentIndex > -1 {\n\t\tpage := li.children[li.currentIndex]\n\n\t\tadjustment := IntFrom96DPI(1, li.ctx.dpi)\n\t\treturn []LayoutResultItem{\n\t\t\t{\n\t\t\t\tItem: page,\n\t\t\t\tBounds: Rectangle{\n\t\t\t\t\tX:      li.pagePos.X,\n\t\t\t\t\tY:      li.pagePos.Y,\n\t\t\t\t\tWidth:  li.geometry.Size.Width - li.pagePos.X*2 - adjustment,\n\t\t\t\t\tHeight: li.geometry.Size.Height - li.pagePos.Y - 2*adjustment,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "textedit.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"sync\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype TextEdit struct {\n\tWidgetBase\n\treadOnlyChangedPublisher EventPublisher\n\ttextChangedPublisher     EventPublisher\n\ttextColor                Color\n\tcompactHeight            bool\n\tmargins                  Size // in native pixels\n\tlastHeight               int\n\torigWordbreakProcPtr     uintptr\n}\n\nfunc NewTextEdit(parent Container) (*TextEdit, error) {\n\treturn NewTextEditWithStyle(parent, 0)\n}\n\nfunc NewTextEditWithStyle(parent Container, style uint32) (*TextEdit, error) {\n\tte := new(TextEdit)\n\n\tif err := InitWidget(\n\t\tte,\n\t\tparent,\n\t\t\"EDIT\",\n\t\twin.WS_TABSTOP|win.WS_VISIBLE|win.ES_MULTILINE|win.ES_WANTRETURN|style,\n\t\twin.WS_EX_CLIENTEDGE); err != nil {\n\t\treturn nil, err\n\t}\n\n\tte.origWordbreakProcPtr = te.SendMessage(win.EM_GETWORDBREAKPROC, 0, 0)\n\n\tte.GraphicsEffects().Add(InteractionEffect)\n\tte.GraphicsEffects().Add(FocusEffect)\n\n\tte.MustRegisterProperty(\"ReadOnly\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn te.ReadOnly()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn te.SetReadOnly(v.(bool))\n\t\t},\n\t\tte.readOnlyChangedPublisher.Event()))\n\n\tte.MustRegisterProperty(\"Text\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn te.Text()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn te.SetText(assertStringOr(v, \"\"))\n\t\t},\n\t\tte.textChangedPublisher.Event()))\n\n\treturn te, nil\n}\n\nfunc (te *TextEdit) applyFont(font *Font) {\n\tte.WidgetBase.applyFont(font)\n\n\tte.updateMargins()\n}\n\nfunc (te *TextEdit) updateMargins() {\n\t// 56 works at least from 96 to 192 DPI, so until a better solution comes up, this is it.\n\tdefaultSize := te.dialogBaseUnitsToPixels(Size{56, 12})\n\n\tvar rc win.RECT\n\tte.SendMessage(win.EM_GETRECT, 0, uintptr(unsafe.Pointer(&rc)))\n\n\tif te.hasExtendedStyleBits(win.WS_EX_CLIENTEDGE) {\n\t\twidth := te.WidthPixels()\n\t\tif width == 0 {\n\t\t\twidth = defaultSize.Width\n\t\t}\n\t\tte.margins.Width = width - int(rc.Right-rc.Left)\n\t} else {\n\t\tte.margins.Width = int(rc.Left) * 2\n\t}\n\n\tlineHeight := te.calculateTextSizeImpl(\"gM\").Height\n\tte.margins.Height = defaultSize.Height - lineHeight\n}\n\nvar drawTextCompatibleEditWordbreakProcPtr uintptr\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tdrawTextCompatibleEditWordbreakProcPtr = syscall.NewCallback(drawTextCompatibleEditWordbreakProc)\n\t})\n}\n\nfunc drawTextCompatibleEditWordbreakProc(lpch *uint16, ichCurrent, cch, code uintptr) uintptr {\n\tswitch code {\n\tcase win.WB_LEFT:\n\t\tfor i := int(ichCurrent); i >= 0; i-- {\n\t\t\tif *(*uint16)(unsafe.Pointer(uintptr(unsafe.Pointer(lpch)) + uintptr(i)*2)) == 32 {\n\t\t\t\treturn uintptr(i)\n\t\t\t}\n\t\t}\n\n\tcase win.WB_RIGHT:\n\t\tfor i := int(ichCurrent); i < int(cch); i++ {\n\t\t\tif *(*uint16)(unsafe.Pointer(uintptr(unsafe.Pointer(lpch)) + uintptr(i)*2)) == 32 {\n\t\t\t\treturn uintptr(i)\n\t\t\t}\n\t\t}\n\n\tcase win.WB_ISDELIMITER:\n\t\tif *(*uint16)(unsafe.Pointer(uintptr(unsafe.Pointer(lpch)) + ichCurrent*2)) == 32 {\n\t\t\treturn 1\n\t\t}\n\t}\n\n\treturn 0\n}\n\nfunc (te *TextEdit) Text() string {\n\treturn te.text()\n}\n\nfunc (te *TextEdit) TextLength() int {\n\treturn int(te.SendMessage(win.WM_GETTEXTLENGTH, 0, 0))\n}\n\nfunc (te *TextEdit) SetText(text string) (err error) {\n\tif text == te.Text() {\n\t\treturn nil\n\t}\n\n\tvar oldLineCount int\n\tif te.compactHeight {\n\t\toldLineCount = int(te.SendMessage(win.EM_GETLINECOUNT, 0, 0))\n\t}\n\terr = te.setText(text)\n\tif te.compactHeight {\n\t\tif newLineCount := int(te.SendMessage(win.EM_GETLINECOUNT, 0, 0)); newLineCount != oldLineCount {\n\t\t\tte.RequestLayout()\n\t\t}\n\t}\n\tte.textChangedPublisher.Publish()\n\treturn\n}\n\nfunc (te *TextEdit) CompactHeight() bool {\n\treturn te.compactHeight\n}\n\nfunc (te *TextEdit) SetCompactHeight(enabled bool) {\n\tif enabled == te.compactHeight {\n\t\treturn\n\t}\n\n\tte.compactHeight = enabled\n\n\tvar ptr uintptr\n\tif enabled {\n\t\tte.updateMargins()\n\t\tptr = drawTextCompatibleEditWordbreakProcPtr\n\t} else {\n\t\tptr = te.origWordbreakProcPtr\n\t}\n\tte.SendMessage(win.EM_SETWORDBREAKPROC, 0, ptr)\n\n\tte.RequestLayout()\n}\n\nfunc (te *TextEdit) TextAlignment() Alignment1D {\n\tswitch win.GetWindowLong(te.hWnd, win.GWL_STYLE) & (win.ES_LEFT | win.ES_CENTER | win.ES_RIGHT) {\n\tcase win.ES_CENTER:\n\t\treturn AlignCenter\n\n\tcase win.ES_RIGHT:\n\t\treturn AlignFar\n\t}\n\n\treturn AlignNear\n}\n\nfunc (te *TextEdit) SetTextAlignment(alignment Alignment1D) error {\n\tif alignment == AlignDefault {\n\t\talignment = AlignNear\n\t}\n\n\tvar bit uint32\n\n\tswitch alignment {\n\tcase AlignCenter:\n\t\tbit = win.ES_CENTER\n\n\tcase AlignFar:\n\t\tbit = win.ES_RIGHT\n\n\tdefault:\n\t\tbit = win.ES_LEFT\n\t}\n\n\treturn te.setAndClearStyleBits(bit, win.ES_LEFT|win.ES_CENTER|win.ES_RIGHT)\n}\n\nfunc (te *TextEdit) MaxLength() int {\n\treturn int(te.SendMessage(win.EM_GETLIMITTEXT, 0, 0))\n}\n\nfunc (te *TextEdit) SetMaxLength(value int) {\n\tte.SendMessage(win.EM_SETLIMITTEXT, uintptr(value), 0)\n}\n\nfunc (te *TextEdit) ScrollToCaret() {\n\tte.SendMessage(win.EM_SCROLLCARET, 0, 0)\n}\n\nfunc (te *TextEdit) TextSelection() (start, end int) {\n\tte.SendMessage(win.EM_GETSEL, uintptr(unsafe.Pointer(&start)), uintptr(unsafe.Pointer(&end)))\n\treturn\n}\n\nfunc (te *TextEdit) SetTextSelection(start, end int) {\n\tte.SendMessage(win.EM_SETSEL, uintptr(start), uintptr(end))\n}\n\nfunc (te *TextEdit) ReplaceSelectedText(text string, canUndo bool) {\n\tte.SendMessage(win.EM_REPLACESEL,\n\t\tuintptr(win.BoolToBOOL(canUndo)),\n\t\tuintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))))\n}\n\nfunc (te *TextEdit) AppendText(value string) {\n\ts, e := te.TextSelection()\n\tl := te.TextLength()\n\tte.SetTextSelection(l, l)\n\tte.ReplaceSelectedText(value, false)\n\tte.SetTextSelection(s, e)\n}\n\nfunc (te *TextEdit) ReadOnly() bool {\n\treturn te.hasStyleBits(win.ES_READONLY)\n}\n\nfunc (te *TextEdit) SetReadOnly(readOnly bool) error {\n\tif 0 == te.SendMessage(win.EM_SETREADONLY, uintptr(win.BoolToBOOL(readOnly)), 0) {\n\t\treturn newError(\"SendMessage(EM_SETREADONLY)\")\n\t}\n\n\tte.readOnlyChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (te *TextEdit) TextChanged() *Event {\n\treturn te.textChangedPublisher.Event()\n}\n\nfunc (te *TextEdit) TextColor() Color {\n\treturn te.textColor\n}\n\nfunc (te *TextEdit) SetTextColor(c Color) {\n\tte.textColor = c\n\n\tte.Invalidate()\n}\n\n// ContextMenuLocation returns carret position in screen coordinates in native pixels.\nfunc (te *TextEdit) ContextMenuLocation() Point {\n\tidx := int(te.SendMessage(win.EM_GETCARETINDEX, 0, 0))\n\tif idx < 0 {\n\t\tstart, end := te.TextSelection()\n\t\tidx = (start + end) / 2\n\t}\n\tres := uint32(te.SendMessage(win.EM_POSFROMCHAR, uintptr(idx), 0))\n\tpt := win.POINT{int32(win.LOWORD(res)), int32(win.HIWORD(res))}\n\twindowTrimToClientBounds(te.hWnd, &pt)\n\treturn pointPixelsFromPOINT(pt)\n}\n\nfunc (*TextEdit) NeedsWmSize() bool {\n\treturn true\n}\n\nfunc (te *TextEdit) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_COMMAND:\n\t\tswitch win.HIWORD(uint32(wParam)) {\n\t\tcase win.EN_CHANGE:\n\t\t\tif te.compactHeight {\n\t\t\t\tif createLayoutItemForWidget(te).(MinSizer).MinSize().Height != te.HeightPixels() {\n\t\t\t\t\tte.RequestLayout()\n\t\t\t\t}\n\t\t\t}\n\t\t\tte.textChangedPublisher.Publish()\n\t\t}\n\n\tcase win.WM_GETDLGCODE:\n\t\tif wParam == win.VK_RETURN {\n\t\t\treturn win.DLGC_WANTALLKEYS\n\t\t}\n\n\t\treturn win.DLGC_HASSETSEL | win.DLGC_WANTARROWS | win.DLGC_WANTCHARS\n\n\tcase win.WM_KEYDOWN:\n\t\tif Key(wParam) == KeyA && ControlDown() {\n\t\t\tte.SetTextSelection(0, -1)\n\t\t}\n\t}\n\n\treturn te.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (te *TextEdit) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tif te.margins.Width <= 0 {\n\t\tte.updateMargins()\n\t}\n\n\treturn &textEditLayoutItem{\n\t\twidth2Height:            make(map[int]int),\n\t\tcompactHeight:           te.compactHeight,\n\t\tmargins:                 te.margins,\n\t\ttext:                    te.Text(),\n\t\tfont:                    te.Font(),\n\t\tminWidth:                te.calculateTextSizeImpl(\"W\").Width,\n\t\tnonCompactHeightMinSize: te.dialogBaseUnitsToPixels(Size{20, 12}),\n\t}\n}\n\ntype textEditLayoutItem struct {\n\tLayoutItemBase\n\tmutex                   sync.Mutex\n\twidth2Height            map[int]int // in native pixels\n\tnonCompactHeightMinSize Size        // in native pixels\n\tmargins                 Size        // in native pixels\n\ttext                    string\n\tfont                    *Font\n\tminWidth                int // in native pixels\n\tcompactHeight           bool\n}\n\nfunc (li *textEditLayoutItem) LayoutFlags() LayoutFlags {\n\tflags := ShrinkableHorz | GrowableHorz | GreedyHorz\n\tif !li.compactHeight {\n\t\tflags |= GreedyVert | GrowableVert | ShrinkableVert\n\t}\n\treturn flags\n}\n\nfunc (li *textEditLayoutItem) IdealSize() Size {\n\tif li.compactHeight {\n\t\treturn li.MinSize()\n\t} else {\n\t\treturn SizeFrom96DPI(Size{100, 100}, li.ctx.dpi)\n\t}\n}\n\nfunc (li *textEditLayoutItem) MinSize() Size {\n\tif li.compactHeight {\n\t\twidth := IntFrom96DPI(100, li.ctx.dpi)\n\t\treturn Size{width, li.HeightForWidth(width)}\n\t} else {\n\t\treturn li.nonCompactHeightMinSize\n\t}\n}\n\nfunc (li *textEditLayoutItem) HasHeightForWidth() bool {\n\treturn li.compactHeight\n}\n\nfunc (li *textEditLayoutItem) HeightForWidth(width int) int {\n\tli.mutex.Lock()\n\tdefer li.mutex.Unlock()\n\n\tif height, ok := li.width2Height[width]; ok {\n\t\treturn height\n\t}\n\n\tsize := calculateTextSize(li.text, li.font, li.ctx.dpi, width-li.margins.Width, li.handle)\n\tsize.Height += li.margins.Height\n\tsize.Height = maxi(size.Height, li.nonCompactHeightMinSize.Height)\n\n\tli.width2Height[width] = size.Height\n\n\treturn size.Height\n}\n"
  },
  {
    "path": "textlabel.go",
    "content": "// Copyright 2018 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"sync\"\n)\n\ntype TextLabel struct {\n\tstatic\n\ttextChangedPublisher EventPublisher\n}\n\nfunc NewTextLabel(parent Container) (*TextLabel, error) {\n\treturn NewTextLabelWithStyle(parent, 0)\n}\n\nfunc NewTextLabelWithStyle(parent Container, style uint32) (*TextLabel, error) {\n\ttl := new(TextLabel)\n\n\tif err := tl.init(tl, parent, style); err != nil {\n\t\treturn nil, err\n\t}\n\n\ttl.textAlignment = AlignHNearVNear\n\n\ttl.MustRegisterProperty(\"Text\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn tl.Text()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn tl.SetText(assertStringOr(v, \"\"))\n\t\t},\n\t\ttl.textChangedPublisher.Event()))\n\n\treturn tl, nil\n}\n\nfunc (tl *TextLabel) asStatic() *static {\n\treturn &tl.static\n}\n\nfunc (tl *TextLabel) TextAlignment() Alignment2D {\n\treturn tl.textAlignment\n}\n\nfunc (tl *TextLabel) SetTextAlignment(alignment Alignment2D) error {\n\tif alignment == AlignHVDefault {\n\t\talignment = AlignHNearVNear\n\t}\n\n\treturn tl.setTextAlignment(alignment)\n}\n\nfunc (tl *TextLabel) Text() string {\n\treturn tl.text()\n}\n\nfunc (tl *TextLabel) SetText(text string) error {\n\tif changed, err := tl.setText(text); err != nil {\n\t\treturn err\n\t} else if !changed {\n\t\treturn nil\n\t}\n\n\ttl.textChangedPublisher.Publish()\n\n\treturn nil\n}\n\nfunc (tl *TextLabel) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn &textLabelLayoutItem{\n\t\twidth2Height: make(map[int]int),\n\t\ttext:         tl.Text(),\n\t\tfont:         tl.Font(),\n\t\tminWidth:     tl.MinSizePixels().Width,\n\t}\n}\n\ntype textLabelLayoutItem struct {\n\tLayoutItemBase\n\tmutex        sync.Mutex\n\twidth2Height map[int]int // in native pixels\n\ttext         string\n\tfont         *Font\n\tminWidth     int // in native pixels\n}\n\nfunc (*textLabelLayoutItem) LayoutFlags() LayoutFlags {\n\treturn GrowableHorz | GrowableVert\n}\n\nfunc (li *textLabelLayoutItem) IdealSize() Size {\n\treturn li.MinSize()\n}\n\nfunc (li *textLabelLayoutItem) MinSize() Size {\n\treturn calculateTextSize(li.text, li.font, li.ctx.dpi, li.minWidth, li.handle)\n}\n\nfunc (li *textLabelLayoutItem) HasHeightForWidth() bool {\n\treturn true\n}\n\nfunc (li *textLabelLayoutItem) HeightForWidth(width int) int {\n\tli.mutex.Lock()\n\tdefer li.mutex.Unlock()\n\n\tif height, ok := li.width2Height[width]; ok {\n\t\treturn height\n\t}\n\n\tsize := calculateTextSize(li.text, li.font, li.ctx.dpi, width, li.handle)\n\n\tli.width2Height[width] = size.Height\n\n\treturn size.Height\n}\n"
  },
  {
    "path": "toolbar.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype ToolBarButtonStyle int\n\nconst (\n\tToolBarButtonImageOnly ToolBarButtonStyle = iota\n\tToolBarButtonTextOnly\n\tToolBarButtonImageBeforeText\n\tToolBarButtonImageAboveText\n)\n\ntype ToolBar struct {\n\tWidgetBase\n\timageList          *ImageList\n\tactions            *ActionList\n\tdefaultButtonWidth int\n\tmaxTextRows        int\n\tbuttonStyle        ToolBarButtonStyle\n}\n\nfunc NewToolBarWithOrientationAndButtonStyle(parent Container, orientation Orientation, buttonStyle ToolBarButtonStyle) (*ToolBar, error) {\n\tvar style uint32\n\tif orientation == Vertical {\n\t\tstyle = win.CCS_VERT | win.CCS_NORESIZE\n\t} else {\n\t\tstyle = win.TBSTYLE_WRAPABLE\n\t}\n\n\tif buttonStyle != ToolBarButtonImageAboveText {\n\t\tstyle |= win.TBSTYLE_LIST\n\t}\n\n\ttb := &ToolBar{\n\t\tbuttonStyle: buttonStyle,\n\t}\n\ttb.actions = newActionList(tb)\n\n\tif orientation == Vertical {\n\t\ttb.defaultButtonWidth = 100\n\t}\n\n\tif err := InitWidget(\n\t\ttb,\n\t\tparent,\n\t\t\"ToolbarWindow32\",\n\t\twin.CCS_NODIVIDER|win.TBSTYLE_FLAT|win.TBSTYLE_TOOLTIPS|style,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\texStyle := tb.SendMessage(win.TB_GETEXTENDEDSTYLE, 0, 0)\n\texStyle |= win.TBSTYLE_EX_DRAWDDARROWS | win.TBSTYLE_EX_MIXEDBUTTONS\n\ttb.SendMessage(win.TB_SETEXTENDEDSTYLE, 0, exStyle)\n\n\treturn tb, nil\n}\n\nfunc NewToolBar(parent Container) (*ToolBar, error) {\n\treturn NewToolBarWithOrientationAndButtonStyle(parent, Horizontal, ToolBarButtonImageOnly)\n}\n\nfunc NewVerticalToolBar(parent Container) (*ToolBar, error) {\n\treturn NewToolBarWithOrientationAndButtonStyle(parent, Vertical, ToolBarButtonImageAboveText)\n}\n\nfunc (tb *ToolBar) Dispose() {\n\ttb.WidgetBase.Dispose()\n\n\ttb.actions.Clear()\n\n\tif tb.imageList != nil {\n\t\ttb.imageList.Dispose()\n\t\ttb.imageList = nil\n\t}\n}\n\nfunc (tb *ToolBar) applyFont(font *Font) {\n\ttb.WidgetBase.applyFont(font)\n\n\ttb.applyDefaultButtonWidth()\n\n\ttb.RequestLayout()\n}\n\nfunc (tb *ToolBar) ApplyDPI(dpi int) {\n\ttb.WidgetBase.ApplyDPI(dpi)\n\n\tvar maskColor Color\n\tvar size Size\n\tif tb.imageList != nil {\n\t\tmaskColor = tb.imageList.maskColor\n\t\tsize = SizeFrom96DPI(tb.imageList.imageSize96dpi, dpi)\n\t} else {\n\t\tsize = SizeFrom96DPI(Size{16, 16}, dpi)\n\t}\n\n\timl, err := NewImageListForDPI(size, maskColor, dpi)\n\tif err != nil {\n\t\treturn\n\t}\n\n\ttb.SendMessage(win.TB_SETIMAGELIST, 0, uintptr(iml.hIml))\n\n\tif tb.imageList != nil {\n\t\ttb.imageList.Dispose()\n\t}\n\n\ttb.imageList = iml\n\n\tfor _, action := range tb.actions.actions {\n\t\tif action.image != nil {\n\t\t\ttb.onActionChanged(action)\n\t\t}\n\t}\n\n\ttb.hFont = tb.Font().handleForDPI(tb.DPI())\n\tsetWindowFont(tb.hWnd, tb.hFont)\n}\n\nfunc (tb *ToolBar) Orientation() Orientation {\n\tstyle := win.GetWindowLong(tb.hWnd, win.GWL_STYLE)\n\n\tif style&win.CCS_VERT > 0 {\n\t\treturn Vertical\n\t}\n\n\treturn Horizontal\n}\n\nfunc (tb *ToolBar) ButtonStyle() ToolBarButtonStyle {\n\treturn tb.buttonStyle\n}\n\nfunc (tb *ToolBar) applyDefaultButtonWidth() error {\n\tif tb.defaultButtonWidth == 0 {\n\t\treturn nil\n\t}\n\n\tdpi := tb.DPI()\n\twidth := IntFrom96DPI(tb.defaultButtonWidth, dpi)\n\n\tlParam := uintptr(win.MAKELONG(uint16(width), uint16(width)))\n\tif 0 == tb.SendMessage(win.TB_SETBUTTONWIDTH, 0, lParam) {\n\t\treturn newError(\"SendMessage(TB_SETBUTTONWIDTH)\")\n\t}\n\n\tsize := uint32(tb.SendMessage(win.TB_GETBUTTONSIZE, 0, 0))\n\theight := win.HIWORD(size)\n\n\tlParam = uintptr(win.MAKELONG(uint16(width), height))\n\tif win.FALSE == tb.SendMessage(win.TB_SETBUTTONSIZE, 0, lParam) {\n\t\treturn newError(\"SendMessage(TB_SETBUTTONSIZE)\")\n\t}\n\n\treturn nil\n}\n\n// DefaultButtonWidth returns the default button width of the ToolBar.\n//\n// The default value for a horizontal ToolBar is 0, resulting in automatic\n// sizing behavior. For a vertical ToolBar, the default is 100 pixels.\nfunc (tb *ToolBar) DefaultButtonWidth() int {\n\treturn tb.defaultButtonWidth\n}\n\n// SetDefaultButtonWidth sets the default button width of the ToolBar.\n//\n// Calling this method affects all buttons in the ToolBar, no matter if they are\n// added before or after the call. A width of 0 results in automatic sizing\n// behavior. Negative values are not allowed.\nfunc (tb *ToolBar) SetDefaultButtonWidth(width int) error {\n\tif width == tb.defaultButtonWidth {\n\t\treturn nil\n\t}\n\n\tif width < 0 {\n\t\treturn newError(\"width must be >= 0\")\n\t}\n\n\told := tb.defaultButtonWidth\n\n\ttb.defaultButtonWidth = width\n\n\tfor _, action := range tb.actions.actions {\n\t\tif err := tb.onActionChanged(action); err != nil {\n\t\t\ttb.defaultButtonWidth = old\n\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn tb.applyDefaultButtonWidth()\n}\n\nfunc (tb *ToolBar) MaxTextRows() int {\n\treturn tb.maxTextRows\n}\n\nfunc (tb *ToolBar) SetMaxTextRows(maxTextRows int) error {\n\tif 0 == tb.SendMessage(win.TB_SETMAXTEXTROWS, uintptr(maxTextRows), 0) {\n\t\treturn newError(\"SendMessage(TB_SETMAXTEXTROWS)\")\n\t}\n\n\ttb.maxTextRows = maxTextRows\n\n\treturn nil\n}\n\nfunc (tb *ToolBar) Actions() *ActionList {\n\treturn tb.actions\n}\n\nfunc (tb *ToolBar) ImageList() *ImageList {\n\treturn tb.imageList\n}\n\nfunc (tb *ToolBar) SetImageList(value *ImageList) {\n\tvar hIml win.HIMAGELIST\n\n\tif tb.buttonStyle != ToolBarButtonTextOnly && value != nil {\n\t\thIml = value.hIml\n\t}\n\n\ttb.SendMessage(win.TB_SETIMAGELIST, 0, uintptr(hIml))\n\n\ttb.imageList = value\n}\n\nfunc (tb *ToolBar) imageIndex(image Image) (imageIndex int32, err error) {\n\tif tb.imageList == nil {\n\t\tdpi := tb.DPI()\n\t\timl, err := NewImageListForDPI(SizeFrom96DPI(Size{16, 16}, dpi), 0, dpi)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\ttb.SetImageList(iml)\n\t}\n\n\timageIndex = -1\n\tif image != nil {\n\t\tif imageIndex, err = tb.imageList.AddImage(image); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc (tb *ToolBar) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_MOUSEMOVE, win.WM_MOUSELEAVE, win.WM_LBUTTONDOWN:\n\t\ttb.Invalidate()\n\n\tcase win.WM_COMMAND:\n\t\tswitch win.HIWORD(uint32(wParam)) {\n\t\tcase win.BN_CLICKED:\n\t\t\tactionId := uint16(win.LOWORD(uint32(wParam)))\n\t\t\tif action, ok := actionsById[actionId]; ok {\n\t\t\t\taction.raiseTriggered()\n\t\t\t\treturn 0\n\t\t\t}\n\t\t}\n\n\tcase win.WM_NOTIFY:\n\t\tnmhdr := (*win.NMHDR)(unsafe.Pointer(lParam))\n\n\t\tswitch int32(nmhdr.Code) {\n\t\tcase win.TBN_DROPDOWN:\n\t\t\tnmtb := (*win.NMTOOLBAR)(unsafe.Pointer(lParam))\n\t\t\tactionId := uint16(nmtb.IItem)\n\t\t\tif action := actionsById[actionId]; action != nil {\n\t\t\t\tvar r win.RECT\n\t\t\t\tif 0 == tb.SendMessage(win.TB_GETRECT, uintptr(actionId), uintptr(unsafe.Pointer(&r))) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tp := win.POINT{r.Left, r.Bottom}\n\n\t\t\t\tif !win.ClientToScreen(tb.hWnd, &p) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\taction.menu.updateItemsWithImageForWindow(tb)\n\n\t\t\t\twin.TrackPopupMenuEx(\n\t\t\t\t\taction.menu.hMenu,\n\t\t\t\t\twin.TPM_NOANIMATION,\n\t\t\t\t\tp.X,\n\t\t\t\t\tp.Y,\n\t\t\t\t\ttb.hWnd,\n\t\t\t\t\tnil)\n\n\t\t\t\treturn win.TBDDRET_DEFAULT\n\t\t\t}\n\t\t}\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\ttb.SendMessage(win.TB_AUTOSIZE, 0, 0)\n\t}\n\n\treturn tb.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (tb *ToolBar) initButtonForAction(action *Action, state, style *byte, image *int32, text *uintptr) (err error) {\n\tif tb.hasStyleBits(win.CCS_VERT) {\n\t\t*state |= win.TBSTATE_WRAP\n\t} else if tb.defaultButtonWidth == 0 {\n\t\t*style |= win.BTNS_AUTOSIZE\n\t}\n\n\tif action.checked {\n\t\t*state |= win.TBSTATE_CHECKED\n\t}\n\n\tif action.enabled {\n\t\t*state |= win.TBSTATE_ENABLED\n\t}\n\n\tif action.checkable {\n\t\t*style |= win.BTNS_CHECK\n\t}\n\n\tif action.exclusive {\n\t\t*style |= win.BTNS_GROUP\n\t}\n\n\tif tb.buttonStyle != ToolBarButtonImageOnly && len(action.text) > 0 {\n\t\t*style |= win.BTNS_SHOWTEXT\n\t}\n\n\tif action.menu != nil {\n\t\tif len(action.Triggered().handlers) > 0 {\n\t\t\t*style |= win.BTNS_DROPDOWN\n\t\t} else {\n\t\t\t*style |= win.BTNS_WHOLEDROPDOWN\n\t\t}\n\t}\n\n\tif action.IsSeparator() {\n\t\t*style = win.BTNS_SEP\n\t}\n\n\tif tb.buttonStyle != ToolBarButtonTextOnly {\n\t\tif *image, err = tb.imageIndex(action.image); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tvar actionText string\n\tif s := action.shortcut; tb.buttonStyle == ToolBarButtonImageOnly && s.Key != 0 {\n\t\tactionText = fmt.Sprintf(\"%s (%s)\", action.Text(), s.String())\n\t} else {\n\t\tactionText = action.Text()\n\t}\n\n\tif len(actionText) != 0 {\n\t\t*text = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(actionText)))\n\t} else if len(action.toolTip) != 0 {\n\t\t*text = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(action.toolTip)))\n\t}\n\n\treturn\n}\n\nfunc (tb *ToolBar) onActionChanged(action *Action) error {\n\ttbbi := win.TBBUTTONINFO{\n\t\tDwMask: win.TBIF_IMAGE | win.TBIF_STATE | win.TBIF_STYLE | win.TBIF_TEXT,\n\t\tIImage: win.I_IMAGENONE,\n\t}\n\n\ttbbi.CbSize = uint32(unsafe.Sizeof(tbbi))\n\n\tif err := tb.initButtonForAction(\n\t\taction,\n\t\t&tbbi.FsState,\n\t\t&tbbi.FsStyle,\n\t\t&tbbi.IImage,\n\t\t&tbbi.PszText); err != nil {\n\n\t\treturn err\n\t}\n\n\tif 0 == tb.SendMessage(\n\t\twin.TB_SETBUTTONINFO,\n\t\tuintptr(action.id),\n\t\tuintptr(unsafe.Pointer(&tbbi))) {\n\n\t\treturn newError(\"SendMessage(TB_SETBUTTONINFO) failed\")\n\t}\n\n\ttb.RequestLayout()\n\n\treturn nil\n}\n\nfunc (tb *ToolBar) onActionVisibleChanged(action *Action) error {\n\tif !action.IsSeparator() {\n\t\tdefer tb.actions.updateSeparatorVisibility()\n\t}\n\n\tif action.Visible() {\n\t\treturn tb.insertAction(action, true)\n\t}\n\n\treturn tb.removeAction(action, true)\n}\n\nfunc (tb *ToolBar) insertAction(action *Action, visibleChanged bool) (err error) {\n\tif !visibleChanged {\n\t\taction.addChangedHandler(tb)\n\t\tdefer func() {\n\t\t\tif err != nil {\n\t\t\t\taction.removeChangedHandler(tb)\n\t\t\t}\n\t\t}()\n\t}\n\n\tif !action.Visible() {\n\t\treturn\n\t}\n\n\tindex := tb.actions.indexInObserver(action)\n\n\ttbb := win.TBBUTTON{\n\t\tIdCommand: int32(action.id),\n\t}\n\n\tif err = tb.initButtonForAction(\n\t\taction,\n\t\t&tbb.FsState,\n\t\t&tbb.FsStyle,\n\t\t&tbb.IBitmap,\n\t\t&tbb.IString); err != nil {\n\n\t\treturn\n\t}\n\n\ttb.SetVisible(true)\n\n\ttb.SendMessage(win.TB_BUTTONSTRUCTSIZE, uintptr(unsafe.Sizeof(tbb)), 0)\n\n\tif win.FALSE == tb.SendMessage(win.TB_INSERTBUTTON, uintptr(index), uintptr(unsafe.Pointer(&tbb))) {\n\t\treturn newError(\"SendMessage(TB_ADDBUTTONS)\")\n\t}\n\n\tif err = tb.applyDefaultButtonWidth(); err != nil {\n\t\treturn\n\t}\n\n\ttb.SendMessage(win.TB_AUTOSIZE, 0, 0)\n\n\ttb.RequestLayout()\n\n\treturn\n}\n\nfunc (tb *ToolBar) removeAction(action *Action, visibleChanged bool) error {\n\tindex := tb.actions.indexInObserver(action)\n\n\tif !visibleChanged {\n\t\taction.removeChangedHandler(tb)\n\t}\n\n\tif 0 == tb.SendMessage(win.TB_DELETEBUTTON, uintptr(index), 0) {\n\t\treturn newError(\"SendMessage(TB_DELETEBUTTON) failed\")\n\t}\n\n\ttb.RequestLayout()\n\n\treturn nil\n}\n\nfunc (tb *ToolBar) onInsertedAction(action *Action) error {\n\treturn tb.insertAction(action, false)\n}\n\nfunc (tb *ToolBar) onRemovingAction(action *Action) error {\n\treturn tb.removeAction(action, false)\n}\n\nfunc (tb *ToolBar) onClearingActions() error {\n\tfor i := tb.actions.Len() - 1; i >= 0; i-- {\n\t\tif action := tb.actions.At(i); action.Visible() {\n\t\t\tif err := tb.onRemovingAction(action); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (tb *ToolBar) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\tbuttonSize := uint32(tb.SendMessage(win.TB_GETBUTTONSIZE, 0, 0))\n\n\tdpi := tb.DPI()\n\twidth := IntFrom96DPI(tb.defaultButtonWidth, dpi)\n\tif width == 0 {\n\t\twidth = int(win.LOWORD(buttonSize))\n\t}\n\n\theight := int(win.HIWORD(buttonSize))\n\n\tvar size win.SIZE\n\tvar wp uintptr\n\tvar layoutFlags LayoutFlags\n\n\tif tb.Orientation() == Vertical {\n\t\twp = win.TRUE\n\t\tlayoutFlags = ShrinkableVert | GrowableVert | GreedyVert\n\t} else {\n\t\twp = win.FALSE\n\t\t// FIXME: Since reimplementation of BoxLayout we must use 0 here,\n\t\t// otherwise the ToolBar contained in MainWindow will eat half the space.\n\t\t//layoutFlags = ShrinkableHorz | GrowableHorz\n\t}\n\n\tif win.FALSE != tb.SendMessage(win.TB_GETIDEALSIZE, wp, uintptr(unsafe.Pointer(&size))) {\n\t\tif wp == win.TRUE {\n\t\t\theight = int(size.CY)\n\t\t} else {\n\t\t\twidth = int(size.CX)\n\t\t}\n\t}\n\n\treturn &toolBarLayoutItem{\n\t\tlayoutFlags: layoutFlags,\n\t\tidealSize:   Size{width, height},\n\t}\n}\n\ntype toolBarLayoutItem struct {\n\tLayoutItemBase\n\tlayoutFlags LayoutFlags\n\tidealSize   Size // in native pixels\n}\n\nfunc (li *toolBarLayoutItem) LayoutFlags() LayoutFlags {\n\treturn li.layoutFlags\n}\n\nfunc (li *toolBarLayoutItem) IdealSize() Size {\n\treturn li.idealSize\n}\n\nfunc (li *toolBarLayoutItem) MinSize() Size {\n\treturn li.idealSize\n}\n"
  },
  {
    "path": "toolbutton.go",
    "content": "// Copyright 2012 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype ToolButton struct {\n\tButton\n}\n\nfunc NewToolButton(parent Container) (*ToolButton, error) {\n\ttb := new(ToolButton)\n\n\tif err := InitWidget(\n\t\ttb,\n\t\tparent,\n\t\t\"BUTTON\",\n\t\twin.WS_TABSTOP|win.WS_VISIBLE|win.BS_BITMAP|win.BS_PUSHBUTTON,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\ttb.Button.init()\n\n\ttb.GraphicsEffects().Add(InteractionEffect)\n\ttb.GraphicsEffects().Add(FocusEffect)\n\n\treturn tb, nil\n}\n\nfunc (tb *ToolButton) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_GETDLGCODE:\n\t\treturn win.DLGC_BUTTON\n\t}\n\n\treturn tb.Button.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (tb *ToolButton) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn &toolButtonLayoutItem{\n\t\tidealSize: tb.dialogBaseUnitsToPixels(Size{16, 12}),\n\t}\n}\n\ntype toolButtonLayoutItem struct {\n\tLayoutItemBase\n\tidealSize Size // in native pixels\n}\n\nfunc (*toolButtonLayoutItem) LayoutFlags() LayoutFlags {\n\treturn 0\n}\n\nfunc (tb *toolButtonLayoutItem) IdealSize() Size {\n\treturn tb.idealSize\n}\n\nfunc (tb *toolButtonLayoutItem) MinSize() Size {\n\treturn tb.idealSize\n}\n"
  },
  {
    "path": "tools/ui2walk/ui2walk.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/xml\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n)\n\nvar forceUpdate *bool = flag.Bool(\"force\", false, \"forces code generation for up-to-date files\")\nvar translatable *bool = flag.Bool(\"tr\", false, \"adds calls to a user provided 'func tr(source string, context ...string) string' that returns a translation of the source argument, using provided context args for disambiguation\")\n\ntype String struct {\n\tText         string `xml:\"string\"`\n\tComment      string `xml:\"comment,attr\"`\n\tExtraComment string `xml:\"extracomment,attr\"`\n}\n\ntype UI struct {\n\tClass         string        `xml:\"class\"`\n\tWidget        Widget        `xml:\"widget\"`\n\tCustomWidgets CustomWidgets `xml:\"customwidgets\"`\n\tTabStops      []string      `xml:\"tabstops>tabstop\"`\n}\n\ntype Widget struct {\n\tClass     string       `xml:\"class,attr\"`\n\tName      string       `xml:\"name,attr\"`\n\tAttribute []*Attribute `xml:\"attribute\"`\n\tProperty  []*Property  `xml:\"property\"`\n\tLayout    *Layout      `xml:\"layout\"`\n\tWidget    []*Widget    `xml:\"widget\"`\n\tAddAction []*AddAction `xml:\"addaction\"`\n\tAction    []*Action    `xml:\"action\"`\n\tignored   bool\n}\n\ntype Layout struct {\n\tClass    string      `xml:\"class,attr\"`\n\tName     string      `xml:\"name,attr\"`\n\tStretch  string      `xml:\"stretch,attr\"`\n\tProperty []*Property `xml:\"property\"`\n\tItem     []*Item     `xml:\"item\"`\n\tignored  bool\n}\n\ntype Item struct {\n\tRow     string  `xml:\"row,attr\"`\n\tColumn  string  `xml:\"column,attr\"`\n\tRowSpan string  `xml:\"rowspan,attr\"`\n\tColSpan string  `xml:\"colspan,attr\"`\n\tWidget  *Widget `xml:\"widget\"`\n\tSpacer  *Spacer `xml:\"spacer\"`\n}\n\ntype Spacer struct {\n\tName     string      `xml:\"name,attr\"`\n\tProperty []*Property `xml:\"property\"`\n}\n\ntype AddAction struct {\n\tName string `xml:\"name,attr\"`\n}\n\ntype Action struct {\n\tName     string      `xml:\"name,attr\"`\n\tProperty []*Property `xml:\"property\"`\n}\n\ntype Attribute struct {\n\tName string `xml:\"name,attr\"`\n\tString\n}\n\ntype Property struct {\n\tName   string    `xml:\"name,attr\"`\n\tBool   bool      `xml:\"bool\"`\n\tEnum   string    `xml:\"enum\"`\n\tFont   *Font     `xml:\"font\"`\n\tNumber float64   `xml:\"number\"`\n\tRect   Rectangle `xml:\"rect\"`\n\tSet    string    `xml:\"set\"`\n\tSize   Size      `xml:\"size\"`\n\tString\n}\n\ntype Font struct {\n\tFamily    string `xml:\"family\"`\n\tPointSize int    `xml:\"pointsize\"`\n\tItalic    bool   `xml:\"italic\"`\n\tBold      bool   `xml:\"bold\"`\n\tUnderline bool   `xml:\"underline\"`\n\tStrikeOut bool   `xml:\"strikeout\"`\n}\n\ntype Rectangle struct {\n\tX      int `xml:\"x\"`\n\tY      int `xml:\"y\"`\n\tWidth  int `xml:\"width\"`\n\tHeight int `xml:\"height\"`\n}\n\ntype Size struct {\n\tWidth  int `xml:\"width\"`\n\tHeight int `xml:\"height\"`\n}\n\ntype CustomWidgets struct {\n\tCustomWidget []*CustomWidget `xml:\"customwidget\"`\n}\n\ntype CustomWidget struct {\n\tClass   string `xml:\"class\"`\n\tExtends string `xml:\"extends\"`\n}\n\nfunc trString(str *String) string {\n\tif str == nil {\n\t\treturn \"\"\n\t}\n\n\tif !*translatable {\n\t\treturn fmt.Sprintf(\"`%s`\", str.Text)\n\t}\n\n\tbuf := new(bytes.Buffer)\n\tbuf.WriteString(\"tr(`\")\n\tbuf.WriteString(str.Text)\n\tbuf.WriteString(\"`\")\n\n\tif str.Comment != \"\" {\n\t\tbuf.WriteString(\", `\")\n\t\tbuf.WriteString(str.Comment)\n\t\tbuf.WriteString(\"`\")\n\t}\n\n\tif str.ExtraComment != \"\" {\n\t\tbuf.WriteString(\", `\")\n\t\tbuf.WriteString(str.ExtraComment)\n\t\tbuf.WriteString(\"`\")\n\t}\n\n\tbuf.WriteString(\")\")\n\n\treturn buf.String()\n}\n\nfunc logFatal(err error) {\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc parseUI(reader io.Reader) (*UI, error) {\n\tui := &UI{}\n\n\tif err := xml.NewDecoder(reader).Decode(ui); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ui, nil\n}\n\nfunc writeAttribute(buf *bytes.Buffer, attr *Attribute, qualifiedReceiver string) (err error) {\n\tswitch attr.Name {\n\tcase \"title\":\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t\"if err := %s.SetTitle(%s); err != nil {\\nreturn err\\n}\\n\",\n\t\t\tqualifiedReceiver, trString(&attr.String)))\n\n\tdefault:\n\t\tfmt.Printf(\"Ignoring unsupported attribute: '%s'\\n\", attr.Name)\n\t\treturn nil\n\t}\n\n\treturn nil\n}\n\nfunc writeAttributes(buf *bytes.Buffer, attrs []*Attribute, qualifiedReceiver string) error {\n\tfor _, attr := range attrs {\n\t\tif err := writeAttribute(buf, attr, qualifiedReceiver); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc writeProperty(buf *bytes.Buffer, prop *Property, qualifiedReceiver string, widget *Widget) (err error) {\n\tif prop.Name == \"windowTitle\" && widget != nil && widget.Class == \"QWidget\" {\n\t\treturn\n\t}\n\n\tswitch prop.Name {\n\tcase \"decimals\":\n\t\tbuf.WriteString(fmt.Sprintf(\"if err := %s.SetDecimals(%d); err != nil {\\nreturn err\\n}\\n\", qualifiedReceiver, int(prop.Number)))\n\n\tcase \"echoMode\":\n\t\tswitch prop.Enum {\n\t\tcase \"QLineEdit::Normal\":\n\t\t\t// nop\n\n\t\tcase \"QLineEdit::Password\":\n\t\t\tbuf.WriteString(fmt.Sprintf(\"%s.SetPasswordMode(true)\\n\", qualifiedReceiver))\n\n\t\tdefault:\n\t\t\tfmt.Printf(\"Ignoring unsupported echoMode: '%s'\\n\", prop.Enum)\n\t\t\treturn nil\n\t\t}\n\n\tcase \"enabled\":\n\t\tbuf.WriteString(fmt.Sprintf(\"%s.SetEnabled(%t)\\n\", qualifiedReceiver, prop.Bool))\n\n\tcase \"font\":\n\t\tf := prop.Font\n\t\tfamily := f.Family\n\t\tif family == \"\" {\n\t\t\tfamily = \"MS Shell Dlg 2\"\n\t\t}\n\t\tpointSize := f.PointSize\n\t\tif pointSize == 0 {\n\t\t\tpointSize = 8\n\t\t}\n\t\tbuf.WriteString(fmt.Sprintf(\"if font, err = walk.NewFont(\\\"%s\\\", %d, \",\n\t\t\tfamily, pointSize))\n\t\tincluded := []bool{f.Bold, f.Italic, f.StrikeOut, f.Underline}\n\t\tflags := []string{\"walk.FontBold\", \"walk.FontItalic\", \"walk.FontStrikeOut\", \"walk.FontUnderline\"}\n\t\tvar includedFlags []string\n\t\tfor i := 0; i < len(included); i++ {\n\t\t\tif included[i] {\n\t\t\t\tincludedFlags = append(includedFlags, flags[i])\n\t\t\t}\n\t\t}\n\t\tif len(includedFlags) == 0 {\n\t\t\tbuf.WriteString(\"0\")\n\t\t} else {\n\t\t\tbuf.WriteString(strings.Join(includedFlags, \"|\"))\n\t\t}\n\t\tbuf.WriteString(`); err != nil {\n\t\t\treturn err\n\t\t\t}\n\t\t\t`)\n\t\tbuf.WriteString(fmt.Sprintf(\"%s.SetFont(font)\\n\", qualifiedReceiver))\n\n\tcase \"geometry\":\n\t\tif qualifiedReceiver == \"w\" {\n\t\t\t// Only set client size for top level\n\t\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t\t`if err := %s.SetClientSize(walk.Size{%d, %d}); err != nil {\n\t\t\treturn err\n\t\t\t}\n\t\t\t`,\n\t\t\t\tqualifiedReceiver, prop.Rect.Width, prop.Rect.Height))\n\t\t} else {\n\t\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t\t`if err := %s.SetBounds(walk.Rectangle{%d, %d, %d, %d}); err != nil {\n\t\t\treturn err\n\t\t\t}\n\t\t\t`,\n\t\t\t\tqualifiedReceiver, prop.Rect.X, prop.Rect.Y, prop.Rect.Width, prop.Rect.Height))\n\t\t}\n\n\tcase \"maximumSize\", \"minimumSize\":\n\t\t// We do these two guys in writeProperties, because we want to map them\n\t\t// to a single method call, if both are present.\n\n\tcase \"maxLength\":\n\t\tbuf.WriteString(fmt.Sprintf(\"%s.SetMaxLength(%d)\\n\", qualifiedReceiver, int(prop.Number)))\n\n\tcase \"readOnly\":\n\t\tbuf.WriteString(fmt.Sprintf(\"%s.SetReadOnly(%t)\\n\", qualifiedReceiver, prop.Bool))\n\n\tcase \"text\":\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t\"if err := %s.SetText(%s); err != nil {\\nreturn err\\n}\\n\",\n\t\t\tqualifiedReceiver, trString(&prop.String)))\n\n\tcase \"title\", \"windowTitle\":\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t\"if err := %s.SetTitle(%s); err != nil {\\nreturn err\\n}\\n\",\n\t\t\tqualifiedReceiver, trString(&prop.String)))\n\n\tcase \"orientation\":\n\t\tvar orientation string\n\t\tswitch prop.Enum {\n\t\tcase \"Qt::Horizontal\":\n\t\t\torientation = \"walk.Horizontal\"\n\n\t\tcase \"Qt::Vertical\":\n\t\t\torientation = \"walk.Vertical\"\n\n\t\tdefault:\n\t\t\treturn errors.New(fmt.Sprintf(\"unknown orientation: '%s'\", prop.Enum))\n\t\t}\n\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t`if err := %s.SetOrientation(%s); err != nil {\n\t\t\treturn err\n\t\t\t}\n\t\t\t`,\n\t\t\tqualifiedReceiver, orientation))\n\n\tdefault:\n\t\tfmt.Printf(\"Ignoring unsupported property: '%s'\\n\", prop.Name)\n\t\treturn nil\n\t}\n\n\treturn\n}\n\nfunc writeProperties(buf *bytes.Buffer, props []*Property, qualifiedReceiver string, widget *Widget) error {\n\tvar minSize, maxSize Size\n\tvar hasMinOrMaxSize bool\n\n\tfor _, prop := range props {\n\t\tif err := writeProperty(buf, prop, qualifiedReceiver, widget); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif prop.Name == \"minimumSize\" {\n\t\t\tminSize = prop.Size\n\t\t\thasMinOrMaxSize = true\n\t\t}\n\t\tif prop.Name == \"maximumSize\" {\n\t\t\tmaxSize = prop.Size\n\t\t\thasMinOrMaxSize = true\n\t\t}\n\t}\n\n\tif hasMinOrMaxSize {\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t`if err := %s.SetMinMaxSize(walk.Size{%d, %d}, walk.Size{%d, %d}); err != nil {\n\t\t\treturn err\n\t\t\t}\n\t\t\t`,\n\t\t\tqualifiedReceiver, minSize.Width, minSize.Height, maxSize.Width, maxSize.Height))\n\t}\n\n\treturn nil\n}\n\nfunc writeItemInitializations(buf *bytes.Buffer, items []*Item, parent *Widget, qualifiedParent string, layout string) error {\n\tfor _, item := range items {\n\t\tvar itemName string\n\n\t\tif item.Spacer != nil {\n\t\t\titemName = item.Spacer.Name\n\t\t\tname2Prop := make(map[string]*Property)\n\n\t\t\tfor _, prop := range item.Spacer.Property {\n\t\t\t\tname2Prop[prop.Name] = prop\n\t\t\t}\n\n\t\t\torientation := name2Prop[\"orientation\"]\n\t\t\tsizeType := name2Prop[\"sizeType\"]\n\t\t\tsizeHint := name2Prop[\"sizeHint\"]\n\n\t\t\tvar orientStr string\n\t\t\tvar fixedStr string\n\t\t\tvar secondParamStr string\n\n\t\t\tif orientation.Enum == \"Qt::Horizontal\" {\n\t\t\t\torientStr = \"H\"\n\n\t\t\t\tif sizeType != nil && sizeType.Enum == \"QSizePolicy::Fixed\" {\n\t\t\t\t\tfixedStr = \"Fixed\"\n\t\t\t\t\tsecondParamStr = fmt.Sprintf(\", %d\", sizeHint.Size.Width)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\torientStr = \"V\"\n\n\t\t\t\tif sizeType != nil && sizeType.Enum == \"QSizePolicy::Fixed\" {\n\t\t\t\t\tfixedStr = \"Fixed\"\n\t\t\t\t\tsecondParamStr = fmt.Sprintf(\", %d\", sizeHint.Size.Height)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif layout == \"\" {\n\t\t\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t\t\t`\n\t\t\t\t\t// anonymous spacer\n\t\t\t\t\tif _, err := walk.New%sSpacer%s(%s%s); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\t`,\n\t\t\t\t\torientStr, fixedStr, qualifiedParent, secondParamStr))\n\t\t\t} else {\n\t\t\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t\t\t`\n\t\t\t\t\t// %s\n\t\t\t\t\t%s, err := walk.New%sSpacer%s(%s%s)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\t`,\n\t\t\t\t\titemName, itemName, orientStr, fixedStr, qualifiedParent, secondParamStr))\n\t\t\t}\n\t\t}\n\n\t\tif item.Widget != nil && !item.Widget.ignored {\n\t\t\titemName = fmt.Sprintf(\"w.ui.%s\", item.Widget.Name)\n\t\t\tif err := writeWidgetInitialization(buf, item.Widget, parent, qualifiedParent); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif layout != \"\" && itemName != \"\" && item.Row != \"\" && item.Column != \"\" {\n\t\t\tif item.ColSpan == \"\" {\n\t\t\t\titem.ColSpan = \"1\"\n\t\t\t}\n\t\t\tif item.RowSpan == \"\" {\n\t\t\t\titem.RowSpan = \"1\"\n\t\t\t}\n\t\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t\t`\t\t\t\tif err := %s.SetRange(%s, walk.Rectangle{%s, %s, %s, %s}); err != nil {\n\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\tlayout, itemName, item.Column, item.Row, item.ColSpan, item.RowSpan))\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc writeLayoutInitialization(buf *bytes.Buffer, layout *Layout, parent *Widget, qualifiedParent string) error {\n\tvar typ string\n\tswitch layout.Class {\n\tcase \"QGridLayout\":\n\t\ttyp = \"GridLayout\"\n\n\tcase \"QHBoxLayout\":\n\t\ttyp = \"HBoxLayout\"\n\n\tcase \"QVBoxLayout\":\n\t\ttyp = \"VBoxLayout\"\n\n\tdefault:\n\t\treturn errors.New(fmt.Sprintf(\"unsupported layout type: '%s'\", layout.Class))\n\t}\n\n\tbuf.WriteString(fmt.Sprintf(\"%s := walk.New%s()\\n\",\n\t\tlayout.Name, typ))\n\n\tbuf.WriteString(fmt.Sprintf(\n\t\t`if err := %s.SetLayout(%s); err != nil {\n\t\treturn err\n\t\t}\n\t\t`,\n\t\tqualifiedParent, layout.Name))\n\n\tspacing := 6\n\tmargL, margT, margR, margB := 9, 9, 9, 9\n\n\tfor _, prop := range layout.Property {\n\t\tswitch prop.Name {\n\t\tcase \"spacing\":\n\t\t\tspacing = int(prop.Number)\n\n\t\tcase \"leftMargin\":\n\t\t\tmargL = int(prop.Number)\n\n\t\tcase \"topMargin\":\n\t\t\tmargT = int(prop.Number)\n\n\t\tcase \"rightMargin\":\n\t\t\tmargR = int(prop.Number)\n\n\t\tcase \"bottomMargin\":\n\t\t\tmargB = int(prop.Number)\n\n\t\tcase \"margin\":\n\t\t\tm := int(prop.Number)\n\t\t\tmargL, margT, margR, margB = m, m, m, m\n\t\t}\n\t}\n\n\tif margL != 0 || margT != 0 || margR != 0 || margB != 0 {\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t`if err := %s.SetMargins(walk.Margins{%d, %d, %d, %d}); err != nil {\n\t\t\treturn err\n\t\t\t}\n\t\t\t`,\n\t\t\tlayout.Name, margL, margT, margR, margB))\n\t}\n\n\tif spacing != 0 {\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t`if err := %s.SetSpacing(%d); err != nil {\n\t\t\treturn err\n\t\t\t}\n\t\t\t`,\n\t\t\tlayout.Name, spacing))\n\t}\n\n\tvar layoutName string\n\tif typ == \"GridLayout\" {\n\t\tlayoutName = layout.Name\n\t}\n\n\tif err := writeItemInitializations(buf, layout.Item, parent, qualifiedParent, layoutName); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc writeWidgetInitialization(buf *bytes.Buffer, widget *Widget, parent *Widget, qualifiedParent string) error {\n\treceiver := fmt.Sprintf(\"w.ui.%s\", widget.Name)\n\n\tvar typ string\n\tvar custom bool\n\tswitch widget.Class {\n\tcase \"QCheckBox\":\n\t\ttyp = \"CheckBox\"\n\n\tcase \"QComboBox\":\n\t\ttyp = \"ComboBox\"\n\n\tcase \"QDateEdit\":\n\t\ttyp = \"DateEdit\"\n\n\tcase \"QDoubleSpinBox\", \"QSpinBox\":\n\t\ttyp = \"NumberEdit\"\n\n\tcase \"QFrame\":\n\t\ttyp = \"Composite\"\n\n\tcase \"QGroupBox\":\n\t\ttyp = \"GroupBox\"\n\n\tcase \"QLabel\":\n\t\ttyp = \"Label\"\n\n\tcase \"QLineEdit\":\n\t\ttyp = \"LineEdit\"\n\n\tcase \"QPlainTextEdit\", \"QTextEdit\":\n\t\ttyp = \"TextEdit\"\n\n\tcase \"QProgressBar\":\n\t\ttyp = \"ProgressBar\"\n\n\tcase \"QPushButton\":\n\t\ttyp = \"PushButton\"\n\n\tcase \"QRadioButton\":\n\t\ttyp = \"RadioButton\"\n\n\tcase \"QSplitter\":\n\t\ttyp = \"Splitter\"\n\n\tcase \"QTabWidget\":\n\t\ttyp = \"TabWidget\"\n\n\tcase \"QTableView\", \"QTableWidget\":\n\t\ttyp = \"TableView\"\n\n\tcase \"QToolButton\":\n\t\ttyp = \"ToolButton\"\n\n\tcase \"QTreeView\", \"QTreeWidget\":\n\t\ttyp = \"TreeView\"\n\n\tcase \"QWebView\":\n\t\ttyp = \"WebView\"\n\n\tcase \"QWidget\":\n\t\tif parent != nil && parent.Class == \"QTabWidget\" {\n\t\t\ttyp = \"TabPage\"\n\t\t} else {\n\t\t\ttyp = \"Composite\"\n\t\t}\n\n\tdefault:\n\t\t// FIXME: We assume this is a custom widget in the same package.\n\t\t// We also require a func NewFoo(parent) (*Foo, error).\n\t\ttyp = widget.Class\n\t\tcustom = true\n\t}\n\n\tif custom {\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t`\n\t\t\t// %s\n\t\t\tif %s, err = New%s(%s); err != nil {\n\t\t\treturn err\n\t\t\t}\n\t\t\t`,\n\t\t\twidget.Name, receiver, typ, qualifiedParent))\n\t} else {\n\t\tif typ == \"TabPage\" {\n\t\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t\t`\n\t\t\t\t// %s\n\t\t\t\tif %s, err = walk.NewTabPage(); err != nil {\n\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\twidget.Name, receiver))\n\t\t} else {\n\t\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t\t`\n\t\t\t\t// %s\n\t\t\t\tif %s, err = walk.New%s(%s); err != nil {\n\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\twidget.Name, receiver, typ, qualifiedParent))\n\t\t}\n\t}\n\n\tbuf.WriteString(fmt.Sprintf(\"%s.SetName(\\\"%s\\\")\\n\",\n\t\treceiver, widget.Name))\n\n\tif err := writeAttributes(buf, widget.Attribute, receiver); err != nil {\n\t\treturn err\n\t}\n\n\tif err := writeProperties(buf, widget.Property, receiver, widget); err != nil {\n\t\treturn err\n\t}\n\n\tif widget.Layout != nil && !widget.Layout.ignored {\n\t\tif err := writeLayoutInitialization(buf, widget.Layout, widget, receiver); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif typ == \"TabPage\" {\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t`if err := %s.Pages().Add(%s); err != nil {\n\t\t\treturn err\n\t\t\t}\n\t\t\t`,\n\t\t\tqualifiedParent, receiver))\n\t}\n\n\treturn writeWidgetInitializations(buf, widget.Widget, widget, receiver)\n}\n\nfunc writeWidgetInitializations(buf *bytes.Buffer, widgets []*Widget, parent *Widget, qualifiedParent string) error {\n\tfor _, widget := range widgets {\n\t\tif widget.ignored || widget.Class == \"QMenuBar\" || widget.Class == \"QStatusBar\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := writeWidgetInitialization(buf, widget, parent, qualifiedParent); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc writeWidgetDecl(buf *bytes.Buffer, widget *Widget, parent *Widget) error {\n\tvar typ string\n\tswitch widget.Class {\n\tcase \"QCheckBox\":\n\t\ttyp = \"walk.CheckBox\"\n\n\tcase \"QComboBox\":\n\t\ttyp = \"walk.ComboBox\"\n\n\tcase \"QDateEdit\":\n\t\ttyp = \"walk.DateEdit\"\n\n\tcase \"QDoubleSpinBox\", \"QSpinBox\":\n\t\ttyp = \"walk.NumberEdit\"\n\n\tcase \"QFrame\":\n\t\ttyp = \"walk.Composite\"\n\n\tcase \"QGroupBox\":\n\t\ttyp = \"walk.GroupBox\"\n\n\tcase \"QLabel\":\n\t\ttyp = \"walk.Label\"\n\n\tcase \"QLineEdit\":\n\t\ttyp = \"walk.LineEdit\"\n\n\tcase \"QPlainTextEdit\", \"QTextEdit\":\n\t\ttyp = \"walk.TextEdit\"\n\n\tcase \"QProgressBar\":\n\t\ttyp = \"walk.ProgressBar\"\n\n\tcase \"QPushButton\":\n\t\ttyp = \"walk.PushButton\"\n\n\tcase \"QRadioButton\":\n\t\ttyp = \"walk.RadioButton\"\n\n\tcase \"QSplitter\":\n\t\ttyp = \"walk.Splitter\"\n\n\tcase \"QTabWidget\":\n\t\ttyp = \"walk.TabWidget\"\n\n\tcase \"QTableView\", \"QTableWidget\":\n\t\ttyp = \"walk.TableView\"\n\n\tcase \"QToolButton\":\n\t\ttyp = \"walk.ToolButton\"\n\n\tcase \"QTreeView\", \"QTreeWidget\":\n\t\ttyp = \"walk.TreeView\"\n\n\tcase \"QWebView\":\n\t\ttyp = \"walk.WebView\"\n\n\tcase \"QWidget\":\n\t\tif parent != nil && parent.Class == \"QTabWidget\" {\n\t\t\ttyp = \"walk.TabPage\"\n\t\t} else {\n\t\t\ttyp = \"walk.Composite\"\n\t\t}\n\n\tdefault:\n\t\t// FIXME: For now, we assume this is a custom widget in the same package\n\t\ttyp = widget.Class\n\t}\n\n\tbuf.WriteString(fmt.Sprintf(\"%s *%s\\n\", widget.Name, typ))\n\n\tif widget.Layout != nil {\n\t\treturn writeItemDecls(buf, widget.Layout.Item, widget)\n\t}\n\n\treturn writeWidgetDecls(buf, widget.Widget, widget)\n}\n\nfunc writeWidgetDecls(buf *bytes.Buffer, widgets []*Widget, parent *Widget) error {\n\tfor _, widget := range widgets {\n\t\tswitch widget.Class {\n\t\tcase \"QMenuBar\", \"QStatusBar\":\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := writeWidgetDecl(buf, widget, parent); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc writeItemDecls(buf *bytes.Buffer, items []*Item, parent *Widget) error {\n\tfor _, item := range items {\n\t\tif item.Widget == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := writeWidgetDecl(buf, item.Widget, parent); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc writeActionDecl(buf *bytes.Buffer, action *Action) error {\n\tbuf.WriteString(action.Name)\n\tbuf.WriteString(\" *walk.Action\\n\")\n\treturn nil\n}\n\nfunc writeActionDecls(buf *bytes.Buffer, actions []*Action) error {\n\tfor _, action := range actions {\n\t\tif err := writeActionDecl(buf, action); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc writeMenuInitialization(buf *bytes.Buffer, menu *Widget, realActions map[string]bool) error {\n\tvar qualifiedParentMenu string\n\n\tif menu.Class == \"QMenuBar\" {\n\t\tbuf.WriteString(\"// Menus\\n\\n\")\n\n\t\tqualifiedParentMenu = \"w.Menu()\"\n\t} else {\n\t\tqualifiedParentMenu = menu.Name\n\t}\n\n\tfor _, addAction := range menu.AddAction {\n\t\tif realActions[addAction.Name] {\n\t\t\tbuf.WriteString(\"if err := \")\n\t\t\tbuf.WriteString(qualifiedParentMenu)\n\t\t\tbuf.WriteString(\".Actions().Add(w.ui.actions.\")\n\t\t\tbuf.WriteString(addAction.Name)\n\t\t\tbuf.WriteString(`); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t\n\t\t\t`)\n\t\t} else {\n\t\t\tfor _, submenu := range menu.Widget {\n\t\t\t\tif submenu.Name != addAction.Name {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tbuf.WriteString(\"// \")\n\t\t\t\tbuf.WriteString(submenu.Name)\n\t\t\t\tbuf.WriteString(\"\\n\")\n\n\t\t\t\tbuf.WriteString(submenu.Name)\n\t\t\t\tbuf.WriteString(`, err := walk.NewMenu()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\t`)\n\t\t\t\tsubmenuActionName := submenu.Name + \"Action\"\n\n\t\t\t\tbuf.WriteString(submenuActionName)\n\t\t\t\tbuf.WriteString(\", err := \")\n\t\t\t\tbuf.WriteString(qualifiedParentMenu)\n\t\t\t\tbuf.WriteString(\".Actions().AddMenu(\")\n\t\t\t\tbuf.WriteString(submenu.Name)\n\t\t\t\tbuf.WriteString(`)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\t`)\n\n\t\t\t\tfor _, prop := range submenu.Property {\n\t\t\t\t\tif prop.Name == \"title\" {\n\t\t\t\t\t\tbuf.WriteString(\"if err := \")\n\t\t\t\t\t\tbuf.WriteString(submenuActionName)\n\t\t\t\t\t\tbuf.WriteString(\".SetText(\")\n\t\t\t\t\t\tbuf.WriteString(trString(&prop.String))\n\t\t\t\t\t\tbuf.WriteString(`); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t`)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif err := writeMenuInitialization(buf, submenu, realActions); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc writeActionInitializations(buf *bytes.Buffer, actions []*Action) error {\n\tbuf.WriteString(\"\\n// Actions\\n\\n\")\n\n\tfor _, action := range actions {\n\t\tqualifiedReceiver := \"w.ui.actions.\" + action.Name\n\n\t\tbuf.WriteString(\"// \")\n\t\tbuf.WriteString(qualifiedReceiver)\n\t\tbuf.WriteString(\"\\n\")\n\n\t\tbuf.WriteString(qualifiedReceiver)\n\t\tbuf.WriteString(\" = walk.NewAction()\\n\")\n\n\t\tif err := writeProperties(buf, action.Property, qualifiedReceiver, nil); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbuf.WriteString(\"\\n\")\n\t}\n\n\treturn nil\n}\n\nfunc generateUICode(buf *bytes.Buffer, ui *UI) error {\n\t// Comment, package decl, imports\n\tbuf.WriteString(\n\t\t`// This file was created by ui2walk and may be regenerated.\n\t\t// DO NOT EDIT OR YOUR MODIFICATIONS WILL BE LOST!\n\n\t\tpackage main\n\t\t\n\t\timport (\n\t\t\t\"github.com/lxn/walk\"\n\t\t)\n\t\t\n\t\t`)\n\n\t// Embed the corresponding Walk type.\n\tvar embeddedType string\n\tswitch ui.Widget.Class {\n\tcase \"QMainWindow\":\n\t\tembeddedType = \"MainWindow\"\n\n\tcase \"QDialog\":\n\t\tembeddedType = \"Dialog\"\n\n\tcase \"QWidget\":\n\t\tembeddedType = \"Composite\"\n\n\tdefault:\n\t\treturn errors.New(fmt.Sprintf(\"Top level '%s' currently not supported.\", ui.Widget.Class))\n\t}\n\n\tgenTypeBaseName := strings.ToLower(ui.Class[:1]) + ui.Class[1:]\n\n\tif len(ui.Widget.Action) > 0 {\n\t\t// This struct will contain actions.\n\t\tbuf.WriteString(fmt.Sprintf(\"type %sActions struct {\\n\", genTypeBaseName))\n\n\t\twriteActionDecls(buf, ui.Widget.Action)\n\n\t\tbuf.WriteString(\"}\\n\\n\")\n\t}\n\n\t// Struct containing all descendant widgets.\n\tbuf.WriteString(fmt.Sprintf(\"type %sUI struct {\\n\", genTypeBaseName))\n\n\tif len(ui.Widget.Action) > 0 {\n\t\tbuf.WriteString(fmt.Sprintf(\"actions %sActions\\n\", genTypeBaseName))\n\t}\n\n\t// Descendant widget decls\n\tif ui.Widget.Widget != nil {\n\t\tif err := writeWidgetDecls(buf, ui.Widget.Widget, &ui.Widget); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif ui.Widget.Layout != nil {\n\t\tif err := writeItemDecls(buf, ui.Widget.Layout.Item, &ui.Widget); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// end struct\n\tbuf.WriteString(\"}\\n\\n\")\n\n\t// init func\n\tswitch embeddedType {\n\tcase \"MainWindow\":\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t`func (w *%s) init() (err error) {\n\t\t\tif w.MainWindow, err = walk.NewMainWindow()`,\n\t\t\tui.Widget.Name))\n\n\tcase \"Dialog\":\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t`func (w *%s) init(owner walk.Form) (err error) {\n\t\t\tif w.Dialog, err = walk.NewDialog(owner)`,\n\t\t\tui.Widget.Name))\n\n\tcase \"Composite\":\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t`func (w *%s) init(parent walk.Container) (err error) {\n\t\t\tif w.Composite, err = walk.NewComposite(parent)`,\n\t\t\tui.Widget.Name))\n\t}\n\n\tbuf.WriteString(fmt.Sprintf(`; err != nil {\n\t\t\treturn err\n\t\t\t}\n\t\t\t\n\t\t\tsucceeded := false\n\t\t\tdefer func(){\n\t\t\t\tif !succeeded {\n\t\t\t\t\tw.Dispose()\n\t\t\t\t}\n\t\t\t}()\n\t\t\t\n\t\t\tvar font *walk.Font\n\t\t\tif font == nil {\n\t\t\t\tfont = nil\n\t\t\t}\n\t\t\t\n\t\t\tw.SetName(\"%s\")\n\t\t\t`,\n\t\tui.Widget.Name))\n\n\tif embeddedType == \"MainWindow\" {\n\t\tbuf.WriteString(fmt.Sprintf(\n\t\t\t`l := walk.NewVBoxLayout()\n\t\t\tif err := l.SetMargins(walk.Margins{0, 0, 0, 0}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := w.SetLayout(l); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t`))\n\t}\n\n\tif err := writeProperties(buf, ui.Widget.Property, \"w\", &ui.Widget); err != nil {\n\t\treturn err\n\t}\n\n\t// Let's see if we find a QMenuBar widget.\n\tvar menuBar *Widget\n\tfor _, widget := range ui.Widget.Widget {\n\t\tif widget.Class == \"QMenuBar\" {\n\t\t\tmenuBar = widget\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif len(ui.Widget.Action) > 0 {\n\t\twriteActionInitializations(buf, ui.Widget.Action)\n\n\t\tif menuBar != nil {\n\t\t\trealActions := make(map[string]bool)\n\n\t\t\tfor _, action := range ui.Widget.Action {\n\t\t\t\trealActions[action.Name] = true\n\t\t\t}\n\n\t\t\twriteMenuInitialization(buf, menuBar, realActions)\n\t\t}\n\t}\n\n\tif ui.Widget.Widget != nil {\n\t\tif err := writeWidgetInitializations(buf, ui.Widget.Widget, &ui.Widget, \"w\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif ui.Widget.Layout != nil {\n\t\tif err := writeLayoutInitialization(buf, ui.Widget.Layout, &ui.Widget, \"w\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tbuf.WriteString(\"\\n// Tab order\\n\")\n\tfor i := len(ui.TabStops) - 1; i >= 0; i-- {\n\t\tbuf.WriteString(fmt.Sprintf(`if err = w.ui.%s.BringToTop(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t`,\n\t\t\tui.TabStops[i]))\n\t}\n\n\t// end func\n\tbuf.WriteString(`\n\t\tsucceeded = true\n\t\t\n\t\treturn nil\n\t\t}`)\n\n\treturn nil\n}\n\nfunc generateLogicCode(buf *bytes.Buffer, ui *UI) error {\n\t// Comment, package decl, imports\n\tbuf.WriteString(\n\t\t`package main\n\t\t\n\t\timport (\n\t\t\t\"github.com/lxn/walk\"\n\t\t)\n\t\t\n\t\t`)\n\n\t// Embed the corresponding Walk type.\n\tvar embeddedType string\n\tswitch ui.Widget.Class {\n\tcase \"QMainWindow\":\n\t\tembeddedType = \"MainWindow\"\n\n\tcase \"QDialog\":\n\t\tembeddedType = \"Dialog\"\n\n\tcase \"QWidget\":\n\t\tembeddedType = \"Composite\"\n\n\tdefault:\n\t\treturn errors.New(fmt.Sprintf(\"Top level '%s' currently not supported.\", ui.Widget.Class))\n\t}\n\n\tbuf.WriteString(\"type \")\n\tbuf.WriteString(ui.Widget.Name)\n\tbuf.WriteString(\" struct {\\n*walk.\")\n\tbuf.WriteString(embeddedType)\n\tbuf.WriteString(\"\\nui \")\n\tbuf.WriteString(strings.ToLower(ui.Class[:1]) + ui.Class[1:])\n\tbuf.WriteString(`UI\n\t}\n\t\n\t`)\n\n\tswitch embeddedType {\n\tcase \"MainWindow\":\n\t\tbuf.WriteString(\"func run\")\n\t\tbuf.WriteString(ui.Widget.Name)\n\t\tbuf.WriteString(`() (int, error) {\n\t\tmw := new(`)\n\t\tbuf.WriteString(ui.Widget.Name)\n\t\tbuf.WriteString(`)\n\t\tif err := mw.init(); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tdefer mw.Dispose()\n\t\t\n\t\t// TODO: Do further required setup, e.g. for event handling, here.\n\t\t\n\t\tmw.Show()\n\t\t\n\t\treturn mw.Run(), nil\n\t\t}\n\t\t`)\n\n\tcase \"Dialog\":\n\t\tbuf.WriteString(\"func run\")\n\t\tbuf.WriteString(ui.Widget.Name)\n\t\tbuf.WriteString(`(owner walk.Form) (int, error) {\n\t\tdlg := new(`)\n\t\tbuf.WriteString(ui.Widget.Name)\n\t\tbuf.WriteString(`)\n\t\tif err := dlg.init(owner); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\t\n\t\t`)\n\n\t\tif b := findWidget(&ui.Widget, \"QPushButton\", []string{\"accept\", \"ok\"}); b != nil {\n\t\t\tbuf.WriteString(\"if err := dlg.SetDefaultButton(dlg.ui.\")\n\t\t\tbuf.WriteString(b.Name)\n\t\t\tbuf.WriteString(`); err != nil {\n\t\t\treturn 0, err\n\t\t\t}\n\t\t\t\n\t\t\tdlg.ui.`)\n\t\t\tbuf.WriteString(b.Name)\n\t\t\tbuf.WriteString(`.Clicked().Attach(func(){\n\t\t\tdlg.Accept()\n\t\t\t})\n\t\t\t\n\t\t\t`)\n\t\t}\n\n\t\tif b := findWidget(&ui.Widget, \"QPushButton\", []string{\"cancel\"}); b != nil {\n\t\t\tbuf.WriteString(\"if err := dlg.SetCancelButton(dlg.ui.\")\n\t\t\tbuf.WriteString(b.Name)\n\t\t\tbuf.WriteString(`); err != nil {\n\t\t\treturn 0, err\n\t\t\t}\n\t\t\t\n\t\t\tdlg.ui.`)\n\t\t\tbuf.WriteString(b.Name)\n\t\t\tbuf.WriteString(`.Clicked().Attach(func(){\n\t\t\tdlg.Cancel()\n\t\t\t})\n\t\t\t\n\t\t\t`)\n\t\t}\n\n\t\tbuf.WriteString(`// TODO: Do further required setup, e.g. for event handling, here.\n\t\t\n\t\treturn dlg.Run(), nil\n\t\t}\n\t\t`)\n\n\tcase \"Composite\":\n\t\tbuf.WriteString(\"func new\")\n\t\tbuf.WriteString(ui.Widget.Name)\n\t\tbuf.WriteString(\"(parent walk.Container) (*\")\n\t\tbuf.WriteString(ui.Widget.Name)\n\t\tbuf.WriteString(`, error) {\n\t\tc := new(`)\n\t\tbuf.WriteString(ui.Widget.Name)\n\t\tbuf.WriteString(`)\n\t\tif err := c.init(parent); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t\n\t\t// TODO: Do further required setup, e.g. for event handling, here.\n\t\t\n\t\treturn c, nil\n\t\t}\n\t\t`)\n\t}\n\n\treturn nil\n}\n\nfunc findWidget(parent *Widget, class string, nameSubstrs []string) *Widget {\n\tfind := func(widget *Widget) *Widget {\n\t\tif widget.Class == class {\n\t\t\tfor _, substr := range nameSubstrs {\n\t\t\t\tif strings.Contains(widget.Name, substr) {\n\t\t\t\t\treturn widget\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif w := findWidget(widget, class, nameSubstrs); w != nil {\n\t\t\treturn w\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tfor _, widget := range parent.Widget {\n\t\tif w := find(widget); w != nil {\n\t\t\treturn w\n\t\t}\n\t}\n\n\tif parent.Layout != nil {\n\t\tfor _, item := range parent.Layout.Item {\n\t\t\tif item.Widget != nil {\n\t\t\t\tif w := find(item.Widget); w != nil {\n\t\t\t\t\treturn w\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc processFile(uiFilePath string) error {\n\tgoLogicFilePath := uiFilePath[:len(uiFilePath)-3] + \".go\"\n\tgoUIFilePath := uiFilePath[:len(uiFilePath)-3] + \"_ui.go\"\n\n\tuiFileInfo, err := os.Stat(uiFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tgoUIFileInfo, err := os.Stat(goUIFilePath)\n\tif !*forceUpdate && err == nil && !uiFileInfo.ModTime().After(goUIFileInfo.ModTime()) {\n\t\t// The go file should be up-to-date\n\t\treturn nil\n\t}\n\n\tfmt.Printf(\"Processing '%s'\\n\", uiFilePath)\n\tdefer fmt.Println(\"\")\n\n\tuiFile, err := os.Open(uiFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer uiFile.Close()\n\n\treader := bufio.NewReader(uiFile)\n\n\tui, err := parseUI(reader)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tgoLogicFile, err := os.OpenFile(goLogicFilePath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0666)\n\tif err == nil {\n\t\tdefer goLogicFile.Close()\n\n\t\tbuf := new(bytes.Buffer)\n\n\t\tif err := generateLogicCode(buf, ui); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif _, err := io.Copy(goLogicFile, buf); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := goLogicFile.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tgoUIFile, err := os.Create(goUIFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer goUIFile.Close()\n\n\tbuf := new(bytes.Buffer)\n\n\tif err := generateUICode(buf, ui); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := io.Copy(goUIFile, buf); err != nil {\n\t\treturn err\n\t}\n\tif err := goUIFile.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tdirPath := os.Getenv(\"GOBIN\")\n\tif dirPath == \"\" {\n\t\tdirPath = filepath.Join(runtime.GOROOT(), \"bin\")\n\t}\n\n\tgofmtPath := filepath.Join(dirPath, \"gofmt.exe\")\n\n\targs := []string{gofmtPath, \"-w\", goUIFilePath}\n\tif goLogicFile != nil {\n\t\targs = append(args, goLogicFilePath)\n\t}\n\n\tgofmt, err := os.StartProcess(gofmtPath, args, &os.ProcAttr{Files: []*os.File{nil, nil, os.Stderr}})\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer gofmt.Release()\n\n\treturn nil\n}\n\nfunc processDirectory(dirPath string) error {\n\tdir, err := os.Open(dirPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer dir.Close()\n\n\tnames, err := dir.Readdirnames(-1)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, name := range names {\n\t\tfullPath := path.Join(dirPath, name)\n\n\t\tfi, err := os.Stat(fullPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif fi.IsDir() {\n\t\t\tif err := processDirectory(fullPath); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if !fi.IsDir() && strings.HasSuffix(name, \".ui\") {\n\t\t\tif err := processFile(fullPath); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc main() {\n\tflag.Parse()\n\n\tcwd, err := os.Getwd()\n\tlogFatal(err)\n\n\tlogFatal(processDirectory(cwd))\n}\n"
  },
  {
    "path": "tooltip.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\n// https://msdn.microsoft.com/en-us/library/windows/desktop/bb760416(v=vs.85).aspx says 80,\n// but in reality, that hasn't been enforced for many many Windows versions. So we give it\n// 1024 instead.\nconst maxToolTipTextLen = 1024 // including NUL terminator\n\ntype ToolTip struct {\n\tWindowBase\n}\n\nfunc NewToolTip() (*ToolTip, error) {\n\ttt, err := newToolTip(0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\twin.SetWindowPos(tt.hWnd, win.HWND_TOPMOST, 0, 0, 0, 0, win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_NOACTIVATE)\n\n\treturn tt, nil\n}\n\nfunc newToolTip(style uint32) (*ToolTip, error) {\n\ttt := new(ToolTip)\n\n\tif err := InitWindow(\n\t\ttt,\n\t\tnil,\n\t\t\"tooltips_class32\",\n\t\twin.WS_DISABLED|win.WS_POPUP|win.TTS_ALWAYSTIP|win.TTS_NOPREFIX|style,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\ttt.Dispose()\n\t\t}\n\t}()\n\n\ttt.SendMessage(win.TTM_SETMAXTIPWIDTH, 0, 300)\n\n\tsucceeded = true\n\n\treturn tt, nil\n}\n\nfunc (tt *ToolTip) Title() string {\n\tvar gt win.TTGETTITLE\n\n\tbuf := make([]uint16, 100)\n\n\tgt.DwSize = uint32(unsafe.Sizeof(gt))\n\tgt.Cch = uint32(len(buf))\n\tgt.PszTitle = &buf[0]\n\n\ttt.SendMessage(win.TTM_GETTITLE, 0, uintptr(unsafe.Pointer(&gt)))\n\n\treturn syscall.UTF16ToString(buf)\n}\n\nfunc (tt *ToolTip) SetTitle(title string) error {\n\treturn tt.setTitle(title, win.TTI_NONE)\n}\n\nfunc (tt *ToolTip) SetInfoTitle(title string) error {\n\treturn tt.setTitle(title, win.TTI_INFO)\n}\n\nfunc (tt *ToolTip) SetWarningTitle(title string) error {\n\treturn tt.setTitle(title, win.TTI_WARNING)\n}\n\nfunc (tt *ToolTip) SetErrorTitle(title string) error {\n\treturn tt.setTitle(title, win.TTI_ERROR)\n}\n\nfunc (tt *ToolTip) setTitle(title string, icon uintptr) error {\n\tif len(title) > 99 {\n\t\ttitle = title[:99]\n\t}\n\n\tif win.FALSE == tt.SendMessage(win.TTM_SETTITLE, icon, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title)))) {\n\t\treturn newError(\"TTM_SETTITLE failed\")\n\t}\n\n\treturn nil\n}\n\nfunc (tt *ToolTip) track(tool Widget) error {\n\tform := tool.Form()\n\tif form == nil {\n\t\treturn nil\n\t}\n\t// HACK: We may have to delay this until the form is fully up to avoid glitches.\n\tif !form.AsFormBase().started {\n\t\tform.Starting().Once(func() {\n\t\t\ttt.track(tool)\n\t\t})\n\t\treturn nil\n\t}\n\n\tti := tt.toolInfo(tool.Handle())\n\tif ti == nil {\n\t\treturn newError(\"unknown tool\")\n\t}\n\n\ttt.SendMessage(win.TTM_TRACKACTIVATE, 1, uintptr(unsafe.Pointer(ti)))\n\n\tb := tool.BoundsPixels()\n\n\tp := Point{0, b.Y + b.Height}.toPOINT()\n\tif form.RightToLeftLayout() {\n\t\tp.X = int32(b.X - b.Width/2)\n\t} else {\n\t\tp.X = int32(b.X + b.Width/2)\n\t}\n\n\twin.ClientToScreen(tool.Parent().Handle(), &p)\n\n\ttt.SendMessage(win.TTM_TRACKPOSITION, 0, uintptr(win.MAKELONG(uint16(p.X), uint16(p.Y))))\n\n\tvar insertAfterHWND win.HWND\n\tif form := tool.Form(); form != nil && win.GetForegroundWindow() == form.Handle() {\n\t\tinsertAfterHWND = win.HWND_TOP\n\t} else {\n\t\tinsertAfterHWND = tool.Handle()\n\t}\n\twin.SetWindowPos(tt.hWnd, insertAfterHWND, 0, 0, 0, 0, win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_NOACTIVATE)\n\n\treturn nil\n}\n\nfunc (tt *ToolTip) untrack(tool Widget) error {\n\tti := tt.toolInfo(tool.Handle())\n\tif ti == nil {\n\t\treturn newError(\"unknown tool\")\n\t}\n\n\ttt.SendMessage(win.TTM_TRACKACTIVATE, 0, uintptr(unsafe.Pointer(ti)))\n\n\treturn nil\n}\n\nfunc (tt *ToolTip) AddTool(tool Widget) error {\n\treturn tt.addTool(tt.hwndForTool(tool), false)\n}\n\nfunc (tt *ToolTip) addTrackedTool(tool Widget) error {\n\treturn tt.addTool(tt.hwndForTool(tool), true)\n}\n\nfunc (tt *ToolTip) addTool(hwnd win.HWND, track bool) error {\n\tif hwnd == 0 {\n\t\treturn nil\n\t}\n\n\tvar ti win.TOOLINFO\n\tti.CbSize = uint32(unsafe.Sizeof(ti))\n\tti.Hwnd = hwnd\n\tti.UFlags = win.TTF_IDISHWND\n\tif track {\n\t\tti.UFlags |= win.TTF_TRACK\n\t} else {\n\t\tti.UFlags |= win.TTF_SUBCLASS\n\t}\n\tti.UId = uintptr(hwnd)\n\n\tif win.FALSE == tt.SendMessage(win.TTM_ADDTOOL, 0, uintptr(unsafe.Pointer(&ti))) {\n\t\treturn newError(\"TTM_ADDTOOL failed\")\n\t}\n\n\treturn nil\n}\n\nfunc (tt *ToolTip) RemoveTool(tool Widget) error {\n\treturn tt.removeTool(tt.hwndForTool(tool))\n}\n\nfunc (tt *ToolTip) removeTool(hwnd win.HWND) error {\n\tvar ti win.TOOLINFO\n\tti.CbSize = uint32(unsafe.Sizeof(ti))\n\tti.Hwnd = hwnd\n\tti.UId = uintptr(hwnd)\n\n\ttt.SendMessage(win.TTM_DELTOOL, 0, uintptr(unsafe.Pointer(&ti)))\n\n\treturn nil\n}\n\nfunc (tt *ToolTip) Text(tool Widget) string {\n\treturn tt.text(tt.hwndForTool(tool))\n}\n\nfunc (tt *ToolTip) text(hwnd win.HWND) string {\n\tti := tt.toolInfo(hwnd)\n\tif ti == nil {\n\t\treturn \"\"\n\t}\n\n\treturn win.UTF16PtrToString(ti.LpszText)\n}\n\nfunc (tt *ToolTip) SetText(tool Widget, text string) error {\n\treturn tt.setText(tt.hwndForTool(tool), text)\n}\n\nfunc (tt *ToolTip) setText(hwnd win.HWND, text string) error {\n\tti := tt.toolInfo(hwnd)\n\tif ti == nil {\n\t\treturn newError(\"unknown tool\")\n\t}\n\n\tn := 0\n\tfor i, r := range text {\n\t\tif r < 0x10000 {\n\t\t\tn++\n\t\t} else {\n\t\t\tn += 2 // surrogate pair\n\t\t}\n\t\tif n >= maxToolTipTextLen {\n\t\t\ttext = text[:i]\n\t\t\tbreak\n\t\t}\n\t}\n\n\tti.LpszText = syscall.StringToUTF16Ptr(text)\n\n\ttt.SendMessage(win.TTM_SETTOOLINFO, 0, uintptr(unsafe.Pointer(ti)))\n\n\treturn nil\n}\n\nfunc (tt *ToolTip) toolInfo(hwnd win.HWND) *win.TOOLINFO {\n\tvar ti win.TOOLINFO\n\tvar buf [maxToolTipTextLen]uint16\n\n\tti.CbSize = uint32(unsafe.Sizeof(ti))\n\tti.Hwnd = hwnd\n\tti.UId = uintptr(hwnd)\n\tti.LpszText = &buf[0]\n\n\tif win.FALSE == tt.SendMessage(win.TTM_GETTOOLINFO, 0, uintptr(unsafe.Pointer(&ti))) {\n\t\treturn nil\n\t}\n\n\treturn &ti\n}\n\nfunc (*ToolTip) hwndForTool(tool Widget) win.HWND {\n\tif hftt, ok := tool.(interface{ handleForToolTip() win.HWND }); ok {\n\t\treturn hftt.handleForToolTip()\n\t}\n\n\treturn tool.Handle()\n}\n"
  },
  {
    "path": "tooltiperrorpresenter.go",
    "content": "// Copyright 2017 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\nvar ValidationErrorEffect WidgetGraphicsEffect\n\ntype ToolTipErrorPresenter struct {\n\ttoolTip                     *ToolTip\n\tcurWidget                   Widget\n\twidget2error                map[Widget]error\n\ttrackedBoundsChangedHandles map[Window]int\n\tform                        Form\n\tformActivatingHandle        int\n\tformDeactivatingHandle      int\n}\n\nfunc NewToolTipErrorPresenter() (*ToolTipErrorPresenter, error) {\n\ttt, err := newToolTip(win.TTS_BALLOON)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\ttt.Dispose()\n\t\t}\n\t}()\n\n\tsucceeded = true\n\n\treturn &ToolTipErrorPresenter{\n\t\ttoolTip:                     tt,\n\t\twidget2error:                make(map[Widget]error),\n\t\ttrackedBoundsChangedHandles: make(map[Window]int),\n\t\tformActivatingHandle:        -1,\n\t\tformDeactivatingHandle:      -1,\n\t}, nil\n}\n\nfunc (ttep *ToolTipErrorPresenter) Dispose() {\n\tif ttep.toolTip != nil {\n\t\tttep.untrack()\n\t\tttep.toolTip.Dispose()\n\t\tttep.toolTip = nil\n\t\tif ttep.form != nil {\n\t\t\tttep.form.AsFormBase().activatingPublisher.event.Detach(ttep.formActivatingHandle)\n\t\t\tttep.form.AsFormBase().deactivatingPublisher.event.Detach(ttep.formDeactivatingHandle)\n\t\t\tttep.form = nil\n\t\t}\n\t}\n}\n\nfunc (ttep *ToolTipErrorPresenter) PresentError(err error, widget Widget) {\n\tif ttep.toolTip == nil {\n\t\treturn\n\t}\n\n\tif err == nil && widget == ttep.curWidget {\n\t\tttep.untrack()\n\t}\n\n\tif err == nil {\n\t\tttep.toolTip.RemoveTool(widget)\n\t\tdelete(ttep.widget2error, widget)\n\t} else {\n\t\tttep.toolTip.addTrackedTool(widget)\n\t\tttep.widget2error[widget] = err\n\t}\n\n\tvar found bool\n\tif widget != nil {\n\t\twalkDescendants(widget.Form().AsFormBase().clientComposite, func(w Window) bool {\n\t\t\twt := w.(Widget)\n\n\t\t\tif !found {\n\t\t\t\tif e, ok := ttep.widget2error[wt]; ok {\n\t\t\t\t\terr, widget, found = e, wt, true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !found && wt == ttep.curWidget || wt != widget || err == nil {\n\t\t\t\twt.GraphicsEffects().Remove(ValidationErrorEffect)\n\t\t\t}\n\n\t\t\treturn true\n\t\t})\n\t}\n\n\tif found {\n\t\tif widget != ttep.curWidget {\n\t\t\tttep.untrack()\n\t\t}\n\n\t\tif ve, ok := err.(*ValidationError); ok {\n\t\t\tttep.toolTip.SetErrorTitle(ve.title)\n\t\t\tttep.toolTip.SetText(widget, ve.message)\n\t\t} else {\n\t\t\tttep.toolTip.SetErrorTitle(tr(\"Invalid Input\"))\n\t\t\tttep.toolTip.SetText(widget, err.Error())\n\t\t}\n\n\t\tif widget != ttep.curWidget {\n\t\t\tttep.track(widget)\n\n\t\t\tif effects := widget.GraphicsEffects(); !effects.Contains(ValidationErrorEffect) {\n\t\t\t\teffects.Add(ValidationErrorEffect)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (ttep *ToolTipErrorPresenter) track(widget Widget) {\n\tvar wnd Window\n\n\twnd = widget\n\n\tfor wnd != nil {\n\t\thandle := wnd.AsWindowBase().boundsChangedPublisher.event.Attach(func() {\n\t\t\tttep.toolTip.track(widget)\n\t\t})\n\n\t\tttep.trackedBoundsChangedHandles[wnd] = handle\n\n\t\tif ttep.form == nil {\n\t\t\tttep.form = widget.Form()\n\t\t\tttep.formActivatingHandle = ttep.form.AsFormBase().activatingPublisher.event.Attach(func() {\n\t\t\t\tttep.toolTip.track(widget)\n\t\t\t})\n\t\t\tttep.formDeactivatingHandle = ttep.form.AsFormBase().deactivatingPublisher.event.Attach(func() {\n\t\t\t\tttep.toolTip.track(widget)\n\t\t\t})\n\t\t}\n\n\t\tif w, ok := wnd.(Widget); ok {\n\t\t\tif parent := w.Parent(); parent != nil {\n\t\t\t\twnd = parent\n\t\t\t}\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tttep.toolTip.track(widget)\n\n\tttep.curWidget = widget\n}\n\nfunc (ttep *ToolTipErrorPresenter) untrack() {\n\tif ttep.curWidget == nil {\n\t\treturn\n\t}\n\n\tttep.toolTip.untrack(ttep.curWidget)\n\n\tfor wnd, handle := range ttep.trackedBoundsChangedHandles {\n\t\twnd.AsWindowBase().boundsChangedPublisher.event.Detach(handle)\n\t\tdelete(ttep.trackedBoundsChangedHandles, wnd)\n\t}\n\n\tttep.curWidget = nil\n}\n"
  },
  {
    "path": "treeitemevent.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\ntype treeItemEventHandlerInfo struct {\n\thandler TreeItemEventHandler\n\tonce    bool\n}\n\ntype TreeItemEventHandler func(item TreeItem)\n\ntype TreeItemEvent struct {\n\thandlers []treeItemEventHandlerInfo\n}\n\nfunc (e *TreeItemEvent) Attach(handler TreeItemEventHandler) int {\n\thandlerInfo := treeItemEventHandlerInfo{handler, false}\n\n\tfor i, h := range e.handlers {\n\t\tif h.handler == nil {\n\t\t\te.handlers[i] = handlerInfo\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handlerInfo)\n\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *TreeItemEvent) Detach(handle int) {\n\te.handlers[handle].handler = nil\n}\n\nfunc (e *TreeItemEvent) Once(handler TreeItemEventHandler) {\n\ti := e.Attach(handler)\n\te.handlers[i].once = true\n}\n\ntype TreeItemEventPublisher struct {\n\tevent TreeItemEvent\n}\n\nfunc (p *TreeItemEventPublisher) Event() *TreeItemEvent {\n\treturn &p.event\n}\n\nfunc (p *TreeItemEventPublisher) Publish(item TreeItem) {\n\tfor i, h := range p.event.handlers {\n\t\tif h.handler != nil {\n\t\t\th.handler(item)\n\n\t\t\tif h.once {\n\t\t\t\tp.event.Detach(i)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "treeview.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\ntype treeViewItemInfo struct {\n\thandle       win.HTREEITEM\n\tchild2Handle map[TreeItem]win.HTREEITEM\n}\n\ntype TreeView struct {\n\tWidgetBase\n\tmodel                          TreeModel\n\tlazyPopulation                 bool\n\titemsResetEventHandlerHandle   int\n\titemChangedEventHandlerHandle  int\n\titemInsertedEventHandlerHandle int\n\titemRemovedEventHandlerHandle  int\n\titem2Info                      map[TreeItem]*treeViewItemInfo\n\thandle2Item                    map[win.HTREEITEM]TreeItem\n\tcurrItem                       TreeItem\n\thIml                           win.HIMAGELIST\n\tusingSysIml                    bool\n\timageUintptr2Index             map[uintptr]int32\n\tfilePath2IconIndex             map[string]int32\n\texpandedChangedPublisher       TreeItemEventPublisher\n\tcurrentItemChangedPublisher    EventPublisher\n\titemActivatedPublisher         EventPublisher\n}\n\nfunc NewTreeView(parent Container) (*TreeView, error) {\n\ttv := new(TreeView)\n\n\tif err := InitWidget(\n\t\ttv,\n\t\tparent,\n\t\t\"SysTreeView32\",\n\t\twin.WS_TABSTOP|win.WS_VISIBLE|win.TVS_HASBUTTONS|win.TVS_LINESATROOT|win.TVS_SHOWSELALWAYS|win.TVS_TRACKSELECT,\n\t\twin.WS_EX_CLIENTEDGE); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\ttv.Dispose()\n\t\t}\n\t}()\n\n\tif hr := win.HRESULT(tv.SendMessage(win.TVM_SETEXTENDEDSTYLE, win.TVS_EX_DOUBLEBUFFER, win.TVS_EX_DOUBLEBUFFER)); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"TVM_SETEXTENDEDSTYLE\", hr)\n\t}\n\n\tif err := tv.setTheme(\"Explorer\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\ttv.GraphicsEffects().Add(InteractionEffect)\n\ttv.GraphicsEffects().Add(FocusEffect)\n\n\ttv.MustRegisterProperty(\"CurrentItem\", NewReadOnlyProperty(\n\t\tfunc() interface{} {\n\t\t\treturn tv.CurrentItem()\n\t\t},\n\t\ttv.CurrentItemChanged()))\n\n\ttv.MustRegisterProperty(\"CurrentItemLevel\", NewReadOnlyProperty(\n\t\tfunc() interface{} {\n\t\t\tlevel := -1\n\t\t\titem := tv.CurrentItem()\n\n\t\t\tfor item != nil {\n\t\t\t\tlevel++\n\t\t\t\titem = item.Parent()\n\t\t\t}\n\n\t\t\treturn level\n\t\t},\n\t\ttv.CurrentItemChanged()))\n\n\ttv.MustRegisterProperty(\"HasCurrentItem\", NewReadOnlyBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn tv.CurrentItem() != nil\n\t\t},\n\t\ttv.CurrentItemChanged()))\n\n\tsucceeded = true\n\n\treturn tv, nil\n}\n\nfunc (tv *TreeView) Dispose() {\n\ttv.WidgetBase.Dispose()\n\n\ttv.disposeImageListAndCaches()\n}\n\nfunc (tv *TreeView) SetBackground(bg Brush) {\n\ttv.WidgetBase.SetBackground(bg)\n\n\tcolor := Color(win.GetSysColor(win.COLOR_WINDOW))\n\n\tif bg != nil {\n\t\ttype Colorer interface {\n\t\t\tColor() Color\n\t\t}\n\n\t\tif c, ok := bg.(Colorer); ok {\n\t\t\tcolor = c.Color()\n\t\t}\n\t}\n\n\ttv.SendMessage(win.TVM_SETBKCOLOR, 0, uintptr(color))\n}\n\nfunc (tv *TreeView) Model() TreeModel {\n\treturn tv.model\n}\n\nfunc (tv *TreeView) SetModel(model TreeModel) error {\n\tif tv.model != nil {\n\t\ttv.model.ItemsReset().Detach(tv.itemsResetEventHandlerHandle)\n\t\ttv.model.ItemChanged().Detach(tv.itemChangedEventHandlerHandle)\n\t\ttv.model.ItemInserted().Detach(tv.itemInsertedEventHandlerHandle)\n\t\ttv.model.ItemRemoved().Detach(tv.itemRemovedEventHandlerHandle)\n\n\t\ttv.disposeImageListAndCaches()\n\t}\n\n\ttv.model = model\n\n\tif model != nil {\n\t\ttv.lazyPopulation = model.LazyPopulation()\n\n\t\ttv.itemsResetEventHandlerHandle = model.ItemsReset().Attach(func(parent TreeItem) {\n\t\t\tif parent == nil {\n\t\t\t\ttv.resetItems()\n\t\t\t} else if tv.item2Info[parent] != nil {\n\t\t\t\ttv.SetSuspended(true)\n\t\t\t\tdefer tv.SetSuspended(false)\n\n\t\t\t\tif err := tv.removeDescendants(parent); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif err := tv.insertChildren(parent); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\n\t\ttv.itemChangedEventHandlerHandle = model.ItemChanged().Attach(func(item TreeItem) {\n\t\t\tif item == nil || tv.item2Info[item] == nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif err := tv.updateItem(item); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\n\t\ttv.itemInsertedEventHandlerHandle = model.ItemInserted().Attach(func(item TreeItem) {\n\t\t\ttv.SetSuspended(true)\n\t\t\tdefer tv.SetSuspended(false)\n\n\t\t\tvar hInsertAfter win.HTREEITEM\n\t\t\tparent := item.Parent()\n\t\t\tfor i := parent.ChildCount() - 1; i >= 0; i-- {\n\t\t\t\tif parent.ChildAt(i) == item {\n\t\t\t\t\tif i > 0 {\n\t\t\t\t\t\thInsertAfter = tv.item2Info[parent.ChildAt(i-1)].handle\n\t\t\t\t\t} else {\n\t\t\t\t\t\thInsertAfter = win.TVI_FIRST\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif _, err := tv.insertItemAfter(item, hInsertAfter); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\n\t\ttv.itemRemovedEventHandlerHandle = model.ItemRemoved().Attach(func(item TreeItem) {\n\t\t\tif err := tv.removeItem(item); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\t}\n\n\treturn tv.resetItems()\n}\n\nfunc (tv *TreeView) CurrentItem() TreeItem {\n\treturn tv.currItem\n}\n\nfunc (tv *TreeView) SetCurrentItem(item TreeItem) error {\n\tif item == tv.currItem {\n\t\treturn nil\n\t}\n\n\tif item != nil {\n\t\tif err := tv.ensureItemAndAncestorsInserted(item); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\thandle, err := tv.handleForItem(item)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif 0 == tv.SendMessage(win.TVM_SELECTITEM, win.TVGN_CARET, uintptr(handle)) {\n\t\treturn newError(\"SendMessage(TVM_SELECTITEM) failed\")\n\t}\n\n\ttv.currItem = item\n\n\treturn nil\n}\n\nfunc (tv *TreeView) EnsureVisible(item TreeItem) error {\n\thandle, err := tv.handleForItem(item)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttv.SendMessage(win.TVM_ENSUREVISIBLE, 0, uintptr(handle))\n\n\treturn nil\n}\n\nfunc (tv *TreeView) handleForItem(item TreeItem) (win.HTREEITEM, error) {\n\tif item != nil {\n\t\tif info := tv.item2Info[item]; info == nil {\n\t\t\treturn 0, newError(\"invalid item\")\n\t\t} else {\n\t\t\treturn info.handle, nil\n\t\t}\n\t}\n\n\treturn 0, newError(\"invalid item\")\n}\n\n// ItemAt determines the location of the specified point in native pixels relative to the client area of a tree-view control.\nfunc (tv *TreeView) ItemAt(x, y int) TreeItem {\n\thti := win.TVHITTESTINFO{Pt: Point{x, y}.toPOINT()}\n\n\ttv.SendMessage(win.TVM_HITTEST, 0, uintptr(unsafe.Pointer(&hti)))\n\n\tif item, ok := tv.handle2Item[hti.HItem]; ok {\n\t\treturn item\n\t}\n\n\treturn nil\n}\n\n// ItemHeight returns the height of each item in native pixels.\nfunc (tv *TreeView) ItemHeight() int {\n\treturn int(tv.SendMessage(win.TVM_GETITEMHEIGHT, 0, 0))\n}\n\n// SetItemHeight sets the height of the tree-view items in native pixels.\nfunc (tv *TreeView) SetItemHeight(height int) {\n\ttv.SendMessage(win.TVM_SETITEMHEIGHT, uintptr(height), 0)\n}\n\nfunc (tv *TreeView) resetItems() error {\n\ttv.SetSuspended(true)\n\tdefer tv.SetSuspended(false)\n\n\tif err := tv.clearItems(); err != nil {\n\t\treturn err\n\t}\n\n\tif tv.model == nil {\n\t\treturn nil\n\t}\n\n\tif err := tv.insertRoots(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TreeView) clearItems() error {\n\tif 0 == tv.SendMessage(win.TVM_DELETEITEM, 0, 0) {\n\t\treturn newError(\"SendMessage(TVM_DELETEITEM) failed\")\n\t}\n\n\ttv.item2Info = make(map[TreeItem]*treeViewItemInfo)\n\ttv.handle2Item = make(map[win.HTREEITEM]TreeItem)\n\n\treturn nil\n}\n\nfunc (tv *TreeView) insertRoots() error {\n\tfor i := tv.model.RootCount() - 1; i >= 0; i-- {\n\t\tif _, err := tv.insertItem(tv.model.RootAt(i)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TreeView) ApplyDPI(dpi int) {\n\ttv.WidgetBase.ApplyDPI(dpi)\n\n\ttv.disposeImageListAndCaches()\n}\n\nfunc (tv *TreeView) applyImageListForImage(image interface{}) {\n\ttv.hIml, tv.usingSysIml, _ = imageListForImage(image, tv.DPI())\n\n\ttv.SendMessage(win.TVM_SETIMAGELIST, 0, uintptr(tv.hIml))\n\n\ttv.imageUintptr2Index = make(map[uintptr]int32)\n\ttv.filePath2IconIndex = make(map[string]int32)\n}\n\nfunc (tv *TreeView) disposeImageListAndCaches() {\n\tif tv.hIml != 0 && !tv.usingSysIml {\n\t\twin.ImageList_Destroy(tv.hIml)\n\t}\n\ttv.hIml = 0\n\n\ttv.imageUintptr2Index = nil\n\ttv.filePath2IconIndex = nil\n}\n\nfunc (tv *TreeView) setTVITEMImageInfo(tvi *win.TVITEM, item TreeItem) {\n\tif imager, ok := item.(Imager); ok {\n\t\tif tv.hIml == 0 {\n\t\t\ttv.applyImageListForImage(imager.Image())\n\t\t}\n\n\t\t// FIXME: If not setting TVIF_SELECTEDIMAGE and tvi.ISelectedImage,\n\t\t// some default icon will show up, even though we have not asked for it.\n\n\t\ttvi.Mask |= win.TVIF_IMAGE | win.TVIF_SELECTEDIMAGE\n\t\ttvi.IImage = imageIndexMaybeAdd(\n\t\t\timager.Image(),\n\t\t\ttv.hIml,\n\t\t\ttv.usingSysIml,\n\t\t\ttv.imageUintptr2Index,\n\t\t\ttv.filePath2IconIndex,\n\t\t\ttv.DPI())\n\n\t\ttvi.ISelectedImage = tvi.IImage\n\t}\n}\n\nfunc (tv *TreeView) insertItem(item TreeItem) (win.HTREEITEM, error) {\n\treturn tv.insertItemAfter(item, win.TVI_FIRST)\n}\n\nfunc (tv *TreeView) insertItemAfter(item TreeItem, hInsertAfter win.HTREEITEM) (win.HTREEITEM, error) {\n\tvar tvins win.TVINSERTSTRUCT\n\ttvi := &tvins.Item\n\n\ttvi.Mask = win.TVIF_CHILDREN | win.TVIF_TEXT\n\ttvi.PszText = win.LPSTR_TEXTCALLBACK\n\ttvi.CChildren = win.I_CHILDRENCALLBACK\n\n\ttv.setTVITEMImageInfo(tvi, item)\n\n\tparent := item.Parent()\n\n\tif parent == nil {\n\t\ttvins.HParent = win.TVI_ROOT\n\t} else {\n\t\tinfo := tv.item2Info[parent]\n\t\tif info == nil {\n\t\t\treturn 0, newError(\"invalid parent\")\n\t\t}\n\t\ttvins.HParent = info.handle\n\t}\n\n\ttvins.HInsertAfter = hInsertAfter\n\n\thItem := win.HTREEITEM(tv.SendMessage(win.TVM_INSERTITEM, 0, uintptr(unsafe.Pointer(&tvins))))\n\tif hItem == 0 {\n\t\treturn 0, newError(\"TVM_INSERTITEM failed\")\n\t}\n\ttv.item2Info[item] = &treeViewItemInfo{hItem, make(map[TreeItem]win.HTREEITEM)}\n\ttv.handle2Item[hItem] = item\n\n\tif !tv.lazyPopulation {\n\t\tif err := tv.insertChildren(item); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\n\treturn hItem, nil\n}\n\nfunc (tv *TreeView) insertChildren(parent TreeItem) error {\n\tinfo := tv.item2Info[parent]\n\n\tfor i := parent.ChildCount() - 1; i >= 0; i-- {\n\t\tchild := parent.ChildAt(i)\n\n\t\tif handle, err := tv.insertItem(child); err != nil {\n\t\t\treturn err\n\t\t} else {\n\t\t\tinfo.child2Handle[child] = handle\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TreeView) updateItem(item TreeItem) error {\n\ttvi := &win.TVITEM{\n\t\tMask:    win.TVIF_TEXT,\n\t\tHItem:   tv.item2Info[item].handle,\n\t\tPszText: win.LPSTR_TEXTCALLBACK,\n\t}\n\n\ttv.setTVITEMImageInfo(tvi, item)\n\n\tif 0 == tv.SendMessage(win.TVM_SETITEM, 0, uintptr(unsafe.Pointer(tvi))) {\n\t\treturn newError(\"SendMessage(TVM_SETITEM) failed\")\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TreeView) removeItem(item TreeItem) error {\n\tif err := tv.removeDescendants(item); err != nil {\n\t\treturn err\n\t}\n\n\tinfo := tv.item2Info[item]\n\tif info == nil {\n\t\treturn newError(\"invalid item\")\n\t}\n\n\tif 0 == tv.SendMessage(win.TVM_DELETEITEM, 0, uintptr(info.handle)) {\n\t\treturn newError(\"SendMessage(TVM_DELETEITEM) failed\")\n\t}\n\n\tif parentInfo := tv.item2Info[item.Parent()]; parentInfo != nil {\n\t\tdelete(parentInfo.child2Handle, item)\n\t}\n\tdelete(tv.item2Info, item)\n\tdelete(tv.handle2Item, info.handle)\n\n\treturn nil\n}\n\nfunc (tv *TreeView) removeDescendants(parent TreeItem) error {\n\tfor item, _ := range tv.item2Info[parent].child2Handle {\n\t\tif err := tv.removeItem(item); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TreeView) ensureItemAndAncestorsInserted(item TreeItem) error {\n\tif item == nil {\n\t\treturn newError(\"invalid item\")\n\t}\n\n\ttv.SetSuspended(true)\n\tdefer tv.SetSuspended(false)\n\n\tvar hierarchy []TreeItem\n\n\tfor item != nil && tv.item2Info[item] == nil {\n\t\titem = item.Parent()\n\n\t\tif item != nil {\n\t\t\thierarchy = append(hierarchy, item)\n\t\t} else {\n\t\t\treturn newError(\"invalid item\")\n\t\t}\n\t}\n\n\tfor i := len(hierarchy) - 1; i >= 0; i-- {\n\t\tif err := tv.insertChildren(hierarchy[i]); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TreeView) Expanded(item TreeItem) bool {\n\tif tv.item2Info[item] == nil {\n\t\treturn false\n\t}\n\n\ttvi := &win.TVITEM{\n\t\tHItem:     tv.item2Info[item].handle,\n\t\tMask:      win.TVIF_STATE,\n\t\tStateMask: win.TVIS_EXPANDED,\n\t}\n\n\tif 0 == tv.SendMessage(win.TVM_GETITEM, 0, uintptr(unsafe.Pointer(tvi))) {\n\t\tnewError(\"SendMessage(TVM_GETITEM) failed\")\n\t}\n\n\treturn tvi.State&win.TVIS_EXPANDED != 0\n}\n\nfunc (tv *TreeView) SetExpanded(item TreeItem, expanded bool) error {\n\tif expanded {\n\t\tif err := tv.ensureItemAndAncestorsInserted(item); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tinfo := tv.item2Info[item]\n\tif info == nil {\n\t\treturn newError(\"invalid item\")\n\t}\n\n\tvar action uintptr\n\tif expanded {\n\t\taction = win.TVE_EXPAND\n\t} else {\n\t\taction = win.TVE_COLLAPSE\n\t}\n\n\tif 0 == tv.SendMessage(win.TVM_EXPAND, action, uintptr(info.handle)) {\n\t\treturn newError(\"SendMessage(TVM_EXPAND) failed\")\n\t}\n\n\treturn nil\n}\n\nfunc (tv *TreeView) ExpandedChanged() *TreeItemEvent {\n\treturn tv.expandedChangedPublisher.Event()\n}\n\nfunc (tv *TreeView) CurrentItemChanged() *Event {\n\treturn tv.currentItemChangedPublisher.Event()\n}\n\nfunc (tv *TreeView) ItemActivated() *Event {\n\treturn tv.itemActivatedPublisher.Event()\n}\n\nfunc (tv *TreeView) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_GETDLGCODE:\n\t\tif wParam == win.VK_RETURN {\n\t\t\treturn win.DLGC_WANTALLKEYS\n\t\t}\n\n\tcase win.WM_NOTIFY:\n\t\tnmhdr := (*win.NMHDR)(unsafe.Pointer(lParam))\n\n\t\tswitch nmhdr.Code {\n\t\tcase win.TVN_GETDISPINFO:\n\t\t\tnmtvdi := (*win.NMTVDISPINFO)(unsafe.Pointer(lParam))\n\t\t\titem := tv.handle2Item[nmtvdi.Item.HItem]\n\n\t\t\tif nmtvdi.Item.Mask&win.TVIF_TEXT != 0 {\n\t\t\t\ttext := item.Text()\n\t\t\t\tutf16 := syscall.StringToUTF16(text)\n\t\t\t\tbuf := (*[264]uint16)(unsafe.Pointer(nmtvdi.Item.PszText))\n\t\t\t\tmax := mini(len(utf16), int(nmtvdi.Item.CchTextMax))\n\t\t\t\tcopy((*buf)[:], utf16[:max])\n\t\t\t\t(*buf)[max-1] = 0\n\t\t\t}\n\t\t\tif nmtvdi.Item.Mask&win.TVIF_CHILDREN != 0 {\n\t\t\t\tif hc, ok := item.(HasChilder); ok {\n\t\t\t\t\tif hc.HasChild() {\n\t\t\t\t\t\tnmtvdi.Item.CChildren = 1\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnmtvdi.Item.CChildren = 0\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tnmtvdi.Item.CChildren = int32(item.ChildCount())\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase win.TVN_ITEMEXPANDING:\n\t\t\tnmtv := (*win.NMTREEVIEW)(unsafe.Pointer(lParam))\n\t\t\titem := tv.handle2Item[nmtv.ItemNew.HItem]\n\n\t\t\tif nmtv.Action == win.TVE_EXPAND && tv.lazyPopulation {\n\t\t\t\tinfo := tv.item2Info[item]\n\t\t\t\tif len(info.child2Handle) == 0 {\n\t\t\t\t\ttv.insertChildren(item)\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase win.TVN_ITEMEXPANDED:\n\t\t\tnmtv := (*win.NMTREEVIEW)(unsafe.Pointer(lParam))\n\t\t\titem := tv.handle2Item[nmtv.ItemNew.HItem]\n\n\t\t\tswitch nmtv.Action {\n\t\t\tcase win.TVE_COLLAPSE:\n\t\t\t\ttv.expandedChangedPublisher.Publish(item)\n\n\t\t\tcase win.TVE_COLLAPSERESET:\n\n\t\t\tcase win.TVE_EXPAND:\n\t\t\t\ttv.expandedChangedPublisher.Publish(item)\n\n\t\t\tcase win.TVE_EXPANDPARTIAL:\n\n\t\t\tcase win.TVE_TOGGLE:\n\t\t\t}\n\n\t\tcase win.NM_DBLCLK:\n\t\t\ttv.itemActivatedPublisher.Publish()\n\n\t\tcase win.TVN_KEYDOWN:\n\t\t\tnmtvkd := (*win.NMTVKEYDOWN)(unsafe.Pointer(lParam))\n\t\t\tif nmtvkd.WVKey == uint16(KeyReturn) {\n\t\t\t\ttv.itemActivatedPublisher.Publish()\n\t\t\t}\n\n\t\tcase win.TVN_SELCHANGED:\n\t\t\tnmtv := (*win.NMTREEVIEW)(unsafe.Pointer(lParam))\n\n\t\t\ttv.currItem = tv.handle2Item[nmtv.ItemNew.HItem]\n\n\t\t\ttv.currentItemChangedPublisher.Publish()\n\t\t}\n\t}\n\n\treturn tv.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (*TreeView) NeedsWmSize() bool {\n\treturn true\n}\n\nfunc (tv *TreeView) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn NewGreedyLayoutItem()\n}\n"
  },
  {
    "path": "util.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"bytes\"\n\t\"math\"\n\t\"math/big\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/lxn/win\"\n)\n\nvar (\n\tdecimalSepB      byte\n\tdecimalSepUint16 uint16\n\tdecimalSepS      string\n\tgroupSepB        byte\n\tgroupSepUint16   uint16\n\tgroupSepS        string\n)\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tvar buf [4]uint16\n\n\t\twin.GetLocaleInfo(win.LOCALE_USER_DEFAULT, win.LOCALE_SDECIMAL, &buf[0], int32(len(buf)))\n\t\tdecimalSepB = byte(buf[0])\n\t\tdecimalSepS = syscall.UTF16ToString(buf[0:1])\n\t\tdecimalSepUint16 = buf[0]\n\n\t\twin.GetLocaleInfo(win.LOCALE_USER_DEFAULT, win.LOCALE_STHOUSAND, &buf[0], int32(len(buf)))\n\t\tgroupSepB = byte(buf[0])\n\t\tgroupSepS = syscall.UTF16ToString(buf[0:1])\n\t\tgroupSepUint16 = buf[0]\n\t})\n}\n\nfunc maxi(a, b int) int {\n\tif a > b {\n\t\treturn a\n\t}\n\n\treturn b\n}\n\nfunc mini(a, b int) int {\n\tif a < b {\n\t\treturn a\n\t}\n\n\treturn b\n}\n\nfunc boolToInt(value bool) int {\n\tif value {\n\t\treturn 1\n\t}\n\n\treturn 0\n}\n\nfunc uint16IndexUint16(s []uint16, v uint16) int {\n\tfor i, u := range s {\n\t\tif u == v {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc uint16ContainsUint16(s []uint16, v uint16) bool {\n\treturn uint16IndexUint16(s, v) != -1\n}\n\nfunc uint16CountUint16(s []uint16, v uint16) int {\n\tvar count int\n\n\tfor _, u := range s {\n\t\tif u == v {\n\t\t\tcount++\n\t\t}\n\t}\n\n\treturn count\n}\n\nfunc uint16RemoveUint16(s []uint16, v uint16) []uint16 {\n\tcount := uint16CountUint16(s, v)\n\tif count == 0 {\n\t\treturn s\n\t}\n\n\tret := make([]uint16, 0, len(s)-count)\n\n\tfor _, u := range s {\n\t\tif u != v {\n\t\t\tret = append(ret, u)\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc assertFloat64Or(value interface{}, defaultValue float64) float64 {\n\tif f, ok := value.(float64); ok {\n\t\treturn f\n\t}\n\n\treturn defaultValue\n}\n\nfunc assertIntOr(value interface{}, defaultValue int) int {\n\tif n, ok := value.(int); ok {\n\t\treturn n\n\t}\n\n\treturn defaultValue\n}\n\nfunc assertStringOr(value interface{}, defaultValue string) string {\n\tif s, ok := value.(string); ok {\n\t\treturn s\n\t}\n\n\treturn defaultValue\n}\n\nfunc assertTimeOr(value interface{}, defaultValue time.Time) time.Time {\n\tif t, ok := value.(time.Time); ok {\n\t\treturn t\n\t}\n\n\treturn defaultValue\n}\n\nfunc ParseFloat(s string) (float64, error) {\n\ts = strings.TrimSpace(s)\n\n\tt := FormatFloatGrouped(1000, 2)\n\n\treplaceSep := func(new string, index func(string, func(rune) bool) int) {\n\t\ti := index(t, func(r rune) bool {\n\t\t\treturn r < '0' || r > '9'\n\t\t})\n\n\t\tvar sep string\n\t\tif i > -1 {\n\t\t\tsep = string(t[i])\n\t\t}\n\t\tif sep != \"\" {\n\t\t\ts = strings.Replace(s, string(sep), new, -1)\n\t\t}\n\t}\n\n\treplaceSep(\"\", strings.IndexFunc)\n\treplaceSep(\".\", strings.LastIndexFunc)\n\n\treturn strconv.ParseFloat(s, 64)\n}\n\nfunc FormatFloat(f float64, prec int) string {\n\treturn formatFloatString(strconv.FormatFloat(f, 'f', prec, 64), prec, false)\n}\n\nfunc FormatFloatGrouped(f float64, prec int) string {\n\treturn formatFloatString(strconv.FormatFloat(f, 'f', maxi(1, prec), 64), prec, true)\n}\n\nfunc formatBigRat(r *big.Rat, prec int) string {\n\treturn formatFloatString(r.FloatString(prec), prec, false)\n}\n\nfunc formatBigRatGrouped(r *big.Rat, prec int) string {\n\treturn formatFloatString(r.FloatString(prec), prec, true)\n}\n\nfunc formatFloatString(s string, prec int, grouped bool) string {\n\tswitch s {\n\tcase \"NaN\", \"-Inf\", \"+Inf\":\n\t\treturn s\n\t}\n\n\ts = strings.Replace(s, \".\", decimalSepS, 1)\n\tif !grouped {\n\t\treturn s\n\t}\n\n\tb := new(bytes.Buffer)\n\n\tvar firstDigit int\n\tif len(s) > 0 && s[0] == '-' {\n\t\tfirstDigit = 1\n\t\tb.WriteByte('-')\n\t\ts = s[1:]\n\t}\n\n\tintLen := len(s) - maxi(1, prec) - 1\n\n\tn := intLen % 3\n\tif n != 0 {\n\t\tb.WriteString(s[:n])\n\t}\n\tfor i := n; i < intLen; i += 3 {\n\t\tif b.Len() > firstDigit {\n\t\t\tb.WriteByte(groupSepB)\n\t\t}\n\t\tb.WriteString(s[i : i+3])\n\t}\n\n\tb.WriteString(s[intLen:])\n\n\ts = b.String()\n\n\tif prec == 0 {\n\t\ts = s[:len(s)-2]\n\t}\n\n\treturn s\n}\n\nfunc applyEnabledToDescendants(window Window, enabled bool) {\n\twb := window.AsWindowBase()\n\twb.applyEnabled(enabled)\n\n\twalkDescendants(window, func(w Window) bool {\n\t\tif w.Handle() == wb.hWnd {\n\t\t\treturn true\n\t\t}\n\n\t\tif enabled && !w.AsWindowBase().enabled {\n\t\t\treturn false\n\t\t}\n\n\t\tw.(applyEnableder).applyEnabled(enabled)\n\n\t\treturn true\n\t})\n}\n\nvar seenInApplyFontToDescendantsDuringDPIChange map[*WindowBase]bool\n\nfunc applyFontToDescendants(window Window, font *Font) {\n\twb := window.AsWindowBase()\n\twb.applyFont(font)\n\n\twalkDescendants(window, func(w Window) bool {\n\t\tif w.Handle() == wb.hWnd {\n\t\t\treturn true\n\t\t}\n\n\t\tif w.AsWindowBase().font != nil {\n\t\t\treturn false\n\t\t}\n\n\t\tif seenInApplyFontToDescendantsDuringDPIChange != nil {\n\t\t\twb := w.AsWindowBase()\n\t\t\tif seenInApplyFontToDescendantsDuringDPIChange[wb] {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tseenInApplyFontToDescendantsDuringDPIChange[wb] = true\n\t\t}\n\n\t\tw.(applyFonter).applyFont(font)\n\n\t\treturn true\n\t})\n}\n\nfunc applySysColorsToDescendants(window Window) {\n\twb := window.AsWindowBase()\n\twb.ApplySysColors()\n\n\twalkDescendants(window, func(w Window) bool {\n\t\tif w.Handle() == wb.hWnd {\n\t\t\treturn true\n\t\t}\n\n\t\tw.(ApplySysColorser).ApplySysColors()\n\n\t\treturn true\n\t})\n}\n\nvar seenInApplyDPIToDescendantsDuringDPIChange map[*WindowBase]bool\n\nfunc applyDPIToDescendants(window Window, dpi int) {\n\twb := window.AsWindowBase()\n\twb.ApplyDPI(dpi)\n\n\twalkDescendants(window, func(w Window) bool {\n\t\tif w.Handle() == wb.hWnd {\n\t\t\treturn true\n\t\t}\n\n\t\tif seenInApplyDPIToDescendantsDuringDPIChange != nil {\n\t\t\twb := w.AsWindowBase()\n\t\t\tif seenInApplyDPIToDescendantsDuringDPIChange[wb] {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tseenInApplyDPIToDescendantsDuringDPIChange[wb] = true\n\t\t}\n\n\t\tw.(ApplyDPIer).ApplyDPI(dpi)\n\n\t\treturn true\n\t})\n}\n\nfunc walkDescendants(window Window, f func(w Window) bool) {\n\twindow = window.AsWindowBase().window\n\n\tif window == nil || !f(window) {\n\t\treturn\n\t}\n\n\tvar children []*WidgetBase\n\n\tswitch w := window.(type) {\n\tcase *NumberEdit:\n\t\tif w.edit != nil {\n\t\t\tchildren = append(children, w.edit.AsWidgetBase())\n\t\t}\n\n\tcase *TabWidget:\n\t\tfor _, p := range w.Pages().items {\n\t\t\tchildren = append(children, p.AsWidgetBase())\n\t\t}\n\n\tcase Container:\n\t\tif c := w.Children(); c != nil {\n\t\t\tchildren = c.items\n\t\t} else {\n\t\t\tchildren = nil\n\t\t}\n\t}\n\n\tfor _, wb := range children {\n\t\twalkDescendants(wb.window.(Widget), f)\n\t}\n}\n\nfunc less(a, b interface{}, order SortOrder) bool {\n\tif _, ok := a.(error); ok {\n\t\t_, bIsErr := b.(error)\n\n\t\treturn order == SortAscending == !bIsErr\n\t}\n\tif _, ok := b.(error); ok {\n\t\treturn order == SortDescending\n\t}\n\n\tif a == nil {\n\t\treturn order == SortAscending == (b != nil)\n\t}\n\tif b == nil {\n\t\treturn order == SortDescending\n\t}\n\n\tswitch av := a.(type) {\n\tcase string:\n\t\tif bv, ok := b.(string); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase int:\n\t\tif bv, ok := b.(int); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase float64:\n\t\tif bv, ok := b.(float64); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase float32:\n\t\tif bv, ok := b.(float32); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase int64:\n\t\tif bv, ok := b.(int64); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase int32:\n\t\tif bv, ok := b.(int32); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase int16:\n\t\tif bv, ok := b.(int16); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase int8:\n\t\tif bv, ok := b.(int8); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase uint:\n\t\tif bv, ok := b.(uint); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase uint64:\n\t\tif bv, ok := b.(uint64); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase uint32:\n\t\tif bv, ok := b.(uint32); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase uint16:\n\t\tif bv, ok := b.(uint16); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase uint8:\n\t\tif bv, ok := b.(uint8); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av < bv\n\t\t\t} else {\n\t\t\t\treturn bv < av\n\t\t\t}\n\t\t}\n\n\tcase time.Time:\n\t\tif bv, ok := b.(time.Time); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn av.Before(bv)\n\t\t\t} else {\n\t\t\t\treturn bv.Before(av)\n\t\t\t}\n\t\t}\n\n\tcase bool:\n\t\tif bv, ok := b.(bool); ok {\n\t\t\tif order == SortAscending {\n\t\t\t\treturn !av && bv\n\t\t\t} else {\n\t\t\t\treturn !bv && av\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc dpiForHDC(hdc win.HDC) int {\n\tif hwnd := win.WindowFromDC(hdc); hwnd != 0 {\n\t\treturn int(win.GetDpiForWindow(hwnd))\n\t}\n\n\treturn int(win.GetDeviceCaps(hdc, win.LOGPIXELSX))\n}\n\n// IntFrom96DPI converts from 1/96\" units to native pixels.\nfunc IntFrom96DPI(value, dpi int) int {\n\treturn scaleInt(value, float64(dpi)/96.0)\n}\n\n// IntTo96DPI converts from native pixels to 1/96\" units.\nfunc IntTo96DPI(value, dpi int) int {\n\treturn scaleInt(value, 96.0/float64(dpi))\n}\n\nfunc scaleInt(value int, scale float64) int {\n\treturn int(math.Round(float64(value) * scale))\n}\n\n// MarginsFrom96DPI converts from 1/96\" units to native pixels.\nfunc MarginsFrom96DPI(value Margins, dpi int) Margins {\n\treturn scaleMargins(value, float64(dpi)/96.0)\n}\n\n// MarginsTo96DPI converts from native pixels to 1/96\" units.\nfunc MarginsTo96DPI(value Margins, dpi int) Margins {\n\treturn scaleMargins(value, 96.0/float64(dpi))\n}\n\nfunc scaleMargins(value Margins, scale float64) Margins {\n\treturn Margins{\n\t\tHNear: scaleInt(value.HNear, scale),\n\t\tVNear: scaleInt(value.VNear, scale),\n\t\tHFar:  scaleInt(value.HFar, scale),\n\t\tVFar:  scaleInt(value.VFar, scale),\n\t}\n}\n\n// PointFrom96DPI converts from 1/96\" units to native pixels.\nfunc PointFrom96DPI(value Point, dpi int) Point {\n\treturn scalePoint(value, float64(dpi)/96.0)\n}\n\n// PointTo96DPI converts from native pixels to 1/96\" units.\nfunc PointTo96DPI(value Point, dpi int) Point {\n\treturn scalePoint(value, 96.0/float64(dpi))\n}\n\nfunc scalePoint(value Point, scale float64) Point {\n\treturn Point{\n\t\tX: scaleInt(value.X, scale),\n\t\tY: scaleInt(value.Y, scale),\n\t}\n}\n\n// RectangleFrom96DPI converts from 1/96\" units to native pixels.\nfunc RectangleFrom96DPI(value Rectangle, dpi int) Rectangle {\n\treturn scaleRectangle(value, float64(dpi)/96.0)\n}\n\n// RectangleTo96DPI converts from native pixels to 1/96\" units.\nfunc RectangleTo96DPI(value Rectangle, dpi int) Rectangle {\n\treturn scaleRectangle(value, 96.0/float64(dpi))\n}\n\nfunc scaleRectangle(value Rectangle, scale float64) Rectangle {\n\treturn Rectangle{\n\t\tX:      scaleInt(value.X, scale),\n\t\tY:      scaleInt(value.Y, scale),\n\t\tWidth:  scaleInt(value.Width, scale),\n\t\tHeight: scaleInt(value.Height, scale),\n\t}\n}\n\n// SizeFrom96DPI converts from 1/96\" units to native pixels.\nfunc SizeFrom96DPI(value Size, dpi int) Size {\n\treturn scaleSize(value, float64(dpi)/96.0)\n}\n\n// SizeTo96DPI converts from native pixels to 1/96\" units.\nfunc SizeTo96DPI(value Size, dpi int) Size {\n\treturn scaleSize(value, 96.0/float64(dpi))\n}\n\nfunc scaleSize(value Size, scale float64) Size {\n\treturn Size{\n\t\tWidth:  scaleInt(value.Width, scale),\n\t\tHeight: scaleInt(value.Height, scale),\n\t}\n}\n"
  },
  {
    "path": "validators.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"regexp\"\n)\n\ntype Validator interface {\n\tValidate(v interface{}) error\n}\n\ntype ValidationError struct {\n\ttitle   string\n\tmessage string\n}\n\nfunc NewValidationError(title, message string) *ValidationError {\n\treturn &ValidationError{title: title, message: message}\n}\n\nfunc (ve *ValidationError) Title() string {\n\treturn ve.title\n}\n\nfunc (ve *ValidationError) Message() string {\n\treturn ve.message\n}\n\nfunc (ve *ValidationError) Error() string {\n\treturn fmt.Sprintf(\"%s - %s\", ve.title, ve.message)\n}\n\ntype RangeValidator struct {\n\tmin float64\n\tmax float64\n}\n\nfunc NewRangeValidator(min, max float64) (*RangeValidator, error) {\n\tif max < min {\n\t\treturn nil, errors.New(\"max < min\")\n\t}\n\n\treturn &RangeValidator{min: min, max: max}, nil\n}\n\nfunc (rv *RangeValidator) Min() float64 {\n\treturn rv.min\n}\n\nfunc (rv *RangeValidator) Max() float64 {\n\treturn rv.max\n}\n\nfunc (rv *RangeValidator) Reset(min, max float64) error {\n\tif max < min {\n\t\treturn errors.New(\"max < min\")\n\t}\n\n\trv.min, rv.max = min, max\n\n\treturn nil\n}\n\nfunc (rv *RangeValidator) Validate(v interface{}) error {\n\tf64 := v.(float64)\n\n\tif f64 < rv.min || f64 > rv.max {\n\t\tvar msg string\n\t\tif math.Abs(rv.min-math.Floor(rv.min)) < math.SmallestNonzeroFloat64 &&\n\t\t\tmath.Abs(rv.max-math.Floor(rv.max)) < math.SmallestNonzeroFloat64 {\n\n\t\t\tmsg = fmt.Sprintf(tr(\"Please enter a number from %.f to %.f.\", \"walk\"),\n\t\t\t\trv.min, rv.max)\n\t\t} else {\n\t\t\tmsg = fmt.Sprintf(tr(\"Please enter a number from %s to %s.\", \"walk\"),\n\t\t\t\tFormatFloatGrouped(rv.min, 2), FormatFloatGrouped(rv.max, 2))\n\t\t}\n\n\t\treturn NewValidationError(tr(\"Number out of allowed range\", \"walk\"), msg)\n\t}\n\n\treturn nil\n}\n\ntype RegexpValidator struct {\n\tre *regexp.Regexp\n}\n\nfunc NewRegexpValidator(pattern string) (*RegexpValidator, error) {\n\tre, err := regexp.Compile(pattern)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &RegexpValidator{re}, nil\n}\n\nfunc (rv *RegexpValidator) Pattern() string {\n\treturn rv.re.String()\n}\n\nfunc (rv *RegexpValidator) Validate(v interface{}) error {\n\tvar matched bool\n\n\tswitch val := v.(type) {\n\tcase string:\n\t\tmatched = rv.re.MatchString(val)\n\n\tcase []byte:\n\t\tmatched = rv.re.Match(val)\n\n\tcase fmt.Stringer:\n\t\tmatched = rv.re.MatchString(val.String())\n\n\tdefault:\n\t\tpanic(\"Unsupported type\")\n\t}\n\n\tif !matched {\n\t\treturn errors.New(tr(\"The text does not match the required pattern.\", \"walk\"))\n\t}\n\n\treturn nil\n}\n\ntype selectionRequiredValidator struct {\n}\n\nvar selectionRequiredValidatorSingleton Validator = selectionRequiredValidator{}\n\nfunc SelectionRequiredValidator() Validator {\n\treturn selectionRequiredValidatorSingleton\n}\n\nfunc (selectionRequiredValidator) Validate(v interface{}) error {\n\tif v == nil {\n\t\t// For Widgets like ComboBox nil is passed to indicate \"no selection\".\n\t\treturn NewValidationError(\n\t\t\ttr(\"Selection Required\", \"walk\"),\n\t\t\ttr(\"Please select one of the provided options.\", \"walk\"))\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "walk.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"errors\"\n)\n\nvar (\n\tErrInvalidType = errors.New(\"invalid type\")\n)\n\nfunc LogErrors() bool {\n\treturn logErrors\n}\n\nfunc SetLogErrors(v bool) {\n\tlogErrors = v\n}\n\nfunc PanicOnError() bool {\n\treturn panicOnError\n}\n\nfunc SetPanicOnError(v bool) {\n\tpanicOnError = v\n}\n\nfunc TranslationFunc() TranslationFunction {\n\treturn translation\n}\n\nfunc SetTranslationFunc(f TranslationFunction) {\n\ttranslation = f\n}\n\ntype TranslationFunction func(source string, context ...string) string\n\nvar translation TranslationFunction\n\nfunc tr(source string, context ...string) string {\n\tif translation == nil {\n\t\treturn source\n\t}\n\n\treturn translation(source, context...)\n}\n\ntype Disposable interface {\n\tDispose()\n}\n\ntype Disposables struct {\n\titems []Disposable\n\tdone  bool\n}\n\nfunc (d *Disposables) Add(item Disposable) {\n\td.items = append(d.items, item)\n}\n\nfunc (d *Disposables) Spare() {\n\td.done = true\n}\n\nfunc (d *Disposables) Treat() {\n\tif d.done {\n\t\treturn\n\t}\n\n\tfor _, item := range d.items {\n\t\titem.Dispose()\n\t}\n\n\td.done = true\n}\n"
  },
  {
    "path": "webview.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\nconst webViewWindowClass = `\\o/ Walk_WebView_Class \\o/`\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tMustRegisterWindowClass(webViewWindowClass)\n\t})\n}\n\ntype WebView struct {\n\tWidgetBase\n\tclientSite                               webViewIOleClientSite // IMPORTANT: Must remain first member after WidgetBase\n\tbrowserObject                            *win.IOleObject\n\turlChangedPublisher                      EventPublisher\n\tshortcutsEnabled                         bool\n\tshortcutsEnabledChangedPublisher         EventPublisher\n\tnativeContextMenuEnabled                 bool\n\tnativeContextMenuEnabledChangedPublisher EventPublisher\n\tnavigatingPublisher                      WebViewNavigatingEventPublisher\n\tnavigatedPublisher                       StringEventPublisher\n\tdownloadingPublisher                     EventPublisher\n\tdownloadedPublisher                      EventPublisher\n\tdocumentCompletedPublisher               StringEventPublisher\n\tnavigatedErrorPublisher                  WebViewNavigatedErrorEventPublisher\n\tnewWindowPublisher                       WebViewNewWindowEventPublisher\n\tquittingPublisher                        EventPublisher\n\twindowClosingPublisher                   WebViewWindowClosingEventPublisher\n\tstatusBarVisible                         bool\n\tstatusBarVisibleChangedPublisher         EventPublisher\n\tisTheaterMode                            bool\n\ttheaterModeChangedPublisher              EventPublisher\n\ttoolBarVisible                           bool\n\ttoolBarVisibleChangedPublisher           EventPublisher\n\tbrowserVisible                           bool\n\tbrowserVisibleChangedPublisher           EventPublisher\n\ttoolBarEnabled                           bool\n\ttoolBarEnabledChangedPublisher           EventPublisher\n\tcanGoBack                                bool\n\tcanGoBackChangedPublisher                EventPublisher\n\tcanGoForward                             bool\n\tcanGoForwardChangedPublisher             EventPublisher\n\tprogressValue                            int32\n\tprogressMax                              int32\n\tprogressChangedPublisher                 EventPublisher\n\tstatusText                               string\n\tstatusTextChangedPublisher               EventPublisher\n\tdocumentTitle                            string\n\tdocumentTitleChangedPublisher            EventPublisher\n}\n\nfunc NewWebView(parent Container) (*WebView, error) {\n\tif hr := win.OleInitialize(); hr != win.S_OK && hr != win.S_FALSE {\n\t\treturn nil, newError(fmt.Sprint(\"OleInitialize Error: \", hr))\n\t}\n\n\twv := &WebView{\n\t\tclientSite: webViewIOleClientSite{\n\t\t\tIOleClientSite: win.IOleClientSite{\n\t\t\t\tLpVtbl: webViewIOleClientSiteVtbl,\n\t\t\t},\n\t\t\tinPlaceSite: webViewIOleInPlaceSite{\n\t\t\t\tIOleInPlaceSite: win.IOleInPlaceSite{\n\t\t\t\t\tLpVtbl: webViewIOleInPlaceSiteVtbl,\n\t\t\t\t},\n\t\t\t\tinPlaceFrame: webViewIOleInPlaceFrame{\n\t\t\t\t\tIOleInPlaceFrame: win.IOleInPlaceFrame{\n\t\t\t\t\t\tLpVtbl: webViewIOleInPlaceFrameVtbl,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tdocHostUIHandler: webViewIDocHostUIHandler{\n\t\t\t\tIDocHostUIHandler: win.IDocHostUIHandler{\n\t\t\t\t\tLpVtbl: webViewIDocHostUIHandlerVtbl,\n\t\t\t\t},\n\t\t\t},\n\t\t\twebBrowserEvents2: webViewDWebBrowserEvents2{\n\t\t\t\tDWebBrowserEvents2: win.DWebBrowserEvents2{\n\t\t\t\t\tLpVtbl: webViewDWebBrowserEvents2Vtbl,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tshortcutsEnabled:         false,\n\t\tnativeContextMenuEnabled: false,\n\t}\n\n\tif err := InitWidget(\n\t\twv,\n\t\tparent,\n\t\twebViewWindowClass,\n\t\twin.WS_CLIPCHILDREN|win.WS_VISIBLE,\n\t\t0); err != nil {\n\t\treturn nil, err\n\t}\n\n\twv.clientSite.inPlaceSite.inPlaceFrame.webView = wv\n\n\tsucceeded := false\n\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\twv.Dispose()\n\t\t}\n\t}()\n\n\tvar classFactoryPtr unsafe.Pointer\n\tif hr := win.CoGetClassObject(&win.CLSID_WebBrowser, win.CLSCTX_INPROC_HANDLER|win.CLSCTX_INPROC_SERVER, nil, &win.IID_IClassFactory, &classFactoryPtr); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"CoGetClassObject\", hr)\n\t}\n\tclassFactory := (*win.IClassFactory)(classFactoryPtr)\n\tdefer classFactory.Release()\n\n\tvar browserObjectPtr unsafe.Pointer\n\tif hr := classFactory.CreateInstance(nil, &win.IID_IOleObject, &browserObjectPtr); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"IClassFactory.CreateInstance\", hr)\n\t}\n\tbrowserObject := (*win.IOleObject)(browserObjectPtr)\n\n\twv.browserObject = browserObject\n\n\tif hr := browserObject.SetClientSite((*win.IOleClientSite)(unsafe.Pointer(&wv.clientSite))); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"IOleObject.SetClientSite\", hr)\n\t}\n\n\tif hr := browserObject.SetHostNames(syscall.StringToUTF16Ptr(\"Walk.WebView\"), nil); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"IOleObject.SetHostNames\", hr)\n\t}\n\n\tif hr := win.OleSetContainedObject((*win.IUnknown)(unsafe.Pointer(browserObject)), true); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"OleSetContainedObject\", hr)\n\t}\n\n\tvar rect win.RECT\n\twin.GetClientRect(wv.hWnd, &rect)\n\n\tif hr := browserObject.DoVerb(win.OLEIVERB_SHOW, nil, (*win.IOleClientSite)(unsafe.Pointer(&wv.clientSite)), 0, wv.hWnd, &rect); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"IOleObject.DoVerb\", hr)\n\t}\n\n\tvar cpcPtr unsafe.Pointer\n\tif hr := browserObject.QueryInterface(&win.IID_IConnectionPointContainer, &cpcPtr); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"IOleObject.QueryInterface(IID_IConnectionPointContainer)\", hr)\n\t}\n\tcpc := (*win.IConnectionPointContainer)(cpcPtr)\n\tdefer cpc.Release()\n\n\tvar cp *win.IConnectionPoint\n\tif hr := cpc.FindConnectionPoint(&win.DIID_DWebBrowserEvents2, &cp); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"IConnectionPointContainer.FindConnectionPoint(DIID_DWebBrowserEvents2)\", hr)\n\t}\n\tdefer cp.Release()\n\n\tvar cookie uint32\n\tif hr := cp.Advise(unsafe.Pointer(&wv.clientSite.webBrowserEvents2), &cookie); win.FAILED(hr) {\n\t\treturn nil, errorFromHRESULT(\"IConnectionPoint.Advise\", hr)\n\t}\n\n\twv.onResize()\n\n\twv.MustRegisterProperty(\"URL\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\turl, _ := wv.URL()\n\t\t\treturn url\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\treturn wv.SetURL(assertStringOr(v, \"\"))\n\t\t},\n\t\twv.urlChangedPublisher.Event()))\n\n\twv.MustRegisterProperty(\"ShortcutsEnabled\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn wv.ShortcutsEnabled()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\twv.SetShortcutsEnabled(v.(bool))\n\t\t\treturn nil\n\t\t},\n\t\twv.shortcutsEnabledChangedPublisher.Event()))\n\n\twv.MustRegisterProperty(\"NativeContextMenuEnabled\", NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn wv.NativeContextMenuEnabled()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\twv.SetNativeContextMenuEnabled(v.(bool))\n\t\t\treturn nil\n\t\t},\n\t\twv.nativeContextMenuEnabledChangedPublisher.Event()))\n\n\tsucceeded = true\n\n\treturn wv, nil\n}\n\nfunc (wv *WebView) Dispose() {\n\tif wv.browserObject != nil {\n\t\twv.browserObject.Close(win.OLECLOSE_NOSAVE)\n\t\twv.browserObject.Release()\n\n\t\twv.browserObject = nil\n\n\t\twin.OleUninitialize()\n\t}\n\n\twv.WidgetBase.Dispose()\n}\n\nfunc (wv *WebView) URL() (url string, err error) {\n\terr = wv.withWebBrowser2(func(webBrowser2 *win.IWebBrowser2) error {\n\t\tvar urlBstr *uint16 /*BSTR*/\n\t\tif hr := webBrowser2.Get_LocationURL(&urlBstr); win.FAILED(hr) {\n\t\t\treturn errorFromHRESULT(\"IWebBrowser2.Get_LocationURL\", hr)\n\t\t}\n\t\tdefer win.SysFreeString(urlBstr)\n\n\t\turl = win.BSTRToString(urlBstr)\n\n\t\treturn nil\n\t})\n\n\treturn\n}\n\nfunc (wv *WebView) SetURL(url string) error {\n\treturn wv.withWebBrowser2(func(webBrowser2 *win.IWebBrowser2) error {\n\t\turlBstr := win.StringToVariantBSTR(url)\n\t\tflags := win.IntToVariantI4(0)\n\t\ttargetFrameName := win.StringToVariantBSTR(\"_self\")\n\n\t\tif hr := webBrowser2.Navigate2(urlBstr, flags, targetFrameName, nil, nil); win.FAILED(hr) {\n\t\t\treturn errorFromHRESULT(\"IWebBrowser2.Navigate2\", hr)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\nfunc (wv *WebView) URLChanged() *Event {\n\treturn wv.urlChangedPublisher.Event()\n}\n\nfunc (wv *WebView) ShortcutsEnabled() bool {\n\treturn wv.shortcutsEnabled\n}\n\nfunc (wv *WebView) SetShortcutsEnabled(value bool) {\n\twv.shortcutsEnabled = value\n\twv.shortcutsEnabledChangedPublisher.Publish()\n}\n\nfunc (wv *WebView) ShortcutsEnabledChanged() *Event {\n\treturn wv.shortcutsEnabledChangedPublisher.Event()\n}\n\nfunc (wv *WebView) NativeContextMenuEnabled() bool {\n\treturn wv.nativeContextMenuEnabled\n}\n\nfunc (wv *WebView) SetNativeContextMenuEnabled(value bool) {\n\twv.nativeContextMenuEnabled = value\n\twv.nativeContextMenuEnabledChangedPublisher.Publish()\n}\n\nfunc (wv *WebView) NativeContextMenuEnabledChanged() *Event {\n\treturn wv.nativeContextMenuEnabledChangedPublisher.Event()\n}\n\nfunc (wv *WebView) Navigating() *WebViewNavigatingEvent {\n\treturn wv.navigatingPublisher.Event()\n}\n\nfunc (wv *WebView) Navigated() *StringEvent {\n\treturn wv.navigatedPublisher.Event()\n}\n\nfunc (wv *WebView) Downloading() *Event {\n\treturn wv.downloadingPublisher.Event()\n}\n\nfunc (wv *WebView) Downloaded() *Event {\n\treturn wv.downloadedPublisher.Event()\n}\n\nfunc (wv *WebView) DocumentCompleted() *StringEvent {\n\treturn wv.documentCompletedPublisher.Event()\n}\n\nfunc (wv *WebView) NavigatedError() *WebViewNavigatedErrorEvent {\n\treturn wv.navigatedErrorPublisher.Event()\n}\n\nfunc (wv *WebView) NewWindow() *WebViewNewWindowEvent {\n\treturn wv.newWindowPublisher.Event()\n}\n\nfunc (wv *WebView) Quitting() *Event {\n\treturn wv.quittingPublisher.Event()\n}\n\nfunc (wv *WebView) WindowClosing() *WebViewWindowClosingEvent {\n\treturn wv.windowClosingPublisher.Event()\n}\n\nfunc (wv *WebView) StatusBarVisible() bool {\n\treturn wv.statusBarVisible\n}\n\nfunc (wv *WebView) StatusBarVisibleChanged() *Event {\n\treturn wv.statusBarVisibleChangedPublisher.Event()\n}\n\nfunc (wv *WebView) IsTheaterMode() bool {\n\treturn wv.isTheaterMode\n}\n\nfunc (wv *WebView) TheaterModeChanged() *Event {\n\treturn wv.theaterModeChangedPublisher.Event()\n}\n\nfunc (wv *WebView) ToolBarVisible() bool {\n\treturn wv.toolBarVisible\n}\n\nfunc (wv *WebView) ToolBarVisibleChanged() *Event {\n\treturn wv.toolBarVisibleChangedPublisher.Event()\n}\n\nfunc (wv *WebView) BrowserVisible() bool {\n\treturn wv.browserVisible\n}\n\nfunc (wv *WebView) BrowserVisibleChanged() *Event {\n\treturn wv.browserVisibleChangedPublisher.Event()\n}\n\nfunc (wv *WebView) ToolBarEnabled() bool {\n\treturn wv.toolBarEnabled\n}\n\nfunc (wv *WebView) ToolBarEnabledChanged() *Event {\n\treturn wv.toolBarEnabledChangedPublisher.Event()\n}\n\nfunc (wv *WebView) CanGoBack() bool {\n\treturn wv.canGoBack\n}\n\nfunc (wv *WebView) CanGoBackChanged() *Event {\n\treturn wv.canGoBackChangedPublisher.Event()\n}\n\nfunc (wv *WebView) CanGoForward() bool {\n\treturn wv.canGoForward\n}\n\nfunc (wv *WebView) CanGoForwardChanged() *Event {\n\treturn wv.canGoForwardChangedPublisher.Event()\n}\n\nfunc (wv *WebView) ProgressValue() int32 {\n\treturn wv.progressValue\n}\n\nfunc (wv *WebView) ProgressMax() int32 {\n\treturn wv.progressMax\n}\n\nfunc (wv *WebView) ProgressChanged() *Event {\n\treturn wv.progressChangedPublisher.Event()\n}\n\nfunc (wv *WebView) StatusText() string {\n\treturn wv.statusText\n}\n\nfunc (wv *WebView) StatusTextChanged() *Event {\n\treturn wv.statusTextChangedPublisher.Event()\n}\n\nfunc (wv *WebView) DocumentTitle() string {\n\treturn wv.documentTitle\n}\n\nfunc (wv *WebView) DocumentTitleChanged() *Event {\n\treturn wv.documentTitleChangedPublisher.Event()\n}\n\nfunc (wv *WebView) Refresh() error {\n\treturn wv.withWebBrowser2(func(webBrowser2 *win.IWebBrowser2) error {\n\t\tif hr := webBrowser2.Refresh(); win.FAILED(hr) {\n\t\t\treturn errorFromHRESULT(\"IWebBrowser2.Refresh\", hr)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\nfunc (wv *WebView) withWebBrowser2(f func(webBrowser2 *win.IWebBrowser2) error) error {\n\tvar webBrowser2Ptr unsafe.Pointer\n\tif hr := wv.browserObject.QueryInterface(&win.IID_IWebBrowser2, &webBrowser2Ptr); win.FAILED(hr) {\n\t\treturn errorFromHRESULT(\"IOleObject.QueryInterface\", hr)\n\t}\n\twebBrowser2 := (*win.IWebBrowser2)(webBrowser2Ptr)\n\tdefer webBrowser2.Release()\n\n\treturn f(webBrowser2)\n}\n\nfunc (wv *WebView) onResize() {\n\t// FIXME: handle error?\n\twv.withWebBrowser2(func(webBrowser2 *win.IWebBrowser2) error {\n\t\tbounds := wv.ClientBoundsPixels()\n\n\t\twebBrowser2.Put_Left(0)\n\t\twebBrowser2.Put_Top(0)\n\t\twebBrowser2.Put_Width(int32(bounds.Width))\n\t\twebBrowser2.Put_Height(int32(bounds.Height))\n\n\t\treturn nil\n\t})\n}\n\nfunc (wv *WebView) withInPlaceActiveObject(f func(activeObject *win.IOleInPlaceActiveObject) error) error {\n\tif wv.browserObject == nil {\n\t\treturn nil\n\t}\n\twv.withWebBrowser2(func(webBrowser2 *win.IWebBrowser2) error {\n\t\tvar activeObjectPtr unsafe.Pointer\n\t\tif hr := webBrowser2.QueryInterface(&win.IID_IOleInPlaceActiveObject, &activeObjectPtr); win.FAILED(hr) {\n\t\t\treturn errorFromHRESULT(\"WebBowser2.QueryInterface\", hr)\n\t\t}\n\t\tactiveObject := (*win.IOleInPlaceActiveObject)(activeObjectPtr)\n\t\tdefer activeObject.Release()\n\t\treturn f(activeObject)\n\t})\n\treturn nil\n}\n\nfunc (wv *WebView) translateAccelerator(msg *win.MSG) bool {\n\tif wv.shortcutsEnabled {\n\t\thr := wv.inPlaceActiveObjectTranslateAccelerator(msg)\n\t\treturn hr == win.S_OK\n\t}\n\treturn false\n}\n\nfunc (wv *WebView) inPlaceActiveObjectTranslateAccelerator(msg *win.MSG) win.HRESULT {\n\tvar ret win.HRESULT\n\tret = win.S_FALSE\n\twv.withInPlaceActiveObject(func(activeObject *win.IOleInPlaceActiveObject) error {\n\t\thr := activeObject.TranslateAccelerator(msg)\n\t\tif hr == win.S_OK {\n\t\t\tret = win.S_OK\n\t\t}\n\t\treturn nil\n\t})\n\treturn ret\n}\n\nfunc (wv *WebView) inPlaceActiveObjectSetFocus() win.HRESULT {\n\tvar ret win.HRESULT\n\tret = win.S_FALSE\n\twv.withInPlaceActiveObject(func(activeObject *win.IOleInPlaceActiveObject) error {\n\t\tvar hWndActive win.HWND\n\t\thr := activeObject.GetWindow(&hWndActive)\n\t\tif hr != win.S_OK {\n\t\t\treturn nil\n\t\t}\n\t\twin.SetFocus(hWndActive)\n\t\tret = win.S_OK\n\n\t\treturn nil\n\t})\n\treturn ret\n}\n\nfunc (wv *WebView) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\tswitch msg {\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif wv.clientSite.inPlaceSite.inPlaceFrame.webView == nil {\n\t\t\tbreak\n\t\t}\n\n\t\twv.onResize()\n\n\tcase win.WM_MOUSEACTIVATE:\n\t\twv.invalidateBorderInParent()\n\t}\n\n\treturn wv.WidgetBase.WndProc(hwnd, msg, wParam, lParam)\n}\n\nfunc (wv *WebView) CreateLayoutItem(ctx *LayoutContext) LayoutItem {\n\treturn NewGreedyLayoutItem()\n}\n"
  },
  {
    "path": "webview_dwebbrowserevents2.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n)\n\nimport (\n\t\"time\"\n\n\t\"github.com/lxn/win\"\n)\n\nvar webViewDWebBrowserEvents2Vtbl *win.DWebBrowserEvents2Vtbl\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\twebViewDWebBrowserEvents2Vtbl = &win.DWebBrowserEvents2Vtbl{\n\t\t\tsyscall.NewCallback(webView_DWebBrowserEvents2_QueryInterface),\n\t\t\tsyscall.NewCallback(webView_DWebBrowserEvents2_AddRef),\n\t\t\tsyscall.NewCallback(webView_DWebBrowserEvents2_Release),\n\t\t\tsyscall.NewCallback(webView_DWebBrowserEvents2_GetTypeInfoCount),\n\t\t\tsyscall.NewCallback(webView_DWebBrowserEvents2_GetTypeInfo),\n\t\t\tsyscall.NewCallback(webView_DWebBrowserEvents2_GetIDsOfNames),\n\t\t\tsyscall.NewCallback(webView_DWebBrowserEvents2_Invoke),\n\t\t}\n\t})\n}\n\ntype webViewDWebBrowserEvents2 struct {\n\twin.DWebBrowserEvents2\n}\n\nfunc webView_DWebBrowserEvents2_QueryInterface(wbe2 *webViewDWebBrowserEvents2, riid win.REFIID, ppvObject *unsafe.Pointer) uintptr {\n\t// Just reuse the QueryInterface implementation we have for IOleClientSite.\n\t// We need to adjust object, which initially points at our\n\t// webViewDWebBrowserEvents2, so it refers to the containing\n\t// webViewIOleClientSite for the call.\n\tvar clientSite win.IOleClientSite\n\tvar webViewInPlaceSite webViewIOleInPlaceSite\n\tvar docHostUIHandler webViewIDocHostUIHandler\n\n\tptr := uintptr(unsafe.Pointer(wbe2)) -\n\t\tuintptr(unsafe.Sizeof(clientSite)) -\n\t\tuintptr(unsafe.Sizeof(webViewInPlaceSite)) -\n\t\tuintptr(unsafe.Sizeof(docHostUIHandler))\n\n\treturn webView_IOleClientSite_QueryInterface((*webViewIOleClientSite)(unsafe.Pointer(ptr)), riid, ppvObject)\n}\n\nfunc webView_DWebBrowserEvents2_AddRef(args *uintptr) uintptr {\n\treturn 1\n}\n\nfunc webView_DWebBrowserEvents2_Release(args *uintptr) uintptr {\n\treturn 1\n}\n\nfunc webView_DWebBrowserEvents2_GetTypeInfoCount(args *uintptr) uintptr {\n\t/*\tp := (*struct {\n\t\t\twbe2    *webViewDWebBrowserEvents2\n\t\t\tpctinfo *uint\n\t\t})(unsafe.Pointer(args))\n\n\t\t*p.pctinfo = 0\n\n\t\treturn S_OK*/\n\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_DWebBrowserEvents2_GetTypeInfo(args *uintptr) uintptr {\n\t/*\tp := (*struct {\n\t\t\t\twbe2         *webViewDWebBrowserEvents2\n\t\t\t})(unsafe.Pointer(args))\n\n\t\t    unsigned int  iTInfo,\n\t\t    LCID  lcid,\n\t\t    ITypeInfo FAR* FAR*  ppTInfo*/\n\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_DWebBrowserEvents2_GetIDsOfNames(args *uintptr) uintptr {\n\t/*\tp := (*struct {\n\t\twbe2      *webViewDWebBrowserEvents2\n\t\triid      REFIID\n\t\trgszNames **uint16\n\t\tcNames    uint32\n\t\tlcid      LCID\n\t\trgDispId  *DISPID\n\t})(unsafe.Pointer(args))*/\n\n\treturn win.E_NOTIMPL\n}\n\n/*\nfunc webView_DWebBrowserEvents2_Invoke(\n\twbe2 *webViewDWebBrowserEvents2,\n\tdispIdMember win.DISPID,\n\triid win.REFIID,\n\tlcid uint32, // LCID\n\twFlags uint16,\n\tpDispParams *win.DISPPARAMS,\n\tpVarResult *win.VARIANT,\n\tpExcepInfo unsafe.Pointer, // *EXCEPINFO\n\tpuArgErr *uint32) uintptr {\n*/\nfunc webView_DWebBrowserEvents2_Invoke(\n\targ0 uintptr,\n\targ1 uintptr,\n\targ2 uintptr,\n\targ3 uintptr,\n\targ4 uintptr,\n\targ5 uintptr,\n\targ6 uintptr,\n\targ7 uintptr,\n\targ8 uintptr) uintptr {\n\n\twbe2 := (*webViewDWebBrowserEvents2)(unsafe.Pointer(arg0))\n\tdispIdMember := *(*win.DISPID)(unsafe.Pointer(&arg1))\n\t//riid := *(*win.REFIID)(unsafe.Pointer(&arg2))\n\t//lcid := *(*uint32)(unsafe.Pointer(&arg3))\n\t//wFlags := *(*uint16)(unsafe.Pointer(&arg4))\n\tpDispParams := (*win.DISPPARAMS)(unsafe.Pointer(arg5))\n\t//pVarResult := (*win.VARIANT)(unsafe.Pointer(arg6))\n\t//pExcepInfo := unsafe.Pointer(arg7)\n\t//puArgErr := (*uint32)(unsafe.Pointer(arg8))\n\n\tvar wb WidgetBase\n\tvar wvcs webViewIOleClientSite\n\n\twv := (*WebView)(unsafe.Pointer(uintptr(unsafe.Pointer(wbe2)) +\n\t\tuintptr(unsafe.Sizeof(*wbe2)) -\n\t\tuintptr(unsafe.Sizeof(wvcs)) -\n\t\tuintptr(unsafe.Sizeof(wb))))\n\n\tswitch dispIdMember {\n\tcase win.DISPID_BEFORENAVIGATE2:\n\t\trgvargPtr := (*[7]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\teventData := &WebViewNavigatingEventData{\n\t\t\tpDisp:           (*rgvargPtr)[6].MustPDispatch(),\n\t\t\turl:             (*rgvargPtr)[5].MustPVariant(),\n\t\t\tflags:           (*rgvargPtr)[4].MustPVariant(),\n\t\t\ttargetFrameName: (*rgvargPtr)[3].MustPVariant(),\n\t\t\tpostData:        (*rgvargPtr)[2].MustPVariant(),\n\t\t\theaders:         (*rgvargPtr)[1].MustPVariant(),\n\t\t\tcancel:          (*rgvargPtr)[0].MustPBool(),\n\t\t}\n\t\twv.navigatingPublisher.Publish(eventData)\n\n\tcase win.DISPID_NAVIGATECOMPLETE2:\n\t\trgvargPtr := (*[2]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\turl := (*rgvargPtr)[0].MustPVariant()\n\t\turlStr := \"\"\n\t\tif url != nil && url.MustBSTR() != nil {\n\t\t\turlStr = win.BSTRToString(url.MustBSTR())\n\t\t}\n\t\twv.navigatedPublisher.Publish(urlStr)\n\n\t\twv.urlChangedPublisher.Publish()\n\n\tcase win.DISPID_DOWNLOADBEGIN:\n\t\twv.downloadingPublisher.Publish()\n\n\tcase win.DISPID_DOWNLOADCOMPLETE:\n\t\twv.downloadedPublisher.Publish()\n\n\tcase win.DISPID_DOCUMENTCOMPLETE:\n\t\trgvargPtr := (*[2]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\turl := (*rgvargPtr)[0].MustPVariant()\n\t\turlStr := \"\"\n\t\tif url != nil && url.MustBSTR() != nil {\n\t\t\turlStr = win.BSTRToString(url.MustBSTR())\n\t\t}\n\n\t\t// FIXME: Horrible hack to avoid glitch where the document is not displayed.\n\t\ttime.AfterFunc(time.Millisecond*100, func() {\n\t\t\twv.Synchronize(func() {\n\t\t\t\tb := wv.BoundsPixels()\n\t\t\t\tb.Width++\n\t\t\t\twv.SetBoundsPixels(b)\n\t\t\t\tb.Width--\n\t\t\t\twv.SetBoundsPixels(b)\n\t\t\t})\n\t\t})\n\n\t\twv.documentCompletedPublisher.Publish(urlStr)\n\n\tcase win.DISPID_NAVIGATEERROR:\n\t\trgvargPtr := (*[5]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\teventData := &WebViewNavigatedErrorEventData{\n\t\t\tpDisp:           (*rgvargPtr)[4].MustPDispatch(),\n\t\t\turl:             (*rgvargPtr)[3].MustPVariant(),\n\t\t\ttargetFrameName: (*rgvargPtr)[2].MustPVariant(),\n\t\t\tstatusCode:      (*rgvargPtr)[1].MustPVariant(),\n\t\t\tcancel:          (*rgvargPtr)[0].MustPBool(),\n\t\t}\n\t\twv.navigatedErrorPublisher.Publish(eventData)\n\n\tcase win.DISPID_NEWWINDOW3:\n\t\trgvargPtr := (*[5]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\teventData := &WebViewNewWindowEventData{\n\t\t\tppDisp:         (*rgvargPtr)[4].MustPPDispatch(),\n\t\t\tcancel:         (*rgvargPtr)[3].MustPBool(),\n\t\t\tdwFlags:        (*rgvargPtr)[2].MustULong(),\n\t\t\tbstrUrlContext: (*rgvargPtr)[1].MustBSTR(),\n\t\t\tbstrUrl:        (*rgvargPtr)[0].MustBSTR(),\n\t\t}\n\t\twv.newWindowPublisher.Publish(eventData)\n\n\tcase win.DISPID_ONQUIT:\n\t\twv.quittingPublisher.Publish()\n\n\tcase win.DISPID_WINDOWCLOSING:\n\t\trgvargPtr := (*[2]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\teventData := &WebViewWindowClosingEventData{\n\t\t\tbIsChildWindow: (*rgvargPtr)[1].MustBool(),\n\t\t\tcancel:         (*rgvargPtr)[0].MustPBool(),\n\t\t}\n\t\twv.windowClosingPublisher.Publish(eventData)\n\n\tcase win.DISPID_ONSTATUSBAR:\n\t\trgvargPtr := (*[1]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\tstatusBar := (*rgvargPtr)[0].MustBool()\n\t\tif statusBar != win.VARIANT_FALSE {\n\t\t\twv.statusBarVisible = true\n\t\t} else {\n\t\t\twv.statusBarVisible = false\n\t\t}\n\t\twv.statusBarVisibleChangedPublisher.Publish()\n\n\tcase win.DISPID_ONTHEATERMODE:\n\t\trgvargPtr := (*[1]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\ttheaterMode := (*rgvargPtr)[0].MustBool()\n\t\tif theaterMode != win.VARIANT_FALSE {\n\t\t\twv.isTheaterMode = true\n\t\t} else {\n\t\t\twv.isTheaterMode = false\n\t\t}\n\t\twv.theaterModeChangedPublisher.Publish()\n\n\tcase win.DISPID_ONTOOLBAR:\n\t\trgvargPtr := (*[1]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\ttoolBar := (*rgvargPtr)[0].MustBool()\n\t\tif toolBar != win.VARIANT_FALSE {\n\t\t\twv.toolBarVisible = true\n\t\t} else {\n\t\t\twv.toolBarVisible = false\n\t\t}\n\t\twv.toolBarVisibleChangedPublisher.Publish()\n\n\tcase win.DISPID_ONVISIBLE:\n\t\trgvargPtr := (*[1]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\tvVisible := (*rgvargPtr)[0].MustBool()\n\t\tif vVisible != win.VARIANT_FALSE {\n\t\t\twv.browserVisible = true\n\t\t} else {\n\t\t\twv.browserVisible = false\n\t\t}\n\t\twv.browserVisibleChangedPublisher.Publish()\n\n\tcase win.DISPID_COMMANDSTATECHANGE:\n\t\trgvargPtr := (*[2]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\tcommand := (*rgvargPtr)[1].MustLong()\n\t\tenable := (*rgvargPtr)[0].MustBool()\n\t\tenableBool := (enable != win.VARIANT_FALSE)\n\t\tswitch command {\n\t\tcase win.CSC_UPDATECOMMANDS:\n\t\t\twv.toolBarEnabled = enableBool\n\t\t\twv.toolBarEnabledChangedPublisher.Publish()\n\n\t\tcase win.CSC_NAVIGATEFORWARD:\n\t\t\twv.canGoForward = enableBool\n\t\t\twv.canGoForwardChangedPublisher.Publish()\n\n\t\tcase win.CSC_NAVIGATEBACK:\n\t\t\twv.canGoBack = enableBool\n\t\t\twv.canGoBackChangedPublisher.Publish()\n\t\t}\n\n\tcase win.DISPID_PROGRESSCHANGE:\n\t\trgvargPtr := (*[2]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\twv.progressValue = (*rgvargPtr)[1].MustLong()\n\t\twv.progressMax = (*rgvargPtr)[0].MustLong()\n\t\twv.progressChangedPublisher.Publish()\n\n\tcase win.DISPID_STATUSTEXTCHANGE:\n\t\trgvargPtr := (*[1]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\tsText := (*rgvargPtr)[0].MustBSTR()\n\t\tif sText != nil {\n\t\t\twv.statusText = win.BSTRToString(sText)\n\t\t} else {\n\t\t\twv.statusText = \"\"\n\t\t}\n\t\twv.statusTextChangedPublisher.Publish()\n\n\tcase win.DISPID_TITLECHANGE:\n\t\trgvargPtr := (*[1]win.VARIANTARG)(unsafe.Pointer(pDispParams.Rgvarg))\n\t\tsText := (*rgvargPtr)[0].MustBSTR()\n\t\tif sText != nil {\n\t\t\twv.documentTitle = win.BSTRToString(sText)\n\t\t} else {\n\t\t\twv.documentTitle = \"\"\n\t\t}\n\t\twv.documentTitleChangedPublisher.Publish()\n\t}\n\n\treturn win.DISP_E_MEMBERNOTFOUND\n}\n"
  },
  {
    "path": "webview_events.go",
    "content": "// Copyright 2011 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype WebViewNavigatingEventData struct {\n\tpDisp           *win.IDispatch\n\turl             *win.VARIANT\n\tflags           *win.VARIANT\n\ttargetFrameName *win.VARIANT\n\tpostData        *win.VARIANT\n\theaders         *win.VARIANT\n\tcancel          *win.VARIANT_BOOL\n}\n\nfunc (eventData *WebViewNavigatingEventData) Url() string {\n\turl := eventData.url\n\tif url != nil && url.MustBSTR() != nil {\n\t\treturn win.BSTRToString(url.MustBSTR())\n\t}\n\treturn \"\"\n}\n\nfunc (eventData *WebViewNavigatingEventData) Flags() int32 {\n\tflags := eventData.flags\n\tif flags != nil {\n\t\treturn flags.MustLong()\n\t}\n\treturn 0\n}\n\nfunc (eventData *WebViewNavigatingEventData) PostData() string {\n\tpostData := eventData.postData\n\tif postData != nil {\n\t\tpvar := postData.MustPVariant()\n\t\tif pvar != nil && pvar.Vt == win.VT_ARRAY|win.VT_UI1 {\n\t\t\tpsa := pvar.MustPSafeArray()\n\t\t\tif psa != nil && psa.CDims == 1 && psa.CbElements == 1 {\n\t\t\t\tpostDataSize := psa.Rgsabound[0].CElements * psa.CbElements\n\t\t\t\tbyteAryPtr := (*[200000000]byte)(unsafe.Pointer(psa.PvData))\n\t\t\t\tbyteArySlice := (*byteAryPtr)[0 : postDataSize-1]\n\t\t\t\treturn string(byteArySlice)\n\t\t\t}\n\t\t}\n\t}\n\treturn \"\"\n}\n\nfunc (eventData *WebViewNavigatingEventData) Headers() string {\n\theaders := eventData.headers\n\tif headers != nil && headers.MustBSTR() != nil {\n\t\treturn win.BSTRToString(headers.MustBSTR())\n\t}\n\treturn \"\"\n}\n\nfunc (eventData *WebViewNavigatingEventData) TargetFrameName() string {\n\ttargetFrameName := eventData.targetFrameName\n\tif targetFrameName != nil && targetFrameName.MustBSTR() != nil {\n\t\treturn win.BSTRToString(targetFrameName.MustBSTR())\n\t}\n\treturn \"\"\n}\n\nfunc (eventData *WebViewNavigatingEventData) Canceled() bool {\n\tcancel := eventData.cancel\n\tif cancel != nil {\n\t\tif *cancel != win.VARIANT_FALSE {\n\t\t\treturn true\n\t\t} else {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (eventData *WebViewNavigatingEventData) SetCanceled(value bool) {\n\tcancel := eventData.cancel\n\tif cancel != nil {\n\t\tif value {\n\t\t\t*cancel = win.VARIANT_TRUE\n\t\t} else {\n\t\t\t*cancel = win.VARIANT_FALSE\n\t\t}\n\t}\n}\n\ntype WebViewNavigatingEventHandler func(eventData *WebViewNavigatingEventData)\n\ntype WebViewNavigatingEvent struct {\n\thandlers []WebViewNavigatingEventHandler\n}\n\nfunc (e *WebViewNavigatingEvent) Attach(handler WebViewNavigatingEventHandler) int {\n\tfor i, h := range e.handlers {\n\t\tif h == nil {\n\t\t\te.handlers[i] = handler\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handler)\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *WebViewNavigatingEvent) Detach(handle int) {\n\te.handlers[handle] = nil\n}\n\ntype WebViewNavigatingEventPublisher struct {\n\tevent WebViewNavigatingEvent\n}\n\nfunc (p *WebViewNavigatingEventPublisher) Event() *WebViewNavigatingEvent {\n\treturn &p.event\n}\n\nfunc (p *WebViewNavigatingEventPublisher) Publish(eventData *WebViewNavigatingEventData) {\n\tfor _, handler := range p.event.handlers {\n\t\tif handler != nil {\n\t\t\thandler(eventData)\n\t\t}\n\t}\n}\n\ntype WebViewNavigatedErrorEventData struct {\n\tpDisp           *win.IDispatch\n\turl             *win.VARIANT\n\ttargetFrameName *win.VARIANT\n\tstatusCode      *win.VARIANT\n\tcancel          *win.VARIANT_BOOL\n}\n\nfunc (eventData *WebViewNavigatedErrorEventData) Url() string {\n\turl := eventData.url\n\tif url != nil && url.MustBSTR() != nil {\n\t\treturn win.BSTRToString(url.MustBSTR())\n\t}\n\treturn \"\"\n}\n\nfunc (eventData *WebViewNavigatedErrorEventData) TargetFrameName() string {\n\ttargetFrameName := eventData.targetFrameName\n\tif targetFrameName != nil && targetFrameName.MustBSTR() != nil {\n\t\treturn win.BSTRToString(targetFrameName.MustBSTR())\n\t}\n\treturn \"\"\n}\n\nfunc (eventData *WebViewNavigatedErrorEventData) StatusCode() int32 {\n\tstatusCode := eventData.statusCode\n\tif statusCode != nil {\n\t\treturn statusCode.MustLong()\n\t}\n\treturn 0\n}\n\nfunc (eventData *WebViewNavigatedErrorEventData) Canceled() bool {\n\tcancel := eventData.cancel\n\tif cancel != nil {\n\t\tif *cancel != win.VARIANT_FALSE {\n\t\t\treturn true\n\t\t} else {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (eventData *WebViewNavigatedErrorEventData) SetCanceled(value bool) {\n\tcancel := eventData.cancel\n\tif cancel != nil {\n\t\tif value {\n\t\t\t*cancel = win.VARIANT_TRUE\n\t\t} else {\n\t\t\t*cancel = win.VARIANT_FALSE\n\t\t}\n\t}\n}\n\ntype WebViewNavigatedErrorEventHandler func(eventData *WebViewNavigatedErrorEventData)\n\ntype WebViewNavigatedErrorEvent struct {\n\thandlers []WebViewNavigatedErrorEventHandler\n}\n\nfunc (e *WebViewNavigatedErrorEvent) Attach(handler WebViewNavigatedErrorEventHandler) int {\n\tfor i, h := range e.handlers {\n\t\tif h == nil {\n\t\t\te.handlers[i] = handler\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handler)\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *WebViewNavigatedErrorEvent) Detach(handle int) {\n\te.handlers[handle] = nil\n}\n\ntype WebViewNavigatedErrorEventPublisher struct {\n\tevent WebViewNavigatedErrorEvent\n}\n\nfunc (p *WebViewNavigatedErrorEventPublisher) Event() *WebViewNavigatedErrorEvent {\n\treturn &p.event\n}\n\nfunc (p *WebViewNavigatedErrorEventPublisher) Publish(eventData *WebViewNavigatedErrorEventData) {\n\tfor _, handler := range p.event.handlers {\n\t\tif handler != nil {\n\t\t\thandler(eventData)\n\t\t}\n\t}\n}\n\ntype WebViewNewWindowEventData struct {\n\tppDisp         **win.IDispatch\n\tcancel         *win.VARIANT_BOOL\n\tdwFlags        uint32\n\tbstrUrlContext *uint16\n\tbstrUrl        *uint16\n}\n\nfunc (eventData *WebViewNewWindowEventData) Canceled() bool {\n\tcancel := eventData.cancel\n\tif cancel != nil {\n\t\tif *cancel != win.VARIANT_FALSE {\n\t\t\treturn true\n\t\t} else {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (eventData *WebViewNewWindowEventData) SetCanceled(value bool) {\n\tcancel := eventData.cancel\n\tif cancel != nil {\n\t\tif value {\n\t\t\t*cancel = win.VARIANT_TRUE\n\t\t} else {\n\t\t\t*cancel = win.VARIANT_FALSE\n\t\t}\n\t}\n}\n\nfunc (eventData *WebViewNewWindowEventData) Flags() uint32 {\n\treturn eventData.dwFlags\n}\n\nfunc (eventData *WebViewNewWindowEventData) UrlContext() string {\n\tbstrUrlContext := eventData.bstrUrlContext\n\tif bstrUrlContext != nil {\n\t\treturn win.BSTRToString(bstrUrlContext)\n\t}\n\treturn \"\"\n}\n\nfunc (eventData *WebViewNewWindowEventData) Url() string {\n\tbstrUrl := eventData.bstrUrl\n\tif bstrUrl != nil {\n\t\treturn win.BSTRToString(bstrUrl)\n\t}\n\treturn \"\"\n}\n\ntype WebViewNewWindowEventHandler func(eventData *WebViewNewWindowEventData)\n\ntype WebViewNewWindowEvent struct {\n\thandlers []WebViewNewWindowEventHandler\n}\n\nfunc (e *WebViewNewWindowEvent) Attach(handler WebViewNewWindowEventHandler) int {\n\tfor i, h := range e.handlers {\n\t\tif h == nil {\n\t\t\te.handlers[i] = handler\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handler)\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *WebViewNewWindowEvent) Detach(handle int) {\n\te.handlers[handle] = nil\n}\n\ntype WebViewNewWindowEventPublisher struct {\n\tevent WebViewNewWindowEvent\n}\n\nfunc (p *WebViewNewWindowEventPublisher) Event() *WebViewNewWindowEvent {\n\treturn &p.event\n}\n\nfunc (p *WebViewNewWindowEventPublisher) Publish(eventData *WebViewNewWindowEventData) {\n\tfor _, handler := range p.event.handlers {\n\t\tif handler != nil {\n\t\t\thandler(eventData)\n\t\t}\n\t}\n}\n\ntype WebViewWindowClosingEventData struct {\n\tbIsChildWindow win.VARIANT_BOOL\n\tcancel         *win.VARIANT_BOOL\n}\n\nfunc (eventData *WebViewWindowClosingEventData) IsChildWindow() bool {\n\tbIsChildWindow := eventData.bIsChildWindow\n\tif bIsChildWindow != win.VARIANT_FALSE {\n\t\treturn true\n\t} else {\n\t\treturn false\n\t}\n\treturn false\n}\n\nfunc (eventData *WebViewWindowClosingEventData) Canceled() bool {\n\tcancel := eventData.cancel\n\tif cancel != nil {\n\t\tif *cancel != win.VARIANT_FALSE {\n\t\t\treturn true\n\t\t} else {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (eventData *WebViewWindowClosingEventData) SetCanceled(value bool) {\n\tcancel := eventData.cancel\n\tif cancel != nil {\n\t\tif value {\n\t\t\t*cancel = win.VARIANT_TRUE\n\t\t} else {\n\t\t\t*cancel = win.VARIANT_FALSE\n\t\t}\n\t}\n}\n\ntype WebViewWindowClosingEventHandler func(eventData *WebViewWindowClosingEventData)\n\ntype WebViewWindowClosingEvent struct {\n\thandlers []WebViewWindowClosingEventHandler\n}\n\nfunc (e *WebViewWindowClosingEvent) Attach(handler WebViewWindowClosingEventHandler) int {\n\tfor i, h := range e.handlers {\n\t\tif h == nil {\n\t\t\te.handlers[i] = handler\n\t\t\treturn i\n\t\t}\n\t}\n\n\te.handlers = append(e.handlers, handler)\n\treturn len(e.handlers) - 1\n}\n\nfunc (e *WebViewWindowClosingEvent) Detach(handle int) {\n\te.handlers[handle] = nil\n}\n\ntype WebViewWindowClosingEventPublisher struct {\n\tevent WebViewWindowClosingEvent\n}\n\nfunc (p *WebViewWindowClosingEventPublisher) Event() *WebViewWindowClosingEvent {\n\treturn &p.event\n}\n\nfunc (p *WebViewWindowClosingEventPublisher) Publish(eventData *WebViewWindowClosingEventData) {\n\tfor _, handler := range p.event.handlers {\n\t\tif handler != nil {\n\t\t\thandler(eventData)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "webview_idochostuihandler.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\nvar webViewIDocHostUIHandlerVtbl *win.IDocHostUIHandlerVtbl\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\twebViewIDocHostUIHandlerVtbl = &win.IDocHostUIHandlerVtbl{\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_QueryInterface),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_AddRef),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_Release),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_ShowContextMenu),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_GetHostInfo),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_ShowUI),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_HideUI),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_UpdateUI),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_EnableModeless),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_OnDocWindowActivate),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_OnFrameWindowActivate),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_ResizeBorder),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_TranslateAccelerator),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_GetOptionKeyPath),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_GetDropTarget),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_GetExternal),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_TranslateUrl),\n\t\t\tsyscall.NewCallback(webView_IDocHostUIHandler_FilterDataObject),\n\t\t}\n\t})\n}\n\ntype webViewIDocHostUIHandler struct {\n\twin.IDocHostUIHandler\n}\n\nfunc webView_IDocHostUIHandler_QueryInterface(docHostUIHandler *webViewIDocHostUIHandler, riid win.REFIID, ppvObject *unsafe.Pointer) uintptr {\n\t// Just reuse the QueryInterface implementation we have for IOleClientSite.\n\t// We need to adjust object, which initially points at our\n\t// webViewIDocHostUIHandler, so it refers to the containing\n\t// webViewIOleClientSite for the call.\n\tvar clientSite win.IOleClientSite\n\tvar webViewInPlaceSite webViewIOleInPlaceSite\n\n\tptr := uintptr(unsafe.Pointer(docHostUIHandler)) - uintptr(unsafe.Sizeof(clientSite)) -\n\t\tuintptr(unsafe.Sizeof(webViewInPlaceSite))\n\n\treturn webView_IOleClientSite_QueryInterface((*webViewIOleClientSite)(unsafe.Pointer(ptr)), riid, ppvObject)\n}\n\nfunc webView_IDocHostUIHandler_AddRef(docHostUIHandler *webViewIDocHostUIHandler) uintptr {\n\treturn 1\n}\n\nfunc webView_IDocHostUIHandler_Release(docHostUIHandler *webViewIDocHostUIHandler) uintptr {\n\treturn 1\n}\n\nfunc webView_IDocHostUIHandler_ShowContextMenu(docHostUIHandler *webViewIDocHostUIHandler, dwID uint32, ppt *win.POINT, pcmdtReserved *win.IUnknown, pdispReserved uintptr) uintptr {\n\tvar webViewInPlaceSite webViewIOleInPlaceSite\n\tvar iOleClientSite win.IOleClientSite\n\tvar wb WidgetBase\n\tptr := uintptr(unsafe.Pointer(docHostUIHandler)) -\n\t\tuintptr(unsafe.Sizeof(webViewInPlaceSite)) -\n\t\tuintptr(unsafe.Sizeof(iOleClientSite)) -\n\t\tuintptr(unsafe.Sizeof(wb))\n\twebView := (*WebView)(unsafe.Pointer(ptr))\n\n\t// show context menu\n\tif webView.NativeContextMenuEnabled() {\n\t\treturn win.S_FALSE\n\t}\n\n\treturn win.S_OK\n}\n\nfunc webView_IDocHostUIHandler_GetHostInfo(docHostUIHandler *webViewIDocHostUIHandler, pInfo *win.DOCHOSTUIINFO) uintptr {\n\tpInfo.CbSize = uint32(unsafe.Sizeof(*pInfo))\n\tpInfo.DwFlags = win.DOCHOSTUIFLAG_NO3DBORDER\n\tpInfo.DwDoubleClick = win.DOCHOSTUIDBLCLK_DEFAULT\n\n\treturn win.S_OK\n}\n\nfunc webView_IDocHostUIHandler_ShowUI(docHostUIHandler *webViewIDocHostUIHandler, dwID uint32, pActiveObject uintptr, pCommandTarget uintptr, pFrame *win.IOleInPlaceFrame, pDoc uintptr) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IDocHostUIHandler_HideUI(docHostUIHandler *webViewIDocHostUIHandler) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IDocHostUIHandler_UpdateUI(docHostUIHandler *webViewIDocHostUIHandler) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IDocHostUIHandler_EnableModeless(docHostUIHandler *webViewIDocHostUIHandler, fEnable win.BOOL) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IDocHostUIHandler_OnDocWindowActivate(docHostUIHandler *webViewIDocHostUIHandler, fActivate win.BOOL) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IDocHostUIHandler_OnFrameWindowActivate(docHostUIHandler *webViewIDocHostUIHandler, fActivate win.BOOL) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IDocHostUIHandler_ResizeBorder(docHostUIHandler *webViewIDocHostUIHandler, prcBorder *win.RECT, pUIWindow uintptr, fRameWindow win.BOOL) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IDocHostUIHandler_TranslateAccelerator(docHostUIHandler *webViewIDocHostUIHandler, lpMsg *win.MSG, pguidCmdGroup *syscall.GUID, nCmdID uint) uintptr {\n\treturn win.S_FALSE\n}\n\nfunc webView_IDocHostUIHandler_GetOptionKeyPath(docHostUIHandler *webViewIDocHostUIHandler, pchKey *uint16, dw uint) uintptr {\n\treturn win.S_FALSE\n}\n\nfunc webView_IDocHostUIHandler_GetDropTarget(docHostUIHandler *webViewIDocHostUIHandler, pDropTarget uintptr, ppDropTarget *uintptr) uintptr {\n\treturn win.S_FALSE\n}\n\nfunc webView_IDocHostUIHandler_GetExternal(docHostUIHandler *webViewIDocHostUIHandler, ppDispatch *uintptr) uintptr {\n\t*ppDispatch = 0\n\n\treturn win.S_FALSE\n}\n\nfunc webView_IDocHostUIHandler_TranslateUrl(docHostUIHandler *webViewIDocHostUIHandler, dwTranslate uint32, pchURLIn *uint16, ppchURLOut **uint16) uintptr {\n\t*ppchURLOut = nil\n\n\treturn win.S_FALSE\n}\n\nfunc webView_IDocHostUIHandler_FilterDataObject(docHostUIHandler *webViewIDocHostUIHandler, pDO uintptr, ppDORet *uintptr) uintptr {\n\t*ppDORet = 0\n\n\treturn win.S_FALSE\n}\n"
  },
  {
    "path": "webview_ioleclientsite.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\nvar webViewIOleClientSiteVtbl *win.IOleClientSiteVtbl\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\twebViewIOleClientSiteVtbl = &win.IOleClientSiteVtbl{\n\t\t\tsyscall.NewCallback(webView_IOleClientSite_QueryInterface),\n\t\t\tsyscall.NewCallback(webView_IOleClientSite_AddRef),\n\t\t\tsyscall.NewCallback(webView_IOleClientSite_Release),\n\t\t\tsyscall.NewCallback(webView_IOleClientSite_SaveObject),\n\t\t\tsyscall.NewCallback(webView_IOleClientSite_GetMoniker),\n\t\t\tsyscall.NewCallback(webView_IOleClientSite_GetContainer),\n\t\t\tsyscall.NewCallback(webView_IOleClientSite_ShowObject),\n\t\t\tsyscall.NewCallback(webView_IOleClientSite_OnShowWindow),\n\t\t\tsyscall.NewCallback(webView_IOleClientSite_RequestNewObjectLayout),\n\t\t}\n\t})\n}\n\ntype webViewIOleClientSite struct {\n\twin.IOleClientSite\n\tinPlaceSite       webViewIOleInPlaceSite\n\tdocHostUIHandler  webViewIDocHostUIHandler\n\twebBrowserEvents2 webViewDWebBrowserEvents2\n}\n\nfunc webView_IOleClientSite_QueryInterface(clientSite *webViewIOleClientSite, riid win.REFIID, ppvObject *unsafe.Pointer) uintptr {\n\tif win.EqualREFIID(riid, &win.IID_IUnknown) {\n\t\t*ppvObject = unsafe.Pointer(clientSite)\n\t} else if win.EqualREFIID(riid, &win.IID_IOleClientSite) {\n\t\t*ppvObject = unsafe.Pointer(clientSite)\n\t} else if win.EqualREFIID(riid, &win.IID_IOleInPlaceSite) {\n\t\t*ppvObject = unsafe.Pointer(&clientSite.inPlaceSite)\n\t} else if win.EqualREFIID(riid, &win.IID_IDocHostUIHandler) {\n\t\t*ppvObject = unsafe.Pointer(&clientSite.docHostUIHandler)\n\t} else if win.EqualREFIID(riid, &win.DIID_DWebBrowserEvents2) {\n\t\t*ppvObject = unsafe.Pointer(&clientSite.webBrowserEvents2)\n\t} else {\n\t\t*ppvObject = nil\n\t\treturn win.E_NOINTERFACE\n\t}\n\n\treturn win.S_OK\n}\n\nfunc webView_IOleClientSite_AddRef(clientSite *webViewIOleClientSite) uintptr {\n\treturn 1\n}\n\nfunc webView_IOleClientSite_Release(clientSite *webViewIOleClientSite) uintptr {\n\treturn 1\n}\n\nfunc webView_IOleClientSite_SaveObject(clientSite *webViewIOleClientSite) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleClientSite_GetMoniker(clientSite *webViewIOleClientSite, dwAssign, dwWhichMoniker uint32, ppmk *unsafe.Pointer) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleClientSite_GetContainer(clientSite *webViewIOleClientSite, ppContainer *unsafe.Pointer) uintptr {\n\t*ppContainer = nil\n\n\treturn win.E_NOINTERFACE\n}\n\nfunc webView_IOleClientSite_ShowObject(clientSite *webViewIOleClientSite) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IOleClientSite_OnShowWindow(clientSite *webViewIOleClientSite, fShow win.BOOL) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleClientSite_RequestNewObjectLayout(clientSite *webViewIOleClientSite) uintptr {\n\treturn win.E_NOTIMPL\n}\n"
  },
  {
    "path": "webview_ioleinplaceframe.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\nvar webViewIOleInPlaceFrameVtbl *win.IOleInPlaceFrameVtbl\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\twebViewIOleInPlaceFrameVtbl = &win.IOleInPlaceFrameVtbl{\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_QueryInterface),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_AddRef),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_Release),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_GetWindow),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_ContextSensitiveHelp),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_GetBorder),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_RequestBorderSpace),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_SetBorderSpace),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_SetActiveObject),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_InsertMenus),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_SetMenu),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_RemoveMenus),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_SetStatusText),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_EnableModeless),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceFrame_TranslateAccelerator),\n\t\t}\n\t})\n}\n\ntype webViewIOleInPlaceFrame struct {\n\twin.IOleInPlaceFrame\n\twebView *WebView\n}\n\nfunc webView_IOleInPlaceFrame_QueryInterface(inPlaceFrame *webViewIOleInPlaceFrame, riid win.REFIID, ppvObj *uintptr) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceFrame_AddRef(inPlaceFrame *webViewIOleInPlaceFrame) uintptr {\n\treturn 1\n}\n\nfunc webView_IOleInPlaceFrame_Release(inPlaceFrame *webViewIOleInPlaceFrame) uintptr {\n\treturn 1\n}\n\nfunc webView_IOleInPlaceFrame_GetWindow(inPlaceFrame *webViewIOleInPlaceFrame, lphwnd *win.HWND) uintptr {\n\t*lphwnd = inPlaceFrame.webView.hWnd\n\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceFrame_ContextSensitiveHelp(inPlaceFrame *webViewIOleInPlaceFrame, fEnterMode win.BOOL) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceFrame_GetBorder(inPlaceFrame *webViewIOleInPlaceFrame, lprectBorder *win.RECT) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceFrame_RequestBorderSpace(inPlaceFrame *webViewIOleInPlaceFrame, pborderwidths uintptr) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceFrame_SetBorderSpace(inPlaceFrame *webViewIOleInPlaceFrame, pborderwidths uintptr) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceFrame_SetActiveObject(inPlaceFrame *webViewIOleInPlaceFrame, pActiveObject uintptr, pszObjName *uint16) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceFrame_InsertMenus(inPlaceFrame *webViewIOleInPlaceFrame, hmenuShared win.HMENU, lpMenuWidths uintptr) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceFrame_SetMenu(inPlaceFrame *webViewIOleInPlaceFrame, hmenuShared win.HMENU, holemenu win.HMENU, hwndActiveObject win.HWND) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceFrame_RemoveMenus(inPlaceFrame *webViewIOleInPlaceFrame, hmenuShared win.HMENU) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceFrame_SetStatusText(inPlaceFrame *webViewIOleInPlaceFrame, pszStatusText *uint16) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceFrame_EnableModeless(inPlaceFrame *webViewIOleInPlaceFrame, fEnable win.BOOL) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceFrame_TranslateAccelerator(inPlaceFrame *webViewIOleInPlaceFrame, lpmsg *win.MSG, wID uint32) uintptr {\n\treturn win.E_NOTIMPL\n}\n"
  },
  {
    "path": "webview_ioleinplacesite.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n)\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\nvar webViewIOleInPlaceSiteVtbl *win.IOleInPlaceSiteVtbl\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\twebViewIOleInPlaceSiteVtbl = &win.IOleInPlaceSiteVtbl{\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_QueryInterface),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_AddRef),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_Release),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_GetWindow),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_ContextSensitiveHelp),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_CanInPlaceActivate),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_OnInPlaceActivate),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_OnUIActivate),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_GetWindowContext),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_Scroll),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_OnUIDeactivate),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_OnInPlaceDeactivate),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_DiscardUndoState),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_DeactivateAndUndo),\n\t\t\tsyscall.NewCallback(webView_IOleInPlaceSite_OnPosRectChange),\n\t\t}\n\t})\n}\n\ntype webViewIOleInPlaceSite struct {\n\twin.IOleInPlaceSite\n\tinPlaceFrame webViewIOleInPlaceFrame\n}\n\nfunc webView_IOleInPlaceSite_QueryInterface(inPlaceSite *webViewIOleInPlaceSite, riid win.REFIID, ppvObject *unsafe.Pointer) uintptr {\n\t// Just reuse the QueryInterface implementation we have for IOleClientSite.\n\t// We need to adjust object from the webViewIDocHostUIHandler to the\n\t// containing webViewIOleInPlaceSite.\n\tvar clientSite win.IOleClientSite\n\n\tptr := uintptr(unsafe.Pointer(inPlaceSite)) - uintptr(unsafe.Sizeof(clientSite))\n\n\treturn webView_IOleClientSite_QueryInterface((*webViewIOleClientSite)(unsafe.Pointer(ptr)), riid, ppvObject)\n}\n\nfunc webView_IOleInPlaceSite_AddRef(inPlaceSite *webViewIOleInPlaceSite) uintptr {\n\treturn 1\n}\n\nfunc webView_IOleInPlaceSite_Release(inPlaceSite *webViewIOleInPlaceSite) uintptr {\n\treturn 1\n}\n\nfunc webView_IOleInPlaceSite_GetWindow(inPlaceSite *webViewIOleInPlaceSite, lphwnd *win.HWND) uintptr {\n\t*lphwnd = inPlaceSite.inPlaceFrame.webView.hWnd\n\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceSite_ContextSensitiveHelp(inPlaceSite *webViewIOleInPlaceSite, fEnterMode win.BOOL) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceSite_CanInPlaceActivate(inPlaceSite *webViewIOleInPlaceSite) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceSite_OnInPlaceActivate(inPlaceSite *webViewIOleInPlaceSite) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceSite_OnUIActivate(inPlaceSite *webViewIOleInPlaceSite) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceSite_GetWindowContext(inPlaceSite *webViewIOleInPlaceSite, lplpFrame **webViewIOleInPlaceFrame, lplpDoc *uintptr, lprcPosRect, lprcClipRect *win.RECT, lpFrameInfo *win.OLEINPLACEFRAMEINFO) uintptr {\n\t*lplpFrame = &inPlaceSite.inPlaceFrame\n\t*lplpDoc = 0\n\n\tlpFrameInfo.FMDIApp = win.FALSE\n\tlpFrameInfo.HwndFrame = inPlaceSite.inPlaceFrame.webView.hWnd\n\tlpFrameInfo.Haccel = 0\n\tlpFrameInfo.CAccelEntries = 0\n\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceSite_Scroll(inPlaceSite *webViewIOleInPlaceSite, scrollExtentX, scrollExtentY int32) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceSite_OnUIDeactivate(inPlaceSite *webViewIOleInPlaceSite, fUndoable win.BOOL) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceSite_OnInPlaceDeactivate(inPlaceSite *webViewIOleInPlaceSite) uintptr {\n\treturn win.S_OK\n}\n\nfunc webView_IOleInPlaceSite_DiscardUndoState(inPlaceSite *webViewIOleInPlaceSite) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceSite_DeactivateAndUndo(inPlaceSite *webViewIOleInPlaceSite) uintptr {\n\treturn win.E_NOTIMPL\n}\n\nfunc webView_IOleInPlaceSite_OnPosRectChange(inPlaceSite *webViewIOleInPlaceSite, lprcPosRect *win.RECT) uintptr {\n\tbrowserObject := inPlaceSite.inPlaceFrame.webView.browserObject\n\tvar inPlaceObjectPtr unsafe.Pointer\n\tif hr := browserObject.QueryInterface(&win.IID_IOleInPlaceObject, &inPlaceObjectPtr); win.FAILED(hr) {\n\t\treturn uintptr(hr)\n\t}\n\tinPlaceObject := (*win.IOleInPlaceObject)(inPlaceObjectPtr)\n\tdefer inPlaceObject.Release()\n\n\treturn uintptr(inPlaceObject.SetObjectRects(lprcPosRect, lprcPosRect))\n}\n"
  },
  {
    "path": "widget.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\n// LayoutFlags specify how a Widget wants to be treated when used with a Layout.\n//\n// These flags are interpreted in respect to Widget.SizeHint.\ntype LayoutFlags byte\n\nconst (\n\t// ShrinkableHorz allows a Widget to be shrunk horizontally.\n\tShrinkableHorz LayoutFlags = 1 << iota\n\n\t// ShrinkableVert allows a Widget to be shrunk vertically.\n\tShrinkableVert\n\n\t// GrowableHorz allows a Widget to be enlarged horizontally.\n\tGrowableHorz\n\n\t// GrowableVert allows a Widget to be enlarged vertically.\n\tGrowableVert\n\n\t// GreedyHorz specifies that the widget prefers to take up as much space as\n\t// possible, horizontally.\n\tGreedyHorz\n\n\t// GreedyVert specifies that the widget prefers to take up as much space as\n\t// possible, vertically.\n\tGreedyVert\n)\n\ntype Widget interface {\n\tWindow\n\n\t// Alignment returns the alignment of the Widget.\n\tAlignment() Alignment2D\n\n\t// AlwaysConsumeSpace returns if the Widget should consume space even if it\n\t// is not visible.\n\tAlwaysConsumeSpace() bool\n\n\t// AsWidgetBase returns a *WidgetBase that implements Widget.\n\tAsWidgetBase() *WidgetBase\n\n\t// CreateLayoutItem creates and returns a new LayoutItem specific to the\n\t// concrete Widget type, that carries all data and logic required to layout\n\t// the Widget.\n\tCreateLayoutItem(ctx *LayoutContext) LayoutItem\n\n\t// GraphicsEffects returns a list of WidgetGraphicsEffects that are applied to the Widget.\n\tGraphicsEffects() *WidgetGraphicsEffectList\n\n\t// LayoutFlags returns a combination of LayoutFlags that specify how the\n\t// Widget wants to be treated by Layout implementations.\n\tLayoutFlags() LayoutFlags\n\n\t// MinSizeHint returns the minimum outer size in native pixels, including decorations, that\n\t// makes sense for the respective type of Widget.\n\tMinSizeHint() Size\n\n\t// Parent returns the Container of the Widget.\n\tParent() Container\n\n\t// SetAlignment sets the alignment of the widget.\n\tSetAlignment(alignment Alignment2D) error\n\n\t// SetAlwaysConsumeSpace sets if the Widget should consume space even if it\n\t// is not visible.\n\tSetAlwaysConsumeSpace(b bool) error\n\n\t// SetParent sets the parent of the Widget and adds the Widget to the\n\t// Children list of the Container.\n\tSetParent(value Container) error\n\n\t// SetToolTipText sets the tool tip text of the Widget.\n\tSetToolTipText(s string) error\n\n\t// SizeHint returns the preferred size in native pixels for the respective type of Widget.\n\tSizeHint() Size\n\n\t// ToolTipText returns the tool tip text of the Widget.\n\tToolTipText() string\n}\n\ntype WidgetBase struct {\n\tWindowBase\n\tgeometry                    Geometry\n\tparent                      Container\n\ttoolTipTextProperty         Property\n\ttoolTipTextChangedPublisher EventPublisher\n\tgraphicsEffects             *WidgetGraphicsEffectList\n\talignment                   Alignment2D\n\talwaysConsumeSpace          bool\n}\n\n// InitWidget initializes a Widget.\nfunc InitWidget(widget Widget, parent Window, className string, style, exStyle uint32) error {\n\tif parent == nil {\n\t\treturn newError(\"parent cannot be nil\")\n\t}\n\n\tif err := InitWindow(widget, parent, className, style|win.WS_CHILD, exStyle); err != nil {\n\t\treturn err\n\t}\n\n\tif container, ok := parent.(Container); ok {\n\t\tif container.Children() == nil {\n\t\t\t// Required by parents like MainWindow and GroupBox.\n\t\t\tif win.SetParent(widget.Handle(), container.Handle()) == 0 {\n\t\t\t\treturn lastError(\"SetParent\")\n\t\t\t}\n\t\t} else {\n\t\t\tif err := container.Children().Add(widget); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (wb *WidgetBase) init(widget Widget) error {\n\twb.graphicsEffects = newWidgetGraphicsEffectList(wb)\n\n\ttt, err := wb.group.CreateToolTip()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := tt.AddTool(wb.window.(Widget)); err != nil {\n\t\treturn err\n\t}\n\n\twb.toolTipTextProperty = NewProperty(\n\t\tfunc() interface{} {\n\t\t\treturn wb.window.(Widget).ToolTipText()\n\t\t},\n\t\tfunc(v interface{}) error {\n\t\t\twb.window.(Widget).SetToolTipText(assertStringOr(v, \"\"))\n\t\t\treturn nil\n\t\t},\n\t\twb.toolTipTextChangedPublisher.Event())\n\n\twb.MustRegisterProperty(\"ToolTipText\", wb.toolTipTextProperty)\n\n\treturn nil\n}\n\nfunc (wb *WidgetBase) Dispose() {\n\tif wb.hWnd == 0 {\n\t\treturn\n\t}\n\n\tif wb.parent != nil && win.GetParent(wb.hWnd) == wb.parent.Handle() {\n\t\twb.SetParent(nil)\n\t}\n\n\tif tt := wb.group.ToolTip(); tt != nil {\n\t\ttt.RemoveTool(wb.window.(Widget))\n\t}\n\n\twb.WindowBase.Dispose()\n}\n\n// AsWidgetBase just returns the receiver.\nfunc (wb *WidgetBase) AsWidgetBase() *WidgetBase {\n\treturn wb\n}\n\n// Bounds returns the outer bounding box rectangle of the WidgetBase, including\n// decorations.\n//\n// The coordinates are relative to the parent of the Widget.\nfunc (wb *WidgetBase) Bounds() Rectangle {\n\treturn wb.RectangleTo96DPI(wb.BoundsPixels())\n}\n\n// BoundsPixels returns the outer bounding box rectangle of the WidgetBase, including\n// decorations.\n//\n// The coordinates are relative to the parent of the Widget.\nfunc (wb *WidgetBase) BoundsPixels() Rectangle {\n\tb := wb.WindowBase.BoundsPixels()\n\n\tif wb.parent != nil {\n\t\tp := b.Location().toPOINT()\n\t\tif !win.ScreenToClient(wb.parent.Handle(), &p) {\n\t\t\tnewError(\"ScreenToClient failed\")\n\t\t\treturn Rectangle{}\n\t\t}\n\t\tb.X = int(p.X)\n\t\tb.Y = int(p.Y)\n\t}\n\n\treturn b\n}\n\n// BringToTop moves the WidgetBase to the top of the keyboard focus order.\nfunc (wb *WidgetBase) BringToTop() error {\n\tif wb.parent != nil {\n\t\tif err := wb.parent.BringToTop(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn wb.WindowBase.BringToTop()\n}\n\n// Enabled returns if the WidgetBase is enabled for user interaction.\nfunc (wb *WidgetBase) Enabled() bool {\n\tif wb.parent != nil {\n\t\treturn wb.enabled && wb.parent.Enabled()\n\t}\n\n\treturn wb.enabled\n}\n\n// Font returns the Font of the WidgetBase.\n//\n// By default this is a MS Shell Dlg 2, 8 point font.\nfunc (wb *WidgetBase) Font() *Font {\n\tif wb.font != nil {\n\t\treturn wb.font\n\t} else if wb.parent != nil {\n\t\treturn wb.parent.Font()\n\t}\n\n\treturn defaultFont\n}\n\nfunc (wb *WidgetBase) applyFont(font *Font) {\n\twb.WindowBase.applyFont(font)\n\n\twb.RequestLayout()\n}\n\n// Alignment return the alignment ot the *WidgetBase.\nfunc (wb *WidgetBase) Alignment() Alignment2D {\n\treturn wb.alignment\n}\n\n// SetAlignment sets the alignment of the *WidgetBase.\nfunc (wb *WidgetBase) SetAlignment(alignment Alignment2D) error {\n\tif alignment != wb.alignment {\n\t\tif alignment < AlignHVDefault || alignment > AlignHFarVFar {\n\t\t\treturn newError(\"invalid Alignment value\")\n\t\t}\n\n\t\twb.alignment = alignment\n\n\t\twb.RequestLayout()\n\t}\n\n\treturn nil\n}\n\n// SetMinMaxSize sets the minimum and maximum outer size of the *WidgetBase,\n// including decorations.\n//\n// Use walk.Size{} to make the respective limit be ignored.\nfunc (wb *WidgetBase) SetMinMaxSize(min, max Size) (err error) {\n\terr = wb.WindowBase.SetMinMaxSize(min, max)\n\n\twb.RequestLayout()\n\n\treturn\n}\n\n// AlwaysConsumeSpace returns if the Widget should consume space even if it is\n// not visible.\nfunc (wb *WidgetBase) AlwaysConsumeSpace() bool {\n\treturn wb.alwaysConsumeSpace\n}\n\n// SetAlwaysConsumeSpace sets if the Widget should consume space even if it is\n// not visible.\nfunc (wb *WidgetBase) SetAlwaysConsumeSpace(b bool) error {\n\twb.alwaysConsumeSpace = b\n\n\twb.RequestLayout()\n\n\treturn nil\n}\n\n// Parent returns the Container of the WidgetBase.\nfunc (wb *WidgetBase) Parent() Container {\n\treturn wb.parent\n}\n\n// SetParent sets the parent of the WidgetBase and adds the WidgetBase to the\n// Children list of the Container.\nfunc (wb *WidgetBase) SetParent(parent Container) (err error) {\n\tif parent == wb.parent {\n\t\treturn nil\n\t}\n\n\tstyle := uint32(win.GetWindowLong(wb.hWnd, win.GWL_STYLE))\n\tif style == 0 {\n\t\treturn lastError(\"GetWindowLong\")\n\t}\n\n\tif parent == nil {\n\t\twb.SetVisible(false)\n\n\t\tstyle &^= win.WS_CHILD\n\t\tstyle |= win.WS_POPUP\n\n\t\tif win.SetParent(wb.hWnd, 0) == 0 {\n\t\t\treturn lastError(\"SetParent\")\n\t\t}\n\t\twin.SetLastError(0)\n\t\tif win.SetWindowLong(wb.hWnd, win.GWL_STYLE, int32(style)) == 0 {\n\t\t\treturn lastError(\"SetWindowLong\")\n\t\t}\n\t} else {\n\t\tstyle |= win.WS_CHILD\n\t\tstyle &^= win.WS_POPUP\n\n\t\twin.SetLastError(0)\n\t\tif win.SetWindowLong(wb.hWnd, win.GWL_STYLE, int32(style)) == 0 {\n\t\t\treturn lastError(\"SetWindowLong\")\n\t\t}\n\t\tif win.SetParent(wb.hWnd, parent.Handle()) == 0 {\n\t\t\treturn lastError(\"SetParent\")\n\t\t}\n\n\t\tif cb := parent.AsContainerBase(); cb != nil {\n\t\t\twin.SetWindowLong(wb.hWnd, win.GWL_ID, cb.NextChildID())\n\t\t}\n\t}\n\n\tb := wb.BoundsPixels()\n\n\tif !win.SetWindowPos(\n\t\twb.hWnd,\n\t\twin.HWND_BOTTOM,\n\t\tint32(b.X),\n\t\tint32(b.Y),\n\t\tint32(b.Width),\n\t\tint32(b.Height),\n\t\twin.SWP_FRAMECHANGED) {\n\n\t\treturn lastError(\"SetWindowPos\")\n\t}\n\n\toldParent := wb.parent\n\n\twb.parent = parent\n\n\tvar oldChildren, newChildren *WidgetList\n\tif oldParent != nil {\n\t\toldChildren = oldParent.Children()\n\t}\n\tif parent != nil {\n\t\tnewChildren = parent.Children()\n\t}\n\n\tif newChildren == oldChildren {\n\t\treturn nil\n\t}\n\n\twidget := wb.window.(Widget)\n\n\tif oldChildren != nil {\n\t\toldChildren.Remove(widget)\n\t}\n\n\tif newChildren != nil && !newChildren.containsHandle(wb.hWnd) {\n\t\tnewChildren.Add(widget)\n\t}\n\n\treturn nil\n}\n\nfunc (wb *WidgetBase) ForEachAncestor(f func(window Window) bool) {\n\thwnd := win.GetParent(wb.hWnd)\n\n\tfor hwnd != 0 {\n\t\tif window := windowFromHandle(hwnd); window != nil {\n\t\t\tif !f(window) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\thwnd = win.GetParent(hwnd)\n\t}\n}\n\n// ToolTipText returns the tool tip text of the WidgetBase.\nfunc (wb *WidgetBase) ToolTipText() string {\n\tif tt := wb.group.ToolTip(); tt != nil {\n\t\treturn tt.Text(wb.window.(Widget))\n\t}\n\treturn \"\"\n}\n\n// SetToolTipText sets the tool tip text of the WidgetBase.\nfunc (wb *WidgetBase) SetToolTipText(s string) error {\n\tif tt := wb.group.ToolTip(); tt != nil {\n\t\tif err := tt.SetText(wb.window.(Widget), s); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\twb.toolTipTextChangedPublisher.Publish()\n\n\treturn nil\n}\n\n// GraphicsEffects returns a list of WidgetGraphicsEffects that are applied to the WidgetBase.\nfunc (wb *WidgetBase) GraphicsEffects() *WidgetGraphicsEffectList {\n\treturn wb.graphicsEffects\n}\n\nfunc (wb *WidgetBase) onInsertedGraphicsEffect(index int, effect WidgetGraphicsEffect) error {\n\twb.invalidateBorderInParent()\n\n\treturn nil\n}\n\nfunc (wb *WidgetBase) onRemovedGraphicsEffect(index int, effect WidgetGraphicsEffect) error {\n\twb.invalidateBorderInParent()\n\n\treturn nil\n}\n\nfunc (wb *WidgetBase) onClearedGraphicsEffects() error {\n\twb.invalidateBorderInParent()\n\n\treturn nil\n}\n\nfunc (wb *WidgetBase) invalidateBorderInParent() {\n\tif !wb.hasActiveGraphicsEffects() {\n\t\treturn\n\t}\n\n\tif wb.parent != nil && wb.parent.Layout() != nil {\n\t\tb := wb.BoundsPixels().toRECT()\n\t\ts := int32(wb.parent.Layout().Spacing())\n\n\t\thwnd := wb.parent.Handle()\n\n\t\trc := win.RECT{Left: b.Left - s, Top: b.Top - s, Right: b.Left, Bottom: b.Bottom + s}\n\t\twin.InvalidateRect(hwnd, &rc, true)\n\n\t\trc = win.RECT{Left: b.Right, Top: b.Top - s, Right: b.Right + s, Bottom: b.Bottom + s}\n\t\twin.InvalidateRect(hwnd, &rc, true)\n\n\t\trc = win.RECT{Left: b.Left, Top: b.Top - s, Right: b.Right, Bottom: b.Top}\n\t\twin.InvalidateRect(hwnd, &rc, true)\n\n\t\trc = win.RECT{Left: b.Left, Top: b.Bottom, Right: b.Right, Bottom: b.Bottom + s}\n\t\twin.InvalidateRect(hwnd, &rc, true)\n\t}\n}\n\nfunc (wb *WidgetBase) hasActiveGraphicsEffects() bool {\n\tif wb.graphicsEffects == nil {\n\t\treturn false\n\t}\n\n\tcount := wb.graphicsEffects.Len()\n\n\tfor _, gfx := range [...]WidgetGraphicsEffect{FocusEffect, InteractionEffect, ValidationErrorEffect} {\n\t\tif wb.graphicsEffects.Contains(gfx) {\n\t\t\tif gfx == nil {\n\t\t\t\tcount--\n\t\t\t}\n\t\t}\n\t}\n\n\treturn count > 0\n}\n\nfunc (wb *WidgetBase) hasComplexBackground() bool {\n\tif bg := wb.window.Background(); bg != nil && bg != nullBrushSingleton {\n\t\treturn !bg.simple()\n\t}\n\n\tvar complex bool\n\twb.ForEachAncestor(func(window Window) bool {\n\t\tif bg := window.Background(); bg != nil && !bg.simple() {\n\t\t\tcomplex = true\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t})\n\n\treturn complex\n}\n\nfunc ancestor(w Widget) Form {\n\tif w == nil {\n\t\treturn nil\n\t}\n\n\thWndRoot := win.GetAncestor(w.Handle(), win.GA_ROOT)\n\n\trw, _ := windowFromHandle(hWndRoot).(Form)\n\treturn rw\n}\n\nfunc (wb *WidgetBase) LayoutFlags() LayoutFlags {\n\treturn createLayoutItemForWidget(wb.window.(Widget)).LayoutFlags()\n}\n\nfunc (wb *WidgetBase) SizeHint() Size {\n\tif is, ok := createLayoutItemForWidget(wb.window.(Widget)).(IdealSizer); ok {\n\t\treturn is.IdealSize()\n\t}\n\n\treturn Size{}\n}\n\nfunc (wb *WidgetBase) MinSizeHint() Size {\n\tif ms, ok := createLayoutItemForWidget(wb.window.(Widget)).(MinSizer); ok {\n\t\treturn ms.MinSize()\n\t}\n\n\treturn Size{}\n}\n"
  },
  {
    "path": "widgetlist.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"github.com/lxn/win\"\n)\n\ntype widgetListObserver interface {\n\tonInsertingWidget(index int, widget Widget) error\n\tonInsertedWidget(index int, widget Widget) error\n\tonRemovingWidget(index int, widget Widget) error\n\tonRemovedWidget(index int, widget Widget) error\n\tonClearingWidgets() error\n\tonClearedWidgets() error\n}\n\ntype WidgetList struct {\n\titems           []*WidgetBase\n\tobserver        widgetListObserver\n\twidgetInRemoval *WidgetBase\n}\n\nfunc newWidgetList(observer widgetListObserver) *WidgetList {\n\treturn &WidgetList{observer: observer}\n}\n\nfunc (l *WidgetList) Add(item Widget) error {\n\treturn l.Insert(len(l.items), item)\n}\n\nfunc (l *WidgetList) At(index int) Widget {\n\treturn l.items[index].window.(Widget)\n}\n\nfunc (l *WidgetList) Clear() error {\n\tobserver := l.observer\n\tif observer != nil {\n\t\tif err := observer.onClearingWidgets(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\toldItems := l.items\n\tl.items = l.items[:0]\n\n\tif observer != nil {\n\t\tif err := observer.onClearedWidgets(); err != nil {\n\t\t\tl.items = oldItems\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, item := range oldItems {\n\t\titem.form = nil\n\t}\n\n\treturn nil\n}\n\nfunc (l *WidgetList) Index(item Widget) int {\n\twb := item.AsWidgetBase()\n\n\tfor i, widget := range l.items {\n\t\tif widget == wb {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (l *WidgetList) Contains(item Widget) bool {\n\treturn l.Index(item) > -1\n}\n\nfunc (l *WidgetList) indexHandle(handle win.HWND) int {\n\tfor i, widget := range l.items {\n\t\tif widget.Handle() == handle {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (l *WidgetList) containsHandle(handle win.HWND) bool {\n\treturn l.indexHandle(handle) > -1\n}\n\nfunc (l *WidgetList) insertIntoSlice(index int, item Widget) {\n\tl.items = append(l.items, nil)\n\tcopy(l.items[index+1:], l.items[index:])\n\tl.items[index] = item.AsWidgetBase()\n}\n\nfunc (l *WidgetList) Insert(index int, item Widget) error {\n\tif l.Contains(item) {\n\t\treturn newError(\"cannot insert same widget multiple times\")\n\t}\n\n\tobserver := l.observer\n\tif observer != nil {\n\t\tif err := observer.onInsertingWidget(index, item); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tl.insertIntoSlice(index, item)\n\n\tif observer != nil {\n\t\tif err := observer.onInsertedWidget(index, item); err != nil {\n\t\t\tl.items = append(l.items[:index], l.items[index+1:]...)\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (l *WidgetList) Len() int {\n\treturn len(l.items)\n}\n\nfunc (l *WidgetList) Remove(item Widget) error {\n\tindex := l.Index(item)\n\tif index == -1 {\n\t\treturn nil\n\t}\n\n\treturn l.RemoveAt(index)\n}\n\nfunc (l *WidgetList) RemoveAt(index int) error {\n\titem := l.items[index]\n\n\tif item == l.widgetInRemoval {\n\t\treturn nil\n\t}\n\n\tobserver := l.observer\n\twidget := item.window.(Widget)\n\n\tif observer != nil {\n\t\tl.widgetInRemoval = item\n\t\tdefer func() {\n\t\t\tl.widgetInRemoval = nil\n\t\t}()\n\n\t\tif err := observer.onRemovingWidget(index, widget); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tl.items = append(l.items[:index], l.items[index+1:]...)\n\n\tif observer != nil {\n\t\tif err := observer.onRemovedWidget(index, widget); err != nil {\n\t\t\tl.insertIntoSlice(index, widget)\n\t\t\treturn err\n\t\t}\n\t}\n\n\titem.form = nil\n\n\treturn nil\n}\n"
  },
  {
    "path": "window.go",
    "content": "// Copyright 2010 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"image\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\n// App-specific message ids for internal use in Walk.\n// TODO: Document reserved range somewhere (when we have an idea how many we need).\nconst (\n\tnotifyIconMessageId = win.WM_APP + iota\n)\n\n// Window is an interface that provides operations common to all windows.\ntype Window interface {\n\t// AddDisposable adds a Disposable resource that should be disposed of\n\t// together with this Window.\n\tAddDisposable(d Disposable)\n\n\t// AsWindowBase returns a *WindowBase, a pointer to an instance of the\n\t// struct that implements most operations common to all windows.\n\tAsWindowBase() *WindowBase\n\n\t// Accessibility returns the accessibility object used to set Dynamic Annotation properties of the\n\t// window.\n\tAccessibility() *Accessibility\n\n\t// Background returns the background Brush of the Window.\n\t//\n\t// By default this is nil.\n\tBackground() Brush\n\n\t// Bounds returns the outer bounding box rectangle of the Window, including\n\t// decorations.\n\t//\n\t// For a Form, like *MainWindow or *Dialog, the rectangle is in screen\n\t// coordinates, for a child Window the coordinates are relative to its\n\t// parent.\n\tBounds() Rectangle\n\n\t// BoundsPixels returns the outer bounding box rectangle of the Window, including\n\t// decorations.\n\t//\n\t// For a Form, like *MainWindow or *Dialog, the rectangle is in screen\n\t// coordinates, for a child Window the coordinates are relative to its\n\t// parent.\n\tBoundsPixels() Rectangle\n\n\t// BoundsChanged returns an *Event that you can attach to for handling bounds\n\t// changed events for the Window.\n\tBoundsChanged() *Event\n\n\t// BringToTop moves the Window to the top of the keyboard focus order.\n\tBringToTop() error\n\n\t// ClientBounds returns the inner bounding box rectangle of the Window,\n\t// excluding decorations.\n\tClientBounds() Rectangle\n\n\t// ClientBoundsPixels returns the inner bounding box rectangle of the Window,\n\t// excluding decorations.\n\tClientBoundsPixels() Rectangle\n\n\t// ContextMenu returns the context menu of the Window.\n\t//\n\t// By default this is nil.\n\tContextMenu() *Menu\n\n\t// ContextMenuLocation returns the context menu suggested location in screen coordinates in\n\t// native pixels. This method is called when context menu is invoked using keyboard and mouse\n\t// coordinates are not available.\n\tContextMenuLocation() Point\n\n\t// CreateCanvas creates and returns a *Canvas that can be used to draw\n\t// inside the ClientBoundsPixels of the Window.\n\t//\n\t// Remember to call the Dispose method on the canvas to release resources,\n\t// when you no longer need it.\n\tCreateCanvas() (*Canvas, error)\n\n\t// Cursor returns the Cursor of the Window.\n\t//\n\t// By default this is nil.\n\tCursor() Cursor\n\n\t// Dispose releases the operating system resources, associated with the\n\t// Window.\n\t//\n\t// If a user closes a *MainWindow or *Dialog, it is automatically released.\n\t// Also, if a Container is disposed of, all its descendants will be released\n\t// as well.\n\tDispose()\n\n\t// Disposing returns an Event that is published when the Window is disposed\n\t// of.\n\tDisposing() *Event\n\n\t// DoubleBuffering returns whether double buffering of the\n\t// drawing is enabled, which may help reduce flicker.\n\tDoubleBuffering() bool\n\n\t// DPI returns the current DPI value of the Window.\n\tDPI() int\n\n\t// Enabled returns if the Window is enabled for user interaction.\n\tEnabled() bool\n\n\t// Focused returns whether the Window has the keyboard input focus.\n\tFocused() bool\n\n\t// FocusedChanged returns an Event that you can attach to for handling focus\n\t// changed events for the Window.\n\tFocusedChanged() *Event\n\n\t// Font returns the *Font of the Window.\n\t//\n\t// By default this is a MS Shell Dlg 2, 8 point font.\n\tFont() *Font\n\n\t// Form returns the Form of the Window.\n\tForm() Form\n\n\t// Handle returns the window handle of the Window.\n\tHandle() win.HWND\n\n\t// Height returns the outer height of the Window, including decorations.\n\tHeight() int\n\n\t// HeightPixels returns the outer height of the Window, including decorations.\n\tHeightPixels() int\n\n\t// Invalidate schedules a full repaint of the Window.\n\tInvalidate() error\n\n\t// IsDisposed returns if the Window has been disposed of.\n\tIsDisposed() bool\n\n\t// KeyDown returns a *KeyEvent that you can attach to for handling key down\n\t// events for the Window.\n\tKeyDown() *KeyEvent\n\n\t// KeyPress returns a *KeyEvent that you can attach to for handling key\n\t// press events for the Window.\n\tKeyPress() *KeyEvent\n\n\t// KeyUp returns a *KeyEvent that you can attach to for handling key up\n\t// events for the Window.\n\tKeyUp() *KeyEvent\n\n\t// MaxSize returns the maximum allowed outer size for the Window, including\n\t// decorations.\n\t//\n\t// For child windows, this is only relevant when the parent of the Window\n\t// has a Layout. RootWidgets, like *MainWindow and *Dialog, also honor this.\n\tMaxSize() Size\n\n\t// MaxSizePixels returns the maximum allowed outer size for the Window, including\n\t// decorations.\n\t//\n\t// For child windows, this is only relevant when the parent of the Window\n\t// has a Layout. RootWidgets, like *MainWindow and *Dialog, also honor this.\n\tMaxSizePixels() Size\n\n\t// MinSize returns the minimum allowed outer size for the Window, including\n\t// decorations.\n\t//\n\t// For child windows, this is only relevant when the parent of the Window\n\t// has a Layout. RootWidgets, like *MainWindow and *Dialog, also honor this.\n\tMinSize() Size\n\n\t// MinSizePixels returns the minimum allowed outer size for the Window, including\n\t// decorations.\n\t//\n\t// For child windows, this is only relevant when the parent of the Window\n\t// has a Layout. RootWidgets, like *MainWindow and *Dialog, also honor this.\n\tMinSizePixels() Size\n\n\t// MouseDown returns a *MouseEvent that you can attach to for handling\n\t// mouse down events for the Window.\n\tMouseDown() *MouseEvent\n\n\t// MouseMove returns a *MouseEvent that you can attach to for handling\n\t// mouse move events for the Window.\n\tMouseMove() *MouseEvent\n\n\t// MouseUp returns a *MouseEvent that you can attach to for handling\n\t// mouse up events for the Window.\n\tMouseUp() *MouseEvent\n\n\t// Name returns the name of the Window.\n\tName() string\n\n\t// RequestLayout either schedules or immediately starts performing layout.\n\tRequestLayout()\n\n\t// RightToLeftReading returns whether the reading order of the Window\n\t// is from right to left.\n\tRightToLeftReading() bool\n\n\t// Screenshot returns an image of the window.\n\tScreenshot() (*image.RGBA, error)\n\n\t// SendMessage sends a message to the window and returns the result.\n\tSendMessage(msg uint32, wParam, lParam uintptr) uintptr\n\n\t// SetBackground sets the background Brush of the Window.\n\tSetBackground(value Brush)\n\n\t// SetBounds sets the outer bounding box rectangle of the Window, including\n\t// decorations.\n\t//\n\t// For a Form, like *MainWindow or *Dialog, the rectangle is in screen\n\t// coordinates, for a child Window the coordinates are relative to its\n\t// parent.\n\tSetBounds(value Rectangle) error\n\n\t// SetBoundsPixels sets the outer bounding box rectangle of the Window, including\n\t// decorations.\n\t//\n\t// For a Form, like *MainWindow or *Dialog, the rectangle is in screen\n\t// coordinates, for a child Window the coordinates are relative to its\n\t// parent.\n\tSetBoundsPixels(value Rectangle) error\n\n\t// SetClientSize sets the size of the inner bounding box of the Window,\n\t// excluding decorations.\n\tSetClientSize(value Size) error\n\n\t// SetClientSizePixels sets the size of the inner bounding box of the Window,\n\t// excluding decorations.\n\tSetClientSizePixels(value Size) error\n\n\t// SetContextMenu sets the context menu of the Window.\n\tSetContextMenu(value *Menu)\n\n\t// SetCursor sets the Cursor of the Window.\n\tSetCursor(value Cursor)\n\n\t// SetDoubleBuffering enables or disables double buffering of the\n\t// drawing, which may help reduce flicker.\n\tSetDoubleBuffering(value bool) error\n\n\t// SetEnabled sets if the Window is enabled for user interaction.\n\tSetEnabled(value bool)\n\n\t// SetFocus sets the keyboard input focus to the Window.\n\tSetFocus() error\n\n\t// SetFont sets the *Font of the Window.\n\tSetFont(value *Font)\n\n\t// SetHeight sets the outer height of the Window, including decorations.\n\tSetHeight(value int) error\n\n\t// SetHeightPixels sets the outer height of the Window, including decorations.\n\tSetHeightPixels(value int) error\n\n\t// SetMinMaxSize sets the minimum and maximum outer size of the Window,\n\t// including decorations.\n\t//\n\t// Use walk.Size{} to make the respective limit be ignored.\n\tSetMinMaxSize(min, max Size) error\n\n\t// SetMinMaxSizePixels sets the minimum and maximum outer size of the Window,\n\t// including decorations.\n\t//\n\t// Use walk.Size{} to make the respective limit be ignored.\n\tSetMinMaxSizePixels(min, max Size) error\n\n\t// SetName sets the name of the Window.\n\t//\n\t// This is important if you want to make use of the built-in UI persistence.\n\t// Some windows support automatic state persistence. See Settings for\n\t// details.\n\tSetName(name string)\n\n\t// SetRightToLeftReading sets whether the reading order of the Window\n\t// is from right to left.\n\tSetRightToLeftReading(rtl bool) error\n\n\t// SetSize sets the outer size of the Window, including decorations.\n\tSetSize(value Size) error\n\n\t// SetSizePixels sets the outer size of the Window, including decorations.\n\tSetSizePixels(value Size) error\n\n\t// SetSuspended sets if the Window is suspended for layout and repainting\n\t// purposes.\n\t//\n\t// You should call SetSuspended(true), before doing a batch of modifications\n\t// that would cause multiple layout or drawing updates. Remember to call\n\t// SetSuspended(false) afterwards, which will update the Window accordingly.\n\tSetSuspended(suspend bool)\n\n\t// SetVisible sets if the Window is visible.\n\tSetVisible(value bool)\n\n\t// SetWidth sets the outer width of the Window, including decorations.\n\tSetWidth(value int) error\n\n\t// SetWidthPixels sets the outer width of the Window, including decorations.\n\tSetWidthPixels(value int) error\n\n\t// SetX sets the x coordinate of the Window, relative to the screen for\n\t// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n\t// child Windows.\n\tSetX(value int) error\n\n\t// SetXPixels sets the x coordinate of the Window, relative to the screen for\n\t// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n\t// child Windows.\n\tSetXPixels(value int) error\n\n\t// SetY sets the y coordinate of the Window, relative to the screen for\n\t// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n\t// child Windows.\n\tSetY(value int) error\n\n\t// SetYPixels sets the y coordinate of the Window, relative to the screen for\n\t// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n\t// child Windows.\n\tSetYPixels(value int) error\n\n\t// Size returns the outer size of the Window, including decorations.\n\tSize() Size\n\n\t// SizePixels returns the outer size of the Window, including decorations.\n\tSizePixels() Size\n\n\t// SizeChanged returns an *Event that you can attach to for handling size\n\t// changed events for the Window.\n\tSizeChanged() *Event\n\n\t// Suspended returns if the Window is suspended for layout and repainting\n\t// purposes.\n\tSuspended() bool\n\n\t// Synchronize enqueues func f to be called some time later by the main\n\t// goroutine from inside a message loop.\n\tSynchronize(f func())\n\n\t// Visible returns if the Window is visible.\n\tVisible() bool\n\n\t// VisibleChanged returns an Event that you can attach to for handling\n\t// visible changed events for the Window.\n\tVisibleChanged() *Event\n\n\t// Width returns the outer width of the Window, including decorations.\n\tWidth() int\n\n\t// WidthPixels returns the outer width of the Window, including decorations.\n\tWidthPixels() int\n\n\t// WndProc is the window procedure of the window.\n\t//\n\t// When implementing your own WndProc to add or modify behavior, call the\n\t// WndProc of the embedded window for messages you don't handle yourself.\n\tWndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr\n\n\t// X returns the x coordinate of the Window, relative to the screen for\n\t// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n\t// child Windows.\n\tX() int\n\n\t// XPixels returns the x coordinate of the Window, relative to the screen for\n\t// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n\t// child Windows.\n\tXPixels() int\n\n\t// Y returns the y coordinate of the Window, relative to the screen for\n\t// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n\t// child Windows.\n\tY() int\n\n\t// YPixels returns the y coordinate of the Window, relative to the screen for\n\t// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n\t// child Windows.\n\tYPixels() int\n}\n\ntype calcTextSizeInfo struct {\n\twidth int // in native pixels\n\tfont  fontInfo\n\ttext  string\n\tdpi   int\n}\n\n// WindowBase implements many operations common to all Windows.\ntype WindowBase struct {\n\tnopActionListObserver\n\tgroup                     *WindowGroup\n\twindow                    Window\n\tform                      Form\n\thWnd                      win.HWND\n\torigWndProcPtr            uintptr\n\tname                      string\n\tfont                      *Font\n\thFont                     win.HFONT\n\tcontextMenu               *Menu\n\tshortcutActions           *ActionList\n\tdisposables               []Disposable\n\tdisposingPublisher        EventPublisher\n\tdropFilesPublisher        DropFilesEventPublisher\n\tkeyDownPublisher          KeyEventPublisher\n\tkeyPressPublisher         KeyEventPublisher\n\tkeyUpPublisher            KeyEventPublisher\n\tmouseDownPublisher        MouseEventPublisher\n\tmouseUpPublisher          MouseEventPublisher\n\tmouseMovePublisher        MouseEventPublisher\n\tmouseWheelPublisher       MouseEventPublisher\n\tboundsChangedPublisher    EventPublisher\n\tsizeChangedPublisher      EventPublisher\n\tmaxSize96dpi              Size\n\tminSize96dpi              Size\n\tbackground                Brush\n\tcursor                    Cursor\n\tname2Property             map[string]Property\n\tenabledProperty           Property\n\tenabledChangedPublisher   EventPublisher\n\tvisibleProperty           Property\n\tvisibleChangedPublisher   EventPublisher\n\tfocusedProperty           Property\n\tfocusedChangedPublisher   EventPublisher\n\tcalcTextSizeInfo2TextSize map[calcTextSizeInfo]Size // in native pixels\n\tsuspended                 bool\n\tvisible                   bool\n\tenabled                   bool\n\tacc                       *Accessibility\n}\n\nvar (\n\tregisteredWindowClasses = make(map[string]bool)\n\tdefaultWndProcPtr       uintptr\n\thwnd2WindowBase         = make(map[win.HWND]*WindowBase)\n)\n\nfunc init() {\n\tAppendToWalkInit(func() {\n\t\tforEachDescendantCallbackPtr = syscall.NewCallback(forEachDescendant)\n\t\tforEachDescendantRawCallbackPtr = syscall.NewCallback(forEachDescendantRaw)\n\t\tdialogBaseUnitsUTF16StringPtr = syscall.StringToUTF16Ptr(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\")\n\t})\n}\n\n// MustRegisterWindowClass registers the specified window class.\n//\n// MustRegisterWindowClass must be called once for every window type that is not\n// based on any system provided control, before calling InitChildWidget or\n// InitWidget. Calling MustRegisterWindowClass twice with the same className\n// results in a panic.\nfunc MustRegisterWindowClass(className string) {\n\tMustRegisterWindowClassWithWndProcPtr(className, defaultWndProcPtr)\n}\n\nfunc MustRegisterWindowClassWithStyle(className string, style uint32) {\n\tMustRegisterWindowClassWithWndProcPtrAndStyle(className, defaultWndProcPtr, style)\n}\n\nfunc MustRegisterWindowClassWithWndProcPtr(className string, wndProcPtr uintptr) {\n\tMustRegisterWindowClassWithWndProcPtrAndStyle(className, wndProcPtr, 0)\n}\n\nfunc MustRegisterWindowClassWithWndProcPtrAndStyle(className string, wndProcPtr uintptr, style uint32) {\n\tif registeredWindowClasses[className] {\n\t\tpanic(\"window class already registered\")\n\t}\n\n\thInst := win.GetModuleHandle(nil)\n\tif hInst == 0 {\n\t\tpanic(\"GetModuleHandle\")\n\t}\n\n\thIcon := win.LoadIcon(hInst, win.MAKEINTRESOURCE(7)) // rsrc uses 7 for app icon\n\tif hIcon == 0 {\n\t\thIcon = win.LoadIcon(0, win.MAKEINTRESOURCE(win.IDI_APPLICATION))\n\t}\n\tif hIcon == 0 {\n\t\tpanic(\"LoadIcon\")\n\t}\n\n\thCursor := win.LoadCursor(0, win.MAKEINTRESOURCE(win.IDC_ARROW))\n\tif hCursor == 0 {\n\t\tpanic(\"LoadCursor\")\n\t}\n\n\tvar wc win.WNDCLASSEX\n\twc.CbSize = uint32(unsafe.Sizeof(wc))\n\twc.LpfnWndProc = wndProcPtr\n\twc.HInstance = hInst\n\twc.HIcon = hIcon\n\twc.HCursor = hCursor\n\twc.HbrBackground = win.COLOR_BTNFACE + 1\n\twc.LpszClassName = syscall.StringToUTF16Ptr(className)\n\twc.Style = style\n\n\tif atom := win.RegisterClassEx(&wc); atom == 0 {\n\t\tpanic(\"RegisterClassEx\")\n\t}\n\n\tregisteredWindowClasses[className] = true\n}\n\nvar initedWalk uint32\nvar walkInit []func()\n\nfunc AppendToWalkInit(fn func()) {\n\twalkInit = append(walkInit, fn)\n}\n\ntype windowCfg struct {\n\tWindow    Window\n\tParent    Window\n\tClassName string\n\tStyle     uint32\n\tExStyle   uint32\n\tBounds    Rectangle\n}\n\n// InitWindow initializes a window.\n//\n// Widgets should be initialized using InitWidget instead.\nfunc InitWindow(window, parent Window, className string, style, exStyle uint32) error {\n\treturn initWindowWithCfg(&windowCfg{\n\t\tWindow:    window,\n\t\tParent:    parent,\n\t\tClassName: className,\n\t\tStyle:     style,\n\t\tExStyle:   exStyle,\n\t})\n}\n\nfunc initWindowWithCfg(cfg *windowCfg) error {\n\t// We can't use sync.Once, because tooltip.go's init also calls InitWindow, so we deadlock.\n\tif atomic.CompareAndSwapUint32(&initedWalk, 0, 1) {\n\t\truntime.LockOSThread()\n\n\t\tvar initCtrls win.INITCOMMONCONTROLSEX\n\t\tinitCtrls.DwSize = uint32(unsafe.Sizeof(initCtrls))\n\t\tinitCtrls.DwICC = win.ICC_LINK_CLASS | win.ICC_LISTVIEW_CLASSES | win.ICC_PROGRESS_CLASS | win.ICC_TAB_CLASSES | win.ICC_TREEVIEW_CLASSES\n\t\twin.InitCommonControlsEx(&initCtrls)\n\n\t\tdefaultWndProcPtr = syscall.NewCallback(defaultWndProc)\n\t\tfor _, fn := range walkInit {\n\t\t\tfn()\n\t\t}\n\t}\n\n\twb := cfg.Window.AsWindowBase()\n\twb.window = cfg.Window\n\twb.enabled = true\n\twb.visible = cfg.Style&win.WS_VISIBLE != 0\n\twb.calcTextSizeInfo2TextSize = make(map[calcTextSizeInfo]Size)\n\twb.name2Property = make(map[string]Property)\n\n\tvar hwndParent win.HWND\n\tvar hMenu win.HMENU\n\tif cfg.Parent != nil {\n\t\thwndParent = cfg.Parent.Handle()\n\n\t\tif widget, ok := cfg.Window.(Widget); ok {\n\t\t\tif container, ok := cfg.Parent.(Container); ok {\n\t\t\t\tif cb := container.AsContainerBase(); cb != nil {\n\t\t\t\t\thMenu = win.HMENU(cb.NextChildID())\n\t\t\t\t}\n\t\t\t\twidget.AsWidgetBase().parent = container\n\t\t\t}\n\t\t}\n\t}\n\n\tvar windowName *uint16\n\tif len(wb.name) != 0 {\n\t\twindowName = syscall.StringToUTF16Ptr(wb.name)\n\t}\n\n\tif hwnd := cfg.Window.Handle(); hwnd == 0 {\n\t\tvar x, y, w, h int32\n\t\tif cfg.Bounds.IsZero() {\n\t\t\tx = win.CW_USEDEFAULT\n\t\t\ty = win.CW_USEDEFAULT\n\t\t\tw = win.CW_USEDEFAULT\n\t\t\th = win.CW_USEDEFAULT\n\t\t} else {\n\t\t\tx = int32(cfg.Bounds.X)\n\t\t\ty = int32(cfg.Bounds.Y)\n\t\t\tw = int32(cfg.Bounds.Width)\n\t\t\th = int32(cfg.Bounds.Height)\n\t\t}\n\n\t\twb.hWnd = win.CreateWindowEx(\n\t\t\tcfg.ExStyle,\n\t\t\tsyscall.StringToUTF16Ptr(cfg.ClassName),\n\t\t\twindowName,\n\t\t\tcfg.Style|win.WS_CLIPSIBLINGS,\n\t\t\tx,\n\t\t\ty,\n\t\t\tw,\n\t\t\th,\n\t\t\thwndParent,\n\t\t\thMenu,\n\t\t\t0,\n\t\t\tnil)\n\t\tif wb.hWnd == 0 {\n\t\t\treturn lastError(\"CreateWindowEx\")\n\t\t}\n\t} else {\n\t\twb.hWnd = hwnd\n\t}\n\n\t// Handles returned by CreateWindowEx can only be used by the calling\n\t// thread. As a result, InitWindow *must* be called from a goroutine that\n\t// has been locked to an OS thread via runtime.LockOSThread().\n\t//\n\t// This means we can ask the OS for the ID of the current thread and we\n\t// don't have to worry about the scheduler moving us onto another thread\n\t// later.\n\ttid := win.GetCurrentThreadId()\n\n\t// Use the thread ID to look up our window group, which stores data that\n\t// is common to all windows on a common thread. A group will be created\n\t// if one doesn't already exist for the thread ID.\n\t//\n\t// CreateGroup automatically increments the reference counter for the\n\t// group. The counter will be decremented later in WindowBase.Dispose.\n\twb.group = wgm.CreateGroup(tid)\n\n\tsucceeded := false\n\tdefer func() {\n\t\tif !succeeded {\n\t\t\twb.Dispose()\n\t\t}\n\t}()\n\n\thwnd2WindowBase[wb.hWnd] = wb\n\n\tif !registeredWindowClasses[cfg.ClassName] {\n\t\t// We subclass all windows of system classes.\n\t\twb.origWndProcPtr = win.SetWindowLongPtr(wb.hWnd, win.GWLP_WNDPROC, defaultWndProcPtr)\n\t\tif wb.origWndProcPtr == 0 {\n\t\t\treturn lastError(\"SetWindowLongPtr\")\n\t\t}\n\t}\n\n\tSetWindowFont(wb.hWnd, defaultFont)\n\n\tif form, ok := cfg.Window.(Form); ok {\n\t\tif fb := form.AsFormBase(); fb != nil {\n\t\t\tif err := fb.init(form); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tif widget, ok := cfg.Window.(Widget); ok {\n\t\tif wb := widget.AsWidgetBase(); wb != nil {\n\t\t\tif err := wb.init(widget); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\twb.enabledProperty = NewBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn wb.window.Enabled()\n\t\t},\n\t\tfunc(b bool) error {\n\t\t\twb.window.SetEnabled(b)\n\t\t\treturn nil\n\t\t},\n\t\twb.enabledChangedPublisher.Event())\n\n\twb.visibleProperty = NewBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn wb.visible\n\t\t},\n\t\tfunc(b bool) error {\n\t\t\twb.window.SetVisible(b)\n\t\t\treturn nil\n\t\t},\n\t\twb.visibleChangedPublisher.Event())\n\n\twb.focusedProperty = NewReadOnlyBoolProperty(\n\t\tfunc() bool {\n\t\t\treturn wb.window.Focused()\n\t\t},\n\t\twb.focusedChangedPublisher.Event())\n\n\twb.MustRegisterProperty(\"Enabled\", wb.enabledProperty)\n\twb.MustRegisterProperty(\"Visible\", wb.visibleProperty)\n\twb.MustRegisterProperty(\"Focused\", wb.focusedProperty)\n\n\tsucceeded = true\n\n\treturn nil\n}\n\n// InitWrapperWindow initializes a window that wraps (embeds) another window.\n//\n// Calling this method is necessary, if you want to be able to override the\n// WndProc method of the embedded window. The embedded window should only be\n// used as inseparable part of the wrapper window to avoid undefined behavior.\nfunc InitWrapperWindow(window Window) error {\n\twb := window.AsWindowBase()\n\n\twb.window = window\n\n\tif container, ok := window.(Container); ok {\n\t\tchildren := container.Children()\n\n\t\tif wlo, ok := window.(widgetListObserver); ok {\n\t\t\tchildren.observer = wlo\n\t\t}\n\n\t\tfor _, child := range children.items {\n\t\t\tchild.parent = container\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (wb *WindowBase) MustRegisterProperty(name string, property Property) {\n\tif property == nil {\n\t\tpanic(\"property must not be nil\")\n\t}\n\tif wb.name2Property[name] != nil {\n\t\tpanic(\"property already registered\")\n\t}\n\n\twb.name2Property[name] = property\n}\n\nfunc (wb *WindowBase) Property(name string) Property {\n\treturn wb.name2Property[name]\n}\n\nfunc (wb *WindowBase) hasStyleBits(bits uint32) bool {\n\treturn hasWindowLongBits(wb.hWnd, win.GWL_STYLE, bits)\n}\n\nfunc (wb *WindowBase) hasExtendedStyleBits(bits uint32) bool {\n\treturn hasWindowLongBits(wb.hWnd, win.GWL_EXSTYLE, bits)\n}\n\nfunc hasWindowLongBits(hwnd win.HWND, index int32, bits uint32) bool {\n\tvalue := uint32(win.GetWindowLong(hwnd, index))\n\n\treturn value&bits == bits\n}\n\nfunc (wb *WindowBase) setAndClearStyleBits(set, clear uint32) error {\n\treturn setAndClearWindowLongBits(wb.hWnd, win.GWL_STYLE, set, clear)\n}\n\nfunc (wb *WindowBase) setAndClearExtendedStyleBits(set, clear uint32) error {\n\treturn setAndClearWindowLongBits(wb.hWnd, win.GWL_EXSTYLE, set, clear)\n}\n\nfunc setAndClearWindowLongBits(hwnd win.HWND, index int32, set, clear uint32) error {\n\tvalue := uint32(win.GetWindowLong(hwnd, index))\n\tif value == 0 {\n\t\treturn lastError(\"GetWindowLong\")\n\t}\n\n\tif newValue := value&^clear | set; newValue != value {\n\t\twin.SetLastError(0)\n\t\tif win.SetWindowLong(hwnd, index, int32(newValue)) == 0 {\n\t\t\treturn lastError(\"SetWindowLong\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (wb *WindowBase) ensureStyleBits(bits uint32, set bool) error {\n\treturn ensureWindowLongBits(wb.hWnd, win.GWL_STYLE, bits, set)\n}\n\nfunc (wb *WindowBase) ensureExtendedStyleBits(bits uint32, set bool) error {\n\treturn ensureWindowLongBits(wb.hWnd, win.GWL_EXSTYLE, bits, set)\n}\n\nfunc ensureWindowLongBits(hwnd win.HWND, index int32, bits uint32, set bool) error {\n\tvar setBits uint32\n\tvar clearBits uint32\n\tif set {\n\t\tsetBits = bits\n\t} else {\n\t\tclearBits = bits\n\t}\n\treturn setAndClearWindowLongBits(hwnd, index, setBits, clearBits)\n}\n\n// Accessibility returns the accessibility object used to set Dynamic Annotation properties of the\n// window.\nfunc (wb *WindowBase) Accessibility() *Accessibility {\n\tif wb.acc == nil {\n\t\twb.acc = &Accessibility{wb: wb}\n\t}\n\treturn wb.acc\n}\n\n// Handle returns the window handle of the Window.\nfunc (wb *WindowBase) Handle() win.HWND {\n\treturn wb.hWnd\n}\n\n// SendMessage sends a message to the window and returns the result.\nfunc (wb *WindowBase) SendMessage(msg uint32, wParam, lParam uintptr) uintptr {\n\treturn win.SendMessage(wb.hWnd, msg, wParam, lParam)\n}\n\n// Name returns the name of the *WindowBase.\nfunc (wb *WindowBase) Name() string {\n\treturn wb.name\n}\n\n// SetName sets the name of the *WindowBase.\nfunc (wb *WindowBase) SetName(name string) {\n\twb.name = name\n}\n\nfunc (wb *WindowBase) writePath(buf *bytes.Buffer) {\n\thWndParent := win.GetAncestor(wb.hWnd, win.GA_PARENT)\n\tif pwi := windowFromHandle(hWndParent); pwi != nil {\n\t\tif sv, ok := pwi.(*ScrollView); ok {\n\t\t\tpwi = sv.Parent()\n\t\t}\n\t\tpwi.AsWindowBase().writePath(buf)\n\t\tbuf.WriteByte('/')\n\t}\n\n\tbuf.WriteString(wb.name)\n}\n\nfunc (wb *WindowBase) path() string {\n\tbuf := bytes.NewBuffer(nil)\n\n\twb.writePath(buf)\n\n\treturn buf.String()\n}\n\n// WindowBase simply returns the receiver.\nfunc (wb *WindowBase) AsWindowBase() *WindowBase {\n\treturn wb\n}\n\n// AddDisposable adds a Disposable resource that should be disposed of\n// together with this Window.\nfunc (wb *WindowBase) AddDisposable(d Disposable) {\n\twb.disposables = append(wb.disposables, d)\n}\n\n// Dispose releases the operating system resources, associated with the\n// *WindowBase.\n//\n// If a user closes a *MainWindow or *Dialog, it is automatically released.\n// Also, if a Container is disposed of, all its descendants will be released\n// as well.\nfunc (wb *WindowBase) Dispose() {\n\tfor _, d := range wb.disposables {\n\t\td.Dispose()\n\t}\n\n\tif wb.background != nil {\n\t\twb.background.detachWindow(wb)\n\t}\n\n\thWnd := wb.hWnd\n\tif hWnd != 0 {\n\t\twb.disposingPublisher.Publish()\n\n\t\twb.hWnd = 0\n\t\tif _, ok := hwnd2WindowBase[hWnd]; ok {\n\t\t\twin.DestroyWindow(hWnd)\n\t\t}\n\t}\n\n\tif cm := wb.contextMenu; cm != nil {\n\t\tcm.actions.Clear()\n\t\tcm.Dispose()\n\t}\n\n\tif wb.shortcutActions != nil {\n\t\twb.shortcutActions.Clear()\n\t}\n\n\tfor _, p := range wb.name2Property {\n\t\tp.SetSource(nil)\n\t}\n\n\tif hWnd != 0 {\n\t\twb.group.accClearHwndProps(wb.hWnd)\n\t\twb.group.Done()\n\t}\n}\n\n// Disposing returns an Event that is published when the Window is disposed\n// of.\nfunc (wb *WindowBase) Disposing() *Event {\n\treturn wb.disposingPublisher.Event()\n}\n\n// IsDisposed returns if the *WindowBase has been disposed of.\nfunc (wb *WindowBase) IsDisposed() bool {\n\treturn wb.hWnd == 0\n}\n\n// ContextMenu returns the context menu of the *WindowBase.\n//\n// By default this is nil.\nfunc (wb *WindowBase) ContextMenu() *Menu {\n\treturn wb.contextMenu\n}\n\n// SetContextMenu sets the context menu of the *WindowBase.\nfunc (wb *WindowBase) SetContextMenu(value *Menu) {\n\twb.contextMenu = value\n}\n\n// ContextMenuLocation returns the the *WindowBase center in screen coordinates in native pixels.\nfunc (wb *WindowBase) ContextMenuLocation() Point {\n\tvar rc win.RECT\n\tif !win.GetWindowRect(wb.hWnd, &rc) {\n\t\treturn Point{}\n\t}\n\treturn Point{int(rc.Left+rc.Right) / 2, int(rc.Top+rc.Bottom) / 2}\n}\n\n// ShortcutActions returns the list of actions that will be triggered if their\n// shortcut is pressed when this window or one of its descendants has the\n// keyboard focus.\nfunc (wb *WindowBase) ShortcutActions() *ActionList {\n\tif wb.shortcutActions == nil {\n\t\twb.shortcutActions = newActionList(wb)\n\t}\n\n\treturn wb.shortcutActions\n}\n\n// Background returns the background Brush of the *WindowBase.\n//\n// By default this is nil.\nfunc (wb *WindowBase) Background() Brush {\n\treturn wb.background\n}\n\n// SetBackground sets the background Brush of the *WindowBase.\nfunc (wb *WindowBase) SetBackground(background Brush) {\n\tif wb.background != nil {\n\t\twb.background.detachWindow(wb)\n\t}\n\n\twb.background = background\n\n\tif background != nil {\n\t\tbackground.attachWindow(wb)\n\t}\n\n\twb.Invalidate()\n\n\t// Sliders need some extra encouragement...\n\twalkDescendants(wb, func(w Window) bool {\n\t\tif s, ok := w.(*Slider); ok {\n\t\t\ts.SetRange(s.MinValue(), s.MaxValue()+1)\n\t\t\ts.SetRange(s.MinValue(), s.MaxValue()-1)\n\t\t}\n\n\t\treturn true\n\t})\n}\n\n// Cursor returns the Cursor of the *WindowBase.\n//\n// By default this is nil.\nfunc (wb *WindowBase) Cursor() Cursor {\n\treturn wb.cursor\n}\n\n// SetCursor sets the Cursor of the *WindowBase.\nfunc (wb *WindowBase) SetCursor(value Cursor) {\n\twb.cursor = value\n}\n\n// DoubleBuffering returns whether double buffering of the\n// drawing is enabled, which may help reduce flicker.\nfunc (wb *WindowBase) DoubleBuffering() bool {\n\treturn wb.hasExtendedStyleBits(win.WS_EX_COMPOSITED)\n}\n\n// SetDoubleBuffering enables or disables double buffering of the\n// drawing, which may help reduce flicker.\nfunc (wb *WindowBase) SetDoubleBuffering(enabled bool) error {\n\treturn wb.ensureExtendedStyleBits(win.WS_EX_COMPOSITED, enabled)\n}\n\ntype ApplySysColorser interface {\n\tApplySysColors()\n}\n\nfunc (wb *WindowBase) ApplySysColors() {\n\twb.Invalidate()\n}\n\n// DPI returns the current DPI value of the WindowBase.\nfunc (wb *WindowBase) DPI() int {\n\treturn int(win.GetDpiForWindow(wb.hWnd))\n}\n\ntype ApplyDPIer interface {\n\tApplyDPI(dpi int)\n}\n\nfunc (wb *WindowBase) ApplyDPI(dpi int) {\n\tif af, ok := wb.window.(applyFonter); ok {\n\t\taf.applyFont(wb.window.Font())\n\t}\n}\n\n// IntFrom96DPI converts from 1/96\" units to native pixels.\nfunc (wb *WindowBase) IntFrom96DPI(value int) int {\n\treturn IntFrom96DPI(value, wb.DPI())\n}\n\n// IntTo96DPI converts from native pixels to 1/96\" units.\nfunc (wb *WindowBase) IntTo96DPI(value int) int {\n\treturn IntTo96DPI(value, wb.DPI())\n}\n\n// MarginsFrom96DPI converts from 1/96\" units to native pixels.\nfunc (wb *WindowBase) MarginsFrom96DPI(value Margins) Margins {\n\treturn MarginsFrom96DPI(value, wb.DPI())\n}\n\n// MarginsTo96DPI converts from native pixels to 1/96\" units.\nfunc (wb *WindowBase) MarginsTo96DPI(value Margins) Margins {\n\treturn MarginsTo96DPI(value, wb.DPI())\n}\n\n// PointFrom96DPI converts from 1/96\" units to native pixels.\nfunc (wb *WindowBase) PointFrom96DPI(value Point) Point {\n\treturn PointFrom96DPI(value, wb.DPI())\n}\n\n// PointTo96DPI converts from native pixels to 1/96\" units.\nfunc (wb *WindowBase) PointTo96DPI(value Point) Point {\n\treturn PointTo96DPI(value, wb.DPI())\n}\n\n// RectangleFrom96DPI converts from 1/96\" units to native pixels.\nfunc (wb *WindowBase) RectangleFrom96DPI(value Rectangle) Rectangle {\n\treturn RectangleFrom96DPI(value, wb.DPI())\n}\n\n// RectangleTo96DPI converts from native pixels to 1/96\" units.\nfunc (wb *WindowBase) RectangleTo96DPI(value Rectangle) Rectangle {\n\treturn RectangleTo96DPI(value, wb.DPI())\n}\n\n// SizeFrom96DPI converts from 1/96\" units to native pixels.\nfunc (wb *WindowBase) SizeFrom96DPI(value Size) Size {\n\treturn SizeFrom96DPI(value, wb.DPI())\n}\n\n// SizeTo96DPI converts from native pixels to 1/96\" units.\nfunc (wb *WindowBase) SizeTo96DPI(value Size) Size {\n\treturn SizeTo96DPI(value, wb.DPI())\n}\n\n// Enabled returns if the *WindowBase is enabled for user interaction.\nfunc (wb *WindowBase) Enabled() bool {\n\treturn wb.enabled\n}\n\n// SetEnabled sets if the *WindowBase is enabled for user interaction.\nfunc (wb *WindowBase) SetEnabled(enabled bool) {\n\twb.enabled = enabled\n\n\twb.window.(applyEnableder).applyEnabled(wb.window.Enabled())\n\n\tif widget, ok := wb.window.(Widget); ok {\n\t\twidget.AsWidgetBase().invalidateBorderInParent()\n\t}\n\n\twb.enabledChangedPublisher.Publish()\n}\n\ntype applyEnableder interface {\n\tapplyEnabled(enabled bool)\n}\n\nfunc (wb *WindowBase) applyEnabled(enabled bool) {\n\tsetWindowEnabled(wb.hWnd, enabled)\n}\n\nfunc setWindowEnabled(hwnd win.HWND, enabled bool) {\n\twin.EnableWindow(hwnd, enabled)\n\n\twin.UpdateWindow(hwnd)\n}\n\n// Font returns the *Font of the *WindowBase.\n//\n// By default this is a MS Shell Dlg 2, 8 point font.\nfunc (wb *WindowBase) Font() *Font {\n\tif wb.font != nil {\n\t\treturn wb.font\n\t}\n\n\treturn defaultFont\n}\n\n// SetFont sets the *Font of the *WindowBase.\nfunc (wb *WindowBase) SetFont(font *Font) {\n\tif font != wb.font {\n\t\twb.font = font\n\n\t\twb.window.(applyFonter).applyFont(font)\n\t}\n}\n\ntype applyFonter interface {\n\tapplyFont(font *Font)\n}\n\ntype ApplyFonter interface {\n\tApplyFont(font *Font)\n}\n\nfunc (wb *WindowBase) applyFont(font *Font) {\n\tif hFont := font.handleForDPI(wb.DPI()); hFont != wb.hFont {\n\t\twb.hFont = hFont\n\n\t\tsetWindowFont(wb.hWnd, hFont)\n\t}\n\n\tif af, ok := wb.window.(ApplyFonter); ok {\n\t\taf.ApplyFont(font)\n\t}\n}\n\nfunc SetWindowFont(hwnd win.HWND, font *Font) {\n\tdpi := int(win.GetDpiForWindow(hwnd))\n\tsetWindowFont(hwnd, font.handleForDPI(dpi))\n}\n\nfunc setWindowFont(hwnd win.HWND, hFont win.HFONT) {\n\twin.SendMessage(hwnd, win.WM_SETFONT, uintptr(hFont), 1)\n\n\tif window := windowFromHandle(hwnd); window != nil {\n\t\tif widget, ok := window.(Widget); ok {\n\t\t\twidget.AsWidgetBase().RequestLayout()\n\t\t}\n\t}\n}\n\n// Suspended returns if the *WindowBase is suspended for layout and repainting\n// purposes.\nfunc (wb *WindowBase) Suspended() bool {\n\treturn wb.suspended\n}\n\n// SetSuspended sets if the *WindowBase is suspended for layout and repainting\n// purposes.\n//\n// You should call SetSuspended(true), before doing a batch of modifications\n// that would cause multiple layout or drawing updates. Remember to call\n// SetSuspended(false) afterwards, which will update the *WindowBase\n// accordingly.\nfunc (wb *WindowBase) SetSuspended(suspend bool) {\n\tif suspend == wb.suspended {\n\t\treturn\n\t}\n\n\tvar wParam int\n\tif suspend {\n\t\twParam = 0\n\t} else {\n\t\twParam = 1\n\t}\n\n\tif wb.visible {\n\t\twb.SendMessage(win.WM_SETREDRAW, uintptr(wParam), 0)\n\t}\n\n\twb.suspended = suspend\n\n\tif !suspend && wb.visible {\n\t\twb.Invalidate()\n\t\twb.RequestLayout()\n\t}\n}\n\n// Invalidate schedules a full repaint of the *WindowBase.\nfunc (wb *WindowBase) Invalidate() error {\n\tif !win.InvalidateRect(wb.hWnd, nil, true) {\n\t\treturn newError(\"InvalidateRect failed\")\n\t}\n\n\treturn nil\n}\n\nfunc (wb *WindowBase) text() string {\n\treturn windowText(wb.hWnd)\n}\n\nfunc (wb *WindowBase) setText(text string) error {\n\tif err := setWindowText(wb.hWnd, text); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc windowText(hwnd win.HWND) string {\n\ttextLength := win.SendMessage(hwnd, win.WM_GETTEXTLENGTH, 0, 0)\n\tbuf := make([]uint16, textLength+1)\n\twin.SendMessage(hwnd, win.WM_GETTEXT, uintptr(textLength+1), uintptr(unsafe.Pointer(&buf[0])))\n\treturn syscall.UTF16ToString(buf)\n}\n\nfunc setWindowText(hwnd win.HWND, text string) error {\n\tif win.TRUE != win.SendMessage(hwnd, win.WM_SETTEXT, 0, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text)))) {\n\t\treturn newError(\"WM_SETTEXT failed\")\n\t}\n\n\treturn nil\n}\n\nfunc (wb *WindowBase) RestoreState() (err error) {\n\twb.ForEachDescendant(func(widget Widget) bool {\n\t\tif persistable, ok := widget.(Persistable); ok && persistable.Persistent() {\n\t\t\tif err = persistable.RestoreState(); err != nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif _, ok := widget.(Container); ok {\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t})\n\n\treturn\n}\n\nfunc (wb *WindowBase) SaveState() (err error) {\n\twb.ForEachDescendant(func(widget Widget) bool {\n\t\tif persistable, ok := widget.(Persistable); ok && persistable.Persistent() {\n\t\t\tif err = persistable.SaveState(); err != nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif _, ok := widget.(Container); ok {\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t})\n\n\treturn\n}\n\n// Form returns the Form of the Window.\nfunc (wb *WindowBase) Form() Form {\n\tif wb.form == nil {\n\t\tif form, ok := wb.window.(Form); ok {\n\t\t\twb.form = form\n\t\t} else {\n\t\t\twb.form = ancestor(wb.window.(Widget))\n\t\t}\n\t}\n\n\treturn wb.form\n}\n\nfunc forEachDescendant(hwnd win.HWND, lParam uintptr) uintptr {\n\tif window := windowFromHandle(hwnd); window == nil || forEachDescendantCallback(window.(Widget)) {\n\t\treturn 1\n\t}\n\n\treturn 0\n}\n\nvar (\n\tforEachDescendantCallbackPtr uintptr\n\tforEachDescendantCallback    func(widget Widget) bool\n)\n\nfunc (wb *WindowBase) ForEachDescendant(f func(widget Widget) bool) {\n\tforEachDescendantCallback = f\n\tdefer func() {\n\t\tforEachDescendantCallback = nil\n\t}()\n\n\twin.EnumChildWindows(wb.hWnd, forEachDescendantCallbackPtr, 0)\n}\n\nfunc forEachDescendantRaw(hwnd win.HWND, lParam uintptr) uintptr {\n\tif forEachDescendantRawCallback(hwnd, lParam) {\n\t\treturn 1\n\t}\n\n\treturn 0\n}\n\nvar (\n\tforEachDescendantRawCallbackPtr uintptr\n\tforEachDescendantRawCallback    func(hwnd win.HWND, lParam uintptr) bool\n)\n\nfunc (wb *WindowBase) forEachDescendantRaw(lParam uintptr, f func(hwnd win.HWND, lParam uintptr) bool) {\n\tforEachDescendantRawCallback = f\n\tdefer func() {\n\t\tforEachDescendantRawCallback = nil\n\t}()\n\n\twin.EnumChildWindows(wb.hWnd, forEachDescendantRawCallbackPtr, lParam)\n}\n\n// Visible returns if the *WindowBase is visible.\nfunc (wb *WindowBase) Visible() bool {\n\treturn win.IsWindowVisible(wb.hWnd)\n}\n\n// SetVisible sets if the *WindowBase is visible.\nfunc (wb *WindowBase) SetVisible(visible bool) {\n\told := wb.Visible()\n\n\tsetWindowVisible(wb.hWnd, visible)\n\n\twb.visible = visible\n\n\twalkDescendants(wb.window, func(w Window) bool {\n\t\tw.AsWindowBase().visibleChangedPublisher.Publish()\n\n\t\treturn true\n\t})\n\n\tif visible == old {\n\t\treturn\n\t}\n\n\tif widget, ok := wb.window.(Widget); ok {\n\t\twb := widget.AsWidgetBase()\n\t\twb.invalidateBorderInParent()\n\t\twb.RequestLayout()\n\t}\n\n\twb.visibleChangedPublisher.Publish()\n}\n\n// VisibleChanged returns an Event that you can attach to for handling\n// visible changed events for the Window.\nfunc (wb *WindowBase) VisibleChanged() *Event {\n\treturn wb.visibleChangedPublisher.Event()\n}\n\nfunc setWindowVisible(hwnd win.HWND, visible bool) {\n\tvar cmd int32\n\tif visible {\n\t\tcmd = win.SW_SHOWNA\n\t} else {\n\t\tcmd = win.SW_HIDE\n\t}\n\twin.ShowWindow(hwnd, cmd)\n}\n\n// BringToTop moves the *WindowBase to the top of the keyboard focus order.\nfunc (wb *WindowBase) BringToTop() error {\n\tif !win.SetWindowPos(wb.hWnd, win.HWND_TOP, 0, 0, 0, 0, win.SWP_NOACTIVATE|win.SWP_NOMOVE|win.SWP_NOSIZE) {\n\t\treturn lastError(\"SetWindowPos\")\n\t}\n\n\treturn nil\n}\n\n// Bounds returns the outer bounding box rectangle of the *WindowBase, including\n// decorations.\n//\n// The coordinates are relative to the screen.\nfunc (wb *WindowBase) Bounds() Rectangle {\n\treturn wb.RectangleTo96DPI(wb.BoundsPixels())\n}\n\n// SetBounds sets the outer bounding box rectangle of the *WindowBase,\n// including decorations.\n//\n// For a Form, like *MainWindow or *Dialog, the rectangle is in screen\n// coordinates, for a child Window the coordinates are relative to its parent.\nfunc (wb *WindowBase) SetBounds(bounds Rectangle) error {\n\treturn wb.SetBoundsPixels(wb.RectangleFrom96DPI(bounds))\n}\n\n// BoundsPixels returns the outer bounding box rectangle of the *WindowBase, including\n// decorations.\n//\n// The coordinates are relative to the screen.\nfunc (wb *WindowBase) BoundsPixels() Rectangle {\n\tvar r win.RECT\n\n\tif !win.GetWindowRect(wb.hWnd, &r) {\n\t\tlastError(\"GetWindowRect\")\n\t\treturn Rectangle{}\n\t}\n\n\treturn rectangleFromRECT(r)\n}\n\n// SetBoundsPixels sets the outer bounding box rectangle of the *WindowBase,\n// including decorations.\n//\n// For a Form, like *MainWindow or *Dialog, the rectangle is in screen\n// coordinates, for a child Window the coordinates are relative to its parent.\nfunc (wb *WindowBase) SetBoundsPixels(bounds Rectangle) error {\n\tif !win.MoveWindow(\n\t\twb.hWnd,\n\t\tint32(bounds.X),\n\t\tint32(bounds.Y),\n\t\tint32(bounds.Width),\n\t\tint32(bounds.Height),\n\t\ttrue) {\n\n\t\treturn lastError(\"MoveWindow\")\n\t}\n\n\treturn nil\n}\n\n// MinSize returns the minimum allowed outer size for the *WindowBase, including\n// decorations.\n//\n// For child windows, this is only relevant when the parent of the *WindowBase\n// has a Layout. RootWidgets, like *MainWindow and *Dialog, also honor this.\nfunc (wb *WindowBase) MinSize() Size {\n\treturn wb.minSize96dpi\n}\n\n// MinSizePixels returns the minimum allowed outer size for the *WindowBase, including\n// decorations.\n//\n// For child windows, this is only relevant when the parent of the *WindowBase\n// has a Layout. RootWidgets, like *MainWindow and *Dialog, also honor this.\nfunc (wb *WindowBase) MinSizePixels() Size {\n\treturn wb.SizeFrom96DPI(wb.minSize96dpi)\n}\n\n// MaxSize returns the maximum allowed outer size for the *WindowBase, including\n// decorations.\n//\n// For child windows, this is only relevant when the parent of the *WindowBase\n// has a Layout. RootWidgets, like *MainWindow and *Dialog, also honor this.\nfunc (wb *WindowBase) MaxSize() Size {\n\treturn wb.maxSize96dpi\n}\n\n// MaxSizePixels returns the maximum allowed outer size for the *WindowBase, including\n// decorations.\n//\n// For child windows, this is only relevant when the parent of the *WindowBase\n// has a Layout. RootWidgets, like *MainWindow and *Dialog, also honor this.\nfunc (wb *WindowBase) MaxSizePixels() Size {\n\treturn wb.SizeFrom96DPI(wb.maxSize96dpi)\n}\n\n// SetMinMaxSize sets the minimum and maximum outer size of the *WindowBase,\n// including decorations.\n//\n// Use walk.Size{} to make the respective limit be ignored.\nfunc (wb *WindowBase) SetMinMaxSize(min, max Size) error {\n\tif min.Width < 0 || min.Height < 0 {\n\t\treturn newError(\"min must be positive\")\n\t}\n\tif max.Width > 0 && max.Width < min.Width ||\n\t\tmax.Height > 0 && max.Height < min.Height {\n\t\treturn newError(\"max must be greater as or equal to min\")\n\t}\n\twb.minSize96dpi = min\n\twb.maxSize96dpi = max\n\treturn nil\n}\n\n// SetMinMaxSizePixels sets the minimum and maximum outer size of the *WindowBase,\n// including decorations.\n//\n// Use walk.Size{} to make the respective limit be ignored.\nfunc (wb *WindowBase) SetMinMaxSizePixels(min, max Size) error {\n\tdpi := wb.DPI()\n\treturn wb.SetMinMaxSize(SizeTo96DPI(min, dpi), SizeTo96DPI(max, dpi))\n}\n\ntype fontInfoAndDPI struct {\n\tfontInfo\n\tdpi int\n}\n\nvar (\n\tdialogBaseUnitsUTF16StringPtr  *uint16\n\tfontInfoAndDPI2DialogBaseUnits = make(map[fontInfoAndDPI]Size)\n)\n\n// dialogBaseUnits returns dialog unit base size in native pixels.\nfunc (wb *WindowBase) dialogBaseUnits() Size {\n\t// The window may use a font different from that in WindowBase,\n\t// like e.g. NumberEdit does, so we try to use the right one.\n\tfont := wb.window.Font()\n\tfi := fontInfoAndDPI{\n\t\tfontInfo: fontInfo{\n\t\t\tfamily:    font.Family(),\n\t\t\tpointSize: font.PointSize(),\n\t\t\tstyle:     font.Style(),\n\t\t},\n\t\tdpi: wb.DPI()}\n\tif s, ok := fontInfoAndDPI2DialogBaseUnits[fi]; ok {\n\t\treturn s\n\t}\n\n\thdc := win.GetDC(wb.hWnd)\n\tdefer win.ReleaseDC(wb.hWnd, hdc)\n\n\thFont := font.handleForDPI(wb.DPI())\n\thFontOld := win.SelectObject(hdc, win.HGDIOBJ(hFont))\n\tdefer win.SelectObject(hdc, win.HGDIOBJ(hFontOld))\n\n\tvar tm win.TEXTMETRIC\n\tif !win.GetTextMetrics(hdc, &tm) {\n\t\tnewError(\"GetTextMetrics failed\")\n\t}\n\n\tvar size win.SIZE\n\tif !win.GetTextExtentPoint32(\n\t\thdc,\n\t\tdialogBaseUnitsUTF16StringPtr,\n\t\t52,\n\t\t&size) {\n\t\tnewError(\"GetTextExtentPoint32 failed\")\n\t}\n\n\ts := Size{int((size.CX/26 + 1) / 2), int(tm.TmHeight)}\n\n\tfontInfoAndDPI2DialogBaseUnits[fi] = s\n\n\treturn s\n}\n\n// dialogBaseUnitsToPixels returns size in dialog based units in native pixels.\nfunc (wb *WindowBase) dialogBaseUnitsToPixels(dlus Size) (pixels Size) {\n\tbase := wb.dialogBaseUnits()\n\n\treturn Size{\n\t\tint(win.MulDiv(int32(dlus.Width), int32(base.Width), 4)),\n\t\tint(win.MulDiv(int32(dlus.Height), int32(base.Height), 8)),\n\t}\n}\n\n// calculateTextSizeImpl returns text size in native pixels.\nfunc (wb *WindowBase) calculateTextSizeImpl(text string) Size {\n\treturn wb.calculateTextSizeImplForWidth(text, 0)\n}\n\n// calculateTextSizeImplForWidth calculates text size for specified width in native pixels.\nfunc (wb *WindowBase) calculateTextSizeImplForWidth(text string, width int) Size {\n\tfont := wb.window.Font()\n\n\tdpi := wb.DPI()\n\n\tw := width\n\tif w == 0 {\n\t\tw = wb.WidthPixels()\n\t}\n\n\tkey := calcTextSizeInfo{\n\t\twidth: w,\n\t\tfont: fontInfo{\n\t\t\tfamily:    font.family,\n\t\t\tpointSize: font.pointSize,\n\t\t\tstyle:     font.style,\n\t\t},\n\t\ttext: text,\n\t\tdpi:  dpi,\n\t}\n\n\tif size, ok := wb.calcTextSizeInfo2TextSize[key]; ok {\n\t\treturn size\n\t}\n\n\tsize := calculateTextSize(text, font, dpi, width, wb.hWnd)\n\n\twb.calcTextSizeInfo2TextSize[key] = size\n\n\treturn size\n}\n\n// calculateTextSize calculates text size in native pixels.\nfunc (wb *WindowBase) calculateTextSize() Size {\n\treturn wb.calculateTextSizeForWidth(0)\n}\n\n// calculateTextSizeForWidth calculates text size for specified width in native pixels.\nfunc (wb *WindowBase) calculateTextSizeForWidth(width int) Size {\n\treturn wb.calculateTextSizeImplForWidth(wb.text(), width)\n}\n\n// calculateTextSize calculates text size at specified DPI and for width in native pixels.\nfunc calculateTextSize(text string, font *Font, dpi int, width int, hwnd win.HWND) Size {\n\thdc := win.GetDC(hwnd)\n\tif hdc == 0 {\n\t\tnewError(\"GetDC failed\")\n\t\treturn Size{}\n\t}\n\tdefer win.ReleaseDC(hwnd, hdc)\n\n\tvar size Size\n\tif width > 0 {\n\t\tcanvas, err := newCanvasFromHDC(hdc)\n\t\tif err != nil {\n\t\t\treturn size\n\t\t}\n\t\tdefer canvas.Dispose()\n\n\t\tbounds, err := canvas.measureTextForDPI(text, font, Rectangle{Width: width, Height: 9999999}, 0, dpi)\n\t\tif err != nil {\n\t\t\treturn size\n\t\t}\n\n\t\tsize = bounds.Size()\n\t} else {\n\t\thFontOld := win.SelectObject(hdc, win.HGDIOBJ(font.handleForDPI(dpi)))\n\t\tdefer win.SelectObject(hdc, hFontOld)\n\n\t\tlines := strings.Split(text, \"\\n\")\n\n\t\tfor _, line := range lines {\n\t\t\tvar s win.SIZE\n\t\t\tstr := syscall.StringToUTF16(strings.TrimRight(line, \"\\r \"))\n\n\t\t\tif !win.GetTextExtentPoint32(hdc, &str[0], int32(len(str)-1), &s) {\n\t\t\t\tnewError(\"GetTextExtentPoint32 failed\")\n\t\t\t\treturn Size{}\n\t\t\t}\n\n\t\t\tsize.Width = maxi(size.Width, int(s.CX))\n\t\t\tsize.Height += int(s.CY)\n\t\t}\n\t}\n\n\treturn size\n}\n\n// Size returns the outer size of the *WindowBase, including decorations.\nfunc (wb *WindowBase) Size() Size {\n\treturn wb.SizeTo96DPI(wb.SizePixels())\n}\n\n// SizePixels returns the outer size of the *WindowBase, including decorations.\nfunc (wb *WindowBase) SizePixels() Size {\n\treturn wb.window.BoundsPixels().Size()\n}\n\n// SetSize sets the outer size of the *WindowBase, including decorations.\nfunc (wb *WindowBase) SetSize(size Size) error {\n\treturn wb.SetSizePixels(wb.SizeFrom96DPI(size))\n}\n\n// SetSizePixels sets the outer size of the *WindowBase, including decorations.\nfunc (wb *WindowBase) SetSizePixels(size Size) error {\n\tbounds := wb.window.BoundsPixels()\n\n\treturn wb.SetBoundsPixels(bounds.SetSize(size))\n}\n\n// X returns the x coordinate of the *WindowBase, relative to the screen for\n// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n// child Windows.\nfunc (wb *WindowBase) X() int {\n\treturn wb.IntTo96DPI(wb.XPixels())\n}\n\n// XPixels returns the x coordinate of the *WindowBase, relative to the screen for\n// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n// child Windows.\nfunc (wb *WindowBase) XPixels() int {\n\treturn wb.window.BoundsPixels().X\n}\n\n// SetX sets the x coordinate of the *WindowBase, relative to the screen for\n// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n// child Windows.\nfunc (wb *WindowBase) SetX(value int) error {\n\treturn wb.SetXPixels(wb.IntFrom96DPI(value))\n}\n\n// SetXPixels sets the x coordinate of the *WindowBase, relative to the screen for\n// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n// child Windows.\nfunc (wb *WindowBase) SetXPixels(value int) error {\n\tbounds := wb.window.BoundsPixels()\n\tbounds.X = value\n\n\treturn wb.SetBoundsPixels(bounds)\n}\n\n// Y returns the y coordinate of the *WindowBase, relative to the screen for\n// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n// child Windows.\nfunc (wb *WindowBase) Y() int {\n\treturn wb.IntTo96DPI(wb.YPixels())\n}\n\n// YPixels returns the y coordinate of the *WindowBase, relative to the screen for\n// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n// child Windows.\nfunc (wb *WindowBase) YPixels() int {\n\treturn wb.window.BoundsPixels().Y\n}\n\n// SetY sets the y coordinate of the *WindowBase, relative to the screen for\n// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n// child Windows.\nfunc (wb *WindowBase) SetY(value int) error {\n\treturn wb.SetYPixels(wb.IntFrom96DPI(value))\n}\n\n// SetYPixels sets the y coordinate of the *WindowBase, relative to the screen for\n// RootWidgets like *MainWindow or *Dialog and relative to the parent for\n// child Windows.\nfunc (wb *WindowBase) SetYPixels(value int) error {\n\tbounds := wb.window.BoundsPixels()\n\tbounds.Y = value\n\n\treturn wb.SetBoundsPixels(bounds)\n}\n\n// Width returns the outer width of the *WindowBase, including decorations.\nfunc (wb *WindowBase) Width() int {\n\treturn wb.IntTo96DPI(wb.WidthPixels())\n}\n\n// WidthPixels returns the outer width of the *WindowBase, including decorations.\nfunc (wb *WindowBase) WidthPixels() int {\n\treturn wb.window.BoundsPixels().Width\n}\n\n// SetWidth sets the outer width of the *WindowBase, including decorations.\nfunc (wb *WindowBase) SetWidth(value int) error {\n\treturn wb.SetWidthPixels(wb.IntFrom96DPI(value))\n}\n\n// SetWidthPixels sets the outer width of the *WindowBase, including decorations.\nfunc (wb *WindowBase) SetWidthPixels(value int) error {\n\tbounds := wb.window.BoundsPixels()\n\tbounds.Width = value\n\n\treturn wb.SetBoundsPixels(bounds)\n}\n\n// Height returns the outer height of the *WindowBase, including decorations.\nfunc (wb *WindowBase) Height() int {\n\treturn wb.IntTo96DPI(wb.HeightPixels())\n}\n\n// HeightPixels returns the outer height of the *WindowBase, including decorations.\nfunc (wb *WindowBase) HeightPixels() int {\n\treturn wb.window.BoundsPixels().Height\n}\n\n// SetHeight sets the outer height of the *WindowBase, including decorations.\nfunc (wb *WindowBase) SetHeight(value int) error {\n\treturn wb.SetHeightPixels(wb.IntFrom96DPI(value))\n}\n\n// SetHeightPixels sets the outer height of the *WindowBase, including decorations.\nfunc (wb *WindowBase) SetHeightPixels(value int) error {\n\tbounds := wb.window.BoundsPixels()\n\tbounds.Height = value\n\n\treturn wb.SetBoundsPixels(bounds)\n}\n\nfunc windowTrimToClientBounds(hwnd win.HWND, pt *win.POINT) {\n\tvar r win.RECT\n\n\tif !win.GetClientRect(hwnd, &r) {\n\t\tlastError(\"GetClientRect\")\n\t\treturn\n\t}\n\n\tif pt.X < r.Left {\n\t\tpt.X = r.Left\n\t}\n\tif pt.X > r.Right {\n\t\tpt.X = r.Right\n\t}\n\tif pt.Y < r.Top {\n\t\tpt.Y = r.Top\n\t}\n\tif pt.Y > r.Bottom {\n\t\tpt.Y = r.Bottom\n\t}\n}\n\n// windowClientBounds returns window client bounds in native pixels.\nfunc windowClientBounds(hwnd win.HWND) Rectangle {\n\tvar r win.RECT\n\n\tif !win.GetClientRect(hwnd, &r) {\n\t\tlastError(\"GetClientRect\")\n\t\treturn Rectangle{}\n\t}\n\n\treturn rectangleFromRECT(r)\n}\n\n// ClientBounds returns the inner bounding box rectangle of the *WindowBase,\n// excluding decorations.\nfunc (wb *WindowBase) ClientBounds() Rectangle {\n\treturn wb.RectangleTo96DPI(wb.ClientBoundsPixels())\n}\n\n// ClientBoundsPixels returns the inner bounding box rectangle of the *WindowBase,\n// excluding decorations.\nfunc (wb *WindowBase) ClientBoundsPixels() Rectangle {\n\treturn windowClientBounds(wb.hWnd)\n}\n\n// sizeFromClientSizePixels calculates size from client size in native pixels.\nfunc (wb *WindowBase) sizeFromClientSizePixels(clientSize Size) Size {\n\twindow := wb.window\n\ts := window.SizePixels()\n\tcs := window.ClientBoundsPixels().Size()\n\tncs := Size{s.Width - cs.Width, s.Height - cs.Height}\n\n\treturn Size{clientSize.Width + ncs.Width, clientSize.Height + ncs.Height}\n}\n\n// clientSizeFromSizePixels calculates client size from size in native pixels.\nfunc (wb *WindowBase) clientSizeFromSizePixels(size Size) Size {\n\twindow := wb.window\n\ts := window.SizePixels()\n\tcs := window.ClientBoundsPixels().Size()\n\tncs := Size{s.Width - cs.Width, s.Height - cs.Height}\n\n\treturn Size{size.Width - ncs.Width, size.Height - ncs.Height}\n}\n\n// SetClientSize sets the size of the inner bounding box of the *WindowBase,\n// excluding decorations.\nfunc (wb *WindowBase) SetClientSize(value Size) error {\n\treturn wb.SetClientSizePixels(wb.SizeFrom96DPI(value))\n}\n\n// SetClientSizePixels sets the size of the inner bounding box of the *WindowBase,\n// excluding decorations.\nfunc (wb *WindowBase) SetClientSizePixels(value Size) error {\n\treturn wb.SetSizePixels(wb.sizeFromClientSizePixels(value))\n}\n\n// RequestLayout either schedules or immediately starts performing layout.\nfunc (wb *WindowBase) RequestLayout() {\n\tvar form Form\n\n\thwnd := wb.hWnd\n\twindow := wb.window\n\n\tfor hwnd != 0 {\n\t\tif window != nil {\n\t\t\tvar ok, visible bool\n\t\t\tif form, ok = window.(Form); ok {\n\t\t\t\tvisible = form.Visible()\n\t\t\t} else {\n\t\t\t\tvisible = window.AsWindowBase().visible\n\t\t\t}\n\n\t\t\tif !visible && window != wb.window || window.Suspended() {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif container, ok := window.(Container); ok && container.Layout() == nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif widget, ok := window.(Widget); ok {\n\t\t\t\tif window = widget.Parent(); window != nil {\n\t\t\t\t\thwnd = window.Handle()\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t} else if !win.IsWindowVisible(hwnd) {\n\t\t\treturn\n\t\t}\n\n\t\thwnd = win.GetParent(hwnd)\n\t\twindow = windowFromHandle(hwnd)\n\t}\n\n\tif form == nil {\n\t\treturn\n\t}\n\n\tif fb := form.AsFormBase(); fb.group.ActiveForm() != form || fb.inProgressEventCount == 0 {\n\t\tfb.startLayout()\n\t} else {\n\t\tfb.layoutScheduled = true\n\t}\n}\n\n// RightToLeftReading returns whether the reading order of the Window\n// is from right to left.\nfunc (wb *WindowBase) RightToLeftReading() bool {\n\treturn wb.hasExtendedStyleBits(win.WS_EX_RTLREADING)\n}\n\n// SetRightToLeftReading sets whether the reading order of the Window\n// is from right to left.\nfunc (wb *WindowBase) SetRightToLeftReading(rtl bool) error {\n\treturn wb.ensureExtendedStyleBits(win.WS_EX_RTLREADING, rtl)\n}\n\n// Screenshot returns an image of the window.\nfunc (wb *WindowBase) Screenshot() (*image.RGBA, error) {\n\tbmp, err := NewBitmapFromWindow(wb)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer bmp.Dispose()\n\n\treturn bmp.ToImage()\n}\n\n// FocusedWindow returns the Window that has the keyboard input focus.\nfunc FocusedWindow() Window {\n\treturn windowFromHandle(win.GetFocus())\n}\n\n// Focused returns whether the Window has the keyboard input focus.\nfunc (wb *WindowBase) Focused() bool {\n\treturn wb.hWnd == win.GetFocus()\n}\n\n// SetFocus sets the keyboard input focus to the *WindowBase.\nfunc (wb *WindowBase) SetFocus() error {\n\tif win.SetFocus(wb.hWnd) == 0 {\n\t\treturn lastError(\"SetFocus\")\n\t}\n\n\treturn nil\n}\n\n// FocusedChanged returns an Event that you can attach to for handling focus\n// change events for the WindowBase.\nfunc (wb *WindowBase) FocusedChanged() *Event {\n\treturn wb.focusedChangedPublisher.Event()\n}\n\n// CreateCanvas creates and returns a *Canvas that can be used to draw\n// inside the ClientBoundsPixels of the *WindowBase.\n//\n// Remember to call the Dispose method on the canvas to release resources,\n// when you no longer need it.\nfunc (wb *WindowBase) CreateCanvas() (*Canvas, error) {\n\treturn newCanvasFromWindow(wb.window)\n}\n\nfunc (wb *WindowBase) setTheme(appName string) error {\n\tif hr := win.SetWindowTheme(wb.hWnd, syscall.StringToUTF16Ptr(appName), nil); win.FAILED(hr) {\n\t\treturn errorFromHRESULT(\"SetWindowTheme\", hr)\n\t}\n\n\treturn nil\n}\n\n// KeyDown returns a *KeyEvent that you can attach to for handling key down\n// events for the *WindowBase.\nfunc (wb *WindowBase) KeyDown() *KeyEvent {\n\treturn wb.keyDownPublisher.Event()\n}\n\n// KeyPress returns a *KeyEvent that you can attach to for handling key press\n// events for the *WindowBase.\nfunc (wb *WindowBase) KeyPress() *KeyEvent {\n\treturn wb.keyPressPublisher.Event()\n}\n\n// KeyUp returns a *KeyEvent that you can attach to for handling key up\n// events for the *WindowBase.\nfunc (wb *WindowBase) KeyUp() *KeyEvent {\n\treturn wb.keyUpPublisher.Event()\n}\n\n// DropFiles returns a *DropFilesEvent that you can attach to for handling\n// drop file events for the *WindowBase.\nfunc (wb *WindowBase) DropFiles() *DropFilesEvent {\n\treturn wb.dropFilesPublisher.Event(wb.hWnd)\n}\n\n// MouseDown returns a *MouseEvent that you can attach to for handling\n// mouse down events for the *WindowBase.\nfunc (wb *WindowBase) MouseDown() *MouseEvent {\n\treturn wb.mouseDownPublisher.Event()\n}\n\n// MouseMove returns a *MouseEvent that you can attach to for handling\n// mouse move events for the *WindowBase.\nfunc (wb *WindowBase) MouseMove() *MouseEvent {\n\treturn wb.mouseMovePublisher.Event()\n}\n\n// MouseUp returns a *MouseEvent that you can attach to for handling\n// mouse up events for the *WindowBase.\nfunc (wb *WindowBase) MouseUp() *MouseEvent {\n\treturn wb.mouseUpPublisher.Event()\n}\n\nfunc (wb *WindowBase) MouseWheel() *MouseEvent {\n\treturn wb.mouseWheelPublisher.Event()\n}\n\nfunc (wb *WindowBase) publishMouseEvent(publisher *MouseEventPublisher, msg uint32, wParam, lParam uintptr) {\n\tx := int(win.GET_X_LPARAM(lParam))\n\ty := int(win.GET_Y_LPARAM(lParam))\n\n\tvar button MouseButton\n\tswitch msg {\n\tcase win.WM_LBUTTONUP:\n\t\tbutton = LeftButton\n\n\tcase win.WM_RBUTTONUP:\n\t\tbutton = RightButton\n\n\tcase win.WM_MBUTTONUP:\n\t\tbutton = MiddleButton\n\n\tdefault:\n\t\tbutton = MouseButton(wParam&win.MK_LBUTTON | wParam&win.MK_RBUTTON | wParam&win.MK_MBUTTON)\n\t}\n\n\tpublisher.Publish(x, y, button)\n}\n\nfunc (wb *WindowBase) publishMouseWheelEvent(publisher *MouseEventPublisher, wParam, lParam uintptr) {\n\tx := int(win.GET_X_LPARAM(lParam))\n\ty := int(win.GET_Y_LPARAM(lParam))\n\tbutton := MouseButton(uint32(wParam))\n\n\tpublisher.Publish(x, y, button)\n}\n\n// SizeChanged returns an *Event that you can attach to for handling size\n// changed events for the *WindowBase.\nfunc (wb *WindowBase) SizeChanged() *Event {\n\treturn wb.sizeChangedPublisher.Event()\n}\n\n// BoundsChanged returns an *Event that you can attach to for handling bounds\n// changed events for the *WindowBase.\nfunc (wb *WindowBase) BoundsChanged() *Event {\n\treturn wb.boundsChangedPublisher.Event()\n}\n\n// Synchronize enqueues func f to be called some time later by the main\n// goroutine from inside a message loop.\nfunc (wb *WindowBase) Synchronize(f func()) {\n\twb.group.Synchronize(f)\n\n\twin.PostMessage(wb.hWnd, syncMsgId, 0, 0)\n}\n\n// synchronizeLayout causes the given layout computations to be applied\n// later by the message loop running on the group's thread.\n//\n// Any previously queued layout computations that have not yet been applied\n// will be replaced.\nfunc (wb *WindowBase) synchronizeLayout(result *formLayoutResult) {\n\twb.group.synchronizeLayout(result)\n\n\twin.PostMessage(wb.hWnd, syncMsgId, 0, 0)\n}\n\nfunc (wb *WindowBase) ReadState() (string, error) {\n\tsettings := App().Settings()\n\tif settings == nil {\n\t\treturn \"\", newError(\"App().Settings() must not be nil\")\n\t}\n\n\tstate, _ := settings.Get(wb.path())\n\treturn state, nil\n}\n\nfunc (wb *WindowBase) WriteState(state string) error {\n\tsettings := App().Settings()\n\tif settings == nil {\n\t\treturn newError(\"App().Settings() must not be nil\")\n\t}\n\n\tp := wb.path()\n\tif strings.HasPrefix(p, \"/\") ||\n\t\tstrings.HasSuffix(p, \"/\") ||\n\t\tstrings.Contains(p, \"//\") {\n\n\t\treturn nil\n\t}\n\n\treturn settings.PutExpiring(p, state)\n}\n\nfunc windowFromHandle(hwnd win.HWND) Window {\n\tif wb := hwnd2WindowBase[hwnd]; wb != nil {\n\t\treturn wb.window\n\t}\n\n\treturn nil\n}\n\nfunc defaultWndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) (result uintptr) {\n\tdefer func() {\n\t\t// FIXME: Rework the panicking publisher so that we don't have to\n\t\t// access a private member here.\n\t\tif len(App().panickingPublisher.event.handlers) > 0 {\n\t\t\tvar err error\n\t\t\tif x := recover(); x != nil {\n\t\t\t\tif e, ok := x.(error); ok {\n\t\t\t\t\terr = wrapErrorNoPanic(e)\n\t\t\t\t} else {\n\t\t\t\t\terr = newErrorNoPanic(fmt.Sprint(x))\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tApp().panickingPublisher.Publish(err)\n\t\t\t}\n\t\t}\n\t}()\n\n\tif msg == notifyIconMessageId {\n\t\treturn notifyIconWndProc(hwnd, msg, wParam, lParam)\n\t}\n\n\twi := windowFromHandle(hwnd)\n\tif wi == nil {\n\t\treturn win.DefWindowProc(hwnd, msg, wParam, lParam)\n\t}\n\n\tresult = wi.WndProc(hwnd, msg, wParam, lParam)\n\n\treturn\n}\n\ntype menuer interface {\n\tMenu() *Menu\n}\n\nfunc menuContainsAction(menu *Menu, action *Action) bool {\n\tif menu.Actions().Contains(action) {\n\t\treturn true\n\t}\n\n\tfor _, a := range menu.actions.actions {\n\t\tif a.menu != nil && menuContainsAction(a.menu, action) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (wb *WindowBase) handleKeyDown(wParam, lParam uintptr) {\n\tkey := Key(wParam)\n\n\tif uint32(lParam)>>30 == 0 {\n\t\twb.keyDownPublisher.Publish(key)\n\n\t\t// Using TranslateAccelerators refused to work, so we handle them\n\t\t// ourselves, at least for now.\n\t\tshortcut := Shortcut{ModifiersDown(), key}\n\t\tif action, ok := shortcut2Action[shortcut]; ok {\n\t\t\tif action.Visible() && action.Enabled() {\n\t\t\t\twindow := wb.window\n\n\t\t\t\tif w, ok := window.(Widget); ok {\n\t\t\t\t\twindow = ancestor(w)\n\t\t\t\t}\n\n\t\t\t\tif m, ok := window.(menuer); ok && menuContainsAction(m.Menu(), action) {\n\t\t\t\t\taction.raiseTriggered()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch key {\n\tcase KeyAlt, KeyControl, KeyShift:\n\t\t// nop\n\n\tdefault:\n\t\twb.keyPressPublisher.Publish(key)\n\t}\n}\n\nfunc (wb *WindowBase) handleKeyUp(wParam, lParam uintptr) {\n\twb.keyUpPublisher.Publish(Key(wParam))\n}\n\nfunc (wb *WindowBase) backgroundEffective() (Brush, Window) {\n\twnd := wb.window\n\tbg := wnd.Background()\n\n\tif widget, ok := wb.window.(Widget); ok {\n\t\tfor bg == nullBrushSingleton && widget != nil {\n\t\t\tif hwndParent := win.GetParent(widget.Handle()); hwndParent != 0 {\n\t\t\t\tif parent := windowFromHandle(hwndParent); parent != nil {\n\t\t\t\t\twnd = parent\n\t\t\t\t\tbg = parent.Background()\n\n\t\t\t\t\twidget, _ = parent.(Widget)\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif bg != nil {\n\t\tif pwb, ok := bg.(perWindowBrush); ok {\n\t\t\tbg = pwb.delegateForWindow(wnd.AsWindowBase())\n\t\t}\n\t}\n\n\treturn bg, wnd\n}\n\nfunc (wb *WindowBase) prepareDCForBackground(hdc win.HDC, hwnd win.HWND, brushWnd Window) {\n\tif _, ok := brushWnd.(Container); ok {\n\t\twin.SetBkMode(hdc, win.TRANSPARENT)\n\t}\n\n\tvar bgRC win.RECT\n\twin.GetWindowRect(brushWnd.Handle(), &bgRC)\n\n\tvar rc win.RECT\n\twin.GetWindowRect(hwnd, &rc)\n\n\twin.SetBrushOrgEx(hdc, bgRC.Left-rc.Left, bgRC.Top-rc.Top, nil)\n}\n\nfunc (wb *WindowBase) handleWMCTLCOLOR(wParam, lParam uintptr) uintptr {\n\thwnd := win.HWND(lParam)\n\thdc := win.HDC(wParam)\n\n\ttype TextColorer interface {\n\t\tTextColor() Color\n\t}\n\n\twnd := windowFromHandle(hwnd)\n\tif wnd == nil {\n\t\tswitch windowFromHandle(win.GetParent(hwnd)).(type) {\n\t\tcase *ComboBox:\n\t\t\t// nop\n\t\t\treturn 0\n\t\t}\n\n\t\twnd = wb\n\t} else if tc, ok := wnd.(TextColorer); ok {\n\t\tcolor := tc.TextColor()\n\t\tif color == 0 {\n\t\t\tcolor = Color(win.GetSysColor(win.COLOR_WINDOWTEXT))\n\t\t}\n\t\twin.SetTextColor(hdc, win.COLORREF(color))\n\t}\n\n\tif bg, wnd := wnd.AsWindowBase().backgroundEffective(); bg != nil {\n\t\twb.prepareDCForBackground(hdc, hwnd, wnd)\n\n\t\ttype Colorer interface {\n\t\t\tColor() Color\n\t\t}\n\n\t\tif c, ok := bg.(Colorer); ok {\n\t\t\twin.SetBkColor(hdc, win.COLORREF(c.Color()))\n\t\t}\n\n\t\treturn uintptr(bg.handle())\n\t}\n\n\tswitch wnd.(type) {\n\tcase *LineEdit, *numberLineEdit, *TextEdit:\n\t\ttype ReadOnlyer interface {\n\t\t\tReadOnly() bool\n\t\t}\n\n\t\tvar sysColor int\n\t\tif ro, ok := wnd.(ReadOnlyer); ok && ro.ReadOnly() {\n\t\t\tsysColor = win.COLOR_BTNFACE\n\t\t} else {\n\t\t\tsysColor = win.COLOR_WINDOW\n\t\t}\n\n\t\twin.SetBkColor(hdc, win.COLORREF(win.GetSysColor(sysColor)))\n\n\t\treturn uintptr(win.GetSysColorBrush(sysColor))\n\t}\n\n\treturn 0\n}\n\n// WndProc is the window procedure of the window.\n//\n// When implementing your own WndProc to add or modify behavior, call the\n// WndProc of the embedded window for messages you don't handle yourself.\nfunc (wb *WindowBase) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\twindow := windowFromHandle(hwnd)\n\n\tswitch msg {\n\tcase win.WM_ERASEBKGND:\n\t\tif _, ok := window.(Widget); !ok {\n\t\t\treturn 0\n\t\t}\n\n\t\tbg, wnd := wb.backgroundEffective()\n\t\tif bg == nil {\n\t\t\tbreak\n\t\t}\n\n\t\thdc := win.HDC(wParam)\n\n\t\tcanvas, err := newCanvasFromHDC(hdc)\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\tdefer canvas.Dispose()\n\n\t\twb.prepareDCForBackground(hdc, hwnd, wnd)\n\n\t\tif err := canvas.FillRectanglePixels(bg, wb.ClientBoundsPixels()); err != nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn 1\n\n\tcase win.WM_HSCROLL, win.WM_VSCROLL:\n\t\tif window := windowFromHandle(win.HWND(lParam)); window != nil {\n\t\t\t// The window that sent the notification shall handle it itself.\n\t\t\treturn window.WndProc(hwnd, msg, wParam, lParam)\n\t\t}\n\n\tcase win.WM_LBUTTONDOWN, win.WM_MBUTTONDOWN, win.WM_RBUTTONDOWN:\n\t\tif msg == win.WM_LBUTTONDOWN && wb.origWndProcPtr == 0 {\n\t\t\t// Only call SetCapture if this is no subclassed control.\n\t\t\t// (Otherwise e.g. WM_COMMAND(BN_CLICKED) would no longer\n\t\t\t// be generated for PushButton.)\n\t\t\twin.SetCapture(wb.hWnd)\n\t\t}\n\t\twb.publishMouseEvent(&wb.mouseDownPublisher, msg, wParam, lParam)\n\n\tcase win.WM_LBUTTONUP, win.WM_MBUTTONUP, win.WM_RBUTTONUP:\n\t\tif msg == win.WM_LBUTTONUP && wb.origWndProcPtr == 0 {\n\t\t\t// See WM_LBUTTONDOWN for why we require origWndProcPtr == 0 here.\n\t\t\tif !win.ReleaseCapture() {\n\t\t\t\tlastError(\"ReleaseCapture\")\n\t\t\t}\n\t\t}\n\t\twb.publishMouseEvent(&wb.mouseUpPublisher, msg, wParam, lParam)\n\n\tcase win.WM_MOUSEMOVE:\n\t\twb.publishMouseEvent(&wb.mouseMovePublisher, msg, wParam, lParam)\n\n\tcase win.WM_MOUSEWHEEL:\n\t\twb.publishMouseWheelEvent(&wb.mouseWheelPublisher, wParam, lParam)\n\n\tcase win.WM_SETFOCUS, win.WM_KILLFOCUS:\n\t\tswitch wnd := wb.window.(type) {\n\t\t// case *splitterHandle:\n\t\t// nop\n\n\t\tcase Widget:\n\t\t\tparent := wnd.Parent()\n\t\t\tif parent == nil {\n\t\t\t\thwndParent := win.GetParent(wnd.Handle())\n\t\t\t\tfor parent == nil && hwndParent != 0 {\n\t\t\t\t\thwndParent = win.GetParent(hwndParent)\n\t\t\t\t\tif wnd := windowFromHandle(hwndParent); wnd != nil {\n\t\t\t\t\t\tparent, _ = wnd.(Container)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif wb.Form() == wb.group.ActiveForm() {\n\t\t\t\twnd.AsWidgetBase().invalidateBorderInParent()\n\t\t\t}\n\t\t}\n\n\t\twb.focusedChangedPublisher.Publish()\n\n\tcase win.WM_SETCURSOR:\n\t\tif wb.cursor != nil {\n\t\t\twin.SetCursor(wb.cursor.handle())\n\t\t\treturn 0\n\t\t}\n\n\tcase win.WM_CONTEXTMENU:\n\t\tsourceWindow := windowFromHandle(win.HWND(wParam))\n\t\tif sourceWindow == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tcontextMenu := sourceWindow.ContextMenu()\n\n\t\tvar handle win.HWND\n\t\tif widget, ok := sourceWindow.(Widget); ok {\n\t\t\tif form := ancestor(widget); form != nil {\n\t\t\t\thandle = form.Handle()\n\t\t\t}\n\t\t}\n\n\t\tif handle == 0 {\n\t\t\thandle = sourceWindow.Handle()\n\t\t}\n\n\t\tif contextMenu != nil {\n\t\t\tx := win.GET_X_LPARAM(lParam)\n\t\t\ty := win.GET_Y_LPARAM(lParam)\n\t\t\tif x == -1 && y == -1 {\n\t\t\t\tpt := sourceWindow.ContextMenuLocation()\n\t\t\t\tx = int32(pt.X)\n\t\t\t\ty = int32(pt.Y)\n\t\t\t}\n\n\t\t\tcontextMenu.updateItemsWithImageForWindow(wb.window)\n\n\t\t\twin.TrackPopupMenuEx(\n\t\t\t\tcontextMenu.hMenu,\n\t\t\t\twin.TPM_NOANIMATION,\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\thandle,\n\t\t\t\tnil)\n\t\t\treturn 0\n\t\t}\n\n\tcase win.WM_KEYDOWN:\n\t\twb.handleKeyDown(wParam, lParam)\n\n\tcase win.WM_KEYUP:\n\t\twb.handleKeyUp(wParam, lParam)\n\n\tcase win.WM_DROPFILES:\n\t\twb.dropFilesPublisher.Publish(win.HDROP(wParam))\n\n\tcase win.WM_WINDOWPOSCHANGED:\n\t\twp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))\n\n\t\tif wp.Flags&win.SWP_NOMOVE != 0 && wp.Flags&win.SWP_NOSIZE != 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tif wp.Flags&win.SWP_NOSIZE == 0 {\n\t\t\tif widget, ok := wb.window.(Widget); ok {\n\t\t\t\twb := widget.AsWidgetBase()\n\t\t\t\twb.geometry.Size = wb.window.SizePixels()\n\t\t\t\twb.geometry.ClientSize = Size{int(wp.Cx), int(wp.Cy)}\n\n\t\t\t\twb.invalidateBorderInParent()\n\t\t\t}\n\n\t\t\twb.sizeChangedPublisher.Publish()\n\t\t}\n\n\t\twb.boundsChangedPublisher.Publish()\n\n\t\tif nws, ok := wb.window.(interface{ NeedsWmSize() bool }); !ok || !nws.NeedsWmSize() {\n\t\t\treturn 0\n\t\t}\n\n\tcase win.WM_THEMECHANGED:\n\t\twb.window.(ApplySysColorser).ApplySysColors()\n\n\tcase win.WM_DESTROY:\n\t\tif wb.origWndProcPtr != 0 {\n\t\t\t// As we subclass all windows of system classes, we prevented the\n\t\t\t// clean-up code in the WM_NCDESTROY handlers of some windows from\n\t\t\t// being called. To fix this, we restore the original window\n\t\t\t// procedure here.\n\t\t\twin.SetWindowLongPtr(wb.hWnd, win.GWLP_WNDPROC, wb.origWndProcPtr)\n\t\t}\n\n\t\tdelete(hwnd2WindowBase, hwnd)\n\n\t\twb.window.Dispose()\n\t\twb.hWnd = 0\n\t}\n\n\tif window != nil {\n\t\tif wndProc := window.AsWindowBase().origWndProcPtr; wndProc != 0 {\n\t\t\treturn win.CallWindowProc(wndProc, hwnd, msg, wParam, lParam)\n\t\t}\n\t}\n\n\treturn win.DefWindowProc(hwnd, msg, wParam, lParam)\n}\n"
  },
  {
    "path": "windowgroup.go",
    "content": "// Copyright 2019 The Walk Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// +build windows\n\npackage walk\n\nimport (\n\t\"sync\"\n\t\"unsafe\"\n\n\t\"github.com/lxn/win\"\n)\n\n// The global window group manager instance.\nvar wgm windowGroupManager\n\n// windowGroupManager manages window groups for each thread with one or\n// more windows.\ntype windowGroupManager struct {\n\tmutex  sync.RWMutex\n\tgroups map[uint32]*WindowGroup\n}\n\n// Group returns a window group for the given thread ID, if one exists.\n// If a group does not already exist it returns nil.\nfunc (m *windowGroupManager) Group(threadID uint32) *WindowGroup {\n\tm.mutex.RLock()\n\tdefer m.mutex.RUnlock()\n\tif m.groups == nil {\n\t\treturn nil\n\t}\n\treturn m.groups[threadID]\n}\n\n// CreateGroup returns a window group for the given thread ID. If one does\n// not already exist, it will be created.\n//\n// The group will have its counter incremented as a result of this call.\n// It is the caller's responsibility to call Done when finished with the\n// group.\nfunc (m *windowGroupManager) CreateGroup(threadID uint32) *WindowGroup {\n\t// Fast path with read lock\n\tm.mutex.RLock()\n\tif m.groups != nil {\n\t\tif group := m.groups[threadID]; group != nil {\n\t\t\tm.mutex.RUnlock()\n\t\t\tgroup.Add(1)\n\t\t\treturn group\n\t\t}\n\t}\n\tm.mutex.RUnlock()\n\n\t// Slow path with write lock\n\tm.mutex.Lock()\n\tif m.groups == nil {\n\t\tm.groups = make(map[uint32]*WindowGroup)\n\t} else {\n\t\tif group := m.groups[threadID]; group != nil {\n\t\t\t// Another caller raced with our lock and beat us\n\t\t\tm.mutex.Unlock()\n\t\t\tgroup.Add(1)\n\t\t\treturn group\n\t\t}\n\t}\n\n\tgroup := newWindowGroup(threadID, m.removeGroup)\n\tgroup.Add(1)\n\tm.groups[threadID] = group\n\tm.mutex.Unlock()\n\n\treturn group\n}\n\n// removeGroup is called by window groups to remove themselves from\n// the manager.\nfunc (m *windowGroupManager) removeGroup(threadID uint32) {\n\tm.mutex.Lock()\n\tdelete(m.groups, threadID)\n\tm.mutex.Unlock()\n}\n\n// WindowGroup holds data common to windows that share a thread.\n//\n// Each WindowGroup keeps track of the number of references to\n// the group. When the number of references reaches zero, the\n// group is disposed of.\ntype WindowGroup struct {\n\trefs            int // Tracks the number of windows that rely on this group\n\tignored         int // Tracks the number of refs created by the group itself\n\tthreadID        uint32\n\tcompletion      func(uint32) // Used to tell the window group manager to remove this group\n\tremoved         bool         // Has this group been removed from its manager? (used for race detection)\n\ttoolTip         *ToolTip\n\tactiveForm      Form\n\toleInit         bool\n\taccPropServices *win.IAccPropServices\n\n\tsyncMutex           sync.Mutex\n\tsyncFuncs           []func()                   // Functions queued to run on the group's thread\n\tlayoutResultsByForm map[Form]*formLayoutResult // Layout computations queued for application on the group's thread\n}\n\n// newWindowGroup returns a new window group for the given thread ID.\n//\n// The completion function will be called when the group is disposed of.\nfunc newWindowGroup(threadID uint32, completion func(uint32)) *WindowGroup {\n\thr := win.OleInitialize()\n\n\treturn &WindowGroup{\n\t\tthreadID:            threadID,\n\t\tcompletion:          completion,\n\t\toleInit:             hr == win.S_OK || hr == win.S_FALSE,\n\t\tlayoutResultsByForm: make(map[Form]*formLayoutResult),\n\t}\n}\n\n// ThreadID identifies the thread that the group is affiliated with.\nfunc (g *WindowGroup) ThreadID() uint32 {\n\treturn g.threadID\n}\n\n// Refs returns the current number of references to the group.\nfunc (g *WindowGroup) Refs() int {\n\treturn g.refs\n}\n\n// AccessibilityServices returns an instance of CLSID_AccPropServices class.\nfunc (g *WindowGroup) accessibilityServices() *win.IAccPropServices {\n\tif g.accPropServices != nil {\n\t\treturn g.accPropServices\n\t}\n\n\tvar accPropServices *win.IAccPropServices\n\thr := win.CoCreateInstance(&win.CLSID_AccPropServices, nil, win.CLSCTX_ALL, &win.IID_IAccPropServices, (*unsafe.Pointer)(unsafe.Pointer(&accPropServices)))\n\tif win.FAILED(hr) {\n\t\treturn nil\n\t}\n\n\tg.accPropServices = accPropServices\n\treturn accPropServices\n}\n\n// accPropIds is a static list of accessibility properties user (may) set for a window\n// and we should clear when the window is disposed.\nvar accPropIds = []win.MSAAPROPID{\n\twin.PROPID_ACC_DEFAULTACTION,\n\twin.PROPID_ACC_DESCRIPTION,\n\twin.PROPID_ACC_HELP,\n\twin.PROPID_ACC_KEYBOARDSHORTCUT,\n\twin.PROPID_ACC_NAME,\n\twin.PROPID_ACC_ROLE,\n\twin.PROPID_ACC_ROLEMAP,\n\twin.PROPID_ACC_STATE,\n\twin.PROPID_ACC_STATEMAP,\n\twin.PROPID_ACC_VALUEMAP,\n}\n\n// accClearHwndProps clears all window properties for Dynamic Annotation to release resources.\nfunc (g *WindowGroup) accClearHwndProps(hwnd win.HWND) {\n\tif g.accPropServices != nil {\n\t\tg.accPropServices.ClearHwndProps(hwnd, win.OBJID_CLIENT, win.CHILDID_SELF, accPropIds)\n\t}\n}\n\n// Add changes the group's reference counter by delta, which may be negative.\n//\n// If the reference counter becomes zero the group will be disposed of.\n//\n// If the reference counter goes negative Add will panic.\nfunc (g *WindowGroup) Add(delta int) {\n\tif g.removed {\n\t\tpanic(\"walk: add() called on a WindowGroup that has been removed from its manager\")\n\t}\n\n\tg.refs += delta\n\tif g.refs < 0 {\n\t\tpanic(\"walk: negative WindowGroup refs counter\")\n\t}\n\tif g.refs-g.ignored == 0 {\n\t\tg.dispose()\n\t}\n}\n\n// Done decrements the group's reference counter by one.\nfunc (g *WindowGroup) Done() {\n\tg.Add(-1)\n}\n\n// Synchronize adds f to the group's function queue, to be executed\n// by the message loop running on the the group's thread.\n//\n// Synchronize can be called from any thread.\nfunc (g *WindowGroup) Synchronize(f func()) {\n\tg.syncMutex.Lock()\n\tdefer g.syncMutex.Unlock()\n\tg.syncFuncs = append(g.syncFuncs, f)\n}\n\n// synchronizeLayout causes the given layout computations to be applied\n// later by the message loop running on the group's thread.\n//\n// Any previously queued layout computations for the affected form that\n// have not yet been applied will be replaced.\n//\n// synchronizeLayout can be called from any thread.\nfunc (g *WindowGroup) synchronizeLayout(result *formLayoutResult) {\n\tg.syncMutex.Lock()\n\tg.layoutResultsByForm[result.form] = result\n\tg.syncMutex.Unlock()\n}\n\n// RunSynchronized runs all of the function calls queued by Synchronize\n// and applies any layout changes queued by synchronizeLayout.\n//\n// RunSynchronized must be called by the group's thread.\nfunc (g *WindowGroup) RunSynchronized() {\n\t// Clear the list of callbacks first to avoid deadlock\n\t// if a callback itself calls Synchronize()...\n\tg.syncMutex.Lock()\n\tfuncs := g.syncFuncs\n\tvar results []*formLayoutResult\n\tfor _, result := range g.layoutResultsByForm {\n\t\tresults = append(results, result)\n\t\tdelete(g.layoutResultsByForm, result.form)\n\t}\n\tg.syncFuncs = nil\n\tg.syncMutex.Unlock()\n\n\tfor _, result := range results {\n\t\tapplyLayoutResults(result.results, result.stopwatch)\n\t}\n\tfor _, f := range funcs {\n\t\tf()\n\t}\n}\n\n// ToolTip returns the tool tip control for the group, if one exists.\nfunc (g *WindowGroup) ToolTip() *ToolTip {\n\treturn g.toolTip\n}\n\n// CreateToolTip returns a tool tip control for the group.\n//\n// If a control has not already been prepared for the group one will be\n// created.\nfunc (g *WindowGroup) CreateToolTip() (*ToolTip, error) {\n\tif g.toolTip != nil {\n\t\treturn g.toolTip, nil\n\t}\n\n\ttt, err := NewToolTip() // This must not call group.ToolTip()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tg.toolTip = tt\n\n\t// At this point the ToolTip has already added a reference for itself\n\t// to the group as part of the ToolTip's InitWindow process. We don't\n\t// want it to count toward the group's liveness, however, because it\n\t// would keep the group from cleaning up after itself.\n\t//\n\t// To solve this problem we also keep track of the number of\n\t// references that each group should ignore. The ignored references\n\t// are subtracted from the total number of references when evaluating\n\t// liveness. The expectation is that ignored references will be\n\t// removed as part of the group's disposal process.\n\tg.ignore(1)\n\n\treturn tt, nil\n}\n\n// ActiveForm returns the currently active form for the group. If no\n// form is active it returns nil.\nfunc (g *WindowGroup) ActiveForm() Form {\n\treturn g.activeForm\n}\n\n// SetActiveForm updates the currently active form for the group.\nfunc (g *WindowGroup) SetActiveForm(form Form) {\n\tg.activeForm = form\n}\n\n// ignore changes the number of references that the group will ignore.\n//\n// ignore is used internally by WindowGroup to keep track of the number\n// of references created by the group itself. When finished with a group,\n// call Done() instead.\nfunc (g *WindowGroup) ignore(delta int) {\n\tif g.removed {\n\t\tpanic(\"walk: ignore() called on a WindowGroup that has been removed from its manager\")\n\t}\n\n\tg.ignored += delta\n\tif g.ignored < 0 {\n\t\tpanic(\"walk: negative WindowGroup ignored counter\")\n\t}\n\tif g.refs-g.ignored == 0 {\n\t\tg.dispose()\n\t}\n}\n\n// dispose releases any resources consumed by the group.\nfunc (g *WindowGroup) dispose() {\n\tif g.accPropServices != nil {\n\t\tg.accPropServices.Release()\n\t\tg.accPropServices = nil\n\t}\n\n\tif g.oleInit {\n\t\twin.OleUninitialize()\n\t\tg.oleInit = false\n\t}\n\n\tif g.toolTip != nil {\n\t\tg.toolTip.Dispose()\n\t\tg.toolTip = nil\n\t}\n\tg.removed = true // race detection only\n\tg.completion(g.threadID)\n}\n"
  }
]