Added nested selectors to stylesheets

This commit is contained in:
OmniaX-Dev 2026-04-16 17:44:19 +02:00
parent 40b51bf3dc
commit 777124579f
7 changed files with 116 additions and 47 deletions

View file

@ -30,7 +30,7 @@ window.backgroundColor = rgba(160, 160, 160, 255)
titlebarHeight = 18
titlebarFontSize = 18
titlebarTextAlign = text_left
% scrollSpeed = Vec2(0.8, 0.8)
scrollSpeed = Vec2(0.8, 0.8)
padding = Rect(15, 15, 15, 15)
margin = Rect(0, 0, 0, 0)
}
@ -39,11 +39,25 @@ window.backgroundColor = rgba(160, 160, 160, 255)
% ====== Scrollbar ======
% (scrollbar) {
% (handle) {
% }
% }
(scrollbar) {
width = 20
(handle) {
color = #333333FF
}
(track) {
color = #555555FF
}
}
(scrollbar:handle_hover) {
(handle) {
color = $accentColorDark
}
}
(scrollbar:handle_pressed) {
(handle) {
color = $accentColorDark
}
}
% =======================

View file

@ -142,6 +142,8 @@ namespace ogfx
connectSignal(ostd::BuiltinSignals::FileDragAndDropped);
connectSignal(ostd::BuiltinSignals::TextDragAndDropped);
setCursor(eCursor::Default);
__on_window_init(width, height, title);
setSize(m_windowWidth, m_windowHeight);
}
@ -237,12 +239,41 @@ namespace ogfx
case eCursor::W_Resize:
SDL_SetCursor(m_cursor_W_Resize);
break;
case eCursor::NoCursor:
default:
SDL_SetCursor(m_cursor_Default);
break;
}
}
WindowCore::eCursor WindowCore::getCurosr(void) const
{
auto cur = SDL_GetCursor();
if (cur == m_cursor_Default) return eCursor::Default;
if (cur == m_cursor_Text) return eCursor::Text;
if (cur == m_cursor_Wait) return eCursor::Wait;
if (cur == m_cursor_Crosshair) return eCursor::Crosshair;
if (cur == m_cursor_Progress) return eCursor::Progress;
if (cur == m_cursor_NWSE_Resize) return eCursor::NWSE_Resize;
if (cur == m_cursor_NESW_Resize) return eCursor::NESW_Resize;
if (cur == m_cursor_EW_Resize) return eCursor::EW_Resize;
if (cur == m_cursor_NS_Resize) return eCursor::NS_Resize;
if (cur == m_cursor_Move) return eCursor::Move;
if (cur == m_cursor_NotAllowed) return eCursor::NotAllowed;
if (cur == m_cursor_Pointer) return eCursor::Pointer;
if (cur == m_cursor_NW_Resize) return eCursor::NW_Resize;
if (cur == m_cursor_N_Resize) return eCursor::N_Resize;
if (cur == m_cursor_NE_Resize) return eCursor::NE_Resize;
if (cur == m_cursor_E_Resize) return eCursor::E_Resize;
if (cur == m_cursor_SE_Resize) return eCursor::SE_Resize;
if (cur == m_cursor_S_Resize) return eCursor::S_Resize;
if (cur == m_cursor_SW_Resize) return eCursor::SW_Resize;
if (cur == m_cursor_W_Resize) return eCursor::W_Resize;
return eCursor::Default;
}
void WindowCore::enableResizable(bool enable)
{
SDL_SetWindowResizable(m_window, enable);
@ -443,6 +474,7 @@ namespace ogfx
m_defaultStylesheetVariables["cursor_s_resize"] = { String("").add(cast<i32>(eCursor::S_Resize)), true };
m_defaultStylesheetVariables["cursor_sw_resize"] = { String("").add(cast<i32>(eCursor::SW_Resize)), true };
m_defaultStylesheetVariables["cursor_w_resize"] = { String("").add(cast<i32>(eCursor::W_Resize)), true };
m_defaultStylesheetVariables["cursor_inherit"] = { String("").add(cast<i32>(eCursor::NoCursor)), true };
// Colors
m_defaultStylesheetVariables["color_transparent"] = { "Color(" + Colors::Transparent.hexString(true, "#") + ")", true };

View file

@ -57,7 +57,8 @@ namespace ogfx
SW_Resize,
W_Resize,
Count
Count,
NoCursor = 255
};
public: enum class eTextAlign : u8 {
Default = 0,
@ -74,6 +75,7 @@ namespace ogfx
void setSize(i32 width, i32 height);
void setTitle(const String& title);
void setCursor(eCursor cursor);
eCursor getCurosr(void) const;
void enableResizable(bool enable = true);
void setIcon(const String& iconFilePath);
void setBlockingEventsRefreshFPS(u32 fps);

View file

@ -82,13 +82,13 @@ namespace ogfx
f32 maxScroll = -(ext.h - cont.h);
if (event.mouse->scroll == MouseEventData::eScrollDirection::Down && m_scrollOffset.y > maxScroll)
{
m_scrollOffset -= (m_scrollSpeed * 15.0f);
m_scrollOffset.y -= (m_scrollSpeed.y * 15.0f);
if (m_scrollOffset.y < maxScroll)
m_scrollOffset.y = maxScroll;
}
else if (event.mouse->scroll == MouseEventData::eScrollDirection::Up && m_scrollOffset.y < 0)
{
m_scrollOffset += (m_scrollSpeed * 15.0f);
m_scrollOffset.y += (m_scrollSpeed.y * 15.0f);
if (m_scrollOffset.y > 0)
m_scrollOffset.y = 0;
}

View file

@ -26,6 +26,7 @@ namespace ostd
{
Stylesheet::Stylesheet(void)
{
//
}
Stylesheet& Stylesheet::clear(void)
@ -47,10 +48,9 @@ namespace ostd
m_values.clear();
stdvec<String> lines = content.tokenize("\n", false, true).getRawData();
stdvec<String> originalLines = lines;
auto richLines = getRichStringLines(lines);
u32 lineNumber = 0;
auto l_warn = [&](const String& msg) -> void {
OX_WARN("%s in theme line. File: <%s:%d>", msg.c_str(), filePath.c_str(), lineNumber, originalLines[lineNumber - 1].c_str());
OX_WARN("%s in theme line. File: <%s:%d>\n %s", msg.c_str(), filePath.c_str(), lineNumber, originalLines[lineNumber - 1].c_str());
};
auto l_parseLine = [&](String& line) -> void {
if (!parseThemeFileLine(line, variables))
@ -60,17 +60,18 @@ namespace ostd
String groupSelector = "";
bool groupLines = true;
stdvec<String> group;
u32 groupSelectorCount = 0;
bool debug_print = false;
for (auto& line : lines)
{
lineNumber++;
line.trim();
if (line.startsWith("%"))
goto custom_continue;
continue;
if (line.contains("%"))
line.substr(0, line.indexOf("%")).trim();
if (line == "")
goto custom_continue;
continue;
if (line.startsWith("const ") || line.startsWith("$"))
{
bool is_const = false;
@ -83,29 +84,37 @@ namespace ostd
if (line.count("=") != 1 || line.endsWith("="))
{
l_warn("Invalid variable");
goto custom_continue;
continue;
}
String varName = line.new_substr(0, line.indexOf("=")).trim();
String varValue = line.new_substr(line.indexOf("=") + 1).trim();
if (!varName.regexMatches(m_validNameRegex))
{
l_warn("Invalid variable name");
goto custom_continue;
continue;
}
auto var = variables.find("$" + varName);
if (var != variables.end() && var->second.second)
{
l_warn("Trying to re-assign a const variable");
goto custom_continue;
continue;
}
variables["$" + varName] = { varValue, is_const };
goto custom_continue;
continue;
}
if (groupSelector != "")
{
if (groupLines)
{
if (line == "}")
if (line.endsWith("{"))
{
groupSelectorCount++;
}
else if (line == "}" && groupSelectorCount > 1)
{
groupSelectorCount--;
}
else if (line == "}" && groupSelectorCount == 1)
{
groupLines = false;
auto newLines = parseGroup(groupSelector, group);
@ -117,31 +126,35 @@ namespace ostd
lineNumber++;
}
groupSelector = "";
groupSelectorCount = 0;
group.clear();
goto custom_continue;
continue;
}
group.push_back(line);
}
else
{
if (line == "{")
{
groupLines = true;
groupSelectorCount++;
}
}
goto custom_continue;
continue;
}
if (line.startsWith("("))
{
if (line.count(")") != 1 || line.indexOf(")") < 3)
{
l_warn("Invalid group selector");
goto custom_continue;
continue;
}
String rawSelector = line.new_substr(1, line.indexOf(")")).trim();
groupSelector = parseGroupSelector(rawSelector);
if (groupSelector == "")
{
l_warn("Invalid group selector");
goto custom_continue;
continue;
}
if (line.contains("{"))
{
@ -149,17 +162,15 @@ namespace ostd
if (line != "{")
{
l_warn("Invalid group selector");
goto custom_continue;
continue;
}
groupLines = true;
groupSelectorCount = 1;
}
goto custom_continue;
continue;
}
l_parseLine(line);
continue;
custom_continue:
if (debug_print)
std::cout << String("").add(lineNumber).addLeftPadding(lineNumberMaxWidth, ' ') << "| " << richLines[lineNumber - 1] << "\n";
}
return *this;
}
@ -243,7 +254,6 @@ custom_continue:
(value.startsWith("rgb(") && value.endsWith(")")) ||
(value.startsWith("rgba(") && value.endsWith(")")))
{
return value;
}
return "";
@ -273,7 +283,7 @@ custom_continue:
}
else if (value.startsWith("vec2(") && value.endsWith(")"))
{
value.substr(4, value.len() - 1).trim();
value.substr(5, value.len() - 1).trim();
auto tokens = value.tokenize(",");
if (tokens.count() != 2)
return false;
@ -359,8 +369,35 @@ custom_continue:
if (selector.new_trim() == "" || group.size() == 0)
return {};
stdvec<String> newLines;
stdvec<String> subSelectorStack;
for (const auto& property : group)
newLines.push_back(selector.new_add(".").new_add(property));
{
String p = property.new_trim();
if (p.startsWith("(") && p.lastIndexOf(")") > 1 && p.endsWith("{") && p.len() > 3)
{
String ss = p.substr(1, p.lastIndexOf(")")).trim();
if (!ss.regexMatches(m_validNameRegex))
return {};
subSelectorStack.push_back(ss);
}
else if (p == "}")
{
if (subSelectorStack.size() > 0)
subSelectorStack.pop_back();
else
return {};
}
else
{
String fullSelector = selector;
for (const auto& ss : subSelectorStack)
fullSelector.add(".").add(ss);
newLines.push_back(fullSelector.new_add(".").new_add(property));
}
}
// for (const auto& l : newLines)
// std::cout << l << "\n";
// std::cout << "\n\n\n";
return newLines;
}
@ -391,20 +428,4 @@ custom_continue:
return *p;
return "";
}
stdvec<ostd::RegexRichString> Stylesheet::getRichStringLines(const stdvec<String>& lines)
{
stdvec<ostd::RegexRichString> richLines;
for (auto line : lines)
{
ostd::RegexRichString rgxrstr(line);
rgxrstr.fg("\\{|\\}|\\+|\\*|\\-|\\/|\\(|\\)|\\[|\\]", "Red"); //Operators
rgxrstr.fg("0x[0-9A-Fa-f]+|0b[0-1]+|(?<!\\w)[0-9]+(?!\\w)", "Blue"); //Number Constants
rgxrstr.fg("(?<!\\w)(r[1-9]|r10|fl|pp|rv|fp|sp|ip|acc)(?!\\w)", "BrightGreen", true); //Registers
rgxrstr.fg("\\%low", "Magenta");
rgxrstr.fg("\\$\\w+", "Cyan"); //Labels
richLines.push_back(rgxrstr);
}
return richLines;
}
}

View file

@ -57,7 +57,6 @@ namespace ostd
void debugPrint(void);
String typeVariantToString(const TypeVariant& v);
stdvec<ostd::RegexRichString> getRichStringLines(const stdvec<String>& lines);
private:
bool parseThemeFileLine(const String& line, const VariableList& variables, bool exitCondition = false);

View file

@ -58,6 +58,7 @@ class Window : public ogfx::gui::Window
m_label1.addThemeOverride("@.label.borderColor", Colors::DarkMagenta);
m_label1.addThemeOverride("@:pressed.label.backgroundColor", Colors::Crimson);
m_label1.addThemeOverride("@:hover.label.backgroundColor", Colors::DarkRed);
m_label1.addThemeOverride("@:hover.label.cursor", cast<i32>(ogfx::WindowCore::eCursor::Pointer));
m_label1.reloadTheme();
m_check1.setText("Check this out!");