### Basic Visage Application Window Example (C++) Source: https://github.com/vitalaudio/visage/blob/main/README.md Demonstrates the fundamental structure of a Visage application. It initializes an application window, sets up a drawing callback to fill the window with a color, and then displays and runs the event loop. This example requires the Visage library. ```cpp #include int main() { visage::ApplicationWindow app; app.onDraw() = [&app](visage::Canvas& canvas) { canvas.setColor(0xffff00ff); canvas.fill(0, 0, app.width(), app.height()); }; app.show(800, 600); // Opens as 800 x 600 pixel window app.runEventLoop(); // Runs window events. Returns when window is closed. return 0; } ``` -------------------------------- ### Build CLAP Plugin Example in Visage CMake Source: https://github.com/vitalaudio/visage/blob/main/examples/CMakeLists.txt Builds a CLAP plugin example, fetching the CLAP SDK and helpers if not building for Emscripten. It includes platform-specific configurations for macOS bundles and Linux/Windows plugin suffixes. ```cmake if (NOT EMSCRIPTEN) message(STATUS "VISAGE: Downloading CLAP SDK for plugin example") FetchContent_Declare(clap GIT_REPOSITORY https://github.com/free-audio/clap.git GIT_TAG main GIT_SHALLOW TRUE EXCLUDE_FROM_ALL ) FetchContent_Declare(clap_helpers GIT_REPOSITORY https://github.com/free-audio/clap-helpers.git GIT_TAG main GIT_SHALLOW TRUE EXCLUDE_FROM_ALL ) FetchContent_MakeAvailable(clap) FetchContent_MakeAvailable(clap_helpers) file(GLOB SOURCE_FILES ClapPlugin/*.cpp) file(GLOB HEADER_FILES ClapPlugin/*.h) add_library(ExampleClapPlugin MODULE ${SOURCE_FILES} ${HEADER_FILES}) if (APPLE) set(EXAMPLE_NAME ExampleClapPlugin) configure_file(Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/ClapPlugin/ExampleInfo.plist) set_target_properties(ExampleClapPlugin PROPERTIES BUNDLE TRUE BUNDLE_EXTENSION clap OUTPUT_NAME "ExampleClapPlugin" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/ClapPlugin/ExampleInfo.plist" ) else () set_target_properties(ExampleClapPlugin PROPERTIES SUFFIX ".clap" PREFIX "") endif () target_link_libraries(ExampleClapPlugin PRIVATE visage EmbeddedShaderResources EmbeddedFontResources EmbeddedIconResources EmbeddedImageResources clap clap-helpers ) endif () ``` -------------------------------- ### Build Example Executables in Visage CMake Source: https://github.com/vitalaudio/visage/blob/main/examples/CMakeLists.txt Builds example executables from C++ source and header files found in subdirectories. It includes platform-specific configurations for Windows, macOS, and Emscripten. ```cmake foreach (EXAMPLE ${EXAMPLES}) file(GLOB SOURCE_FILES ${EXAMPLE}/*.cpp) file(GLOB HEADER_FILES ${EXAMPLE}/*.h) if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${EXAMPLE}" AND SOURCE_FILES AND NOT EXAMPLE STREQUAL "ClapPlugin") add_executable(Example${EXAMPLE} main.cpp ${SOURCE_FILES} ${HEADER_FILES}) if (WIN32) set_target_properties(Example${EXAMPLE} PROPERTIES WIN32_EXECUTABLE YES) elseif (APPLE) set(EXAMPLE_NAME Example${EXAMPLE}) configure_file(Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE}/ExampleInfo.plist) set_target_properties(Example${EXAMPLE} PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE}/ExampleInfo.plist ) elseif (EMSCRIPTEN) target_link_options(Example${EXAMPLE} PRIVATE --shell-file ${CMAKE_CURRENT_SOURCE_DIR}/emscripten_template.html -sGL_ENABLE_GET_PROC_ADDRESS -sALLOW_MEMORY_GROWTH --bind "-sEXPORTED_FUNCTIONS=['_main', '_pasteCallback']" "-sEXPORTED_RUNTIME_METHODS=['ccall', 'cwrap', 'UTF8ToString']" ) set_target_properties(Example${EXAMPLE} PROPERTIES SUFFIX ".html" OUTPUT_NAME "index" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/builds/${EXAMPLE}" ) endif () target_link_libraries(Example${EXAMPLE} PRIVATE visage EmbeddedShaderResources EmbeddedFontResources EmbeddedIconResources EmbeddedImageResources ) endif () endforeach () ``` -------------------------------- ### Create Button Widgets in C++ Source: https://context7.com/vitalaudio/visage/llms.txt Provides examples for creating text buttons, icon buttons, and toggle buttons. It demonstrates how to handle user interactions through callback functions and configure button styling. ```cpp #include #include visage::UiButton textButton("Click Me"); textButton.setFont(visage::Font(16, resources::fonts::Lato_Regular_ttf)); textButton.onToggle() = [](visage::Button* button, bool on) { std::cout << "Button clicked!" << std::endl; }; visage::IconButton iconButton(resources::icons::check_circle_svg, true); iconButton.setMargin(visage::Dimension::logicalPixels(8)); visage::ToggleTextButton toggle("Enable Feature"); toggle.setToggled(true); toggle.onToggle() = [](visage::Button* button, bool on) { auto* toggle = static_cast(button); std::cout << "Toggle is now: " << (toggle->toggled() ? "ON" : "OFF") << std::endl; }; ``` -------------------------------- ### Visage Color and Gradient System Source: https://context7.com/vitalaudio/visage/llms.txt Demonstrates how to use Visage's color and gradient system for drawing. Supports solid colors from various formats (hex, ARGB, HSV) and different gradient types (linear, radial, multi-color, scientific colormaps). Includes examples of gradient repeat and reflect patterns, and custom gradient generation. ```cpp #include app.onDraw() = [&](visage::Canvas& canvas) { // Solid colors from various formats canvas.setColor(0xffff0000); // ARGB hex canvas.setColor(visage::Color(1.0f, 1.0f, 0.0f, 0.0f, 1.0f)); // alpha, r, g, b, hdr canvas.setColor(visage::Color::fromAHSV(1.0f, 180.0f, 1.0f, 1.0f)); // HSV canvas.setColor(visage::Color::fromHexString("#ff00ff")); // Hex string // Linear gradient between two points visage::Point from(0, 0); visage::Point to(app.width(), app.height()); visage::Gradient twoColor(0xffffff00, 0xff00aaff); canvas.setColor(visage::Brush::linear(twoColor, from, to)); canvas.fill(0, 0, app.width(), app.height() * 0.25f); // Radial gradient from center visage::Point center(app.width() * 0.5f, app.height() * 0.5f); canvas.setColor(visage::Brush::radial(twoColor, center, 200.0f)); canvas.circle(center.x - 100, app.height() * 0.25f, 200); // Multi-color rainbow gradient visage::Gradient rainbow(0xffff0000, 0xffffff00, 0xff00ff00, 0xff00ffff, 0xff0000ff, 0xffff00ff, 0xffff0000); canvas.setColor(visage::Brush::horizontal(rainbow)); canvas.fill(0, app.height() * 0.5f, app.width(), 50); // Built-in scientific colormap (Viridis) canvas.setColor(visage::Brush::horizontal(visage::Gradient::kViridis)); canvas.fill(0, app.height() * 0.6f, app.width(), 50); // Gradient with repeat/reflect patterns visage::Gradient repeating(0xffffff00, 0xff00aaff); repeating.setRepeat(true); // Tiles the gradient // or: repeating.setReflect(true); // Mirror pattern canvas.setColor(visage::Brush::linear(repeating, from, to)); canvas.fill(0, app.height() * 0.75f, app.width(), app.height() * 0.25f); // Custom gradient from sample function auto oklab = [](float t) { // Custom color sampling logic return visage::Color(1.0f, t, 1.0f - t, 0.5f); }; visage::Gradient custom = visage::Gradient::fromSampleFunction(100, oklab); }; ``` -------------------------------- ### Implement Mouse and Keyboard Event Handling in C++ Source: https://context7.com/vitalaudio/visage/llms.txt Demonstrates how to override visage::ApplicationWindow methods to handle mouse movement, clicks, dragging, scrolling, and keyboard input. It includes examples of managing cursor visibility and relative mouse modes for interactive applications. ```cpp #include class InteractiveEditor : public visage::ApplicationWindow { public: void draw(visage::Canvas& canvas) override { canvas.setColor(0xff000000); canvas.fill(0, 0, width(), height()); canvas.setColor(isPressed_ ? 0xff00ffff : 0xffffffff); canvas.circle(mouseX_ - 20, mouseY_ - 20, 40); } void mouseMove(const visage::MouseEvent& e) override { mouseX_ = e.position.x; mouseY_ = e.position.y; redraw(); } void mouseDrag(const visage::MouseEvent& e) override { mouseX_ = e.position.x; mouseY_ = e.position.y; redraw(); } void mouseDown(const visage::MouseEvent& e) override { if (e.isLeftButton()) { isPressed_ = true; redraw(); } if (e.isMiddleButton()) { setMouseRelativeMode(true); setCursorVisible(false); } } void mouseUp(const visage::MouseEvent& e) override { if (e.isMiddleButton()) { setMouseRelativeMode(false); setCursorVisible(true); } isPressed_ = false; redraw(); } void mouseExit(const visage::MouseEvent& e) override { mouseX_ = -100; mouseY_ = -100; redraw(); } bool mouseWheel(const visage::MouseEvent& e) override { return true; } bool keyPress(const visage::KeyEvent& e) override { if (e.key == visage::KeyCode::Escape) { close(); return true; } if (e.modifiers.ctrl && e.key == visage::KeyCode::S) { return true; } return false; } void textInput(const std::string& text) override {} bool receivesTextInput() override { return true; } private: float mouseX_ = 0, mouseY_ = 0; bool isPressed_ = false; }; ``` -------------------------------- ### Create and Show Native Window with Visage ApplicationWindow Source: https://context7.com/vitalaudio/visage/llms.txt Demonstrates how to create a native window using Visage's ApplicationWindow class. It sets the window title, defines a drawing callback to render graphics using the Canvas API, and shows the window with specified dimensions, including an option for DPI-aware sizing. The application then enters an event loop. ```cpp #include int main() { visage::ApplicationWindow app; // Set window title app.setTitle("My Visage Application"); // Handle drawing with Canvas app.onDraw() = [&app](visage::Canvas& canvas) { // Fill background with dark blue canvas.setColor(0xff000066); canvas.fill(0, 0, app.width(), app.height()); // Draw a cyan circle in the center float radius = app.height() * 0.1f; float x = app.width() * 0.5f - radius; float y = app.height() * 0.5f - radius; canvas.setColor(0xff00ffff); canvas.circle(x, y, 2.0f * radius); }; // Show window with specific dimensions app.show(800, 600); // Or use logical pixels for DPI-aware sizing app.show(visage::Dimension::logicalPixels(800), visage::Dimension::logicalPixels(600)); // Run the event loop (blocks until window is closed) app.runEventLoop(); return 0; } ``` -------------------------------- ### Implement Flexbox Layouts Source: https://context7.com/vitalaudio/visage/llms.txt Shows how to enable and configure the flexbox-inspired layout system in Visage. This includes setting padding, gaps, flex growth factors, and nesting layouts to create responsive UI structures. ```cpp #include #include using namespace visage::dimension; int main() { visage::ApplicationWindow app; app.layout().setFlex(true); app.layout().setFlexGap(8); app.layout().setPadding(16); visage::Frame row1, row2, row3; row1.layout().setFlexGrow(1.0f); row2.layout().setFlexGrow(2.0f); row3.layout().setFlexGrow(1.0f); row1.layout().setHeight(visage::Dimension::logicalPixels(100)); app.addChild(&row1); app.addChild(&row2); app.addChild(&row3); row2.layout().setFlex(true); row2.layout().setFlexRows(false); row2.layout().setFlexGap(4_px); visage::UiButton btn1("Button 1"), btn2("Button 2"), btn3("Button 3"); btn1.layout().setFlexGrow(1.0f); btn2.layout().setFlexGrow(1.0f); btn3.layout().setFlexGrow(1.0f); row2.addChild(&btn1); row2.addChild(&btn2); row2.addChild(&btn3); btn2.layout().setMargin(4_px); app.layout().setFlexItemAlignment(visage::Layout::ItemAlignment::Center); app.layout().setFlexWrapAlignment(visage::Layout::WrapAlignment::SpaceBetween); app.layout().setFlexWrap(true); app.show(80_vmin, 60_vmin); app.runEventLoop(); } ``` -------------------------------- ### Create Custom UI Components with Frame Source: https://context7.com/vitalaudio/visage/llms.txt Demonstrates how to extend the base Frame class to implement custom drawing logic, event handling for mouse interactions, and layout management. It also covers visibility, transparency, and caching settings for UI elements. ```cpp #include class CustomFrame : public visage::Frame { public: void draw(visage::Canvas& canvas) override { canvas.setColor(isHovered_ ? 0xff00ff00 : 0xff888888); canvas.roundedRectangle(0, 0, width(), height(), 8.0f); } void mouseEnter(const visage::MouseEvent& e) override { isHovered_ = true; redraw(); } void mouseExit(const visage::MouseEvent& e) override { isHovered_ = false; redraw(); } void mouseDown(const visage::MouseEvent& e) override { if (e.isLeftButton()) {} if (e.shouldTriggerPopup()) {} } void resized() override {} private: bool isHovered_ = false; }; int main() { visage::ApplicationWindow app; CustomFrame child1, child2; app.addChild(&child1); app.addChild(&child2); app.onResize() = [&]() { child1.setBounds(10, 10, 200, 100); child2.setBounds(10, 120, 200, 100); }; child1.setVisible(true); child1.setDrawing(true); child1.setOnTop(true); child2.setAlphaTransparency(0.5f); child1.setBlurRadius(5.0f); child2.setCached(true); app.show(800, 600); app.runEventLoop(); } ``` -------------------------------- ### Dependency Fetching with FetchContent (CMake) Source: https://github.com/vitalaudio/visage/blob/main/visage_graphics/CMakeLists.txt This snippet uses the `FetchContent` module to download and make available external dependencies, specifically 'bgfx' and 'freetype', from their respective Git repositories. It sets shallow clones and specific Git tags for reproducibility. ```cmake message(STATUS "VISAGE: Downloading graphics dependencies") set(CMAKE_MESSAGE_LOG_LEVEL "ERROR") FetchContent_Declare(bgfx GIT_REPOSITORY https://github.com/bkaradzic/bgfx.cmake.git GIT_SHALLOW TRUE GIT_TAG v1.129.8958-499 EXCLUDE_FROM_ALL ) FetchContent_MakeAvailable(bgfx) FetchContent_Declare(freetype GIT_REPOSITORY https://gitlab.freedesktop.org/freetype/freetype.git GIT_SHALLOW TRUE GIT_TAG VER-2-14-1 EXCLUDE_FROM_ALL ) FetchContent_MakeAvailable(freetype) set(CMAKE_MESSAGE_LOG_LEVEL "NOTICE") ``` -------------------------------- ### Render Unicode Text and Fonts in C++ Source: https://context7.com/vitalaudio/visage/llms.txt Explains how to load custom fonts and render text with various justifications and orientations. It also covers DPI-aware font scaling to ensure consistent rendering across different display densities. ```cpp #include #include visage::Font titleFont(32, resources::fonts::Lato_Regular_ttf); visage::Font bodyFont(16, resources::fonts::DroidSansMono_ttf); app.onDraw() = [&](visage::Canvas& canvas) { canvas.setColor(0xffffffff); canvas.text("Centered Title", titleFont, visage::Font::kCenter, 0, 0, app.width(), 50); canvas.text("Left aligned", bodyFont, visage::Font::kLeft, 10, 60, app.width() - 20, 30); canvas.text("Right aligned", bodyFont, visage::Font::kRight, 10, 100, app.width() - 20, 30); canvas.text("Rotated", bodyFont, visage::Font::kCenter, 0, 0, 50, app.height(), visage::Direction::Right); visage::Font scaledFont = titleFont.withDpiScale(app.dpiScale()); canvas.text("DPI Scaled", scaledFont, visage::Font::kCenter, 0, 150, app.width(), 50); }; ``` -------------------------------- ### Apply Blend Modes and Frame Compositing in C++ Source: https://context7.com/vitalaudio/visage/llms.txt Shows how to utilize different blend modes like Alpha, Additive, and Subtractive for rendering. It also demonstrates frame-level masking and global transparency settings for complex UI composition. ```cpp #include app.onDraw() = [&](visage::Canvas& canvas) { canvas.setBlendMode(visage::BlendMode::Alpha); canvas.setColor(0xff222222); canvas.fill(0, 0, width, height); canvas.setBlendMode(visage::BlendMode::Add); canvas.setColor(0xffff0000); canvas.circle(100, 100, 80); canvas.setColor(0xff00ff00); canvas.circle(130, 100, 80); canvas.setColor(0xff0000ff); canvas.circle(115, 130, 80); canvas.setBlendMode(visage::BlendMode::Sub); canvas.setColor(0xffff0000); canvas.circle(300, 100, 80); }; visage::Frame maskedFrame; maskedFrame.setMasked(true); maskedFrame.onDraw() = [&](visage::Canvas& canvas) { canvas.setColor(0xffff00ff); canvas.fill(0, 0, width, height); canvas.setBlendMode(visage::BlendMode::MaskRemove); canvas.setColor(0xffffffff); canvas.fill(0, 0, width, height); canvas.setBlendMode(visage::BlendMode::MaskAdd); canvas.setColor(0xffffffff); canvas.circle(width/2 - 50, height/2 - 50, 100); canvas.setBlendMode(visage::BlendMode::Alpha); }; visage::Frame transparentFrame; transparentFrame.setAlphaTransparency(0.5f); ``` -------------------------------- ### Visage Path Drawing and Vector Graphics Source: https://context7.com/vitalaudio/visage/llms.txt Illustrates how to create and manipulate paths in Visage for vector graphics. Covers procedural path creation (e.g., stars), stroking with custom widths and styles, animated dashed strokes, boolean path operations (combination), and path transformations (scaling, translation, rotation). ```cpp #include #include // Create a star path procedurally visage::Path createStarPath(float cx, float cy, float radius) { static constexpr float kPi = 3.14159265f; visage::Path path; int numPoints = 10; for (int i = 0; i < numPoints; ++i) { float angle = (float)i / numPoints * 2.0f * kPi; float r = (i % 2) ? radius : radius * 0.4f; visage::Point point(cx + r * std::sin(angle), cy + r * std::cos(angle)); if (i == 0) path.moveTo(point); else path.lineTo(point); } path.close(); return path; } app.onDraw() = [&](visage::Canvas& canvas) { canvas.setColor(0xff222222); canvas.fill(0, 0, app.width(), app.height()); // Create and fill a path visage::Path star = createStarPath(100, 100, 80); canvas.setColor(0xffff44ff); canvas.fill(star); // Stroke a path with custom settings visage::Path stroked = star.stroke( 3.0f, // stroke width visage::Path::Join::Round, // join style: Round, Miter, Bevel, Square visage::Path::EndCap::Round // end cap: Round, Square, Butt ); canvas.fill(stroked, 220, 0); // draw at offset // Animated dashed stroke float segment = star.length() / 40.0f; visage::Path dashed = star.stroke( 2.0f, visage::Path::Join::Round, visage::Path::EndCap::Round, { segment }, // dash array canvas.time() * segment // animated dash offset ); canvas.fill(dashed, 340, 0); // Path operations visage::Path rect; rect.addRoundedRectangle(0, 0, 100, 100, 10); visage::Path circle; circle.addCircle(50, 50, 40); // Boolean combination visage::Path combined = rect.combine(circle, visage::Path::FillRule::EvenOdd); canvas.fill(combined, 0, 200); // Transform paths visage::Path scaled = star.scaled(0.5f); visage::Path translated = star.translated(100, 200); visage::Path rotated = star.rotated(0.5f); // radians app.redraw(); // Request continuous animation }; ``` -------------------------------- ### Implement Post-Processing Effects and Shaders in C++ Source: https://context7.com/vitalaudio/visage/llms.txt Demonstrates how to apply custom shaders, built-in blur effects, and backdrop glass effects to UI frames. It showcases the use of ShaderPostEffect and BlurPostEffect classes to manipulate frame rendering. ```cpp #include #include visage::ShaderPostEffect grayScale(resources::shaders::vs_custom, resources::shaders::fs_gray_scale); visage::ShaderPostEffect sepia(resources::shaders::vs_custom, resources::shaders::fs_sepia); visage::BlurPostEffect blur; blur.setBlurRadius(40.0f); visage::Frame contentFrame; contentFrame.setPostEffect(&grayScale); visage::Frame glassFrame; visage::BlurPostEffect backdropBlur; backdropBlur.setBlurRadius(30.0f); glassFrame.setBackdropEffect(&backdropBlur); glassFrame.onDraw() = [&](visage::Canvas& canvas) { canvas.setColor(0x44ffffff); canvas.fill(0, 0, glassFrame.width(), glassFrame.height()); canvas.setColor(visage::Brush::vertical(0x44ffffff, 0x44000000)); canvas.roundedRectangleBorder(0, 0, width, height, radius, 2.0f); }; ``` -------------------------------- ### Configure CMake Project and Build Options Source: https://github.com/vitalaudio/visage/blob/main/CMakeLists.txt Initializes the CMake project, sets C++ standards, and defines build-time options such as address sanitizers and feature toggles. It also handles platform-specific requirements like enabling Objective-C/C++ on macOS. ```cmake cmake_minimum_required(VERSION 3.17) project(visage VERSION 0.1.0) if (APPLE) enable_language(OBJC) enable_language(OBJCXX) endif () option(VISAGE_ADDRESS_SANITIZER "Enable AddressSanitizer" OFF) if (VISAGE_ADDRESS_SANITIZER) if (MSVC) add_compile_options(/fsanitize=address /Zi) add_link_options(/fsanitize=address) else () add_compile_options(-fsanitize=address -fno-omit-frame-pointer) add_link_options(-fsanitize=address) endif () endif () ``` -------------------------------- ### Implement Animated Frame with Smooth Transitions in C++ Source: https://context7.com/vitalaudio/visage/llms.txt This C++ code demonstrates how to create an animated frame using Visage. It configures an animation for smooth value interpolation, interpolates colors based on the animation value, and handles mouse events to trigger animations. The `redraw()` function is called to request subsequent frames when animations are in progress. ```cpp #include #include class AnimatedFrame : public visage::Frame { public: AnimatedFrame() { // Configure animation hoverAnimation_.setTargetValue(0.0f); hoverAnimation_.setSnapToTarget(false); // Smooth interpolation } void draw(visage::Canvas& canvas) override { float hover = hoverAnimation_.value(); // Interpolate colors based on animation value visage::Color baseColor(0xff444444); visage::Color hoverColor(0xff00ffff); visage::Color current = baseColor.interpolateWith(hoverColor, hover); canvas.setColor(current); canvas.roundedRectangle(0, 0, width(), height(), 10.0f); // Request redraw if animating if (!hoverAnimation_.isComplete()) redraw(); } void mouseEnter(const visage::MouseEvent& e) override { hoverAnimation_.setTargetValue(1.0f); redraw(); } void mouseExit(const visage::MouseEvent& e) override { hoverAnimation_.setTargetValue(0.0f); redraw(); } private: visage::Animation hoverAnimation_; }; ``` -------------------------------- ### Configure Platform-Specific Build Targets in CMake Source: https://github.com/vitalaudio/visage/blob/main/visage_windowing/CMakeLists.txt This snippet detects the host operating system to include appropriate source files and system libraries. It then aggregates these files to create the VisageWindowing object library with the necessary include directories and link dependencies. ```cmake if (EMSCRIPTEN) file(GLOB PLATFORM_SOURCE_FILES emscripten/*.cpp) file(GLOB PLATFORM_HEADER_FILES emscripten/*.h) elseif (WIN32) file(GLOB PLATFORM_SOURCE_FILES win32/*.cpp) file(GLOB PLATFORM_HEADER_FILES win32/*.h) set(WIN_LIBS dxgi Shell32) elseif (APPLE) file(GLOB PLATFORM_SOURCE_FILES macos/*.mm) file(GLOB PLATFORM_HEADER_FILES macos/*.h) elseif (UNIX) file(GLOB PLATFORM_SOURCE_FILES linux/*.cpp) file(GLOB PLATFORM_HEADER_FILES linux/*.h) find_package(X11 REQUIRED) set(X11_LIBS ${X11_LIBRARIES} ${X11_Xrandr_LIB}) set(X11_INCLUDES ${X11_INCLUDE_DIR} ${Xrandr_INCLUDE_DIR}) endif () file(GLOB HEADERS *.h) file(GLOB SOURCE_FILES *.cpp) amalgamate_headers(${VISAGE_INCLUDE}/visage/windowing.h "${HEADERS}") list(APPEND HEADERS ${VISAGE_INCLUDE}/visage/windowing.h) add_library(VisageWindowing OBJECT ${SOURCE_FILES} ${PLATFORM_SOURCE_FILES} ${HEADERS} ${PLATFORM_HEADER_FILES}) target_include_directories(VisageWindowing PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${VISAGE_INCLUDE_PATH} ${X11_INCLUDES} ) target_link_libraries(VisageWindowing PRIVATE ${X11_LIBS} ${WIN_LIBS}) set_target_properties(VisageWindowing PROPERTIES FOLDER "visage") if (APPLE) target_compile_options(VisageWindowing PRIVATE -fobjc-arc) endif () ``` -------------------------------- ### Configure TextEditor widget in Visage Source: https://context7.com/vitalaudio/visage/llms.txt The TextEditor widget supports multi-line input, password masking, and character limits. It provides callback mechanisms for text changes and key events to handle user interaction. ```cpp #include #include visage::TextEditor editor; // Configure appearance editor.setFont(visage::Font(14, resources::fonts::DroidSansMono_ttf)); editor.setBackgroundRounding(8.0f); editor.setMargin(10.0f, 8.0f); // Configure behavior editor.setMultiLine(true); // Multi-line editing editor.setMaxCharacters(1000); // Character limit editor.setSelectOnFocus(true); // Select all on focus editor.setDefaultText("Enter text here..."); // Set initial text editor.setText("Hello, World!"); // Callbacks editor.onTextChange() = []() { std::cout << "Text changed!" << std::endl; }; editor.onEnterKey() = []() { std::cout << "Enter pressed!" << std::endl; }; editor.onEscapeKey() = []() { std::cout << "Escape pressed!" << std::endl; }; // Get current text visage::String currentText = editor.text(); // Password input visage::TextEditor passwordEditor; passwordEditor.setPassword('*'); // Mask character // Number-only input visage::TextEditor numberEditor; numberEditor.setNumberEntry(); // Single-line text field visage::TextEditor fieldEditor; fieldEditor.setTextFieldEntry(); fieldEditor.setJustification(visage::Font::kLeft); app.addChild(&editor); ``` -------------------------------- ### Visage Canvas Drawing API: Shapes and Primitives Source: https://context7.com/vitalaudio/visage/llms.txt Illustrates the extensive drawing capabilities of the Visage Canvas API. This snippet shows how to draw various shapes like rectangles, rounded rectangles, circles, rings, arcs, triangles, and lines. It also demonstrates drawing Bezier curves, squircles, and applying shadows, all with customizable colors and styles. ```cpp app.onDraw() = [&app](visage::Canvas& canvas) { // Set solid colors using ARGB hex format canvas.setColor(0xff222222); canvas.fill(0, 0, app.width(), app.height()); // Draw filled rectangles and rounded rectangles canvas.setColor(0xffff0000); canvas.rectangle(10, 10, 100, 50); canvas.roundedRectangle(120, 10, 100, 50, 10.0f); // Draw circles and rings canvas.setColor(0xff00ff00); canvas.circle(50, 100, 40); // x, y, diameter canvas.ring(150, 100, 40, 5); // x, y, diameter, thickness // Draw arcs (rounded and flat) canvas.setColor(0xff0000ff); canvas.roundedArc(250, 100, 60, 8, 0.0f, 3.14f); // x, y, width, thickness, center_radians, radians canvas.flatArc(350, 100, 60, 8, 0.0f, 3.14f); // Draw triangles canvas.setColor(0xffffff00); canvas.triangle(50, 200, 100, 200, 75, 150); canvas.triangleUp(150, 180, 20); canvas.triangleDown(200, 150, 20); canvas.triangleLeft(230, 165, 20); canvas.triangleRight(280, 165, 20); // Draw line segments and quadratic curves canvas.setColor(0xffff00ff); canvas.segment(10, 250, 100, 300, 3.0f, true); // rounded ends canvas.quadratic(120, 250, 160, 220, 200, 250, 2.0f); // quadratic bezier // Draw squircles (super ellipses) canvas.setColor(0xff00ffff); canvas.squircle(250, 250, 60, 4.0f); // x, y, width, power // Draw shadows canvas.setColor(0x66000000); canvas.roundedRectangleShadow(350, 240, 80, 50, 8.0f, 10.0f); }; ``` -------------------------------- ### Setting Include Directories (CMake) Source: https://github.com/vitalaudio/visage/blob/main/visage_graphics/CMakeLists.txt Configures the include directories for the 'VisageGraphics' target. It adds both private and system include paths, including paths to the Visage headers, freetype, bgfx, bx, and bimg, as well as local source directories. ```cmake target_include_directories(VisageGraphics PRIVATE ${VISAGE_INCLUDE_PATH} ${freetype_SOURCE_DIR}/include ${BGFX_DIR}/include ${BGFX_DIR}/3rdparty ${BX_DIR}/include ${BIMG_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR} ) target_include_directories(VisageGraphics SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/ ${CMAKE_CURRENT_SOURCE_DIR}/third_party/bgfx/3rdparty ${CMAKE_CURRENT_SOURCE_DIR}/third_party/bgfx/include ${CMAKE_CURRENT_SOURCE_DIR}/third_party/bgfx/tools ${CMAKE_CURRENT_SOURCE_DIR}/third_party/bx/include ${CMAKE_CURRENT_SOURCE_DIR}/third_party/bimg/include ) ``` -------------------------------- ### Globbing Files in CMake Source: https://github.com/vitalaudio/visage/blob/main/visage_ui/CMakeLists.txt Uses the 'file(GLOB ...)' command to find all files matching a pattern in the current directory. This is a convenient way to include multiple header or source files without listing them individually. ```cmake file(GLOB HEADERS *.h) file(GLOB SOURCE_FILES *.cpp) ``` -------------------------------- ### Platform-Specific File Globbing in CMake Source: https://github.com/vitalaudio/visage/blob/main/visage_utils/CMakeLists.txt This CMake code snippet dynamically selects header and source files based on the operating system (WIN32 or POSIX). It uses `file(GLOB ...)` to find files matching patterns in platform-specific directories. ```cmake if (WIN32) file(GLOB PLATFORM_HEADER_FILES win32/*.h) file(GLOB PLATFORM_SOURCE_FILES win32/*.cpp) else () file(GLOB PLATFORM_HEADER_FILES posix/*.h) file(GLOB PLATFORM_SOURCE_FILES posix/*.cpp) endif () file(GLOB HEADERS *.h ${PLATFORM_HEADER_FILES}) file(GLOB SOURCE_FILES *.cpp ${PLATFORM_SOURCE_FILES}) ``` -------------------------------- ### Amalgamate Source and Header Files Source: https://github.com/vitalaudio/visage/blob/main/CMakeLists.txt Provides utility functions to combine multiple source or header files into single amalgamated files. This is useful for reducing build complexity and improving compilation times. ```cmake function(amalgamate_headers AMALGAMATED_HEADER_NAME FILE_HEADERS) set(FILE_CONTENTS "// Auto generated amalgamated header.\n#pragma once\n") foreach (FILE ${FILE_HEADERS}) set(FILE_CONTENTS "${FILE_CONTENTS}#include \"${FILE}\"\n") endforeach () file(CONFIGURE OUTPUT "${AMALGAMATED_HEADER_NAME}" CONTENT "${FILE_CONTENTS}") endfunction() function(amalgamate_sources GENERATED_FILES AMALGAMATED_SOURCE_BASE FILE_SOURCES) # Implementation logic to group files into chunks of 7 # ... (omitted for brevity) endfunction() ``` -------------------------------- ### Platform-Specific Source File Inclusion (CMake) Source: https://github.com/vitalaudio/visage/blob/main/visage_graphics/CMakeLists.txt This snippet conditionally appends platform-specific source files to the main source list based on the operating system (Windows, macOS, or Unix). It also defines platform-specific libraries for Windows and macOS. ```cmake if (WIN32) list(APPEND SOURCE_FILES win32/emoji_win32.cpp) set(WIN_LIBS d2d1 dwrite Windowscodecs) elseif (APPLE) list(APPEND SOURCE_FILES macos/emoji_macos.cpp) list(APPEND PLATFORM_FILES macos/windowless_context.mm) elseif (UNIX) list(APPEND SOURCE_FILES linux/emoji_linux.cpp) endif () ``` -------------------------------- ### Emscripten Module Initialization and Configuration (JavaScript) Source: https://github.com/vitalaudio/visage/blob/main/examples/emscripten_template.html This JavaScript code configures the Emscripten module for a web application. It sets up functions for printing output to a textarea, handling canvas interactions including WebGL context loss, and updating the status and progress indicators during module loading and execution. It also includes error handling for exceptions. ```javascript var statusElement = document.getElementById('status'); var progressElement = document.getElementById('progress'); var spinnerElement = document.getElementById('spinner'); var canvas = document.getElementById('canvas'); var Module = { print: (function () { var element = document.getElementById('output'); if (element) element.value = ''; // clear browser cache return (...args) => { var text = args.join(' '); console.log(text); if (element) { element.value += text + "\n"; element.scrollTop = element.scrollHeight; // focus on bottom } }; })(), canvas: (() => { // As a default initial behavior, pop up an alert when webgl context is lost. // To make your application robust, you may want to override this behavior before shipping! // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 canvas.addEventListener("webglcontextlost", (e) => { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); return canvas; })(), setStatus: (text) => { if (!Module.setStatus.last) Module.setStatus.last = {time: Date.now(), text: ''}; if (text === Module.setStatus.last.text) return; var m = text.match(/(\[^(\\]+)\\((\d+(\.\d+)?)\\/(\d+)\)/); var now = Date.now(); if (m && now - Module.setStatus.last.time < 30) return; Module.setStatus.last.time = now; Module.setStatus.last.text = text; if (m) { text = m[1]; progressElement.value = parseInt(m[2]) * 100; progressElement.max = parseInt(m[4]) * 100; progressElement.hidden = false; spinnerElement.hidden = false; } else { progressElement.value = null; progressElement.max = null; progressElement.hidden = true; if (!text) { spinnerElement.hidden = true; canvas.style.opacity = 1; } } statusElement.innerHTML = text; }, totalDependencies: 0, monitorRunDependencies: (left) => { this.totalDependencies = Math.max(this.totalDependencies, left); } }; window.onerror = () => { Module.setStatus('Exception thrown, see JavaScript console'); spinnerElement.style.display = 'none'; Module.setStatus = (text) => { if (text) console.error('\[post-exception status\] ' + text); }; }; {{{ SCRIPT }}} ``` -------------------------------- ### Amalgamating Headers in CMake Source: https://github.com/vitalaudio/visage/blob/main/visage_ui/CMakeLists.txt Amalgamates header files into a single header. This is typically done to simplify dependency management and potentially improve build times. It uses a custom 'amalgamate_headers' command. ```cmake amalgamate_headers(${VISAGE_INCLUDE}/visage/ui.h "${HEADERS}") list(APPEND HEADERS ${VISAGE_INCLUDE}/visage/ui.h) ``` -------------------------------- ### Disabling Warnings for Dependencies (CMake) Source: https://github.com/vitalaudio/visage/blob/main/visage_graphics/CMakeLists.txt This code configures the build to disable compiler warnings for several third-party libraries ('freetype', 'bgfx', 'bx', 'bimg'). It sets a `DISABLE_WARNINGS` variable based on the compiler (MSVC or others) and applies it using `target_compile_options`. ```cmake if (MSVC) set(DISABLE_WARNINGS /W0) else () set(DISABLE_WARNINGS -w) endif () target_compile_options(freetype PRIVATE ${DISABLE_WARNINGS}) target_compile_options(bgfx PRIVATE ${DISABLE_WARNINGS}) target_compile_options(bx PRIVATE ${DISABLE_WARNINGS}) target_compile_definitions(bx PRIVATE BX_CONFIG_EXCEPTION_HANDLING_USE_WINDOWS_SEH=0) target_compile_options(bimg_decode PRIVATE ${DISABLE_WARNINGS}) target_compile_options(bimg_encode PRIVATE ${DISABLE_WARNINGS}) target_compile_options(bimg PRIVATE ${DISABLE_WARNINGS}) ``` -------------------------------- ### Setting Target Include Directories in CMake Source: https://github.com/vitalaudio/visage/blob/main/visage_ui/CMakeLists.txt Configures the include directories for the 'VisageUi' target. 'PRIVATE' indicates that these include directories are only used for compiling the target itself and not for targets that link to it. It includes the current source directory and a specified include path. ```cmake target_include_directories(VisageUi PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${VISAGE_INCLUDE_PATH}) ``` -------------------------------- ### Render SVG and Raster Images in Visage Source: https://context7.com/vitalaudio/visage/llms.txt Visage provides classes for loading and drawing vector graphics and images. It supports custom styling for SVGs and direct rendering onto the canvas during the draw loop. ```cpp #include #include // Load SVG from embedded file visage::Svg icon(resources::icons::check_circle_svg.data, resources::icons::check_circle_svg.size); icon.setDimensions(64, 64, 1.0f); // SVG with custom fill/stroke visage::Svg customIcon(iconData, iconSize); customIcon.setFillBrush(visage::Brush::solid(0xff00ff00)); customIcon.setStrokeBrush(visage::Brush::solid(0xff000000)); app.onDraw() = [&](visage::Canvas& canvas) { // Draw SVG at position canvas.setColor(0xffffffff); canvas.svg(icon, 10, 10); // Draw SVG at position with custom size canvas.svg(icon, 100, 10, 128, 128); // Draw SVG from embedded file directly canvas.svg(resources::icons::check_circle_svg, 10, 150, 64, 64); // Draw raster image canvas.image(resources::images::test_png, 200, 10, 100, 100); // Draw image from raw data visage::Image img(imageData, dataSize, width, height); canvas.image(img, 200, 150); }; // SVG Frame widget visage::SvgFrame svgFrame; svgFrame.load(resources::icons::menu_svg); svgFrame.setMargin(visage::Dimension::logicalPixels(4)); app.addChild(&svgFrame); ``` -------------------------------- ### Linking Libraries for VisageGraphics (CMake) Source: https://github.com/vitalaudio/visage/blob/main/visage_graphics/CMakeLists.txt This snippet links the necessary libraries to the 'VisageGraphics' target. It includes core dependencies like 'bx', 'bgfx', 'bimg_decode', 'bimg_encode', and 'freetype', along with platform-specific libraries and fontconfig libraries. ```cmake target_link_libraries( VisageGraphics PRIVATE bx bgfx bx bimg_decode bimg_encode freetype ${WIN_LIBS} ${METAL_LIBS} ${FONTCONFIG_LIBRARIES} ) ``` -------------------------------- ### Amalgamated Build and Header Processing (CMake) Source: https://github.com/vitalaudio/visage/blob/main/visage_graphics/CMakeLists.txt This section handles the creation of amalgamated source and header files if the VISAGE_AMALGAMATED_BUILD option is enabled. It uses custom CMake functions `amalgamate_sources` and `amalgamate_headers` to combine source and header files. ```cmake if (VISAGE_AMALGAMATED_BUILD) amalgamate_sources(AMALGAMATED ${CMAKE_CURRENT_BINARY_DIR}/visage_graphics_amalgamated "${SOURCE_FILES}") list(APPEND SOURCE_FILES ${AMALGAMATED}) endif () amalgamate_headers(${VISAGE_INCLUDE}/visage/graphics.h "${HEADERS}") list(APPEND HEADERS ${VISAGE_INCLUDE}/visage/graphics.h) ``` -------------------------------- ### Adding a Library Target in CMake Source: https://github.com/vitalaudio/visage/blob/main/visage_ui/CMakeLists.txt Defines a new library target named 'VisageUi' as an OBJECT library. It specifies the source files, header files, and platform-specific files to be included in the library. OBJECT libraries are typically used as building blocks for other targets. ```cmake add_library(VisageUi OBJECT ${SOURCE_FILES} ${HEADERS} ${PLATFORM_FILES}) ``` -------------------------------- ### Library and Test Target Configuration in CMake Source: https://github.com/vitalaudio/visage/blob/main/visage_utils/CMakeLists.txt This CMake code defines the `VisageUtils` library as an OBJECT library, including its source and header files. It also sets include directories and defines a `VisageUtilsDefinitions` INTERFACE library. Finally, it configures a test target `VisageUtilsTests` using a custom macro `visage_add_test_target`. ```cmake amalgamate_headers(${VISAGE_INCLUDE}/visage/utils.h "${HEADERS}") list(APPEND HEADERS ${VISAGE_INCLUDE}/visage/utils.h) add_library(VisageUtils OBJECT ${SOURCE_FILES} ${HEADERS}) target_include_directories(VisageUtils PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) add_library(VisageUtilsDefinitions INTERFACE) set_target_properties(VisageUtils PROPERTIES FOLDER "visage") visage_add_test_target( TARGET VisageUtilsTests TEST_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests ) ```