702 lines
20 KiB
Go
702 lines
20 KiB
Go
|
// Copyright 2012 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 (
|
||
|
"syscall"
|
||
|
|
||
|
"github.com/lxn/win"
|
||
|
)
|
||
|
|
||
|
// BindingValueProvider is the interface that a model must implement to support
|
||
|
// data binding with widgets like ComboBox.
|
||
|
type BindingValueProvider interface {
|
||
|
BindingValue(index int) interface{}
|
||
|
}
|
||
|
|
||
|
// ListModel is the interface that a model must implement to support widgets
|
||
|
// like ComboBox.
|
||
|
type ListModel interface {
|
||
|
// ItemCount returns the number of items in the model.
|
||
|
ItemCount() int
|
||
|
|
||
|
// Value returns the value that should be displayed for the given index.
|
||
|
Value(index int) interface{}
|
||
|
|
||
|
// ItemsReset returns the event that the model should publish when the
|
||
|
// number of its items changes.
|
||
|
ItemsReset() *Event
|
||
|
|
||
|
// ItemChanged returns the event that the model should publish when an item
|
||
|
// was changed.
|
||
|
ItemChanged() *IntEvent
|
||
|
|
||
|
// ItemsInserted returns the event that the model should publish when a
|
||
|
// contiguous range of items was inserted.
|
||
|
ItemsInserted() *IntRangeEvent
|
||
|
|
||
|
// ItemsRemoved returns the event that the model should publish when a
|
||
|
// contiguous range of items was removed.
|
||
|
ItemsRemoved() *IntRangeEvent
|
||
|
}
|
||
|
|
||
|
// ListModelBase implements the ItemsReset and ItemChanged methods of the
|
||
|
// ListModel interface.
|
||
|
type ListModelBase struct {
|
||
|
itemsResetPublisher EventPublisher
|
||
|
itemChangedPublisher IntEventPublisher
|
||
|
itemsInsertedPublisher IntRangeEventPublisher
|
||
|
itemsRemovedPublisher IntRangeEventPublisher
|
||
|
}
|
||
|
|
||
|
func (lmb *ListModelBase) ItemsReset() *Event {
|
||
|
return lmb.itemsResetPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (lmb *ListModelBase) ItemChanged() *IntEvent {
|
||
|
return lmb.itemChangedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (lmb *ListModelBase) ItemsInserted() *IntRangeEvent {
|
||
|
return lmb.itemsInsertedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (lmb *ListModelBase) ItemsRemoved() *IntRangeEvent {
|
||
|
return lmb.itemsRemovedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (lmb *ListModelBase) PublishItemsReset() {
|
||
|
lmb.itemsResetPublisher.Publish()
|
||
|
}
|
||
|
|
||
|
func (lmb *ListModelBase) PublishItemChanged(index int) {
|
||
|
lmb.itemChangedPublisher.Publish(index)
|
||
|
}
|
||
|
|
||
|
func (lmb *ListModelBase) PublishItemsInserted(from, to int) {
|
||
|
lmb.itemsInsertedPublisher.Publish(from, to)
|
||
|
}
|
||
|
|
||
|
func (lmb *ListModelBase) PublishItemsRemoved(from, to int) {
|
||
|
lmb.itemsRemovedPublisher.Publish(from, to)
|
||
|
}
|
||
|
|
||
|
// ReflectListModel provides an alternative to the ListModel interface. It
|
||
|
// uses reflection to obtain data.
|
||
|
type ReflectListModel interface {
|
||
|
// Items returns the model data, which must be a slice of pointer to struct.
|
||
|
Items() interface{}
|
||
|
|
||
|
// ItemsReset returns the event that the model should publish when the
|
||
|
// number of its items changes.
|
||
|
ItemsReset() *Event
|
||
|
|
||
|
// ItemChanged returns the event that the model should publish when an item
|
||
|
// was changed.
|
||
|
ItemChanged() *IntEvent
|
||
|
|
||
|
// ItemsInserted returns the event that the model should publish when a
|
||
|
// contiguous range of items was inserted.
|
||
|
ItemsInserted() *IntRangeEvent
|
||
|
|
||
|
// ItemsRemoved returns the event that the model should publish when a
|
||
|
// contiguous range of items was removed.
|
||
|
ItemsRemoved() *IntRangeEvent
|
||
|
|
||
|
setValueFunc(value func(index int) interface{})
|
||
|
}
|
||
|
|
||
|
// ReflectListModelBase implements the ItemsReset and ItemChanged methods of
|
||
|
// the ReflectListModel interface.
|
||
|
type ReflectListModelBase struct {
|
||
|
ListModelBase
|
||
|
value func(index int) interface{}
|
||
|
}
|
||
|
|
||
|
func (rlmb *ReflectListModelBase) setValueFunc(value func(index int) interface{}) {
|
||
|
rlmb.value = value
|
||
|
}
|
||
|
|
||
|
func (rlmb *ReflectListModelBase) Value(index int) interface{} {
|
||
|
return rlmb.value(index)
|
||
|
}
|
||
|
|
||
|
// TableModel is the interface that a model must implement to support widgets
|
||
|
// like TableView.
|
||
|
type TableModel interface {
|
||
|
// RowCount returns the number of rows in the model.
|
||
|
RowCount() int
|
||
|
|
||
|
// Value returns the value that should be displayed for the given cell.
|
||
|
Value(row, col int) interface{}
|
||
|
|
||
|
// RowsReset returns the event that the model should publish when the number
|
||
|
// of its rows changes.
|
||
|
RowsReset() *Event
|
||
|
|
||
|
// RowChanged returns the event that the model should publish when a row was
|
||
|
// changed.
|
||
|
RowChanged() *IntEvent
|
||
|
|
||
|
// RowsChanged returns the event that the model should publish when a
|
||
|
// contiguous range of items was changed.
|
||
|
RowsChanged() *IntRangeEvent
|
||
|
|
||
|
// RowsInserted returns the event that the model should publish when a
|
||
|
// contiguous range of items was inserted. If the model supports sorting, it
|
||
|
// is assumed to be sorted before the model publishes the event.
|
||
|
RowsInserted() *IntRangeEvent
|
||
|
|
||
|
// RowsRemoved returns the event that the model should publish when a
|
||
|
// contiguous range of items was removed.
|
||
|
RowsRemoved() *IntRangeEvent
|
||
|
}
|
||
|
|
||
|
// TableModelBase implements the RowsReset and RowChanged methods of the
|
||
|
// TableModel interface.
|
||
|
type TableModelBase struct {
|
||
|
rowsResetPublisher EventPublisher
|
||
|
rowChangedPublisher IntEventPublisher
|
||
|
rowsChangedPublisher IntRangeEventPublisher
|
||
|
rowsInsertedPublisher IntRangeEventPublisher
|
||
|
rowsRemovedPublisher IntRangeEventPublisher
|
||
|
}
|
||
|
|
||
|
func (tmb *TableModelBase) RowsReset() *Event {
|
||
|
return tmb.rowsResetPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (tmb *TableModelBase) RowChanged() *IntEvent {
|
||
|
return tmb.rowChangedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (tmb *TableModelBase) RowsChanged() *IntRangeEvent {
|
||
|
return tmb.rowsChangedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (tmb *TableModelBase) RowsInserted() *IntRangeEvent {
|
||
|
return tmb.rowsInsertedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (tmb *TableModelBase) RowsRemoved() *IntRangeEvent {
|
||
|
return tmb.rowsRemovedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (tmb *TableModelBase) PublishRowsReset() {
|
||
|
tmb.rowsResetPublisher.Publish()
|
||
|
}
|
||
|
|
||
|
func (tmb *TableModelBase) PublishRowChanged(row int) {
|
||
|
tmb.rowChangedPublisher.Publish(row)
|
||
|
}
|
||
|
|
||
|
func (tmb *TableModelBase) PublishRowsChanged(from, to int) {
|
||
|
tmb.rowsChangedPublisher.Publish(from, to)
|
||
|
}
|
||
|
|
||
|
func (tmb *TableModelBase) PublishRowsInserted(from, to int) {
|
||
|
tmb.rowsInsertedPublisher.Publish(from, to)
|
||
|
}
|
||
|
|
||
|
func (tmb *TableModelBase) PublishRowsRemoved(from, to int) {
|
||
|
tmb.rowsRemovedPublisher.Publish(from, to)
|
||
|
}
|
||
|
|
||
|
// ReflectTableModel provides an alternative to the TableModel interface. It
|
||
|
// uses reflection to obtain data.
|
||
|
type ReflectTableModel interface {
|
||
|
// Items returns the model data, which must be a slice of pointer to struct.
|
||
|
Items() interface{}
|
||
|
|
||
|
// RowsReset returns the event that the model should publish when the
|
||
|
// number of its items changes.
|
||
|
RowsReset() *Event
|
||
|
|
||
|
// RowChanged returns the event that the model should publish when an item
|
||
|
// was changed.
|
||
|
RowChanged() *IntEvent
|
||
|
|
||
|
// RowsChanged returns the event that the model should publish when a
|
||
|
// contiguous range of items was changed.
|
||
|
RowsChanged() *IntRangeEvent
|
||
|
|
||
|
// RowsInserted returns the event that the model should publish when a
|
||
|
// contiguous range of items was inserted. If the model supports sorting, it
|
||
|
// is assumed to be sorted before the model publishes the event.
|
||
|
RowsInserted() *IntRangeEvent
|
||
|
|
||
|
// RowsRemoved returns the event that the model should publish when a
|
||
|
// contiguous range of items was removed.
|
||
|
RowsRemoved() *IntRangeEvent
|
||
|
|
||
|
setValueFunc(value func(row, col int) interface{})
|
||
|
}
|
||
|
|
||
|
// ReflectTableModelBase implements the ItemsReset and ItemChanged methods of
|
||
|
// the ReflectTableModel interface.
|
||
|
type ReflectTableModelBase struct {
|
||
|
TableModelBase
|
||
|
value func(row, col int) interface{}
|
||
|
}
|
||
|
|
||
|
func (rtmb *ReflectTableModelBase) setValueFunc(value func(row, col int) interface{}) {
|
||
|
rtmb.value = value
|
||
|
}
|
||
|
|
||
|
func (rtmb *ReflectTableModelBase) Value(row, col int) interface{} {
|
||
|
return rtmb.value(row, col)
|
||
|
}
|
||
|
|
||
|
type interceptedSorter interface {
|
||
|
sorterBase() *SorterBase
|
||
|
setSortFunc(sort func(col int, order SortOrder) error)
|
||
|
}
|
||
|
|
||
|
// SortedReflectTableModelBase implements the RowsReset and RowChanged methods
|
||
|
// of the ReflectTableModel interface as well as the Sorter interface for
|
||
|
// pre-implemented in-memory sorting.
|
||
|
type SortedReflectTableModelBase struct {
|
||
|
ReflectTableModelBase
|
||
|
SorterBase
|
||
|
sort func(col int, order SortOrder) error
|
||
|
}
|
||
|
|
||
|
func (srtmb *SortedReflectTableModelBase) setSortFunc(sort func(col int, order SortOrder) error) {
|
||
|
srtmb.sort = sort
|
||
|
}
|
||
|
|
||
|
func (srtmb *SortedReflectTableModelBase) sorterBase() *SorterBase {
|
||
|
return &srtmb.SorterBase
|
||
|
}
|
||
|
|
||
|
func (srtmb *SortedReflectTableModelBase) Sort(col int, order SortOrder) error {
|
||
|
if srtmb.sort != nil {
|
||
|
return srtmb.sort(col, order)
|
||
|
}
|
||
|
|
||
|
return srtmb.SorterBase.Sort(col, order)
|
||
|
}
|
||
|
|
||
|
// Populator is an interface that can be implemented by Reflect*Models and slice
|
||
|
// types to populate themselves on demand.
|
||
|
//
|
||
|
// Widgets like TableView, ListBox and ComboBox support lazy population of a
|
||
|
// Reflect*Model or slice, if it implements this interface.
|
||
|
type Populator interface {
|
||
|
// Populate initializes the slot specified by index.
|
||
|
//
|
||
|
// For best performance it is probably a good idea to populate more than a
|
||
|
// single slot of the slice at once.
|
||
|
Populate(index int) error
|
||
|
}
|
||
|
|
||
|
// ImageProvider is the interface that a model must implement to support
|
||
|
// displaying an item image.
|
||
|
type ImageProvider interface {
|
||
|
// Image returns the image to display for the item at index index.
|
||
|
//
|
||
|
// Supported types are *walk.Bitmap, *walk.Icon and string. A string will be
|
||
|
// interpreted as a file path and the icon associated with the file will be
|
||
|
// used. It is not supported to use strings together with the other options
|
||
|
// in the same model instance.
|
||
|
Image(index int) interface{}
|
||
|
}
|
||
|
|
||
|
// CellStyler is the interface that must be implemented to provide a tabular
|
||
|
// widget like TableView with cell display style information.
|
||
|
type CellStyler interface {
|
||
|
// StyleCell is called for each cell to pick up cell style information.
|
||
|
StyleCell(style *CellStyle)
|
||
|
}
|
||
|
|
||
|
// CellStyle carries information about the display style of a cell in a tabular widget
|
||
|
// like TableView.
|
||
|
type CellStyle struct {
|
||
|
row int
|
||
|
col int
|
||
|
bounds Rectangle // in native pixels
|
||
|
hdc win.HDC
|
||
|
dpi int
|
||
|
canvas *Canvas
|
||
|
BackgroundColor Color
|
||
|
TextColor Color
|
||
|
Font *Font
|
||
|
|
||
|
// Image is the image to display in the cell.
|
||
|
//
|
||
|
// Supported types are *walk.Bitmap, *walk.Icon and string. A string will be
|
||
|
// interpreted as a file path and the icon associated with the file will be
|
||
|
// used. It is not supported to use strings together with the other options
|
||
|
// in the same model instance.
|
||
|
Image interface{}
|
||
|
}
|
||
|
|
||
|
func (cs *CellStyle) Row() int {
|
||
|
return cs.row
|
||
|
}
|
||
|
|
||
|
func (cs *CellStyle) Col() int {
|
||
|
return cs.col
|
||
|
}
|
||
|
|
||
|
func (cs *CellStyle) Bounds() Rectangle {
|
||
|
return RectangleTo96DPI(cs.bounds, cs.dpi)
|
||
|
}
|
||
|
|
||
|
func (cs *CellStyle) BoundsPixels() Rectangle {
|
||
|
return cs.bounds
|
||
|
}
|
||
|
|
||
|
func (cs *CellStyle) Canvas() *Canvas {
|
||
|
if cs.canvas != nil {
|
||
|
cs.canvas.dpi = cs.dpi
|
||
|
return cs.canvas
|
||
|
}
|
||
|
|
||
|
if cs.hdc != 0 {
|
||
|
cs.canvas, _ = newCanvasFromHDC(cs.hdc)
|
||
|
cs.canvas.dpi = cs.dpi
|
||
|
}
|
||
|
|
||
|
return cs.canvas
|
||
|
}
|
||
|
|
||
|
// ListItemStyler is the interface that must be implemented to provide a list
|
||
|
// widget like ListBox with item display style information.
|
||
|
type ListItemStyler interface {
|
||
|
// ItemHeightDependsOnWidth returns whether item height depends on width.
|
||
|
ItemHeightDependsOnWidth() bool
|
||
|
|
||
|
// DefaultItemHeight returns the initial height in native pixels for any item.
|
||
|
DefaultItemHeight() int
|
||
|
|
||
|
// ItemHeight is called for each item to retrieve the height of the item. width parameter and
|
||
|
// return value are specified in native pixels.
|
||
|
ItemHeight(index int, width int) int
|
||
|
|
||
|
// StyleItem is called for each item to pick up item style information.
|
||
|
StyleItem(style *ListItemStyle)
|
||
|
}
|
||
|
|
||
|
// ListItemStyle carries information about the display style of an item in a list widget
|
||
|
// like ListBox.
|
||
|
type ListItemStyle struct {
|
||
|
BackgroundColor Color
|
||
|
TextColor Color
|
||
|
LineColor Color
|
||
|
Font *Font
|
||
|
index int
|
||
|
hoverIndex int
|
||
|
rc win.RECT
|
||
|
bounds Rectangle // in native pixels
|
||
|
state uint32
|
||
|
hTheme win.HTHEME
|
||
|
hwnd win.HWND
|
||
|
hdc win.HDC
|
||
|
dpi int
|
||
|
canvas *Canvas
|
||
|
highContrastActive bool
|
||
|
}
|
||
|
|
||
|
func (lis *ListItemStyle) Index() int {
|
||
|
return lis.index
|
||
|
}
|
||
|
|
||
|
func (lis *ListItemStyle) Bounds() Rectangle {
|
||
|
return RectangleTo96DPI(lis.bounds, lis.dpi)
|
||
|
}
|
||
|
|
||
|
func (lis *ListItemStyle) BoundsPixels() Rectangle {
|
||
|
return lis.bounds
|
||
|
}
|
||
|
|
||
|
func (lis *ListItemStyle) Canvas() *Canvas {
|
||
|
if lis.canvas != nil {
|
||
|
lis.canvas.dpi = lis.dpi
|
||
|
return lis.canvas
|
||
|
}
|
||
|
|
||
|
if lis.hdc != 0 {
|
||
|
lis.canvas, _ = newCanvasFromHDC(lis.hdc)
|
||
|
lis.canvas.dpi = lis.dpi
|
||
|
}
|
||
|
|
||
|
return lis.canvas
|
||
|
}
|
||
|
|
||
|
func (lis *ListItemStyle) DrawBackground() error {
|
||
|
canvas := lis.Canvas()
|
||
|
if canvas == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
stateID := lis.stateID()
|
||
|
|
||
|
if lis.hTheme != 0 && stateID != win.LISS_NORMAL {
|
||
|
if win.FAILED(win.DrawThemeBackground(lis.hTheme, lis.hdc, win.LVP_LISTITEM, stateID, &lis.rc, nil)) {
|
||
|
return newError("DrawThemeBackground failed")
|
||
|
}
|
||
|
} else {
|
||
|
brush, err := NewSolidColorBrush(lis.BackgroundColor)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer brush.Dispose()
|
||
|
|
||
|
if err := canvas.FillRectanglePixels(brush, lis.bounds); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if lis.highContrastActive && (lis.index == lis.hoverIndex || stateID != win.LISS_NORMAL) {
|
||
|
pen, err := NewCosmeticPen(PenSolid, lis.LineColor)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer pen.Dispose()
|
||
|
|
||
|
if err := canvas.DrawRectanglePixels(pen, lis.bounds); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// DrawText draws text inside given bounds specified in native pixels.
|
||
|
func (lis *ListItemStyle) DrawText(text string, bounds Rectangle, format DrawTextFormat) error {
|
||
|
if lis.hTheme != 0 {
|
||
|
if lis.Font != nil {
|
||
|
hFontOld := win.SelectObject(lis.hdc, win.HGDIOBJ(lis.Font.handleForDPI(lis.dpi)))
|
||
|
defer win.SelectObject(lis.hdc, hFontOld)
|
||
|
}
|
||
|
rc := bounds.toRECT()
|
||
|
|
||
|
if win.FAILED(win.DrawThemeTextEx(lis.hTheme, lis.hdc, win.LVP_LISTITEM, lis.stateID(), syscall.StringToUTF16Ptr(text), int32(len(([]rune)(text))), uint32(format), &rc, nil)) {
|
||
|
return newError("DrawThemeTextEx failed")
|
||
|
}
|
||
|
} else {
|
||
|
if canvas := lis.Canvas(); canvas != nil {
|
||
|
if err := canvas.DrawTextPixels(text, lis.Font, lis.TextColor, bounds, format); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (lis *ListItemStyle) stateID() int32 {
|
||
|
if lis.state&win.ODS_CHECKED != 0 {
|
||
|
if win.GetFocus() == lis.hwnd {
|
||
|
if lis.index == lis.hoverIndex {
|
||
|
return win.LISS_HOTSELECTED
|
||
|
} else {
|
||
|
return win.LISS_SELECTED
|
||
|
}
|
||
|
} else {
|
||
|
return win.LISS_SELECTEDNOTFOCUS
|
||
|
}
|
||
|
} else if lis.index == lis.hoverIndex {
|
||
|
return win.LISS_HOT
|
||
|
}
|
||
|
|
||
|
return win.LISS_NORMAL
|
||
|
}
|
||
|
|
||
|
// ItemChecker is the interface that a model must implement to support check
|
||
|
// boxes in a widget like TableView.
|
||
|
type ItemChecker interface {
|
||
|
// Checked returns if the specified item is checked.
|
||
|
Checked(index int) bool
|
||
|
|
||
|
// SetChecked sets if the specified item is checked.
|
||
|
SetChecked(index int, checked bool) error
|
||
|
}
|
||
|
|
||
|
// SortOrder specifies the order by which items are sorted.
|
||
|
type SortOrder int
|
||
|
|
||
|
const (
|
||
|
// SortAscending specifies ascending sort order.
|
||
|
SortAscending SortOrder = iota
|
||
|
|
||
|
// SortDescending specifies descending sort order.
|
||
|
SortDescending
|
||
|
)
|
||
|
|
||
|
// Sorter is the interface that a model must implement to support sorting with a
|
||
|
// widget like TableView.
|
||
|
type Sorter interface {
|
||
|
// ColumnSortable returns whether column col is sortable.
|
||
|
ColumnSortable(col int) bool
|
||
|
|
||
|
// Sort sorts column col in order order.
|
||
|
//
|
||
|
// If col is -1 then no column is to be sorted. Sort must publish the event
|
||
|
// returned from SortChanged() after sorting.
|
||
|
Sort(col int, order SortOrder) error
|
||
|
|
||
|
// SortChanged returns an event that is published after sorting.
|
||
|
SortChanged() *Event
|
||
|
|
||
|
// SortedColumn returns the index of the currently sorted column, or -1 if
|
||
|
// no column is currently sorted.
|
||
|
SortedColumn() int
|
||
|
|
||
|
// SortOrder returns the current sort order.
|
||
|
SortOrder() SortOrder
|
||
|
}
|
||
|
|
||
|
// SorterBase implements the Sorter interface.
|
||
|
//
|
||
|
// You still need to provide your own implementation of at least the Sort method
|
||
|
// to actually sort and reset the model. Your Sort method should call the
|
||
|
// SorterBase implementation so the SortChanged event, that e.g. a TableView
|
||
|
// widget depends on, is published.
|
||
|
type SorterBase struct {
|
||
|
changedPublisher EventPublisher
|
||
|
col int
|
||
|
order SortOrder
|
||
|
}
|
||
|
|
||
|
func (sb *SorterBase) ColumnSortable(col int) bool {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (sb *SorterBase) Sort(col int, order SortOrder) error {
|
||
|
sb.col, sb.order = col, order
|
||
|
|
||
|
sb.changedPublisher.Publish()
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (sb *SorterBase) SortChanged() *Event {
|
||
|
return sb.changedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (sb *SorterBase) SortedColumn() int {
|
||
|
return sb.col
|
||
|
}
|
||
|
|
||
|
func (sb *SorterBase) SortOrder() SortOrder {
|
||
|
return sb.order
|
||
|
}
|
||
|
|
||
|
// Imager provides access to an image of objects like tree items.
|
||
|
type Imager interface {
|
||
|
// Image returns the image to display for an item.
|
||
|
//
|
||
|
// Supported types are *walk.Bitmap, *walk.Icon and string. A string will be
|
||
|
// interpreted as a file path and the icon associated with the file will be
|
||
|
// used. It is not supported to use strings together with the other options
|
||
|
// in the same model instance.
|
||
|
Image() interface{}
|
||
|
}
|
||
|
|
||
|
// TreeItem represents an item in a TreeView widget.
|
||
|
type TreeItem interface {
|
||
|
// Text returns the text of the item.
|
||
|
Text() string
|
||
|
|
||
|
// Parent returns the parent of the item.
|
||
|
Parent() TreeItem
|
||
|
|
||
|
// ChildCount returns the number of children of the item.
|
||
|
ChildCount() int
|
||
|
|
||
|
// ChildAt returns the child at the specified index.
|
||
|
ChildAt(index int) TreeItem
|
||
|
}
|
||
|
|
||
|
// HasChilder enables widgets like TreeView to determine if an item has any
|
||
|
// child, without enforcing to fully count all children.
|
||
|
type HasChilder interface {
|
||
|
HasChild() bool
|
||
|
}
|
||
|
|
||
|
// TreeModel provides widgets like TreeView with item data.
|
||
|
type TreeModel interface {
|
||
|
// LazyPopulation returns if the model prefers on-demand population.
|
||
|
//
|
||
|
// This is useful for models that potentially contain huge amounts of items,
|
||
|
// e.g. a model that represents a file system.
|
||
|
LazyPopulation() bool
|
||
|
|
||
|
// RootCount returns the number of root items.
|
||
|
RootCount() int
|
||
|
|
||
|
// RootAt returns the root item at the specified index.
|
||
|
RootAt(index int) TreeItem
|
||
|
|
||
|
// ItemsReset returns the event that the model should publish when the
|
||
|
// descendants of the specified item, or all items if no item is specified,
|
||
|
// are reset.
|
||
|
ItemsReset() *TreeItemEvent
|
||
|
|
||
|
// ItemChanged returns the event that the model should publish when an item
|
||
|
// was changed.
|
||
|
ItemChanged() *TreeItemEvent
|
||
|
|
||
|
// ItemInserted returns the event that the model should publish when an item
|
||
|
// was inserted into the model.
|
||
|
ItemInserted() *TreeItemEvent
|
||
|
|
||
|
// ItemRemoved returns the event that the model should publish when an item
|
||
|
// was removed from the model.
|
||
|
ItemRemoved() *TreeItemEvent
|
||
|
}
|
||
|
|
||
|
// TreeModelBase partially implements the TreeModel interface.
|
||
|
//
|
||
|
// You still need to provide your own implementation of at least the
|
||
|
// RootCount and RootAt methods. If your model needs lazy population,
|
||
|
// you will also have to implement LazyPopulation.
|
||
|
type TreeModelBase struct {
|
||
|
itemsResetPublisher TreeItemEventPublisher
|
||
|
itemChangedPublisher TreeItemEventPublisher
|
||
|
itemInsertedPublisher TreeItemEventPublisher
|
||
|
itemRemovedPublisher TreeItemEventPublisher
|
||
|
}
|
||
|
|
||
|
func (tmb *TreeModelBase) LazyPopulation() bool {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (tmb *TreeModelBase) ItemsReset() *TreeItemEvent {
|
||
|
return tmb.itemsResetPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (tmb *TreeModelBase) ItemChanged() *TreeItemEvent {
|
||
|
return tmb.itemChangedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (tmb *TreeModelBase) ItemInserted() *TreeItemEvent {
|
||
|
return tmb.itemInsertedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (tmb *TreeModelBase) ItemRemoved() *TreeItemEvent {
|
||
|
return tmb.itemRemovedPublisher.Event()
|
||
|
}
|
||
|
|
||
|
func (tmb *TreeModelBase) PublishItemsReset(parent TreeItem) {
|
||
|
tmb.itemsResetPublisher.Publish(parent)
|
||
|
}
|
||
|
|
||
|
func (tmb *TreeModelBase) PublishItemChanged(item TreeItem) {
|
||
|
tmb.itemChangedPublisher.Publish(item)
|
||
|
}
|
||
|
|
||
|
func (tmb *TreeModelBase) PublishItemInserted(item TreeItem) {
|
||
|
tmb.itemInsertedPublisher.Publish(item)
|
||
|
}
|
||
|
|
||
|
func (tmb *TreeModelBase) PublishItemRemoved(item TreeItem) {
|
||
|
tmb.itemRemovedPublisher.Publish(item)
|
||
|
}
|