XCGUI

repository·main·Indexed 20 days ago

https://github.com/twgh/xcgui

A high-performance, lightweight Go wrapper for a C/C++ based DirectUI library. XCGUI enables the creation of hardware-accelerated, highly customizable 2D graphical user interfaces without relying on standard Windows controls or MFC/ATL. It features a WYSIWYG visual UI designer for loading XML layouts, comprehensive support for UI widgets, animations, SVG graphics, and a specialized system for marshaling calls to the UI thread.

Tokens
6K
Snippets
14
Records
22
Agent score
70%

What's inside xcgui

  1. Overview of XCGUI encapsulated classes

    main
    XCGUI provides a high-level encapsulation of over a thousand functions from the underlying xc package. The library is organized into several functional packages including app, window, widget, adapter, ani (animation), and more. This structure allows developers to build complex GUIs using structured Go classes rather than low-level function calls.
  2. How to use the Visual UI Designer with XCGUI

    main

    XCGUI provides a visual UI designer for rapid interface development using a 'what you see is what you get' (WYSIWYG) approach. Instead of writing manual layout code, you can design your UI in the designer and load the resulting layout files (e.g., .xml) directly from memory or disk.

    To use a layout designed in the tool, you can load a ZIP archive containing your resources and layout files using app.LoadResourceZipMem and then create a window using window.NewByLayoutZipMem.

    package main
    
    import (
    	"_" // for embed
    	"github.com/twgh/xcgui/app"
    	"github.com/twgh/xcgui/widget"
    	"github.com/twgh/xcgui/window"
    )
    
    //go:embed res/qqmusic.zip
    var qqmusic []byte
    
    func main() {
        app.Init()
    	a := app.New(true)
    	a.EnableAutoDPI(true).EnableDPI(true)
    	
        // Load resource files from memory ZIP
        a.LoadResourceZipMem(qqmusic, "resource.res", "")
        
        // Create window object from layout file inside the memory ZIP
        w := window.NewByLayoutZipMem(qqmusic, "main.xml", "", 0, 0)
        
        // Access components by the 'name' attribute defined in the XML
        song := widget.NewShapeTextByName("songTitle")
        println(song.GetText())
        
        w.AdjustLayout()
        w.Show(true)
        a.Run()
        a.Exit()
    }
  3. How event handling and callbacks work in XCGUI

    main

    XCGUI supports multiple callback handlers for a single event type.

    Execution Order: The last registered callback is executed first, and the first registered callback is executed last.

    Event Interception: To intercept an event or prevent it from propagating further, set the *pbHandled parameter to true within your callback function.

    AddEvent vs Event prefixes:

    • AddEvent functions: These are recommended for most use cases. They reuse existing callback functions, which prevents hitting the system limit of approximately 2000 callback functions created via syscall.NewCallback.
    • Event functions: These create a new callback function every time they are called. If you use these with anonymous functions in a loop or frequently, you may trigger a panic by exceeding the 2000-callback limit.
  4. How event handling and interception works

    main

    XCGUI allows multiple callback functions to be registered for a single event type.

    Execution Order: Callbacks are executed in reverse order of registration (the last registered callback runs first, and the first registered runs last).

    Event Interception: To stop an event from propagating to subsequent handlers or to intercept it, set the *pbHandled parameter to true within your callback function.

    AddEvent vs Event:

    • Use AddEvent methods (e.g., AddEvent_BnClick) when using anonymous functions. AddEvent reuses existing callbacks, preventing you from hitting the system limit of approximately 2,000 callbacks.
    • Avoid using Event methods with anonymous functions, as each call creates a new callback and can lead to a panic if the 2,000 limit is exceeded.
  5. Use the Visualization UI Designer for rapid development

    main

    XCGUI provides a free UI designer tool that follows a 'what you see is what you get' (WYSIWYG) approach. This allows you to design interfaces visually and save significant manual coding time. You can load the resulting layout files (e.g., XML) and resource files (e.g., ZIP) directly from memory using the app and window packages.

    package main
    
    import (
    	_ "embed"
    	"github.com/twgh/xcgui/app"
    	"github.com/twgh/xcgui/widget"
    	"github.com/twgh/xcgui/window"
    )
    
    //go:embed res/qqmusic.zip
    var qqmusic []byte
    
    func main() {
        app.Init()
    	appInstance := app.New(true)
    	appInstance.EnableAutoDPI(true).EnableDPI(true)
    	
    	// Load resource files from memory zip
    	appInstance.LoadResourceZipMem(qqmusic, "resource.res", "")
    	
    	// Load layout file from memory zip, Create window object
    	w := window.NewByLayoutZipMem(qqmusic, "main.xml", "", 0, 0)
        
    	// Access components by the 'name' property set in the XML layout
    	song := widget.NewShapeTextByName("songTitle")
    	println(song.GetText())
        
    	w.AdjustLayout()
    	w.Show(true)
    	appInstance.Run()
    	appInstance.Exit()
    }
  6. Execute code on the UI thread

    main

    Since GUI operations must typically happen on the main UI thread, XCGUI provides several methods to marshal calls from other goroutines to the UI thread:

    • CallUiThread(pCall func(data int) int, data int) int: The standard way to call the UI thread. Warning: This method has a limit of 2000 callbacks. Avoid using anonymous functions inside this method to prevent hitting the limit and causing a panic.
    • CallUiThreadEx(pCall func(data int) int, data int) int: A version of CallUiThread that has no limit on the number of callbacks and allows the use of anonymous functions.
    • CallUT(f func()) *App (and its alias UI(f func()) *App): A simplified version for functions that take no arguments and return nothing. It has no callback limit and supports anonymous functions.
    • CallUiThreader(u xc.UiThreader, data int) int: Uses an xc.UiThreader object to execute the callback.
    // Using the safe, unlimited version for anonymous functions
    myApp.CallUT(func() {
        // Perform UI operations here
    })
  7. Create and run an XCGUI application

    main

    The App struct is the main controller for the XCGUI lifecycle.

    1. New(bD2D ...bool): Initializes the application. It searches for xcgui.dll in the application directory or system32. You can optionally pass true to enable Direct2D (D2D) support (defaults to true). If it fails, it returns nil.
    2. Run(): Starts the GUI message loop. The loop continues until the number of XCGUI windows reaches zero.
    3. Exit(): Terminates the GUI library and releases resources.
    4. ShowAndRun(hWindow int): A convenience method that shows a specific window handle and immediately starts the message loop.
    // Initialize the app with D2D enabled
    myApp := app.New(true)
    if myApp == nil {
        panic("failed to initialize app")
    }
    
    // ... create windows/elements ...
    
    // Start the message loop
    myApp.Run()
    
    // Clean up
    myApp.Exit()
  8. Initialize the XCGUI environment

    main

    Before using XCGUI, you must initialize the underlying DLL. There are two primary ways to do this:

    1. Init(): Writes xcgui.dll to a specific temporary directory in Windows. If the DLL already exists, it won't be overwritten. You do not need to call xc.SetXcguiPath() manually after this.
    2. InitOrExit(): Similar to Init(), but if initialization fails, it will display an error popup and terminate the program immediately.

    To clean up the DLL on program exit, call DeleteDll().

    err := app.Init()
    if err != nil {
        // handle error
    }
    // ... use XCGUI ...
    app.DeleteDll()
  9. Create a simple window using pure code

    main

    If you prefer not to use the UI designer, you can construct windows and widgets entirely through Go code. This involves initializing the app, creating a window with specific styles, and adding widgets like buttons manually.

    package main
    
    import (
    	"github.com/twgh/xcgui/app"
    	"github.com/twgh/xcgui/imagex"
    	"github.com/twgh/xcgui/widget"
    	"github.com/twgh/xcgui/window"
    	"github.com/twgh/xcgui/xcc"
    )
    
    func main() {
    	// 1. Initialize XCGUI
        app.Init()
    	a := app.New(true)
    	a.EnableAutoDPI(true).EnableDPI(true)
    
    	// 2. Create window
    	w := window.New(0, 0, 430, 300, "xcgui window", 0, xcc.Window_Style_Default|xcc.Window_Style_Drag_Window)
        
    	w.SetBorderSize(0, 30, 0, 0)
    	a.SetWindowIcon(imagex.NewBySvgString(svgIcon).Handle)
    	w.SetTransparentType(xcc.Window_Transparent_Shadow)
    	w.SetShadowInfo(8, 255, 10, false, 0)
        
    	// Create a button
    	btn := widget.NewButton(165, 135, 100, 30, "Button", w.Handle)
    	
    	// Registration button clicked event
    	btn.AddEvent_BnClick(func(hEle int, pbHandled *bool) int {
    		w.MessageBox("tip", btn.GetText(), xcc.MessageBox_Flag_Ok|xcc.MessageBox_Flag_Icon_Info, xcc.Window_Style_Modal)
    		return 0
    	})
        
    	// 3. Display window
    	w.Show(true)
    	// 4. Run the program
    	a.Run()
    	// 5. Exit the program
    	a.Exit()
    }
    
    var svgIcon = `<svg ...>...</svg>` // SVG content
  10. Configure DPI and Rendering settings

    main

    To ensure high-quality visuals and proper scaling on high-resolution displays, use these configuration methods:

    • EnableAutoDPI(bEnable ...bool) *App: When enabled, XCGUI automatically detects DPI changes and adjusts UI scaling. Defaults to true.
    • EnableDPI(bEnable ...bool) bool: Manually enables DPI awareness for the Go process.
    • EnableAutoRedrawUI(bEnable ...bool) *App: When enabled, modifying UI properties (like a button's text) will automatically trigger a redraw. Defaults to true.
    • SetTextRenderingHint(nType int32) *App: Sets the quality of text rendering (compatible with GDI+ TextRenderingHint).
    • SetD2dTextAntialiasMode(mode int32) *App: Configures anti-aliasing for Direct2D text.
  11. Reference the XCGUI package structure and encapsulated classes

    main

    XCGUI is a high-level wrapper around approximately 2,000 functions from the xc package. The library is organized into several specialized packages based on functionality. Use these packages to access specific UI components, window types, and utility services:

    Core & Window Management

    • app: Global application API (App)
    • window: Window management including Window, FrameWindow, ModalWindow, FloatWindow, and TrayIcon
    • edge: WebView environments (Edge, WebView)

    UI Widgets & Layout

    • widget: The primary package for UI elements. Includes Element (base), Button, ComboBox, Edit, Editor, List, ListBox, Menu, ProgressBar, LayoutFrame, ListView, MenuBar, Pane, ScrollView, TabBar, ToolBar, Tree, DateTime, MonthCal, and GifPlayer.
    • widget/shape: Various shape objects like ShapeRect, ShapeEllipse, ShapeLine, ShapeText, etc.
    • adapter: Data adapters for connecting data to UI components, such as AdapterListView, AdapterMap, AdapterTable, and AdapterTree.

    Graphics, Animation & Styling

    • bkmanager & bkobj: Background management and background objects.
    • font: Font management (Font).
    • imagex: Image operations (Image, ImageSrc).
    • svg: SVG vector graphics (Svg).
    • drawx: Graphics drawing (Draw).
    • ani: Animation systems including Anima, AnimaGroup, AnimaItem, AnimaRotate, and AnimaScale.
    • ease: Easing functions.

    Utilities & Constants

    • xcc: XCGUI constants.
    • res: Resource operations.
    • tmpl: Templating for list items (ListItemTemplate) and nodes (Node).
    • wapi: Windows system API (currently under active development).
    • wapi/wnd: Window-specific Windows API wrappers.
    • wapi/wutil: Common utility functions for Windows API.