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

601 lines
11 KiB
Go

// 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 (
"bytes"
"math"
"math/big"
"strconv"
"strings"
"syscall"
"time"
"github.com/lxn/win"
)
var (
decimalSepB byte
decimalSepUint16 uint16
decimalSepS string
groupSepB byte
groupSepUint16 uint16
groupSepS string
)
func init() {
AppendToWalkInit(func() {
var buf [4]uint16
win.GetLocaleInfo(win.LOCALE_USER_DEFAULT, win.LOCALE_SDECIMAL, &buf[0], int32(len(buf)))
decimalSepB = byte(buf[0])
decimalSepS = syscall.UTF16ToString(buf[0:1])
decimalSepUint16 = buf[0]
win.GetLocaleInfo(win.LOCALE_USER_DEFAULT, win.LOCALE_STHOUSAND, &buf[0], int32(len(buf)))
groupSepB = byte(buf[0])
groupSepS = syscall.UTF16ToString(buf[0:1])
groupSepUint16 = buf[0]
})
}
func maxi(a, b int) int {
if a > b {
return a
}
return b
}
func mini(a, b int) int {
if a < b {
return a
}
return b
}
func boolToInt(value bool) int {
if value {
return 1
}
return 0
}
func uint16IndexUint16(s []uint16, v uint16) int {
for i, u := range s {
if u == v {
return i
}
}
return -1
}
func uint16ContainsUint16(s []uint16, v uint16) bool {
return uint16IndexUint16(s, v) != -1
}
func uint16CountUint16(s []uint16, v uint16) int {
var count int
for _, u := range s {
if u == v {
count++
}
}
return count
}
func uint16RemoveUint16(s []uint16, v uint16) []uint16 {
count := uint16CountUint16(s, v)
if count == 0 {
return s
}
ret := make([]uint16, 0, len(s)-count)
for _, u := range s {
if u != v {
ret = append(ret, u)
}
}
return ret
}
func assertFloat64Or(value interface{}, defaultValue float64) float64 {
if f, ok := value.(float64); ok {
return f
}
return defaultValue
}
func assertIntOr(value interface{}, defaultValue int) int {
if n, ok := value.(int); ok {
return n
}
return defaultValue
}
func assertStringOr(value interface{}, defaultValue string) string {
if s, ok := value.(string); ok {
return s
}
return defaultValue
}
func assertTimeOr(value interface{}, defaultValue time.Time) time.Time {
if t, ok := value.(time.Time); ok {
return t
}
return defaultValue
}
func ParseFloat(s string) (float64, error) {
s = strings.TrimSpace(s)
t := FormatFloatGrouped(1000, 2)
replaceSep := func(new string, index func(string, func(rune) bool) int) {
i := index(t, func(r rune) bool {
return r < '0' || r > '9'
})
var sep string
if i > -1 {
sep = string(t[i])
}
if sep != "" {
s = strings.Replace(s, string(sep), new, -1)
}
}
replaceSep("", strings.IndexFunc)
replaceSep(".", strings.LastIndexFunc)
return strconv.ParseFloat(s, 64)
}
func FormatFloat(f float64, prec int) string {
return formatFloatString(strconv.FormatFloat(f, 'f', prec, 64), prec, false)
}
func FormatFloatGrouped(f float64, prec int) string {
return formatFloatString(strconv.FormatFloat(f, 'f', maxi(1, prec), 64), prec, true)
}
func formatBigRat(r *big.Rat, prec int) string {
return formatFloatString(r.FloatString(prec), prec, false)
}
func formatBigRatGrouped(r *big.Rat, prec int) string {
return formatFloatString(r.FloatString(prec), prec, true)
}
func formatFloatString(s string, prec int, grouped bool) string {
switch s {
case "NaN", "-Inf", "+Inf":
return s
}
s = strings.Replace(s, ".", decimalSepS, 1)
if !grouped {
return s
}
b := new(bytes.Buffer)
var firstDigit int
if len(s) > 0 && s[0] == '-' {
firstDigit = 1
b.WriteByte('-')
s = s[1:]
}
intLen := len(s) - maxi(1, prec) - 1
n := intLen % 3
if n != 0 {
b.WriteString(s[:n])
}
for i := n; i < intLen; i += 3 {
if b.Len() > firstDigit {
b.WriteByte(groupSepB)
}
b.WriteString(s[i : i+3])
}
b.WriteString(s[intLen:])
s = b.String()
if prec == 0 {
s = s[:len(s)-2]
}
return s
}
func applyEnabledToDescendants(window Window, enabled bool) {
wb := window.AsWindowBase()
wb.applyEnabled(enabled)
walkDescendants(window, func(w Window) bool {
if w.Handle() == wb.hWnd {
return true
}
if enabled && !w.AsWindowBase().enabled {
return false
}
w.(applyEnableder).applyEnabled(enabled)
return true
})
}
var seenInApplyFontToDescendantsDuringDPIChange map[*WindowBase]bool
func applyFontToDescendants(window Window, font *Font) {
wb := window.AsWindowBase()
wb.applyFont(font)
walkDescendants(window, func(w Window) bool {
if w.Handle() == wb.hWnd {
return true
}
if w.AsWindowBase().font != nil {
return false
}
if seenInApplyFontToDescendantsDuringDPIChange != nil {
wb := w.AsWindowBase()
if seenInApplyFontToDescendantsDuringDPIChange[wb] {
return true
}
seenInApplyFontToDescendantsDuringDPIChange[wb] = true
}
w.(applyFonter).applyFont(font)
return true
})
}
func applySysColorsToDescendants(window Window) {
wb := window.AsWindowBase()
wb.ApplySysColors()
walkDescendants(window, func(w Window) bool {
if w.Handle() == wb.hWnd {
return true
}
w.(ApplySysColorser).ApplySysColors()
return true
})
}
var seenInApplyDPIToDescendantsDuringDPIChange map[*WindowBase]bool
func applyDPIToDescendants(window Window, dpi int) {
wb := window.AsWindowBase()
wb.ApplyDPI(dpi)
walkDescendants(window, func(w Window) bool {
if w.Handle() == wb.hWnd {
return true
}
if seenInApplyDPIToDescendantsDuringDPIChange != nil {
wb := w.AsWindowBase()
if seenInApplyDPIToDescendantsDuringDPIChange[wb] {
return true
}
seenInApplyDPIToDescendantsDuringDPIChange[wb] = true
}
w.(ApplyDPIer).ApplyDPI(dpi)
return true
})
}
func walkDescendants(window Window, f func(w Window) bool) {
window = window.AsWindowBase().window
if window == nil || !f(window) {
return
}
var children []*WidgetBase
switch w := window.(type) {
case *NumberEdit:
if w.edit != nil {
children = append(children, w.edit.AsWidgetBase())
}
case *TabWidget:
for _, p := range w.Pages().items {
children = append(children, p.AsWidgetBase())
}
case Container:
if c := w.Children(); c != nil {
children = c.items
} else {
children = nil
}
}
for _, wb := range children {
walkDescendants(wb.window.(Widget), f)
}
}
func less(a, b interface{}, order SortOrder) bool {
if _, ok := a.(error); ok {
_, bIsErr := b.(error)
return order == SortAscending == !bIsErr
}
if _, ok := b.(error); ok {
return order == SortDescending
}
if a == nil {
return order == SortAscending == (b != nil)
}
if b == nil {
return order == SortDescending
}
switch av := a.(type) {
case string:
if bv, ok := b.(string); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case int:
if bv, ok := b.(int); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case float64:
if bv, ok := b.(float64); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case float32:
if bv, ok := b.(float32); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case int64:
if bv, ok := b.(int64); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case int32:
if bv, ok := b.(int32); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case int16:
if bv, ok := b.(int16); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case int8:
if bv, ok := b.(int8); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case uint:
if bv, ok := b.(uint); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case uint64:
if bv, ok := b.(uint64); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case uint32:
if bv, ok := b.(uint32); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case uint16:
if bv, ok := b.(uint16); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case uint8:
if bv, ok := b.(uint8); ok {
if order == SortAscending {
return av < bv
} else {
return bv < av
}
}
case time.Time:
if bv, ok := b.(time.Time); ok {
if order == SortAscending {
return av.Before(bv)
} else {
return bv.Before(av)
}
}
case bool:
if bv, ok := b.(bool); ok {
if order == SortAscending {
return !av && bv
} else {
return !bv && av
}
}
}
return false
}
func dpiForHDC(hdc win.HDC) int {
if hwnd := win.WindowFromDC(hdc); hwnd != 0 {
return int(win.GetDpiForWindow(hwnd))
}
return int(win.GetDeviceCaps(hdc, win.LOGPIXELSX))
}
// IntFrom96DPI converts from 1/96" units to native pixels.
func IntFrom96DPI(value, dpi int) int {
return scaleInt(value, float64(dpi)/96.0)
}
// IntTo96DPI converts from native pixels to 1/96" units.
func IntTo96DPI(value, dpi int) int {
return scaleInt(value, 96.0/float64(dpi))
}
func scaleInt(value int, scale float64) int {
return int(math.Round(float64(value) * scale))
}
// MarginsFrom96DPI converts from 1/96" units to native pixels.
func MarginsFrom96DPI(value Margins, dpi int) Margins {
return scaleMargins(value, float64(dpi)/96.0)
}
// MarginsTo96DPI converts from native pixels to 1/96" units.
func MarginsTo96DPI(value Margins, dpi int) Margins {
return scaleMargins(value, 96.0/float64(dpi))
}
func scaleMargins(value Margins, scale float64) Margins {
return Margins{
HNear: scaleInt(value.HNear, scale),
VNear: scaleInt(value.VNear, scale),
HFar: scaleInt(value.HFar, scale),
VFar: scaleInt(value.VFar, scale),
}
}
// PointFrom96DPI converts from 1/96" units to native pixels.
func PointFrom96DPI(value Point, dpi int) Point {
return scalePoint(value, float64(dpi)/96.0)
}
// PointTo96DPI converts from native pixels to 1/96" units.
func PointTo96DPI(value Point, dpi int) Point {
return scalePoint(value, 96.0/float64(dpi))
}
func scalePoint(value Point, scale float64) Point {
return Point{
X: scaleInt(value.X, scale),
Y: scaleInt(value.Y, scale),
}
}
// RectangleFrom96DPI converts from 1/96" units to native pixels.
func RectangleFrom96DPI(value Rectangle, dpi int) Rectangle {
return scaleRectangle(value, float64(dpi)/96.0)
}
// RectangleTo96DPI converts from native pixels to 1/96" units.
func RectangleTo96DPI(value Rectangle, dpi int) Rectangle {
return scaleRectangle(value, 96.0/float64(dpi))
}
func scaleRectangle(value Rectangle, scale float64) Rectangle {
return Rectangle{
X: scaleInt(value.X, scale),
Y: scaleInt(value.Y, scale),
Width: scaleInt(value.Width, scale),
Height: scaleInt(value.Height, scale),
}
}
// SizeFrom96DPI converts from 1/96" units to native pixels.
func SizeFrom96DPI(value Size, dpi int) Size {
return scaleSize(value, float64(dpi)/96.0)
}
// SizeTo96DPI converts from native pixels to 1/96" units.
func SizeTo96DPI(value Size, dpi int) Size {
return scaleSize(value, 96.0/float64(dpi))
}
func scaleSize(value Size, scale float64) Size {
return Size{
Width: scaleInt(value.Width, scale),
Height: scaleInt(value.Height, scale),
}
}