erm/vendor/github.com/lxn/walk/tableviewcolumn.go
2021-07-30 23:29:20 +01:00

487 lines
9.7 KiB
Go

// Copyright 2013 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"
"unsafe"
"github.com/lxn/win"
)
// TableViewColumn represents a column in a TableView.
type TableViewColumn struct {
tv *TableView
name string
dataMember string
alignment Alignment1D
format string
precision int
title string
titleOverride string
width int
lessFunc func(i, j int) bool
formatFunc func(value interface{}) string
visible bool
frozen bool
}
// NewTableViewColumn returns a new TableViewColumn.
func NewTableViewColumn() *TableViewColumn {
return &TableViewColumn{
format: "%v",
visible: true,
width: 50,
}
}
// Alignment returns the alignment of the TableViewColumn.
func (tvc *TableViewColumn) Alignment() Alignment1D {
return tvc.alignment
}
// SetAlignment sets the alignment of the TableViewColumn.
func (tvc *TableViewColumn) SetAlignment(alignment Alignment1D) (err error) {
if alignment == AlignDefault {
alignment = AlignNear
}
if alignment == tvc.alignment {
return nil
}
old := tvc.alignment
defer func() {
if err != nil {
tvc.alignment = old
}
}()
tvc.alignment = alignment
return tvc.update()
}
// DataMember returns the data member this TableViewColumn is bound against.
func (tvc *TableViewColumn) DataMember() string {
return tvc.dataMember
}
// DataMemberEffective returns the effective data member this TableViewColumn is
// bound against.
func (tvc *TableViewColumn) DataMemberEffective() string {
if tvc.dataMember != "" {
return tvc.dataMember
}
return tvc.name
}
// SetDataMember sets the data member this TableViewColumn is bound against.
func (tvc *TableViewColumn) SetDataMember(dataMember string) {
tvc.dataMember = dataMember
}
// Format returns the format string for converting a value into a string.
func (tvc *TableViewColumn) Format() string {
return tvc.format
}
// SetFormat sets the format string for converting a value into a string.
func (tvc *TableViewColumn) SetFormat(format string) (err error) {
if format == tvc.format {
return nil
}
old := tvc.format
defer func() {
if err != nil {
tvc.format = old
}
}()
tvc.format = format
if tvc.tv == nil {
return nil
}
return tvc.tv.Invalidate()
}
// Name returns the name of this TableViewColumn.
func (tvc *TableViewColumn) Name() string {
return tvc.name
}
// SetName sets the name of this TableViewColumn.
func (tvc *TableViewColumn) SetName(name string) {
tvc.name = name
}
// Precision returns the number of decimal places for formatting float32,
// float64 or big.Rat values.
func (tvc *TableViewColumn) Precision() int {
return tvc.precision
}
// SetPrecision sets the number of decimal places for formatting float32,
// float64 or big.Rat values.
func (tvc *TableViewColumn) SetPrecision(precision int) (err error) {
if precision == tvc.precision {
return nil
}
old := tvc.precision
defer func() {
if err != nil {
tvc.precision = old
}
}()
tvc.precision = precision
if tvc.tv == nil {
return nil
}
return tvc.tv.Invalidate()
}
// Title returns the (default) text to display in the column header.
func (tvc *TableViewColumn) Title() string {
return tvc.title
}
// SetTitle sets the (default) text to display in the column header.
func (tvc *TableViewColumn) SetTitle(title string) (err error) {
if title == tvc.title {
return nil
}
old := tvc.title
defer func() {
if err != nil {
tvc.title = old
}
}()
tvc.title = title
return tvc.update()
}
// TitleOverride returns the (overridden by user) text to display in the column
// header.
func (tvc *TableViewColumn) TitleOverride() string {
return tvc.titleOverride
}
// SetTitleOverride sets the (overridden by user) text to display in the column
// header.
func (tvc *TableViewColumn) SetTitleOverride(titleOverride string) (err error) {
if titleOverride == tvc.titleOverride {
return nil
}
old := tvc.titleOverride
defer func() {
if err != nil {
tvc.titleOverride = old
}
}()
tvc.titleOverride = titleOverride
return tvc.update()
}
// TitleEffective returns the effective text to display in the column header.
func (tvc *TableViewColumn) TitleEffective() string {
if tvc.titleOverride != "" {
return tvc.titleOverride
}
if tvc.title != "" {
return tvc.title
}
return tvc.DataMemberEffective()
}
// Visible returns if the column is visible.
func (tvc *TableViewColumn) Visible() bool {
return tvc.visible
}
// SetVisible sets if the column is visible.
func (tvc *TableViewColumn) SetVisible(visible bool) (err error) {
if visible == tvc.visible {
return nil
}
old := tvc.visible
defer func() {
if err != nil {
tvc.visible = old
}
}()
tvc.visible = visible
if tvc.tv == nil {
return nil
}
if visible {
return tvc.create()
}
return tvc.destroy()
}
// Frozen returns if the column is frozen.
func (tvc *TableViewColumn) Frozen() bool {
return tvc.frozen
}
// SetFrozen sets if the column is frozen.
func (tvc *TableViewColumn) SetFrozen(frozen bool) (err error) {
if frozen == tvc.frozen {
return nil
}
var checkBoxes bool
if tvc.tv != nil {
checkBoxes = tvc.tv.CheckBoxes()
}
old := tvc.frozen
defer func() {
if err != nil {
tvc.frozen = old
if tvc.tv != nil {
tvc.create()
}
}
if tvc.tv != nil {
tvc.tv.hasFrozenColumn = tvc.tv.visibleFrozenColumnCount() > 0
tvc.tv.SetCheckBoxes(checkBoxes)
tvc.tv.applyImageList()
}
}()
if tvc.tv != nil {
if err = tvc.destroy(); err != nil {
return
}
}
tvc.frozen = frozen
if tvc.tv != nil {
return tvc.create()
}
return nil
}
// Width returns the width of the column in pixels.
func (tvc *TableViewColumn) Width() int {
if tvc.tv == nil || !tvc.visible {
return tvc.width
}
// We call win.SendMessage instead of tvc.sendMessage here, because some
// call inside the latter interferes with scrolling via scroll bar button
// when *TableViewColumn.Width is called from *TableView.StretchLastColumn.
var hwnd win.HWND
if tvc.frozen {
hwnd = tvc.tv.hwndFrozenLV
} else {
hwnd = tvc.tv.hwndNormalLV
}
return tvc.tv.IntTo96DPI(int(win.SendMessage(hwnd, win.LVM_GETCOLUMNWIDTH, uintptr(tvc.indexInListView()), 0)))
}
// SetWidth sets the width of the column in pixels.
func (tvc *TableViewColumn) SetWidth(width int) (err error) {
if width == tvc.width {
return nil
}
old := tvc.width
defer func() {
if err != nil {
tvc.width = old
}
}()
tvc.width = width
return tvc.update()
}
// LessFunc returns the less func of this TableViewColumn.
//
// This function is used to provide custom sorting for models based on ReflectTableModel only.
func (tvc *TableViewColumn) LessFunc() func(i, j int) bool {
return tvc.lessFunc
}
// SetLessFunc sets the less func of this TableViewColumn.
//
// This function is used to provide custom sorting for models based on ReflectTableModel only.
func (tvc *TableViewColumn) SetLessFunc(lessFunc func(i, j int) bool) {
tvc.lessFunc = lessFunc
}
// FormatFunc returns the custom format func of this TableViewColumn.
func (tvc *TableViewColumn) FormatFunc() func(value interface{}) string {
return tvc.formatFunc
}
// FormatFunc sets the custom format func of this TableViewColumn.
func (tvc *TableViewColumn) SetFormatFunc(formatFunc func(value interface{}) string) {
tvc.formatFunc = formatFunc
}
func (tvc *TableViewColumn) indexInListView() int32 {
if tvc.tv == nil {
return -1
}
var idx int32
for _, c := range tvc.tv.columns.items {
if c.frozen != tvc.frozen {
continue
}
if c == tvc {
break
}
if c.visible {
idx++
}
}
return idx
}
func (tvc *TableViewColumn) create() error {
var lvc win.LVCOLUMN
index := tvc.indexInListView()
dpi := tvc.tv.DPI()
lvc.Mask = win.LVCF_FMT | win.LVCF_WIDTH | win.LVCF_TEXT | win.LVCF_SUBITEM
lvc.ISubItem = index
lvc.PszText = syscall.StringToUTF16Ptr(tvc.TitleEffective())
if tvc.width > 0 {
lvc.Cx = int32(IntFrom96DPI(tvc.width, dpi))
} else {
lvc.Cx = int32(IntFrom96DPI(100, dpi))
}
switch tvc.alignment {
case AlignCenter:
lvc.Fmt = 2
case AlignFar:
lvc.Fmt = 1
}
if -1 == int(tvc.sendMessage(win.LVM_INSERTCOLUMN, uintptr(index), uintptr(unsafe.Pointer(&lvc)))) {
return newError("LVM_INSERTCOLUMN")
}
tvc.tv.updateLVSizes()
return nil
}
func (tvc *TableViewColumn) destroy() error {
width := tvc.Width()
if win.FALSE == tvc.sendMessage(win.LVM_DELETECOLUMN, uintptr(tvc.indexInListView()), 0) {
return newError("LVM_DELETECOLUMN")
}
tvc.width = width
tvc.tv.updateLVSizes()
return nil
}
func (tvc *TableViewColumn) update() error {
if tvc.tv == nil || !tvc.visible {
return nil
}
lvc := tvc.getLVCOLUMN()
if win.FALSE == tvc.sendMessage(win.LVM_SETCOLUMN, uintptr(tvc.indexInListView()), uintptr(unsafe.Pointer(lvc))) {
return newError("LVM_SETCOLUMN")
}
tvc.tv.updateLVSizes()
return nil
}
func (tvc *TableViewColumn) getLVCOLUMN() *win.LVCOLUMN {
var lvc win.LVCOLUMN
dpi := 96
if tvc.tv != nil {
dpi = tvc.tv.DPI()
} else {
dpi = screenDPI()
}
width := IntFrom96DPI(tvc.width, dpi)
lvc.Mask = win.LVCF_FMT | win.LVCF_WIDTH | win.LVCF_TEXT | win.LVCF_SUBITEM
lvc.ISubItem = int32(tvc.indexInListView())
lvc.PszText = syscall.StringToUTF16Ptr(tvc.TitleEffective())
lvc.Cx = int32(width)
switch tvc.alignment {
case AlignCenter:
lvc.Fmt = 2
case AlignFar:
lvc.Fmt = 1
}
return &lvc
}
func (tvc *TableViewColumn) sendMessage(msg uint32, wp, lp uintptr) uintptr {
if tvc.tv == nil {
return 0
}
tvc.tv.hasFrozenColumn = tvc.tv.visibleFrozenColumnCount() > 0
tvc.tv.SetCheckBoxes(tvc.tv.CheckBoxes())
tvc.tv.applyImageList()
var hwnd win.HWND
if tvc.frozen {
hwnd = tvc.tv.hwndFrozenLV
} else {
hwnd = tvc.tv.hwndNormalLV
}
return win.SendMessage(hwnd, msg, wp, lp)
}