//
// Copyright (c) 2008, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 16 Jun 08 Brian Frank Creation
//
**
** Font models the rendering of text.
**
@Js
@Serializable { simple = true }
const class Font
{
//////////////////////////////////////////////////////////////////////////
// Construction
//////////////////////////////////////////////////////////////////////////
**
** Construct with it-block
**
new make(|This| f)
{
f(this)
}
**
** Construct a Font with family name, size in points, and optional
** bold/italic style. This is internal for now, because eventually
** we should be able to collapse this and it-block into single ctor.
**
@NoDoc new makeFields(Str name, Int size, Bool bold := false, Bool italic := false)
{
this.name = name
this.size = size
this.bold = bold
this.italic = italic
}
**
** Parse font from string (see `toStr`). If invalid
** and checked is true then throw ParseErr otherwise
** return null.
**
** Examples:
** Font.fromStr("12pt Arial")
** Font.fromStr("bold 10pt Courier")
** Font.fromStr("bold italic 8pt Times Roman")
**
static new fromStr(Str s, Bool checked := true)
{
try
{
Str? name := null
Int? size := null
bold := false
italic := false
toks := s.split
for (i:=0; i<toks.size; ++i)
{
tok := toks[i]
if (tok == "bold") bold = true;
else if (tok == "italic") italic = true
else if (size != null) name = name == null ? tok : "$name $tok"
else if (!tok.endsWith("pt")) throw Err()
else size = tok[0..-3].toInt
}
return makeFields(name, size.toInt, bold, italic)
}
catch {}
if (checked) throw ParseErr("Invalid Font: $s")
return null
}
//////////////////////////////////////////////////////////////////////////
// Font
//////////////////////////////////////////////////////////////////////////
**
** Name of font.
**
const Str name := "Serif"
**
** Size of font in points.
**
const Int size := 11
**
** Is this font bold.
**
const Bool bold
**
** Is this font in italic.
**
const Bool italic
//////////////////////////////////////////////////////////////////////////
// Identity
//////////////////////////////////////////////////////////////////////////
**
** Free any operating system resources used by this font.
** Dispose is required if this color has been used in an operation
** such as FWT onPaint which allocated a system resource to
** represent this instance.
**
Void dispose() { GfxEnv.cur(false)?.fontDispose(this) }
**
** Return hash of name, size, and style.
**
override Int hash()
{
hash := name.hash.xor(size)
if (bold) hash *= 73
if (italic) hash *= 19
return hash
}
**
** Equality is based on name, size, and style.
**
override Bool equals(Obj? that)
{
x := that as Font
if (x == null) return false
return name == x.name &&
size == x.size &&
bold == x.bold &&
italic == x.italic
}
**
** Format as '"[bold] [italic] <size>pt <name>"'
**
override Str toStr()
{
s := StrBuf()
if (bold) s.add("bold")
if (italic)
{
if (!s.isEmpty) s.add(" ")
s.add("italic")
}
if (!s.isEmpty) s.add(" ")
s.add(size).add("pt ").add(name)
return s.toStr
}
//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////
**
** Return this font, but with the specified point size.
** If thsi font already has the given size return this.
**
Font toSize(Int size)
{
if (this.size == size) return this
return Font.makeFields(name, size, bold, italic)
}
**
** Return this font, but with a plain styling (neither
** bold, nor italic). If this font is already plain
** then return this.
**
Font toPlain()
{
if (!bold && !italic) return this
return Font.makeFields(name, size, false, false)
}
**
** Return this font, but with a bold styling. If
** this font is already bold then return this.
**
Font toBold()
{
if (bold) return this
return Font.makeFields(name, size, true, italic)
}
**
** Return this font, but with a italic styling. If
** this font is already italic then return this.
**
Font toItalic()
{
if (italic) return this
return Font.makeFields(name, size, bold, true)
}
//////////////////////////////////////////////////////////////////////////
// Metrics
//////////////////////////////////////////////////////////////////////////
**
** Get height of this font which is the pixels is the sum of
** ascent, descent, and leading.
**
Int height() { GfxEnv.cur.fontHeight(this) }
**
** Get ascent of this font which is the distance in pixels from
** baseline to top of chars, not including any leading area.
**
Int ascent() { GfxEnv.cur.fontAscent(this) }
**
** Get descent of this font which is the distance in pixels from
** baseline to bottom of chars, not including any leading area.
**
Int descent() { GfxEnv.cur.fontDescent(this) }
**
** Get leading of this font which is the distance in pixels above
** the ascent which may include accents and other marks.
**
Int leading() { GfxEnv.cur.fontLeading(this) }
**
** Get the width of the string in pixels when painted
** with this font.
**
Int width(Str s) { GfxEnv.cur.fontWidth(this, s) }
}