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 titlebarHeight = 18
titlebarFontSize = 18 titlebarFontSize = 18
titlebarTextAlign = text_left titlebarTextAlign = text_left
% scrollSpeed = Vec2(0.8, 0.8) scrollSpeed = Vec2(0.8, 0.8)
padding = Rect(15, 15, 15, 15) padding = Rect(15, 15, 15, 15)
margin = Rect(0, 0, 0, 0) margin = Rect(0, 0, 0, 0)
} }
@ -39,11 +39,25 @@ window.backgroundColor = rgba(160, 160, 160, 255)
% ====== Scrollbar ====== % ====== Scrollbar ======
% (scrollbar) { (scrollbar) {
% (handle) { 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::FileDragAndDropped);
connectSignal(ostd::BuiltinSignals::TextDragAndDropped); connectSignal(ostd::BuiltinSignals::TextDragAndDropped);
setCursor(eCursor::Default);
__on_window_init(width, height, title); __on_window_init(width, height, title);
setSize(m_windowWidth, m_windowHeight); setSize(m_windowWidth, m_windowHeight);
} }
@ -237,12 +239,41 @@ namespace ogfx
case eCursor::W_Resize: case eCursor::W_Resize:
SDL_SetCursor(m_cursor_W_Resize); SDL_SetCursor(m_cursor_W_Resize);
break; break;
case eCursor::NoCursor:
default: default:
SDL_SetCursor(m_cursor_Default); SDL_SetCursor(m_cursor_Default);
break; 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) void WindowCore::enableResizable(bool enable)
{ {
SDL_SetWindowResizable(m_window, 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_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_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_w_resize"] = { String("").add(cast<i32>(eCursor::W_Resize)), true };
m_defaultStylesheetVariables["cursor_inherit"] = { String("").add(cast<i32>(eCursor::NoCursor)), true };
// Colors // Colors
m_defaultStylesheetVariables["color_transparent"] = { "Color(" + Colors::Transparent.hexString(true, "#") + ")", true }; m_defaultStylesheetVariables["color_transparent"] = { "Color(" + Colors::Transparent.hexString(true, "#") + ")", true };

View file

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

View file

@ -82,13 +82,13 @@ namespace ogfx
f32 maxScroll = -(ext.h - cont.h); f32 maxScroll = -(ext.h - cont.h);
if (event.mouse->scroll == MouseEventData::eScrollDirection::Down && m_scrollOffset.y > maxScroll) 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) if (m_scrollOffset.y < maxScroll)
m_scrollOffset.y = maxScroll; m_scrollOffset.y = maxScroll;
} }
else if (event.mouse->scroll == MouseEventData::eScrollDirection::Up && m_scrollOffset.y < 0) 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) if (m_scrollOffset.y > 0)
m_scrollOffset.y = 0; m_scrollOffset.y = 0;
} }

View file

