restructure-config #8
| @ -1,5 +1,6 @@ | |||||||
| package config | package config | ||||||
| 
 | 
 | ||||||
|  | // Config can return global configuration parameters. | ||||||
| type Config interface { | type Config interface { | ||||||
| 	// Padding returns the amount of internal padding elements should have. | 	// Padding returns the amount of internal padding elements should have. | ||||||
| 	// An element's inner content (such as text) should be inset by this | 	// An element's inner content (such as text) should be inset by this | ||||||
|  | |||||||
| @ -1,48 +0,0 @@ | |||||||
| package theme |  | ||||||
| 
 |  | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" |  | ||||||
| 
 |  | ||||||
| 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 }) |  | ||||||
							
								
								
									
										167
									
								
								theme/default.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								theme/default.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,167 @@ | |||||||
|  | package theme | ||||||
|  | 
 | ||||||
|  | import "image" | ||||||
|  | import "golang.org/x/image/font" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/defaultfont" | ||||||
|  | 
 | ||||||
|  | // Default is the default theme. | ||||||
|  | type Default struct { } | ||||||
|  | 
 | ||||||
|  | // FontFace returns the default font face. | ||||||
|  | func (Default) FontFace (style FontStyle, size FontSize, c Case) font.Face { | ||||||
|  | 	switch style { | ||||||
|  | 	case FontStyleBold: | ||||||
|  | 		return defaultfont.FaceBold | ||||||
|  | 	case FontStyleItalic: | ||||||
|  | 		return defaultfont.FaceItalic | ||||||
|  | 	case FontStyleBoldItalic: | ||||||
|  | 		return defaultfont.FaceBoldItalic | ||||||
|  | 	default: | ||||||
|  | 		return defaultfont.FaceRegular | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Icon returns an icon from the default set corresponding to the given name. | ||||||
|  | func (Default) Icon (string, Case) artist.Pattern { | ||||||
|  | 	// TODO | ||||||
|  | 	return uhex(0) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Pattern returns a pattern from the default theme corresponding to the given | ||||||
|  | // pattern ID. | ||||||
|  | func (Default) Pattern ( | ||||||
|  | 	pattern Pattern, | ||||||
|  | 	c Case, | ||||||
|  | 	state PatternState, | ||||||
|  | ) artist.Pattern { | ||||||
|  | 	switch pattern { | ||||||
|  | 	case PatternAccent: | ||||||
|  | 		return accentPattern | ||||||
|  | 	case PatternBackground: | ||||||
|  | 		return backgroundPattern | ||||||
|  | 	case PatternForeground: | ||||||
|  | 		if state.Disabled { | ||||||
|  | 			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 { | ||||||
|  | 			return sunkenPattern | ||||||
|  | 		} | ||||||
|  | 	case PatternPinboard: | ||||||
|  | 		return texturedSunkenPattern | ||||||
|  | 	case PatternButton: | ||||||
|  | 		if state.Disabled { | ||||||
|  | 			return disabledButtonPattern | ||||||
|  | 		} else { | ||||||
|  | 			if state.Pressed { | ||||||
|  | 				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 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) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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 { 2, 1, 2, 1 } | ||||||
|  | 		} else { | ||||||
|  | 			return Inset { 1, 1, 1, 1 } | ||||||
|  | 		} | ||||||
|  | 	case PatternSunken: | ||||||
|  | 		if c == C("basic", "list") { | ||||||
|  | 			return Inset { 4, 6, 4, 6 } | ||||||
|  | 		} else { | ||||||
|  | 			return Inset { 1, 1, 1, 1 } | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 	case PatternInput, PatternButton, PatternHandle, PatternPinboard: | ||||||
|  | 		return Inset { 1, 1, 1, 1} | ||||||
|  | 	default: return Inset { } | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Sink returns the default sink vector for the given pattern. | ||||||
|  | func (Default) Sink (pattern Pattern, c Case) image.Point { | ||||||
|  | 	return image.Point { 1, 1 } | ||||||
|  | } | ||||||
							
								
								
									
										237
									
								
								theme/defaultpatterns.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								theme/defaultpatterns.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,237 @@ | |||||||
|  | package theme | ||||||
|  | 
 | ||||||
|  | import "image/color" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
|  | 
 | ||||||
|  | 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 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.Striped { | ||||||
|  | 		// First: artist.Stroke { | ||||||
|  | 			// Weight: 2, | ||||||
|  | 			// Pattern: artist.NewUniform(hex(0x97a09cFF)), | ||||||
|  | 		// }, | ||||||
|  | 		// Second: artist.Stroke { | ||||||
|  | 			// Weight: 1, | ||||||
|  | 			// Pattern: artist.NewUniform(hex(0x6e8079FF)), | ||||||
|  | 		// }, | ||||||
|  | 	// }}) | ||||||
|  | 	 | ||||||
|  | 	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 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 disabledScrollGutterPattern = artist.NewMultiBordered ( | ||||||
|  | 	artist.Stroke { Weight: 1, Pattern: weakForegroundPattern }, | ||||||
|  | 	artist.Stroke { Pattern: backgroundPattern }) | ||||||
|  | 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 }) | ||||||
| @ -1,21 +0,0 @@ | |||||||
| package theme |  | ||||||
| 
 |  | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" |  | ||||||
| 
 |  | ||||||
| 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 }) |  | ||||||
							
								
								
									
										42
									
								
								theme/inset.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								theme/inset.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | package theme | ||||||
|  | 
 | ||||||
|  | import "image" | ||||||
|  | 
 | ||||||
|  | // Inset represents an inset amount for all four sides of a rectangle. The top | ||||||
|  | // side is at index zero, the right at index one, the bottom at index two, and | ||||||
|  | // the left at index three. These values may be negative. | ||||||
|  | type Inset [4]int | ||||||
|  | 
 | ||||||
|  | // Apply returns the given rectangle, shrunk on all four sides by the given | ||||||
|  | // inset. If a measurment of the inset is negative, that side will instead be | ||||||
|  | // expanded outward. If the rectangle's dimensions cannot be reduced any | ||||||
|  | // further, an empty rectangle near its center will be returned. | ||||||
|  | func (inset Inset) Apply (bigger image.Rectangle) (smaller image.Rectangle) { | ||||||
|  | 	smaller = bigger | ||||||
|  | 	if smaller.Dx() < inset[3] + inset[1] { | ||||||
|  | 		smaller.Min.X = (smaller.Min.X + smaller.Max.X) / 2 | ||||||
|  | 		smaller.Max.X = smaller.Min.X | ||||||
|  | 	} else { | ||||||
|  | 		smaller.Min.X += inset[3] | ||||||
|  | 		smaller.Max.X -= inset[1] | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if smaller.Dy() < inset[0] + inset[2] { | ||||||
|  | 		smaller.Min.Y = (smaller.Min.Y + smaller.Max.Y) / 2 | ||||||
|  | 		smaller.Max.Y = smaller.Min.Y | ||||||
|  | 	} else { | ||||||
|  | 		smaller.Min.Y += inset[0] | ||||||
|  | 		smaller.Max.Y -= inset[2] | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Inverse returns a negated version of the inset. | ||||||
|  | func (inset Inset) Inverse () (prime Inset) { | ||||||
|  | 	return Inset { | ||||||
|  | 		inset[0] * -1, | ||||||
|  | 		inset[1] * -1, | ||||||
|  | 		inset[2] * -1, | ||||||
|  | 		inset[3] * -1, | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -1,43 +0,0 @@ | |||||||
| package theme |  | ||||||
| 
 |  | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" |  | ||||||
| 
 |  | ||||||
| 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 }, |  | ||||||
| } |  | ||||||
							
								
								
									
										9
									
								
								theme/parse.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								theme/parse.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | package theme | ||||||
|  | 
 | ||||||
|  | import "io" | ||||||
|  | 
 | ||||||
|  | // Parse parses a theme file and returns it as a Theme. | ||||||
|  | func Parse (io.Reader) (Theme) { | ||||||
|  | 	// TODO | ||||||
|  | 	return Default { } | ||||||
|  | } | ||||||
| @ -1,239 +0,0 @@ | |||||||
| package theme |  | ||||||
| 
 |  | ||||||
| import "image" |  | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" |  | ||||||
| 
 |  | ||||||
| // Case sepecifies what kind of element is using a pattern. It contains a |  | ||||||
| // namespace parameter and an element parameter. The element parameter does not |  | ||||||
| // necissarily need to match an element name, but if it can, it should. Both |  | ||||||
| // parameters should be written in camel case. Themes can change their styling |  | ||||||
| // based on this parameter for fine-grained control over the look and feel of |  | ||||||
| // specific elements. |  | ||||||
| type Case struct { Namespace, Element string }  |  | ||||||
|   |  | ||||||
| // C can be used as shorthand to generate a case struct as used in PatternState. |  | ||||||
| func C (namespace, element string) (c Case) { |  | ||||||
| 	return Case { |  | ||||||
| 		Namespace: namespace, |  | ||||||
| 		Element: element, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // PatternState lists parameters which can change the appearance of some |  | ||||||
| // patterns. For example, passing a PatternState with Selected set to true may |  | ||||||
| // result in a pattern that has a colored border within it. |  | ||||||
| type PatternState struct { |  | ||||||
| 	Case |  | ||||||
| 
 |  | ||||||
| 	// On should be set to true if the element that is using this pattern is |  | ||||||
| 	// in some sort of "on" state, such as if a checkbox is checked or a |  | ||||||
| 	// switch is toggled on. This is only necessary if the element in |  | ||||||
| 	// question is capable of being toggled. |  | ||||||
| 	On bool |  | ||||||
| 
 |  | ||||||
| 	// Focused should be set to true if the element that is using this |  | ||||||
| 	// pattern is currently focused. |  | ||||||
| 	Focused bool |  | ||||||
| 
 |  | ||||||
| 	// Pressed should be set to true if the element that is using this |  | ||||||
| 	// pattern is being pressed down by the mouse. This is only necessary if |  | ||||||
| 	// the element in question processes mouse button events. |  | ||||||
| 	Pressed bool |  | ||||||
| 
 |  | ||||||
| 	// Disabled should be set to true if the element that is using this |  | ||||||
| 	// pattern is locked and cannot be interacted with. Disabled variations |  | ||||||
| 	// of patterns are typically flattened and greyed-out. |  | ||||||
| 	Disabled bool |  | ||||||
| 
 |  | ||||||
| 	// Invalid should be set to true if th element that is using this |  | ||||||
| 	// pattern wants to warn the user of an invalid interaction or data |  | ||||||
| 	// entry. Invalid variations typically have some sort of reddish tint |  | ||||||
| 	// or outline. |  | ||||||
| 	Invalid bool |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Inset represents an inset amount for all four sides of a rectangle. The top |  | ||||||
| // side is at index zero, the right at index one, the bottom at index two, and |  | ||||||
| // the left at index three. These values may be negative. |  | ||||||
| type Inset [4]int |  | ||||||
| 
 |  | ||||||
| // Apply returns the given rectangle, shrunk on all four sides by the given |  | ||||||
| // inset. If a measurment of the inset is negative, that side will instead be |  | ||||||
| // expanded outward. If the rectangle's dimensions cannot be reduced any |  | ||||||
| // further, an empty rectangle near its center will be returned. |  | ||||||
| func (inset Inset) Apply (bigger image.Rectangle) (smaller image.Rectangle) { |  | ||||||
| 	smaller = bigger |  | ||||||
| 	if smaller.Dx() < inset[3] + inset[1] { |  | ||||||
| 		smaller.Min.X = (smaller.Min.X + smaller.Max.X) / 2 |  | ||||||
| 		smaller.Max.X = smaller.Min.X |  | ||||||
| 	} else { |  | ||||||
| 		smaller.Min.X += inset[3] |  | ||||||
| 		smaller.Max.X -= inset[1] |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if smaller.Dy() < inset[0] + inset[2] { |  | ||||||
| 		smaller.Min.Y = (smaller.Min.Y + smaller.Max.Y) / 2 |  | ||||||
| 		smaller.Max.Y = smaller.Min.Y |  | ||||||
| 	} else { |  | ||||||
| 		smaller.Min.Y += inset[0] |  | ||||||
| 		smaller.Max.Y -= inset[2] |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Inverse returns a negated version of the inset. |  | ||||||
| func (inset Inset) Inverse () (prime Inset) { |  | ||||||
| 	return Inset { |  | ||||||
| 		inset[0] * -1, |  | ||||||
| 		inset[1] * -1, |  | ||||||
| 		inset[2] * -1, |  | ||||||
| 		inset[3] * -1, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // AccentPattern returns the accent pattern, which is usually just a solid |  | ||||||
| // color. |  | ||||||
| func AccentPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	return accentPattern, Inset { } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // BackgroundPattern returns the main background pattern. |  | ||||||
| func BackgroundPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	return backgroundPattern, Inset { } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // DeadPattern returns a pattern that can be used to mark an area or gap that |  | ||||||
| // serves no purpose, but still needs aesthetic structure. |  | ||||||
| func DeadPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	return deadPattern, Inset { } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // ForegroundPattern returns the color text should be. |  | ||||||
| func ForegroundPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	if state.Disabled { |  | ||||||
| 		return weakForegroundPattern, Inset { } |  | ||||||
| 	} else { |  | ||||||
| 		return foregroundPattern, Inset { } |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // InputPattern returns a background pattern for any input field that can be |  | ||||||
| // edited by typing with the keyboard. |  | ||||||
| func InputPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	if state.Disabled { |  | ||||||
| 		return disabledInputPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 	} else { |  | ||||||
| 		if state.Focused { |  | ||||||
| 			return selectedInputPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 		} else { |  | ||||||
| 			return inputPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // ListPattern returns a background pattern for a list of things. |  | ||||||
| func ListPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	if state.Focused { |  | ||||||
| 		pattern = focusedListPattern |  | ||||||
| 		inset = Inset { 2, 1, 2, 1 } |  | ||||||
| 	} else { |  | ||||||
| 		pattern = listPattern |  | ||||||
| 		inset = Inset { 2, 1, 1, 1 } |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // ItemPattern returns a background pattern for a list item. |  | ||||||
| func ItemPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	if state.Focused { |  | ||||||
| 		if state.On { |  | ||||||
| 			pattern = focusedOnListEntryPattern |  | ||||||
| 		} else { |  | ||||||
| 			pattern = focusedListEntryPattern |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		if state.On { |  | ||||||
| 			pattern = onListEntryPattern |  | ||||||
| 		} else { |  | ||||||
| 			pattern = listEntryPattern |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	inset = Inset { 4, 6, 4, 6 } |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // ButtonPattern returns a pattern to be displayed on buttons. |  | ||||||
| func ButtonPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	if state.Disabled { |  | ||||||
| 		return disabledButtonPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 	} else { |  | ||||||
| 		if state.Pressed { |  | ||||||
| 			if state.Focused { |  | ||||||
| 				return pressedSelectedButtonPattern, Inset { |  | ||||||
| 					2, 0, 0, 2 } |  | ||||||
| 			} else { |  | ||||||
| 				return pressedButtonPattern, Inset { 2, 0, 0, 2 } |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			if state.Focused { |  | ||||||
| 				return selectedButtonPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 			} else { |  | ||||||
| 				return buttonPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GutterPattern returns a pattern to be used to mark a track along which |  | ||||||
| // something slides. |  | ||||||
| func GutterPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	if state.Disabled { |  | ||||||
| 		return disabledScrollGutterPattern, Inset { 0, 0, 0, 0 } |  | ||||||
| 	} else { |  | ||||||
| 		return scrollGutterPattern, Inset { 0, 0, 0, 0 } |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // HandlePattern returns a pattern to be displayed on a grab handle that slides |  | ||||||
| // along a gutter. |  | ||||||
| func HandlePattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	if state.Disabled { |  | ||||||
| 		return disabledScrollBarPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 	} else { |  | ||||||
| 		if state.Focused { |  | ||||||
| 			if state.Pressed { |  | ||||||
| 				return pressedSelectedScrollBarPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 			} else { |  | ||||||
| 				return selectedScrollBarPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			if state.Pressed { |  | ||||||
| 				return pressedScrollBarPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 			} else { |  | ||||||
| 				return scrollBarPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // SunkenPattern returns a general purpose pattern that is sunken/engraved into |  | ||||||
| // the background. |  | ||||||
| func SunkenPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	return sunkenPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // RaisedPattern returns a general purpose pattern that is raised up out of the |  | ||||||
| // background. |  | ||||||
| func RaisedPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	if state.Focused { |  | ||||||
| 		return selectedRaisedPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 	} else { |  | ||||||
| 		return raisedPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // PinboardPattern returns a textured backdrop pattern. Anything drawn within it |  | ||||||
| // should have its own background pattern. |  | ||||||
| func PinboardPattern (state PatternState) (pattern artist.Pattern, inset Inset) { |  | ||||||
| 	return texturedSunkenPattern, Inset { 1, 1, 1, 1 } |  | ||||||
| } |  | ||||||
| @ -1,63 +0,0 @@ | |||||||
| package theme |  | ||||||
| 
 |  | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" |  | ||||||
| 
 |  | ||||||
| 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 disabledScrollGutterPattern = artist.NewMultiBordered ( |  | ||||||
| 	artist.Stroke { Weight: 1, Pattern: weakForegroundPattern }, |  | ||||||
| 	artist.Stroke { Pattern: backgroundPattern }) |  | ||||||
| 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 }) |  | ||||||
							
								
								
									
										48
									
								
								theme/state.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								theme/state.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | package theme | ||||||
|  | 
 | ||||||
|  | // Case sepecifies what kind of element is using a pattern. It contains a | ||||||
|  | // namespace parameter and an element parameter. The element parameter does not | ||||||
|  | // necissarily need to match an element name, but if it can, it should. Both | ||||||
|  | // parameters should be written in camel case. Themes can change their styling | ||||||
|  | // based on this parameter for fine-grained control over the look and feel of | ||||||
|  | // specific elements. | ||||||
|  | type Case struct { Namespace, Element string }  | ||||||
|  |   | ||||||
|  | // C can be used as shorthand to generate a case struct as used in PatternState. | ||||||
|  | func C (namespace, element string) (c Case) { | ||||||
|  | 	return Case { | ||||||
|  | 		Namespace: namespace, | ||||||
|  | 		Element: element, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PatternState lists parameters which can change the appearance of some | ||||||
|  | // patterns. For example, passing a PatternState with Selected set to true may | ||||||
|  | // result in a pattern that has a colored border within it. | ||||||
|  | type PatternState struct { | ||||||
|  | 	// On should be set to true if the element that is using this pattern is | ||||||
|  | 	// in some sort of "on" state, such as if a checkbox is checked or a | ||||||
|  | 	// switch is toggled on. This is only necessary if the element in | ||||||
|  | 	// question is capable of being toggled. | ||||||
|  | 	On bool | ||||||
|  | 
 | ||||||
|  | 	// Focused should be set to true if the element that is using this | ||||||
|  | 	// pattern is currently focused. | ||||||
|  | 	Focused bool | ||||||
|  | 
 | ||||||
|  | 	// Pressed should be set to true if the element that is using this | ||||||
|  | 	// pattern is being pressed down by the mouse. This is only necessary if | ||||||
|  | 	// the element in question processes mouse button events. | ||||||
|  | 	Pressed bool | ||||||
|  | 
 | ||||||
|  | 	// Disabled should be set to true if the element that is using this | ||||||
|  | 	// pattern is locked and cannot be interacted with. Disabled variations | ||||||
|  | 	// of patterns are typically flattened and greyed-out. | ||||||
|  | 	Disabled bool | ||||||
|  | 
 | ||||||
|  | 	// Invalid should be set to true if th element that is using this | ||||||
|  | 	// pattern wants to warn the user of an invalid interaction or data | ||||||
|  | 	// entry. Invalid variations typically have some sort of reddish tint | ||||||
|  | 	// or outline. | ||||||
|  | 	Invalid bool | ||||||
|  | } | ||||||
							
								
								
									
										199
									
								
								theme/theme.go
									
									
									
									
									
								
							
							
						
						
									
										199
									
								
								theme/theme.go
									
									
									
									
									
								
							| @ -1,113 +1,100 @@ | |||||||
| package theme | package theme | ||||||
| 
 | 
 | ||||||
| import "image/color" | import "image" | ||||||
| import "golang.org/x/image/font" | import "golang.org/x/image/font" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/defaultfont" |  | ||||||
| 
 | 
 | ||||||
| // none of these colors are final! TODO: generate these values from a theme | // FontStyle specifies stylistic alterations to a font face. | ||||||
| // file at startup. | type FontStyle int; const ( | ||||||
|  | 	FontStyleRegular    FontStyle = 0 | ||||||
|  | 	FontStyleBold       FontStyle = 1 | ||||||
|  | 	FontStyleItalic     FontStyle = 2 | ||||||
|  | 	FontStyleBoldItalic FontStyle = 1 | 2 | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| func hex (color uint32) (c color.RGBA) { | // FontSize specifies the general size of a font face in a semantic way. | ||||||
| 	c.A = uint8(color) | type FontSize int; const ( | ||||||
| 	c.B = uint8(color >>  8) | 	// FontSizeNormal is the default font size that should be used for most | ||||||
| 	c.G = uint8(color >> 16) | 	// things. | ||||||
| 	c.R = uint8(color >> 24) | 	FontSizeNormal FontSize = iota | ||||||
| 	return | 
 | ||||||
| } | 	// FontSizeLarge is a larger font size suitable for things like section | ||||||
| 
 | 	// headings. | ||||||
| func uhex (color uint32) (pattern artist.Pattern) { | 	FontSizeLarge | ||||||
| 	return artist.NewUniform(hex(color)) | 
 | ||||||
| } | 	// FontSizeHuge is a very large font size suitable for things like | ||||||
| 
 | 	// titles, wizard step names, digital clocks, etc. | ||||||
| var accentPattern         = artist.NewUniform(hex(0x408090FF)) | 	FontSizeHuge | ||||||
| var backgroundPattern     = artist.NewUniform(color.Gray16 { 0xAAAA }) | 
 | ||||||
| var foregroundPattern     = artist.NewUniform(color.Gray16 { 0x0000 }) | 	// FontSizeSmall is a smaller font size. Try not to use this unless it | ||||||
| var weakForegroundPattern = artist.NewUniform(color.Gray16 { 0x4444 }) | 	// makes a lot of sense to do so, because it can negatively impact | ||||||
| var strokePattern         = artist.NewUniform(color.Gray16 { 0x0000 }) | 	// accessibility. It is useful for things like copyright notices at the | ||||||
| 
 | 	// bottom of some window that the average user doesn't actually care | ||||||
| var sunkenPattern = artist.NewMultiBordered ( | 	// about. | ||||||
| 	artist.Stroke { Weight: 1, Pattern: strokePattern }, | 	FontSizeSmall | ||||||
| 	artist.Stroke { | ) | ||||||
| 		Weight: 1, | 
 | ||||||
| 		Pattern: artist.Beveled { | // Pattern lists a number of cannonical pattern types, each with its own ID. | ||||||
| 			artist.NewUniform(hex(0x3b534eFF)), | // This allows custom elements to follow themes, even those that do not | ||||||
| 			artist.NewUniform(hex(0x97a09cFF)), | // explicitly support them. | ||||||
| 		}, | type Pattern int; const ( | ||||||
| 	}, | 	// PatternAccent is the accent color of the theme. It is safe to assume | ||||||
| 	artist.Stroke { Pattern: artist.NewUniform(hex(0x97a09cFF)) }) | 	// that this is, by default, a solid color. | ||||||
| 
 | 	PatternAccent Pattern = iota | ||||||
| var texturedSunkenPattern = artist.NewMultiBordered ( | 
 | ||||||
| 	artist.Stroke { Weight: 1, Pattern: strokePattern }, | 	// PatternBackground is the background color of the theme. It is safe to | ||||||
| 	artist.Stroke { | 	// assume that this is, by default, a solid color. | ||||||
| 		Weight: 1, | 	PatternBackground | ||||||
| 		Pattern: artist.Beveled { | 
 | ||||||
| 			artist.NewUniform(hex(0x3b534eFF)), | 	// PatternForeground is the foreground text color of the theme. It is | ||||||
| 			artist.NewUniform(hex(0x97a09cFF)), | 	// safe to assume that this is, by default, a solid color. | ||||||
| 		}, | 	PatternForeground | ||||||
| 	}, | 
 | ||||||
| 	// artist.Stroke { Pattern: artist.Striped { | 	// PatternDead is a pattern that is displayed on a "dead area" where no | ||||||
| 		// First: artist.Stroke { | 	// controls exist, but there still must be some indication of visual | ||||||
| 			// Weight: 2, | 	// structure (such as in the corner between two scroll bars). | ||||||
| 			// Pattern: artist.NewUniform(hex(0x97a09cFF)), | 	PatternDead | ||||||
| 		// }, | 
 | ||||||
| 		// Second: artist.Stroke { | 	// PatternRaised is a generic raised pattern. | ||||||
| 			// Weight: 1, | 	PatternRaised | ||||||
| 			// Pattern: artist.NewUniform(hex(0x6e8079FF)), | 
 | ||||||
| 		// }, | 	// PatternSunken is a generic sunken pattern. | ||||||
| 	// }}) | 	PatternSunken | ||||||
| 	 | 
 | ||||||
| 	artist.Stroke { Pattern: artist.Noisy { | 	// PatternPinboard is similar to PatternSunken, but it is textured. | ||||||
| 		Low:  artist.NewUniform(hex(0x97a09cFF)), | 	PatternPinboard | ||||||
| 		High: artist.NewUniform(hex(0x6e8079FF)), | 
 | ||||||
| 	}}) | 	// PatternButton is a button pattern. | ||||||
| 
 | 	PatternButton | ||||||
| var raisedPattern = artist.NewMultiBordered ( | 
 | ||||||
| 	artist.Stroke { Weight: 1, Pattern: strokePattern }, | 	// PatternInput is a pattern for input fields, editable text areas, etc. | ||||||
| 	artist.Stroke { | 	PatternInput | ||||||
| 		Weight: 1, | 
 | ||||||
| 		Pattern: artist.Beveled { | 	// PatternGutter is a track for things to slide on. | ||||||
| 			artist.NewUniform(hex(0xDBDBDBFF)), | 	PatternGutter | ||||||
| 			artist.NewUniform(hex(0x383C3AFF)), | 
 | ||||||
| 		}, | 	// PatternHandle is a handle that slides along a gutter. | ||||||
| 	}, | 	PatternHandle | ||||||
| 	artist.Stroke { Pattern: artist.NewUniform(hex(0xAAAAAAFF)) }) | ) | ||||||
| 
 | 
 | ||||||
| var selectedRaisedPattern = artist.NewMultiBordered ( | // Theme represents a visual style configuration, | ||||||
| 	artist.Stroke { Weight: 1, Pattern: strokePattern }, | type Theme interface { | ||||||
| 	artist.Stroke { | 	// FontFace returns the proper font for a given style, size, and case. | ||||||
| 		Weight: 1, | 	FontFace (FontStyle, FontSize, Case) font.Face | ||||||
| 		Pattern: artist.Beveled { | 
 | ||||||
| 			artist.NewUniform(hex(0xDBDBDBFF)), | 	// Icon returns an appropriate icon given an icon name and case. | ||||||
| 			artist.NewUniform(hex(0x383C3AFF)), | 	Icon (string, Case) artist.Pattern | ||||||
| 		}, | 
 | ||||||
| 	}, | 	// Pattern returns an appropriate pattern given a pattern name, case, | ||||||
| 	artist.Stroke { Weight: 1, Pattern: accentPattern }, | 	// and state. | ||||||
| 	artist.Stroke { Pattern: artist.NewUniform(hex(0xAAAAAAFF)) }) | 	Pattern (Pattern, Case, PatternState) artist.Pattern | ||||||
| 
 | 
 | ||||||
| var deadPattern = artist.NewMultiBordered ( | 	// Inset returns the area on all sides of a given pattern that is not | ||||||
| 	artist.Stroke { Weight: 1, Pattern: strokePattern }, | 	// meant to be drawn on. | ||||||
| 	artist.Stroke { Pattern: artist.NewUniform(hex(0x97a09cFF)) }) | 	Inset (Pattern, Case) Inset | ||||||
| 
 | 
 | ||||||
| // TODO: load fonts from an actual source instead of using defaultfont | 	// 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 | ||||||
| // FontFaceRegular returns the font face to be used for normal text. | 	// sinking effect. | ||||||
| func FontFaceRegular () font.Face { | 	Sink (Pattern, Case) image.Point | ||||||
| 	return defaultfont.FaceRegular |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // FontFaceBold returns the font face to be used for bolded text. |  | ||||||
| func FontFaceBold () font.Face { |  | ||||||
| 	return defaultfont.FaceBold |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // FontFaceItalic returns the font face to be used for italicized text. |  | ||||||
| func FontFaceItalic () font.Face { |  | ||||||
| 	return defaultfont.FaceItalic |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // FontFaceBoldItalic returns the font face to be used for text that is both |  | ||||||
| // bolded and italicized. |  | ||||||
| func FontFaceBoldItalic () font.Face { |  | ||||||
| 	return defaultfont.FaceBoldItalic |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								theme/util.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								theme/util.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | 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)) | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user