diff options
author | Alexander Neumann <alexander.neumann@picos-software.com> | 2019-02-25 17:38:01 +0100 |
---|---|---|
committer | Alexander Neumann <alexander.neumann@picos-software.com> | 2019-02-25 17:38:01 +0100 |
commit | a154dd0297ec89bfb806454e36ef2b95032b1d12 (patch) | |
tree | f7e8e5963d56654ee5f8d6f64a0d6cf311671555 | |
parent | FormBase: Try to fix scrolling problems with initially focused descendant (diff) | |
download | wireguard-windows-a154dd0297ec89bfb806454e36ef2b95032b1d12.tar.xz wireguard-windows-a154dd0297ec89bfb806454e36ef2b95032b1d12.zip |
Nothing to see here. Move on.
Who needs best practices when you can just stuff mountains of accumulated entangled cruft into a single commit?
-rw-r--r-- | container.go | 46 | ||||
-rw-r--r-- | splitter.go | 98 | ||||
-rw-r--r-- | splitterhandle.go | 12 | ||||
-rw-r--r-- | splitterlayout.go | 128 | ||||
-rw-r--r-- | util.go | 10 | ||||
-rw-r--r-- | widget.go | 8 | ||||
-rw-r--r-- | widgetlist.go | 18 | ||||
-rw-r--r-- | window.go | 40 |
8 files changed, 263 insertions, 97 deletions
diff --git a/container.go b/container.go index ebf2062a..b3087709 100644 --- a/container.go +++ b/container.go @@ -116,9 +116,9 @@ type layoutResultItem struct { } func applyLayoutResults(container Container, items []layoutResultItem) error { - if applyLayoutResultsProc != 0 { - return applyLayoutResultsRun(container, items) - } + // if applyLayoutResultsProc != 0 { + // return applyLayoutResultsRun(container, items) + // } return applyLayoutResultsWalk(container, items) } @@ -167,13 +167,13 @@ func applyLayoutResultsWalk(container Container, items []layoutResultItem) error } // FIXME: Is this really necessary? - for _, item := range items { - if !shouldLayoutWidget(item.widget) || item.widget.GraphicsEffects().Len() == 0 { - continue - } - - item.widget.AsWidgetBase().invalidateBorderInParent() + // for _, item := range items { + if /*!shouldLayoutWidget(item.widget) ||*/ item.widget.GraphicsEffects().Len() == 0 { + continue } + + item.widget.AsWidgetBase().invalidateBorderInParent() + // } } if !win.EndDeferWindowPos(hdwp) { @@ -209,7 +209,7 @@ func applyLayoutResultsRun(container Container, items []layoutResultItem) error w: int32(w), h: int32(h), oldBounds: b.toRECT(), - shouldInvalidateBorderInParent: win.BoolToBOOL(shouldLayoutWidget(item.widget) && item.widget.GraphicsEffects().Len() > 0), + shouldInvalidateBorderInParent: win.BoolToBOOL( /*shouldLayoutWidget(item.widget) &&*/ item.widget.GraphicsEffects().Len() > 0), }) } @@ -265,6 +265,24 @@ func shouldLayoutWidget(widget Widget) bool { return isSpacer || widget.AsWindowBase().visible || widget.AlwaysConsumeSpace() } +func anyVisibleWidgetInHierarchy(root *WidgetBase) bool { + if root == nil || !root.visible { + return false + } + + if container, ok := root.window.(Container); ok { + for _, child := range container.Children().items { + if anyVisibleWidgetInHierarchy(child) { + return true + } + } + } else if _, ok := root.window.(*Spacer); !ok { + return true + } + + return false +} + func DescendantByName(container Container, name string) Widget { var widget Widget @@ -408,8 +426,8 @@ func (cb *ContainerBase) forEachPersistableChild(f func(p Persistable) error) er return nil } - for _, child := range cb.children.items { - if persistable, ok := child.(Persistable); ok && persistable.Persistent() { + for _, wb := range cb.children.items { + if persistable, ok := wb.window.(Persistable); ok && persistable.Persistent() { if err := f(persistable); err != nil { return err } @@ -461,7 +479,9 @@ func (cb *ContainerBase) doPaint() error { } defer canvas.Dispose() - for _, widget := range cb.children.items { + for _, wb := range cb.children.items { + widget := wb.window.(Widget) + for _, effect := range widget.GraphicsEffects().items { switch effect { case InteractionEffect: diff --git a/splitter.go b/splitter.go index 153b7969..62f7075f 100644 --- a/splitter.go +++ b/splitter.go @@ -11,9 +11,7 @@ import ( "log" "strconv" "strings" -) -import ( "github.com/lxn/win" ) @@ -127,9 +125,9 @@ func (s *Splitter) setOrientation(value Orientation) error { cursor = CursorSizeNS() } - for i, w := range s.Children().items { + for i, wb := range s.Children().items { if i%2 == 1 { - w.SetCursor(cursor) + wb.window.SetCursor(cursor) } } @@ -151,8 +149,8 @@ func (s *Splitter) updateMarginsForFocusEffect() { var affected bool if FocusEffect != nil { - for _, w := range s.children.items { - if w.GraphicsEffects().Contains(FocusEffect) { + for _, wb := range s.children.items { + if wb.window.(Widget).GraphicsEffects().Contains(FocusEffect) { affected = true break } @@ -161,8 +159,8 @@ func (s *Splitter) updateMarginsForFocusEffect() { if affected { var marginsNeeded bool - for _, w := range s.children.items { - switch w.(type) { + for _, wb := range s.children.items { + switch wb.window.(type) { case *splitterHandle, *TabWidget, Container: default: @@ -212,8 +210,8 @@ func (s *Splitter) SaveState() error { s.WriteState(buf.String()) - for _, widget := range s.children.items { - if persistable, ok := widget.(Persistable); ok { + for _, wb := range s.children.items { + if persistable, ok := wb.window.(Persistable); ok { if err := persistable.SaveState(); err != nil { return err } @@ -245,14 +243,20 @@ func (s *Splitter) RestoreState() error { return nil } - s.SetSuspended(true) - defer s.SetSuspended(false) - layout := s.layout.(*splitterLayout) + s.SetSuspended(true) + layout.suspended = true + defer func() { + layout.suspended = false + s.SetSuspended(false) + }() + regularSpace := layout.spaceForRegularWidgets() - for i, widget := range s.children.items { + for i, wb := range s.children.items { + widget := wb.window.(Widget) + if i%2 == 0 { j := i/2 + i%2 s := sizeStrs[j] @@ -290,7 +294,7 @@ func (s *Splitter) Fixed(widget Widget) bool { func (s *Splitter) SetFixed(widget Widget, fixed bool) error { item := s.layout.(*splitterLayout).hwnd2Item[widget.Handle()] if item == nil { - return newErr("unknown widget") + return newError("unknown widget") } item.fixed = fixed @@ -304,6 +308,18 @@ func (s *Splitter) SetFixed(widget Widget, fixed bool) error { return nil } +func (s *Splitter) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr { + switch msg { + case win.WM_SIZE: + layout := s.layout.(*splitterLayout) + for _, item := range layout.hwnd2Item { + item.oldExplicitSize = 0 + } + } + + return s.ContainerBase.WndProc(hwnd, msg, wParam, lParam) +} + func (s *Splitter) onInsertingWidget(index int, widget Widget) (err error) { return s.ContainerBase.onInsertingWidget(index, widget) } @@ -326,7 +342,13 @@ func (s *Splitter) onInsertedWidget(index int, widget Widget) (err error) { } } else { layout := s.Layout().(*splitterLayout) - layout.hwnd2Item[widget.Handle()] = &splitterLayoutItem{stretchFactor: 1} + item := &splitterLayoutItem{stretchFactor: 1} + layout.hwnd2Item[widget.Handle()] = item + item.visibleChangedHandle = widget.AsWidgetBase().Property("Visible").Changed().Attach(func() { + if !layout.suspended && widget.AsWidgetBase().visible != item.wasVisible { + layout.Update(true) + } + }) if s.children.Len()%2 == 0 { defer func() { @@ -340,12 +362,21 @@ func (s *Splitter) onInsertedWidget(index int, widget Widget) (err error) { return } - var handleIndex int - if index == 0 { - handleIndex = 1 - } else { - handleIndex = index + closestVisibleWidget := func(offset, direction int) Widget { + index := offset + direction + + for index >= 0 && index < len(s.children.items) { + if wb := s.children.items[index]; wb.visible { + return wb.window.(Widget) + } + + index += direction + } + + return nil } + + handleIndex := index + 1 - index%2 err = s.children.Insert(handleIndex, handle) if err == nil { // FIXME: These handlers will be leaked, if widgets get removed. @@ -367,11 +398,11 @@ func (s *Splitter) onInsertedWidget(index int, widget Widget) (err error) { handleIndex := s.children.Index(s.draggedHandle) bh := s.draggedHandle.Bounds() - prev := s.children.At(handleIndex - 1) + prev := closestVisibleWidget(handleIndex, -1) bp := prev.Bounds() msep := minSizeEffective(prev) - next := s.children.At(handleIndex + 1) + next := closestVisibleWidget(handleIndex, 1) bn := next.Bounds() msen := minSizeEffective(next) @@ -434,8 +465,8 @@ func (s *Splitter) onInsertedWidget(index int, widget Widget) (err error) { dragHandle := s.draggedHandle handleIndex := s.children.Index(dragHandle) - prev := s.children.At(handleIndex - 1) - next := s.children.At(handleIndex + 1) + prev := closestVisibleWidget(handleIndex, -1) + next := closestVisibleWidget(handleIndex, 1) s.draggedHandle = nil dragHandle.SetBackground(NullBrush()) @@ -514,6 +545,11 @@ func (s *Splitter) onRemovedWidget(index int, widget Widget) (err error) { return newError("cannot remove splitter handle") } + if !isHandle { + sl := s.layout.(*splitterLayout) + widget.AsWidgetBase().Property("Visible").Changed().Detach(sl.hwnd2Item[widget.Handle()].visibleChangedHandle) + } + if !isHandle && s.children.Len() > 1 { defer func() { if err != nil { @@ -528,9 +564,17 @@ func (s *Splitter) onRemovedWidget(index int, widget Widget) (err error) { } s.removing = true - handle := s.children.items[handleIndex] + handle := s.children.items[handleIndex].window.(*splitterHandle) + if err = handle.SetParent(nil); err == nil { - s.children.items = append(s.children.items[:index], s.children.items[index+1:]...) + // s.children.items = append(s.children.items[:index], s.children.items[index+1:]...) + + sl := s.layout.(*splitterLayout) + + for _, item := range sl.hwnd2Item { + item.oldExplicitSize = 0 + item.keepSize = false + } s.layout.Update(true) diff --git a/splitterhandle.go b/splitterhandle.go index 06dcfaef..49972e91 100644 --- a/splitterhandle.go +++ b/splitterhandle.go @@ -47,7 +47,11 @@ func newSplitterHandle(splitter *Splitter) (*splitterHandle, error) { } func (sh *splitterHandle) LayoutFlags() LayoutFlags { - splitter := sh.Parent().(*Splitter) + splitter, ok := sh.Parent().(*Splitter) + if !ok { + return 0 + } + if splitter.Orientation() == Horizontal { return ShrinkableVert | GrowableVert | GreedyVert } @@ -60,7 +64,11 @@ func (sh *splitterHandle) MinSizeHint() Size { } func (sh *splitterHandle) SizeHint() Size { - splitter := sh.Parent().(*Splitter) + splitter, ok := sh.Parent().(*Splitter) + if !ok { + return Size{} + } + handleWidth := splitter.HandleWidth() var size Size diff --git a/splitterlayout.go b/splitterlayout.go index d6580500..a52192a4 100644 --- a/splitterlayout.go +++ b/splitterlayout.go @@ -18,15 +18,18 @@ type splitterLayout struct { margins Margins hwnd2Item map[win.HWND]*splitterLayoutItem resetNeeded bool + suspended bool } type splitterLayoutItem struct { - size int - oldExplicitSize int - stretchFactor int - growth int - fixed bool - keepSize bool + size int + oldExplicitSize int + stretchFactor int + growth int + visibleChangedHandle int + fixed bool + keepSize bool + wasVisible bool } func newSplitterLayout(orientation Orientation) *splitterLayout { @@ -165,7 +168,13 @@ func (l *splitterLayout) MinSizeForSize(size Size) Size { anyNonFixed := l.anyNonFixed() - for _, widget := range l.container.Children().items { + for _, wb := range l.container.Children().items { + if !anyVisibleWidgetInHierarchy(wb) { + continue + } + + widget := wb.window.(Widget) + var cur Size if anyNonFixed && l.Fixed(widget) { @@ -213,21 +222,69 @@ func (l *splitterLayout) spaceForRegularWidgets() int { space = s.Height - l.margins.VNear - l.margins.VFar } - return space - (splitter.Children().Len()/2)*splitter.handleWidth + for _, widget := range l.container.Children().items { + if _, isHandle := widget.window.(*splitterHandle); isHandle && widget.visible { + space -= splitter.handleWidth + } + } + + return space } func (l *splitterLayout) reset() { l.cleanupItems() children := l.container.Children() + + var anyVisible bool + + for i, wb := range children.items { + item := l.hwnd2Item[wb.hWnd] + + visible := anyVisibleWidgetInHierarchy(wb) + if !anyVisible && visible { + anyVisible = true + } + + if item == nil || visible == item.wasVisible { + continue + } + + item.wasVisible = visible + + if _, isHandle := wb.window.(*splitterHandle); !isHandle { + var handleIndex int + + if i == 0 { + if len(children.items) > 1 { + handleIndex = i + 1 + } else { + handleIndex = -1 + } + } else { + handleIndex = i - 1 + } + + if handleIndex > -1 { + children.items[handleIndex].SetVisible(visible) + } + } + } + + if l.container.AsWindowBase().visible != anyVisible { + l.suspended = true + l.container.SetVisible(anyVisible) + l.suspended = false + } + minSizes := make([]int, children.Len()) var minSizesTotal int - for i, w := range children.items { - if i%2 == 1 { + for i, wb := range children.items { + if i%2 == 1 || !anyVisibleWidgetInHierarchy(wb) { continue } - min := minSizeEffective(w) + min := minSizeEffective(wb.window.(Widget)) if l.orientation == Horizontal { minSizes[i] = min.Width minSizesTotal += min.Width @@ -239,34 +296,31 @@ func (l *splitterLayout) reset() { regularSpace := l.spaceForRegularWidgets() stretchTotal := 0 - for i := children.Len() - 1; i >= 0; i-- { - if i%2 == 1 { + for i, wb := range children.items { + if i%2 == 1 || !anyVisibleWidgetInHierarchy(wb) { continue } - child := children.At(i) - - if item := l.hwnd2Item[child.Handle()]; item == nil { - l.hwnd2Item[child.Handle()] = &splitterLayoutItem{stretchFactor: 1} + if item := l.hwnd2Item[wb.hWnd]; item == nil { + l.hwnd2Item[wb.hWnd] = &splitterLayoutItem{stretchFactor: 1} } - stretchTotal += l.StretchFactor(child) + stretchTotal += l.StretchFactor(wb.window.(Widget)) } - for i := children.Len() - 1; i >= 0; i-- { - if i%2 == 1 { + for i, wb := range children.items { + if i%2 == 1 || !anyVisibleWidgetInHierarchy(wb) { continue } - child := children.At(i) - - item := l.hwnd2Item[child.Handle()] + widget := wb.window.(Widget) + item := l.hwnd2Item[wb.hWnd] item.growth = 0 item.keepSize = false if item.oldExplicitSize > 0 { item.size = item.oldExplicitSize } else { - item.size = int(float64(l.StretchFactor(child)) / float64(stretchTotal) * float64(regularSpace)) + item.size = int(float64(l.StretchFactor(widget)) / float64(stretchTotal) * float64(regularSpace)) } min := minSizes[i] @@ -277,7 +331,7 @@ func (l *splitterLayout) reset() { } if item.size >= min { - flags := child.LayoutFlags() + flags := widget.LayoutFlags() if l.orientation == Horizontal && flags&GrowableHorz == 0 || l.orientation == Vertical && flags&GrowableVert == 0 { item.size = min @@ -327,7 +381,13 @@ func (l *splitterLayout) Update(reset bool) error { anyNonFixed := l.anyNonFixed() var totalRegularSize int - for i, widget := range widgets { + for i, wb := range widgets { + if !anyVisibleWidgetInHierarchy(wb) { + continue + } + + widget := wb.window.(Widget) + if i%2 == 0 { size := l.hwnd2Item[widget.Handle()].size totalRegularSize += size @@ -349,7 +409,13 @@ func (l *splitterLayout) Update(reset bool) error { var wis []WidgetItem - for i, widget := range widgets { + for i, wb := range widgets { + if !anyVisibleWidgetInHierarchy(wb) { + continue + } + + widget := wb.window.(Widget) + if i%2 == 0 { if item := l.hwnd2Item[widget.Handle()]; !anyNonFixed || !item.fixed { var min, max int @@ -431,7 +497,13 @@ func (l *splitterLayout) Update(reset bool) error { } else { p1 = l.margins.VNear } - for i, widget := range widgets { + for i, wb := range widgets { + if !anyVisibleWidgetInHierarchy(wb) { + continue + } + + widget := wb.window.(Widget) + s1 := sizes[i] var x, y, w, h int @@ -265,15 +265,15 @@ func walkDescendants(window Window, f func(w Window) bool) { return } - var children []Widget + var children []*WidgetBase switch w := window.(type) { case *NumberEdit: - children = append(children, w.edit) + children = append(children, w.edit.AsWidgetBase()) case *TabWidget: for _, p := range w.Pages().items { - children = append(children, p) + children = append(children, p.AsWidgetBase()) } case Container: @@ -284,8 +284,8 @@ func walkDescendants(window Window, f func(w Window) bool) { } } - for _, w := range children { - walkDescendants(w, f) + for _, wb := range children { + walkDescendants(wb.window.(Widget), f) } } @@ -429,6 +429,10 @@ func (wb *WidgetBase) hasComplexBackground() bool { } func (wb *WidgetBase) updateParentLayout() error { + return wb.updateParentLayoutWithReset(false) +} + +func (wb *WidgetBase) updateParentLayoutWithReset(reset bool) error { parent := wb.window.(Widget).Parent() if parent == nil || parent.Layout() == nil || parent.Suspended() || !parent.Visible() { @@ -448,7 +452,7 @@ func (wb *WidgetBase) updateParentLayout() error { return nil case Widget: - return wnd.AsWidgetBase().updateParentLayout() + return wnd.AsWidgetBase().updateParentLayoutWithReset(reset) case Form: if len(inProgressEventsByForm[appSingleton.activeForm]) > 0 { @@ -468,7 +472,7 @@ func (wb *WidgetBase) updateParentLayout() error { } } - layout.Update(false) + layout.Update(reset) if FocusEffect != nil { if focusedWnd := windowFromHandle(win.GetFocus()); focusedWnd != nil && win.GetParent(focusedWnd.Handle()) == parent.Handle() { diff --git a/widgetlist.go b/widgetlist.go index edbfdd3d..4e6db6ea 100644 --- a/widgetlist.go +++ b/widgetlist.go @@ -20,13 +20,13 @@ type widgetListObserver interface { } type WidgetList struct { - items []*WidgetBase - observer widgetListObserver - removingIndex int + items []*WidgetBase + observer widgetListObserver + widgetInRemoval *WidgetBase } func newWidgetList(observer widgetListObserver) *WidgetList { - return &WidgetList{observer: observer, removingIndex: -1} + return &WidgetList{observer: observer} } func (l *WidgetList) Add(item Widget) error { @@ -132,17 +132,19 @@ func (l *WidgetList) Remove(item Widget) error { } func (l *WidgetList) RemoveAt(index int) error { - if index == l.removingIndex { + item := l.items[index] + + if item == l.widgetInRemoval { return nil } observer := l.observer - widget := l.items[index].window.(Widget) + widget := item.window.(Widget) if observer != nil { - l.removingIndex = index + l.widgetInRemoval = item defer func() { - l.removingIndex = -1 + l.widgetInRemoval = nil }() if err := observer.onRemovingWidget(index, widget); err != nil { @@ -10,6 +10,7 @@ import ( "bytes" "fmt" "image" + "log" "strings" "syscall" "unsafe" @@ -482,7 +483,7 @@ func InitWindow(window, parent Window, className string, style, exStyle uint32) wb.visibleProperty = NewBoolProperty( func() bool { - return window.Visible() + return window.AsWindowBase().visible }, func(b bool) error { wb.window.SetVisible(b) @@ -515,21 +516,33 @@ func InitWrapperWindow(window Window) error { wb.window = window - if widget, ok := window.(Widget); ok { - widgetBase := widget.AsWidgetBase() + if container, ok := window.(Container); ok { + children := container.Children() - if widgetBase.parent != nil { - children := widgetBase.parent.Children().items + if wlo, ok := window.(widgetListObserver); ok { + children.observer = wlo + } - for i, w := range children { - if w.AsWidgetBase() == widgetBase { - children[i] = widget - break - } - } + for _, child := range children.items { + child.parent = container } } + // if widget, ok := window.(Widget); ok { + // widgetBase := widget.AsWidgetBase() + + // if widgetBase.parent != nil { + // children := widgetBase.parent.Children().items + + // for i, wb := range children { + // if wb == widgetBase { + // children[i] = widget.AsWidgetBase() + // break + // } + // } + // } + // } + return nil } @@ -1000,7 +1013,7 @@ func (wb *WindowBase) SetVisible(visible bool) { if widget, ok := wb.window.(Widget); ok { wb := widget.AsWidgetBase() wb.invalidateBorderInParent() - wb.updateParentLayout() + wb.updateParentLayoutWithReset(true) } wb.visibleChangedPublisher.Publish() @@ -1654,6 +1667,9 @@ func (wb *WindowBase) backgroundEffective() (Brush, Window) { bg = parent.Background() widget, _ = parent.(Widget) + } else { + log.Printf("*WindowBase.backgroundEffective - breaing out of infinite loop - bg: %T, wnd: %T %s %d", bg, wnd, wnd.Name(), wnd.Handle()) + break } } else { break |