{"id":18822104,"url":"https://github.com/x39/slate-ui","last_synced_at":"2026-01-18T13:30:18.610Z","repository":{"id":258666096,"uuid":"825434580","full_name":"X39/slate-ui","owner":"X39","description":null,"archived":false,"fork":false,"pushed_at":"2024-10-17T22:32:49.000Z","size":17,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-10-21T03:48:54.614Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/X39.png","metadata":{"files":{"readme":"ReadMe.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-07T19:01:09.000Z","updated_at":"2024-10-17T22:32:53.000Z","dependencies_parsed_at":"2024-10-21T16:23:33.442Z","dependency_job_id":null,"html_url":"https://github.com/X39/slate-ui","commit_stats":null,"previous_names":["x39/slate-ui"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/X39%2Fslate-ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/X39%2Fslate-ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/X39%2Fslate-ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/X39%2Fslate-ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/X39","download_url":"https://codeload.github.com/X39/slate-ui/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239758902,"owners_count":19692041,"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":[],"created_at":"2024-11-08T00:47:50.895Z","updated_at":"2025-02-20T01:15:25.882Z","avatar_url":"https://github.com/X39.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# The Project\nslate-ui is a software library that aims to provide a proper\nsolution for desktop graphical user interfaces built in `rust`.\n\nThe current version is pre-alpha and not ready for any use.\n# The Theory\nThe basics of UI are simple:\n- You have a set canvas of size `width` x `height`\n- You have a bunch of buttons, labels, textboxes, etc. you want to draw\n- You have a bunch of events you want to handle\n\nBut how to translate that best into code?\nThe general \"agreed\" way is either clunky software built\nstuff, where all control is mandated by the developer or\nwith implicit flow, based on inheritance and callbacks.\n\nWith rust not having inheritance, the second option is out.\nHowever, the first is also out, as it is, simply put, bad at\nevery level.\n\nThis is where slate-ui comes in. It aims to provide a\nmiddleground that marries the pros of object-oriented ui\nframeworks with the rather data driven nature of rust.\n\n## The Rendering\nThe rendering is generally agreed to be a three step process:\n1. Measure what you would like to have, size-wise\n2. Arrange yourself in the space you will be given\n3. Render yourself\n\nThis is simple enough to actually do, but with rust lacking\ninheritance, doing rendering can be troublesome when everyone\nhas to implement eg. margin and padding themselves.\nTo solve this, slate-ui approaches this pipeline slightly\ndifferent:\n\n### Render\n\nWe start off with a blank slate, called `Control`. This\ncontrol has nothing but a list of \"Primitives\".\nA Primitive is a simple rendering construct that has follows\nthe already mentioned three steps. The catch here is:\nall primitives are added up and have a priority. This\npriority is used to determine the order in which they are\nrendered.\nThe render step itself is split into three parts then:\npre-render, render and post-render. The pre-render step\nis used to allow a primitive to do some pre-rendering\nsetup, like setting up a clipping region. The render step\nis used to actually render the primitive. The post-render\nstep is used to clean up after the rendering or add some\noverlay (like a border).\nThe primitives are then rendered in order of their priority,\nhaving every step being called in the render order.\n\nThis allows for a very flexible rendering pipeline, where\nevery primitive can do whatever it wants, but still have\na clear way to do most shenanigans one would want to do.\n\n### Measuring and Arranging\nJust like rendering, measuring and arranging is done in\nthe common way but with a twist that is easier explained\nusing a sample: A scroll panel.\n\nImagine you have a scroll panel that has a height of 100px\nand want to render a list of items in it.\nThe list of items is 200px high (note that this for now\nassumes that the list is fully rendered, not virtualized).\nTo now render the list, we have to measure it and the\nscroll panel.\nThe scroll panel has a scroll bar, potentially, and the\n\"child\" to render (more on that later).\nIgnoring the fact that this could be solved using two\ncontrols, we now have to render our list and the scroll\nbar in 100px height. To do this, the measure step\nwill first take the lowest priority child and measure it,\npassing the measured size to the next child, allowing it to\nappend its size to the passed size. In our sample, the\nlist returns 200px height, which is then passed to the\nscroll bar, which returns 100px height (the actual act of\nrendering can later be resolved using clipping regions).\nThis effectively allows for a very simple way to change\nthe measure of a control by different composition parts.\n\nSimilar to the measure step, the arrange step will take\nthe measured size and only change the direction of the\npassing of the size. This allows for a very simple way\nto arrange controls in a space, limited only by the\nimagination of the developer.\n\n### State\nWhile technically speaking, rendering is a three step process,\nit often is overlooked that there is a step 0: Reseting the\nstate.\n\nslate-ui is not stateless for its rendering! It is stateful,\nusing the structures to store the state of rendering.\nThis essentially brings back in the object-oriented way\nof doings things, making it easier to reason about the\nui system.\n\nBut let us quickly elaborate on the decision to make the \nprimitives stateful and thus not immutable:\nRendering is a stateful process. You have to keep track\nof what you have rendered and what you will render.\nWhile technically speaking, you could make the primitives\nimmutable, creating a full new tree for every step,\ndoing so would make the rendering process rather complicated.\nThis is why slate-ui opts for a stateful approach, where\nthe primitives are mutable and can change their state\nbetween the render steps.\n\nThis may feel counter-intuitive for rust developers, but\nit is the way used by non-rust ui frameworks for a reason.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fx39%2Fslate-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fx39%2Fslate-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fx39%2Fslate-ui/lists"}