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

223 lines
4.6 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 (
"syscall"
)
import (
"github.com/lxn/win"
)
type FontStyle byte
// Font style flags
const (
FontBold FontStyle = 0x01
FontItalic FontStyle = 0x02
FontUnderline FontStyle = 0x04
FontStrikeOut FontStyle = 0x08
)
var (
defaultFont *Font
knownFonts = make(map[fontInfo]*Font)
)
func init() {
AppendToWalkInit(func() {
// Initialize default font
var err error
if defaultFont, err = NewFont("MS Shell Dlg 2", 8, 0); err != nil {
panic("failed to create default font")
}
})
}
type fontInfo struct {
family string
pointSize int
style FontStyle
}
// Font represents a typographic typeface that is used for text drawing
// operations and on many GUI widgets.
type Font struct {
dpi2hFont map[int]win.HFONT
family string
pointSize int
style FontStyle
}
// NewFont returns a new Font with the specified attributes.
func NewFont(family string, pointSize int, style FontStyle) (*Font, error) {
if style > FontBold|FontItalic|FontUnderline|FontStrikeOut {
return nil, newError("invalid style")
}
fi := fontInfo{
family: family,
pointSize: pointSize,
style: style,
}
if font, ok := knownFonts[fi]; ok {
return font, nil
}
font := &Font{
family: family,
pointSize: pointSize,
style: style,
}
knownFonts[fi] = font
return font, nil
}
func newFontFromLOGFONT(lf *win.LOGFONT, dpi int) (*Font, error) {
if lf == nil {
return nil, newError("lf cannot be nil")
}
family := win.UTF16PtrToString(&lf.LfFaceName[0])
pointSize := int(win.MulDiv(lf.LfHeight, 72, int32(dpi)))
if pointSize < 0 {
pointSize = -pointSize
}
var style FontStyle
if lf.LfWeight > win.FW_NORMAL {
style |= FontBold
}
if lf.LfItalic == win.TRUE {
style |= FontItalic
}
if lf.LfUnderline == win.TRUE {
style |= FontUnderline
}
if lf.LfStrikeOut == win.TRUE {
style |= FontStrikeOut
}
return NewFont(family, pointSize, style)
}
func (f *Font) createForDPI(dpi int) (win.HFONT, error) {
var lf win.LOGFONT
lf.LfHeight = -win.MulDiv(int32(f.pointSize), int32(dpi), 72)
if f.style&FontBold > 0 {
lf.LfWeight = win.FW_BOLD
} else {
lf.LfWeight = win.FW_NORMAL
}
if f.style&FontItalic > 0 {
lf.LfItalic = 1
}
if f.style&FontUnderline > 0 {
lf.LfUnderline = 1
}
if f.style&FontStrikeOut > 0 {
lf.LfStrikeOut = 1
}
lf.LfCharSet = win.DEFAULT_CHARSET
lf.LfOutPrecision = win.OUT_TT_PRECIS
lf.LfClipPrecision = win.CLIP_DEFAULT_PRECIS
lf.LfQuality = win.CLEARTYPE_QUALITY
lf.LfPitchAndFamily = win.VARIABLE_PITCH | win.FF_SWISS
src := syscall.StringToUTF16(f.family)
dest := lf.LfFaceName[:]
copy(dest, src)
hFont := win.CreateFontIndirect(&lf)
if hFont == 0 {
return 0, newError("CreateFontIndirect failed")
}
return hFont, nil
}
// Bold returns if text drawn using the Font appears with
// greater weight than normal.
func (f *Font) Bold() bool {
return f.style&FontBold > 0
}
// Dispose releases the os resources that were allocated for the Font.
//
// The Font can no longer be used for drawing operations or with GUI widgets
// after calling this method. It is safe to call Dispose multiple times.
func (f *Font) Dispose() {
if len(f.dpi2hFont) == 0 {
return
}
for dpi, hFont := range f.dpi2hFont {
win.DeleteObject(win.HGDIOBJ(hFont))
delete(f.dpi2hFont, dpi)
}
}
// Family returns the family name of the Font.
func (f *Font) Family() string {
return f.family
}
// Italic returns if text drawn using the Font appears slanted.
func (f *Font) Italic() bool {
return f.style&FontItalic > 0
}
// HandleForDPI returns the os resource handle of the font for the specified
// DPI value.
func (f *Font) handleForDPI(dpi int) win.HFONT {
if f.dpi2hFont == nil {
f.dpi2hFont = make(map[int]win.HFONT)
} else if handle, ok := f.dpi2hFont[dpi]; ok {
return handle
}
hFont, err := f.createForDPI(dpi)
if err != nil {
return 0
}
f.dpi2hFont[dpi] = hFont
return hFont
}
// StrikeOut returns if text drawn using the Font appears striked out.
func (f *Font) StrikeOut() bool {
return f.style&FontStrikeOut > 0
}
// Style returns the combination of style flags of the Font.
func (f *Font) Style() FontStyle {
return f.style
}
// Underline returns if text drawn using the font appears underlined.
func (f *Font) Underline() bool {
return f.style&FontUnderline > 0
}
// PointSize returns the size of the Font in point units.
func (f *Font) PointSize() int {
return f.pointSize
}
func screenDPI() int {
hDC := win.GetDC(0)
defer win.ReleaseDC(0, hDC)
return int(win.GetDeviceCaps(hDC, win.LOGPIXELSY))
}