1 Star 0 Fork 0

zxy/walk

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
listbox.go 21.15 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
// Copyright 2012 The Walk Authors. All rights reserved.
// Use of lb source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package walk
import (
"fmt"
"math/big"
"reflect"
"syscall"
"time"
"unsafe"
"github.com/lxn/win"
)
type ListBox struct {
WidgetBase
bindingValueProvider BindingValueProvider
model ListModel
providedModel interface{}
styler ListItemStyler
style ListItemStyle
bindingMember string
displayMember string
format string
precision int
prevCurIndex int
currentValue interface{}
itemsResetHandlerHandle int
itemChangedHandlerHandle int
itemsInsertedHandlerHandle int
itemsRemovedHandlerHandle int
maxItemTextWidth int // in native pixels
lastWidth int // in native pixels
lastWidthsMeasuredFor []int // in native pixels
currentIndexChangedPublisher EventPublisher
selectedIndexesChangedPublisher EventPublisher
itemActivatedPublisher EventPublisher
themeNormalBGColor Color
themeNormalTextColor Color
themeSelectedBGColor Color
themeSelectedTextColor Color
themeSelectedNotFocusedBGColor Color
trackingMouseEvent bool
}
func NewListBox(parent Container) (*ListBox, error) {
return NewListBoxWithStyle(parent, 0)
}
func NewListBoxWithStyle(parent Container, style uint32) (*ListBox, error) {
lb := new(ListBox)
err := InitWidget(
lb,
parent,
"LISTBOX",
win.WS_BORDER|win.WS_TABSTOP|win.WS_VISIBLE|win.WS_VSCROLL|win.WS_HSCROLL|win.LBS_NOINTEGRALHEIGHT|win.LBS_NOTIFY|style,
0)
if err != nil {
return nil, err
}
succeeded := false
defer func() {
if !succeeded {
lb.Dispose()
}
}()
lb.setTheme("Explorer")
lb.style.dpi = lb.DPI()
lb.ApplySysColors()
lb.GraphicsEffects().Add(InteractionEffect)
lb.GraphicsEffects().Add(FocusEffect)
lb.MustRegisterProperty("CurrentIndex", NewProperty(
func() interface{} {
return lb.CurrentIndex()
},
func(v interface{}) error {
return lb.SetCurrentIndex(assertIntOr(v, -1))
},
lb.CurrentIndexChanged()))
lb.MustRegisterProperty("CurrentItem", NewReadOnlyProperty(
func() interface{} {
if i := lb.CurrentIndex(); i > -1 {
if rm, ok := lb.providedModel.(reflectModel); ok {
return reflect.ValueOf(rm.Items()).Index(i).Interface()
}
}
return nil
},
lb.CurrentIndexChanged()))
lb.MustRegisterProperty("HasCurrentItem", NewReadOnlyBoolProperty(
func() bool {
return lb.CurrentIndex() != -1
},
lb.CurrentIndexChanged()))
lb.MustRegisterProperty("Value", NewProperty(
func() interface{} {
index := lb.CurrentIndex()
if lb.bindingValueProvider == nil || index == -1 {
return nil
}
return lb.bindingValueProvider.BindingValue(index)
},
func(v interface{}) error {
if lb.bindingValueProvider == nil {
if lb.model == nil {
return nil
} else {
return newError("Data binding is only supported using a model that implements BindingValueProvider.")
}
}
index := -1
count := lb.model.ItemCount()
for i := 0; i < count; i++ {
if lb.bindingValueProvider.BindingValue(i) == v {
index = i
break
}
}
return lb.SetCurrentIndex(index)
},
lb.CurrentIndexChanged()))
succeeded = true
return lb, nil
}
func (*ListBox) LayoutFlags() LayoutFlags {
return ShrinkableHorz | ShrinkableVert | GrowableHorz | GrowableVert | GreedyHorz | GreedyVert
}
func (lb *ListBox) ItemStyler() ListItemStyler {
return lb.styler
}
func (lb *ListBox) SetItemStyler(styler ListItemStyler) {
lb.styler = styler
}
func (lb *ListBox) ApplySysColors() {
lb.WidgetBase.ApplySysColors()
var hc win.HIGHCONTRAST
hc.CbSize = uint32(unsafe.Sizeof(hc))
if win.SystemParametersInfo(win.SPI_GETHIGHCONTRAST, hc.CbSize, unsafe.Pointer(&hc), 0) {
lb.style.highContrastActive = hc.DwFlags&win.HCF_HIGHCONTRASTON != 0
}
lb.themeNormalBGColor = Color(win.GetSysColor(win.COLOR_WINDOW))
lb.themeNormalTextColor = Color(win.GetSysColor(win.COLOR_WINDOWTEXT))
lb.themeSelectedBGColor = Color(win.GetSysColor(win.COLOR_HIGHLIGHT))
lb.themeSelectedTextColor = Color(win.GetSysColor(win.COLOR_HIGHLIGHTTEXT))
lb.themeSelectedNotFocusedBGColor = Color(win.GetSysColor(win.COLOR_BTNFACE))
}
func (lb *ListBox) ApplyDPI(dpi int) {
lb.style.dpi = dpi
lb.WidgetBase.ApplyDPI(dpi)
}
func (lb *ListBox) applyFont(font *Font) {
lb.WidgetBase.applyFont(font)
for i := range lb.lastWidthsMeasuredFor {
lb.lastWidthsMeasuredFor[i] = 0
}
}
func (lb *ListBox) itemString(index int) string {
switch val := lb.model.Value(index).(type) {
case string:
return val
case time.Time:
return val.Format(lb.format)
case *big.Rat:
return val.FloatString(lb.precision)
default:
return fmt.Sprintf(lb.format, val)
}
}
//insert one item from list model
func (lb *ListBox) insertItemAt(index int) error {
str := lb.itemString(index)
lp := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(str)))
ret := int(lb.SendMessage(win.LB_INSERTSTRING, uintptr(index), lp))
if ret == win.LB_ERRSPACE || ret == win.LB_ERR {
return newError("SendMessage(LB_INSERTSTRING)")
}
return nil
}
func (lb *ListBox) removeItem(index int) error {
if win.LB_ERR == int(lb.SendMessage(win.LB_DELETESTRING, uintptr(index), 0)) {
return newError("SendMessage(LB_DELETESTRING)")
}
return nil
}
// reread all the items from list model
func (lb *ListBox) resetItems() error {
lb.SetSuspended(true)
defer lb.SetSuspended(false)
lb.SendMessage(win.LB_RESETCONTENT, 0, 0)
lb.maxItemTextWidth = 0
oldValue := lb.currentValue
if lb.model == nil {
lb.SetCurrentIndex(-1)
return nil
}
count := lb.model.ItemCount()
lb.lastWidthsMeasuredFor = make([]int, count)
for i := 0; i < count; i++ {
if err := lb.insertItemAt(i); err != nil {
return err
}
}
if oldValue != nil {
lb.Property("Value").Set(oldValue)
} else {
lb.SetCurrentIndex(-1)
}
if lb.styler == nil {
// Update the listbox width (this sets the correct horizontal scrollbar).
sh := lb.idealSize()
lb.SendMessage(win.LB_SETHORIZONTALEXTENT, uintptr(sh.Width), 0)
}
return nil
}
func (lb *ListBox) ensureVisibleItemsHeightUpToDate() error {
if lb.styler == nil {
return nil
}
if !lb.Suspended() {
lb.SetSuspended(true)
defer lb.SetSuspended(false)
}
topIndex := int(lb.SendMessage(win.LB_GETTOPINDEX, 0, 0))
offset := maxi(0, topIndex-10)
count := lb.model.ItemCount()
var rc win.RECT
lb.SendMessage(win.LB_GETITEMRECT, uintptr(offset), uintptr(unsafe.Pointer(&rc)))
width := int(rc.Right - rc.Left)
offsetTop := int(rc.Top)
lbHeight := lb.HeightPixels()
var pastBottomCount int
for i := offset; i >= 0 && i < count; i++ {
if lb.lastWidthsMeasuredFor[i] == lb.lastWidth {
continue
}
lb.SendMessage(win.LB_GETITEMRECT, uintptr(i), uintptr(unsafe.Pointer(&rc)))
if int(rc.Top)-offsetTop > lbHeight {
if pastBottomCount++; pastBottomCount > 10 {
break
}
}
height := lb.styler.ItemHeight(i, width)
lb.SendMessage(win.LB_SETITEMHEIGHT, uintptr(i), uintptr(height))
lb.lastWidthsMeasuredFor[i] = lb.lastWidth
}
lb.EnsureItemVisible(topIndex)
return nil
}
func (lb *ListBox) attachModel() {
itemsResetHandler := func() {
lb.resetItems()
}
lb.itemsResetHandlerHandle = lb.model.ItemsReset().Attach(itemsResetHandler)
itemChangedHandler := func(index int) {
if win.CB_ERR == lb.SendMessage(win.LB_DELETESTRING, uintptr(index), 0) {
newError("SendMessage(CB_DELETESTRING)")
}
lb.insertItemAt(index)
if lb.styler != nil {
var rc win.RECT
lb.SendMessage(win.LB_GETITEMRECT, uintptr(index), uintptr(unsafe.Pointer(&rc)))
width := int(rc.Right - rc.Left)
height := lb.styler.ItemHeight(index, width)
lb.SendMessage(win.LB_SETITEMHEIGHT, uintptr(index), uintptr(height))
lb.lastWidthsMeasuredFor[index] = lb.lastWidth
}
lb.SetCurrentIndex(lb.prevCurIndex)
}
lb.itemChangedHandlerHandle = lb.model.ItemChanged().Attach(itemChangedHandler)
lb.itemsInsertedHandlerHandle = lb.model.ItemsInserted().Attach(func(from, to int) {
if !lb.Suspended() {
lb.SetSuspended(true)
defer lb.SetSuspended(false)
}
for i := from; i <= to; i++ {
lb.insertItemAt(i)
}
lb.lastWidthsMeasuredFor = append(lb.lastWidthsMeasuredFor[:from], append(make([]int, to-from+1), lb.lastWidthsMeasuredFor[from:]...)...)
lb.ensureVisibleItemsHeightUpToDate()
})
lb.itemsRemovedHandlerHandle = lb.model.ItemsRemoved().Attach(func(from, to int) {
if !lb.Suspended() {
lb.SetSuspended(true)
defer lb.SetSuspended(false)
}
for i := to; i >= from; i-- {
lb.removeItem(i)
}
lb.lastWidthsMeasuredFor = append(lb.lastWidthsMeasuredFor[:from], lb.lastWidthsMeasuredFor[to:]...)
lb.ensureVisibleItemsHeightUpToDate()
})
}
func (lb *ListBox) detachModel() {
lb.model.ItemsReset().Detach(lb.itemsResetHandlerHandle)
lb.model.ItemChanged().Detach(lb.itemChangedHandlerHandle)
lb.model.ItemsInserted().Detach(lb.itemsInsertedHandlerHandle)
lb.model.ItemsRemoved().Detach(lb.itemsRemovedHandlerHandle)
}
// Model returns the model of the ListBox.
func (lb *ListBox) Model() interface{} {
return lb.providedModel
}
// SetModel sets the model of the ListBox.
//
// It is required that mdl either implements walk.ListModel or
// walk.ReflectListModel or be a slice of pointers to struct or a []string.
func (lb *ListBox) SetModel(mdl interface{}) error {
model, ok := mdl.(ListModel)
if !ok && mdl != nil {
var err error
if model, err = newReflectListModel(mdl); err != nil {
return err
}
if _, ok := mdl.([]string); !ok {
if badms, ok := model.(bindingAndDisplayMemberSetter); ok {
badms.setBindingMember(lb.bindingMember)
badms.setDisplayMember(lb.displayMember)
}
}
}
lb.providedModel = mdl
if lb.model != nil {
lb.detachModel()
}
lb.model = model
lb.bindingValueProvider, _ = model.(BindingValueProvider)
if model != nil {
lb.attachModel()
}
if err := lb.resetItems(); err != nil {
return err
}
return lb.ensureVisibleItemsHeightUpToDate()
}
// BindingMember returns the member from the model of the ListBox that is bound
// to a field of the data source managed by an associated DataBinder.
//
// This is only applicable to walk.ReflectListModel models and simple slices of
// pointers to struct.
func (lb *ListBox) BindingMember() string {
return lb.bindingMember
}
// SetBindingMember sets the member from the model of the ListBox that is bound
// to a field of the data source managed by an associated DataBinder.
//
// This is only applicable to walk.ReflectListModel models and simple slices of
// pointers to struct.
//
// For a model consisting of items of type S, data source field of type T and
// bindingMember "Foo", this can be one of the following:
//
// A field Foo T
// A method func (s S) Foo() T
// A method func (s S) Foo() (T, error)
//
// If bindingMember is not a simple member name like "Foo", but a path to a
// member like "A.B.Foo", members "A" and "B" both must be one of the options
// mentioned above, but with T having type pointer to struct.
func (lb *ListBox) SetBindingMember(bindingMember string) error {
if bindingMember != "" {
if _, ok := lb.providedModel.([]string); ok {
return newError("invalid for []string model")
}
}
lb.bindingMember = bindingMember
if badms, ok := lb.model.(bindingAndDisplayMemberSetter); ok {
badms.setBindingMember(bindingMember)
}
return nil
}
// DisplayMember returns the member from the model of the ListBox that is
// displayed in the ListBox.
//
// This is only applicable to walk.ReflectListModel models and simple slices of
// pointers to struct.
func (lb *ListBox) DisplayMember() string {
return lb.displayMember
}
// SetDisplayMember sets the member from the model of the ListBox that is
// displayed in the ListBox.
//
// This is only applicable to walk.ReflectListModel models and simple slices of
// pointers to struct.
//
// For a model consisting of items of type S, the type of the specified member T
// and displayMember "Foo", this can be one of the following:
//
// A field Foo T
// A method func (s S) Foo() T
// A method func (s S) Foo() (T, error)
//
// If displayMember is not a simple member name like "Foo", but a path to a
// member like "A.B.Foo", members "A" and "B" both must be one of the options
// mentioned above, but with T having type pointer to struct.
func (lb *ListBox) SetDisplayMember(displayMember string) error {
if displayMember != "" {
if _, ok := lb.providedModel.([]string); ok {
return newError("invalid for []string model")
}
}
lb.displayMember = displayMember
if badms, ok := lb.model.(bindingAndDisplayMemberSetter); ok {
badms.setDisplayMember(displayMember)
}
return nil
}
func (lb *ListBox) Format() string {
return lb.format
}
func (lb *ListBox) SetFormat(value string) {
lb.format = value
}
func (lb *ListBox) Precision() int {
return lb.precision
}
func (lb *ListBox) SetPrecision(value int) {
lb.precision = value
}
// calculateMaxItemTextWidth returns maximum item text width in native pixels.
func (lb *ListBox) calculateMaxItemTextWidth() int {
hdc := win.GetDC(lb.hWnd)
if hdc == 0 {
newError("GetDC failed")
return -1
}
defer win.ReleaseDC(lb.hWnd, hdc)
hFontOld := win.SelectObject(hdc, win.HGDIOBJ(lb.Font().handleForDPI(lb.DPI())))
defer win.SelectObject(hdc, hFontOld)
var maxWidth int
if lb.model == nil {
return -1
}
count := lb.model.ItemCount()
for i := 0; i < count; i++ {
item := lb.itemString(i)
var s win.SIZE
str := syscall.StringToUTF16(item)
if !win.GetTextExtentPoint32(hdc, &str[0], int32(len(str)-1), &s) {
newError("GetTextExtentPoint32 failed")
return -1
}
maxWidth = maxi(maxWidth, int(s.CX))
}
return maxWidth
}
// idealSize returns listbox ideal size in native pixels.
func (lb *ListBox) idealSize() Size {
defaultSize := lb.dialogBaseUnitsToPixels(Size{50, 12})
if lb.maxItemTextWidth <= 0 {
lb.maxItemTextWidth = lb.calculateMaxItemTextWidth()
}
// FIXME: Use GetThemePartSize instead of guessing
w := maxi(defaultSize.Width, lb.maxItemTextWidth+IntFrom96DPI(24, lb.DPI()))
h := defaultSize.Height + 1
return Size{w, h}
}
func (lb *ListBox) ItemVisible(index int) bool {
topIndex := int(lb.SendMessage(win.LB_GETTOPINDEX, 0, 0))
var rc win.RECT
lb.SendMessage(win.LB_GETITEMRECT, uintptr(index), uintptr(unsafe.Pointer(&rc)))
return index >= topIndex && int(rc.Top) < lb.HeightPixels()
}
func (lb *ListBox) EnsureItemVisible(index int) {
lb.SendMessage(win.LB_SETTOPINDEX, uintptr(index), 0)
}
func (lb *ListBox) CurrentIndex() int {
return int(int32(lb.SendMessage(win.LB_GETCURSEL, 0, 0)))
}
func (lb *ListBox) SetCurrentIndex(value int) error {
if value > -1 && win.LB_ERR == int(int32(lb.SendMessage(win.LB_SETCURSEL, uintptr(value), 0))) {
return newError("Invalid index or ensure lb is single-selection listbox")
}
if value != lb.prevCurIndex {
if value == -1 {
lb.currentValue = nil
} else {
lb.currentValue = lb.Property("Value").Get()
}
lb.prevCurIndex = value
lb.currentIndexChangedPublisher.Publish()
}
return nil
}
func (lb *ListBox) SelectedIndexes() []int {
count := int(int32(lb.SendMessage(win.LB_GETCOUNT, 0, 0)))
if count < 1 {
return nil
}
index32 := make([]int32, count)
if n := int(int32(lb.SendMessage(win.LB_GETSELITEMS, uintptr(count), uintptr(unsafe.Pointer(&index32[0]))))); n == win.LB_ERR {
return nil
} else {
indexes := make([]int, n)
for i := 0; i < n; i++ {
indexes[i] = int(index32[i])
}
return indexes
}
}
func (lb *ListBox) SetSelectedIndexes(indexes []int) {
var m int32 = -1
lb.SendMessage(win.LB_SETSEL, win.FALSE, uintptr(m))
for _, v := range indexes {
lb.SendMessage(win.LB_SETSEL, win.TRUE, uintptr(uint32(v)))
}
lb.selectedIndexesChangedPublisher.Publish()
}
func (lb *ListBox) CurrentIndexChanged() *Event {
return lb.currentIndexChangedPublisher.Event()
}
func (lb *ListBox) SelectedIndexesChanged() *Event {
return lb.selectedIndexesChangedPublisher.Event()
}
func (lb *ListBox) ItemActivated() *Event {
return lb.itemActivatedPublisher.Event()
}
func (lb *ListBox) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {
switch msg {
case win.WM_MEASUREITEM:
if lb.styler == nil {
break
}
mis := (*win.MEASUREITEMSTRUCT)(unsafe.Pointer(lParam))
mis.ItemHeight = uint32(lb.styler.DefaultItemHeight())
return win.TRUE
case win.WM_DRAWITEM:
dis := (*win.DRAWITEMSTRUCT)(unsafe.Pointer(lParam))
if lb.styler == nil || dis.ItemID < 0 || dis.ItemAction != win.ODA_DRAWENTIRE {
return win.TRUE
}
lb.style.index = int(dis.ItemID)
lb.style.rc = dis.RcItem
lb.style.bounds = rectangleFromRECT(dis.RcItem)
lb.style.dpi = lb.DPI()
lb.style.state = dis.ItemState
lb.style.hwnd = lb.hWnd
lb.style.hdc = dis.HDC
lb.style.Font = lb.Font()
if dis.ItemAction == win.ODA_FOCUS {
return win.TRUE
}
var hTheme win.HTHEME
if !lb.style.highContrastActive {
if hTheme = win.OpenThemeData(lb.hWnd, syscall.StringToUTF16Ptr("Listview")); hTheme != 0 {
defer win.CloseThemeData(hTheme)
}
}
lb.style.hTheme = hTheme
if dis.ItemState&win.ODS_CHECKED != 0 {
if lb.style.highContrastActive || lb.Focused() {
lb.style.BackgroundColor = lb.themeSelectedBGColor
lb.style.TextColor = lb.themeSelectedTextColor
} else {
lb.style.BackgroundColor = lb.themeSelectedNotFocusedBGColor
lb.style.TextColor = lb.themeNormalTextColor
}
} else if int(dis.ItemID) == lb.style.hoverIndex {
if hTheme == 0 {
lb.style.BackgroundColor = lb.themeNormalBGColor
} else {
lb.style.BackgroundColor = lb.themeSelectedBGColor
}
lb.style.TextColor = lb.themeNormalTextColor
} else {
lb.style.BackgroundColor = lb.themeNormalBGColor
lb.style.TextColor = lb.themeNormalTextColor
}
if lb.themeNormalTextColor == RGB(0, 0, 0) {
lb.style.LineColor = RGB(0, 0, 0)
} else {
lb.style.LineColor = RGB(255, 255, 255)
}
lb.style.defaultTextColor = lb.style.TextColor
lb.style.DrawBackground()
lb.styler.StyleItem(&lb.style)
defer func() {
lb.style.bounds = Rectangle{}
if lb.style.canvas != nil {
lb.style.canvas.Dispose()
lb.style.canvas = nil
}
lb.style.hdc = 0
}()
return win.TRUE
case win.WM_WINDOWPOSCHANGED:
wp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))
if wp.Flags&win.SWP_NOSIZE != 0 {
break
}
if lb.styler != nil && lb.styler.ItemHeightDependsOnWidth() {
width := lb.WidthPixels()
if width != lb.lastWidth {
lb.lastWidth = width
lb.lastWidthsMeasuredFor = make([]int, lb.model.ItemCount())
}
}
lb.ensureVisibleItemsHeightUpToDate()
return win.CallWindowProc(lb.origWndProcPtr, hwnd, msg, wParam, lParam)
case win.WM_VSCROLL:
lb.ensureVisibleItemsHeightUpToDate()
case win.WM_MOUSEWHEEL:
lb.ensureVisibleItemsHeightUpToDate()
case win.WM_LBUTTONDOWN:
lb.Invalidate()
case win.WM_MOUSEMOVE:
if lb.styler == nil {
break
}
if !lb.trackingMouseEvent {
var tme win.TRACKMOUSEEVENT
tme.CbSize = uint32(unsafe.Sizeof(tme))
tme.DwFlags = win.TME_LEAVE
tme.HwndTrack = lb.hWnd
lb.trackingMouseEvent = win.TrackMouseEvent(&tme)
}
oldHoverIndex := lb.style.hoverIndex
result := uint32(lb.SendMessage(win.LB_ITEMFROMPOINT, 0, lParam))
if win.HIWORD(result) == 0 {
index := int(win.LOWORD(result))
var rc win.RECT
lb.SendMessage(win.LB_GETITEMRECT, uintptr(index), uintptr(unsafe.Pointer(&rc)))
lp := uint32(lParam)
x := int32(win.LOWORD(lp))
y := int32(win.HIWORD(lp))
if x >= rc.Left && x <= rc.Right && y >= rc.Top && y <= rc.Bottom {
lb.style.hoverIndex = index
win.InvalidateRect(lb.hWnd, &rc, true)
}
}
if lb.style.hoverIndex != oldHoverIndex {
if wParam&win.MK_LBUTTON != 0 {
lb.Invalidate()
} else {
lb.invalidateItem(oldHoverIndex)
lb.invalidateItem(lb.style.hoverIndex)
}
}
case win.WM_MOUSELEAVE:
if lb.styler == nil {
break
}
lb.trackingMouseEvent = false
index := lb.style.hoverIndex
lb.style.hoverIndex = -1
lb.invalidateItem(index)
case win.WM_COMMAND:
switch win.HIWORD(uint32(wParam)) {
case win.LBN_SELCHANGE:
lb.ensureVisibleItemsHeightUpToDate()
lb.prevCurIndex = lb.CurrentIndex()
lb.currentValue = lb.Property("Value").Get()
lb.currentIndexChangedPublisher.Publish()
lb.selectedIndexesChangedPublisher.Publish()
case win.LBN_DBLCLK:
lb.itemActivatedPublisher.Publish()
}
case win.WM_GETDLGCODE:
if form := ancestor(lb); form != nil {
if dlg, ok := form.(dialogish); ok {
if dlg.DefaultButton() != nil {
// If the ListBox lives in a Dialog that has a DefaultButton,
// we won't swallow the return key.
break
}
}
}
if wParam == win.VK_RETURN {
return win.DLGC_WANTALLKEYS
}
case win.WM_KEYDOWN:
if uint32(lParam)>>30 == 0 && Key(wParam) == KeyReturn && lb.CurrentIndex() > -1 {
lb.itemActivatedPublisher.Publish()
}
}
return lb.WidgetBase.WndProc(hwnd, msg, wParam, lParam)
}
func (lb *ListBox) invalidateItem(index int) {
var rc win.RECT
lb.SendMessage(win.LB_GETITEMRECT, uintptr(index), uintptr(unsafe.Pointer(&rc)))
win.InvalidateRect(lb.hWnd, &rc, true)
}
func (lb *ListBox) CreateLayoutItem(ctx *LayoutContext) LayoutItem {
return NewGreedyLayoutItem()
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/zxy4096/walk.git
git@gitee.com:zxy4096/walk.git
zxy4096
walk
walk
c389da54e794

搜索帮助