diff --git a/artist/patterns/uniform.go b/artist/patterns/uniform.go index 0aedbca..c31aad4 100644 --- a/artist/patterns/uniform.go +++ b/artist/patterns/uniform.go @@ -12,3 +12,16 @@ type Uniform color.RGBA func (pattern Uniform) Draw (destination canvas.Canvas, clip image.Rectangle) { shapes.FillColorRectangle(destination, color.RGBA(pattern), clip) } + +// Uhex creates a new Uniform pattern from an RGBA integer value. +func Uhex (color uint32) (uniform Uniform) { + return Uniform(hex(color)) +} + +func hex (color uint32) (c color.RGBA) { + c.A = uint8(color) + c.B = uint8(color >> 8) + c.G = uint8(color >> 16) + c.R = uint8(color >> 24) + return +} diff --git a/config/config.go b/config/config.go index 2937e0c..a7e2a66 100644 --- a/config/config.go +++ b/config/config.go @@ -2,15 +2,6 @@ package config // Config can return global configuration parameters. type Config interface { - // Padding returns the amount of internal padding elements should have. - // An element's inner content (such as text) should be inset by this - // amount, in addition to the inset returned by the pattern of its - // background. - Padding () int - - // Margin returns how much space should be put in between elements. - Margin () int - // HandleWidth returns how large grab handles should typically be. This // is important for accessibility reasons. HandleWidth () int @@ -26,15 +17,6 @@ type Config interface { // Default specifies default configuration values. type Default struct { } -// Padding returns the default padding value. -func (Default) Padding () int { - return 7 -} - -// Margin returns the default margin value. -func (Default) Margin () int { - return 8 -} // HandleWidth returns the default handle width value. func (Default) HandleWidth () int { @@ -56,19 +38,6 @@ type Wrapped struct { Config } -// Padding returns the amount of internal padding elements should have. -// An element's inner content (such as text) should be inset by this -// amount, in addition to the inset returned by the pattern of its -// background. -func (wrapped Wrapped) Padding () int { - return wrapped.ensure().Padding() -} - -// Margin returns how much space should be put in between elements. -func (wrapped Wrapped) Margin () int { - return wrapped.ensure().Margin() -} - // HandleWidth returns how large grab handles should typically be. This // is important for accessibility reasons. func (wrapped Wrapped) HandleWidth () int { diff --git a/theme/default.go b/theme/default.go index e211037..4cdebcb 100644 --- a/theme/default.go +++ b/theme/default.go @@ -5,6 +5,7 @@ import "golang.org/x/image/font" import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/canvas" import "git.tebibyte.media/sashakoshka/tomo/defaultfont" +import "git.tebibyte.media/sashakoshka/tomo/artist/patterns" // Default is the default theme. type Default struct { } @@ -38,204 +39,37 @@ func (Default) Pattern ( ) artist.Pattern { switch pattern { case PatternAccent: - return accentPattern + return patterns.Uhex(0xFF8800FF) case PatternBackground: - return backgroundPattern + return patterns.Uhex(0x000000FF) case PatternForeground: - if state.Disabled || c == C("basic", "spacer") { - return weakForegroundPattern - } else { - return foregroundPattern - } - case PatternDead: - return deadPattern - case PatternRaised: - if c == C("basic", "listEntry") { - if state.Focused { - if state.On { - return focusedOnListEntryPattern - } else { - return focusedListEntryPattern - } - } else { - if state.On { - return onListEntryPattern - } else { - return listEntryPattern - } - } - } else { - if state.Focused { - return selectedRaisedPattern - } else { - return raisedPattern - } - } - case PatternSunken: - if c == C("basic", "list") { - if state.Focused { - return focusedListPattern - } else { - return listPattern - } - } else if c == C("basic", "textBox") { - if state.Disabled { - return disabledInputPattern - } else { - if state.Focused { - return selectedInputPattern - } else { - return inputPattern - } - } - } else { - if state.Focused { - return focusedSunkenPattern - } else { - return sunkenPattern - } - } - case PatternPinboard: - if state.Focused { - return focusedTexturedSunkenPattern - } else { - return texturedSunkenPattern - } - case PatternButton: - if state.Disabled { - return disabledButtonPattern - } else { - if c == C("fun", "sharpKey") { - if state.Pressed { - return pressedDarkButtonPattern - } else { - return darkButtonPattern - } - } else if c == C("fun", "flatKey") { - if state.Pressed { - return pressedButtonPattern - } else { - return buttonPattern - } - } else { - if state.Pressed || state.On && c == C("basic", "checkbox") { - if state.Focused { - return pressedSelectedButtonPattern - } else { - return pressedButtonPattern - } - } else { - if state.Focused { - return selectedButtonPattern - } else { - return buttonPattern - } - } - } - } - case PatternInput: - if state.Disabled { - return disabledInputPattern - } else { - if state.Focused { - return selectedInputPattern - } else { - return inputPattern - } - } - case PatternGutter: - if c == C("basic", "sliderVertical") || c == C("basic", "sliderHorizontal") { - if state.Disabled { - return disabledThinScrollGutterPattern - } else { - return thinScrollGutterPattern - } - } else { - if state.Disabled { - return disabledScrollGutterPattern - } else { - return scrollGutterPattern - } - } - case PatternHandle: - if state.Disabled { - return disabledScrollBarPattern - } else { - if state.Focused { - if state.Pressed { - return pressedSelectedScrollBarPattern - } else { - return selectedScrollBarPattern - } - } else { - if state.Pressed { - return pressedScrollBarPattern - } else { - return scrollBarPattern - } - } - } - default: - return uhex(0) + return patterns.Uhex(0xFFFFFFFF) + // case PatternDead: + // case PatternRaised: + // case PatternSunken: + // case PatternPinboard: + // case PatternButton: + // case PatternInput: + // case PatternGutter: + // case PatternHandle: + default: return patterns.Uhex(0x888888FF) } } -// Inset returns the default inset value for the given pattern. -func (Default) Inset (pattern Pattern, c Case) Inset { - switch pattern { - case PatternRaised: - if c == C("basic", "listEntry") { - return Inset { 4, 6, 4, 6 } - } else { - return Inset { 2, 2, 2, 2 } - } - - case PatternSunken: - if c == C("basic", "list") { - return Inset { 2, 1, 2, 1 } - } else if c == C("basic", "progressBar") { - return Inset { 2, 1, 1, 2 } - } else { - return Inset { 2, 2, 2, 2 } - } +// Padding returns the default padding value for the given pattern. +func (Default) Padding (pattern Pattern, c Case) artist.Inset { + return artist.Inset { 4, 4, 4, 4} +} - case PatternPinboard: - return Inset { 2, 2, 2, 2 } - - case PatternInput, PatternButton, PatternHandle: - return Inset { 2, 2, 2, 2} - - default: return Inset { } - } +// Margin returns the default margin value for the given pattern. +func (Default) Margin (id Pattern, c Case) image.Point { + return image.Pt(4, 4) } // Hints returns rendering optimization hints for a particular pattern. // These are optional, but following them may result in improved // performance. func (Default) Hints (pattern Pattern, c Case) (hints Hints) { - switch pattern { - case PatternRaised: - if c == C("basic", "listEntry") { - hints.StaticInset = Inset { 0, 1, 0, 1 } - } else { - hints.StaticInset = Inset { 3, 3, 3, 3 } - } - - case PatternSunken: - if c == C("basic", "list") { - hints.StaticInset = Inset { 2, 1, 2, 1 } - } else { - hints.StaticInset = Inset { 3, 3, 3, 3 } - } - - case - PatternPinboard, - PatternInput, - PatternButton, - PatternHandle: - - hints.StaticInset = Inset { 3, 3, 3, 3 } - } return } diff --git a/theme/defaultpatterns.go b/theme/defaultpatterns.go index 82afd47..2ec48b5 100644 --- a/theme/defaultpatterns.go +++ b/theme/defaultpatterns.go @@ -1,272 +1,4 @@ package theme -import "image/color" -import "git.tebibyte.media/sashakoshka/tomo/artist" - -// var backgroundPattern = artist.Gradient { - // First: uhex(0xFF0000FF), - // Second: uhex(0x00FF00FF), -// } -var accentPattern = artist.NewUniform(hex(0x408090FF)) -var backgroundPattern = artist.NewUniform(color.Gray16 { 0xAAAA }) -var foregroundPattern = artist.NewUniform(color.Gray16 { 0x0000 }) -var weakForegroundPattern = artist.NewUniform(color.Gray16 { 0x4444 }) -var strokePattern = artist.NewUniform(color.Gray16 { 0x0000 }) - -var sunkenPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0x3b534eFF)), - artist.NewUniform(hex(0x97a09cFF)), - }, - }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x97a09cFF)) }) -var focusedSunkenPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { Weight: 1, Pattern: accentPattern }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x97a09cFF)) }) - -var texturedSunkenPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0x3b534eFF)), - artist.NewUniform(hex(0x97a09cFF)), - }, - }, - - artist.Stroke { Pattern: artist.Noisy { - Low: artist.NewUniform(hex(0x97a09cFF)), - High: artist.NewUniform(hex(0x6e8079FF)), - }}) -var focusedTexturedSunkenPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { Weight: 1, Pattern: accentPattern }, - artist.Stroke { Pattern: artist.Noisy { - Low: artist.NewUniform(hex(0x97a09cFF)), - High: artist.NewUniform(hex(0x6e8079FF)), - }}) - -var raisedPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0xDBDBDBFF)), - artist.NewUniform(hex(0x383C3AFF)), - }, - }, - artist.Stroke { Pattern: artist.NewUniform(hex(0xAAAAAAFF)) }) - -var selectedRaisedPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0xDBDBDBFF)), - artist.NewUniform(hex(0x383C3AFF)), - }, - }, - artist.Stroke { Weight: 1, Pattern: accentPattern }, - artist.Stroke { Pattern: artist.NewUniform(hex(0xAAAAAAFF)) }) - -var deadPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x97a09cFF)) }) - -var buttonPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0xCCD5D2FF)), - artist.NewUniform(hex(0x4B5B59FF)), - }, - }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x8D9894FF)) }) -var selectedButtonPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0xCCD5D2FF)), - artist.NewUniform(hex(0x4B5B59FF)), - }, - }, - artist.Stroke { Weight: 1, Pattern: accentPattern }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x8D9894FF)) }) -var pressedButtonPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0x4B5B59FF)), - artist.NewUniform(hex(0x8D9894FF)), - }, - }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x8D9894FF)) }) -var pressedSelectedButtonPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0x4B5B59FF)), - artist.NewUniform(hex(0x8D9894FF)), - }, - }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x8D9894FF)) }) -var disabledButtonPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: weakForegroundPattern }, - artist.Stroke { Pattern: backgroundPattern }) - -var darkButtonPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0xaebdb9FF)), - artist.NewUniform(hex(0x3b4947FF)), - }, - }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x6b7a75FF)) }) -var pressedDarkButtonPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0x3b4947FF)), - artist.NewUniform(hex(0x6b7a75FF)), - }, - }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x6b7a75FF)) }) - -var inputPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0x89925AFF)), - artist.NewUniform(hex(0xD2CB9AFF)), - }, - }, - artist.Stroke { Pattern: artist.NewUniform(hex(0xD2CB9AFF)) }) -var selectedInputPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { Weight: 1, Pattern: accentPattern }, - artist.Stroke { Pattern: artist.NewUniform(hex(0xD2CB9AFF)) }) -var disabledInputPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: weakForegroundPattern }, - artist.Stroke { Pattern: backgroundPattern }) - -var listPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - uhex(0x383C3AFF), - uhex(0x999C99FF), - }, - }, - artist.Stroke { Pattern: uhex(0x999C99FF) }) - -var focusedListPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { Weight: 1, Pattern: accentPattern }, - artist.Stroke { Pattern: uhex(0x999C99FF) }) - -var listEntryPattern = artist.Padded { - Stroke: uhex(0x383C3AFF), - Fill: uhex(0x999C99FF), - Sides: []int { 0, 0, 0, 1 }, -} - -var onListEntryPattern = artist.Padded { - Stroke: uhex(0x383C3AFF), - Fill: uhex(0x6e8079FF), - Sides: []int { 0, 0, 0, 1 }, -} - -var focusedListEntryPattern = artist.Padded { - Stroke: accentPattern, - Fill: uhex(0x999C99FF), - Sides: []int { 0, 1, 0, 1 }, -} - -var focusedOnListEntryPattern = artist.Padded { - Stroke: accentPattern, - Fill: uhex(0x6e8079FF), - Sides: []int { 0, 1, 0, 1 }, -} - -var scrollGutterPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0x3b534eFF)), - artist.NewUniform(hex(0x6e8079FF)), - }, - }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x6e8079FF)) }) -var thinScrollGutterPattern = artist.Padded { - Fill: scrollGutterPattern, - Stroke: sunkenPattern, - Sides: []int{ 6, 6, 6, 6 }, -} -var disabledScrollGutterPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: weakForegroundPattern }, - artist.Stroke { Pattern: backgroundPattern }) -var disabledThinScrollGutterPattern = artist.Padded { - Fill: disabledScrollGutterPattern, - Stroke: disabledButtonPattern, - Sides: []int{ 6, 6, 6, 6}, -} -var scrollBarPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0xCCD5D2FF)), - artist.NewUniform(hex(0x4B5B59FF)), - }, - }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x8D9894FF)) }) -var selectedScrollBarPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0xCCD5D2FF)), - artist.NewUniform(hex(0x4B5B59FF)), - }, - }, - artist.Stroke { Weight: 1, Pattern: accentPattern }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x8D9894FF)) }) -var pressedScrollBarPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0xCCD5D2FF)), - artist.NewUniform(hex(0x4B5B59FF)), - }, - }, - artist.Stroke { Weight: 1, Pattern: artist.NewUniform(hex(0x8D9894FF)) }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x7f8c89FF)) }) -var pressedSelectedScrollBarPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: strokePattern }, - artist.Stroke { - Weight: 1, - Pattern: artist.Beveled { - artist.NewUniform(hex(0xCCD5D2FF)), - artist.NewUniform(hex(0x4B5B59FF)), - }, - }, - artist.Stroke { Weight: 1, Pattern: accentPattern }, - artist.Stroke { Pattern: artist.NewUniform(hex(0x7f8c89FF)) }) -var disabledScrollBarPattern = artist.NewMultiBordered ( - artist.Stroke { Weight: 1, Pattern: weakForegroundPattern }, - artist.Stroke { Pattern: backgroundPattern }) +// import "image/color" +// import "git.tebibyte.media/sashakoshka/tomo/artist" diff --git a/theme/theme.go b/theme/theme.go index e88e028..f506035 100644 --- a/theme/theme.go +++ b/theme/theme.go @@ -63,7 +63,7 @@ type Hints struct { // StaticInset defines an inset rectangular area in the middle of the // pattern that does not change between PatternStates. If the inset is // zero on all sides, this hint does not apply. - StaticInset Inset + StaticInset artist.Inset // Uniform specifies a singular color for the entire pattern. If the // alpha channel is zero, this hint does not apply. @@ -82,9 +82,14 @@ type Theme interface { // and state. Pattern (Pattern, PatternState, Case) artist.Pattern - // Inset returns the area on all sides of a given pattern that is not - // meant to be drawn on. - Inset (Pattern, Case) Inset + // Padding returns how much space should be between the bounds of a + // pattern whatever an element draws inside of it. + Padding (Pattern, Case) artist.Inset + + // Margin returns the left/right (x) and top/bottom (y) margins that + // should be put between any self-contained objects drawn within this + // pattern (if applicable). + Margin (Pattern, Case) image.Point // Sink returns a vector that should be added to an element's inner // content when it is pressed down (if applicable) to simulate a 3D @@ -96,57 +101,3 @@ type Theme interface { // performance. Hints (Pattern, Case) Hints } - -// Wrapped wraps any theme and injects a case into it automatically so that it -// doesn't need to be specified for each query. Additionally, if the underlying -// theme is nil, it just uses the default theme instead. -type Wrapped struct { - Theme - Case -} - -// FontFace returns the proper font for a given style and size. -func (wrapped Wrapped) FontFace (style FontStyle, size FontSize) font.Face { - real := wrapped.ensure() - return real.FontFace(style, size, wrapped.Case) -} - -// Icon returns an appropriate icon given an icon name. -func (wrapped Wrapped) Icon (name string, size IconSize) canvas.Image { - real := wrapped.ensure() - return real.Icon(name, size, wrapped.Case) -} - -// Pattern returns an appropriate pattern given a pattern name and state. -func (wrapped Wrapped) Pattern (id Pattern, state PatternState) artist.Pattern { - real := wrapped.ensure() - return real.Pattern(id, state, wrapped.Case) -} - -// Inset returns the area on all sides of a given pattern that is not meant to -// be drawn on. -func (wrapped Wrapped) Inset (id Pattern) Inset { - real := wrapped.ensure() - return real.Inset(id, wrapped.Case) -} - -// Sink returns a vector that should be added to an element's inner content when -// it is pressed down (if applicable) to simulate a 3D sinking effect. -func (wrapped Wrapped) Sink (id Pattern) image.Point { - real := wrapped.ensure() - return real.Sink(id, wrapped.Case) -} - -// Hints returns rendering optimization hints for a particular pattern. -// These are optional, but following them may result in improved -// performance. -func (wrapped Wrapped) Hints (id Pattern) Hints { - real := wrapped.ensure() - return real.Hints(id, wrapped.Case) -} - -func (wrapped Wrapped) ensure () (real Theme) { - real = wrapped.Theme - if real == nil { real = Default { } } - return -} diff --git a/theme/util.go b/theme/util.go deleted file mode 100644 index 2e9723e..0000000 --- a/theme/util.go +++ /dev/null @@ -1,16 +0,0 @@ -package theme - -import "image/color" -import "git.tebibyte.media/sashakoshka/tomo/artist" - -func hex (color uint32) (c color.RGBA) { - c.A = uint8(color) - c.B = uint8(color >> 8) - c.G = uint8(color >> 16) - c.R = uint8(color >> 24) - return -} - -func uhex (color uint32) (pattern artist.Pattern) { - return artist.NewUniform(hex(color)) -} diff --git a/theme/wrapped.go b/theme/wrapped.go new file mode 100644 index 0000000..947481b --- /dev/null +++ b/theme/wrapped.go @@ -0,0 +1,68 @@ +package theme + +import "image" +import "golang.org/x/image/font" +import "git.tebibyte.media/sashakoshka/tomo/artist" +import "git.tebibyte.media/sashakoshka/tomo/canvas" + +// Wrapped wraps any theme and injects a case into it automatically so that it +// doesn't need to be specified for each query. Additionally, if the underlying +// theme is nil, it just uses the default theme instead. +type Wrapped struct { + Theme + Case +} + +// FontFace returns the proper font for a given style and size. +func (wrapped Wrapped) FontFace (style FontStyle, size FontSize) font.Face { + real := wrapped.ensure() + return real.FontFace(style, size, wrapped.Case) +} + +// Icon returns an appropriate icon given an icon name. +func (wrapped Wrapped) Icon (name string, size IconSize) canvas.Image { + real := wrapped.ensure() + return real.Icon(name, size, wrapped.Case) +} + +// Pattern returns an appropriate pattern given a pattern name and state. +func (wrapped Wrapped) Pattern (id Pattern, state PatternState) artist.Pattern { + real := wrapped.ensure() + return real.Pattern(id, state, wrapped.Case) +} + +// Padding returns how much space should be between the bounds of a +// pattern whatever an element draws inside of it. +func (wrapped Wrapped) Padding (id Pattern) artist.Inset { + real := wrapped.ensure() + return real.Padding(id, wrapped.Case) +} + +// Margin returns the left/right (x) and top/bottom (y) margins that +// should be put between any self-contained objects drawn within this +// pattern (if applicable). +func (wrapped Wrapped) Margin (id Pattern) image.Point { + real := wrapped.ensure() + return real.Margin(id, wrapped.Case) +} + +// Sink returns a vector that should be added to an element's inner content when +// it is pressed down (if applicable) to simulate a 3D sinking effect. +func (wrapped Wrapped) Sink (id Pattern) image.Point { + real := wrapped.ensure() + return real.Sink(id, wrapped.Case) +} + +// Hints returns rendering optimization hints for a particular pattern. +// These are optional, but following them may result in improved +// performance. +func (wrapped Wrapped) Hints (id Pattern) Hints { + real := wrapped.ensure() + return real.Hints(id, wrapped.Case) +} + +func (wrapped Wrapped) ensure () (real Theme) { + real = wrapped.Theme + if real == nil { real = Default { } } + return +}