Files
jack-looper/docs/usage.md
Loic Coenen 05c6f34b8f feat: add microui-based GUI with transport controls and progress bar
Co-authored-by: aider (deepseek/deepseek-coder) <aider@aider.chat>
2026-05-01 13:02:39 +00:00

303 KiB
Raw Blame History

<html lang="en"

data-color-mode="auto" data-light-theme="light" data-dark-theme="dark" data-a11y-animated-images="system" data-a11y-link-underlines="true"

<head> <style type="text/css"> :root { --tab-size-preference: 4; } pre, code { tab-size: var(--tab-size-preference); } </style>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-7f694b60439d06c0.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-b48faa60c69660fa.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-b40ec823a1a6a1af.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-f825c0edd7ad57f8.css" />
<script type="application/json" id="client-env">{"locale":"en","featureFlags":["actions_custom_images_storage_billing_ui_visibility","actions_image_version_event","actions_workflow_language_service_allow_concurrency_queue","agent_conflict_resolution","alternate_user_config_repo","arianotify_comprehensive_migration","billing_discount_threshold_notification","code_scanning_dfa_degraded_experience_notice","codespaces_prebuild_region_target_update","codespaces_tab_react","coding_agent_model_selection","coding_agent_model_selection_all_skus","comment_viewer_copy_raw_markdown","contentful_primer_code_blocks","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_automation_session_author","copilot_chat_attach_multiple_images","copilot_chat_category_rate_limit_messages","copilot_chat_clear_model_selection_for_default_change","copilot_chat_contextual_suggestions_updated","copilot_chat_enable_tool_call_logs","copilot_chat_file_redirect","copilot_chat_input_commands","copilot_chat_opening_thread_switch","copilot_chat_prettify_pasted_code","copilot_chat_reduce_quota_checks","copilot_chat_search_bar_redirect","copilot_chat_selection_attachments","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_diff_explain_conversation_intent","copilot_diff_reference_context","copilot_duplicate_thread","copilot_extensions_hide_in_dotcom_chat","copilot_extensions_removal_on_marketplace","copilot_features_sql_server_logo","copilot_file_block_ref_matching","copilot_ftp_hyperspace_upgrade_prompt","copilot_icebreakers_experiment_dashboard","copilot_icebreakers_experiment_hyperspace","copilot_immersive_code_block_transition_wrap","copilot_immersive_embedded","copilot_immersive_embedded_deferred_payload","copilot_immersive_embedded_draggable","copilot_immersive_embedded_header_button","copilot_immersive_embedded_implicit_references","copilot_immersive_file_block_transition_open","copilot_immersive_file_preview_keep_mounted","copilot_immersive_job_result_preview","copilot_immersive_structured_model_picker","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mission_control_always_send_integration_id","copilot_mission_control_cli_session_status","copilot_mission_control_initial_data_spinner","copilot_mission_control_logs_incremental","copilot_mission_control_task_alive_updates","copilot_org_policy_page_focus_mode","copilot_redirect_header_button_to_agents","copilot_resource_panel","copilot_scroll_preview_tabs","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spaces_pagination","copilot_spark_empty_state","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_unconfigured_is_inherited","copilot_upgrade_freeze","copilot_usage_metrics_ga","copilot_workbench_slim_line_top_tabs","custom_instructions_file_references","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","dotgithub_fork_warning","flex_cta_groups_mvp","global_nav_react","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","ipm_global_transactional_message_agents","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","issue_cca_modal_open","issue_cca_multi_assign_modal","issue_cca_task_side_panel","issue_cca_visualization","issue_cca_visualization_session_panel","issue_fields_global_search","issues_expanded_file_types","issues_lazy_load_comment_box_suggestions","issues_react_bots_timeline_pagination","issues_react_chrome_container_query_fix","issues_search_type_gql","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","low_quality_classifier","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_status_header_feedback","notifications_menu_defer_labels","oauth_authorize_clickjacking_protection","octocaptcha_origin_optimization","prs_conversations_react","prs_css_anchor_positioning","rules_insights_filter_bar_created","sample_network_conn_type","secret_scanning_pattern_alerts_link","security_center_artifact_filters_popover","session_logs_ungroup_reasoning_text","site_features_copilot_universe","site_homepage_collaborate_video","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","ui_skip_on_anchor_click","viewscreen_sandbox","warn_inaccessible_attachments","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"}</script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/high-contrast-cookie-218067197ba03c91.js"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/wp-runtime-99fe43e971cd2379.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/fetch-utilities-3140609b5732710f.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/28839-7adfdde5afeb1a03.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/85924-ac5602ef611dc506.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/34646-4c7883eb242d5210.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/environment-a12df3cf35884818.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/runtime-helpers-cb4dfbc9d23f30be.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/2966-d68f2b4558d86113.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/96232-540ff5f81016a9ca.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/41013-647932573fc130af.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/51210-45dfb7dd106f6b96.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/64247-73a9861fe185671f.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/81683-382ccc88e034ea1d.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/9338-f6bee5a8d66d930f.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/46740-5a373320e5ef9c01.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/67466-79abcbf599986a00.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/github-elements-61af8f0198be4afd.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/element-registry-bb0ddc66dbc0b1de.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/react-core-1bf2dfbca21efd20.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/react-lib-1353f2cef82bcdc0.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/58889-5b136bc717e57a8b.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/79039-69acf717ffc901a4.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/61110-073153e0413daf3a.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/2887-91b9c645d570616a.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/26533-f22c29ae5e9b1ed2.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/86483-c3a819d46503a3da.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/37460-fcd4830a1194eace.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/60481-24b13ea726837f7b.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/46287-853bfcb69bb5b3f9.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/2498-f0375ed070e22e54.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/61025-5b1312da907b4074.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/89627-40275597692dc855.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/79087-4f706db8aa2ec0fb.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/49029-42bd0899fca05960.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/99328-a2c6b180d25cb160.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/behaviors-05170beef7088f93.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/4244-97fb660009234136.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/notifications-global-442a23b66c306470.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/39373-075d662e5ab13538.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/code-menu-ad3e18f5935a3ed8.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/primer-react-c90c0af6f94c2ff4.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/octicons-react-60e727d7a1b6f52c.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/89960-3369b8943362e07e.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/37869-3811d0fa923a406d.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/68751-830b37204cdf7847.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/7463-30e02617b93e1c07.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/15272-0fca7ba11b03440f.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/32769-abc9916acf2cd4f1.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/36505-9798da05fe2143ec.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/46148-264173ef30e2e838.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/57712-447a29413bbba322.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/61545-6a3a31f92bb5e61a.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/20999-9b5648501d55c42d.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/98228-7a59d90d972526cc.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/63991-466700d8cea41498.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/59852-fc77b3df0a08d405.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/3624-fdb7d4ead672734b.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/66231-a2e789b56df018f7.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/71001-7431ccad12c501aa.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/33684-bbaee6839ab84dd8.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/18222-8b85d637a2041072.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/96755-770967b1236437cd.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/4916-0bb8c44ba1b3d0f7.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/75674-28ffd7157e7cb9e8.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/75601-d9eafa1fbbb5172b.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/8987-366fbcea269300af.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/38184-1e8a3a630d385487.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/41110-df3d2329c8277a27.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/22216-7b6bcf152c4599f6.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/32639-b4f0cdce4bef4ac5.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/58085-77d3143b51231967.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/66519-27db8d6ec9c71a98.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/50110-0f4d902364ca3e5b.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/26497-bb0dd27f414e3e71.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/49135-5f8ca97edb189a81.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/71920-723318c28b0f8f3a.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/code-view-121a46f29c0d4946.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/70234-1ee48b3a4eebdc7d.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/notifications-subscriptions-menu-8cd581c0af350d7f.js" defer="defer"></script>
<meta name="hovercard-subject-tag" content="repository:149854705" data-turbo-transient>
<meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I">
<meta name="user-login" content="">



<meta name="viewport" content="width=device-width">



  <meta name="description" content="A tiny immediate-mode UI library. Contribute to rxi/microui development by creating an account on GitHub.">

  <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">

<link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
<meta property="fb:app_id" content="1401488693436528">
<meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/rxi/microui/blob/master/doc/usage.md" />

  <meta name="twitter:image" content="https://opengraph.githubassets.com/fb782404943e40f6b55639439b9497c64d00b144e77dde51739df9a72e1be973/rxi/microui" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="microui/doc/usage.md at master · rxi/microui" /><meta name="twitter:description" content="A tiny immediate-mode UI library. Contribute to rxi/microui development by creating an account on GitHub." />
  <meta name="hostname" content="github.com">



    <meta name="expected-hostname" content="github.com">
  <meta name="turbo-cache-control" content="no-cache" data-turbo-transient>

<meta data-hydrostats="publish">
<meta name="turbo-body-classes" content="logged-out env-production page-responsive">
</head>
<div class="position-relative header-wrapper js-header-wrapper ">
  <a href="#start-of-content" data-skip-target-assigned="false" class="px-2 tmp-py-4 color-bg-accent-emphasis color-fg-on-emphasis show-on-focus js-skip-to-content">Skip to content</a>

  <span data-view-component="true" class="progress-pjax-loader Progress position-fixed width-full">
<span style="width: 0%;" data-view-component="true" class="Progress-item progress-pjax-loader-bar left-0 top-0 color-bg-accent-emphasis"></span>
  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.00ba154d21e54e53.module.css" />

<react-partial partial-name="keyboard-shortcuts-dialog" data-ssr="false" data-attempted-ssr="false" data-react-profiling="false"

<script type="application/json" data-target="react-partial.embeddedData">{"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}</script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/46752-7bd8967216f7ea42.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/90350-89ca7e5359af8f77.js" defer="defer"></script> <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/sessions-e0da6ce03532723c.js" defer="defer"></script> <style> /* Override primer focus outline color for marketing header dropdown links for better contrast */ [data-color-mode="light"] .HeaderMenu-dropdown-link:focus-visible, [data-color-mode="light"] .HeaderMenu-trailing-link a:focus-visible { outline-color: var(--color-accent-fg); } </style>

Navigation Menu

Toggle navigation
  <a class="tmp-mr-lg-3 color-fg-inherit flex-order-2 js-prevent-focus-on-mobile-nav"
    href="/"
    aria-label="Homepage"
    data-analytics-event="{&quot;category&quot;:&quot;Marketing nav&quot;,&quot;action&quot;:&quot;click to go to homepage&quot;,&quot;label&quot;:&quot;ref_page:Marketing;ref_cta:Logomark;ref_loc:Header&quot;}">
    <svg height="32" aria-hidden="true" viewBox="0 0 24 24" version="1.1" width="32" data-view-component="true" class="octicon octicon-mark-github">
<path d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943"></path>
  <div class="d-flex flex-1 flex-order-2 text-right d-lg-none gap-2 flex-justify-end">
      <a
        href="/login?return_to=https%3A%2F%2Fgithub.com%2Frxi%2Fmicroui%2Fblob%2Fmaster%2Fdoc%2Fusage.md"
        class="HeaderMenu-link HeaderMenu-button d-inline-flex f5 no-underline border color-border-default rounded-2 px-2 py-1 color-fg-inherit js-prevent-focus-on-mobile-nav"
        data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/rxi/microui/blob/master/doc/usage.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="7cdd986d4f5ca9a0fdea330bb2a561ec575cd91a8e0742c575348424eb6818d9"
        data-analytics-event="{&quot;category&quot;:&quot;Marketing nav&quot;,&quot;action&quot;:&quot;click to Sign in&quot;,&quot;label&quot;:&quot;ref_page:Marketing;ref_cta:Sign in;ref_loc:Header&quot;}"
      >
        Sign in
      </a>
          <div class="AppHeader-appearanceSettings">
<react-partial-anchor>
  <button data-target="react-partial-anchor.anchor" id="icon-button-19c037d6-61be-4fcc-9089-f8ec408d76e5" aria-labelledby="tooltip-e6de1935-0dcb-4268-a3fb-23e2be4dbb40" type="button" disabled="disabled" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium AppHeader-button HeaderMenu-link border cursor-wait">  <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-sliders Button-visual">
<path d="M15 2.75a.75.75 0 0 1-.75.75h-4a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75Zm-8.5.75v1.25a.75.75 0 0 0 1.5 0v-4a.75.75 0 0 0-1.5 0V2H1.75a.75.75 0 0 0 0 1.5H6.5Zm1.25 5.25a.75.75 0 0 0 0-1.5h-6a.75.75 0 0 0 0 1.5h6ZM15 8a.75.75 0 0 1-.75.75H11.5V10a.75.75 0 1 1-1.5 0V6a.75.75 0 0 1 1.5 0v1.25h2.75A.75.75 0 0 1 15 8Zm-9 5.25v-2a.75.75 0 0 0-1.5 0v1.25H1.75a.75.75 0 0 0 0 1.5H4.5v1.25a.75.75 0 0 0 1.5 0v-2Zm9 0a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h6a.75.75 0 0 1 .75.75Z"></path>
Appearance settings
  <template data-target="react-partial-anchor.template">
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.00ba154d21e54e53.module.css" />

<react-partial partial-name="appearance-settings" data-ssr="false" data-attempted-ssr="false" data-react-profiling="false"

<script type="application/json" data-target="react-partial.embeddedData">{"props":{}}</script>
  </template>
</react-partial-anchor>
  </div>
</div>


<div class="HeaderMenu js-header-menu height-fit position-lg-relative d-lg-flex flex-column flex-auto top-0">
  <div class="HeaderMenu-wrapper d-flex flex-column flex-self-start flex-lg-row flex-auto rounded rounded-lg-0">
        <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.00ba154d21e54e53.module.css" />

<react-partial partial-name="marketing-navigation" data-ssr="true" data-attempted-ssr="true" data-react-profiling="false"

<script type="application/json" data-target="react-partial.embeddedData">{"props":{"should_use_dotcom_links":true}}</script>
<script type="application/json" id="__PRIMER_DATA__R_0___">{"resolvedServerColorMode":"day"}</script>
    <div class="d-flex flex-column flex-lg-row width-full flex-justify-end flex-lg-items-center text-center tmp-mt-3 tmp-mt-lg-0 text-lg-left tmp-ml-lg-3">
Search or jump to...
<input type="hidden" name="type" class="js-site-search-type-field">

Search code, repositories, users, issues, pull requests...

      <div data-view-component="true">        <div class="search-suggestions position-fixed width-full color-shadow-large border color-fg-default color-bg-default overflow-hidden d-flex flex-column query-builder-container"
      style="border-radius: 12px;"
      data-target="qbsearch-input.queryBuilderContainer"
      hidden
    >
      <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="query-builder-test-form" action="" accept-charset="UTF-8" method="get">
Clear
      </span>
  </div>
  <template id="search-icon">
    <div class="position-relative">
                    <ul
          role="listbox"
          class="ActionListWrap QueryBuilder-ListWrap"
          aria-label="Suggestions"
          data-action="
            combobox-commit:query-builder#comboboxCommit
            mousedown:query-builder#resultsMousedown
          "
          data-target="query-builder.resultsList"
          data-persist-list=false
          id="query-builder-test-results"
          tabindex="-1"
        ></ul>

    </div>
  <div class="FormControl-inlineValidation" id="validation-cec40d6d-5add-4f9e-bdb4-59fb380d376c" hidden="hidden">
    <span class="FormControl-inlineValidation--visual">
      <svg aria-hidden="true" height="12" viewBox="0 0 12 12" version="1.1" width="12" data-view-component="true" class="octicon octicon-alert-fill">
<path d="M4.855.708c.5-.896 1.79-.896 2.29 0l4.675 8.351a1.312 1.312 0 0 1-1.146 1.954H1.33A1.313 1.313 0 0 1 .183 9.058ZM7 7V3H5v4Zm-1 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"></path>
</div>

Provide feedback

</div>
<div class="Overlay-actionWrap">
  <button data-close-dialog-id="feedback-dialog" aria-label="Close" aria-label="Close" type="button" data-view-component="true" class="close-button Overlay-closeButton"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
<path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>

We read every piece of feedback, and take your input very seriously.

Cancel Submit feedback
<custom-scopes data-target="qbsearch-input.customScopesManager">

Saved searches

Use saved searches to filter your results more quickly

    <div hidden class="create-custom-scope-form" data-target="custom-scopes.createCustomScopeForm">
    <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="custom-scopes-dialog-form" data-turbo="false" action="/search/custom_scopes" accept-charset="UTF-8" method="post"><input type="hidden" data-csrf="true" name="authenticity_token" value="Q+mkbypeFoCtmkK2P+XrUe+URjXl0iYmLXStLAiX7z9ipT01K+ATO1FJOW19DWgPHFK12scCHnRf9HwKHcn5sw==" />
      <div data-target="custom-scopes.customScopesModalDialogFlash"></div>

      <input type="hidden" id="custom_scope_id" name="custom_scope_id" data-target="custom-scopes.customScopesIdField">

      <div class="form-group">
        <label for="custom_scope_name">Name</label>
        <auto-check src="/search/custom_scopes/check_name" required>
          <input
            type="text"
            name="custom_scope_name"
            id="custom_scope_name"
            data-target="custom-scopes.customScopesNameField"
            class="form-control"
            autocomplete="off"
            placeholder="github-ruby"
            required
            maxlength="50">
          <input type="hidden" data-csrf="true" value="vt22MvSW1cacEy5tYG6+X71+FtbGcZuIeZjgULSzz9SqMirFQsCSUM+JREfJ3Kw9et9n2YuIYH0d6xhpvFTE0g==" />
        </auto-check>
      </div>

      <div class="form-group">
        <label for="custom_scope_query">Query</label>
        <input
          type="text"
          name="custom_scope_query"
          id="custom_scope_query"
          data-target="custom-scopes.customScopesQueryField"
          class="form-control"
          autocomplete="off"
          placeholder="(repo:mona/a OR repo:mona/b) AND lang:python"
          required
          maxlength="500">
      </div>

      <p class="text-small color-fg-muted">
        To see all available qualifiers, see our <a class="Link--inTextBlock" href="https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax">documentation</a>.
      </p>
    <div data-target="custom-scopes.manageCustomScopesForm">
      <div data-target="custom-scopes.list"></div>
    </div>
Cancel Create saved search
        <div class="position-relative HeaderMenu-link-wrap d-lg-inline-block">
          <a
            href="/login?return_to=https%3A%2F%2Fgithub.com%2Frxi%2Fmicroui%2Fblob%2Fmaster%2Fdoc%2Fusage.md"
            class="HeaderMenu-link HeaderMenu-link--sign-in HeaderMenu-button flex-shrink-0 no-underline d-none d-lg-inline-flex border border-lg-0 rounded px-2 py-1"
            style="margin-left: 12px;"
            data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/rxi/microui/blob/master/doc/usage.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="7cdd986d4f5ca9a0fdea330bb2a561ec575cd91a8e0742c575348424eb6818d9"
            data-analytics-event="{&quot;category&quot;:&quot;Marketing nav&quot;,&quot;action&quot;:&quot;click to go to homepage&quot;,&quot;label&quot;:&quot;ref_page:Marketing;ref_cta:Sign in;ref_loc:Header&quot;}"
          >
            Sign in
          </a>
        </div>

          <a href="/signup?ref_cta=Sign+up&amp;ref_loc=header+logged+out&amp;ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fblob%2Fshow&amp;source=header-repo&amp;source_repo=rxi%2Fmicroui"
            class="HeaderMenu-link HeaderMenu-link--sign-up HeaderMenu-button flex-shrink-0 d-flex d-lg-inline-flex no-underline border color-border-default rounded px-2 py-1"
            data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/rxi/microui/blob/master/doc/usage.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="7cdd986d4f5ca9a0fdea330bb2a561ec575cd91a8e0742c575348424eb6818d9"
            data-analytics-event="{&quot;category&quot;:&quot;Sign up&quot;,&quot;action&quot;:&quot;click to sign up for account&quot;,&quot;label&quot;:&quot;ref_page:/&lt;user-name&gt;/&lt;repo-name&gt;/blob/show;ref_cta:Sign up;ref_loc:header logged out&quot;}"
          >
            Sign up
          </a>

            <div class="AppHeader-appearanceSettings">
<react-partial-anchor>
  <button data-target="react-partial-anchor.anchor" id="icon-button-f1ed9c8b-59fa-451b-b975-fe63510450e7" aria-labelledby="tooltip-8bc6f88e-6c0c-4f08-b0d2-4e2375d711fb" type="button" disabled="disabled" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium AppHeader-button HeaderMenu-link border cursor-wait">  <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-sliders Button-visual">
<path d="M15 2.75a.75.75 0 0 1-.75.75h-4a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75Zm-8.5.75v1.25a.75.75 0 0 0 1.5 0v-4a.75.75 0 0 0-1.5 0V2H1.75a.75.75 0 0 0 0 1.5H6.5Zm1.25 5.25a.75.75 0 0 0 0-1.5h-6a.75.75 0 0 0 0 1.5h6ZM15 8a.75.75 0 0 1-.75.75H11.5V10a.75.75 0 1 1-1.5 0V6a.75.75 0 0 1 1.5 0v1.25h2.75A.75.75 0 0 1 15 8Zm-9 5.25v-2a.75.75 0 0 0-1.5 0v1.25H1.75a.75.75 0 0 0 0 1.5H4.5v1.25a.75.75 0 0 0 1.5 0v-2Zm9 0a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h6a.75.75 0 0 1 .75.75Z"></path>
Appearance settings
  <template data-target="react-partial-anchor.template">
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.00ba154d21e54e53.module.css" />

<react-partial partial-name="appearance-settings" data-ssr="false" data-attempted-ssr="false" data-react-profiling="false"

<script type="application/json" data-target="react-partial.embeddedData">{"props":{}}</script>
  </template>
</react-partial-anchor>
      <button type="button" class="sr-only js-header-menu-focus-trap d-block d-lg-none">Resetting focus</button>
    </div>
  </div>
</div>
  <div hidden="hidden" data-view-component="true" class="js-stale-session-flash stale-session-flash flash flash-warn flash-full">

    <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert">
<path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
<button id="icon-button-826a9c3d-0d50-41a6-93d0-77c37dcd6b65" aria-labelledby="tooltip-efa1dc30-9f40-4ac2-b7a9-246ccd1d2607" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium flash-close js-flash-close">  <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x Button-visual">
<path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
Dismiss alert
<div id="js-flash-container" class="flash-container" data-turbo-replace>
  <div>{{ message }}</div>

</div>
  <div class="d-flex flex-nowrap flex-justify-end tmp-mb-3  tmp-px-3 tmp-px-lg-5" style="gap: 1rem;">

    <div class="flex-auto min-width-0 width-fit">
<span class="author flex-self-stretch" itemprop="author">
  <a class="url fn" rel="author" data-hovercard-type="user" data-hovercard-url="/users/rxi/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/rxi">
    rxi

/ microui

<span></span><span class="Label Label--secondary v-align-middle mr-1">Public</span>
    </div>

    <div id="repository-details-container" class="flex-shrink-0" data-turbo-replace style="max-width: 70%;">
        <ul class="pagehead-actions flex-shrink-0 d-none d-md-inline" style="padding: 2px 0;">

    <li>
      <include-fragment src="/rxi/microui/sponsor_button" data-nonce="v2:e0672f82-d347-7703-92d1-f6d281f58d6d" data-view-component="true">
  <h3 data-view-component="true" class="blankslate-heading">        Uh oh!

There was an error while loading. Please reload this page.

  • Notifications You must be signed in to change notification settings
  • Fork 364
  •     </div>
      </div>
    
        <div id="responsive-meta-container" data-turbo-replace>
    
          <nav data-pjax="#js-repo-pjax-container" aria-label="Repository" data-view-component="true" class="js-repo-nav js-sidenav-container-pjax js-responsive-underlinenav overflow-hidden UnderlineNav px-3 tmp-px-3 px-md-4 tmp-px-md-4 px-lg-5 tmp-px-lg-5">
    
    Additional navigation options
      <div data-view-component="true" class="Overlay-body Overlay-body--paddingNone">          <action-list>
    
    • <a tabindex="-1" id="item-21ee382d-d390-4c16-b4e3-58def344583e" href="/rxi/microui" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
          <span class="ActionListItem-visual ActionListItem-visual--leading">
            <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code">
      <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path>
      
          <span data-view-component="true" class="ActionListItem-label">
            Code
      
    • <a tabindex="-1" id="item-faaab1ed-10e0-4891-bee5-610b0a67b5c1" href="/rxi/microui/issues" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
          <span class="ActionListItem-visual ActionListItem-visual--leading">
            <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened">
      <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path>
      
          <span data-view-component="true" class="ActionListItem-label">
            Issues
      
    • <a tabindex="-1" id="item-abbe330c-5dcd-4a14-8bee-0eea70557295" href="/rxi/microui/pulls" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
          <span class="ActionListItem-visual ActionListItem-visual--leading">
            <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request">
      <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path>
      
          <span data-view-component="true" class="ActionListItem-label">
            Pull requests
      
    • <a tabindex="-1" id="item-918ed193-76f5-4b85-9c30-d6eb22ceed6f" href="/rxi/microui/actions" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
          <span class="ActionListItem-visual ActionListItem-visual--leading">
            <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play">
      <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path>
      
          <span data-view-component="true" class="ActionListItem-label">
            Actions
      
    • <a tabindex="-1" id="item-475635d4-4782-4178-b354-c0dbf471ca3e" href="/rxi/microui/projects" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
          <span class="ActionListItem-visual ActionListItem-visual--leading">
            <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-table">
      <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path>
      
          <span data-view-component="true" class="ActionListItem-label">
            Projects
      
    • <a tabindex="-1" id="item-2e905dc7-e2b9-4955-9c76-209c92183a9d" href="/rxi/microui/security" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
          <span class="ActionListItem-visual ActionListItem-visual--leading">
            <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield">
      <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
      
          <span data-view-component="true" class="ActionListItem-label">
            Security and quality
      
    • <a tabindex="-1" id="item-09b4ee35-fa32-49b7-824e-9ec8d5f08778" href="/rxi/microui/pulse" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
          <span class="ActionListItem-visual ActionListItem-visual--leading">
            <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph">
      <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path>
      
          <span data-view-component="true" class="ActionListItem-label">
            Insights
      

    <react-app app-name="code-view" initial-path="/rxi/microui/blob/master/doc/usage.md" style="display: block; min-height: calc(100vh - 64px);" data-attempted-ssr="true" data-ssr="true" data-lazy="false" data-alternate="false" data-data-router-enabled="true" data-react-profiling="false"

    <script type="application/json" data-target="react-app.embeddedData">{"payload":{"codeViewBlobRoute":{"csv":null,"csvError":null,"headerInfo":{"toc":[{"level":1,"text":"Usage","anchor":"usage","htmlText":"Usage"},{"level":2,"text":"Overview","anchor":"overview","htmlText":"Overview"},{"level":2,"text":"Getting Started","anchor":"getting-started","htmlText":"Getting Started"},{"level":2,"text":"Layout System","anchor":"layout-system","htmlText":"Layout System"},{"level":2,"text":"Style Customisation","anchor":"style-customisation","htmlText":"Style Customisation"},{"level":2,"text":"Custom Controls","anchor":"custom-controls","htmlText":"Custom Controls"}]},"issueTemplate":null,"discussionTemplate":null,"richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eUsage\u003c/h1\u003e\u003ca id=\"user-content-usage\" class=\"anchor\" aria-label=\"Permalink: Usage\" href=\"#usage\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ca href=\"#overview\"\u003eOverview\u003c/a\u003e\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ca href=\"#getting-started\"\u003eGetting Started\u003c/a\u003e\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ca href=\"#layout-system\"\u003eLayout System\u003c/a\u003e\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ca href=\"#style-customisation\"\u003eStyle Customisation\u003c/a\u003e\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ca href=\"#custom-controls\"\u003eCustom Controls\u003c/a\u003e\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOverview\u003c/h2\u003e\u003ca id=\"user-content-overview\" class=\"anchor\" aria-label=\"Permalink: Overview\" href=\"#overview\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe overall structure when using the library is as follows:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"initialise `mu_Context`\n\nmain loop:\n call `mu_input_...` functions\n call `mu_begin()`\n process ui\n call `mu_end()`\n iterate commands using `mu_command_next()`\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003einitialise `mu_Context`\n\nmain loop:\n call `mu_input_...` functions\n call `mu_begin()`\n process ui\n call `mu_end()`\n iterate commands using `mu_command_next()`\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eGetting Started\u003c/h2\u003e\u003ca id=\"user-content-getting-started\" class=\"anchor\" aria-label=\"Permalink: Getting Started\" href=\"#getting-started\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eBefore use a \u003ccode\u003emu_Context\u003c/code\u003e should be initialised:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"mu_Context *ctx = malloc(sizeof(mu_Context));\nmu_init(ctx);\"\u003e\u003cpre\u003e\u003cspan class=\"pl-smi\"\u003emu_Context\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003emalloc\u003c/span\u003e(\u003cspan class=\"pl-k\"\u003esizeof\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003emu_Context\u003c/span\u003e));\n\u003cspan class=\"pl-en\"\u003emu_init\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e);\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFollowing which the context's \u003ccode\u003etext_width\u003c/code\u003e and \u003ccode\u003etext_height\u003c/code\u003e callback functions\nshould be set:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"ctx-\u0026gt;text_width = text_width;\nctx-\u0026gt;text_height = text_height;\"\u003e\u003cpre\u003e\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etext_width\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003etext_width\u003c/span\u003e;\n\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etext_height\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003etext_height\u003c/span\u003e;\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn your main loop you should first pass user input to microui using the\n\u003ccode\u003emu_input_...\u003c/code\u003e functions. It is safe to call the input functions multiple times\nif the same input event occurs in a single frame.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAfter handling the input the \u003ccode\u003emu_begin()\u003c/code\u003e function must be called before\nprocessing your UI:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"mu_begin(ctx);\"\u003e\u003cpre\u003e\u003cspan class=\"pl-en\"\u003emu_begin\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e);\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eBefore any controls can be used we must begin a window using one of the\n\u003ccode\u003emu_begin_window...\u003c/code\u003e or \u003ccode\u003emu_begin_popup...\u003c/code\u003e functions. The \u003ccode\u003emu_begin_...\u003c/code\u003e window\nfunctions return a truthy value if the window is open, if this is not the case\nwe should not process the window any further. When we are finished processing\nthe window's ui the \u003ccode\u003emu_end_...\u003c/code\u003e window function should be called.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"if (mu_begin_window(ctx, \u0026quot;My Window\u0026quot;, mu_rect(10, 10, 300, 400))) {\n /* process ui here... */\n mu_end_window(ctx);\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-en\"\u003emu_begin_window\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\"My Window\"\u003c/span\u003e, \u003cspan class=\"pl-en\"\u003emu_rect\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e300\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e400\u003c/span\u003e))) {\n \u003cspan class=\"pl-c\"\u003e/* process ui here... */\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003emu_end_window\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e);\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIt is safe to nest \u003ccode\u003emu_begin_window()\u003c/code\u003e calls, this can be useful for things like\ncontext menus; the windows will still render separate from one another like\nnormal.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eWhile inside a window block we can safely process controls. Controls that allow\nuser interaction return a bitset of \u003ccode\u003eMU_RES_...\u003c/code\u003e values. Some controls — such\nas buttons — can only potentially return a single \u003ccode\u003eMU_RES_...\u003c/code\u003e, thus their\nreturn value can be treated as a boolean:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"if (mu_button(ctx, \u0026quot;My Button\u0026quot;)) {\n printf(\u0026quot;'My Button' was pressed\\n\u0026quot;);\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-en\"\u003emu_button\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\"My Button\"\u003c/span\u003e)) {\n \u003cspan class=\"pl-en\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"'My Button' was pressed\\n\"\u003c/span\u003e);\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe library generates unique IDs for controls internally to keep track of which\nare focused, hovered, etc. These are typically generated from the name/label\npassed to the function, or, in the case of sliders and checkboxes the value\npointer. An issue arises then if you have several buttons in a window or panel\nthat use the same label. The \u003ccode\u003emu_push_id()\u003c/code\u003e and \u003ccode\u003emu_pop_id()\u003c/code\u003e functions are\nprovided for such situations, allowing you to push additional data that will be\nmixed into the unique ID:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"for (int i = 0; i \u0026lt; 10; i++) {\n mu_push_id(ctx, \u0026amp;i, sizeof(i));\n if (mu_button(ctx, \u0026quot;x\u0026quot;)) {\n printf(\u0026quot;Pressed button %d\\n\u0026quot;, i);\n }\n mu_pop_id(ctx);\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003efor\u003c/span\u003e (\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e; \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e; \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e++\u003c/span\u003e) {\n \u003cspan class=\"pl-en\"\u003emu_push_id\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e, \u003cspan class=\"pl-k\"\u003esizeof\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e));\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-en\"\u003emu_button\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\"x\"\u003c/span\u003e)) {\n \u003cspan class=\"pl-en\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"Pressed button %d\\n\"\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e);\n }\n \u003cspan class=\"pl-en\"\u003emu_pop_id\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e);\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWhen we're finished processing the UI for this frame the \u003ccode\u003emu_end()\u003c/code\u003e function\nshould be called:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"mu_end(ctx);\"\u003e\u003cpre\u003e\u003cspan class=\"pl-en\"\u003emu_end\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e);\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWhen we're ready to draw the UI the \u003ccode\u003emu_next_command()\u003c/code\u003e can be used to iterate\nthe resultant commands. The function expects a \u003ccode\u003emu_Command\u003c/code\u003e pointer initialised\nto \u003ccode\u003eNULL\u003c/code\u003e. It is safe to iterate through the commands list any number of times:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"mu_Command *cmd = NULL;\nwhile (mu_next_command(ctx, \u0026amp;cmd)) {\n if (cmd-\u0026gt;type == MU_COMMAND_TEXT) {\n render_text(cmd-\u0026gt;text.font, cmd-\u0026gt;text.text, cmd-\u0026gt;text.pos.x, cmd-\u0026gt;text.pos.y, cmd-\u0026gt;text.color);\n }\n if (cmd-\u0026gt;type == MU_COMMAND_RECT) {\n render_rect(cmd-\u0026gt;rect.rect, cmd-\u0026gt;rect.color);\n }\n if (cmd-\u0026gt;type == MU_COMMAND_ICON) {\n render_icon(cmd-\u0026gt;icon.id, cmd-\u0026gt;icon.rect, cmd-\u0026gt;icon.color);\n }\n if (cmd-\u0026gt;type == MU_COMMAND_CLIP) {\n set_clip_rect(cmd-\u0026gt;clip.rect);\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-smi\"\u003emu_Command\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eNULL\u003c/span\u003e;\n\u003cspan class=\"pl-k\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"pl-en\"\u003emu_next_command\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e)) {\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etype\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eMU_COMMAND_TEXT\u003c/span\u003e) {\n \u003cspan class=\"pl-en\"\u003erender_text\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etext\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003efont\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etext\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003etext\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etext\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003epos\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003ex\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etext\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003epos\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003ey\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etext\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003ecolor\u003c/span\u003e);\n }\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etype\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eMU_COMMAND_RECT\u003c/span\u003e) {\n \u003cspan class=\"pl-en\"\u003erender_rect\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003erect\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003erect\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003erect\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003ecolor\u003c/span\u003e);\n }\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etype\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eMU_COMMAND_ICON\u003c/span\u003e) {\n \u003cspan class=\"pl-en\"\u003erender_icon\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003eicon\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eid\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003eicon\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003erect\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003eicon\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003ecolor\u003c/span\u003e);\n }\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003etype\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eMU_COMMAND_CLIP\u003c/span\u003e) {\n \u003cspan class=\"pl-en\"\u003eset_clip_rect\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ecmd\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003eclip\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003erect\u003c/span\u003e);\n }\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSee the \u003ca href=\"/rxi/microui/blob/master/demo\"\u003e\u003ccode\u003edemo\u003c/code\u003e\u003c/a\u003e directory for a usage example.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLayout System\u003c/h2\u003e\u003ca id=\"user-content-layout-system\" class=\"anchor\" aria-label=\"Permalink: Layout System\" href=\"#layout-system\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe layout system is primarily based around \u003cem\u003erows\u003c/em\u003e — Each row\ncan contain a number of \u003cem\u003eitems\u003c/em\u003e or \u003cem\u003ecolumns\u003c/em\u003e each column can itself\ncontain a number of rows and so forth. A row is initialised using the\n\u003ccode\u003emu_layout_row()\u003c/code\u003e function, the user should specify the number of items\non the row, an array containing the width of each item, and the height\nof the row:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"/* initialise a row of 3 items: the first item with a width\n** of 90 and the remaining two with the width of 100 */\nmu_layout_row(ctx, 3, (int[]) { 90, 100, 100 }, 0);\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e/* initialise a row of 3 items: the first item with a width\u003c/span\u003e\n\u003cspan class=\"pl-c\"\u003e** of 90 and the remaining two with the width of 100 */\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003emu_layout_row\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e, (\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e[]) { \u003cspan class=\"pl-c1\"\u003e90\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e100\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e100\u003c/span\u003e }, \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e);\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWhen a row is filled the next row is started, for example, in the above\ncode 6 buttons immediately after would result in two rows. The function\ncan be called again to begin a new row.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAs well as absolute values, width and height can be specified as \u003ccode\u003e0\u003c/code\u003e\nwhich will result in the Context's \u003ccode\u003estyle.size\u003c/code\u003e value being used, or a\nnegative value which will size the item relative to the right/bottom edge,\nthus if we wanted a row with a small button at the left, a textbox filling\nmost the row and a larger button at the right, we could do the following:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"mu_layout_row(ctx, 3, (int[]) { 30, -90, -1 }, 0);\nmu_button(ctx, \u0026quot;X\u0026quot;);\nmu_textbox(ctx, buf, sizeof(buf));\nmu_button(ctx, \u0026quot;Submit\u0026quot;);\"\u003e\u003cpre\u003e\u003cspan class=\"pl-en\"\u003emu_layout_row\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e, (\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e[]) { \u003cspan class=\"pl-c1\"\u003e30\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e-90\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e-1\u003c/span\u003e }, \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e);\n\u003cspan class=\"pl-en\"\u003emu_button\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\"X\"\u003c/span\u003e);\n\u003cspan class=\"pl-en\"\u003emu_textbox\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ebuf\u003c/span\u003e, \u003cspan class=\"pl-k\"\u003esizeof\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ebuf\u003c/span\u003e));\n\u003cspan class=\"pl-en\"\u003emu_button\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\"Submit\"\u003c/span\u003e);\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf the \u003ccode\u003eitems\u003c/code\u003e parameter is \u003ccode\u003e0\u003c/code\u003e, the \u003ccode\u003ewidths\u003c/code\u003e parameter is ignored\nand controls will continue to be added to the row at the width last\nspecified by \u003ccode\u003emu_layout_width()\u003c/code\u003e or \u003ccode\u003estyle.size.x\u003c/code\u003e if this function has\nnot been called:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"mu_layout_row(ctx, 0, NULL, 0);\nmu_layout_width(ctx, -90);\nmu_textbox(ctx, buf, sizeof(buf));\nmu_layout_width(ctx, -1);\nmu_button(ctx, \u0026quot;Submit\u0026quot;);\"\u003e\u003cpre\u003e\u003cspan class=\"pl-en\"\u003emu_layout_row\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003eNULL\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e);\n\u003cspan class=\"pl-en\"\u003emu_layout_width\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e-90\u003c/span\u003e);\n\u003cspan class=\"pl-en\"\u003emu_textbox\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ebuf\u003c/span\u003e, \u003cspan class=\"pl-k\"\u003esizeof\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ebuf\u003c/span\u003e));\n\u003cspan class=\"pl-en\"\u003emu_layout_width\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e-1\u003c/span\u003e);\n\u003cspan class=\"pl-en\"\u003emu_button\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\"Submit\"\u003c/span\u003e);\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA column can be started at any point on a row using the\n\u003ccode\u003emu_layout_begin_column()\u003c/code\u003e function. Once begun, rows will act inside\nthe body of the column — all negative size values will be relative to\nthe column's body as opposed to the body of the container. All new rows\nwill be contained within this column until the \u003ccode\u003emu_layout_end_column()\u003c/code\u003e\nfunction is called.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eInternally controls use the \u003ccode\u003emu_layout_next()\u003c/code\u003e function to retrieve the\nnext screen-positioned-Rect and advance the layout system, you should use\nthis function when making custom controls or if you want to advance the\nlayout system without placing a control.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003emu_layout_set_next()\u003c/code\u003e function is provided to set the next layout\nRect explicitly. This will be returned by \u003ccode\u003emu_layout_next()\u003c/code\u003e when it is\nnext called. By using the \u003ccode\u003erelative\u003c/code\u003e boolean you can choose to provide\na screen-space Rect or a Rect which will have the container's position\nand scroll offset applied to it. You can peek the next Rect from the\nlayout system by using the \u003ccode\u003emu_layout_next()\u003c/code\u003e function to retrieve it,\nfollowed by \u003ccode\u003emu_layout_set_next()\u003c/code\u003e to return it:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"mu_Rect rect = mu_layout_next(ctx);\nmu_layout_set_next(ctx, rect, 0);\"\u003e\u003cpre\u003e\u003cspan class=\"pl-smi\"\u003emu_Rect\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003erect\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003emu_layout_next\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e);\n\u003cspan class=\"pl-en\"\u003emu_layout_set_next\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003erect\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e);\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf you want to position controls arbitrarily inside a container the\n\u003ccode\u003erelative\u003c/code\u003e argument of \u003ccode\u003emu_layout_set_next()\u003c/code\u003e should be true:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"/* place a (40, 40) sized button at (300, 300) inside the container: */\nmu_layout_set_next(ctx, mu_rect(300, 300, 40, 40), 1);\nmu_button(ctx, \u0026quot;X\u0026quot;);\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e/* place a (40, 40) sized button at (300, 300) inside the container: */\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003emu_layout_set_next\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-en\"\u003emu_rect\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e300\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e300\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e40\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e40\u003c/span\u003e), \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e);\n\u003cspan class=\"pl-en\"\u003emu_button\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\"X\"\u003c/span\u003e);\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA Rect set with \u003ccode\u003erelative\u003c/code\u003e true will also effect the \u003ccode\u003econtent_size\u003c/code\u003e\nof the container, causing it to effect the scrollbars if it exceeds the\nwidth or height of the container's body.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eStyle Customisation\u003c/h2\u003e\u003ca id=\"user-content-style-customisation\" class=\"anchor\" aria-label=\"Permalink: Style Customisation\" href=\"#style-customisation\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe library provides styling support via the \u003ccode\u003emu_Style\u003c/code\u003e struct and, if you\nwant greater control over the look, the \u003ccode\u003edraw_frame()\u003c/code\u003e callback function.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003emu_Style\u003c/code\u003e struct contains spacing and sizing information, as well\nas a \u003ccode\u003ecolors\u003c/code\u003e array which maps \u003ccode\u003ecolorid\u003c/code\u003e to \u003ccode\u003emu_Color\u003c/code\u003e. The library uses\nthe \u003ccode\u003estyle\u003c/code\u003e pointer field of the context to resolve colors and spacing,\nit is safe to change this pointer or modify any fields of the resultant\nstruct at any point. See \u003ca href=\"/rxi/microui/blob/master/src/microui.h\"\u003e\u003ccode\u003emicroui.h\u003c/code\u003e\u003c/a\u003e for the struct's\nimplementation.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIn addition to the style struct the context stores a \u003ccode\u003edraw_frame()\u003c/code\u003e\ncallback function which is used whenever the \u003cem\u003eframe\u003c/em\u003e of a control needs\nto be drawn, by default this function draws a rectangle using the color\nof the \u003ccode\u003ecolorid\u003c/code\u003e argument, with a one-pixel border around it using the\n\u003ccode\u003eMU_COLOR_BORDER\u003c/code\u003e color.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCustom Controls\u003c/h2\u003e\u003ca id=\"user-content-custom-controls\" class=\"anchor\" aria-label=\"Permalink: Custom Controls\" href=\"#custom-controls\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe library exposes the functions used by built-in controls to allow the\nuser to make custom controls. A control should take a \u003ccode\u003emu_Context*\u003c/code\u003e value\nas its first argument and return a \u003ccode\u003eMU_RES_...\u003c/code\u003e value. Your control's\nimplementation should use \u003ccode\u003emu_layout_next()\u003c/code\u003e to get its destination\nRect and advance the layout system. \u003ccode\u003emu_get_id()\u003c/code\u003e should be used with\nsome data unique to the control to generate an ID for that control and\n\u003ccode\u003emu_update_control()\u003c/code\u003e should be used to update the context's \u003ccode\u003ehover\u003c/code\u003e\nand \u003ccode\u003efocus\u003c/code\u003e values based on the mouse input state.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003eMU_OPT_HOLDFOCUS\u003c/code\u003e opt value can be passed to \u003ccode\u003emu_update_control()\u003c/code\u003e\nif we want the control to retain focus when the mouse button is released\n— this behaviour is used by textboxes which we want to stay focused\nto allow for text input.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eA control that acts as a button which displays an integer and, when\nclicked increments that integer, could be implemented as such:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"int incrementer(mu_Context *ctx, int *value) {\n mu_Id id = mu_get_id(ctx, \u0026amp;value, sizeof(value));\n mu_Rect rect = mu_layout_next(ctx);\n mu_update_control(ctx, id, rect, 0);\n\n /* handle input */\n int res = 0;\n if (ctx-\u0026gt;mouse_pressed == MU_MOUSE_LEFT \u0026amp;\u0026amp; ctx-\u0026gt;focus == id) {\n (*value)++;\n res |= MU_RES_CHANGE;\n }\n\n /* draw */\n char buf[32];\n sprintf(buf, \u0026quot;%d\u0026quot;, *value);\n mu_draw_control_frame(ctx, id, rect, MU_COLOR_BUTTON, 0);\n mu_draw_control_text(ctx, buf, rect, MU_COLOR_TEXT, MU_OPT_ALIGNCENTER);\n\n return res;\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eincrementer\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003emu_Context\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003evalue\u003c/span\u003e) {\n \u003cspan class=\"pl-smi\"\u003emu_Id\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eid\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003emu_get_id\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003evalue\u003c/span\u003e, \u003cspan class=\"pl-k\"\u003esizeof\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003evalue\u003c/span\u003e));\n \u003cspan class=\"pl-smi\"\u003emu_Rect\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003erect\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003emu_layout_next\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e);\n \u003cspan class=\"pl-en\"\u003emu_update_control\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003eid\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003erect\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e);\n\n \u003cspan class=\"pl-c\"\u003e/* handle input */\u003c/span\u003e\n \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eres\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e;\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003emouse_pressed\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eMU_MOUSE_LEFT\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003efocus\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eid\u003c/span\u003e) {\n (\u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003evalue\u003c/span\u003e)\u003cspan class=\"pl-c1\"\u003e++\u003c/span\u003e;\n \u003cspan class=\"pl-s1\"\u003eres\u003c/span\u003e |= \u003cspan class=\"pl-c1\"\u003eMU_RES_CHANGE\u003c/span\u003e;\n }\n\n \u003cspan class=\"pl-c\"\u003e/* draw */\u003c/span\u003e\n \u003cspan class=\"pl-smi\"\u003echar\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ebuf\u003c/span\u003e[\u003cspan class=\"pl-c1\"\u003e32\u003c/span\u003e];\n \u003cspan class=\"pl-en\"\u003esprintf\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ebuf\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\"%d\"\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e*\u003c/span\u003e\u003cspan class=\"pl-s1\"\u003evalue\u003c/span\u003e);\n \u003cspan class=\"pl-en\"\u003emu_draw_control_frame\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003eid\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003erect\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003eMU_COLOR_BUTTON\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e);\n \u003cspan class=\"pl-en\"\u003emu_draw_control_text\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ectx\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003ebuf\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003erect\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003eMU_COLOR_TEXT\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003eMU_OPT_ALIGNCENTER\u003c/span\u003e);\n\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eres\u003c/span\u003e;\n}\u003c/pre\u003e\u003c/div\u003e\n\u003c/article\u003e","richTextTruncated":false,"renderedFileInfo":null,"symbols":{"timed_out":false,"not_analyzed":false,"symbols":[{"name":"Usage","kind":"section_1","ident_start":2,"ident_end":7,"extent_start":0,"extent_end":9303,"fully_qualified_name":"Usage","ident_utf16":{"start":{"line_number":0,"utf16_col":2},"end":{"line_number":0,"utf16_col":7}},"extent_utf16":{"start":{"line_number":0,"utf16_col":0},"end":{"line_number":251,"utf16_col":0}}},{"name":"Overview","kind":"section_2","ident_start":212,"ident_end":220,"extent_start":209,"extent_end":454,"fully_qualified_name":"Overview","ident_utf16":{"start":{"line_number":7,"utf16_col":3},"end":{"line_number":7,"utf16_col":11}},"extent_utf16":{"start":{"line_number":7,"utf16_col":0},"end":{"line_number":20,"utf16_col":0}}},{"name":"Getting Started","kind":"section_2","ident_start":457,"ident_end":472,"extent_start":454,"extent_end":3684,"fully_qualified_name":"Getting Started","ident_utf16":{"start":{"line_number":20,"utf16_col":3},"end":{"line_number":20,"utf16_col":18}},"extent_utf16":{"start":{"line_number":20,"utf16_col":0},"end":{"line_number":118,"utf16_col":0}}},{"name":"Layout System","kind":"section_2","ident_start":3687,"ident_end":3700,"extent_start":3684,"extent_end":6954,"fully_qualified_name":"Layout System","ident_utf16":{"start":{"line_number":118,"utf16_col":3},"end":{"line_number":118,"utf16_col":16}},"extent_utf16":{"start":{"line_number":118,"utf16_col":0},"end":{"line_number":194,"utf16_col":0}}},{"name":"Style Customisation","kind":"section_2","ident_start":6957,"ident_end":6976,"extent_start":6954,"extent_end":7816,"fully_qualified_name":"Style Customisation","ident_utf16":{"start":{"line_number":194,"utf16_col":3},"end":{"line_number":194,"utf16_col":22}},"extent_utf16":{"start":{"line_number":194,"utf16_col":0},"end":{"line_number":212,"utf16_col":0}}},{"name":"Custom Controls","kind":"section_2","ident_start":7819,"ident_end":7834,"extent_start":7816,"extent_end":9303,"fully_qualified_name":"Custom Controls","ident_utf16":{"start":{"line_number":212,"utf16_col":3},"end":{"line_number":212,"utf16_col":18}},"extent_utf16":{"start":{"line_number":212,"utf16_col":0},"end":{"line_number":251,"utf16_col":0}}}]}},"codeViewLayoutRoute":{"repo":{"id":149854705,"defaultBranch":"master","name":"microui","ownerLogin":"rxi","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2018-09-22T07:17:38.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/3920290?v=4","public":true,"private":false,"isOrgOwned":false},"currentUser":null,"uploadToken":"zLfBPUoL9pXW4Eksnezq3AbQhdCN711ttBfuDh0e9gRn7VSCEOj1gKJKK0wgWagaxMIak83kb6VKZbF8Gof7hA","allShortcutsEnabled":false,"treeExpanded":true,"path":"doc/usage.md","symbolsExpanded":false,"refInfo":{"name":"master","listCacheKey":"v0:1582575758.0","canEdit":false,"currentOid":"0850aba860959c3e75fb3e97120ca92957f9d057"},"helpUrl":"https://docs.github.com","findFileWorkerPath":"/assets-cdn/worker/find-file-worker-378c581dbdb2429c.js","findInFileWorkerPath":"/assets-cdn/worker/find-in-file-worker-82470c2dd86b326d.js","githubDevUrl":null},"codeViewFileTreeLayoutRoute":{"fileTree":{"doc":{"items":[{"name":"usage.md","path":"doc/usage.md","contentType":"file"}],"totalCount":1},"":{"items":[{"name":".github","path":".github","contentType":"directory"},{"name":"demo","path":"demo","contentType":"directory"},{"name":"doc","path":"doc","contentType":"directory"},{"name":"src","path":"src","contentType":"directory"},{"name":"LICENSE","path":"LICENSE","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"}],"totalCount":6}},"fileTreeProcessingTime":32.685862,"foldersToFetch":[]},"codeViewBlobLayoutRoute":{"codeLineWrapEnabled":false,"refInfo":{"name":"master","listCacheKey":"v0:1582575758.0","canEdit":false,"refType":"branch","currentOid":"0850aba860959c3e75fb3e97120ca92957f9d057","canEditOnDefaultBranch":false,"fileExistsOnDefault":true},"path":"doc/usage.md","blob":{"copilotSWEAgentEnabled":false,"dependabotInfo":{"showConfigurationBanner":false,"configFilePath":null,"networkDependabotPath":"/rxi/microui/network/updates","dismissConfigurationNoticePath":"/settings/dismiss-notice/dependabot_configuration_notice","configurationNoticeDismissed":null},"displayName":"usage.md","displayUrl":"https://github.com/rxi/microui/blob/master/doc/usage.md?raw=true","headerInfo":{"blobSize":"9.08 KB","deleteTooltip":"You must be signed in to make or propose changes","editTooltip":"You must be signed in to make or propose changes","ghDesktopPath":"https://desktop.github.com","isGitLfs":false,"onBranch":true,"shortPath":"b757bec","siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Frxi%2Fmicroui%2Fblob%2Fmaster%2Fdoc%2Fusage.md","isCSV":false,"isRichtext":true,"lineInfo":{"truncatedLoc":"251","truncatedSloc":"218"},"mode":"file"},"image":false,"isCodeownersFile":null,"isPlain":false,"isValidLegacyIssueTemplate":false,"isIssueTemplate":false,"isDiscussionTemplate":false,"language":"Markdown","languageID":222,"large":false,"planSupportInfo":{"repoIsFork":null,"repoOwnedByCurrentUser":null,"requestFullPath":"/rxi/microui/blob/master/doc/usage.md","showFreeOrgGatedFeatureMessage":null,"showPlanSupportBanner":null,"upgradeDataAttributes":null,"upgradePath":null},"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_dockerfile","releasePath":"/rxi/microui/releases/new?marketplace=true","showPublishActionBanner":false},"rawBlobUrl":"https://github.com/rxi/microui/raw/refs/heads/master/doc/usage.md","renderImageOrRaw":false,"shortPath":null,"symbolsEnabled":true,"tabSize":4,"topBannersInfo":{"overridingGlobalFundingFile":false,"globalPreferredFundingPath":null,"showInvalidCitationWarning":false,"citationHelpUrl":"https://docs.github.com/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-citation-files","actionsOnboardingTip":null},"truncated":false,"viewable":true,"workflowRedirectUrl":null},"copilotInfo":null,"copilotAccessAllowed":false,"copilotSpacesEnabled":false,"modelsAccessAllowed":false,"modelsRepoIntegrationEnabled":false,"isMarketplaceEnabled":true},"codeViewBlobLayoutRoute.StyledBlob":{"rawLines":["# Usage","* **[Overview](#overview)**","* **[Getting Started](#getting-started)**","* **[Layout System](#layout-system)**","* **[Style Customisation](#style-customisation)**","* **[Custom Controls](#custom-controls)**","","## Overview","The overall structure when using the library is as follows:","```","initialise `mu_Context`","","main loop:"," call `mu_input_...` functions"," call `mu_begin()`"," process ui"," call `mu_end()`"," iterate commands using `mu_command_next()`","```","","## Getting Started","Before use a `mu_Context` should be initialised:","```c","mu_Context *ctx = malloc(sizeof(mu_Context));","mu_init(ctx);","```","","Following which the context's `text_width` and `text_height` callback functions","should be set:","```c","ctx-\u003etext_width = text_width;","ctx-\u003etext_height = text_height;","```","","In your main loop you should first pass user input to microui using the","`mu_input_...` functions. It is safe to call the input functions multiple times","if the same input event occurs in a single frame.","","After handling the input the `mu_begin()` function must be called before","processing your UI:","```c","mu_begin(ctx);","```","","Before any controls can be used we must begin a window using one of the","`mu_begin_window...` or `mu_begin_popup...` functions. The `mu_begin_...` window","functions return a truthy value if the window is open, if this is not the case","we should not process the window any further. When we are finished processing","the window's ui the `mu_end_...` window function should be called.","","```c","if (mu_begin_window(ctx, \"My Window\", mu_rect(10, 10, 300, 400))) {"," /* process ui here... */"," mu_end_window(ctx);","}","```","","It is safe to nest `mu_begin_window()` calls, this can be useful for things like","context menus; the windows will still render separate from one another like","normal.","","While inside a window block we can safely process controls. Controls that allow","user interaction return a bitset of `MU_RES_...` values. Some controls — such","as buttons — can only potentially return a single `MU_RES_...`, thus their","return value can be treated as a boolean:","```c","if (mu_button(ctx, \"My Button\")) {"," printf(\"'My Button' was pressed\\n\");","}","```","","The library generates unique IDs for controls internally to keep track of which","are focused, hovered, etc. These are typically generated from the name/label","passed to the function, or, in the case of sliders and checkboxes the value","pointer. An issue arises then if you have several buttons in a window or panel","that use the same label. The `mu_push_id()` and `mu_pop_id()` functions are","provided for such situations, allowing you to push additional data that will be","mixed into the unique ID:","```c","for (int i = 0; i \u003c 10; i++) {"," mu_push_id(ctx, \u0026i, sizeof(i));"," if (mu_button(ctx, \"x\")) {"," printf(\"Pressed button %d\\n\", i);"," }"," mu_pop_id(ctx);","}","```","","When we're finished processing the UI for this frame the `mu_end()` function","should be called:","```c","mu_end(ctx);","```","","When we're ready to draw the UI the `mu_next_command()` can be used to iterate","the resultant commands. The function expects a `mu_Command` pointer initialised","to `NULL`. It is safe to iterate through the commands list any number of times:","```c","mu_Command *cmd = NULL;","while (mu_next_command(ctx, \u0026cmd)) {"," if (cmd-\u003etype == MU_COMMAND_TEXT) {"," render_text(cmd-\u003etext.font, cmd-\u003etext.text, cmd-\u003etext.pos.x, cmd-\u003etext.pos.y, cmd-\u003etext.color);"," }"," if (cmd-\u003etype == MU_COMMAND_RECT) {"," render_rect(cmd-\u003erect.rect, cmd-\u003erect.color);"," }"," if (cmd-\u003etype == MU_COMMAND_ICON) {"," render_icon(cmd-\u003eicon.id, cmd-\u003eicon.rect, cmd-\u003eicon.color);"," }"," if (cmd-\u003etype == MU_COMMAND_CLIP) {"," set_clip_rect(cmd-\u003eclip.rect);"," }","}","```","","See the [`demo`](../demo) directory for a usage example.","","","## Layout System","The layout system is primarily based around *rows* — Each row","can contain a number of *items* or *columns* each column can itself","contain a number of rows and so forth. A row is initialised using the","`mu_layout_row()` function, the user should specify the number of items","on the row, an array containing the width of each item, and the height","of the row:","```c","/* initialise a row of 3 items: the first item with a width","** of 90 and the remaining two with the width of 100 */","mu_layout_row(ctx, 3, (int[]) { 90, 100, 100 }, 0);","```","When a row is filled the next row is started, for example, in the above","code 6 buttons immediately after would result in two rows. The function","can be called again to begin a new row.","","As well as absolute values, width and height can be specified as `0`","which will result in the Context's `style.size` value being used, or a","negative value which will size the item relative to the right/bottom edge,","thus if we wanted a row with a small button at the left, a textbox filling","most the row and a larger button at the right, we could do the following:","```c","mu_layout_row(ctx, 3, (int[]) { 30, -90, -1 }, 0);","mu_button(ctx, \"X\");","mu_textbox(ctx, buf, sizeof(buf));","mu_button(ctx, \"Submit\");","```","","If the `items` parameter is `0`, the `widths` parameter is ignored","and controls will continue to be added to the row at the width last","specified by `mu_layout_width()` or `style.size.x` if this function has","not been called:","```c","mu_layout_row(ctx, 0, NULL, 0);","mu_layout_width(ctx, -90);","mu_textbox(ctx, buf, sizeof(buf));","mu_layout_width(ctx, -1);","mu_button(ctx, \"Submit\");","```","","A column can be started at any point on a row using the","`mu_layout_begin_column()` function. Once begun, rows will act inside","the body of the column — all negative size values will be relative to","the column's body as opposed to the body of the container. All new rows","will be contained within this column until the `mu_layout_end_column()`","function is called.","","Internally controls use the `mu_layout_next()` function to retrieve the","next screen-positioned-Rect and advance the layout system, you should use","this function when making custom controls or if you want to advance the","layout system without placing a control.","","The `mu_layout_set_next()` function is provided to set the next layout","Rect explicitly. This will be returned by `mu_layout_next()` when it is","next called. By using the `relative` boolean you can choose to provide","a screen-space Rect or a Rect which will have the container's position","and scroll offset applied to it. You can peek the next Rect from the","layout system by using the `mu_layout_next()` function to retrieve it,","followed by `mu_layout_set_next()` to return it:","```c","mu_Rect rect = mu_layout_next(ctx);","mu_layout_set_next(ctx, rect, 0);","```","","If you want to position controls arbitrarily inside a container the","`relative` argument of `mu_layout_set_next()` should be true:","```c","/* place a (40, 40) sized button at (300, 300) inside the container: */","mu_layout_set_next(ctx, mu_rect(300, 300, 40, 40), 1);","mu_button(ctx, \"X\");","```","A Rect set with `relative` true will also effect the `content_size`","of the container, causing it to effect the scrollbars if it exceeds the","width or height of the container's body.","","","## Style Customisation","The library provides styling support via the `mu_Style` struct and, if you","want greater control over the look, the `draw_frame()` callback function.","","The `mu_Style` struct contains spacing and sizing information, as well","as a `colors` array which maps `colorid` to `mu_Color`. The library uses","the `style` pointer field of the context to resolve colors and spacing,","it is safe to change this pointer or modify any fields of the resultant","struct at any point. See [`microui.h`](../src/microui.h) for the struct's","implementation.","","In addition to the style struct the context stores a `draw_frame()`","callback function which is used whenever the *frame* of a control needs","to be drawn, by default this function draws a rectangle using the color","of the `colorid` argument, with a one-pixel border around it using the","`MU_COLOR_BORDER` color.","","","## Custom Controls","The library exposes the functions used by built-in controls to allow the","user to make custom controls. A control should take a `mu_Context*` value","as its first argument and return a `MU_RES_...` value. Your control's","implementation should use `mu_layout_next()` to get its destination","Rect and advance the layout system. `mu_get_id()` should be used with","some data unique to the control to generate an ID for that control and","`mu_update_control()` should be used to update the context's `hover`","and `focus` values based on the mouse input state.","","The `MU_OPT_HOLDFOCUS` opt value can be passed to `mu_update_control()`","if we want the control to retain focus when the mouse button is released","— this behaviour is used by textboxes which we want to stay focused","to allow for text input.","","A control that acts as a button which displays an integer and, when","clicked increments that integer, could be implemented as such:","```c","int incrementer(mu_Context *ctx, int *value) {"," mu_Id id = mu_get_id(ctx, \u0026value, sizeof(value));"," mu_Rect rect = mu_layout_next(ctx);"," mu_update_control(ctx, id, rect, 0);",""," /* handle input */"," int res = 0;"," if (ctx-\u003emouse_pressed == MU_MOUSE_LEFT \u0026\u0026 ctx-\u003efocus == id) {"," (*value)++;"," res |= MU_RES_CHANGE;"," }",""," /* draw */"," char buf[32];"," sprintf(buf, \"%d\", *value);"," mu_draw_control_frame(ctx, id, rect, MU_COLOR_BUTTON, 0);"," mu_draw_control_text(ctx, buf, rect, MU_COLOR_TEXT, MU_OPT_ALIGNCENTER);",""," return res;","}","```"],"stylingDirectives":[0,7,"pl-mh"],[2,7,"pl-en",0,1,"pl-v"],[2,4,"pl-s"],[4,5,"pl-s"],[13,14,"pl-s"],[14,15,"pl-s"],[15,24,"pl-corl"],[24,25,"pl-s"],[25,27,"pl-s",0,1,"pl-v"],[2,4,"pl-s"],[4,5,"pl-s"],[20,21,"pl-s"],[21,22,"pl-s"],[22,38,"pl-corl"],[38,39,"pl-s"],[39,41,"pl-s",0,1,"pl-v"],[2,4,"pl-s"],[4,5,"pl-s"],[18,19,"pl-s"],[19,20,"pl-s"],[20,34,"pl-corl"],[34,35,"pl-s"],[35,37,"pl-s",0,1,"pl-v"],[2,4,"pl-s"],[4,5,"pl-s"],[24,25,"pl-s"],[25,26,"pl-s"],[26,46,"pl-corl"],[46,47,"pl-s"],[47,49,"pl-s",0,1,"pl-v"],[2,4,"pl-s"],[4,5,"pl-s"],[20,21,"pl-s"],[21,22,"pl-s"],[22,38,"pl-corl"],[38,39,"pl-s"],[39,41,"pl-s",[],0,11,"pl-mh"],[3,11,"pl-en",[],0,3,"pl-s"],[3,3,"pl-c1",0,23,"pl-c1",0,0,"pl-c1",0,10,"pl-c1",0,31,"pl-c1",0,19,"pl-c1",0,12,"pl-c1",0,17,"pl-c1",0,44,"pl-c1",0,0,"pl-c1"],[0,3,"pl-s",[],0,18,"pl-mh"],[3,18,"pl-en",13,14,"pl-s"],[14,24,"pl-c1"],[24,25,"pl-s",0,3,"pl-s"],[3,4,"pl-en",25,31,"pl-k",0,7,"pl-en",0,3,"pl-s"],[3,3,"pl-c1",0,0,"pl-c1",0,79,"pl-c1",0,14,"pl-c1",0,4,"pl-c1",0,29,"pl-c1",0,31,"pl-c1",0,0,"pl-c1"],[0,3,"pl-s",[],[],0,1,"pl-s"],[1,13,"pl-c1"],[13,14,"pl-s",[],[],29,30,"pl-s"],[30,40,"pl-c1"],[40,41,"pl-s",[],0,3,"pl-s"],[3,4,"pl-en",0,8,"pl-en",0,3,"pl-s"],[3,3,"pl-c1",0,0,"pl-c1",0,71,"pl-c1",0,80,"pl-c1",0,78,"pl-c1",0,77,"pl-c1",0,66,"pl-c1",0,0,"pl-c1",0,4,"pl-c1",0,67,"pl-c1",0,26,"pl-c1",0,21,"pl-c1",0,1,"pl-c1",0,0,"pl-c1"],[0,3,"pl-s",[],19,20,"pl-s"],[20,37,"pl-c1"],[37,38,"pl-s",[],[],[],[],36,37,"pl-s"],[37,47,"pl-c1"],[47,48,"pl-s",50,51,"pl-s"],[51,61,"pl-c1"],[61,62,"pl-s",[],0,3,"pl-s"],[3,4,"pl-en",0,2,"pl-k"],[19,30,"pl-s"],[19,20,"pl-pds"],[29,30,"pl-pds",2,8,"pl-c1",[],0,3,"pl-s",[],[],[],[],[],29,30,"pl-s"],[30,42,"pl-c1"],[42,43,"pl-s"],[48,49,"pl-s"],[49,60,"pl-c1"],[60,61,"pl-s",[],[],0,3,"pl-s"],[3,4,"pl-en",0,3,"pl-k"],[5,8,"pl-k"],[13,14,"pl-c1"],[20,22,"pl-c1",2,12,"pl-c1",[],[],[],2,11,"pl-c1",[],0,3,"pl-s",[],57,58,"pl-s"],[58,66,"pl-c1"],[66,67,"pl-s",[],0,3,"pl-s"],[3,4,"pl-en",0,6,"pl-en",0,3,"pl-s"],[3,3,"pl-c1",0,0,"pl-c1",0,78,"pl-c1",0,79,"pl-c1",0,79,"pl-c1",0,4,"pl-c1",0,23,"pl-c1",0,36,"pl-c1",0,37,"pl-c1",0,99,"pl-c1",0,3,"pl-c1",0,37,"pl-c1",0,49,"pl-c1",0,3,"pl-c1",0,37,"pl-c1",0,63,"pl-c1",0,3,"pl-c1",0,37,"pl-c1",0,34,"pl-c1",0,3,"pl-c1",0,1,"pl-c1",0,0,"pl-c1"],[0,3,"pl-s",[],8,9,"pl-s"],[9,10,"pl-s"],[10,14,"pl-c1"],[14,15,"pl-s"],[15,16,"pl-s"],[16,17,"pl-s"],[17,24,"pl-corl"],[24,25,"pl-s",[],[],0,16,"pl-mh"],[3,16,"pl-en",44,45,"pl-s"],[49,50,"pl-s",24,25,"pl-s"],[30,31,"pl-s"],[35,36,"pl-s"],[43,44,"pl-s",[],0,1,"pl-s"],[1,16,"pl-c1"],[16,17,"pl-s",[],[],0,3,"pl-s"],[3,4,"pl-en",0,59,"pl-c"],[0,2,"pl-c",0,55,"pl-c"],[53,55,"pl-c",0,13,"pl-en"],[26,27,"pl-s"],[27,28,"pl-s",0,3,"pl-s"],[3,3,"pl-c1",0,71,"pl-c1",0,71,"pl-c1",0,39,"pl-c1",0,0,"pl-c1",0,68,"pl-c1",0,70,"pl-c1",0,74,"pl-c1",0,74,"pl-c1",0,73,"pl-c1",0,4,"pl-c1",0,50,"pl-c1",0,20,"pl-c1",0,34,"pl-c1",0,25,"pl-c1",0,0,"pl-c1"],[0,3,"pl-s",[],7,8,"pl-s"],[8,13,"pl-c1"],[13,14,"pl-s"],[28,29,"pl-s"],[29,30,"pl-c1"],[30,31,"pl-s"],[37,38,"pl-s"],[38,44,"pl-c1"],[44,45,"pl-s",[],13,14,"pl-s"],[14,31,"pl-c1"],[31,32,"pl-s"],[36,37,"pl-s"],[37,49,"pl-c1"],[49,50,"pl-s",[],0,3,"pl-s"],[3,4,"pl-en",0,13,"pl-en",[],[],[],[],0,3,"pl-s"],[3,3,"pl-c1",0,0,"pl-c1",0,55,"pl-c1",0,69,"pl-c1",0,69,"pl-c1",0,71,"pl-c1",0,71,"pl-c1",0,19,"pl-c1",0,0,"pl-c1",0,71,"pl-c1",0,73,"pl-c1",0,71,"pl-c1",0,40,"pl-c1",0,0,"pl-c1",0,70,"pl-c1",0,71,"pl-c1",0,70,"pl-c1",0,70,"pl-c1",0,68,"pl-c1",0,70,"pl-c1",0,48,"pl-c1",0,4,"pl-c1",0,35,"pl-c1",0,33,"pl-c1",0,0,"pl-c1"],[0,3,"pl-s",[],[],0,1,"pl-s"],[1,9,"pl-c1"],[9,10,"pl-s"],[23,24,"pl-s"],[24,44,"pl-c1"],[44,45,"pl-s",0,3,"pl-s"],[3,4,"pl-en",0,71,"pl-c"],[0,2,"pl-c"],[69,71,"pl-c",0,18,"pl-en",[],0,3,"pl-s"],[3,3,"pl-c1",0,67,"pl-c1",0,71,"pl-c1",0,40,"pl-c1",0,0,"pl-c1",0,0,"pl-c1",0,22,"pl-c1",0,74,"pl-c1",0,73,"pl-c1",0,0,"pl-c1",0,70,"pl-c1",0,72,"pl-c1",0,71,"pl-c1",0,71,"pl-c1",0,73,"pl-c1",0,15,"pl-c1",0,0,"pl-c1",0,67,"pl-c1",0,71,"pl-c1",0,71,"pl-c1",0,70,"pl-c1",0,24,"pl-c1",0,0,"pl-c1",0,0,"pl-c1",0,18,"pl-c1",0,72,"pl-c1",0,73,"pl-c1",0,69,"pl-c1",0,67,"pl-c1",0,69,"pl-c1",0,70,"pl-c1",0,68,"pl-c1",0,50,"pl-c1",0,0,"pl-c1",0,71,"pl-c1",0,72,"pl-c1",0,67,"pl-c1",0,24,"pl-c1",0,0,"pl-c1",0,67,"pl-c1",0,62,"pl-c1",0,4,"pl-c1",0,46,"pl-c1",0,55,"pl-c1",0,37,"pl-c1",0,38,"pl-c1",0,0,"pl-c1",0,20,"pl-c1",0,14,"pl-c1",0,64,"pl-c1",0,15,"pl-c1",0,25,"pl-c1",0,3,"pl-c1",0,0,"pl-c1",0,12,"pl-c1",0,15,"pl-c1",0,29,"pl-c1",0,59,"pl-c1",0,74,"pl-c1",0,0,"pl-c1",0,13,"pl-c1",0,1,"pl-c1",0,0,"pl-c1"],[0,3,"pl-s"],"colorizedLines":null}},"title":"microui/doc/usage.md at master · rxi/microui","appPayload":{},"meta":{"title":"microui/doc/usage.md at master · rxi/microui"}}</script>

    Files

     master

    Breadcrumbs

    1. microui
    2. doc

    usage.md

    Blame
    Blame

    Latest commit

     

    History

    History
    251 lines (218 loc) · 9.08 KB
     master

    Breadcrumbs

    1. microui
    2. doc

    usage.md

    Top

    File metadata and controls

    • Preview
    • Code
    • Blame
    251 lines (218 loc) · 9.08 KB

    Usage

    Overview

    The overall structure when using the library is as follows:

    main loop: call mu_input_... functions call mu_begin() process ui call mu_end() iterate commands using mu_command_next()">
    initialise mu_Context

    main loop: call mu_input_... functions call mu_begin() process ui call mu_end() iterate commands using mu_command_next()

    Getting Started

    Before use a mu_Context should be initialised:

    mu_Context *ctx = malloc(sizeof(mu_Context));
    mu_init(ctx);

    Following which the context's text_width and text_height callback functions should be set:

    ctx->text_width = text_width;
    ctx->text_height = text_height;

    In your main loop you should first pass user input to microui using the mu_input_... functions. It is safe to call the input functions multiple times if the same input event occurs in a single frame.

    After handling the input the mu_begin() function must be called before processing your UI:

    mu_begin(ctx);

    Before any controls can be used we must begin a window using one of the mu_begin_window... or mu_begin_popup... functions. The mu_begin_... window functions return a truthy value if the window is open, if this is not the case we should not process the window any further. When we are finished processing the window's ui the mu_end_... window function should be called.

    if (mu_begin_window(ctx, "My Window", mu_rect(10, 10, 300, 400))) {
      /* process ui here... */
      mu_end_window(ctx);
    }

    It is safe to nest mu_begin_window() calls, this can be useful for things like context menus; the windows will still render separate from one another like normal.

    While inside a window block we can safely process controls. Controls that allow user interaction return a bitset of MU_RES_... values. Some controls — such as buttons — can only potentially return a single MU_RES_..., thus their return value can be treated as a boolean:

    if (mu_button(ctx, "My Button")) {
      printf("'My Button' was pressed\n");
    }

    The library generates unique IDs for controls internally to keep track of which are focused, hovered, etc. These are typically generated from the name/label passed to the function, or, in the case of sliders and checkboxes the value pointer. An issue arises then if you have several buttons in a window or panel that use the same label. The mu_push_id() and mu_pop_id() functions are provided for such situations, allowing you to push additional data that will be mixed into the unique ID:

    for (int i = 0; i < 10; i++) {
      mu_push_id(ctx, &i, sizeof(i));
      if (mu_button(ctx, "x")) {
        printf("Pressed button %d\n", i);
      }
      mu_pop_id(ctx);
    }

    When we're finished processing the UI for this frame the mu_end() function should be called:

    mu_end(ctx);

    When we're ready to draw the UI the mu_next_command() can be used to iterate the resultant commands. The function expects a mu_Command pointer initialised to NULL. It is safe to iterate through the commands list any number of times:

    mu_Command *cmd = NULL;
    while (mu_next_command(ctx, &cmd)) {
      if (cmd->type == MU_COMMAND_TEXT) {
        render_text(cmd->text.font, cmd->text.text, cmd->text.pos.x, cmd->text.pos.y, cmd->text.color);
      }
      if (cmd->type == MU_COMMAND_RECT) {
        render_rect(cmd->rect.rect, cmd->rect.color);
      }
      if (cmd->type == MU_COMMAND_ICON) {
        render_icon(cmd->icon.id, cmd->icon.rect, cmd->icon.color);
      }
      if (cmd->type == MU_COMMAND_CLIP) {
        set_clip_rect(cmd->clip.rect);
      }
    }

    See the demo directory for a usage example.

    Layout System

    The layout system is primarily based around rows — Each row can contain a number of items or columns each column can itself contain a number of rows and so forth. A row is initialised using the mu_layout_row() function, the user should specify the number of items on the row, an array containing the width of each item, and the height of the row:

    /* initialise a row of 3 items: the first item with a width
    ** of 90 and the remaining two with the width of 100 */
    mu_layout_row(ctx, 3, (int[]) { 90, 100, 100 }, 0);

    When a row is filled the next row is started, for example, in the above code 6 buttons immediately after would result in two rows. The function can be called again to begin a new row.

    As well as absolute values, width and height can be specified as 0 which will result in the Context's style.size value being used, or a negative value which will size the item relative to the right/bottom edge, thus if we wanted a row with a small button at the left, a textbox filling most the row and a larger button at the right, we could do the following:

    mu_layout_row(ctx, 3, (int[]) { 30, -90, -1 }, 0);
    mu_button(ctx, "X");
    mu_textbox(ctx, buf, sizeof(buf));
    mu_button(ctx, "Submit");

    If the items parameter is 0, the widths parameter is ignored and controls will continue to be added to the row at the width last specified by mu_layout_width() or style.size.x if this function has not been called:

    mu_layout_row(ctx, 0, NULL, 0);
    mu_layout_width(ctx, -90);
    mu_textbox(ctx, buf, sizeof(buf));
    mu_layout_width(ctx, -1);
    mu_button(ctx, "Submit");

    A column can be started at any point on a row using the mu_layout_begin_column() function. Once begun, rows will act inside the body of the column — all negative size values will be relative to the column's body as opposed to the body of the container. All new rows will be contained within this column until the mu_layout_end_column() function is called.

    Internally controls use the mu_layout_next() function to retrieve the next screen-positioned-Rect and advance the layout system, you should use this function when making custom controls or if you want to advance the layout system without placing a control.

    The mu_layout_set_next() function is provided to set the next layout Rect explicitly. This will be returned by mu_layout_next() when it is next called. By using the relative boolean you can choose to provide a screen-space Rect or a Rect which will have the container's position and scroll offset applied to it. You can peek the next Rect from the layout system by using the mu_layout_next() function to retrieve it, followed by mu_layout_set_next() to return it:

    mu_Rect rect = mu_layout_next(ctx);
    mu_layout_set_next(ctx, rect, 0);

    If you want to position controls arbitrarily inside a container the relative argument of mu_layout_set_next() should be true:

    /* place a (40, 40) sized button at (300, 300) inside the container: */
    mu_layout_set_next(ctx, mu_rect(300, 300, 40, 40), 1);
    mu_button(ctx, "X");

    A Rect set with relative true will also effect the content_size of the container, causing it to effect the scrollbars if it exceeds the width or height of the container's body.

    Style Customisation

    The library provides styling support via the mu_Style struct and, if you want greater control over the look, the draw_frame() callback function.

    The mu_Style struct contains spacing and sizing information, as well as a colors array which maps colorid to mu_Color. The library uses the style pointer field of the context to resolve colors and spacing, it is safe to change this pointer or modify any fields of the resultant struct at any point. See microui.h for the struct's implementation.

    In addition to the style struct the context stores a draw_frame() callback function which is used whenever the frame of a control needs to be drawn, by default this function draws a rectangle using the color of the colorid argument, with a one-pixel border around it using the MU_COLOR_BORDER color.

    Custom Controls

    The library exposes the functions used by built-in controls to allow the user to make custom controls. A control should take a mu_Context* value as its first argument and return a MU_RES_... value. Your control's implementation should use mu_layout_next() to get its destination Rect and advance the layout system. mu_get_id() should be used with some data unique to the control to generate an ID for that control and mu_update_control() should be used to update the context's hover and focus values based on the mouse input state.

    The MU_OPT_HOLDFOCUS opt value can be passed to mu_update_control() if we want the control to retain focus when the mouse button is released — this behaviour is used by textboxes which we want to stay focused to allow for text input.

    A control that acts as a button which displays an integer and, when clicked increments that integer, could be implemented as such:

    /* handle input */ int res = 0; if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id) { (*value)++; res |= MU_RES_CHANGE; }

    /* draw */ char buf[32]; sprintf(buf, "%d", *value); mu_draw_control_frame(ctx, id, rect, MU_COLOR_BUTTON, 0); mu_draw_control_text(ctx, buf, rect, MU_COLOR_TEXT, MU_OPT_ALIGNCENTER);

    return res; }">

    int incrementer(mu_Context ctx, int value) {
    mu_Id     id = mu_get_id(ctx, &value, sizeof(value));
    mu_Rect rect = mu_layout_next(ctx);
    mu_update_control(ctx, id, rect, 0);

    /* handle input / int res = 0; if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id) { (value)++; res |= MU_RES_CHANGE; }

    /* draw / char buf[32]; sprintf(buf, "%d", value); mu_draw_control_frame(ctx, id, rect, MU_COLOR_BUTTON, 0); mu_draw_control_text(ctx, buf, rect, MU_COLOR_TEXT, MU_OPT_ALIGNCENTER);

    return res; }

    <script type="application/json" id="__PRIMER_DATA__R_1___">{"resolvedServerColorMode":"day"}</script>
    </main>
    
          <footer class="footer tmp-pt-7 tmp-pb-6 f6 color-fg-muted color-border-subtle p-responsive" role="contentinfo" >
    

    Footer

    © 2026 GitHub, Inc.
    <nav aria-label="Footer">
      <h3 class="sr-only" id="sr-footer-heading">Footer navigation</h3>
    
      <ul class="list-style-none d-flex flex-justify-center flex-wrap mb-2 mb-lg-0" aria-labelledby="sr-footer-heading">
    
    
          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to Terms&quot;,&quot;label&quot;:&quot;text:terms&quot;}" href="https://docs.github.com/site-policy/github-terms/github-terms-of-service" data-view-component="true" class="Link--secondary Link">Terms</a>
          </li>
    
          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to privacy&quot;,&quot;label&quot;:&quot;text:privacy&quot;}" href="https://docs.github.com/site-policy/privacy-policies/github-privacy-statement" data-view-component="true" class="Link--secondary Link">Privacy</a>
          </li>
    
          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to security&quot;,&quot;label&quot;:&quot;text:security&quot;}" href="https://github.com/security" data-view-component="true" class="Link--secondary Link">Security</a>
          </li>
    
          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to status&quot;,&quot;label&quot;:&quot;text:status&quot;}" href="https://www.githubstatus.com/" data-view-component="true" class="Link--secondary Link">Status</a>
          </li>
    
          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to community&quot;,&quot;label&quot;:&quot;text:community&quot;}" href="https://github.community/" data-view-component="true" class="Link--secondary Link">Community</a>
          </li>
    
          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to docs&quot;,&quot;label&quot;:&quot;text:docs&quot;}" href="https://docs.github.com/" data-view-component="true" class="Link--secondary Link">Docs</a>
          </li>
    
          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to contact&quot;,&quot;label&quot;:&quot;text:contact&quot;}" href="https://support.github.com?tags=dotcom-footer" data-view-component="true" class="Link--secondary Link">Contact</a>
          </li>
    
          <li class="mx-2" >
    
    Manage cookies
  • Do not share my personal information
  •   </ul>
    </nav>
    
    <ghcc-consent id="ghcc" class="position-fixed bottom-0 left-0" style="z-index: 999999"
      data-locale="en"
      data-initial-cookie-consent-allowed=""
      data-cookie-consent-required="false"
    ></ghcc-consent>
    
    You cant perform that action at this time.
    <template id="site-details-dialog">
    
    <div class="Popover js-hovercard-content position-absolute" style="display: none; outline: none;">
    
    <template id="snippet-clipboard-copy-button">
    
    </div>
    <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true" ></div>
    <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div>
    
    </html>

    Usage

    Overview

    The Jack Looper application provides a simple audio loop player using JACK.

    Getting Started

    1. Ensure JACK is running
    2. Run ./jack-looper
    3. Use the TUI interface to control playback

    Controls

    • Space: Play/Stop
    • Up/Down: Change BPM
    • Left/Right: Change loop length
    • R: Reset beat position
    • Q: Quit

    Building

    Run make to build all targets.