{"id":30417959,"url":"https://github.com/fubardevelopment/layoutengine","last_synced_at":"2026-03-02T21:08:18.623Z","repository":{"id":200036935,"uuid":"703763159","full_name":"FubarDevelopment/LayoutEngine","owner":"FubarDevelopment","description":"Layout engine (Wiindows Forms and generic)","archived":false,"fork":false,"pushed_at":"2025-07-15T17:08:05.000Z","size":224,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-23T16:39:02.308Z","etag":null,"topics":["layout","layout-engine","windows-forms"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FubarDevelopment.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null}},"created_at":"2023-10-11T21:40:06.000Z","updated_at":"2025-07-15T17:07:59.000Z","dependencies_parsed_at":"2023-11-25T22:38:00.561Z","dependency_job_id":null,"html_url":"https://github.com/FubarDevelopment/LayoutEngine","commit_stats":null,"previous_names":["fubardevelopment/layoutengine"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/FubarDevelopment/LayoutEngine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FubarDevelopment%2FLayoutEngine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FubarDevelopment%2FLayoutEngine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FubarDevelopment%2FLayoutEngine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FubarDevelopment%2FLayoutEngine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FubarDevelopment","download_url":"https://codeload.github.com/FubarDevelopment/LayoutEngine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FubarDevelopment%2FLayoutEngine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279017035,"owners_count":26085951,"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","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["layout","layout-engine","windows-forms"],"created_at":"2025-08-22T07:00:39.266Z","updated_at":"2025-10-13T21:34:15.859Z","avatar_url":"https://github.com/FubarDevelopment.png","language":"C#","readme":"# Layout engine for Windows Forms applications\n\nThis is a layout engine for WinForms applications, which took\ninspirations from the following sources:\n\n- [WPF Grid](https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.grid)\n- [ETS Layout](https://www.codeproject.com/articles/116/layout-manager-for-dialogs-formviews-dialogbars-an)\n\n# Example\n\nThis is the dialog we'd like to layout:\n\n![Sample dialog](doc/images/sample-dialog.png)\n\n## Requirements\n\n- \"pnlLogo\" must always be at the left top position\n- \"pnlModuleSelector\" must fill the space between the logo and the \"pnlDashboard\"\n- \"pnlMenu\" and \"pnlDialogView\" must always stay together\n- \"pnlMenu\" and \"pnlDialogView\" must always be in the center of the remaining space\n\n## Solution\n\nWe use panes to group together the various controls/panes.\n\n- We always need to create a root pane with a horizontal layout\n- The root pane is split into two sub-panes\n    - The pane for the space left to the dashboard\n    - The pane for the dashboard\n- The pane for the space left to the dashboard is split into four elements\n    - The pane for the \"pnlLogo\" and the \"pnlModuleSelector\" (pane 1)\n    - The pane to fill the gap between the header and the next pane to keep the next pane centered\n    - The pane which contains the panes 4, 5, the \"pnlMenu\" and the \"pnlDialogView\"\n    - Another pane to fill the gap between the bottom and the previous pane to keep the previous pane centered\n\n## Code for the layout definition\n\n```c#\n_layoutRoot =\n    (CreateRoot(this, Orientation.Horizontal)\n    \u003c\u003c (Pane(Orientation.Vertical).Width(Factor(1))\n        \u003c\u003c (Pane().HorizontalStackLayout(VerticalAlignment.Top)\n            \u003c\u003c Item(pnlLogo)\n            \u003c\u003c Item(pnlModuleSelector).Width(Factor(1)))\n        \u003c\u003c Item().Height(Factor(1))\n        \u003c\u003c (Pane().HorizontalStackLayout(VerticalAlignment.Center)\n            \u003c\u003c Item().Width(Factor(1))\n            \u003c\u003c Item(pnlMenu)\n            \u003c\u003c Item(pnlDialogView)\n            \u003c\u003c Item().Width(Factor(1)))\n        \u003c\u003c Item().Height(Factor(1)))\n    \u003c\u003c Item(pnlDashboard))\n    .Build();\n```\n\nThe functions `CreateRoot`, `Pane`, and `Item` are static functions in the static\n `FubarDev.LayoutEngine.BuilderMethods` class. I'm using a the `using static` C#\n feature to simplify the function calls:\n\n ```c#\n using static FubarDev.LayoutEngine.BuilderMethods;\n using static FubarDev.LayoutEngine.AttachedProperties.AttachedSize;\n```\n\n This makes all static functions in the `BuilderMethods` class directly available.\n\n### Line-by-line explanation\n\n1. Store the built root pane into the variable `_layoutRoot`\n2. The `CreateRoot` creates the root pane for the `Form` whose elements are aligned horizontally\n3. A sub-pane is created for the space left to the \"pnlDashboard\"\n    - The child elements are stacked vertically\n    - The element should consume the whole remaining space (see \"*\" notation of the WPF grid for grid rows/columns)\n4. A sub-pane is created for the header (pane 1)\n    - The child elements are stacked horizontally\n    - The default vertical alignment for the elements will be \"top\"\n        - This causes the child elements to keep their height\n5. Add the \"pnlLogo\" as first child element of the header pane (pane 1)\n6. Add the \"pnlModuleSelector\" as the second child element which should use the remaining width of the header pane (pane 1)\n7. Adds a spacer pane (pane 2)\n8. Adds the pane containing the spacer panes 4 and 5, and the \"pnlMenu\" and \"pnlDialogView\"\n    - All child elements should be centered vertically\n9. Adds the spacer pane (pane 4)\n    - This pane, together with pane 5 ensures that the \"pnlMenu\" and \"pnlDialogView\" are centered horizontally\n    - The `.Width(AttachedSize.Factor(1))` on this pane and pane 5 causes the space\n      not used by \"pnlMenu\" and \"pnlDialogView\" to be split equally between the panes 4 and 5.\n10. Adds the \"pnlMenu\"\n11. Adds the \"pnlDialogView\"\n12. Adds the spacer pane (pane 5)\n13. Adds the spacer pane (pane 3)\n14. Adds the \"pnlDashboard\"\n\nUsing `Orientation.Horizontal` for a pane results in the child elements\nbeing stretched to the full height of the surrounding pane. This behavior\ncan be changed by omitting the `Orientation.Horizontal` and using the\nmethod `.HorizontalStackLayout(VerticalAlignment.Top)` to provide a different\ndefault vertical alignment.\n\n## Example dump\n\nThis dump contains the names of all elements for a layout, together\nwith the calculated minimum size for the element.\n\n```text\nroot: {X=467,Y=415,Width=1232,Height=988}, {Width=1086, Height=762}\n nonDashboardArea: {X=3,Y=4,Width=875,Height=916}, {Width=753, Height=754}\n  headerArea: {X=3,Y=4,Width=875,Height=170}, {Width=154, Height=170}\n   pnlLogo: {X=6,Y=8,Width=142,Height=162}, {Width=142, Height=162}\n   pnlModuleSelector: {X=154,Y=8,Width=721,Height=162}, {Width=0, Height=162}\n  spacerTop: {X=3,Y=174,Width=875,Height=81}, {Width=0, Height=0}\n  mainArea: {X=3,Y=255,Width=875,Height=584}, {Width=753, Height=584}\n   spacerLeft: {X=3,Y=547,Width=61,Height=0}, {Width=0, Height=0}\n   pnlMenu: {X=67,Y=259,Width=225,Height=576}, {Width=225, Height=576}\n   pnlDialogView: {X=298,Y=259,Width=516,Height=576}, {Width=516, Height=576}\n   spacerRight: {X=817,Y=547,Width=61,Height=0}, {Width=0, Height=0}\n  spacerBottom: {X=3,Y=839,Width=875,Height=81}, {Width=0, Height=0}\n pnlDashboard: {X=881,Y=8,Width=321,Height=908}, {Width=321, Height=0}\n```\n\n## Performing the layout\n\nThe layout won't be performed automatically, which is a design decision,\nnot a technical decision.\n\nTo perform the layout, you must explicitly execute the following code:\n\n```c#\n_layoutRoot.Layout();\n```\n\n## Setting the minimum size of a form\n\nThe minimum size of the form can only be calculated if the form (and thus all\nits controls) are visible, which is the reason why you should put the following\ncode into the `VisibleChanged` event handler of the form:\n\n```c#\nvar minSize = _layoutRoot.GetMinimumClientSize();\nvar borderSize = Size - ClientSize;\nMinimumSize = minSize + borderSize;\n```\n\n# Advanced features\n\n## Overlaps\n\nIt's possible to make elements overlap each other.\n\n### Example\n\n```c#\n_layoutRoot =\n    (CreateRoot(this, Orientation.Horizontal)\n    \u003c\u003c (Pane(Orientation.Vertical).Width(Factor(1))\n        \u003c\u003c (Pane().HorizontalStackLayout(VerticalAlignment.Top)\n            \u003c\u003c Item(pnlLogo)\n            \u003c\u003c Item(pnlModuleSelector).Width(Factor(1)))\n        \u003c\u003c Pane().Height(Factor(1)).Identifier(\"a\"))\n    \u003c\u003c Item(pnlDashboard))\n    .AddOverlap(\n        \"a\",\n        Pane(Orientation.Vertical)\n        \u003c\u003c Item().Height(Factor(1))\n        \u003c\u003c (Pane().HorizontalStackLayout(VerticalAlignment.Center)\n            \u003c\u003c Item().Width(Factor(1))\n            \u003c\u003c Item(pnlMenu)\n            \u003c\u003c Item(pnlDialogView)\n            \u003c\u003c Item().Width(Factor(1)))\n        \u003c\u003c Item().Height(Factor(1)))\n    .Build();\n```\n\nAs you might've noticed, there's now a new function to `Identifier`.\nThis adds an application-global identifier to the given layout element.\nItems that overlap the items with the given `Identifier` may now\nbe overlapped with the other controls by calling the `AddOverlap`\nfunction, which takes the identifier of the layout element to\nbe overlapped and the layout that will overlap the target\nlayout element.\n\nYou may specify more that one \"overlap\" for a given layout element.\n\nThe idea behind this is, that you may have two or more controls\nthat should take the same space in the form, but only one should be visible\nat all times.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffubardevelopment%2Flayoutengine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffubardevelopment%2Flayoutengine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffubardevelopment%2Flayoutengine/lists"}