Skip to content

widget_sample

Jan Boon edited this page Jul 19, 2026 · 20 revisions

title: GUI Widget Sample description: Standalone NeL GUI showcase sample (nl_sample_gui) using the legacy w_ interface skin published: true editor: markdown

nl_sample_gui (nel/samples/gui/) is a standalone showcase of the NLGUI widget library. It boots the widget manager, view renderer and interface parser outside the Ryzom client, parses a self-contained interface definition, and renders it with the legacy w_ interface skin — the original beveled reference style whose window frames (w_header_*, w_l0_*, w_l1_*, w_modal_*, w_scroll_l0_*) were later replaced name-for-name by the shipped skin_* set. The sample keeps this otherwise-unused skin exercised and doubles as a minimal reference for embedding NLGUI in any NeL application.

Layout

  • main.cpp — bootstrap: UDriver + text context, CViewRenderer::setDriver/setTextContext + init, atlas loadTextures, parseInterface, updateAllLocalisedElements, activateMasterGroup("ui:sample"), then the pump/draw loop (EventServer.pumpsendClockTickEventcheckCoordsdrawViews). A NLGUI::CEventListener routes driver mouse events into the widget manager.
  • data/config_sample.xml — master <root id="sample">, database defaults, and the w_ skin options blocks (layer0, skin_modal, container_move_opt, container_insertion_opt, context_menu_back, …).
  • data/widgets_sample.xml — shared widget styles (text_button_16, button_ok, tab_button) on the w_text_button_* / w_tab_* textures.
  • data/main_sample.xml — the showcase windows, the generic_pointer view, and the <tree> nodes that register windows.

Textures — packed on the fly

No interface texture data lives in the code repository. At build time, CMake runs the build_interface tool over interfaces/v3/ of a ryzomcore_graphics checkout (NL_GRAPHICS_DIR, default sibling of the source tree) and packs gui_sample_atlas.png/.txt into the build directory — the same pattern the WebGL water sample uses for its assets. build_interface gained a -k/--keep-going flag for this: input files that cannot be loaded as bitmaps (e.g. unmaterialized git-lfs pointer files) are skipped with a warning instead of aborting the pack. The font comes from fonts/basic.ttf in the same checkout.

The Emscripten build preloads the generated atlas, the XML and the font into the .data bundle; when cross-compiling, point NL_BUILD_INTERFACE_TOOL at a host-built build_interface.

Building and running

Native (needs WITH_GUI=ON, which needs Lua and ryzom/luabind; build both into a local prefix and pass LUA_*/LUABIND_* cache variables if the distribution does not package them):

cmake -DWITH_GUI=ON -DWITH_NEL_SAMPLES=ON ...
ninja nl_sample_gui
bin/nl_sample_gui                          # interactive, ESC quits
bin/nl_sample_gui --screenshot out.png --frames 10   # headless witness (works under xvfb-run)

Sample-side action handlers

NLGUI ships the widget-level handlers (set, tab_select, ic_* container buttons, combo box, select number, …) but some conventional handlers live in the Ryzom client. The sample registers its own equivalents: proc (run an interface procedure), enter_modal / leave_modal (CWidgetManager::enableModalWindow), and sample_quit.

Widget coverage (M2)

A launcher window toggles one showcase window per family; the four container layer skins (layer0layer3, pure w_l0_*w_l3_* options blocks) are spread across them. Covered and interaction-verified under Xvfb with xdotool: text views (sizes, colors, case modes, multi-line), bitmaps (scaled/tiled), text_number/digit/text_quantity, bar/bar3 gauges, push/toggle/radio buttons, text buttons, sliders on both axes bound to UI:TEMP:* database entries, edit boxes (typed input works), scroll_text (which contains the runtime-filled group_list), group_tree with arbo_* fold arrows, menus (checkable, grayed, separator, nested submenu — a submenu is a nested <action> inside an <action>, not a <menu> element), the combo box with its dropdown, select_number, the color picker (palette + a makeRGB(...) link recoloring a swatch), tab groups, stacked modals (push_modal/pop_modal), and a <link> showing a warning icon above a threshold. Not exercised: group_html/group_table (need the web stack wired), Lua-scripted UI (handler registered, no demo), edit_box_decor, group_frame/header.

What the application must provide

NLGUI expects several things from the embedding application that the Ryzom client normally supplies:

  • CInterfaceLink::CInterfaceLinkUpdater — instantiate one after creating the widget manager; without it, <link> elements never evaluate (database observer flushes are what pump triggered links). Call CInterfaceLink::updateAllLinks() once after parsing for the initial evaluation.
  • CDBGroupComboBox::selectMenu / selectMenuOut / measureMenu — static ids the combo dropdown machinery resolves; point them at your master group's menus.
  • Action handlers with client-side conventions: proc, enter_modal/leave_modal, push_modal/pop_modal, active_menu, lua.

Bootstrap pitfalls (learned the hard way)

  • Container windows need the global options blocks. CGroupContainer::setup dereferences container_move_opt unchecked — without that options block the first updateAllLocalisedElements crashes.
  • Fresh database leaves default to 0. UI:SAVE:CONTENT_ALPHA, UI:SAVE:CONTAINER_ALPHA and friends must be declared (255) in the XML or every window renders fully transparent. Likewise UI:SAVE:*_ROLLOVER_FACTOR are inverted factors: 255 = no fade-out when the mouse is not over the window, 0 = fade to invisible.
  • Root-level plain <group>s are parsed but never drawn — only windows registered on the master group (containers via <tree>, modals via enableModalWindow) render. Put HUD-style elements inside a registered window.
  • %case_upper etc. are interface defines, not built-ins — declare case_normalcase_first_word_letter_up (0…5).
  • The texture lookup normalizes .png.tga on both the atlas-load and lookup sides, so interface XML keeps the canonical .tga names while the atlas is packed from .png sources. The color picker is the exception: it reads its palette as a loose file (it needs pixel access), so the palette png is staged next to the atlas and CPath::remapExtension("png", "tga", true) is set before the search paths are indexed.
  • Container windows compute their height from the content group unless resizer="true"; a fixed-size window with resizer="false" and an empty-sized content collapses to its title bar.
  • dbview_quantity's registered class name is text_quantity (not quantity).
  • Two NLGUI bugs fixed while building this: CEventListener never subscribed keyboard events (edit boxes were deaf outside the client), and CGroupTree::SNode::parse crashed on a <node> with opened= but no show= (wrong pointer guarded).

Status

  • M1 (landed): skeleton — w_ layer0 container window with header/title/buttons, w_modal modal via enter_modal, mouse pointer, frame-capped loop, headless screenshot mode, xdotool-verified event chain under Xvfb.
  • M2 (landed): comprehensive widget coverage as described above, every interaction verified headless.
  • M3 (planned): Emscripten/WebGL build deployed with the other NeL web samples (wasm cross-builds of lua/luabind/libxml2 plus curl/openssl stub archives; WITH_GUI emscripten configuration prepared).

Clone this wiki locally