package config import ( "fmt" "sync" "github.com/gdamore/tcell/v2" ) // Functions to allow themeing configuration. // UI element tcell.Colors are mapped to a string key, such as "error" or "tab_bg" // These are the same keys used in the config file. // Special color with no real color value // Used for a default foreground color // White is the terminal background is black, black if the terminal background is white // Converted to a real color in this file before being sent out to other modules const ColorFg = tcell.ColorSpecial | 2 // The same as ColorFg, but inverted const ColorBg = tcell.ColorSpecial | 3 var themeMu = sync.RWMutex{} var theme = map[string]tcell.Color{ // Map these for special uses in code "ColorBg": ColorBg, "ColorFg": ColorFg, // Default values below // Only the 16 Xterm system tcell.Colors are used, because those are the tcell.Colors overrided // by the user's default terminal theme // Used for cview.Styles.PrimitiveBackgroundColor // Set to tcell.ColorDefault because that allows transparent terminals to work // The rest of this theme assumes that the background is equivalent to black, but // white colors switched to black later if the background is determined to be white. // // Also, this is set to tcell.ColorBlack in config.go if colors are disabled in the config. "bg": tcell.ColorDefault, "tab_num": tcell.ColorTeal, "tab_divider": ColorFg, "bottombar_label": tcell.ColorTeal, "bottombar_text": ColorBg, "bottombar_bg": ColorFg, "scrollbar": ColorFg, // Modals "btn_bg": tcell.ColorTeal, // All modal buttons "btn_text": tcell.ColorWhite, // White instead of ColorFg because background is known to be Teal "dl_choice_modal_bg": tcell.ColorOlive, "dl_choice_modal_text": tcell.ColorWhite, "dl_modal_bg": tcell.ColorOlive, "dl_modal_text": tcell.ColorWhite, "info_modal_bg": tcell.ColorGray, "info_modal_text": tcell.ColorWhite, "error_modal_bg": tcell.ColorMaroon, "error_modal_text": tcell.ColorWhite, "yesno_modal_bg": tcell.ColorTeal, "yesno_modal_text": tcell.ColorWhite, "tofu_modal_bg": tcell.ColorMaroon, "tofu_modal_text": tcell.ColorWhite, "subscription_modal_bg": tcell.ColorTeal, "subscription_modal_text": tcell.ColorWhite, "input_modal_bg": tcell.ColorGreen, "input_modal_text": tcell.ColorWhite, "input_modal_field_bg": tcell.ColorNavy, "input_modal_field_text": tcell.ColorWhite, "bkmk_modal_bg": tcell.ColorTeal, "bkmk_modal_text": tcell.ColorWhite, "bkmk_modal_label": tcell.ColorYellow, "bkmk_modal_field_bg": tcell.ColorNavy, "bkmk_modal_field_text": tcell.ColorWhite, "hdg_1": tcell.ColorRed, "hdg_2": tcell.ColorLime, "hdg_3": tcell.ColorFuchsia, "amfora_link": tcell.ColorBlue, "foreign_link": tcell.ColorPurple, "link_number": tcell.ColorSilver, "regular_text": ColorFg, "quote_text": ColorFg, "preformatted_text": ColorFg, "list_text": ColorFg, } func SetColor(key string, color tcell.Color) { themeMu.Lock() // Use truecolor because this is only called with user-set tcell.Colors // Which should be represented exactly theme[key] = color.TrueColor() themeMu.Unlock() } // GetColor will return tcell.ColorBlack if there is no tcell.Color for the provided key. func GetColor(key string) tcell.Color { themeMu.RLock() defer themeMu.RUnlock() color := theme[key] if color == ColorFg { if hasDarkTerminalBackground { return tcell.ColorWhite } return tcell.ColorBlack } if color == ColorBg { if hasDarkTerminalBackground { return tcell.ColorBlack } return tcell.ColorWhite } return color } // colorToString converts a color to a string for use in a cview tag func colorToString(color tcell.Color) string { if color == tcell.ColorDefault { return "-" } if color == ColorFg { if hasDarkTerminalBackground { return "white" } return "black" } if color == ColorBg { if hasDarkTerminalBackground { return "black" } return "white" } if color&tcell.ColorIsRGB == 0 { // tcell.Color is not RGB/TrueColor, it's a tcell.Color from the default terminal // theme as set above // Return a tcell.Color name instead of a hex code, so that cview doesn't use TrueColor return ColorToColorName[color] } // Color set by user, must be respected exactly so hex code is used return fmt.Sprintf("#%06x", color.Hex()) } // GetColorString returns a string that can be used in a cview tcell.Color tag, // for the given theme key. // It will return "#000000" if there is no tcell.Color for the provided key. func GetColorString(key string) string { themeMu.RLock() defer themeMu.RUnlock() return colorToString(theme[key]) } // GetContrastingColor returns tcell.ColorBlack if tcell.Color is brighter than gray // otherwise returns tcell.ColorWhite if tcell.Color is dimmer than gray // if tcell.Color is tcell.ColorDefault (undefined luminance) this returns tcell.ColorDefault func GetContrastingColor(color tcell.Color) tcell.Color { if color == tcell.ColorDefault { // tcell.Color should never be tcell.ColorDefault // only config keys which end in bg are allowed to be set to default // and the only way the argument of this function is set to tcell.ColorDefault // is if both the text and bg of an element in the UI are set to default return tcell.ColorDefault } r, g, b := color.RGB() luminance := (77*r + 150*g + 29*b + 1<<7) >> 8 const gray = 119 // The middle gray if luminance > gray { return tcell.ColorBlack } return tcell.ColorWhite } // GetTextColor is the Same as GetColor, unless the key is "default". // This happens on focus of a UI element which has a bg of default, in which case // It return tcell.ColorBlack or tcell.ColorWhite, depending on which is more readable func GetTextColor(key, bg string) tcell.Color { themeMu.RLock() defer themeMu.RUnlock() color := theme[key].TrueColor() if color != tcell.ColorDefault { return color } return GetContrastingColor(theme[bg].TrueColor()) } // GetTextColorString is the Same as GetColorString, unless the key is "default". // This happens on focus of a UI element which has a bg of default, in which case // It return tcell.ColorBlack or tcell.ColorWhite, depending on which is more readable func GetTextColorString(key, bg string) string { return colorToString(GetTextColor(key, bg)) } // Inverted version of a tcell map // https://github.com/gdamore/tcell/blob/v2.3.3/color.go#L845 var ColorToColorName = map[tcell.Color]string{ tcell.ColorBlack: "black", tcell.ColorMaroon: "maroon", tcell.ColorGreen: "green", tcell.ColorOlive: "olive", tcell.ColorNavy: "navy", tcell.ColorPurple: "purple", tcell.ColorTeal: "teal", tcell.ColorSilver: "silver", tcell.ColorGray: "gray", tcell.ColorRed: "red", tcell.ColorLime: "lime", tcell.ColorYellow: "yellow", tcell.ColorBlue: "blue", tcell.ColorFuchsia: "fuchsia", tcell.ColorAqua: "aqua", tcell.ColorWhite: "white", tcell.ColorAliceBlue: "aliceblue", tcell.ColorAntiqueWhite: "antiquewhite", tcell.ColorAquaMarine: "aquamarine", tcell.ColorAzure: "azure", tcell.ColorBeige: "beige", tcell.ColorBisque: "bisque", tcell.ColorBlanchedAlmond: "blanchedalmond", tcell.ColorBlueViolet: "blueviolet", tcell.ColorBrown: "brown", tcell.ColorBurlyWood: "burlywood", tcell.ColorCadetBlue: "cadetblue", tcell.ColorChartreuse: "chartreuse", tcell.ColorChocolate: "chocolate", tcell.ColorCoral: "coral", tcell.ColorCornflowerBlue: "cornflowerblue", tcell.ColorCornsilk: "cornsilk", tcell.ColorCrimson: "crimson", tcell.ColorDarkBlue: "darkblue", tcell.ColorDarkCyan: "darkcyan", tcell.ColorDarkGoldenrod: "darkgoldenrod", tcell.ColorDarkGray: "darkgray", tcell.ColorDarkGreen: "darkgreen", tcell.ColorDarkKhaki: "darkkhaki", tcell.ColorDarkMagenta: "darkmagenta", tcell.ColorDarkOliveGreen: "darkolivegreen", tcell.ColorDarkOrange: "darkorange", tcell.ColorDarkOrchid: "darkorchid", tcell.ColorDarkRed: "darkred", tcell.ColorDarkSalmon: "darksalmon", tcell.ColorDarkSeaGreen: "darkseagreen", tcell.ColorDarkSlateBlue: "darkslateblue", tcell.ColorDarkSlateGray: "darkslategray", tcell.ColorDarkTurquoise: "darkturquoise", tcell.ColorDarkViolet: "darkviolet", tcell.ColorDeepPink: "deeppink", tcell.ColorDeepSkyBlue: "deepskyblue", tcell.ColorDimGray: "dimgray", tcell.ColorDodgerBlue: "dodgerblue", tcell.ColorFireBrick: "firebrick", tcell.ColorFloralWhite: "floralwhite", tcell.ColorForestGreen: "forestgreen", tcell.ColorGainsboro: "gainsboro", tcell.ColorGhostWhite: "ghostwhite", tcell.ColorGold: "gold", tcell.ColorGoldenrod: "goldenrod", tcell.ColorGreenYellow: "greenyellow", tcell.ColorHoneydew: "honeydew", tcell.ColorHotPink: "hotpink", tcell.ColorIndianRed: "indianred", tcell.ColorIndigo: "indigo", tcell.ColorIvory: "ivory", tcell.ColorKhaki: "khaki", tcell.ColorLavender: "lavender", tcell.ColorLavenderBlush: "lavenderblush", tcell.ColorLawnGreen: "lawngreen", tcell.ColorLemonChiffon: "lemonchiffon", tcell.ColorLightBlue: "lightblue", tcell.ColorLightCoral: "lightcoral", tcell.ColorLightCyan: "lightcyan", tcell.ColorLightGoldenrodYellow: "lightgoldenrodyellow", tcell.ColorLightGray: "lightgray", tcell.ColorLightGreen: "lightgreen", tcell.ColorLightPink: "lightpink", tcell.ColorLightSalmon: "lightsalmon", tcell.ColorLightSeaGreen: "lightseagreen", tcell.ColorLightSkyBlue: "lightskyblue", tcell.ColorLightSlateGray: "lightslategray", tcell.ColorLightSteelBlue: "lightsteelblue", tcell.ColorLightYellow: "lightyellow", tcell.ColorLimeGreen: "limegreen", tcell.ColorLinen: "linen", tcell.ColorMediumAquamarine: "mediumaquamarine", tcell.ColorMediumBlue: "mediumblue", tcell.ColorMediumOrchid: "mediumorchid", tcell.ColorMediumPurple: "mediumpurple", tcell.ColorMediumSeaGreen: "mediumseagreen", tcell.ColorMediumSlateBlue: "mediumslateblue", tcell.ColorMediumSpringGreen: "mediumspringgreen", tcell.ColorMediumTurquoise: "mediumturquoise", tcell.ColorMediumVioletRed: "mediumvioletred", tcell.ColorMidnightBlue: "midnightblue", tcell.ColorMintCream: "mintcream", tcell.ColorMistyRose: "mistyrose", tcell.ColorMoccasin: "moccasin", tcell.ColorNavajoWhite: "navajowhite", tcell.ColorOldLace: "oldlace", tcell.ColorOliveDrab: "olivedrab", tcell.ColorOrange: "orange", tcell.ColorOrangeRed: "orangered", tcell.ColorOrchid: "orchid", tcell.ColorPaleGoldenrod: "palegoldenrod", tcell.ColorPaleGreen: "palegreen", tcell.ColorPaleTurquoise: "paleturquoise", tcell.ColorPaleVioletRed: "palevioletred", tcell.ColorPapayaWhip: "papayawhip", tcell.ColorPeachPuff: "peachpuff", tcell.ColorPeru: "peru", tcell.ColorPink: "pink", tcell.ColorPlum: "plum", tcell.ColorPowderBlue: "powderblue", tcell.ColorRebeccaPurple: "rebeccapurple", tcell.ColorRosyBrown: "rosybrown", tcell.ColorRoyalBlue: "royalblue", tcell.ColorSaddleBrown: "saddlebrown", tcell.ColorSalmon: "salmon", tcell.ColorSandyBrown: "sandybrown", tcell.ColorSeaGreen: "seagreen", tcell.ColorSeashell: "seashell", tcell.ColorSienna: "sienna", tcell.ColorSkyblue: "skyblue", tcell.ColorSlateBlue: "slateblue", tcell.ColorSlateGray: "slategray", tcell.ColorSnow: "snow", tcell.ColorSpringGreen: "springgreen", tcell.ColorSteelBlue: "steelblue", tcell.ColorTan: "tan", tcell.ColorThistle: "thistle", tcell.ColorTomato: "tomato", tcell.ColorTurquoise: "turquoise", tcell.ColorViolet: "violet", tcell.ColorWheat: "wheat", tcell.ColorWhiteSmoke: "whitesmoke", tcell.ColorYellowGreen: "yellowgreen", }