mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Store Themes as JSON files (#4471)
Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
parent
7a286480d6
commit
4e3433e966
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
|
@ -26,3 +26,7 @@ jobs:
|
|||
- name: Show diff
|
||||
run: git --no-pager diff --exit-code --color=never
|
||||
shell: bash
|
||||
- name: Check Theme files
|
||||
run: |
|
||||
npm i ajv-cli
|
||||
npx -- ajv validate -s docs/ChatterinoTheme.schema.json -d "resources/themes/*.json"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# JSON resources should not be prettified
|
||||
# JSON resources should not be prettified...
|
||||
resources/*.json
|
||||
# ...themes should be prettified for readability.
|
||||
!resources/themes/*.json
|
||||
|
||||
# Ignore submodule files
|
||||
lib/*/
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
- Bugfix: Fixed search popup ignoring setting for message scrollback limit. (#4496)
|
||||
- Bugfix: Fixed a memory leak that occurred when loading message history. This was mostly noticeable with unstable internet connections where reconnections were frequent or long-running instances of Chatterino. (#4499)
|
||||
- Dev: Disabling precompiled headers on Windows is now tested in CI. (#4472)
|
||||
- Dev: Themes are now stored as JSON files in `resources/themes`. (#4471)
|
||||
- Dev: Ignore unhandled BTTV user-events. (#4438)
|
||||
- Dev: Only log debug messages when NDEBUG is not defined. (#4442)
|
||||
- Dev: Cleaned up theme related code. (#4450)
|
||||
|
|
|
@ -7,6 +7,7 @@ set(
|
|||
resources.qrc
|
||||
resources_autogenerated.qrc
|
||||
windows.rc
|
||||
themes/ChatterinoTheme.schema.json
|
||||
)
|
||||
set(RES_IMAGE_EXCLUDE_FILTER ^linuxinstall/)
|
||||
|
||||
|
|
398
docs/ChatterinoTheme.schema.json
Normal file
398
docs/ChatterinoTheme.schema.json
Normal file
|
@ -0,0 +1,398 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Chatterino Theme",
|
||||
"description": "Colors and metadata for a Chatterino 2 theme",
|
||||
"definitions": {
|
||||
"qt-color": {
|
||||
"type": "string",
|
||||
"$comment": "https://doc.qt.io/qt-5/qcolor.html#setNamedColor",
|
||||
"anyOf": [
|
||||
{
|
||||
"title": "#RGB",
|
||||
"pattern": "^#[a-fA-F0-9]{3}$"
|
||||
},
|
||||
{
|
||||
"title": "#RRGGBB",
|
||||
"pattern": "^#[a-fA-F0-9]{6}$"
|
||||
},
|
||||
{
|
||||
"title": "#AARRGGBB",
|
||||
"$comment": "Note that this isn't identical to the CSS Color Moudle Level 4 <hex-color> where the alpha value is at the end.",
|
||||
"pattern": "^#[a-fA-F0-9]{8}$"
|
||||
},
|
||||
{
|
||||
"title": "#RRRGGGBBB",
|
||||
"pattern": "^#[a-fA-F0-9]{9}$"
|
||||
},
|
||||
{
|
||||
"title": "#RRRRGGGGBBBB",
|
||||
"pattern": "^#[a-fA-F0-9]{12}$"
|
||||
},
|
||||
{
|
||||
"title": "SVG Color",
|
||||
"description": "This is stricter than Qt. You could theoretically put tabs an spaces between characters in a named color and capitalize the color.",
|
||||
"$comment": "https://www.w3.org/TR/SVG11/types.html#ColorKeywords",
|
||||
"enum": [
|
||||
"aliceblue",
|
||||
"antiquewhite",
|
||||
"aqua",
|
||||
"aquamarine",
|
||||
"azure",
|
||||
"beige",
|
||||
"bisque",
|
||||
"black",
|
||||
"blanchedalmond",
|
||||
"blue",
|
||||
"blueviolet",
|
||||
"brown",
|
||||
"burlywood",
|
||||
"cadetblue",
|
||||
"chartreuse",
|
||||
"chocolate",
|
||||
"coral",
|
||||
"cornflowerblue",
|
||||
"cornsilk",
|
||||
"crimson",
|
||||
"cyan",
|
||||
"darkblue",
|
||||
"darkcyan",
|
||||
"darkgoldenrod",
|
||||
"darkgray",
|
||||
"darkgreen",
|
||||
"darkgrey",
|
||||
"darkkhaki",
|
||||
"darkmagenta",
|
||||
"darkolivegreen",
|
||||
"darkorange",
|
||||
"darkorchid",
|
||||
"darkred",
|
||||
"darksalmon",
|
||||
"darkseagreen",
|
||||
"darkslateblue",
|
||||
"darkslategray",
|
||||
"darkslategrey",
|
||||
"darkturquoise",
|
||||
"darkviolet",
|
||||
"deeppink",
|
||||
"deepskyblue",
|
||||
"dimgray",
|
||||
"dimgrey",
|
||||
"dodgerblue",
|
||||
"firebrick",
|
||||
"floralwhite",
|
||||
"forestgreen",
|
||||
"fuchsia",
|
||||
"gainsboro",
|
||||
"ghostwhite",
|
||||
"gold",
|
||||
"goldenrod",
|
||||
"gray",
|
||||
"grey",
|
||||
"green",
|
||||
"greenyellow",
|
||||
"honeydew",
|
||||
"hotpink",
|
||||
"indianred",
|
||||
"indigo",
|
||||
"ivory",
|
||||
"khaki",
|
||||
"lavender",
|
||||
"lavenderblush",
|
||||
"lawngreen",
|
||||
"lemonchiffon",
|
||||
"lightblue",
|
||||
"lightcoral",
|
||||
"lightcyan",
|
||||
"lightgoldenrodyellow",
|
||||
"lightgray",
|
||||
"lightgreen",
|
||||
"lightgrey",
|
||||
"lightpink",
|
||||
"lightsalmon",
|
||||
"lightseagreen",
|
||||
"lightskyblue",
|
||||
"lightslategray",
|
||||
"lightslategrey",
|
||||
"lightsteelblue",
|
||||
"lightyellow",
|
||||
"lime",
|
||||
"limegreen",
|
||||
"linen",
|
||||
"magenta",
|
||||
"maroon",
|
||||
"mediumaquamarine",
|
||||
"mediumblue",
|
||||
"mediumorchid",
|
||||
"mediumpurple",
|
||||
"mediumseagreen",
|
||||
"mediumslateblue",
|
||||
"mediumspringgreen",
|
||||
"mediumturquoise",
|
||||
"mediumvioletred",
|
||||
"midnightblue",
|
||||
"mintcream",
|
||||
"mistyrose",
|
||||
"moccasin",
|
||||
"navajowhite",
|
||||
"navy",
|
||||
"oldlace",
|
||||
"olive",
|
||||
"olivedrab",
|
||||
"orange",
|
||||
"orangered",
|
||||
"orchid",
|
||||
"palegoldenrod",
|
||||
"palegreen",
|
||||
"paleturquoise",
|
||||
"palevioletred",
|
||||
"papayawhip",
|
||||
"peachpuff",
|
||||
"peru",
|
||||
"pink",
|
||||
"plum",
|
||||
"powderblue",
|
||||
"purple",
|
||||
"red",
|
||||
"rosybrown",
|
||||
"royalblue",
|
||||
"saddlebrown",
|
||||
"salmon",
|
||||
"sandybrown",
|
||||
"seagreen",
|
||||
"seashell",
|
||||
"sienna",
|
||||
"silver",
|
||||
"skyblue",
|
||||
"slateblue",
|
||||
"slategray",
|
||||
"slategrey",
|
||||
"snow",
|
||||
"springgreen",
|
||||
"steelblue",
|
||||
"tan",
|
||||
"teal",
|
||||
"thistle",
|
||||
"tomato",
|
||||
"turquoise",
|
||||
"violet",
|
||||
"wheat",
|
||||
"white",
|
||||
"whitesmoke",
|
||||
"yellow",
|
||||
"yellowgreen"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "transparent",
|
||||
"enum": ["transparent"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"tab-colors": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"backgrounds": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"hover": { "$ref": "#/definitions/qt-color" },
|
||||
"regular": { "$ref": "#/definitions/qt-color" },
|
||||
"unfocused": { "$ref": "#/definitions/qt-color" }
|
||||
},
|
||||
"required": ["hover", "regular", "unfocused"]
|
||||
},
|
||||
"line": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"hover": { "$ref": "#/definitions/qt-color" },
|
||||
"regular": { "$ref": "#/definitions/qt-color" },
|
||||
"unfocused": { "$ref": "#/definitions/qt-color" }
|
||||
},
|
||||
"required": ["hover", "regular", "unfocused"]
|
||||
},
|
||||
"text": { "$ref": "#/definitions/qt-color" }
|
||||
},
|
||||
"required": ["backgrounds", "line", "text"]
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"colors": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"accent": { "$ref": "#/definitions/qt-color" },
|
||||
"messages": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"backgrounds": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"alternate": { "$ref": "#/definitions/qt-color" },
|
||||
"regular": { "$ref": "#/definitions/qt-color" }
|
||||
},
|
||||
"required": ["alternate", "regular"]
|
||||
},
|
||||
"disabled": { "$ref": "#/definitions/qt-color" },
|
||||
"highlightAnimationEnd": { "$ref": "#/definitions/qt-color" },
|
||||
"highlightAnimationStart": { "$ref": "#/definitions/qt-color" },
|
||||
"selection": { "$ref": "#/definitions/qt-color" },
|
||||
"textColors": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"caret": { "$ref": "#/definitions/qt-color" },
|
||||
"chatPlaceholder": { "$ref": "#/definitions/qt-color" },
|
||||
"link": { "$ref": "#/definitions/qt-color" },
|
||||
"regular": { "$ref": "#/definitions/qt-color" },
|
||||
"system": { "$ref": "#/definitions/qt-color" }
|
||||
},
|
||||
"required": [
|
||||
"caret",
|
||||
"chatPlaceholder",
|
||||
"link",
|
||||
"regular",
|
||||
"system"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"backgrounds",
|
||||
"disabled",
|
||||
"highlightAnimationEnd",
|
||||
"highlightAnimationStart",
|
||||
"selection",
|
||||
"textColors"
|
||||
]
|
||||
},
|
||||
"scrollbars": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"background": { "$ref": "#/definitions/qt-color" },
|
||||
"thumb": { "$ref": "#/definitions/qt-color" },
|
||||
"thumbSelected": { "$ref": "#/definitions/qt-color" }
|
||||
},
|
||||
"required": ["background", "thumb", "thumbSelected"]
|
||||
},
|
||||
"splits": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"background": { "$ref": "#/definitions/qt-color" },
|
||||
"dropPreview": { "$ref": "#/definitions/qt-color" },
|
||||
"dropPreviewBorder": { "$ref": "#/definitions/qt-color" },
|
||||
"dropTargetRect": { "$ref": "#/definitions/qt-color" },
|
||||
"dropTargetRectBorder": { "$ref": "#/definitions/qt-color" },
|
||||
"header": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"background": { "$ref": "#/definitions/qt-color" },
|
||||
"border": { "$ref": "#/definitions/qt-color" },
|
||||
"focusedBackground": { "$ref": "#/definitions/qt-color" },
|
||||
"focusedBorder": { "$ref": "#/definitions/qt-color" },
|
||||
"focusedText": { "$ref": "#/definitions/qt-color" },
|
||||
"text": { "$ref": "#/definitions/qt-color" }
|
||||
},
|
||||
"required": [
|
||||
"background",
|
||||
"border",
|
||||
"focusedBackground",
|
||||
"focusedBorder",
|
||||
"focusedText",
|
||||
"text"
|
||||
]
|
||||
},
|
||||
"input": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"background": { "$ref": "#/definitions/qt-color" },
|
||||
"text": { "$ref": "#/definitions/qt-color" }
|
||||
},
|
||||
"required": ["background", "text"]
|
||||
},
|
||||
"messageSeperator": { "$ref": "#/definitions/qt-color" },
|
||||
"resizeHandle": { "$ref": "#/definitions/qt-color" },
|
||||
"resizeHandleBackground": { "$ref": "#/definitions/qt-color" }
|
||||
},
|
||||
"required": [
|
||||
"background",
|
||||
"dropPreview",
|
||||
"dropPreviewBorder",
|
||||
"dropTargetRect",
|
||||
"dropTargetRectBorder",
|
||||
"header",
|
||||
"input",
|
||||
"messageSeperator",
|
||||
"resizeHandle",
|
||||
"resizeHandleBackground"
|
||||
]
|
||||
},
|
||||
"tabs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"dividerLine": { "$ref": "#/definitions/qt-color" },
|
||||
"highlighted": {
|
||||
"$ref": "#/definitions/tab-colors"
|
||||
},
|
||||
"newMessage": {
|
||||
"$ref": "#/definitions/tab-colors"
|
||||
},
|
||||
"regular": {
|
||||
"$ref": "#/definitions/tab-colors"
|
||||
},
|
||||
"selected": {
|
||||
"$ref": "#/definitions/tab-colors"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"dividerLine",
|
||||
"highlighted",
|
||||
"newMessage",
|
||||
"regular",
|
||||
"selected"
|
||||
]
|
||||
},
|
||||
"window": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"background": { "$ref": "#/definitions/qt-color" },
|
||||
"text": { "$ref": "#/definitions/qt-color" }
|
||||
},
|
||||
"required": ["background", "text"]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"accent",
|
||||
"messages",
|
||||
"scrollbars",
|
||||
"splits",
|
||||
"tabs",
|
||||
"window"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"iconTheme": {
|
||||
"$comment": "Determines which icons to use. 'dark' will use dark icons (best for a light theme). 'light' will use light icons.",
|
||||
"enum": ["light", "dark"],
|
||||
"default": "light"
|
||||
}
|
||||
},
|
||||
"required": ["iconTheme"]
|
||||
},
|
||||
"$schema": { "type": "string" }
|
||||
},
|
||||
"required": ["colors", "metadata"]
|
||||
}
|
112
resources/themes/Black.json
Normal file
112
resources/themes/Black.json
Normal file
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"$schema": "../../docs/ChatterinoTheme.schema.json",
|
||||
"metadata": {
|
||||
"iconTheme": "light"
|
||||
},
|
||||
"colors": {
|
||||
"accent": "#00aeef",
|
||||
"messages": {
|
||||
"backgrounds": {
|
||||
"alternate": "#0a0a0a",
|
||||
"regular": "#000000"
|
||||
},
|
||||
"disabled": "#99000000",
|
||||
"highlightAnimationEnd": "#00e6e6e6",
|
||||
"highlightAnimationStart": "#6ee6e6e6",
|
||||
"selection": "#40ffffff",
|
||||
"textColors": {
|
||||
"caret": "#ffffff",
|
||||
"chatPlaceholder": "#5d5555",
|
||||
"link": "#4286f4",
|
||||
"regular": "#ffffff",
|
||||
"system": "#8c7f7f"
|
||||
}
|
||||
},
|
||||
"scrollbars": {
|
||||
"background": "#00000000",
|
||||
"thumb": "#4d4d4d",
|
||||
"thumbSelected": "#595959"
|
||||
},
|
||||
"splits": {
|
||||
"background": "#000000",
|
||||
"dropPreview": "#300094ff",
|
||||
"dropPreviewBorder": "#0094ff",
|
||||
"dropTargetRect": "#000094ff",
|
||||
"dropTargetRectBorder": "#000094ff",
|
||||
"header": {
|
||||
"background": "#191919",
|
||||
"border": "#262626",
|
||||
"focusedBackground": "#363636",
|
||||
"focusedBorder": "#383838",
|
||||
"focusedText": "#84c1ff",
|
||||
"text": "#ffffff"
|
||||
},
|
||||
"input": {
|
||||
"background": "#0d0d0d",
|
||||
"text": "#ffffff"
|
||||
},
|
||||
"messageSeperator": "#3c3c3c",
|
||||
"resizeHandle": "#700094ff",
|
||||
"resizeHandleBackground": "#200094ff"
|
||||
},
|
||||
"tabs": {
|
||||
"dividerLine": "#555555",
|
||||
"highlighted": {
|
||||
"backgrounds": {
|
||||
"hover": "#252525",
|
||||
"regular": "#252525",
|
||||
"unfocused": "#252525"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#ee6166",
|
||||
"regular": "#ee6166",
|
||||
"unfocused": "#ee6166"
|
||||
},
|
||||
"text": "#eeeeee"
|
||||
},
|
||||
"newMessage": {
|
||||
"backgrounds": {
|
||||
"hover": "#252525",
|
||||
"regular": "#252525",
|
||||
"unfocused": "#252525"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#888888",
|
||||
"regular": "#888888",
|
||||
"unfocused": "#888888"
|
||||
},
|
||||
"text": "#eeeeee"
|
||||
},
|
||||
"regular": {
|
||||
"backgrounds": {
|
||||
"hover": "#252525",
|
||||
"regular": "#252525",
|
||||
"unfocused": "#252525"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#444444",
|
||||
"regular": "#444444",
|
||||
"unfocused": "#444444"
|
||||
},
|
||||
"text": "#aaaaaa"
|
||||
},
|
||||
"selected": {
|
||||
"backgrounds": {
|
||||
"hover": "#555555",
|
||||
"regular": "#555555",
|
||||
"unfocused": "#555555"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#00aeef",
|
||||
"regular": "#00aeef",
|
||||
"unfocused": "#00aeef"
|
||||
},
|
||||
"text": "#ffffff"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"background": "#111111",
|
||||
"text": "#eeeeee"
|
||||
}
|
||||
}
|
||||
}
|
112
resources/themes/Dark.json
Normal file
112
resources/themes/Dark.json
Normal file
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"$schema": "../../docs/ChatterinoTheme.schema.json",
|
||||
"metadata": {
|
||||
"iconTheme": "light"
|
||||
},
|
||||
"colors": {
|
||||
"accent": "#00aeef",
|
||||
"messages": {
|
||||
"backgrounds": {
|
||||
"alternate": "#222222",
|
||||
"regular": "#191919"
|
||||
},
|
||||
"disabled": "#99191919",
|
||||
"highlightAnimationEnd": "#00e6e6e6",
|
||||
"highlightAnimationStart": "#6ee6e6e6",
|
||||
"selection": "#40ffffff",
|
||||
"textColors": {
|
||||
"caret": "#ffffff",
|
||||
"chatPlaceholder": "#5d5555",
|
||||
"link": "#4286f4",
|
||||
"regular": "#ffffff",
|
||||
"system": "#8c7f7f"
|
||||
}
|
||||
},
|
||||
"scrollbars": {
|
||||
"background": "#00000000",
|
||||
"thumb": "#575757",
|
||||
"thumbSelected": "#616161"
|
||||
},
|
||||
"splits": {
|
||||
"background": "#191919",
|
||||
"dropPreview": "#300094ff",
|
||||
"dropPreviewBorder": "#0094ff",
|
||||
"dropTargetRect": "#000094ff",
|
||||
"dropTargetRectBorder": "#000094ff",
|
||||
"header": {
|
||||
"background": "#2e2e2e",
|
||||
"border": "#383838",
|
||||
"focusedBackground": "#444444",
|
||||
"focusedBorder": "#464646",
|
||||
"focusedText": "#84c1ff",
|
||||
"text": "#ffffff"
|
||||
},
|
||||
"input": {
|
||||
"background": "#242424",
|
||||
"text": "#ffffff"
|
||||
},
|
||||
"messageSeperator": "#3c3c3c",
|
||||
"resizeHandle": "#700094ff",
|
||||
"resizeHandleBackground": "#200094ff"
|
||||
},
|
||||
"tabs": {
|
||||
"dividerLine": "#555555",
|
||||
"highlighted": {
|
||||
"backgrounds": {
|
||||
"hover": "#252525",
|
||||
"regular": "#252525",
|
||||
"unfocused": "#252525"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#ee6166",
|
||||
"regular": "#ee6166",
|
||||
"unfocused": "#ee6166"
|
||||
},
|
||||
"text": "#eeeeee"
|
||||
},
|
||||
"newMessage": {
|
||||
"backgrounds": {
|
||||
"hover": "#252525",
|
||||
"regular": "#252525",
|
||||
"unfocused": "#252525"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#888888",
|
||||
"regular": "#888888",
|
||||
"unfocused": "#888888"
|
||||
},
|
||||
"text": "#eeeeee"
|
||||
},
|
||||
"regular": {
|
||||
"backgrounds": {
|
||||
"hover": "#252525",
|
||||
"regular": "#252525",
|
||||
"unfocused": "#252525"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#444444",
|
||||
"regular": "#444444",
|
||||
"unfocused": "#444444"
|
||||
},
|
||||
"text": "#aaaaaa"
|
||||
},
|
||||
"selected": {
|
||||
"backgrounds": {
|
||||
"hover": "#555555",
|
||||
"regular": "#555555",
|
||||
"unfocused": "#555555"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#00aeef",
|
||||
"regular": "#00aeef",
|
||||
"unfocused": "#00aeef"
|
||||
},
|
||||
"text": "#ffffff"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"background": "#111111",
|
||||
"text": "#eeeeee"
|
||||
}
|
||||
}
|
||||
}
|
112
resources/themes/Light.json
Normal file
112
resources/themes/Light.json
Normal file
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"$schema": "../../docs/ChatterinoTheme.schema.json",
|
||||
"metadata": {
|
||||
"iconTheme": "dark"
|
||||
},
|
||||
"colors": {
|
||||
"accent": "#00aeef",
|
||||
"messages": {
|
||||
"backgrounds": {
|
||||
"alternate": "#dddddd",
|
||||
"regular": "#e6e6e6"
|
||||
},
|
||||
"disabled": "#99e6e6e6",
|
||||
"highlightAnimationEnd": "#00141414",
|
||||
"highlightAnimationStart": "#6e141414",
|
||||
"selection": "#40000000",
|
||||
"textColors": {
|
||||
"caret": "#000000",
|
||||
"chatPlaceholder": "#af9f9f",
|
||||
"link": "#4286f4",
|
||||
"regular": "#000000",
|
||||
"system": "#8c7f7f"
|
||||
}
|
||||
},
|
||||
"scrollbars": {
|
||||
"background": "#00000000",
|
||||
"thumb": "#a8a8a8",
|
||||
"thumbSelected": "#9e9e9e"
|
||||
},
|
||||
"splits": {
|
||||
"background": "#e6e6e6",
|
||||
"dropPreview": "#300094ff",
|
||||
"dropPreviewBorder": "#0094ff",
|
||||
"dropTargetRect": "#00ffffff",
|
||||
"dropTargetRectBorder": "#000094ff",
|
||||
"header": {
|
||||
"background": "#e6e6e6",
|
||||
"border": "#e6e6e6",
|
||||
"focusedBackground": "#dbdbdb",
|
||||
"focusedBorder": "#d1d1d1",
|
||||
"focusedText": "#0051a3",
|
||||
"text": "#000000"
|
||||
},
|
||||
"input": {
|
||||
"background": "#dbdbdb",
|
||||
"text": "#000000"
|
||||
},
|
||||
"messageSeperator": "#7f7f7f",
|
||||
"resizeHandle": "#0094ff",
|
||||
"resizeHandleBackground": "#500094ff"
|
||||
},
|
||||
"tabs": {
|
||||
"dividerLine": "#b4d7ff",
|
||||
"highlighted": {
|
||||
"backgrounds": {
|
||||
"hover": "#eeeeee",
|
||||
"regular": "#ffffff",
|
||||
"unfocused": "#ffffff"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#ff0000",
|
||||
"regular": "#ff0000",
|
||||
"unfocused": "#ff0000"
|
||||
},
|
||||
"text": "#000000"
|
||||
},
|
||||
"newMessage": {
|
||||
"backgrounds": {
|
||||
"hover": "#eeeeee",
|
||||
"regular": "#ffffff",
|
||||
"unfocused": "#ffffff"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#bbbbbb",
|
||||
"regular": "#bbbbbb",
|
||||
"unfocused": "#bbbbbb"
|
||||
},
|
||||
"text": "#222222"
|
||||
},
|
||||
"regular": {
|
||||
"backgrounds": {
|
||||
"hover": "#eeeeee",
|
||||
"regular": "#ffffff",
|
||||
"unfocused": "#ffffff"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#ffffff",
|
||||
"regular": "#ffffff",
|
||||
"unfocused": "#ffffff"
|
||||
},
|
||||
"text": "#444444"
|
||||
},
|
||||
"selected": {
|
||||
"backgrounds": {
|
||||
"hover": "#b4d7ff",
|
||||
"regular": "#b4d7ff",
|
||||
"unfocused": "#b4d7ff"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#00aeef",
|
||||
"regular": "#00aeef",
|
||||
"unfocused": "#00aeef"
|
||||
},
|
||||
"text": "#000000"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"background": "#ffffff",
|
||||
"text": "#000000"
|
||||
}
|
||||
}
|
||||
}
|
112
resources/themes/White.json
Normal file
112
resources/themes/White.json
Normal file
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"$schema": "../../docs/ChatterinoTheme.schema.json",
|
||||
"metadata": {
|
||||
"iconTheme": "dark"
|
||||
},
|
||||
"colors": {
|
||||
"accent": "#00aeef",
|
||||
"messages": {
|
||||
"backgrounds": {
|
||||
"alternate": "#f5f5f5",
|
||||
"regular": "#ffffff"
|
||||
},
|
||||
"disabled": "#99ffffff",
|
||||
"highlightAnimationEnd": "#00141414",
|
||||
"highlightAnimationStart": "#6e141414",
|
||||
"selection": "#40000000",
|
||||
"textColors": {
|
||||
"caret": "#000000",
|
||||
"chatPlaceholder": "#af9f9f",
|
||||
"link": "#4286f4",
|
||||
"regular": "#000000",
|
||||
"system": "#8c7f7f"
|
||||
}
|
||||
},
|
||||
"scrollbars": {
|
||||
"background": "#00000000",
|
||||
"thumb": "#b3b3b3",
|
||||
"thumbSelected": "#a6a6a6"
|
||||
},
|
||||
"splits": {
|
||||
"background": "#ffffff",
|
||||
"dropPreview": "#300094ff",
|
||||
"dropPreviewBorder": "#0094ff",
|
||||
"dropTargetRect": "#00ffffff",
|
||||
"dropTargetRectBorder": "#000094ff",
|
||||
"header": {
|
||||
"background": "#ffffff",
|
||||
"border": "#ffffff",
|
||||
"focusedBackground": "#f2f2f2",
|
||||
"focusedBorder": "#e6e6e6",
|
||||
"focusedText": "#0051a3",
|
||||
"text": "#000000"
|
||||
},
|
||||
"input": {
|
||||
"background": "#f2f2f2",
|
||||
"text": "#000000"
|
||||
},
|
||||
"messageSeperator": "#7f7f7f",
|
||||
"resizeHandle": "#0094ff",
|
||||
"resizeHandleBackground": "#500094ff"
|
||||
},
|
||||
"tabs": {
|
||||
"dividerLine": "#b4d7ff",
|
||||
"highlighted": {
|
||||
"backgrounds": {
|
||||
"hover": "#eeeeee",
|
||||
"regular": "#ffffff",
|
||||
"unfocused": "#ffffff"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#ff0000",
|
||||
"regular": "#ff0000",
|
||||
"unfocused": "#ff0000"
|
||||
},
|
||||
"text": "#000000"
|
||||
},
|
||||
"newMessage": {
|
||||
"backgrounds": {
|
||||
"hover": "#eeeeee",
|
||||
"regular": "#ffffff",
|
||||
"unfocused": "#ffffff"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#bbbbbb",
|
||||
"regular": "#bbbbbb",
|
||||
"unfocused": "#bbbbbb"
|
||||
},
|
||||
"text": "#222222"
|
||||
},
|
||||
"regular": {
|
||||
"backgrounds": {
|
||||
"hover": "#eeeeee",
|
||||
"regular": "#ffffff",
|
||||
"unfocused": "#ffffff"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#ffffff",
|
||||
"regular": "#ffffff",
|
||||
"unfocused": "#ffffff"
|
||||
},
|
||||
"text": "#444444"
|
||||
},
|
||||
"selected": {
|
||||
"backgrounds": {
|
||||
"hover": "#b4d7ff",
|
||||
"regular": "#b4d7ff",
|
||||
"unfocused": "#b4d7ff"
|
||||
},
|
||||
"line": {
|
||||
"hover": "#00aeef",
|
||||
"regular": "#00aeef",
|
||||
"unfocused": "#00aeef"
|
||||
},
|
||||
"text": "#000000"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
"background": "#ffffff",
|
||||
"text": "#000000"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,6 +45,7 @@ Q_LOGGING_CATEGORY(chatterinoSound, "chatterino.sound", logThreshold);
|
|||
Q_LOGGING_CATEGORY(chatterinoStreamerMode, "chatterino.streamermode",
|
||||
logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoStreamlink, "chatterino.streamlink", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoTheme, "chatterino.theme", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoTokenizer, "chatterino.tokenizer", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoTwitch, "chatterino.twitch", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoUpdate, "chatterino.update", logThreshold);
|
||||
|
|
|
@ -34,6 +34,7 @@ Q_DECLARE_LOGGING_CATEGORY(chatterinoSeventvEventAPI);
|
|||
Q_DECLARE_LOGGING_CATEGORY(chatterinoSound);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoStreamerMode);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoStreamlink);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoTheme);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoTokenizer);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoTwitch);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoUpdate);
|
||||
|
|
|
@ -2,34 +2,153 @@
|
|||
#include "singletons/Theme.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "singletons/Resources.hpp"
|
||||
#include "common/QLogging.hpp"
|
||||
|
||||
#include <QColor>
|
||||
#include <QFile>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QSet>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
double getMultiplierByTheme(const QString &themeName)
|
||||
void parseInto(const QJsonObject &obj, const QLatin1String &key, QColor &color)
|
||||
{
|
||||
if (themeName == "Light")
|
||||
const auto &jsonValue = obj[key];
|
||||
if (!jsonValue.isString()) [[unlikely]]
|
||||
{
|
||||
return 0.8;
|
||||
qCWarning(chatterinoTheme) << key
|
||||
<< "was expected but not found in the "
|
||||
"current theme - using previous value.";
|
||||
return;
|
||||
}
|
||||
if (themeName == "White")
|
||||
QColor parsed = {jsonValue.toString()};
|
||||
if (!parsed.isValid()) [[unlikely]]
|
||||
{
|
||||
return 1.0;
|
||||
qCWarning(chatterinoTheme).nospace()
|
||||
<< "While parsing " << key << ": '" << jsonValue.toString()
|
||||
<< "' isn't a valid color.";
|
||||
return;
|
||||
}
|
||||
if (themeName == "Black")
|
||||
{
|
||||
return -1.0;
|
||||
}
|
||||
if (themeName == "Dark")
|
||||
{
|
||||
return -0.8;
|
||||
}
|
||||
|
||||
return -0.8; // default: Dark
|
||||
color = parsed;
|
||||
}
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
|
||||
#define parseColor(to, from, key) \
|
||||
parseInto(from, QLatin1String(#key), (to).from.key)
|
||||
// NOLINTEND(cppcoreguidelines-macro-usage)
|
||||
|
||||
void parseWindow(const QJsonObject &window, chatterino::Theme &theme)
|
||||
{
|
||||
parseColor(theme, window, background);
|
||||
parseColor(theme, window, text);
|
||||
}
|
||||
|
||||
void parseTabs(const QJsonObject &tabs, chatterino::Theme &theme)
|
||||
{
|
||||
const auto parseTabColors = [](auto json, auto &tab) {
|
||||
parseInto(json, QLatin1String("text"), tab.text);
|
||||
{
|
||||
const auto backgrounds = json["backgrounds"].toObject();
|
||||
parseColor(tab, backgrounds, regular);
|
||||
parseColor(tab, backgrounds, hover);
|
||||
parseColor(tab, backgrounds, unfocused);
|
||||
}
|
||||
{
|
||||
const auto line = json["line"].toObject();
|
||||
parseColor(tab, line, regular);
|
||||
parseColor(tab, line, hover);
|
||||
parseColor(tab, line, unfocused);
|
||||
}
|
||||
};
|
||||
parseColor(theme, tabs, dividerLine);
|
||||
parseTabColors(tabs["regular"].toObject(), theme.tabs.regular);
|
||||
parseTabColors(tabs["newMessage"].toObject(), theme.tabs.newMessage);
|
||||
parseTabColors(tabs["highlighted"].toObject(), theme.tabs.highlighted);
|
||||
parseTabColors(tabs["selected"].toObject(), theme.tabs.selected);
|
||||
}
|
||||
|
||||
void parseMessages(const QJsonObject &messages, chatterino::Theme &theme)
|
||||
{
|
||||
{
|
||||
const auto textColors = messages["textColors"].toObject();
|
||||
parseColor(theme.messages, textColors, regular);
|
||||
parseColor(theme.messages, textColors, caret);
|
||||
parseColor(theme.messages, textColors, link);
|
||||
parseColor(theme.messages, textColors, system);
|
||||
parseColor(theme.messages, textColors, chatPlaceholder);
|
||||
}
|
||||
{
|
||||
const auto backgrounds = messages["backgrounds"].toObject();
|
||||
parseColor(theme.messages, backgrounds, regular);
|
||||
parseColor(theme.messages, backgrounds, alternate);
|
||||
}
|
||||
parseColor(theme, messages, disabled);
|
||||
parseColor(theme, messages, selection);
|
||||
parseColor(theme, messages, highlightAnimationStart);
|
||||
parseColor(theme, messages, highlightAnimationEnd);
|
||||
}
|
||||
|
||||
void parseScrollbars(const QJsonObject &scrollbars, chatterino::Theme &theme)
|
||||
{
|
||||
parseColor(theme, scrollbars, background);
|
||||
parseColor(theme, scrollbars, thumb);
|
||||
parseColor(theme, scrollbars, thumbSelected);
|
||||
}
|
||||
|
||||
void parseSplits(const QJsonObject &splits, chatterino::Theme &theme)
|
||||
{
|
||||
parseColor(theme, splits, messageSeperator);
|
||||
parseColor(theme, splits, background);
|
||||
parseColor(theme, splits, dropPreview);
|
||||
parseColor(theme, splits, dropPreviewBorder);
|
||||
parseColor(theme, splits, dropTargetRect);
|
||||
parseColor(theme, splits, dropTargetRectBorder);
|
||||
parseColor(theme, splits, resizeHandle);
|
||||
parseColor(theme, splits, resizeHandleBackground);
|
||||
|
||||
{
|
||||
const auto header = splits["header"].toObject();
|
||||
parseColor(theme.splits, header, border);
|
||||
parseColor(theme.splits, header, focusedBorder);
|
||||
parseColor(theme.splits, header, background);
|
||||
parseColor(theme.splits, header, focusedBackground);
|
||||
parseColor(theme.splits, header, text);
|
||||
parseColor(theme.splits, header, focusedText);
|
||||
}
|
||||
{
|
||||
const auto input = splits["input"].toObject();
|
||||
parseColor(theme.splits, input, background);
|
||||
parseColor(theme.splits, input, text);
|
||||
}
|
||||
}
|
||||
|
||||
void parseColors(const QJsonObject &root, chatterino::Theme &theme)
|
||||
{
|
||||
const auto colors = root["colors"].toObject();
|
||||
|
||||
parseInto(colors, QLatin1String("accent"), theme.accent);
|
||||
|
||||
parseWindow(colors["window"].toObject(), theme);
|
||||
parseTabs(colors["tabs"].toObject(), theme);
|
||||
parseMessages(colors["messages"].toObject(), theme);
|
||||
parseScrollbars(colors["scrollbars"].toObject(), theme);
|
||||
parseSplits(colors["splits"].toObject(), theme);
|
||||
}
|
||||
#undef parseColor
|
||||
|
||||
QString getThemePath(const QString &name)
|
||||
{
|
||||
static QSet<QString> knownThemes = {"White", "Light", "Dark", "Black"};
|
||||
|
||||
if (knownThemes.contains(name))
|
||||
{
|
||||
return QStringLiteral(":/themes/%1.json").arg(name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace chatterino {
|
||||
|
@ -52,142 +171,45 @@ Theme::Theme()
|
|||
|
||||
void Theme::update()
|
||||
{
|
||||
this->actuallyUpdate(getMultiplierByTheme(this->themeName.getValue()));
|
||||
|
||||
this->parse();
|
||||
this->updated.invoke();
|
||||
}
|
||||
|
||||
// multiplier: 1 = white, 0.8 = light, -0.8 dark, -1 black
|
||||
void Theme::actuallyUpdate(double multiplier)
|
||||
void Theme::parse()
|
||||
{
|
||||
this->isLight_ = multiplier > 0;
|
||||
|
||||
const auto isLight = this->isLightTheme();
|
||||
|
||||
auto getGray = [multiplier](double l, double a = 1.0) {
|
||||
return QColor::fromHslF(0, 0, ((l - 0.5) * multiplier) + 0.5, a);
|
||||
};
|
||||
|
||||
/// WINDOW
|
||||
#ifdef Q_OS_LINUX
|
||||
this->window.background = isLight ? "#fff" : QColor(61, 60, 56);
|
||||
#else
|
||||
this->window.background = isLight ? "#fff" : "#111";
|
||||
#endif
|
||||
this->window.text = isLight ? "#000" : "#eee";
|
||||
|
||||
/// TABSs
|
||||
if (isLight)
|
||||
QFile file(getThemePath(this->themeName));
|
||||
if (!file.open(QFile::ReadOnly))
|
||||
{
|
||||
this->tabs.regular = {.text = "#444",
|
||||
.backgrounds = {"#fff", "#eee", "#fff"},
|
||||
.line = {"#fff", "#fff", "#fff"}};
|
||||
this->tabs.newMessage = {.text = "#222",
|
||||
.backgrounds = {"#fff", "#eee", "#fff"},
|
||||
.line = {"#bbb", "#bbb", "#bbb"}};
|
||||
this->tabs.highlighted = {.text = "#000",
|
||||
.backgrounds = {"#fff", "#eee", "#fff"},
|
||||
.line = {"#f00", "#f00", "#f00"}};
|
||||
this->tabs.selected = {
|
||||
.text = "#000",
|
||||
.backgrounds = {"#b4d7ff", "#b4d7ff", "#b4d7ff"},
|
||||
.line = {this->accent, this->accent, this->accent}};
|
||||
}
|
||||
else
|
||||
{
|
||||
this->tabs.regular = {.text = "#aaa",
|
||||
.backgrounds{"#252525", "#252525", "#252525"},
|
||||
.line = {"#444", "#444", "#444"}};
|
||||
this->tabs.newMessage = {.text = "#eee",
|
||||
.backgrounds{"#252525", "#252525", "#252525"},
|
||||
.line = {"#888", "#888", "#888"}};
|
||||
this->tabs.highlighted = {.text = "#eee",
|
||||
.backgrounds{"#252525", "#252525", "#252525"},
|
||||
.line = {"#ee6166", "#ee6166", "#ee6166"}};
|
||||
this->tabs.selected = {
|
||||
.text = "#fff",
|
||||
.backgrounds{"#555", "#555", "#555"},
|
||||
.line = {this->accent, this->accent, this->accent}};
|
||||
qCWarning(chatterinoTheme) << "Failed to open" << file.fileName();
|
||||
return;
|
||||
}
|
||||
|
||||
this->tabs.dividerLine = this->tabs.selected.backgrounds.regular;
|
||||
|
||||
// Message
|
||||
this->messages.textColors.caret = isLight ? "#000" : "#fff";
|
||||
this->messages.textColors.regular = isLight ? "#000" : "#fff";
|
||||
this->messages.textColors.link = QColor(66, 134, 244);
|
||||
this->messages.textColors.system = QColor(140, 127, 127);
|
||||
this->messages.textColors.chatPlaceholder =
|
||||
isLight ? QColor(175, 159, 159) : QColor(93, 85, 85);
|
||||
|
||||
this->messages.backgrounds.regular = getGray(1);
|
||||
this->messages.backgrounds.alternate = getGray(0.96);
|
||||
|
||||
this->messages.disabled = getGray(1, 0.6);
|
||||
|
||||
int complementaryGray = isLight ? 20 : 230;
|
||||
this->messages.highlightAnimationStart =
|
||||
QColor(complementaryGray, complementaryGray, complementaryGray, 110);
|
||||
this->messages.highlightAnimationEnd =
|
||||
QColor(complementaryGray, complementaryGray, complementaryGray, 0);
|
||||
|
||||
// Scrollbar
|
||||
this->scrollbars.background = QColor(0, 0, 0, 0);
|
||||
this->scrollbars.thumb = getGray(0.70);
|
||||
this->scrollbars.thumbSelected = getGray(0.65);
|
||||
|
||||
// Selection
|
||||
this->messages.selection =
|
||||
isLight ? QColor(0, 0, 0, 64) : QColor(255, 255, 255, 64);
|
||||
|
||||
// Splits
|
||||
if (isLight)
|
||||
QJsonParseError error{};
|
||||
auto json = QJsonDocument::fromJson(file.readAll(), &error);
|
||||
if (json.isNull())
|
||||
{
|
||||
this->splits.dropTargetRect = QColor(255, 255, 255, 0);
|
||||
qCWarning(chatterinoTheme) << "Failed to parse" << file.fileName()
|
||||
<< "error:" << error.errorString();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->splits.dropTargetRect = QColor(0, 148, 255, 0);
|
||||
}
|
||||
this->splits.dropTargetRectBorder = QColor(0, 148, 255, 0);
|
||||
this->splits.dropPreview = QColor(0, 148, 255, 48);
|
||||
this->splits.dropPreviewBorder = QColor(0, 148, 255);
|
||||
this->splits.resizeHandle = QColor(0, 148, 255, isLight ? 255 : 112);
|
||||
this->splits.resizeHandleBackground =
|
||||
QColor(0, 148, 255, isLight ? 80 : 32);
|
||||
|
||||
this->splits.header.background = getGray(isLight ? 1 : 0.9);
|
||||
this->splits.header.border = getGray(isLight ? 1 : 0.85);
|
||||
this->splits.header.text = this->messages.textColors.regular;
|
||||
this->splits.header.focusedBackground = getGray(isLight ? 0.95 : 0.79);
|
||||
this->splits.header.focusedBorder = getGray(isLight ? 0.90 : 0.78);
|
||||
this->splits.header.focusedText = QColor::fromHsvF(
|
||||
0.58388, isLight ? 1.0 : 0.482, isLight ? 0.6375 : 1.0);
|
||||
this->parseFrom(json.object());
|
||||
}
|
||||
|
||||
void Theme::parseFrom(const QJsonObject &root)
|
||||
{
|
||||
parseColors(root, *this);
|
||||
|
||||
this->isLight_ =
|
||||
root["metadata"]["iconTheme"].toString() == QStringLiteral("dark");
|
||||
|
||||
this->splits.input.background = getGray(0.95);
|
||||
this->splits.input.text = this->messages.textColors.regular;
|
||||
this->splits.input.styleSheet =
|
||||
"background:" + this->splits.input.background.name() + ";" +
|
||||
"border:" + this->tabs.selected.backgrounds.regular.name() + ";" +
|
||||
"color:" + this->messages.textColors.regular.name() + ";" +
|
||||
"selection-background-color:" +
|
||||
(isLight ? "#68B1FF" : this->tabs.selected.backgrounds.regular.name());
|
||||
|
||||
this->splits.messageSeperator =
|
||||
isLight ? QColor(127, 127, 127) : QColor(60, 60, 60);
|
||||
this->splits.background = getGray(1);
|
||||
|
||||
// Copy button
|
||||
if (isLight)
|
||||
{
|
||||
this->buttons.copy = getResources().buttons.copyDark;
|
||||
this->buttons.pin = getResources().buttons.pinDisabledDark;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->buttons.copy = getResources().buttons.copyLight;
|
||||
this->buttons.pin = getResources().buttons.pinDisabledLight;
|
||||
}
|
||||
(this->isLightTheme() ? "#68B1FF"
|
||||
: this->tabs.selected.backgrounds.regular.name());
|
||||
}
|
||||
|
||||
void Theme::normalizeColor(QColor &color) const
|
||||
|
|
|
@ -120,7 +120,9 @@ public:
|
|||
|
||||
private:
|
||||
bool isLight_ = false;
|
||||
void actuallyUpdate(double multiplier);
|
||||
|
||||
void parse();
|
||||
void parseFrom(const QJsonObject &root);
|
||||
|
||||
pajlada::Signals::NoArgSignal repaintVisibleChatWidgets_;
|
||||
|
||||
|
|
Loading…
Reference in a new issue