summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAlexander Neumann <alexander.neumann@picos-software.com>2019-11-21 16:29:19 +0100
committerAlexander Neumann <alexander.neumann@picos-software.com>2019-11-21 16:29:19 +0100
commitb7c43041fb1bc02b061100c67cb8f8af00379ecc (patch)
treeb74bb4d8f28b8521c3056ce48deba09943e08f97
parentreflectTableModel: Forward RowsChanged events (diff)
downloadwireguard-windows-b7c43041fb1bc02b061100c67cb8f8af00379ecc.tar.xz
wireguard-windows-b7c43041fb1bc02b061100c67cb8f8af00379ecc.zip
Label: Add EllipsisMode
-rw-r--r--boxlayout.go63
-rw-r--r--declarative/label.go13
-rw-r--r--gridlayout.go2
-rw-r--r--label.go30
-rw-r--r--static.go57
-rw-r--r--tooltip.go23
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
diff --git a/label.go b/label.go
index 802dcc99..67cce2dd 100644
--- a/label.go
+++ b/label.go
@@ -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()
}
diff --git a/static.go b/static.go
index ac7d507a..38ed9663 100644
--- a/static.go
+++ b/static.go
@@ -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
}
diff --git a/tooltip.go b/tooltip.go
index 0b8b63fa..5b6f9283 100644
--- a/tooltip.go
+++ b/tooltip.go
@@ -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()
+}