1 Star 0 Fork 0

zxy/walk

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
splitterlayout.go 12.41 KB
一键复制 编辑 原始数据 按行查看 历史
Simon Rozman 提交于 2019-09-26 23:39 +08:00 . DPI: Merge RectanglePixels to Rectangle
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
// Copyright 2010 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package walk
import (
"sort"
"github.com/lxn/win"
)
type splitterLayout struct {
container Container
orientation Orientation
margins96dpi Margins
hwnd2Item map[win.HWND]*splitterLayoutItem
resetNeeded bool
suspended bool
}
type splitterLayoutItem struct {
size int // in native pixels
oldExplicitSize int // in native pixels
stretchFactor int
growth int
visibleChangedHandle int
fixed bool
keepSize bool
wasVisible bool
}
func newSplitterLayout(orientation Orientation) *splitterLayout {
return &splitterLayout{
orientation: orientation,
hwnd2Item: make(map[win.HWND]*splitterLayoutItem),
}
}
func (l *splitterLayout) asLayoutBase() *LayoutBase {
return nil
}
func (l *splitterLayout) Container() Container {
return l.container
}
func (l *splitterLayout) SetContainer(value Container) {
if value != l.container {
if l.container != nil {
l.container.SetLayout(nil)
}
l.container = value
if value != nil && value.Layout() != Layout(l) {
value.SetLayout(l)
l.container.RequestLayout()
}
}
}
func (l *splitterLayout) Margins() Margins {
return l.margins96dpi
}
func (l *splitterLayout) SetMargins(value Margins) error {
l.margins96dpi = value
l.container.RequestLayout()
return nil
}
func (l *splitterLayout) Spacing() int {
return l.container.(*Splitter).handleWidth
}
func (l *splitterLayout) SetSpacing(value int) error {
return newError("not supported")
}
func (l *splitterLayout) Orientation() Orientation {
return l.orientation
}
func (l *splitterLayout) SetOrientation(value Orientation) error {
if value != l.orientation {
switch value {
case Horizontal, Vertical:
default:
return newError("invalid Orientation value")
}
l.orientation = value
l.container.RequestLayout()
}
return nil
}
func (l *splitterLayout) Fixed(widget Widget) bool {
item := l.hwnd2Item[widget.Handle()]
return item != nil && item.fixed
}
func (l *splitterLayout) StretchFactor(widget Widget) int {
item := l.hwnd2Item[widget.Handle()]
if item == nil || item.stretchFactor == 0 {
return 1
}
return item.stretchFactor
}
func (l *splitterLayout) SetStretchFactor(widget Widget, factor int) error {
if factor != l.StretchFactor(widget) {
if factor < 1 {
return newError("factor must be >= 1")
}
if l.container == nil {
return newError("container required")
}
item := l.hwnd2Item[widget.Handle()]
if item == nil {
item = new(splitterLayoutItem)
l.hwnd2Item[widget.Handle()] = item
}
item.stretchFactor = factor
l.container.RequestLayout()
}
return nil
}
func (l *splitterLayout) anyNonFixed() bool {
for i, widget := range l.container.Children().items {
if i%2 == 0 && widget.visible && !l.Fixed(widget.window.(Widget)) {
return true
}
}
return false
}
// spaceUnavailableToRegularWidgets returns amount of space unavailable to regular widgets in native pixels.
func (l *splitterLayout) spaceUnavailableToRegularWidgets() int {
splitter := l.container.(*Splitter)
var space int
for _, widget := range l.container.Children().items {
if _, isHandle := widget.window.(*splitterHandle); isHandle && widget.visible {
space += splitter.handleWidth
}
}
return IntFrom96DPI(space, splitter.DPI())
}
func (l *splitterLayout) CreateLayoutItem(ctx *LayoutContext) ContainerLayoutItem {
splitter := l.container.(*Splitter)
hwnd2Item := make(map[win.HWND]*splitterLayoutItem, len(l.hwnd2Item))
for hwnd, sli := range l.hwnd2Item {
hwnd2Item[hwnd] = sli
}
li := &splitterContainerLayoutItem{
orientation: l.orientation,
hwnd2Item: hwnd2Item,
spaceUnavailableToRegularItems: l.spaceUnavailableToRegularWidgets(),
handleWidth96dpi: splitter.HandleWidth(),
anyNonFixed: l.anyNonFixed(),
resetNeeded: l.resetNeeded,
}
li.margins96dpi = l.margins96dpi
return li
}
type splitterContainerLayoutItem struct {
ContainerLayoutItemBase
orientation Orientation
hwnd2Item map[win.HWND]*splitterLayoutItem
spaceUnavailableToRegularItems int // in native pixels
handleWidth96dpi int
anyNonFixed bool
resetNeeded bool
}
func (li *splitterContainerLayoutItem) StretchFactor(item LayoutItem) int {
sli := li.hwnd2Item[item.Handle()]
if sli == nil || sli.stretchFactor == 0 {
return 1
}
return sli.stretchFactor
}
func (li *splitterContainerLayoutItem) LayoutFlags() LayoutFlags {
return boxLayoutFlags(li.orientation, li.children)
}
func (li *splitterContainerLayoutItem) MinSize() Size {
return li.MinSizeForSize(li.geometry.ClientSize)
}
func (li *splitterContainerLayoutItem) HeightForWidth(width int) int {
return li.MinSizeForSize(Size{width, li.geometry.ClientSize.Height}).Height
}
func (li *splitterContainerLayoutItem) MinSizeForSize(size Size) Size {
marginsPixels := MarginsFrom96DPI(li.margins96dpi, li.ctx.dpi)
margins := Size{marginsPixels.HNear + marginsPixels.HFar, marginsPixels.VNear + marginsPixels.VFar}
s := margins
for _, item := range li.children {
if !anyVisibleItemInHierarchy(item) {
continue
}
var cur Size
if sli, ok := li.hwnd2Item[item.Handle()]; ok && li.anyNonFixed && sli.fixed {
cur = item.Geometry().Size
if li.orientation == Horizontal {
cur.Height = 0
} else {
cur.Width = 0
}
} else {
cur = li.MinSizeEffectiveForChild(item)
}
if li.orientation == Horizontal {
s.Width += cur.Width
s.Height = maxi(s.Height, margins.Height+cur.Height)
} else {
s.Height += cur.Height
s.Width = maxi(s.Width, margins.Width+cur.Width)
}
}
return s
}
func (li *splitterContainerLayoutItem) PerformLayout() []LayoutResultItem {
if li.resetNeeded {
li.reset()
}
margins := MarginsFrom96DPI(li.margins96dpi, li.ctx.dpi)
handleWidthPixels := IntFrom96DPI(li.handleWidth96dpi, li.ctx.dpi)
sizes := make([]int, len(li.children))
cb := Rectangle{Width: li.geometry.ClientSize.Width, Height: li.geometry.ClientSize.Height}
cb.X += margins.HNear
cb.Y += margins.HFar
cb.Width -= margins.HNear + margins.HFar
cb.Height -= margins.VNear + margins.VFar
var space1, space2 int
if li.orientation == Horizontal {
space1 = cb.Width - li.spaceUnavailableToRegularItems
space2 = cb.Height
} else {
space1 = cb.Height - li.spaceUnavailableToRegularItems
space2 = cb.Width
}
type WidgetItem struct {
item *splitterLayoutItem
index int
min int // in native pixels
max int // in native pixels
shrinkable bool
growable bool
}
var wis []WidgetItem
anyNonFixed := li.anyNonFixed
var totalRegularSize int
for i, item := range li.children {
if !anyVisibleItemInHierarchy(item) {
continue
}
if i%2 == 0 {
slItem := li.hwnd2Item[item.Handle()]
var wi *WidgetItem
if !anyNonFixed || !slItem.fixed {
var min, max int
minSize := li.MinSizeEffectiveForChild(item)
maxSize := item.Geometry().MaxSize
if li.orientation == Horizontal {
min = minSize.Width
max = maxSize.Width
} else {
min = minSize.Height
max = maxSize.Height
}
wis = append(wis, WidgetItem{item: slItem, index: i, min: min, max: max})
wi = &wis[len(wis)-1]
}
size := slItem.size
var idealSize Size
if hfw, ok := item.(HeightForWidther); ok && li.orientation == Vertical && hfw.HasHeightForWidth() {
idealSize.Height = hfw.HeightForWidth(space2)
} else {
switch sizer := item.(type) {
case IdealSizer:
idealSize = sizer.IdealSize()
case MinSizer:
idealSize = sizer.MinSize()
}
}
if flags := item.LayoutFlags(); li.orientation == Horizontal {
if flags&ShrinkableHorz == 0 {
size = maxi(size, idealSize.Width)
if wi != nil {
wi.min = maxi(wi.min, size)
}
} else if wi != nil {
wi.shrinkable = true
}
if flags&GrowableHorz == 0 {
size = mini(size, idealSize.Width)
if wi != nil {
wi.max = mini(wi.max, size)
}
} else if wi != nil {
wi.growable = true
}
} else {
if flags&ShrinkableVert == 0 {
size = maxi(size, idealSize.Height)
if wi != nil {
wi.min = maxi(wi.min, size)
}
} else if wi != nil {
wi.shrinkable = true
}
if flags&GrowableVert == 0 {
size = mini(size, idealSize.Height)
if wi != nil {
wi.max = mini(wi.max, size)
}
} else if wi != nil {
wi.growable = true
}
}
totalRegularSize += size
sizes[i] = size
} else {
sizes[i] = handleWidthPixels
}
}
var resultItems []LayoutResultItem
diff := space1 - totalRegularSize
if diff != 0 && len(sizes) > 1 {
for diff != 0 {
sort.SliceStable(wis, func(i, j int) bool {
a := wis[i]
b := wis[j]
x := float64(a.item.growth) / float64(a.item.stretchFactor)
y := float64(b.item.growth) / float64(b.item.stretchFactor)
if diff > 0 {
return x < y && (a.max == 0 || a.max > a.item.size)
} else {
return x > y && a.min < a.item.size
}
})
var wi *WidgetItem
for _, wItem := range wis {
if !wItem.item.keepSize && (diff < 0 && wItem.item.size > wItem.min || diff > 0 && (wItem.item.size < wItem.max || wItem.max == 0)) {
wi = &wItem
break
}
}
if wi == nil {
break
}
if diff > 0 {
sizes[wi.index]++
wi.item.size++
wi.item.growth++
diff--
} else {
sizes[wi.index]--
wi.item.size--
wi.item.growth--
diff++
}
}
}
var p1 int
if li.orientation == Horizontal {
p1 = margins.HNear
} else {
p1 = margins.VNear
}
for i, item := range li.children {
if !anyVisibleItemInHierarchy(item) {
continue
}
s1 := sizes[i]
var x, y, w, h int
if li.orientation == Horizontal {
x, y, w, h = p1, margins.VNear, s1, space2
} else {
x, y, w, h = margins.HNear, p1, space2, s1
}
resultItems = append(resultItems, LayoutResultItem{Item: item, Bounds: Rectangle{x, y, w, h}})
p1 += s1
}
return resultItems
}
func (li *splitterContainerLayoutItem) reset() {
var anyVisible bool
for i, item := range li.children {
sli := li.hwnd2Item[item.Handle()]
visible := anyVisibleItemInHierarchy(item)
if !anyVisible && visible {
anyVisible = true
}
if sli == nil || visible == sli.wasVisible {
continue
}
sli.wasVisible = visible
if _, isHandle := item.(*splitterHandleLayoutItem); !isHandle {
var handleIndex int
if i == 0 {
if len(li.children) > 1 {
handleIndex = 1
} else {
handleIndex = -1
}
} else {
handleIndex = i - 1
}
if handleIndex > -1 {
li.children[handleIndex].AsLayoutItemBase().visible = visible
}
}
}
if li.Visible() != anyVisible {
li.AsLayoutItemBase().visible = anyVisible
}
minSizes := make([]int, len(li.children))
var minSizesTotal int
for i, item := range li.children {
if i%2 == 1 || !anyVisibleItemInHierarchy(item) {
continue
}
min := li.MinSizeEffectiveForChild(item)
if li.orientation == Horizontal {
minSizes[i] = min.Width
minSizesTotal += min.Width
} else {
minSizes[i] = min.Height
minSizesTotal += min.Height
}
}
var regularSpace int
if li.orientation == Horizontal {
regularSpace = li.Geometry().ClientSize.Width - li.spaceUnavailableToRegularItems
} else {
regularSpace = li.Geometry().ClientSize.Height - li.spaceUnavailableToRegularItems
}
stretchTotal := 0
for i, item := range li.children {
if i%2 == 1 || !anyVisibleItemInHierarchy(item) {
continue
}
if sli := li.hwnd2Item[item.Handle()]; sli == nil {
li.hwnd2Item[item.Handle()] = &splitterLayoutItem{stretchFactor: 1}
}
stretchTotal += li.StretchFactor(item)
}
for i, item := range li.children {
if i%2 == 1 || !anyVisibleItemInHierarchy(item) {
continue
}
sli := li.hwnd2Item[item.Handle()]
sli.growth = 0
sli.keepSize = false
if sli.oldExplicitSize > 0 {
sli.size = sli.oldExplicitSize
} else {
sli.size = int(float64(li.StretchFactor(item)) / float64(stretchTotal) * float64(regularSpace))
}
min := minSizes[i]
if minSizesTotal <= regularSpace {
if sli.size < min {
sli.size = min
}
}
if sli.size >= min {
flags := item.LayoutFlags()
if li.orientation == Horizontal && flags&GrowableHorz == 0 || li.orientation == Vertical && flags&GrowableVert == 0 {
sli.size = min
sli.keepSize = true
}
}
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/zxy4096/walk.git
git@gitee.com:zxy4096/walk.git
zxy4096
walk
walk
c389da54e794

搜索帮助