@ -26,6 +26,7 @@ namespace ostd
{ {
Stylesheet::Stylesheet(void) Stylesheet::Stylesheet(void)
{ {
//
} }
Stylesheet& Stylesheet::clear(void) Stylesheet& Stylesheet::clear(void)
@ -47,10 +48,9 @@ namespace ostd
m_values.clear(); m_values.clear();
stdvec<String> lines = content.tokenize("\n", false, true).getRawData(); stdvec<String> lines = content.tokenize("\n", false, true).getRawData();
stdvec<String> originalLines = lines; stdvec<String> originalLines = lines;
auto richLines = getRichStringLines(lines);
u32 lineNumber = 0; u32 lineNumber = 0;
auto l_warn = [&](const String& msg) -> void { 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 { auto l_parseLine = [&](String& line) -> void {
if (!parseThemeFileLine(line, variables)) if (!parseThemeFileLine(line, variables))
@ -60,17 +60,18 @@ namespace ostd
String groupSelector = ""; String groupSelector = "";
bool groupLines = true; bool groupLines = true;
stdvec<String> group; stdvec<String> group;
u32 groupSelectorCount = 0;
bool debug_print = false; bool debug_print = false;
for (auto& line : lines) for (auto& line : lines)
{ {
lineNumber++; lineNumber++;
line.trim(); line.trim();
if (line.startsWith("%")) if (line.startsWith("%"))
goto custom_continue; continue;
if (line.contains("%")) if (line.contains("%"))
line.substr(0, line.indexOf("%")).trim(); line.substr(0, line.indexOf("%")).trim();
if (line == "") if (line == "")
goto custom_continue; continue;
if (line.startsWith("const ") || line.startsWith("$")) if (line.startsWith("const ") || line.startsWith("$"))
{ {
bool is_const = false; bool is_const = false;
@ -83,29 +84,37 @@ namespace ostd
if (line.count("=") != 1 || line.endsWith("=")) if (line.count("=") != 1 || line.endsWith("="))
{ {
l_warn("Invalid variable"); l_warn("Invalid variable");
goto custom_continue; continue;
} }
String varName = line.new_substr(0, line.indexOf("=")).trim(); String varName = line.new_substr(0, line.indexOf("=")).trim();
String varValue = line.new_substr(line.indexOf("=") + 1).trim(); String varValue = line.new_substr(line.indexOf("=") + 1).trim();
if (!varName.regexMatches(m_validNameRegex)) if (!varName.regexMatches(m_validNameRegex))
{ {
l_warn("Invalid variable name"); l_warn("Invalid variable name");
goto custom_continue; continue;
} }
auto var = variables.find("$" + varName); auto var = variables.find("$" + varName);
if (var != variables.end() && var->second.second) if (var != variables.end() && var->second.second)
{ {
l_warn("Trying to re-assign a const variable"); l_warn("Trying to re-assign a const variable");
goto custom_continue; continue;
} }
variables["$" + varName] = { varValue, is_const }; variables["$" + varName] = { varValue, is_const };
goto custom_continue; continue;
} }
if (groupSelector != "") if (groupSelector != "")
{ {
if (groupLines) if (groupLines)
{ {
if (line == "}") if (line.endsWith("{"))
{
groupSelectorCount++;
}
else if (line == "}" && groupSelectorCount > 1)
{
groupSelectorCount--;
}
else if (line == "}" && groupSelectorCount == 1)
{ {
groupLines = false; groupLines = false;
auto newLines = parseGroup(groupSelector, group); auto newLines = parseGroup(groupSelector, group);
@ -117,31 +126,35 @@ namespace ostd
lineNumber++; lineNumber++;
} }
groupSelector = ""; groupSelector = "";
groupSelectorCount = 0;
group.clear(); group.clear();
goto custom_continue; continue;
} }
group.push_back(line); group.push_back(line);
} }
else else
{ {
if (line == "{") if (line == "{")
{
groupLines = true; groupLines = true;
groupSelectorCount++;
}
} }
goto custom_continue; continue;
} }
if (line.startsWith("(")) if (line.startsWith("("))
{ {
if (line.count(")") != 1 || line.indexOf(")") < 3) if (line.count(")") != 1 || line.indexOf(")") < 3)
{ {
l_warn("Invalid group selector"); l_warn("Invalid group selector");
goto custom_continue; continue;
} }
String rawSelector = line.new_substr(1, line.indexOf(")")).trim(); String rawSelector = line.new_substr(1, line.indexOf(")")).trim();
groupSelector = parseGroupSelector(rawSelector); groupSelector = parseGroupSelector(rawSelector);
if (groupSelector == "") if (groupSelector == "")
{ {
l_warn("Invalid group selector"); l_warn("Invalid group selector");
goto custom_continue; continue;
} }
if (line.contains("{")) if (line.contains("{"))
{ {
@ -149,17 +162,15 @@ namespace ostd
if (line != "{") if (line != "{")
{ {
l_warn("Invalid group selector"); l_warn("Invalid group selector");
goto custom_continue; continue;
} }
groupLines = true; groupLines = true;
groupSelectorCount = 1;
} }
goto custom_continue; continue;
} }
l_parseLine(line); l_parseLine(line);
continue; continue;
custom_continue:
if (debug_print)
std::cout << String("").add(lineNumber).addLeftPadding(lineNumberMaxWidth, ' ') << "| " << richLines[lineNumber - 1] << "\n";
} }
return *this; return *this;
} }
@ -243,7 +254,6 @@ custom_continue:
(value.startsWith("rgb(") && value.endsWith(")")) || (value.startsWith("rgb(") && value.endsWith(")")) ||
(value.startsWith("rgba(") && value.endsWith(")"))) (value.startsWith("rgba(") && value.endsWith(")")))
{ {
return value; return value;
} }
return ""; return "";
@ -273,7 +283,7 @@ custom_continue:
} }
else if (value.startsWith("vec2(") && value.endsWith(")")) 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(","); auto tokens = value.tokenize(",");
if (tokens.count() != 2) if (tokens.count() != 2)
return false; return false;
@ -359,8 +369,35 @@ custom_continue:
if (selector.new_trim() == "" || group.size() == 0) if (selector.new_trim() == "" || group.size() == 0)
return {}; return {};
stdvec<String> newLines; stdvec<String> newLines;
stdvec<String> subSelectorStack;
for (const auto& property : group) 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; return newLines;
} }
@ -391,20 +428,4 @@ custom_continue:
return *p; return *p;
return ""; 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); void debugPrint(void);
String typeVariantToString(const TypeVariant& v); String typeVariantToString(const TypeVariant& v);
stdvec<ostd::RegexRichString> getRichStringLines(const stdvec<String>& lines);
private: private:
bool parseThemeFileLine(const String& line, const VariableList& variables, bool exitCondition = false); 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("@.label.borderColor", Colors::DarkMagenta);
m_label1.addThemeOverride("@:pressed.label.backgroundColor", Colors::Crimson); m_label1.addThemeOverride("@:pressed.label.backgroundColor", Colors::Crimson);
m_label1.addThemeOverride("@:hover.label.backgroundColor", Colors::DarkRed); m_label1.addThemeOverride("@:hover.label.backgroundColor", Colors::DarkRed);
m_label1.addThemeOverride("@:hover.label.cursor", cast<i32>(ogfx::WindowCore::eCursor::Pointer));
m_label1.reloadTheme(); m_label1.reloadTheme();
m_check1.setText("Check this out!"); m_check1.setText("Check this out!");