223 lines
4.6 KiB
Go
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))
|
||
|
}
|