HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
theme_book.hpp
1// Copyright Take Vos 2020-2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "theme_mode.hpp"
8#include "style_sheet.hpp"
9#include "style_sheet_parser.hpp"
10#include "../log.hpp"
11#include "../trace.hpp"
12#include "../file/glob.hpp"
13#include <limits>
14#include <vector>
15#include <memory>
16#include <filesystem>
17
18namespace hi { inline namespace v1 {
19namespace detail {
20
25public:
26 [[nodiscard]] inline static theme_book& global() noexcept;
27
28 ~theme_book() = default;
29 theme_book(theme_book const&) = delete;
30 theme_book(theme_book&&) = delete;
31 theme_book& operator=(theme_book const&) = delete;
32 theme_book& operator=(theme_book&&) = delete;
33 theme_book() = default;
34
35 void register_theme_directory(std::filesystem::path const& path) noexcept
36 {
37 theme_dirs.push_back(path);
38 refresh();
39 }
40
43 void refresh()
44 {
45 theme_files.clear();
46
47 for (hilet& theme_dir : theme_dirs) {
48 hilet theme_dir_glob = theme_dir / "**" / "*.css";
49 for (hilet& path : glob(theme_dir_glob)) {
50 try {
51 auto style_sheet = hi::parse_style_sheet(path);
52 hi_log_info("Found theme {}:{} at '{}'.", style_sheet.name, style_sheet.mode, path.generic_string());
53
54 theme_files.emplace_back(style_sheet.name, style_sheet.mode, path);
55
56 } catch (std::exception const& e) {
57 hi_log_error("Unable to load theme from file '{}': {}", path.generic_string(), e.what());
58 }
59 }
60 }
61 }
62
69 [[nodiscard]] std::vector<std::string> names() const noexcept
70 {
72
73 for (hilet& theme_file : theme_files) {
74 names.push_back(theme_file.name);
75 }
76
78 hilet new_end = std::unique(names.begin(), names.end());
79 names.erase(new_end, names.cend());
80 return names;
81 }
82
89 [[nodiscard]] std::optional<std::filesystem::path> find(std::string name, theme_mode mode) const noexcept
90 {
91 // First find the exact match.
92 auto it = find_if(theme_files.begin(), theme_files.end(), [&](hilet& entry) {
93 return entry.name == name and entry.mode == mode;
94 });
95
96 if (it != theme_files.end()) {
97 return it->path;
98 }
99
100 // Next find the theme for different modes..
101 it = find_if(theme_files.begin(), theme_files.end(), [&](hilet& entry) {
102 return entry.name == name;
103 });
104
105 if (it != theme_files.end()) {
106 return it->path;
107 }
108
109 return std::nullopt;
110 }
111
112private:
113 struct theme_file_entry {
114 std::string name;
115 hi::theme_mode mode;
116 std::filesystem::path path;
117 };
118
121};
122
123[[nodiscard]] inline theme_book& theme_book::global() noexcept
124{
125 static auto r = theme_book{};
126 return r;
127}
128
129} // namespace detail
130
131inline void register_theme_directory(std::filesystem::path const& path) noexcept
132{
133 return detail::theme_book::global().register_theme_directory(path);
134}
135
142[[nodiscard]] inline std::vector<std::string> theme_names() noexcept
143{
144 return detail::theme_book::global().names();
145}
146
153inline void load_theme(std::string name, theme_mode mode) noexcept
154{
155 static std::optional<std::pair<std::string, theme_mode>> loaded_theme = std::nullopt;
156
157 if (hilet path = detail::theme_book::global().find(name, mode)) {
158 try {
159 auto style_sheet = parse_style_sheet(*path);
161 loaded_theme = {name, mode};
162 hi_log_info(
163 "Theme {}:{} at '{}' activated successfully.", style_sheet.name, style_sheet.mode, path->generic_string());
164
165 } catch (std::exception const& e) {
166 if (loaded_theme) {
167 hi_log_error("Unable to load theme {} from file '{}': {}", name, path->generic_string(), e.what());
168 } else {
169 hi_log_fatal(
170 "Unable to load theme {} from file '{}': {}. No theme loaded.", name, path->generic_string(), e.what());
171 }
172 }
173
174 } else {
175 if (loaded_theme) {
176 hi_log_error("Unable to find a theme matching {}:{}.", name, mode);
177 } else {
178 hi_log_fatal("Unable to find a theme matching {}:{}. No theme loaded.", name, mode);
179 }
180 }
181}
182
183}} // namespace hi::v1
Defines utilities for handling glob patterns.
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
generator< std::filesystem::path > glob(glob_pattern pattern)
Find paths on the filesystem that match the glob pattern.
Definition glob.hpp:875
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
void load_theme(std::string name, theme_mode mode) noexcept
Find a theme matching the name and mode.
Definition theme_book.hpp:153
std::vector< std::string > theme_names() noexcept
Get a list of theme names.
Definition theme_book.hpp:142
Definition style_sheet.hpp:476
void activate() const noexcept
Activate style sheet as the current theme.
Definition style_sheet.hpp:495
theme_book keeps track of multiple themes.
Definition theme_book.hpp:24
void refresh()
Refresh the list of themes from the theme directories.
Definition theme_book.hpp:43
std::vector< std::string > names() const noexcept
Get a list of theme names.
Definition theme_book.hpp:69
std::optional< std::filesystem::path > find(std::string name, theme_mode mode) const noexcept
Find a theme matching the name and mode.
Definition theme_book.hpp:89
T begin(T... args)
T clear(T... args)
T emplace_back(T... args)
T end(T... args)
T erase(T... args)
T push_back(T... args)
T sort(T... args)
T unique(T... args)
T what(T... args)