diff --git a/extra/DefaultTheme.oss b/extra/DefaultTheme.oss index 56c2f46..159d397 100644 --- a/extra/DefaultTheme.oss +++ b/extra/DefaultTheme.oss @@ -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 + } +} % ======================= diff --git a/src/ogfx/gui/Window.cpp b/src/ogfx/gui/Window.cpp index 6568f7f..8b3d26e 100644 --- a/src/ogfx/gui/Window.cpp +++ b/src/ogfx/gui/Window.cpp @@ -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(eCursor::S_Resize)), true }; m_defaultStylesheetVariables["cursor_sw_resize"] = { String("").add(cast(eCursor::SW_Resize)), true }; m_defaultStylesheetVariables["cursor_w_resize"] = { String("").add(cast(eCursor::W_Resize)), true }; + m_defaultStylesheetVariables["cursor_inherit"] = { String("").add(cast(eCursor::NoCursor)), true }; // Colors m_defaultStylesheetVariables["color_transparent"] = { "Color(" + Colors::Transparent.hexString(true, "#") + ")", true }; diff --git a/src/ogfx/gui/Window.hpp b/src/ogfx/gui/Window.hpp index eb5bd96..5ef4828 100644 --- a/src/ogfx/gui/Window.hpp +++ b/src/ogfx/gui/Window.hpp @@ -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); diff --git a/src/ogfx/gui/widgets/Containers.cpp b/src/ogfx/gui/widgets/Containers.cpp index c38fac5..5b83227 100644 --- a/src/ogfx/gui/widgets/Containers.cpp +++ b/src/ogfx/gui/widgets/Containers.cpp @@ -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; } diff --git a/src/ostd/io/Stylesheet.cpp b/src/ostd/io/Stylesheet.cpp index d36f8fc..6381e68 100644 --- a/src/ostd/io/Stylesheet.cpp +++ b/src/ostd/io/Stylesheet.cpp @@ -26,6 +26,7 @@ namespace ostd { Stylesheet::Stylesheet(void) { + // } Stylesheet& Stylesheet::clear(void) @@ -47,10 +48,9 @@ namespace ostd m_values.clear(); stdvec lines = content.tokenize("\n", false, true).getRawData(); stdvec 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 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 newLines; + stdvec 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 Stylesheet::getRichStringLines(const stdvec& lines) - { - stdvec richLines; - for (auto line : lines) - { - ostd::RegexRichString rgxrstr(line); - rgxrstr.fg("\\{|\\}|\\+|\\*|\\-|\\/|\\(|\\)|\\[|\\]", "Red"); //Operators - rgxrstr.fg("0x[0-9A-Fa-f]+|0b[0-1]+|(? getRichStringLines(const stdvec& lines); private: bool parseThemeFileLine(const String& line, const VariableList& variables, bool exitCondition = false); diff --git a/src/test/GuiTest.cpp b/src/test/GuiTest.cpp index 60df6ad..c27d8b8 100644 --- a/src/test/GuiTest.cpp +++ b/src/test/GuiTest.cpp @@ -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(ogfx::WindowCore::eCursor::Pointer)); m_label1.reloadTheme(); m_check1.setText("Check this out!");