diff options
author | Alexander Neumann <alexander.neumann@picos-software.com> | 2019-11-21 16:29:19 +0100 |
---|---|---|
committer | Alexander Neumann <alexander.neumann@picos-software.com> | 2019-11-21 16:29:19 +0100 |
commit | b7c43041fb1bc02b061100c67cb8f8af00379ecc (patch) | |
tree | b74bb4d8f28b8521c3056ce48deba09943e08f97 | |
parent | reflectTableModel: Forward RowsChanged events (diff) | |
download | wireguard-windows-b7c43041fb1bc02b061100c67cb8f8af00379ecc.tar.xz wireguard-windows-b7c43041fb1bc02b061100c67cb8f8af00379ecc.zip |
Label: Add EllipsisMode
-rw-r--r-- | boxlayout.go | 63 | ||||
-rw-r--r-- | declarative/label.go | 13 | ||||
-rw-r--r-- | gridlayout.go | 2 | ||||
-rw-r--r-- | label.go | 30 | ||||
-rw-r--r-- | static.go | 57 | ||||
-rw-r--r-- | tooltip.go | 23 |
6 files changed, 159 insertions, 29 deletions
diff --git a/boxlayout.go b/boxlayout.go index 5fc20cab..ab6880d0 100644 --- a/boxlayout.go +++ b/boxlayout.go @@ -7,6 +7,7 @@ package walk import ( + "math" "sort" "sync" @@ -17,8 +18,8 @@ type Orientation byte const ( NoOrientation Orientation = 0 - Horizontal = 1 << 0 - Vertical = 1 << 1 + Horizontal = 1 << 0 + Vertical = 1 << 1 ) type BoxLayout struct { @@ -116,12 +117,13 @@ func (l *BoxLayout) CreateLayoutItem(ctx *LayoutContext) ContainerLayoutItem { } type boxLayoutItemInfo struct { - index int - minSize int // in native pixels - maxSize int // in native pixels - stretch int - greedy bool - item LayoutItem + item LayoutItem + index int + prefSize int // in native pixels + minSize int // in native pixels + maxSize int // in native pixels + stretch int + greedy bool } type boxLayoutItemInfoList []boxLayoutItemInfo @@ -305,6 +307,9 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati maxSizes := make([]int, len(items)) sizes := make([]int, len(items)) prefSizes2 := make([]int, len(items)) + var shrinkableAmount1Total int + shrinkableAmount1 := make([]int, len(items)) + shrinkable2 := make([]bool, len(items)) growable2 := make([]bool, len(items)) sortedItemInfo := boxLayoutItemInfoList(make([]boxLayoutItemInfo, len(items))) @@ -342,6 +347,7 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati prefSizes2[i] = pref.Height + sortedItemInfo[i].prefSize = pref.Width sortedItemInfo[i].greedy = flags&GreedyHorz > 0 } else { growable2[i] = flags&GrowableHorz > 0 @@ -364,6 +370,7 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati prefSizes2[i] = pref.Width + sortedItemInfo[i].prefSize = pref.Height sortedItemInfo[i].greedy = flags&GreedyVert > 0 } @@ -373,7 +380,20 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati sortedItemInfo[i].stretch = sf sortedItemInfo[i].item = item - minSizesRemaining += minSizes[i] + if orientation == Horizontal && flags&(ShrinkableHorz|GrowableHorz|GreedyHorz) == ShrinkableHorz || + orientation == Vertical && flags&(ShrinkableVert|GrowableVert|GreedyVert) == ShrinkableVert { + if amount := sortedItemInfo[i].prefSize - minSizes[i]; amount > 0 { + shrinkableAmount1[i] = amount + shrinkableAmount1Total += amount + } + } + shrinkable2[i] = orientation == Horizontal && flags&ShrinkableVert != 0 || orientation == Vertical && flags&ShrinkableHorz != 0 + + if shrinkableAmount1[i] > 0 { + minSizesRemaining += sortedItemInfo[i].prefSize + } else { + minSizesRemaining += minSizes[i] + } if sortedItemInfo[i].greedy { if _, isSpacer := item.(*spacerLayoutItem); !isSpacer { @@ -404,6 +424,7 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati } spacingRemaining := spacing * (len(items) - 1) + excess := float64(space1 - minSizesRemaining - spacingRemaining) offsets := [3]int{0, greedyNonSpacerCount, greedyNonSpacerCount + greedySpacerCount} counts := [3]int{greedyNonSpacerCount, greedySpacerCount, len(items) - greedyNonSpacerCount - greedySpacerCount} @@ -418,11 +439,21 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati stretch := stretchFactors[k] min := info.minSize max := info.maxSize - size := min + var size int + var corrected bool + if shrinkableAmount1[k] > 0 { + size = info.prefSize + if excess < 0.0 { + size -= mini(shrinkableAmount1[k], int(math.Round(-excess/float64(shrinkableAmount1Total)*float64(shrinkableAmount1[k])))) + corrected = true + } + } else { + size = min + } - if min < max { + if !corrected && min < max { excessSpace := float64(space1 - minSizesRemaining - spacingRemaining) - size += int(excessSpace * float64(stretch) / float64(stretchFactorsRemaining)) + size += int(math.Round(excessSpace * float64(stretch) / float64(stretchFactorsRemaining))) if size < min { size = min } else if size > max { @@ -432,7 +463,11 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati sizes[k] = size - minSizesRemaining -= min + if shrinkableAmount1[k] > 0 { + minSizesRemaining -= info.prefSize + } else { + minSizesRemaining -= min + } stretchFactorsRemaining -= stretch space1 -= (size + spacing) spacingRemaining -= spacing @@ -451,7 +486,7 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati var s2 int if hfw, ok := item.(HeightForWidther); ok && orientation == Horizontal && hfw.HasHeightForWidth() { s2 = hfw.HeightForWidth(s1) - } else if growable2[i] { + } else if shrinkable2[i] || growable2[i] { s2 = space2 } else { s2 = prefSizes2[i] diff --git a/declarative/label.go b/declarative/label.go index e9811019..520b6b26 100644 --- a/declarative/label.go +++ b/declarative/label.go @@ -10,6 +10,14 @@ import ( "github.com/lxn/walk" ) +type EllipsisMode int + +const ( + EllipsisNone = EllipsisMode(walk.EllipsisNone) + EllipsisEnd = EllipsisMode(walk.EllipsisEnd) + EllipsisPath = EllipsisMode(walk.EllipsisPath) +) + type Label struct { // Window @@ -49,6 +57,7 @@ type Label struct { // Label AssignTo **walk.Label + EllipsisMode EllipsisMode Text Property TextAlignment Alignment1D TextColor walk.Color @@ -65,6 +74,10 @@ func (l Label) Create(builder *Builder) error { } return builder.InitWidget(l, w, func() error { + if err := w.SetEllipsisMode(walk.EllipsisMode(l.EllipsisMode)); err != nil { + return err + } + if err := w.SetTextAlignment(walk.Alignment1D(l.TextAlignment)); err != nil { return err } diff --git a/gridlayout.go b/gridlayout.go index 5d52c6ed..1b6e2fec 100644 --- a/gridlayout.go +++ b/gridlayout.go @@ -621,6 +621,7 @@ func (li *gridLayoutItem) PerformLayout() []LayoutResultItem { if lf&GrowableHorz == 0 { w = s.Width } + w = mini(w, width) if hfw, ok := item.(HeightForWidther); ok && hfw.HasHeightForWidth() { h = hfw.HeightForWidth(w) @@ -632,6 +633,7 @@ func (li *gridLayoutItem) PerformLayout() []LayoutResultItem { h = s.Height } } + h = mini(h, height) } alignment := item.Geometry().Alignment @@ -6,6 +6,16 @@ package walk +import "github.com/lxn/win" + +type EllipsisMode int + +const ( + EllipsisNone EllipsisMode = 0 + EllipsisEnd = EllipsisMode(win.SS_ENDELLIPSIS) + EllipsisPath = EllipsisMode(win.SS_PATHELLIPSIS) +) + type Label struct { static textChangedPublisher EventPublisher @@ -40,6 +50,26 @@ func (l *Label) asStatic() *static { return &l.static } +func (l *Label) EllipsisMode() EllipsisMode { + return EllipsisMode(win.GetWindowLong(l.hwndStatic, win.GWL_STYLE) & (win.SS_ENDELLIPSIS | win.SS_PATHELLIPSIS)) +} + +func (l *Label) SetEllipsisMode(mode EllipsisMode) error { + oldMode := l.EllipsisMode() + + if mode == oldMode { + return nil + } + + if err := setAndClearWindowLongBits(l.hwndStatic, win.GWL_STYLE, uint32(mode), uint32(oldMode)); err != nil { + return err + } + + l.RequestLayout() + + return nil +} + func (l *Label) TextAlignment() Alignment1D { return l.textAlignment1D() } @@ -46,7 +46,7 @@ func (s *static) init(widget Widget, parent Container) error { 0, syscall.StringToUTF16Ptr("static"), nil, - win.WS_CHILD|win.WS_CLIPSIBLINGS|win.WS_VISIBLE|win.SS_LEFT, + win.WS_CHILD|win.WS_CLIPSIBLINGS|win.WS_VISIBLE|win.SS_LEFT|win.SS_NOTIFY, win.CW_USEDEFAULT, win.CW_USEDEFAULT, win.CW_USEDEFAULT, @@ -59,6 +59,10 @@ func (s *static) init(widget Widget, parent Container) error { return newError("creating static failed") } + if err := s.group.toolTip.AddTool(s); err != nil { + return err + } + s.origStaticWndProcPtr = win.SetWindowLongPtr(s.hwndStatic, win.GWLP_WNDPROC, staticWndProcPtr) if s.origStaticWndProcPtr == 0 { return lastError("SetWindowLongPtr") @@ -82,6 +86,10 @@ func (s *static) Dispose() { s.WidgetBase.Dispose() } +func (s *static) handleForToolTip() win.HWND { + return s.hwndStatic +} + func (s *static) applyEnabled(enabled bool) { s.WidgetBase.applyEnabled(enabled) @@ -187,6 +195,14 @@ func (s *static) SetTextColor(c Color) { s.Invalidate() } +func (s *static) shrinkable() bool { + if em, ok := s.window.(interface{ EllipsisMode() EllipsisMode }); ok { + return em.EllipsisMode() != EllipsisNone + } + + return false +} + func (s *static) updateStaticBounds() { var format DrawTextFormat @@ -214,7 +230,7 @@ func (s *static) updateStaticBounds() { cb := s.ClientBoundsPixels() - if format&TextVCenter != 0 || format&TextBottom != 0 { + if shrinkable := s.shrinkable(); shrinkable || format&TextVCenter != 0 || format&TextBottom != 0 { var size Size if _, ok := s.window.(HeightForWidther); ok { size = s.calculateTextSizeForWidth(cb.Width) @@ -222,13 +238,23 @@ func (s *static) updateStaticBounds() { size = s.calculateTextSize() } - if format&TextVCenter != 0 { - cb.Y += (cb.Height - size.Height) / 2 - } else { - cb.Y += cb.Height - size.Height + if shrinkable { + var text string + if size.Width > cb.Width { + text = s.text() + } + s.SetToolTipText(text) } - cb.Height = size.Height + if format&TextVCenter != 0 || format&TextBottom != 0 { + if format&TextVCenter != 0 { + cb.Y += (cb.Height - size.Height) / 2 + } else { + cb.Y += cb.Height - size.Height + } + + cb.Height = size.Height + } } win.MoveWindow(s.hwndStatic, int32(cb.X), int32(cb.Y), int32(cb.Width), int32(cb.Height), true) @@ -267,6 +293,17 @@ func staticWndProc(hwnd win.HWND, msg uint32, wp, lp uintptr) uintptr { switch msg { case win.WM_NCHITTEST: return win.HTCLIENT + + case win.WM_MOUSEMOVE, win.WM_LBUTTONDOWN, win.WM_LBUTTONUP, win.WM_MBUTTONDOWN, win.WM_MBUTTONUP, win.WM_RBUTTONDOWN, win.WM_RBUTTONUP: + m := win.MSG{ + HWnd: hwnd, + Message: msg, + WParam: wp, + LParam: lp, + Pt: win.POINT{int32(win.LOWORD(uint32(lp))), int32(win.HIWORD(uint32(lp)))}, + } + + return s.group.toolTip.SendMessage(win.TTM_RELAYEVENT, 0, uintptr(unsafe.Pointer(&m))) } return win.CallWindowProc(s.origStaticWndProcPtr, hwnd, msg, wp, lp) @@ -276,6 +313,8 @@ func (s *static) CreateLayoutItem(ctx *LayoutContext) LayoutItem { var layoutFlags LayoutFlags if s.textAlignment1D() != AlignNear { layoutFlags = GrowableHorz + } else if s.shrinkable() { + layoutFlags = ShrinkableHorz } return &staticLayoutItem{ @@ -299,5 +338,9 @@ func (li *staticLayoutItem) IdealSize() Size { } func (li *staticLayoutItem) MinSize() Size { + if li.layoutFlags&ShrinkableHorz != 0 { + return Size{Height: li.idealSize.Height} + } + return li.idealSize } @@ -9,9 +9,7 @@ package walk import ( "syscall" "unsafe" -) -import ( "github.com/lxn/win" ) @@ -110,9 +108,7 @@ func (tt *ToolTip) track(tool Widget) error { } // HACK: We may have to delay this until the form is fully up to avoid glitches. if !form.AsFormBase().started { - var handle int - handle = form.Starting().Attach(func() { - form.Starting().Detach(handle) + form.Starting().Once(func() { tt.track(tool) }) return nil @@ -169,7 +165,10 @@ func (tt *ToolTip) addTrackedTool(tool Widget) error { } func (tt *ToolTip) addTool(tool Widget, track bool) error { - hwnd := tool.Handle() + hwnd := tt.hwndForTool(tool) + if hwnd == 0 { + return nil + } var ti win.TOOLINFO ti.CbSize = uint32(unsafe.Sizeof(ti)) @@ -190,7 +189,7 @@ func (tt *ToolTip) addTool(tool Widget, track bool) error { } func (tt *ToolTip) RemoveTool(tool Widget) error { - hwnd := tool.Handle() + hwnd := tt.hwndForTool(tool) var ti win.TOOLINFO ti.CbSize = uint32(unsafe.Sizeof(ti)) @@ -241,7 +240,7 @@ func (tt *ToolTip) toolInfo(tool Widget) *win.TOOLINFO { var ti win.TOOLINFO var buf [maxToolTipTextLen]uint16 - hwnd := tool.Handle() + hwnd := tt.hwndForTool(tool) ti.CbSize = uint32(unsafe.Sizeof(ti)) ti.Hwnd = hwnd @@ -254,3 +253,11 @@ func (tt *ToolTip) toolInfo(tool Widget) *win.TOOLINFO { return &ti } + +func (*ToolTip) hwndForTool(tool Widget) win.HWND { + if hftt, ok := tool.(interface{ handleForToolTip() win.HWND }); ok { + return hftt.handleForToolTip() + } + + return tool.Handle() +} |