container.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. // Copyright 2010 The Walk Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build windows
  5. package walk
  6. import (
  7. "unsafe"
  8. )
  9. import (
  10. "github.com/lxn/win"
  11. )
  12. type Margins struct {
  13. HNear, VNear, HFar, VFar int
  14. }
  15. type Layout interface {
  16. Container() Container
  17. SetContainer(value Container)
  18. Margins() Margins
  19. SetMargins(value Margins) error
  20. Spacing() int
  21. SetSpacing(value int) error
  22. LayoutFlags() LayoutFlags
  23. MinSize() Size
  24. Update(reset bool) error
  25. }
  26. func shouldLayoutWidget(widget Widget) bool {
  27. if widget == nil {
  28. return false
  29. }
  30. _, isSpacer := widget.(*Spacer)
  31. return isSpacer || widget.AsWindowBase().visible || widget.AlwaysConsumeSpace()
  32. }
  33. func DescendantByName(container Container, name string) Widget {
  34. var widget Widget
  35. walkDescendants(container.AsContainerBase(), func(w Window) bool {
  36. if w.Name() == name {
  37. widget = w.(Widget)
  38. return false
  39. }
  40. return true
  41. })
  42. if widget == nil {
  43. return nil
  44. }
  45. return widget
  46. }
  47. type Container interface {
  48. Window
  49. AsContainerBase() *ContainerBase
  50. Children() *WidgetList
  51. Layout() Layout
  52. SetLayout(value Layout) error
  53. DataBinder() *DataBinder
  54. SetDataBinder(dbm *DataBinder)
  55. }
  56. type ContainerBase struct {
  57. WidgetBase
  58. layout Layout
  59. children *WidgetList
  60. dataBinder *DataBinder
  61. persistent bool
  62. }
  63. func (cb *ContainerBase) AsWidgetBase() *WidgetBase {
  64. return &cb.WidgetBase
  65. }
  66. func (cb *ContainerBase) AsContainerBase() *ContainerBase {
  67. return cb
  68. }
  69. func (cb *ContainerBase) LayoutFlags() LayoutFlags {
  70. if cb.layout == nil {
  71. return 0
  72. }
  73. return cb.layout.LayoutFlags()
  74. }
  75. func (cb *ContainerBase) MinSizeHint() Size {
  76. if cb.layout == nil {
  77. return Size{}
  78. }
  79. return cb.layout.MinSize()
  80. }
  81. func (cb *ContainerBase) applyEnabled(enabled bool) {
  82. cb.WidgetBase.applyEnabled(enabled)
  83. applyEnabledToDescendants(cb.window.(Widget), enabled)
  84. }
  85. func (cb *ContainerBase) applyFont(font *Font) {
  86. cb.WidgetBase.applyFont(font)
  87. applyFontToDescendants(cb.window.(Widget), font)
  88. }
  89. func (cb *ContainerBase) Children() *WidgetList {
  90. return cb.children
  91. }
  92. func (cb *ContainerBase) Layout() Layout {
  93. return cb.layout
  94. }
  95. func (cb *ContainerBase) SetLayout(value Layout) error {
  96. if cb.layout != value {
  97. if cb.layout != nil {
  98. cb.layout.SetContainer(nil)
  99. }
  100. cb.layout = value
  101. if value != nil && value.Container() != Container(cb) {
  102. value.SetContainer(cb)
  103. }
  104. }
  105. return nil
  106. }
  107. func (cb *ContainerBase) DataBinder() *DataBinder {
  108. return cb.dataBinder
  109. }
  110. func (cb *ContainerBase) SetDataBinder(db *DataBinder) {
  111. if db == cb.dataBinder {
  112. return
  113. }
  114. if cb.dataBinder != nil {
  115. cb.dataBinder.SetBoundWidgets(nil)
  116. }
  117. cb.dataBinder = db
  118. if db != nil {
  119. var boundWidgets []Widget
  120. walkDescendants(cb.window, func(w Window) bool {
  121. if w.Handle() == cb.hWnd {
  122. return true
  123. }
  124. if c, ok := w.(Container); ok && c.DataBinder() != nil {
  125. return false
  126. }
  127. for _, prop := range w.AsWindowBase().name2Property {
  128. if _, ok := prop.Source().(string); ok {
  129. boundWidgets = append(boundWidgets, w.(Widget))
  130. break
  131. }
  132. }
  133. return true
  134. })
  135. db.SetBoundWidgets(boundWidgets)
  136. }
  137. }
  138. func (cb *ContainerBase) forEachPersistableChild(f func(p Persistable) error) error {
  139. if cb.children == nil {
  140. return nil
  141. }
  142. for _, child := range cb.children.items {
  143. if persistable, ok := child.(Persistable); ok && persistable.Persistent() {
  144. if err := f(persistable); err != nil {
  145. return err
  146. }
  147. }
  148. }
  149. return nil
  150. }
  151. func (cb *ContainerBase) Persistent() bool {
  152. return cb.persistent
  153. }
  154. func (cb *ContainerBase) SetPersistent(value bool) {
  155. cb.persistent = value
  156. }
  157. func (cb *ContainerBase) SaveState() error {
  158. return cb.forEachPersistableChild(func(p Persistable) error {
  159. return p.SaveState()
  160. })
  161. }
  162. func (cb *ContainerBase) RestoreState() error {
  163. return cb.forEachPersistableChild(func(p Persistable) error {
  164. return p.RestoreState()
  165. })
  166. }
  167. func (cb *ContainerBase) SetSuspended(suspend bool) {
  168. wasSuspended := cb.Suspended()
  169. cb.WidgetBase.SetSuspended(suspend)
  170. if !suspend && wasSuspended && cb.layout != nil {
  171. cb.layout.Update(false)
  172. }
  173. }
  174. func (cb *ContainerBase) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {
  175. switch msg {
  176. case win.WM_COMMAND:
  177. if lParam == 0 {
  178. switch win.HIWORD(uint32(wParam)) {
  179. case 0:
  180. cmdId := win.LOWORD(uint32(wParam))
  181. switch cmdId {
  182. case win.IDOK, win.IDCANCEL:
  183. form := ancestor(cb)
  184. if form == nil {
  185. break
  186. }
  187. dlg, ok := form.(dialogish)
  188. if !ok {
  189. break
  190. }
  191. var button *PushButton
  192. if cmdId == win.IDOK {
  193. button = dlg.DefaultButton()
  194. } else {
  195. button = dlg.CancelButton()
  196. }
  197. if button != nil && button.Visible() && button.Enabled() {
  198. button.raiseClicked()
  199. }
  200. break
  201. }
  202. // Menu
  203. actionId := uint16(win.LOWORD(uint32(wParam)))
  204. if action, ok := actionsById[actionId]; ok {
  205. action.raiseTriggered()
  206. return 0
  207. }
  208. case 1:
  209. // Accelerator
  210. }
  211. } else {
  212. // The window that sent the notification shall handle it itself.
  213. hWnd := win.HWND(lParam)
  214. if window := windowFromHandle(hWnd); window != nil {
  215. window.WndProc(hwnd, msg, wParam, lParam)
  216. return 0
  217. }
  218. }
  219. case win.WM_NOTIFY:
  220. nmh := (*win.NMHDR)(unsafe.Pointer(lParam))
  221. if window := windowFromHandle(nmh.HwndFrom); window != nil {
  222. // The window that sent the notification shall handle it itself.
  223. return window.WndProc(hwnd, msg, wParam, lParam)
  224. }
  225. case win.WM_HSCROLL, win.WM_VSCROLL:
  226. if window := windowFromHandle(win.HWND(lParam)); window != nil {
  227. // The window that sent the notification shall handle it itself.
  228. return window.WndProc(hwnd, msg, wParam, lParam)
  229. }
  230. case win.WM_SIZE, win.WM_SIZING:
  231. if cb.layout != nil {
  232. cb.layout.Update(false)
  233. }
  234. }
  235. return cb.WidgetBase.WndProc(hwnd, msg, wParam, lParam)
  236. }
  237. func (cb *ContainerBase) onInsertingWidget(index int, widget Widget) (err error) {
  238. return nil
  239. }
  240. func (cb *ContainerBase) onInsertedWidget(index int, widget Widget) (err error) {
  241. if parent := widget.Parent(); parent == nil || parent.Handle() != cb.hWnd {
  242. if err = widget.SetParent(cb.window.(Container)); err != nil {
  243. return
  244. }
  245. }
  246. if cb.layout != nil {
  247. cb.layout.Update(true)
  248. }
  249. widget.(applyFonter).applyFont(cb.Font())
  250. return
  251. }
  252. func (cb *ContainerBase) onRemovingWidget(index int, widget Widget) (err error) {
  253. if widget.Parent() == nil {
  254. return
  255. }
  256. if widget.Parent().Handle() == cb.hWnd {
  257. err = widget.SetParent(nil)
  258. }
  259. return
  260. }
  261. func (cb *ContainerBase) onRemovedWidget(index int, widget Widget) (err error) {
  262. if cb.layout != nil {
  263. cb.layout.Update(true)
  264. }
  265. return
  266. }
  267. func (cb *ContainerBase) onClearingWidgets() (err error) {
  268. for _, widget := range cb.children.items {
  269. if widget.Parent().Handle() == cb.hWnd {
  270. if err = widget.SetParent(nil); err != nil {
  271. return
  272. }
  273. }
  274. }
  275. return
  276. }
  277. func (cb *ContainerBase) onClearedWidgets() (err error) {
  278. if cb.layout != nil {
  279. cb.layout.Update(true)
  280. }
  281. return
  282. }