{"id":18831043,"url":"https://github.com/allendang/gimu","last_synced_at":"2025-07-09T18:35:41.033Z","repository":{"id":57502763,"uuid":"228324194","full_name":"AllenDang/gimu","owner":"AllenDang","description":"Cross-platform GUI for go is never this easy and clean.","archived":false,"fork":false,"pushed_at":"2020-02-17T07:13:44.000Z","size":5844,"stargazers_count":73,"open_issues_count":1,"forks_count":4,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-14T04:11:54.477Z","etag":null,"topics":["cross-platform-gui","golang","gui","nuklear"],"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/AllenDang.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}},"created_at":"2019-12-16T07:05:44.000Z","updated_at":"2025-02-24T19:40:33.000Z","dependencies_parsed_at":"2022-09-01T23:22:55.456Z","dependency_job_id":null,"html_url":"https://github.com/AllenDang/gimu","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/AllenDang%2Fgimu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AllenDang%2Fgimu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AllenDang%2Fgimu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AllenDang%2Fgimu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AllenDang","download_url":"https://codeload.github.com/AllenDang/gimu/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248819403,"owners_count":21166477,"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":["cross-platform-gui","golang","gui","nuklear"],"created_at":"2024-11-08T01:51:39.311Z","updated_at":"2025-04-14T04:12:07.565Z","avatar_url":"https://github.com/AllenDang.png","language":"C","readme":"# gimu\n\nStrongly suggest NOT to use this project anymore, the auto-generated cgo wrapper of Nuklear has a random crash issue which is hard to fix (because cgo doesn't provide detail information about where the crash exactly happened).\n\nPlease consider to use [giu](https://github.com/AllenDang/giu) instead. It's very stable and actively developed.\n\nCross-platform GUI for go based on nuklear.\n\nPackage nk provides Go bindings for nuklear.h — a small ANSI C gui library. See [github.com/Immediate-Mode-UI/Nuklear](https://github.com/Immediate-Mode-UI/Nuklear).\n\nAll the binding code has automatically been generated with rules defined in [nk.yml](/nk.yml).\n\nThis package provides a go-style idiomatic wrapper for nuklear.\n\n## Screenshots\n\n\u003cimg src=\"https://github.com/AllenDang/gimu/blob/master/examples/screenshots.png\" alt=\"Simple demo screen shots\" width=\"800\"/\u003e\n\n\u003cimg src=\"https://github.com/AllenDang/gimu/blob/master/examples/screenshots2.png\" alt=\"Chart demo screen shots\" width=\"800\"/\u003e\n\n## Overview\n\nSupported platforms are:\n\n* Windows 32-bit\n* Windows 64-bit\n* OS X\n* Linux\n\nThe desktop support is achieved using [GLFW](https://github.com/go-gl/glfw) and there are backends written in Go for OpenGL 3.2.\n\n### Installation\n\nJust go get it and everythings ready to work.\n\n```\ngo get -u github.com/AllenDang/gimu\n```\n\n### Getting start\n\nLet's create a simple demo.\n\n```go\npackage main\n\nimport (\n  \"fmt\"\n  \"image\"\n  \"runtime\"\n\n  \"github.com/AllenDang/gimu\"\n)\n\nfunc builder(w *gimu.Window) {\n  // Create a new window inside master window\n  width, height := w.MasterWindow().GetSize()\n  bounds := nk.NkRect(0, 0, float32(width), float32(height))\n\n  w.Window(\"Simple Demo\", bounds, nk.WindowNoScrollbar, func(w *gimu.Window) {\n    // Define the row with 25px height, and contains one widget for each row.\n    w.Row(25).Dynamic(1)\n    // Let's create a label first, note the second parameter \"LC\" means the text alignment is left-center.\n    w.Label(\"I'm a label\", \"LC\")\n    // Create a button.\n    clicked := w.Button(\"Click Me\")\n    if clicked {\n      fmt.Println(\"The button is clicked\")\n    }\n  })\n}\n\nfunc main() {\n  runtime.LockOSThread()\n\n  // Create master window\n  wnd := gimu.NewMasterWindow(\"Simple Demo\", 200, 100, gimu.MasterWindowFlagDefault)\n\n  wnd.Main(builder)\n}\n```\n\nSave and run.\n\n### Deploy\n\ngimu provides a tool to pack compiled executable for several platform to enable app icon and etc.\n\n```\ngo get -u github.com/AllenDang/gimu/cmd/gmdeploy\n```\n\nRun gmdeploy in your project folder.\n\n```\ngmdeploy -icon AppIcon.icns .\n```\n\nThen you can find bundled executable in [PROJECTDIR]/build/[OS]/\n\nNote:\n\nCurrently only MacOS is supported. Windows and linux is WIP.\n\n### Layout system\n\nLayouting in general describes placing widget inside a window with position and size. While in this particular implementation there are two different APIs for layouting\n\nAll layouting methods in this library are based around the concept of a row.\n\nA row has a height the window content grows by and a number of columns and each layouting method specifies how each widget is placed inside the row.\n\nAfter a row has been allocated by calling a layouting functions and then filled with widgets will advance an internal pointer over the allocated row. \n\nTo actually define a layout you just call the appropriate layouting function and each subsequent widget call will place the widget as specified. Important here is that if you define more widgets then columns defined inside the layout functions it will allocate the next row without you having to make another layouting call.\n\n#### Static layout\n\nDefine a row with 25px height with two widgets.\n\n```go\nw.Row(25).Static(50, 50)\n```\n\nUse the magic number 0 to define a widget will auto expand if there is enough space.\n\n```go\nw.Row(25).Static(0, 50)\nw.Label(\"I'm a auto growth label\", \"LC\")\nw.Button(\"I'm a button with fixed width\")\n```\n\n#### Dynamic layout\n\nIt provides each widgets with same horizontal space inside the row and dynamically grows if the owning window grows in width. \n\nDefine a row with two widgets each of them will have same width.\n\n```go\nw.Row(25).Dynamic(2)\n```\n\n#### Flexible Layout\n\nFinally the most flexible API directly allows you to place widgets inside the window. The space layout API is an immediate mode API which does not support row auto repeat and directly sets position and size of a widget. Position and size hereby can be either specified as ratio of allocated space or allocated space local position and pixel size. Since this API is quite powerful there are a number of utility functions to get the available space and convert between local allocated space and screen space.\n\n```go\nw.Row(500).Space(nk.Static, func(w *gimu.Window) {\n  w.Push(nk.NkRect(0, 0, 150, 150))\n    w.Group(\"Group Left\", nk.WindowBorder|nk.WindowTitle, func(w *gimu.Window) {\n  })\n\n  w.Push(nk.NkRect(160, 0, 150, 240))\n    w.Group(\"Group Top\", nk.WindowBorder|nk.WindowTitle, func(w *gimu.Window) {\n  })\n\n  w.Push(nk.NkRect(160, 250, 150, 250))\n  w.Group(\"Group Bottom\", nk.WindowBorder|nk.WindowTitle, func(w *gimu.Window) {\n  })\n\n  w.Push(nk.NkRect(320, 0, 150, 150))\n  w.Group(\"Group Right Top\", nk.WindowBorder|nk.WindowTitle, func(w *gimu.Window) {\n  })\n\n  w.Push(nk.NkRect(320, 160, 150, 150))\n  w.Group(\"Group Right Center\", nk.WindowBorder|nk.WindowTitle, func(w *gimu.Window) {\n  })\n\n  w.Push(nk.NkRect(320, 320, 150, 150))\n  w.Group(\"Group Right Center\", nk.WindowBorder|nk.WindowTitle, func(w *gimu.Window) {\n  })\n})\n```\n\n## Widgets usage\n\nMost of the widget's usage are very straight forward.\n\n### Common widgets\n\n#### Label\n\nThe second parameter of label indicates the text alignment.\n\n```go\nw.Label(\"Label caption\", \"LC\")\n```\n\n\"LC\" means horizontally left and vertically center.\n\n\"LT\" means horizontally left and vertically top.\n\nThe alignment char layout is listed below, you could use any combinations of those.\n\n   T\n\nL-C-R\n\n   B\n\n#### Selectable Label\n\nLabel can be toggled by mouse click.\n\n```go\nvar selected bool\nw.SelectableLabel(\"Selectable 1\", \"LC\", \u0026selected1)\n```\n\n#### Button\n\nButton function will return a bool to indicate whether it was clicked.\n\n```go\nclicked := w.Button(\"Click Me\")\nif clicked {\n  // Do something here\n}\n```\n\n#### Progressbar\n\nProgress could be readonly or modifiable.\n\n```go\nprogress := 0\n// Modifiable\nw.Progress(\u0026progress, 100, true)\n// Readonly\nw.Progress(\u0026progress, 100, false)\n```\n\nTo read current progress or update progress bar, just set the progress variable.\n\n#### Slider\n\nSlider behaves like progress bar but step control.\n\n```go\nvar slider int\nw.SliderInt(0, \u0026slider, 100, 1)\n```\n\n#### Property widgets\n\nIt contains a label and a adjustable control to modify int or float variable.\n\n``` go\nvar propertyInt int\nvar propertyFloat float32\nw.PropertyInt(\"Age\", 1, \u0026propertyInt, 100, 10, 1)\nw.PropertyFloat(\"Height\", 1, \u0026propertyFloat, 10, 0.2, 1)\n```\n\n#### Checkbox\n\n```go\nvar checked bool\nw.Checkbox(\"Check me\", \u0026checked)\n```\n\n#### Radio\n\n```go\noption := 1\nif op1 := w.Radio(\"Option 1\", option == 1); op1 {\n  option = 1\n}\nif op2 := w.Radio(\"Option 2\", option == 2); op2 {\n  option = 2\n}\nif op3 := w.Radio(\"Option 3\", option == 3); op3 {\n  option = 3\n}\n```\n\n#### Textedit\n\nTextedit is special because it will retain the input string, so you will have to explicitly create it and call the Edit() function in BuilderFunc.\n\n```go\ntextedit := gimu.NewTextEdit()\n\nfunc builder(w *gimu.Window) {\n  textedit.Edit(w, gimu.EditField, gimu.EditFilterDefault)\n}\n```\n\n#### ListView\n\nListView is designed to display very huge amount of data and only render visible items.\n\n```go\nvar (\n  listview *nk.ListView\n  listitem []interface{}\n)\n\nfunc builder(w *gimu.Window) {\n  width, height := w.MasterWindow().GetSize()\n  bounds := nk.NkRect(0, 0, float32(width), float32(height))\n  w.Window(\"\", bounds, 0, func(w *gimu.Window) {\n    w.Row(int(height - 18)).Dynamic(1)\n    w.ListView(listview, \"huge list\", nk.WindowBorder, 25,\n      listitem,\n      func(r *gimu.Row) {\n        r.Dynamic(1)\n      },\n      func(w *gimu.Window, i int, item interface{}) {\n        if s, ok := item.(string); ok {\n          w.Label(s, \"LC\")\n        }\n      })\n  })\n}\n\nfunc main() {\n  // Init the listview widget\n  listview = \u0026nk.ListView{}\n\n  // Create list items\n  listitem = make([]interface{}, 12345)\n  for i := range listitem {\n    listitem[i] = fmt.Sprintf(\"Label item %d\", i)\n  }\n\n  runtime.LockOSThread()\n\n  wnd := gimu.NewMasterWindow(\"Huge list\", 800, 600, gimu.MasterWindowFlagNoResize)\n  wnd.Main(builder)\n}\n```\n\n### Popups\n\n#### Tooltip\n\n**Note: Tooltip has to be placed above the widget which wants a tooltip when mouse hovering.**\n\n```go\nw.Tooltip(\"This is a tooltip\")\nw.Button(\"Hover me to see tooltip\")\n```\n\n#### Popup Window\n\n```go\nfunc msgbox(w *gimu.Window) {\n  opened := w.Popup(\n    \"Message\", \n    gimu.PopupStatic, \n    nk.WindowTitle|nk.WindowNoScrollbar|nk.WindowClosable, \n    nk.NkRect(30, 10, 300, 100), \n    func(w *gimu.Window) {\n      w.Row(25).Dynamic(1)\n      w.Label(\"Here is a pop up window\", \"LC\")\n      if w.Button(\"Close\") {\n        showPopup = false\n        w.ClosePopup()\n      }\n    })\n  if !opened {\n    showPopup = false\n  }\n}\n```\n\n### Menu\n\n#### Window Menu\n\n**Note: window menu bar has to be the first widget in the builder method.**\n\n```go\n// Menu\nw.Menubar(func(w *gimu.Window) {\n  w.Row(25).Static(60, 60)\n  // Menu 1\n  w.Menu(\"Menu1\", \"CC\", 200, 100, func(w *gimu.Window) {\n    w.Row(25).Dynamic(1)\n    w.MenuItemLabel(\"Menu item 1\", \"LC\")\n    w.MenuItemLabel(\"Menu item 2\", \"LC\")\n    w.Button(\"Button inside menu\")\n  })\n  // Menu 2\n  w.Menu(\"Menu2\", \"CC\", 100, 100, func(w *gimu.Window) {\n    w.Row(25).Dynamic(1)\n    w.MenuItemLabel(\"Menu item 1\", \"LC\")\n    w.SliderInt(0, \u0026slider, 100, 1)\n    w.MenuItemLabel(\"Menu item 2\", \"LC\")\n  })\n})\n```\n\n#### Contextual Menu\n\n**Note: Contextual menu has to be placed above the widget which wants a tooltip when right click.**\n\nYou could put any kind of widgets inside the contextual menu.\n\n```go\nw.Contextual(0, 100, 300, func(w *gimu.Window) {\n  w.Row(25).Dynamic(1)\n  w.ContextualLabel(\"Context menu 1\", \"LC\")\n  w.ContextualLabel(\"Context menu 1\", \"LC\")\n  w.SliderInt(0, \u0026slider, 100, 1)\n})\nw.Button(\"Right click me\")\n```\n\n## License\n\nAll the code except when stated otherwise is licensed under the [MIT license](https://xlab.mit-license.org).\nNuklear (ANSI C version) is in public domain, authored from 2015-2016 by Micha Mettke.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fallendang%2Fgimu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fallendang%2Fgimu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fallendang%2Fgimu/lists"}