summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAlexander Neumann <alexander.neumann@picos-software.com>2019-02-25 17:38:01 +0100
committerAlexander Neumann <alexander.neumann@picos-software.com>2019-02-25 17:38:01 +0100
commita154dd0297ec89bfb806454e36ef2b95032b1d12 (patch)
treef7e8e5963d56654ee5f8d6f64a0d6cf311671555
parentFormBase: Try to fix scrolling problems with initially focused descendant (diff)
downloadwireguard-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.go46
-rw-r--r--splitter.go98
-rw-r--r--splitterhandle.go12
-rw-r--r--splitterlayout.go128
-rw-r--r--util.go10
-rw-r--r--widget.go8
-rw-r--r--widgetlist.go18
-rw-r--r--window.go40
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
diff --git a/util.go b/util.go
index 66dd6116..67db69fa 100644
--- a/util.go
+++ b/util.go
@@ -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)
}
}
diff --git a/widget.go b/widget.go
index 912abb43..e121d8ad 100644
--- a/widget.go
+++ b/widget.go
@@ -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 {
diff --git a/window.go b/window.go
index 13a5b1c5..199de355 100644
--- a/window.go
+++ b/window.go
@@ -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