{"id":13719913,"url":"https://github.com/randrew/layout","last_synced_at":"2025-05-07T12:30:28.294Z","repository":{"id":38805634,"uuid":"60119352","full_name":"randrew/layout","owner":"randrew","description":"Single-file library for calculating 2D UI layouts using stacking boxes. Compiles as C99 or C++.","archived":false,"fork":false,"pushed_at":"2023-03-13T07:06:52.000Z","size":82,"stargazers_count":878,"open_issues_count":7,"forks_count":68,"subscribers_count":37,"default_branch":"master","last_synced_at":"2024-08-04T01:12:56.029Z","etag":null,"topics":["flexbox","gui","imgui","single-file","ui"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/randrew.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-05-31T19:59:42.000Z","updated_at":"2024-08-03T11:18:27.000Z","dependencies_parsed_at":"2024-01-09T23:11:15.194Z","dependency_job_id":"3ca65f91-3988-4b42-82ba-104d0b3b27e7","html_url":"https://github.com/randrew/layout","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/randrew%2Flayout","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/randrew%2Flayout/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/randrew%2Flayout/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/randrew%2Flayout/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/randrew","download_url":"https://codeload.github.com/randrew/layout/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224597014,"owners_count":17337829,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flexbox","gui","imgui","single-file","ui"],"created_at":"2024-08-03T01:00:57.651Z","updated_at":"2024-11-14T09:30:42.611Z","avatar_url":"https://github.com/randrew.png","language":"C","readme":"Layout\n======\n\nA simple/fast stacking box layout library. It's useful for calculating layouts\nfor things like 2D user interfaces. It compiles as C99 or C++. It's tested with\ngcc (mingw64), VS2015, and clang/LLVM. You only need one file to use it in your\nown project: [layout.h](layout.h).\n\n![](https://raw.githubusercontent.com/wiki/randrew/layoutexample/ui_anim_small.gif)\n\nUse Layout in Your Project\n--------------------------\n\nTo use *Layout* in your own project, copy [layout.h](layout.h) into your\nproject's source tree and define `LAY_IMPLEMENTATION` in exactly one `.c` or\n`.cpp` file that includes [layout.h](layout.h).\n\nThe includes in your one special file should look like this:\n\n```C\n#include ...\n#include ...\n#define LAY_IMPLEMENTATION\n#include \"layout.h\"\n```\n\nAll other files in your project should not define `LAY_IMPLEMENTATION`, and can\ninclude [layout.h](layout.h) like normal.\n\nRequirements and Extras\n-----------------------\n\n*Layout* has no external dependencies, but by default it does use `assert.h`,\n`stdlib.h` and `string.h` for `assert`, `realloc` and `memset`. If your own\nproject does not or cannot use these, you can easily exchange them for\nsomething else by using preprocessor definitions. See the section below about\nthe available [customizations](#customizations).\n\n*Layout* can be built as C99 or C++ if you are using GCC or Clang, but must be\nbuilt as C++ if you are using MSVC. This requirement exists because the\n*Layout* implementation code uses the `vector_size` extension in GCC and Clang,\nwhich does not exist in MSVC. C++ operator overloading is used to simulate this\nfeature in MSVC. The code generated by all three compilers is not too different\n-- the `vector_size` extension is used mostly to keep the syntax of the\nimplementation easier to read.\n\n*Layout* is based on the nice library\n[oui](https://bitbucket.org/duangle/oui-blendish) by\n[duangle](https://twitter.com/duangle). Unlike *oui*, *Layout* does not handle\nanything related to user input, focus, or UI state.\n\nBuilding the tests and benchmarks is handled by the [tool.bash](tool.bash)\nscript, or by [GENie](https://github.com/bkaradzic/GENie). See the section\nbelow about [building the tests and\nbenchmarks](#building-the-tests-and-benchmarks). There's also an example of\nusing *Layout* as a Lua `.dll` module. However, you don't need any of that to\nuse *Layout* in your own project.\n\nOptions\n-------\n\nYou can choose to build *Layout* to use either integer (int16) or floating\npoint (float) coordinates. Integer is the default, because UI and other 2D\nlayouts do not often use units smaller than a single point when aligning and\npositioning elements. You can choose to use floating point instead of integer\nby defining `LAY_FLOAT`.\n\n* `LAY_FLOAT`, when defined, will use `float` instead of `int16` for\n  coordinates.\n\nIn addition to the `LAY_FLOAT` preprocessor option, other behavior in *Layout*\ncan be customized by setting preprocessor definitions. Default behavior will be\nused for undefined customizations.\n\n* `LAY_ASSERT` will replace the use of `assert.h`'s `assert`\n\n* `LAY_REALLOC` will replace the use of `stdlib.h`'s `realloc`\n\n* `LAY_MEMSET` will replace the use of `string.h`'s `memset`\n\nIf you define `LAY_REALLOC`, you will also need to define `LAY_FREE`.\n\nExample\n=======\n\n```C\n// LAY_IMPLEMENTATION needs to be defined in exactly one .c or .cpp file that\n// includes layout.h. All other files should not define it.\n\n#define LAY_IMPLEMENTATION\n#include \"layout.h\"\n\n// Let's pretend we're creating some kind of GUI with a master list on the\n// left, and the content view on the right.\n\n// We first need one of these\nlay_context ctx;\n\n// And we need to initialize it\nlay_init_context(\u0026ctx);\n\n// The context will automatically resize its heap buffer to grow as needed\n// during use. But we can avoid multiple reallocations by reserving as much\n// space as we'll need up-front. Don't worry, lay_init_context doesn't do any\n// allocations, so this is our first and only alloc.\nlay_reserve_items_capacity(\u0026ctx, 1024);\n\n// Create our root item. Items are just 2D boxes.\nlay_id root = lay_item(\u0026ctx);\n\n// Let's pretend we have a window in our game or OS of some known dimension.\n// We'll want to explicitly set our root item to be that size.\nlay_set_size_xy(\u0026ctx, root, 1280, 720);\n\n// Set our root item to arrange its children in a row, left-to-right, in the\n// order they are inserted.\nlay_set_contain(\u0026ctx, root, LAY_ROW);\n\n// Create the item for our master list.\nlay_id master_list = lay_item(\u0026ctx);\nlay_insert(\u0026ctx, root, master_list);\n// Our master list has a specific fixed width, but we want it to fill all\n// available vertical space.\nlay_set_size_xy(\u0026ctx, master_list, 400, 0);\n// We set our item's behavior within its parent to desire filling up available\n// vertical space.\nlay_set_behave(\u0026ctx, master_list, LAY_VFILL);\n// And we set it so that it will lay out its children in a column,\n// top-to-bottom, in the order they are inserted.\nlay_set_contain(\u0026ctx, master_list, LAY_COLUMN);\n\nlay_id content_view = lay_item(\u0026ctx);\nlay_insert(\u0026ctx, root, content_view);\n// The content view just wants to fill up all of the remaining space, so we\n// don't need to set any size on it.\n//\n// We could just set LAY_FILL here instead of bitwise-or'ing LAY_HFILL and\n// LAY_VFILL, but I want to demonstrate that this is how you combine flags.\nlay_set_behave(\u0026ctx, content_view, LAY_HFILL | LAY_VFILL);\n\n// Normally at this point, we would probably want to create items for our\n// master list and our content view and insert them. This is just a dumb fake\n// example, so let's move on to finishing up.\n\n// Run the context -- this does all of the actual calculations.\nlay_run_context(\u0026ctx);\n\n// Now we can get the calculated size of our items as 2D rectangles. The four\n// components of the vector represent x and y of the top left corner, and then\n// the width and height.\nlay_vec4 master_list_rect = lay_get_rect(\u0026ctx, master_list);\nlay_vec4 content_view_rect = lay_get_rect(\u0026ctx, content_view);\n\n// master_list_rect  == {  0, 0, 400, 720}\n// content_view_rect == {400, 0, 880, 720}\n\n// If we're using an immediate-mode graphics library, we could draw our boxes\n// with it now.\nmy_ui_library_draw_box_x_y_width_height(\n    master_list_rect[0],\n    master_list_rect[1],\n    master_list_rect[2],\n    master_list_rect[3]);\n\n// You could also recursively go through the entire item hierarchy using\n// lay_first_child and lay_next_sibling, or something like that.\n\n// After you've used lay_run_context, the results should remain valid unless a\n// reallocation occurs.\n//\n// However, while it's true that you could manually update the existing items\n// in the context by using lay_set_size{_xy}, and then calling lay_run_context\n// again, you might want to consider just rebuilding everything from scratch\n// every frame. This is a lot easier to program than tedious fine-grained\n// invalidation, and a context with thousands of items will probably still only\n// take a handful of microseconds.\n//\n// There's no way to remove items -- once you create them and insert them,\n// that's it. If we want to reset our context so that we can rebuild our layout\n// tree from scratch, we use lay_reset_context:\n\nlay_reset_context(\u0026ctx);\n\n// And now we could start over with creating the root item, inserting more\n// items, etc. The reason we don't create a new context from scratch is that we\n// want to reuse the buffer that was already allocated.\n\n// But let's pretend we're shutting down our program -- we need to destroy our\n// context.\nlay_destroy_context(\u0026ctx);\n\n// The heap-allocated buffer is now freed. The context is now invalid for use\n// until lay_init_context is called on it again.\n```\n\nBuilding the Tests and Benchmarks\n=================================\n\nⓘ | None of this is necessary to use in your own project. These directions are only for building the tests and benchmarks programs, which you probably don't care about.\n:---: | :---\n\nIf you have bash and are on a POSIX system, you can use the `tool.bash`\nscript to build *Layout*'s standalone tests and benchmarks programs. Run\n`tool.bash` to see the options.\n\n\u003ch3\u003eUsing GENie\u003c/h3\u003e\n\nInstead of using the `tool.bash` script, you can use GENie to generate a Visual\nStudio project file, or any of the other project and build system output types\nit supports. The GENie generator also lets you build the example Lua module.\n\n\u003cdetails\u003e\n\u003csummary\u003eDirections for acquiring and using GENie\u003c/summary\u003e\n\nThe [genie.lua](genie.lua) script is mostly tested on Windows, so if you use it\non another platform, you might need to tweak it.\n\nYou will first need to get (or make) a GENie binary and place it in your path\nor at the root of this repository.\n\nDownload GENie\n--------------\n\nLinux:  \nhttps://github.com/bkaradzic/bx/raw/master/tools/bin/linux/genie\n\nOSX:  \nhttps://github.com/bkaradzic/bx/raw/master/tools/bin/darwin/genie\n\nWindows:  \nhttps://github.com/bkaradzic/bx/raw/master/tools/bin/windows/genie.exe\n\nVisual Studio 2015/2017\n-----------------------\n\n```\ngenie.exe vs2015\nstart build/vs2015/layout.sln\n```\n\nReplace vs2015 with vs2017 if you want to use Visual Studio 2017.\n\nGCC/MinGW/Clang\n---------------\n\n```\n./genie gmake\n```\n\nand then run your `make` in the directory `build/gmake`. You will need to\nspecify a target and config. Here is an example for building the `tests` target\nin Windows with the 64-bit release configuration using mingw64 in a bash-like\nshell (for example, git bash):\n\n\n```\n./genie.exe gmake \u0026\u0026 mingw32-make.exe -C build/gmake tests config=release64\n```\n\nIf you want to use float coordinates instead of integer, you can use an option in the build script which will define `LAY_FLOAT` for you:\n\n```\n./genie gmake --coords=float\n```\n\nor if you want to specify integer (the default):\n\n```\n./genie gmake --coords=integer\n```\n\n\u003c/details\u003e\n","funding_links":[],"categories":["C","Graphics"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frandrew%2Flayout","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frandrew%2Flayout","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frandrew%2Flayout/lists"}