# LEL & GUECS This project is two small components that make up a minimalist GUI library for game development. The purpose is to provide _only_ a simple layout engine and an ECS (Entity Component System) structure for you put your existing graphical elements into. It's currently working for [SFML](https://www.sfml-dev.org/) but should be easy to retarget or recreate. You can also use only LEL or GUECS depending on your needs. LEL stands for _Layout Expression Language_ and is a layout engine that uses a simple "wiki style" language for specifying a GUI's layout grid. Rather than use nested containers or similar tree-like code structures, a LEL layout is just a string that looks like this: ``` [col1_row1|col2_row1] [col1_row2|col2_row2|cheese_doodles] ``` The LEL parser will read this, and based on the dimensions of its space, determine the size of each cell here. In this case it will create 4 cells, dividing the space into 4 quadrants. You can then access these cells by their names `"col1_row1"` and place your own GUI elements there. The LEL language can create ragged rows, spans, and most anything you need for a layout (to a point). You'll also notice that you can name these cells almost anything. The last row has `cheese_doodles` rather than a column/row identifier. GUECS (Graphical User Entity Component System) is a _very_ simple ECS that lets you quickly build your GUI inside a LEL layout. It works like most ECS systems whereby there are no classes like `Button` or `Input` but instead you use components to create these. For example, a button is simply: ```cpp gui.set(id, {}); gui.set(id, {L"Click Me"}); gui.set(id, { [](auto, auto){ handle_click(); } }); ``` This creates a rectangle with a label that when clicked call the `handle_click()` function. This makes it very easy for you to target your own graphics libraries since you only need to write your own components and toss them into the `guecs::UI` class like this. ## What is it NOT? LEL does _not_ try to create deeply nested complex layouts. It can create reasonably complex _two dimensional_ layouts, but if you need very complex nested layouts then its best to create multiple components with their own LEL expressions. LEL also doesn't try to do automatic rebalancing and recalculating of its layout. Since every game framework (and every game?) starts off with fixed size screens it doesn't make sense to create a layout engine that can handle the equivalent of a web browser HTML/CSS engine. If you change the dimensions of your screen, then simply re-initialize the LEL layouts. You most likely have to do this anyway in your game engine. That being said, LEL's engine is reasonably fast so recalculating the layout won't be expensive. Just don't expect it to rebalance some douchebag swinging a window corner resize around at 200 FPS. GUECS also doesn't include many ready-made components. It has basic building blocks for creating your own components, but it's assumed that you're probably interested in creating your own stylized UI components to match your game's design and your game engine's functionality. Many times game developers end up creating all of their own UI elements so just do that but let GUECS help you keep it all organized. ## Building First, you'll need to install [meson](https://mesonbuild.com/) to run the build. One _MASSIVE_ warning is that `meson` will run each dependency's build, which will require you to have dependencies installed in some OS (like Linux), but then my build will _completely ignore your broke ass hacked up bullshit packages_. I'm serious, nothing on your computer is trusted and I download everything. If you build against your versions of the packages then you're doing it wrong (I'm looking at you Fedora and Debian). Easiest way to try the build is with this: ```shell git clone https://git.learnjsthehardway.com/learn-code-the-hard-way/lel-guecs.git cd lel-guecs make reset make run ``` That should kick off the build attempt, and then you'll be told what's missing for the build to continue, _BUT_ this is platform dependent as I said before. For example, on Windows it just builds by downloading everything, OSX already has most things, and Linux is...well...Linux. ## Using LEL To use LEL with GUECS you first initialize a `guecs::UI` class with its position and size. Here's an example taken from the `demos/calc.cpp` example: ```cpp $gui.position(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); ``` Then you configure a layout with the LEL formatting language: ```cpp $gui.layout( "[*%(400)stack |_|_|_]" "[*%(400)readout|_|_|_]" "[push|pop|clear|eq]" "[add |sub|mul |div]" "[btn7|btn8|btn9]" "[btn4|btn5|btn6]" "[btn1|btn2|btn3]" "[neg |btn0|_ ]"); ``` This creates a simple RPN calculator UI with buttons for numbers, readouts for the results and stack, and basic math operators. For people from other languages, this is actually one big string, but C++ (like C) allows you to "concatenate" strings together that are next to each other, so I just put them on separate lines so they look more like the grid they represent. Once you have that you can give your panel a background and render a debug layout: ```cpp void render(sf::RenderWindow& window) { $gui.render(window); $gui.debug_layout(window); } ``` Since this first version works with SFML this render only takes a `sf::RenderWindow` and renders the gui to it. With these two calls you'll get red lines showing you the grid specified in `layout()`. This lets you refine the layout grid without requiring any components. Keep working the LEL layout until the grid looks good, then add some rectangles and labels: ```cpp for(auto& [name, cell] : $gui.cells()) { auto id = $gui.entity(name); $gui.set(id, {}); $gui.set