diff --git a/build/ImGui.linemap.json b/build/ImGui.linemap.json index 9040d12..df80c81 100644 --- a/build/ImGui.linemap.json +++ b/build/ImGui.linemap.json @@ -1 +1 @@ -[[46, "imgui.lua"], [21395, "imgui_demo.lua"], [29813, "imgui_draw.lua"], [35756, "imgui_h.lua"], [38423, "imgui_impl_roblox.lua"], [40071, "imgui_impl_roblox_fonts.lua"], [46474, "imgui_internal.lua"], [49943, "imgui_tables.lua"], [55002, "imgui_widgets.lua"], [65642, "imstb_rectpack.lua"], [66306, "imstb_textedit.lua"], [67848, "imstb_truetype.lua"], [70636, "imstd_minstdio.lua"]] \ No newline at end of file +[[46, "imgui.lua"], [21395, "imgui_demo.lua"], [31828, "imgui_draw.lua"], [37771, "imgui_h.lua"], [40464, "imgui_impl_roblox.lua"], [42112, "imgui_impl_roblox_fonts.lua"], [48515, "imgui_internal.lua"], [51984, "imgui_tables.lua"], [57043, "imgui_widgets.lua"], [67683, "imstb_rectpack.lua"], [68347, "imstb_textedit.lua"], [69889, "imstb_truetype.lua"], [72677, "imstd_minstdio.lua"]] \ No newline at end of file diff --git a/build/ImGui.luau b/build/ImGui.luau index 64a65e3..edcbea0 100644 --- a/build/ImGui.luau +++ b/build/ImGui.luau @@ -1,7 +1,7 @@ --!optimize 2 -- GENERATED by tools/bundle.py from *.lua, backends/, fonts/ - do not edit -local ImGui, ImVec2, ImVec4, ImRect, ImVec2_Copy, ImStd, ImVector, HelpMarker, IMGUI_DEMO_MARKER, ImGuiInputFlags, ImRect_Copy, ImGuiDataType, ImStb, IM_TRUNC, ImGuiKey, ImGuiStyleVarInfo, ImVec2_CopyV, IM_ASSERT_USER_ERROR, ImGuiHoveredFlags, ImFormatString, ImHashStr, ImS32, ImGuiColorEditFlags, IM_ASSERT_USER_ERROR_RET, ImDrawFlags, ImGuiTableFlags, ImIsPowerOfTwo, ImGuiWindowFlags, ImVec4_Copy, IM_ROUND, ImGuiTreeNodeFlags, ImGuiTableColumnFlags, ImU16, ImAbs, ImGuiItemFlags, ImGui_ImplRoblox_GetBackendData, stbte, ImGuiButtonFlags, ImGuiDebugLogFlags, ImGuiLocKey, ImU32, ImCos, ImGuiTabBarFlags, ImS16, ImSin, ImUpperPowerOfTwo, ImVec2_MulVX, IM_F32_TO_INT8_SAT, ImCeil, ImFontAtlasPackGetRect, ImGuiListClipper, DockSettingsRenameNodeReferences, IM_ASSERT_PARANOID, ImGuiCol, ImGuiTextFilter, ImLengthSqr, ImS8, ImU8, _PathArcToFastExXY, ImFabs, ImGuiLastItemData_Copy, ImGuiScrollFlags, ImLog, ImMemchr, ImStrByte, IMGUI_DEBUG_LOG_VIEWPORT, ImGuiComboFlags, ImGuiInputEvent, ImPow, DemoBuf, DemoHas, IMGUI_DEBUG_LOG_FONT, ImAddClampOverflow, ImFontAtlasBuildInit, ImFontCalcWordWrapPositionEx, ImGuiChildFlags, ImGuiLastItemData, ImGuiPayload_IsDataType, ImGuiPopupFlags, ImGuiSliderFlags, ImRotate, ImSubClampOverflow, ImTextClassifierSetCharClass, ImVec2_AddVA, ImVec2_SubVA, CalcNextScrollFromScrollTargetAndClamp, DemoBufStr, DemoNotPorted, IMGUI_PAYLOAD_TYPE_WINDOW, IMGUI_VERSION, ImCharIsSeparatorW, ImFmod, ImFontAtlasBakedAddFontGlyph, ImFontAtlasPackAddRect, ImFontBaked_BuildLoadGlyph, ImGuiInputTextFlags, ImGuiNavMoveFlags, ImGuiTextBuffer, ImHashData, ImVec1_Copy, ShowExampleMenuFile, ExampleTree_CreateNode, IM_F32_TO_INT8_UNBOUND, IM_PI, ImCharIsBlankA, ImCharIsBlankW, ImFontAtlasBuildRenderBitmapFromString, ImFontAtlasFontDestroyOutput, ImFontAtlasFontDiscardBakes, ImFontAtlasFontSourceAddToFont, ImFontAtlasFontSourceInit, ImFontAtlasRectId_GetIndex, ImFontAtlasTextureAdd, ImFontAtlasTextureBlockQueueUpload, ImFontAtlasTextureGrow, ImFontBaked_BuildGrowIndex, ImFontConfig, ImFontGlyph, ImGuiFocusedFlags, ImGuiTabItemFlags, ImGuiTableColumn, ImGuiWindowClass, ImGui_ImplRoblox_RenderDrawData, ImParseFormatFindStart, ImRect_CopyFromV4, ImTextureRect, ImTextureRef, ImTrunc64, stb_textedit_key, stbtt_GetGlyphBitmapBoxSubpixel, DockSettingsHandler_ClearAll, IMGUI_DEBUG_LOG_TABLE, IMGUI_PAYLOAD_TYPE_COLOR_4F, IM_FREE, ImDrawListSplitter, ImFontAtlasBakedDiscard, ImFontAtlasBuildDestroy, ImFontAtlasBuildNotifySetFont, ImFontAtlasBuildSetTexture, ImFontAtlasBuildSetupFontBakedFallback, ImFontAtlasFontDestroySourceData, ImFontAtlasPackInit, ImFontAtlasTextureBlockCopy, ImFontAtlasTextureGetSizeEstimate, ImFontAtlasUpdateDrawListsSharedData, ImFontBaked_BuildLoadGlyphAdvanceX, ImFontCalcTextSizeEx, ImFontCalcWordWrapPositionEx_Uncached, ImGuiDockNodeFlags, ImGuiDragDropFlags, ImGuiFocusScopeData, ImGuiInputTextCallbackData, ImGuiSettingsHandler, ImGuiStyleMod, ImHashStrRaw, ImTextClassifierClear, ImTextClassifierGet, ImTextClassifierSetCharClassFromStr, ImTextureDataGetFormatBytesPerPixel, stb_text_locate_coord +local ImGui, ImVec2, ImVec4, ImRect, HelpMarker, ImVec2_Copy, IMGUI_DEMO_MARKER, ImGuiTableFlags, ImStd, ImVector, ImGuiInputFlags, ImRect_Copy, ImGuiDataType, ImStb, IM_TRUNC, ImGuiKey, ImGuiStyleVarInfo, ImVec2_CopyV, IM_ASSERT_USER_ERROR, ImGuiHoveredFlags, ImFormatString, ImHashStr, ImS32, IM_ASSERT_USER_ERROR_RET, ImGuiColorEditFlags, ImDrawFlags, ImIsPowerOfTwo, ImVec4_Copy, ExampleAppConsoleMT, IM_ROUND, ImGuiTableColumnFlags, ImGuiTreeNodeFlags, PopStyleCompact, PushStyleCompact, ImU16, ImAbs, ImGuiWindowFlags, ImGuiItemFlags, ImGui_ImplRoblox_GetBackendData, stbte, ImGuiButtonFlags, ImGuiDebugLogFlags, ImGuiLocKey, ImU32, ImColor, ImCos, ImS16, ImGuiTabBarFlags, ImSin, ImUpperPowerOfTwo, ImVec2_MulVX, IM_F32_TO_INT8_SAT, ImCeil, ImFontAtlasPackGetRect, DockSettingsRenameNodeReferences, IM_ASSERT_PARANOID, ImGuiCol, ImGuiListClipper, ImLengthSqr, ImS8, ImU8, _PathArcToFastExXY, ExampleAppPropertyEditorMT, ImFabs, ImGuiChildFlags, ImGuiLastItemData_Copy, ImGuiScrollFlags, ImLog, ImMemchr, ImStrByte, IMGUI_DEBUG_LOG_VIEWPORT, ImGuiInputEvent, ImGuiTextBuffer, ImPow, CustomConstraints, ExampleAppLogMT, IMGUI_DEBUG_LOG_FONT, ImAddClampOverflow, ImFontAtlasBuildInit, ImFontCalcWordWrapPositionEx, ImGuiComboFlags, ImGuiLastItemData, ImGuiPayload_IsDataType, ImGuiPopupFlags, ImGuiSliderFlags, ImGuiTextFilter, ImRotate, ImSubClampOverflow, ImTextClassifierSetCharClass, ImVec2_AddVA, ImVec2_SubVA, MyDocument, ShowExampleMenuFile, CalcNextScrollFromScrollTargetAndClamp, IMGUI_PAYLOAD_TYPE_WINDOW, IMGUI_VERSION, ImCharIsSeparatorW, ImFmod, ImFontAtlasBakedAddFontGlyph, ImFontAtlasPackAddRect, ImFontBaked_BuildLoadGlyph, ImGuiInputTextFlags, ImGuiNavMoveFlags, ImGuiStyle_Copy, ImHashData, ImVec1_Copy, ExampleMemberInfo, ExampleTree_CreateNode, IM_F32_TO_INT8_UNBOUND, IM_PI, ImCharIsBlankA, ImCharIsBlankW, ImFontAtlasBuildRenderBitmapFromString, ImFontAtlasFontDestroyOutput, ImFontAtlasFontDiscardBakes, ImFontAtlasFontSourceAddToFont, ImFontAtlasFontSourceInit, ImFontAtlasRectId_GetIndex, ImFontAtlasTextureAdd, ImFontAtlasTextureBlockQueueUpload, ImFontAtlasTextureGrow, ImFontBaked_BuildGrowIndex, ImFontConfig, ImFontGlyph, ImGuiTableColumn, ImGuiWindowClass, ImGui_ImplRoblox_RenderDrawData, ImParseFormatFindStart, ImRect_CopyFromV4, ImTextureRect, ImTextureRef, ImTrunc64, MyItem_s_current_sort_specs, stb_textedit_key, stbtt_GetGlyphBitmapBoxSubpixel, DockSettingsHandler_ClearAll, EditTableSizingFlags, IMGUI_DEBUG_LOG_TABLE, IMGUI_PAYLOAD_TYPE_COLOR_4F, IM_FREE, ImDrawListSplitter, ImFontAtlasBakedDiscard, ImFontAtlasBuildDestroy, ImFontAtlasBuildNotifySetFont, ImFontAtlasBuildSetTexture, ImFontAtlasBuildSetupFontBakedFallback, ImFontAtlasFontDestroySourceData, ImFontAtlasPackInit, ImFontAtlasTextureBlockCopy, ImFontAtlasTextureGetSizeEstimate, ImFontAtlasUpdateDrawListsSharedData, ImFontBaked_BuildLoadGlyphAdvanceX, ImFontCalcTextSizeEx, ImFontCalcWordWrapPositionEx_Uncached, ImGuiDragDropFlags, ImGuiFocusScopeData, ImGuiFocusedFlags, ImGuiInputTextCallbackData, ImGuiSettingsHandler, ImGuiStyleMod local type, mathMin, mathMax, mathFloor, mathCeil, bitOr, bitLShift = type, math.min, math.max, math.floor, math.ceil, bit32.bor, bit32.lshift local function IM_COL32(R, G, B, A) return (bitOr(bitLShift(A, 24 --[[IM_COL32_A_SHIFT]]), bitLShift(B, 16 --[[IM_COL32_B_SHIFT]]), bitLShift(G, 8 --[[IM_COL32_G_SHIFT]]), bitLShift(R, 0 --[[IM_COL32_R_SHIFT]]))) end @native @@ -21393,18 +21393,15 @@ end __FILES['imgui_demo.lua'] = function() -- dear imgui demo (Luau port of imgui_demo.cpp). Optional: the library never calls into this file. - -do --[[ imgui_demo.lua ]] -- dear imgui, v1.93.0 WIP --- (demo code) Port of imgui_demo.cpp (docking branch) --- This file: shared demo helpers, ShowDemoWindow(), DemoWindowMenuBar(), DemoWindowWidgets() dispatcher, example tree/image viewer helpers. --- Other parts (all global functions, loaded from the same bundle): +-- (demo code) -- Help: -- - Read FAQ at http://dearimgui.com/faq --- - Call and read ImGui.ShowDemoWindow() in imgui_demo.lua. +-- - Call and read ImGui.ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. -- - Need help integrating Dear ImGui in your codebase? -- - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started +-- - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. -- Read top of imgui.cpp and imgui.h for many details, documentation, comments, links. -- Get the latest version at https://github.com/ocornut/imgui @@ -21422,17 +21419,20 @@ do --[[ imgui_demo.lua ]] -- Also include Metrics! ItemPicker! DebugLog! and other debug features. -- Removing this file from your project is hindering access to documentation for everyone in your team, -- likely leading you to poorer usage of the library. --- Whenever you have Dear ImGui available you probably want this to be available for reference. +-- Everything in this file will be stripped out by the linker if you don't call ImGui.ShowDemoWindow(). +-- If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be +-- linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. +-- [Port] There is no linker here: build the bundle with `tools/bundle.py --no-demo` to leave this file out. +-- In another situation, whenever you have Dear ImGui available you probably want this to be available for reference. -- Thank you, -- -Your beloved friend, imgui_demo.cpp (which you won't delete) ---------------------------------------------- -- ABOUT THE MEANING OF THE 'static' KEYWORD: ---------------------------------------------- --- In the upstream C++ demo code, 'static' variables inside functions are frequently used. +-- In this demo code, we frequently use 'static' variables inside functions. -- A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function. -- Think of "static int n = 0;" as "global int n = 0;" ! --- (PORT: Lua has no function-local statics; this port keeps them as fields of file-level tables, e.g. `S`, `SL`, `ST`.) -- We do this IN THE DEMO because we want: -- - to gather code and data in the same place. -- - to make the demo source code faster to read, faster to change, smaller in size. @@ -21440,79 +21440,150 @@ do --[[ imgui_demo.lua ]] -- doesn't need to be reentrant or used in multiple threads. -- This might be a pattern you will want to use in your code, but most of the data you would be working -- with in a complex codebase is likely going to be stored outside your functions. +-- [Port] Lua has no function-level 'static': they are fields of the file-level table S (S.FunctionName.x). ------------------------------------------- -- ABOUT THE CODING STYLE OF OUR DEMO CODE ------------------------------------------- -- The Demo code in this file is designed to be easy to copy-and-paste into your application! -- Because of this: --- - We never omit the ImGui. prefix when calling functions. +-- - We never omit the ImGui. prefix when calling functions, even though most code here is in the same namespace. +-- - We try to declare static variables in the local scope, as close as possible to the code using them. +-- - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API. +-- - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided +-- by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional +-- and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. +-- Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp. -- Navigating this file: +-- - In Visual Studio: Ctrl+Comma ("Edit.GoToAll") can follow symbols inside comments, whereas Ctrl+F12 ("Edit.GoToImplementation") cannot. +-- - In Visual Studio w/ Visual Assist installed: Alt+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. +-- - In VS Code, CLion, etc.: Ctrl+Click can follow symbols inside comments. -- - You can search/grep for all sections listed in the index to find the section. --- Index of this file: --- --- [SECTION] Helpers --- [SECTION] Demo Window / ShowDemoWindow() --- [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) --- [SECTION] Helpers: ExampleImageViewer --- [SECTION] DemoWindowWidgetsBasic() --- [SECTION] DemoWindowWidgetsBullets() --- [SECTION] DemoWindowWidgetsCollapsingHeaders() --- [SECTION] DemoWindowWidgetsComboBoxes() --- [SECTION] DemoWindowWidgetsColorAndPickers() --- [SECTION] DemoWindowWidgetsDataTypes() --- [SECTION] DemoWindowWidgetsDisableBlocks() --- [SECTION] DemoWindowWidgetsDragAndDrop() --- [SECTION] DemoWindowWidgetsDragsAndSliders() --- [SECTION] DemoWindowWidgetsFonts() --- [SECTION] DemoWindowWidgetsImages() --- [SECTION] DemoWindowWidgetsListBoxes() --- [SECTION] DemoWindowWidgetsLiveEdit() --- [SECTION] DemoWindowWidgetsMixedValues() --- [SECTION] DemoWindowWidgetsMultiComponents() --- [SECTION] DemoWindowWidgetsPlotting() --- [SECTION] DemoWindowWidgetsProgressBars() --- [SECTION] DemoWindowWidgetsQueryingStatuses() --- [SECTION] DemoWindowWidgetsSelectables() --- [SECTION] DemoWindowWidgetsTabs() --- [SECTION] DemoWindowWidgetsText() --- [SECTION] DemoWindowWidgetsTextFilter() --- [SECTION] DemoWindowWidgetsTextInput() --- [SECTION] DemoWindowWidgetsTooltips() --- [SECTION] DemoWindowWidgetsTreeNodes() --- [SECTION] DemoWindowWidgetsVerticalSliders() --- [SECTION] DemoWindowWidgets() --- [SECTION] DemoWindowLayout() --- [SECTION] DemoWindowPopups() --- [SECTION] DemoWindowTables() --- [SECTION] About Window / ShowAboutWindow() --- [SECTION] Style Editor / ShowStyleEditor() --- [SECTION] User Guide / ShowUserGuide() --- [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() --- [SECTION] Example App: Debug Console / ShowExampleAppConsole() --- [SECTION] Example App: Debug Log / ShowExampleAppLog() --- [SECTION] Example App: Simple Layout / ShowExampleAppLayout() --- [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() --- [SECTION] Example App: Long Text / ShowExampleAppLongText() --- [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() --- [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() --- [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() --- [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() --- [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() --- [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() --- [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() --- [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() +--[[ -local _ +Index of this file: + +// [SECTION] Forward Declarations +// [SECTION] Helpers +// [SECTION] Demo Window / ShowDemoWindow() +// [SECTION] DemoWindowMenuBar() +// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) +// [SECTION] Helpers: ExampleImageViewer +// [SECTION] DemoWindowWidgetsBasic() +// [SECTION] DemoWindowWidgetsBullets() +// [SECTION] DemoWindowWidgetsCollapsingHeaders() +// [SECTION] DemoWindowWidgetsComboBoxes() +// [SECTION] DemoWindowWidgetsColorAndPickers() +// [SECTION] DemoWindowWidgetsDataTypes() +// [SECTION] DemoWindowWidgetsDisableBlocks() +// [SECTION] DemoWindowWidgetsDragAndDrop() +// [SECTION] DemoWindowWidgetsDragsAndSliders() +// [SECTION] DemoWindowWidgetsFonts() +// [SECTION] DemoWindowWidgetsImages() +// [SECTION] DemoWindowWidgetsListBoxes() +// [SECTION] DemoWindowWidgetsLiveEdit() +// [SECTION] DemoWindowWidgetsMixedValues() +// [SECTION] DemoWindowWidgetsMultiComponents() +// [SECTION] DemoWindowWidgetsPlotting() +// [SECTION] DemoWindowWidgetsProgressBars() +// [SECTION] DemoWindowWidgetsQueryingStatuses() +// [SECTION] DemoWindowWidgetsSelectables() +// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect() +// [SECTION] DemoWindowWidgetsTabs() +// [SECTION] DemoWindowWidgetsText() +// [SECTION] DemoWindowWidgetsTextFilter() +// [SECTION] DemoWindowWidgetsTextInput() +// [SECTION] DemoWindowWidgetsTooltips() +// [SECTION] DemoWindowWidgetsTreeNodes() +// [SECTION] DemoWindowWidgetsVerticalSliders() +// [SECTION] DemoWindowWidgets() +// [SECTION] DemoWindowLayout() +// [SECTION] DemoWindowPopups() +// [SECTION] DemoWindowTables() +// [SECTION] DemoWindowInputs() +// [SECTION] About Window / ShowAboutWindow() +// [SECTION] Style Editor / ShowStyleEditor() +// [SECTION] User Guide / ShowUserGuide() +// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +// [SECTION] Example App: Debug Console / ShowExampleAppConsole() +// [SECTION] Example App: Image Viewer / ShowExampleAppImageViewer() +// [SECTION] Example App: Debug Log / ShowExampleAppLog() +// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() +// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() +// [SECTION] Example App: Long Text / ShowExampleAppLongText() +// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() +// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() +// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() +// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() +// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser() + +]] + +-- [Port] C includes, compiler warning pragmas, snprintf/PRId64/IMGUI_CDECL defines dropped (C only). + +-- Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) +-- [Port] IM_NEWLINE is always "\n" here. + +-- Helpers macros +-- We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, +-- but making an exception here as those are largely simplifying code... +-- In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. +-- [Port] IM_MIN/IM_MAX/IM_CLAMP -> the library globals ImMin/ImMax/ImClamp. + +------------------------------------------------------------------------------- +-- [SECTION] Forward Declarations +------------------------------------------------------------------------------- + +-- Forward Declarations +-- [Port] Not needed in Lua (globals are resolved at call time). Upstream list kept for reference: +-- struct ImGuiDemoWindowData; +-- static void ShowExampleAppMainMenuBar(); +-- static void ShowExampleAppAssetsBrowser(bool* p_open); +-- static void ShowExampleAppConsole(bool* p_open); +-- static void ShowExampleAppCustomRendering(bool* p_open); +-- static void ShowExampleAppDockSpace(bool* p_open); +-- static void ShowExampleAppDocuments(bool* p_open); +-- static void ShowExampleAppImageViewer(bool* p_open); +-- static void ShowExampleAppLog(bool* p_open); +-- static void ShowExampleAppLayout(bool* p_open); +-- static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data); +-- static void ShowExampleAppSimpleOverlay(bool* p_open); +-- static void ShowExampleAppAutoResize(bool* p_open); +-- static void ShowExampleAppConstrainedResize(bool* p_open); +-- static void ShowExampleAppFullscreen(bool* p_open); +-- static void ShowExampleAppLongText(bool* p_open); +-- static void ShowExampleAppWindowTitles(bool* p_open); +-- static void ShowExampleMenuFile(); + +-- We split the contents of the big ShowDemoWindow() function into smaller functions +-- (because the link time of very large functions tends to grow non-linearly) +-- static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data); +-- static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data); +-- static void DemoWindowLayout(); +-- static void DemoWindowPopups(); +-- static void DemoWindowTables(); +-- static void DemoWindowColumns(); +-- static void DemoWindowInputs(); + +-- Helper tree functions used by Property Editor & Multi-Select demos +-- struct ExampleTreeNode; +-- static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent); +-- static void ExampleTree_DestroyNode(ExampleTreeNode* node); ------------------------------------------------------------------------------- -- [SECTION] Helpers ------------------------------------------------------------------------------- --- Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer) -function IMGUI_DEMO_MARKER(_) end -- upstream hook, no-op here +-- [Port] Storage for C++ function-level `static` variables: one sub-table per upstream function (S.FunctionName), +-- declared right above the function. Shared by every part of this file. +local S = {} +local _ -- [Port] discard target for unused return values (`_, v = ImGui.Checkbox(...)`) -- Helper to display a little (?) mark which shows a tooltip when hovered. -- In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md) @@ -21536,138 +21607,17 @@ function ShowDockingDisabledMessage() end end -function DemoNotSupported() ImGui.TextDisabled("(not supported on Roblox)") end -function DemoNotPorted(what) ImGui.TextDisabled("(not ported yet%s)", what and (": " .. what) or "") end -function DemoB2I(b) return b and 1 or 0 end -function DemoHas(flags, f) return bit32.band(flags, f) ~= 0 end -function DemoClamp(v, mn, mx) return (v < mn) and mn or (v > mx) and mx or v end +-- Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer) +function IMGUI_DEMO_MARKER(section) end -- [Port] no ImGui.DemoMarker() hook in this port: no-op ---- `char buf[size] = "str"` -> zero-terminated byte table -function DemoBuf(str, size) - local t = {} - for i = 1, #str do t[i] = string.byte(str, i) end - t[#str + 1] = 0 - if size then for i = #str + 2, size do t[i] = 0 end end - return t -end ---- byte table -> Lua string (up to the zero terminator) -function DemoBufStr(buf) - local n = 0 - while buf[n + 1] ~= nil and buf[n + 1] ~= 0 do n = n + 1 end - if n == 0 then return "" end - return ImGui._ByteArrayToString(buf, 1, n + 1) -end - ---- "a\0b\0c\0\0" -> { "a", "b", "c" } -function DemoItems(s) - if type(s) == "table" then return s end - local t = {} - for item in string.gmatch(s, "([^%z]+)") do t[#t + 1] = item end - return t -end - ---- Combo() one-liner. `idx` is 0-based; `items` is a table of strings (1-based) or a "\0"-separated string. ---- Uses ImGui.Combo if it exists, falls back to BeginCombo/Selectable. ---- @return int idx, bool changed -function DemoCombo(label, idx, items, popup_max_height_in_items) - items = DemoItems(items) - if ImGui.Combo then - return ImGui.Combo(label, idx, items, #items, popup_max_height_in_items or -1) - end - local changed = false - local preview = (idx >= 0 and idx < #items) and items[idx + 1] or "" - if ImGui.BeginCombo(label, preview) then - for n = 0, #items - 1 do - local is_selected = (idx == n) - if ImGui.Selectable(items[n + 1], is_selected) then - idx = n - changed = true - end - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndCombo() - end - return idx, changed -end - ---- ListBox() one-liner (see DemoCombo) -function DemoListBox(label, idx, items, height_in_items) - items = DemoItems(items) - if ImGui.ListBox then - return ImGui.ListBox(label, idx, items, #items, height_in_items or -1) - end - local changed = false - if height_in_items == nil or height_in_items < 0 then height_in_items = math.min(#items, 7) end - local height_in_items_f = height_in_items + 0.25 - local height_in_pixels = math.floor(ImGui.GetTextLineHeightWithSpacing() * height_in_items_f + ImGui.GetStyle().FramePadding.y * 2.0) - if ImGui.BeginListBox and ImGui.BeginListBox(label, ImVec2(0.0, height_in_pixels)) then - for n = 0, #items - 1 do - local is_selected = (idx == n) - if ImGui.Selectable(items[n + 1], is_selected) then - idx = n - changed = true - end - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndListBox() - elseif not ImGui.BeginListBox then - DemoNotPorted("ListBox") - end - return idx, changed -end - ---- Closable header: CollapsingHeader(label, &p_open). Returns visible, open. -function DemoCollapsingHeaderClosable(label, open) - return ImGui.CollapsingHeader(label, open) -end - ---- ImColor::HSV() as ImVec4 -function DemoHSV(h, s, v, a) - local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v) - return ImVec4(r, g, b, a or 1.0) -end - ---- Minimal ImGuiTextFilter when the library one isn't available (Draw/DrawWithHint/PassFilter/Clear/IsActive) -function DemoTextFilter() - if ImGuiTextFilter then return ImGuiTextFilter() end - local f = { InputBuf = DemoBuf("", 256) } - local function parse(self) - local inc, exc = {}, {} - for tok in string.gmatch(string.lower(DemoBufStr(self.InputBuf)), "[^,%s]+") do - if string.sub(tok, 1, 1) == "-" then - if #tok > 1 then exc[#exc + 1] = string.sub(tok, 2) end - else - inc[#inc + 1] = tok - end - end - return inc, exc - end - function f:Draw(label, width) - if width and width ~= 0 then ImGui.SetNextItemWidth(width) end - return ImGui.InputText(label or "Filter (inc,-exc)", self.InputBuf, 256) - end - function f:DrawWithHint(label, hint, width) - if width and width ~= 0 then ImGui.SetNextItemWidth(width) end - return ImGui.InputTextWithHint(label, hint, self.InputBuf, 256) - end - function f:Clear() self.InputBuf[1] = 0 end - function f:IsActive() return self.InputBuf[1] ~= 0 and self.InputBuf[1] ~= nil end - function f:PassFilter(text) - local inc, exc = parse(self) - text = string.lower(text) - for _, e in ipairs(exc) do if string.find(text, e, 1, true) then return false end end - if #inc == 0 then return true end - for _, i in ipairs(inc) do if string.find(text, i, 1, true) then return true end end - return false - end - return f -end +-- Sneakily forward declare functions which aren't worth putting in public API yet +-- [Port] ImGui.ShowFontAtlas(atlas) and ImGui.TreeNodeSetOpen(storage_id, is_open) are already public here. ------------------------------------------------------------------------------- --- [SECTION] Demo Window data +-- [SECTION] Demo Window / ShowDemoWindow() ------------------------------------------------------------------------------- ---- Data to be shared across different functions of the demo. +-- Data to be shared across different functions of the demo. function ImGuiDemoWindowData() return { -- Examples Apps (accessible from the "Examples" menu) @@ -21698,11 +21648,466 @@ function ImGuiDemoWindowData() -- Other data DisableSections = false, LiveEditOverride = false, - LiveEditFlags = 128 --[[ImGuiItemFlags.LiveEditOnInputText]] or 0, + LiveEditFlags = 128 --[[ImGuiItemFlags.LiveEditOnInputText]], DemoTree = nil, + + -- [Port] no destructor: DemoTree is garbage collected (upstream calls ExampleTree_DestroyNode(DemoTree)). } end +S.ShowDemoWindow = { + -- Stored data + demo_data = ImGuiDemoWindowData(), + + -- Demonstrate the various window flags. Typically you would just use the default! + no_titlebar = false, + no_scrollbar = false, + no_menu = false, + no_move = false, + no_resize = false, + no_collapse = false, + no_close = false, + no_nav = false, + no_background = false, + no_bring_to_front = false, + no_docking = false, + unsaved_document = false, +} + +-- Demonstrate most Dear ImGui features (this is big function!) +-- You may execute this function to experiment with the UI and understand what it does. +-- You may then search for keywords in the code when you are interested by a specific feature. +-- [Port] p_open: true/false/nil (nil = no close button). Returns the new p_open value. +function ImGui.ShowDemoWindow(p_open) + local s = S.ShowDemoWindow + + -- Exceptionally add an extra assert here for people confused about initial Dear ImGui setup + -- Most functions would normally just assert/crash if the context is missing. + assert(ImGui.GetCurrentContext() ~= nil, "Missing Dear ImGui context. Refer to examples app!") + + -- Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues. + -- [Port] IMGUI_CHECKVERSION() dropped: no ABI to verify. + + -- Stored data + local demo_data = s.demo_data + + -- Examples Apps (accessible from the "Examples" menu) + if demo_data.ShowMainMenuBar then ShowExampleAppMainMenuBar() end + if demo_data.ShowAppDockSpace then demo_data.ShowAppDockSpace = ShowExampleAppDockSpace(demo_data.ShowAppDockSpace) end -- Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) + if demo_data.ShowAppDocuments then demo_data.ShowAppDocuments = ShowExampleAppDocuments(demo_data.ShowAppDocuments) end -- ...process the Document app next, as it may also use a DockSpace() + if demo_data.ShowAppAssetsBrowser then demo_data.ShowAppAssetsBrowser = ShowExampleAppAssetsBrowser(demo_data.ShowAppAssetsBrowser) end + if demo_data.ShowAppConsole then demo_data.ShowAppConsole = ShowExampleAppConsole(demo_data.ShowAppConsole) end + if demo_data.ShowAppCustomRendering then demo_data.ShowAppCustomRendering = ShowExampleAppCustomRendering(demo_data.ShowAppCustomRendering) end + if demo_data.ShowAppImageViewer then demo_data.ShowAppImageViewer = ShowExampleAppImageViewer(demo_data.ShowAppImageViewer) end + if demo_data.ShowAppLog then demo_data.ShowAppLog = ShowExampleAppLog(demo_data.ShowAppLog) end + if demo_data.ShowAppLayout then demo_data.ShowAppLayout = ShowExampleAppLayout(demo_data.ShowAppLayout) end + if demo_data.ShowAppPropertyEditor then demo_data.ShowAppPropertyEditor = ShowExampleAppPropertyEditor(demo_data.ShowAppPropertyEditor, demo_data) end + if demo_data.ShowAppSimpleOverlay then demo_data.ShowAppSimpleOverlay = ShowExampleAppSimpleOverlay(demo_data.ShowAppSimpleOverlay) end + if demo_data.ShowAppAutoResize then demo_data.ShowAppAutoResize = ShowExampleAppAutoResize(demo_data.ShowAppAutoResize) end + if demo_data.ShowAppConstrainedResize then demo_data.ShowAppConstrainedResize = ShowExampleAppConstrainedResize(demo_data.ShowAppConstrainedResize) end + if demo_data.ShowAppFullscreen then demo_data.ShowAppFullscreen = ShowExampleAppFullscreen(demo_data.ShowAppFullscreen) end + if demo_data.ShowAppLongText then demo_data.ShowAppLongText = ShowExampleAppLongText(demo_data.ShowAppLongText) end + if demo_data.ShowAppWindowTitles then demo_data.ShowAppWindowTitles = ShowExampleAppWindowTitles(demo_data.ShowAppWindowTitles) end + + -- Dear ImGui Tools (accessible from the "Tools" menu) + if demo_data.ShowMetrics then demo_data.ShowMetrics = ImGui.ShowMetricsWindow(demo_data.ShowMetrics) end + if demo_data.ShowDebugLog then demo_data.ShowDebugLog = ImGui.ShowDebugLogWindow(demo_data.ShowDebugLog) end + if demo_data.ShowIDStackTool then demo_data.ShowIDStackTool = ImGui.ShowIDStackToolWindow(demo_data.ShowIDStackTool) end + if demo_data.ShowAbout then demo_data.ShowAbout = ImGui.ShowAboutWindow(demo_data.ShowAbout) end + if demo_data.ShowStyleEditor then + demo_data.ShowStyleEditor = ImGui.Begin("Dear ImGui Style Editor", demo_data.ShowStyleEditor) + ImGui.ShowStyleEditor() + ImGui.End() + end + + -- Demonstrate the various window flags. Typically you would just use the default! + local window_flags = 0 + if s.no_titlebar then window_flags = bit32.bor(window_flags, 1 --[[ImGuiWindowFlags.NoTitleBar]]) end + if s.no_scrollbar then window_flags = bit32.bor(window_flags, 8 --[[ImGuiWindowFlags.NoScrollbar]]) end + if not s.no_menu then window_flags = bit32.bor(window_flags, 1024 --[[ImGuiWindowFlags.MenuBar]]) end + if s.no_move then window_flags = bit32.bor(window_flags, 4 --[[ImGuiWindowFlags.NoMove]]) end + if s.no_resize then window_flags = bit32.bor(window_flags, 2 --[[ImGuiWindowFlags.NoResize]]) end + if s.no_collapse then window_flags = bit32.bor(window_flags, 32 --[[ImGuiWindowFlags.NoCollapse]]) end + if s.no_nav then window_flags = bit32.bor(window_flags, 196608 --[[ImGuiWindowFlags.NoNav]]) end + if s.no_background then window_flags = bit32.bor(window_flags, 128 --[[ImGuiWindowFlags.NoBackground]]) end + if s.no_bring_to_front then window_flags = bit32.bor(window_flags, 8192 --[[ImGuiWindowFlags.NoBringToFrontOnFocus]]) end + if s.no_docking then window_flags = bit32.bor(window_flags, 524288 --[[ImGuiWindowFlags.NoDocking]]) end + if s.unsaved_document then window_flags = bit32.bor(window_flags, 262144 --[[ImGuiWindowFlags.UnsavedDocument]]) end + local begin_p_open = p_open -- [Port] keep the caller's value intact when not passed to Begin() + if s.no_close then begin_p_open = nil end -- Don't pass our bool* to Begin + + -- We specify a default position/size in case there's no data in the .ini file. + -- We only do it to make the demo applications a little more welcoming, but typically this isn't required. + local main_viewport = ImGui.GetMainViewport() + ImGui.SetNextWindowPos(ImVec2(main_viewport.WorkPos.x + 650, main_viewport.WorkPos.y + 20), 4 --[[ImGuiCond.FirstUseEver]]) + ImGui.SetNextWindowSize(ImVec2(550, 680), 4 --[[ImGuiCond.FirstUseEver]]) + + -- Main body of the Demo window starts here. + local open, visible = ImGui.Begin("Dear ImGui Demo", begin_p_open, window_flags) + if begin_p_open ~= nil then p_open = open end -- [Port] write back the bool* output + if not visible then + -- Early out if the window is collapsed, as an optimization. + ImGui.End() + return p_open + end + + -- Most framed widgets share a common width settings. Remaining width is used for the label. + -- The width of the frame may be changed with PushItemWidth() or SetNextItemWidth(). + -- - Positive value for absolute size, negative value for right-alignment. + -- - The default value is about GetWindowWidth() * 0.65f. + -- - See 'Demo->Layout->Widgets Width' for details. + -- Here we change the frame width based on how much width we want to give to the label. + local label_width_base = ImGui.GetFontSize() * 12 -- Some amount of width for label, based on font size. + local label_width_max = ImGui.GetContentRegionAvail().x * 0.40 -- ...but always leave some room for framed widgets. + local label_width = ImMin(label_width_base, label_width_max) + ImGui.PushItemWidth(-label_width) -- Right-align: framed items will leave 'label_width' available for the label. + --ImGui.PushItemWidth(ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for framed widgets, leaving 60% width for labels. + --ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for labels, leaving 60% width for framed widgets. + --ImGui.PushItemWidth(ImGui.GetFontSize() * -12) -- e.g. Use XXX width for labels, leaving the rest for framed widgets. + + -- Menu Bar + DemoWindowMenuBar(demo_data) + + ImGui.Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, 19298 --[[IMGUI_VERSION_NUM]]) + ImGui.Spacing() + + if ImGui.CollapsingHeader("Help") then + IMGUI_DEMO_MARKER("Help") + ImGui.SeparatorText("ABOUT THIS DEMO:") + ImGui.BulletText("Sections below are demonstrating many aspects of the library.") + ImGui.BulletText("The \"Examples\" menu above leads to more demo contents.") + ImGui.BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" .. + "and Metrics/Debugger (general purpose Dear ImGui debugging tool).") + ImGui.BulletText("Web demo (w/ source code browser): ") + ImGui.SameLine(0, 0) + ImGui.TextLinkOpenURL("https://pthom.github.io/imgui_explorer") + + ImGui.SeparatorText("PROGRAMMER GUIDE:") + ImGui.BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!") + ImGui.BulletText("See comments in imgui.cpp.") + ImGui.BulletText("See example applications in the examples/ folder.") + ImGui.BulletText("Read the FAQ at ") + ImGui.SameLine(0, 0) + ImGui.TextLinkOpenURL("https://www.dearimgui.com/faq/") + ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.") + ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.") + + ImGui.SeparatorText("USER GUIDE:") + ImGui.ShowUserGuide() + end + + if ImGui.CollapsingHeader("Configuration") then + local io = ImGui.GetIO() + + if ImGui.TreeNode("Configuration##2") then + IMGUI_DEMO_MARKER("Configuration") + ImGui.SeparatorText("General") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", io.ConfigFlags, 1 --[[ImGuiConfigFlags.NavEnableKeyboard]]) + ImGui.SameLine(); HelpMarker("Enable keyboard controls.") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NavEnableGamepad", io.ConfigFlags, 2 --[[ImGuiConfigFlags.NavEnableGamepad]]) + ImGui.SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NoMouse", io.ConfigFlags, 16 --[[ImGuiConfigFlags.NoMouse]]) + ImGui.SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.") + + -- The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: + if bit32.band(io.ConfigFlags, 16 --[[ImGuiConfigFlags.NoMouse]]) ~= 0 then + if math.fmod(ImGui.GetTime(), 0.40) < 0.20 then + ImGui.SameLine() + ImGui.Text("<>") + end + -- Prevent both being checked + if ImGui.IsKeyPressed(524 --[[ImGuiKey.Space]]) or bit32.band(io.ConfigFlags, 64 --[[ImGuiConfigFlags.NoKeyboard]]) ~= 0 then + io.ConfigFlags = bit32.band(io.ConfigFlags, bit32.bnot(16 --[[ImGuiConfigFlags.NoMouse]])) + end + end + + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", io.ConfigFlags, 32 --[[ImGuiConfigFlags.NoMouseCursorChange]]) + ImGui.SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NoKeyboard", io.ConfigFlags, 64 --[[ImGuiConfigFlags.NoKeyboard]]) + ImGui.SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.") + + _, io.ConfigInputTrickleEventQueue = ImGui.Checkbox("io.ConfigInputTrickleEventQueue", io.ConfigInputTrickleEventQueue) + ImGui.SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.") + _, io.MouseDrawCursor = ImGui.Checkbox("io.MouseDrawCursor", io.MouseDrawCursor) + ImGui.SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).") + + ImGui.SeparatorText("Keyboard/Gamepad Navigation") + _, io.ConfigNavSwapGamepadButtons = ImGui.Checkbox("io.ConfigNavSwapGamepadButtons", io.ConfigNavSwapGamepadButtons) + _, io.ConfigNavMoveSetMousePos = ImGui.Checkbox("io.ConfigNavMoveSetMousePos", io.ConfigNavMoveSetMousePos) + ImGui.SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult") + _, io.ConfigNavCaptureKeyboard = ImGui.Checkbox("io.ConfigNavCaptureKeyboard", io.ConfigNavCaptureKeyboard) + _, io.ConfigNavEscapeClearFocusItem = ImGui.Checkbox("io.ConfigNavEscapeClearFocusItem", io.ConfigNavEscapeClearFocusItem) + ImGui.SameLine(); HelpMarker("Pressing Escape clears focused item.") + _, io.ConfigNavEscapeClearFocusWindow = ImGui.Checkbox("io.ConfigNavEscapeClearFocusWindow", io.ConfigNavEscapeClearFocusWindow) + ImGui.SameLine(); HelpMarker("Pressing Escape clears focused window.") + _, io.ConfigNavCursorVisibleAuto = ImGui.Checkbox("io.ConfigNavCursorVisibleAuto", io.ConfigNavCursorVisibleAuto) + ImGui.SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.") + _, io.ConfigNavCursorVisibleAlways = ImGui.Checkbox("io.ConfigNavCursorVisibleAlways", io.ConfigNavCursorVisibleAlways) + ImGui.SameLine(); HelpMarker("Navigation cursor is always visible.") + + ImGui.SeparatorText("Docking") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: DockingEnable", io.ConfigFlags, 128 --[[ImGuiConfigFlags.DockingEnable]]) + ImGui.SameLine() + if io.ConfigDockingWithShift then + HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") + else + HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") + end + if bit32.band(io.ConfigFlags, 128 --[[ImGuiConfigFlags.DockingEnable]]) ~= 0 then + ImGui.Indent() + _, io.ConfigDockingNoSplit = ImGui.Checkbox("io.ConfigDockingNoSplit", io.ConfigDockingNoSplit) + ImGui.SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.") + _, io.ConfigDockingNoDockingOver = ImGui.Checkbox("io.ConfigDockingNoDockingOver", io.ConfigDockingNoDockingOver) + ImGui.SameLine(); HelpMarker("Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows.") + _, io.ConfigDockingWithShift = ImGui.Checkbox("io.ConfigDockingWithShift", io.ConfigDockingWithShift) + ImGui.SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)") + _, io.ConfigDockingAlwaysTabBar = ImGui.Checkbox("io.ConfigDockingAlwaysTabBar", io.ConfigDockingAlwaysTabBar) + ImGui.SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.") + _, io.ConfigDockingTransparentPayload = ImGui.Checkbox("io.ConfigDockingTransparentPayload", io.ConfigDockingTransparentPayload) + ImGui.SameLine(); HelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.") + ImGui.Unindent() + end + + ImGui.SeparatorText("Multi-viewports") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: ViewportsEnable", io.ConfigFlags, 1024 --[[ImGuiConfigFlags.ViewportsEnable]]) + ImGui.SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.") + if bit32.band(io.ConfigFlags, 1024 --[[ImGuiConfigFlags.ViewportsEnable]]) ~= 0 then + ImGui.Indent() + _, io.ConfigViewportsNoAutoMerge = ImGui.Checkbox("io.ConfigViewportsNoAutoMerge", io.ConfigViewportsNoAutoMerge) + ImGui.SameLine(); HelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.") + _, io.ConfigViewportsNoTaskBarIcon = ImGui.Checkbox("io.ConfigViewportsNoTaskBarIcon", io.ConfigViewportsNoTaskBarIcon) + ImGui.SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)") + _, io.ConfigViewportsNoDecoration = ImGui.Checkbox("io.ConfigViewportsNoDecoration", io.ConfigViewportsNoDecoration) + ImGui.SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)") + _, io.ConfigViewportsNoDefaultParent = ImGui.Checkbox("io.ConfigViewportsNoDefaultParent", io.ConfigViewportsNoDefaultParent) + ImGui.SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)") + _, io.ConfigViewportsPlatformFocusSetsImGuiFocus = ImGui.Checkbox("io.ConfigViewportsPlatformFocusSetsImGuiFocus", io.ConfigViewportsPlatformFocusSetsImGuiFocus) + ImGui.SameLine(); HelpMarker("When a platform window is focused (e.g. using Alt+Tab, clicking Platform Title Bar), apply corresponding focus on imgui windows (may clear focus/active id from imgui windows location in other platform windows). In principle this is better enabled but we provide an opt-out, because some Linux window managers tend to eagerly focus windows (e.g. on mouse hover, or even a simple window pos/size change).") + ImGui.Unindent() + end + + --ImGui.SeparatorText("DPI/Scaling") + --_, io.ConfigDpiScaleFonts = ImGui.Checkbox("io.ConfigDpiScaleFonts", io.ConfigDpiScaleFonts) + --ImGui.SameLine(); HelpMarker("Experimental: Automatically update style.FontScaleDpi when Monitor DPI changes. This will scale fonts but NOT style sizes/padding for now.") + --_, io.ConfigDpiScaleViewports = ImGui.Checkbox("io.ConfigDpiScaleViewports", io.ConfigDpiScaleViewports) + --ImGui.SameLine(); HelpMarker("Experimental: Scale Dear ImGui and Platform Windows when Monitor DPI changes.") + + ImGui.SeparatorText("Windows") + _, io.ConfigWindowsResizeFromEdges = ImGui.Checkbox("io.ConfigWindowsResizeFromEdges", io.ConfigWindowsResizeFromEdges) + ImGui.SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.") + _, io.ConfigWindowsMoveFromTitleBarOnly = ImGui.Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", io.ConfigWindowsMoveFromTitleBarOnly) + _, io.ConfigWindowsCopyContentsWithCtrlC = ImGui.Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", io.ConfigWindowsCopyContentsWithCtrlC) -- [EXPERIMENTAL] + ImGui.SameLine(); HelpMarker("*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.") + _, io.ConfigScrollbarScrollByPage = ImGui.Checkbox("io.ConfigScrollbarScrollByPage", io.ConfigScrollbarScrollByPage) + ImGui.SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.") + + ImGui.SeparatorText("Widgets") + _, io.ConfigInputTextCursorBlink = ImGui.Checkbox("io.ConfigInputTextCursorBlink", io.ConfigInputTextCursorBlink) + ImGui.SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).") + _, io.ConfigInputTextEnterKeepActive = ImGui.Checkbox("io.ConfigInputTextEnterKeepActive", io.ConfigInputTextEnterKeepActive) + ImGui.SameLine(); HelpMarker("Pressing Enter will reactivate item and select all text (single-line only).") + _, io.ConfigDragClickToInputText = ImGui.Checkbox("io.ConfigDragClickToInputText", io.ConfigDragClickToInputText) + ImGui.SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).") + _, io.ConfigMacOSXBehaviors = ImGui.Checkbox("io.ConfigMacOSXBehaviors", io.ConfigMacOSXBehaviors) + ImGui.SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.") + ImGui.Text("Also see Style->Rendering for rendering options.") + + ImGui.SeparatorText("Settings") + _, io.ConfigIniSettingsSaveLastUsedDate = ImGui.Checkbox("io.ConfigIniSettingsSaveLastUsedDate", io.ConfigIniSettingsSaveLastUsedDate) + + -- Also read: https://github.com/ocornut/imgui/wiki/Error-Handling + ImGui.SeparatorText("Error Handling") + + _, io.ConfigErrorRecovery = ImGui.Checkbox("io.ConfigErrorRecovery", io.ConfigErrorRecovery) + ImGui.SameLine(); HelpMarker( + "Options to configure how we handle recoverable errors.\n" .. + "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n" .. + "- You not are not supposed to rely on it in the course of a normal application run.\n" .. + "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n" .. + "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call! " .. + "Otherwise it would severely hinder your ability to catch and correct mistakes!") + _, io.ConfigErrorRecoveryEnableAssert = ImGui.Checkbox("io.ConfigErrorRecoveryEnableAssert", io.ConfigErrorRecoveryEnableAssert) + _, io.ConfigErrorRecoveryEnableDebugLog = ImGui.Checkbox("io.ConfigErrorRecoveryEnableDebugLog", io.ConfigErrorRecoveryEnableDebugLog) + _, io.ConfigErrorRecoveryEnableTooltip = ImGui.Checkbox("io.ConfigErrorRecoveryEnableTooltip", io.ConfigErrorRecoveryEnableTooltip) + if not io.ConfigErrorRecoveryEnableAssert and not io.ConfigErrorRecoveryEnableDebugLog and not io.ConfigErrorRecoveryEnableTooltip then + io.ConfigErrorRecoveryEnableAssert = true; io.ConfigErrorRecoveryEnableDebugLog = true; io.ConfigErrorRecoveryEnableTooltip = true + end + + -- Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools + ImGui.SeparatorText("Debug") + _, io.ConfigDebugIsDebuggerPresent = ImGui.Checkbox("io.ConfigDebugIsDebuggerPresent", io.ConfigDebugIsDebuggerPresent) + ImGui.SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.") + _, io.ConfigDebugHighlightIdConflicts = ImGui.Checkbox("io.ConfigDebugHighlightIdConflicts", io.ConfigDebugHighlightIdConflicts) + ImGui.SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.") + ImGui.BeginDisabled() + _, io.ConfigDebugBeginReturnValueOnce = ImGui.Checkbox("io.ConfigDebugBeginReturnValueOnce", io.ConfigDebugBeginReturnValueOnce) + ImGui.EndDisabled() + ImGui.SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.") + _, io.ConfigDebugBeginReturnValueLoop = ImGui.Checkbox("io.ConfigDebugBeginReturnValueLoop", io.ConfigDebugBeginReturnValueLoop) + ImGui.SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.") + _, io.ConfigDebugIgnoreFocusLoss = ImGui.Checkbox("io.ConfigDebugIgnoreFocusLoss", io.ConfigDebugIgnoreFocusLoss) + ImGui.SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.") + _, io.ConfigDebugDrawListDefaultsToStrokeLegacy = ImGui.Checkbox("io.ConfigDebugDrawListDefaultsToStrokeLegacy", io.ConfigDebugDrawListDefaultsToStrokeLegacy) + ImGui.SameLine(); HelpMarker("Option to default all ImDrawList to ImDrawFlags_StrokeLegacy mode, mimicking pre-1.93.0 rendering.") + _, io.ConfigDebugIniSettings = ImGui.Checkbox("io.ConfigDebugIniSettings", io.ConfigDebugIniSettings) + ImGui.SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).") + + ImGui.TreePop() + ImGui.Spacing() + end + + if ImGui.TreeNode("Backend Flags") then + IMGUI_DEMO_MARKER("Configuration/Backend Flags") + HelpMarker( + "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" .. + "Here we expose them as read-only fields to avoid breaking interactions with your backend.") + + -- Make a local copy to avoid modifying actual backend flags. + -- FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright? + ImGui.BeginDisabled() + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasGamepad", io.BackendFlags, 1 --[[ImGuiBackendFlags.HasGamepad]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseCursors", io.BackendFlags, 2 --[[ImGuiBackendFlags.HasMouseCursors]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasSetMousePos", io.BackendFlags, 4 --[[ImGuiBackendFlags.HasSetMousePos]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: PlatformHasViewports", io.BackendFlags, 2048 --[[ImGuiBackendFlags.PlatformHasViewports]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",io.BackendFlags, 4096 --[[ImGuiBackendFlags.HasMouseHoveredViewport]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasParentViewport", io.BackendFlags, 8192 --[[ImGuiBackendFlags.HasParentViewport]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", io.BackendFlags, 8 --[[ImGuiBackendFlags.RendererHasVtxOffset]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasTextures", io.BackendFlags, 16 --[[ImGuiBackendFlags.RendererHasTextures]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasViewports", io.BackendFlags, 1024 --[[ImGuiBackendFlags.RendererHasViewports]]) + ImGui.EndDisabled() + + ImGui.TreePop() + ImGui.Spacing() + end + + if ImGui.TreeNode("Style, Fonts") then + IMGUI_DEMO_MARKER("Configuration/Style, Fonts") + _, demo_data.ShowStyleEditor = ImGui.Checkbox("Style Editor", demo_data.ShowStyleEditor) + ImGui.SameLine() + HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.") + ImGui.TreePop() + ImGui.Spacing() + end + + if ImGui.TreeNode("Capture/Logging") then + IMGUI_DEMO_MARKER("Configuration/Capture, Logging") + HelpMarker( + "The logging API redirects all text output so you can easily capture the content of " .. + "a window or a block. Tree nodes can be automatically expanded.\n" .. + "Try opening any of the contents below in this window and then click one of the \"Log To\" button.") + ImGui.LogButtons() + + HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.") + if ImGui.Button("Copy \"Hello, world!\" to clipboard") then + ImGui.LogToClipboard() + ImGui.LogText("Hello, world!") + ImGui.LogFinish() + end + ImGui.TreePop() + end + end + + if ImGui.CollapsingHeader("Window options") then + IMGUI_DEMO_MARKER("Window options") + if ImGui.BeginTable("split", 3) then + ImGui.TableNextColumn(); _, s.no_titlebar = ImGui.Checkbox("No titlebar", s.no_titlebar) + ImGui.TableNextColumn(); _, s.no_scrollbar = ImGui.Checkbox("No scrollbar", s.no_scrollbar) + ImGui.TableNextColumn(); _, s.no_menu = ImGui.Checkbox("No menu", s.no_menu) + ImGui.TableNextColumn(); _, s.no_move = ImGui.Checkbox("No move", s.no_move) + ImGui.TableNextColumn(); _, s.no_resize = ImGui.Checkbox("No resize", s.no_resize) + ImGui.TableNextColumn(); _, s.no_collapse = ImGui.Checkbox("No collapse", s.no_collapse) + ImGui.TableNextColumn(); _, s.no_close = ImGui.Checkbox("No close", s.no_close) + ImGui.TableNextColumn(); _, s.no_nav = ImGui.Checkbox("No nav", s.no_nav) + ImGui.TableNextColumn(); _, s.no_background = ImGui.Checkbox("No background", s.no_background) + ImGui.TableNextColumn(); _, s.no_bring_to_front = ImGui.Checkbox("No bring to front", s.no_bring_to_front) + ImGui.TableNextColumn(); _, s.no_docking = ImGui.Checkbox("No docking", s.no_docking) + ImGui.TableNextColumn(); _, s.unsaved_document = ImGui.Checkbox("Unsaved document", s.unsaved_document) + ImGui.EndTable() + end + end + + -- All demo contents + DemoWindowWidgets(demo_data) + DemoWindowLayout() + DemoWindowPopups() + DemoWindowTables() + DemoWindowInputs() + + -- End of ShowDemoWindow() + ImGui.PopItemWidth() + ImGui.End() + return p_open +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowMenuBar() +------------------------------------------------------------------------------- + +function DemoWindowMenuBar(demo_data) + if ImGui.BeginMenuBar() then + if ImGui.BeginMenu("Menu") then + IMGUI_DEMO_MARKER("Menu/File") + ShowExampleMenuFile() + ImGui.EndMenu() + end + if ImGui.BeginMenu("Examples") then + IMGUI_DEMO_MARKER("Menu/Examples") + _, demo_data.ShowMainMenuBar = ImGui.MenuItem("Main menu bar", nil, demo_data.ShowMainMenuBar) + + ImGui.SeparatorText("Mini apps") + _, demo_data.ShowAppAssetsBrowser = ImGui.MenuItem("Assets Browser", nil, demo_data.ShowAppAssetsBrowser) + _, demo_data.ShowAppConsole = ImGui.MenuItem("Console", nil, demo_data.ShowAppConsole) + _, demo_data.ShowAppCustomRendering = ImGui.MenuItem("Custom rendering", nil, demo_data.ShowAppCustomRendering) + _, demo_data.ShowAppDocuments = ImGui.MenuItem("Documents", nil, demo_data.ShowAppDocuments) + _, demo_data.ShowAppDockSpace = ImGui.MenuItem("Dockspace", nil, demo_data.ShowAppDockSpace) + _, demo_data.ShowAppImageViewer = ImGui.MenuItem("Image Viewer", nil, demo_data.ShowAppImageViewer) + _, demo_data.ShowAppLog = ImGui.MenuItem("Log", nil, demo_data.ShowAppLog) + _, demo_data.ShowAppPropertyEditor = ImGui.MenuItem("Property editor", nil, demo_data.ShowAppPropertyEditor) + _, demo_data.ShowAppLayout = ImGui.MenuItem("Simple layout", nil, demo_data.ShowAppLayout) + _, demo_data.ShowAppSimpleOverlay = ImGui.MenuItem("Simple overlay", nil, demo_data.ShowAppSimpleOverlay) + + ImGui.SeparatorText("Concepts") + _, demo_data.ShowAppAutoResize = ImGui.MenuItem("Auto-resizing window", nil, demo_data.ShowAppAutoResize) + _, demo_data.ShowAppConstrainedResize = ImGui.MenuItem("Constrained-resizing window", nil, demo_data.ShowAppConstrainedResize) + _, demo_data.ShowAppFullscreen = ImGui.MenuItem("Fullscreen window", nil, demo_data.ShowAppFullscreen) + _, demo_data.ShowAppLongText = ImGui.MenuItem("Long text display", nil, demo_data.ShowAppLongText) + _, demo_data.ShowAppWindowTitles = ImGui.MenuItem("Manipulating window titles", nil, demo_data.ShowAppWindowTitles) + + ImGui.EndMenu() + end + --if ImGui.MenuItem("MenuItem") then end -- You can also use MenuItem() inside a menu bar! + if ImGui.BeginMenu("Tools") then + IMGUI_DEMO_MARKER("Menu/Tools") + local io = ImGui.GetIO() + local has_debug_tools = true -- [Port] IMGUI_DISABLE_DEBUG_TOOLS is never defined here + _, demo_data.ShowMetrics = ImGui.MenuItem("Metrics/Debugger", nil, demo_data.ShowMetrics, has_debug_tools) + if ImGui.BeginMenu("Debug Options") then + ImGui.BeginDisabled(not has_debug_tools) + _, io.ConfigDebugHighlightIdConflicts = ImGui.Checkbox("Highlight ID Conflicts", io.ConfigDebugHighlightIdConflicts) + ImGui.EndDisabled() + _, io.ConfigErrorRecoveryEnableAssert = ImGui.Checkbox("Assert on error recovery", io.ConfigErrorRecoveryEnableAssert) + ImGui.TextDisabled("(see Demo->Configuration for more)") + ImGui.EndMenu() + end + _, demo_data.ShowDebugLog = ImGui.MenuItem("Debug Log", nil, demo_data.ShowDebugLog, has_debug_tools) + _, demo_data.ShowIDStackTool = ImGui.MenuItem("ID Stack Tool", nil, demo_data.ShowIDStackTool, has_debug_tools) + local is_debugger_present = io.ConfigDebugIsDebuggerPresent + local has_item_picker = ImGui.DebugStartItemPicker ~= nil -- [Port] ImGui.DebugStartItemPicker() is not ported yet: menu item disabled until it is + if ImGui.MenuItem("Item Picker", nil, false, has_debug_tools and has_item_picker) then -- and is_debugger_present + ImGui.DebugStartItemPicker() + end + if not is_debugger_present then + ImGui.SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application.") + end + _, demo_data.ShowStyleEditor = ImGui.MenuItem("Style Editor", nil, demo_data.ShowStyleEditor) + _, demo_data.ShowAbout = ImGui.MenuItem("About Dear ImGui", nil, demo_data.ShowAbout) + + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end +end + ------------------------------------------------------------------------------- -- [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) ------------------------------------------------------------------------------- @@ -21712,23 +22117,43 @@ end function ExampleTreeNode() return { -- Tree structure - Name = "", + Name = "", -- [Port] Lua string (upstream char Name[28]), max 27 bytes UID = 0, Parent = nil, - Childs = {}, -- 1-based - IndexInParent = 0, -- 0-based. Maintaining this allows us to implement linear traversal more easily + Childs = {}, -- [Port] plain 1-based Lua array (upstream ImVector): #Childs, Childs[n + 1] + IndexInParent = 0, -- Maintaining this allows us to implement linear traversal more easily (0-based) -- Leaf Data - HasData = false, -- All leaves have data + HasData = false, -- All leaves have data DataMyBool = true, DataMyInt = 128, DataMyVec2 = ImVec2(0.0, 3.141592), } end +-- Simple representation of struct metadata/serialization data. +-- (this is a minimal version of what a typical advanced application may provide) +function ExampleMemberInfo(name, data_type, data_count, offset) + return { + Name = name, -- Member name + DataType = data_type, -- Member type + DataCount = data_count, -- Member count (1 when scalar) + Offset = offset, -- Offset inside parent structure -- [Port] field key in the node table (no offsetof) + } +end + +-- Metadata description of ExampleTreeNode struct. +ExampleTreeNodeMemberInfos = +{ + ExampleMemberInfo("MyName", ImGuiDataType.String, 1, "Name"), + ExampleMemberInfo("MyBool", ImGuiDataType.Bool, 1, "DataMyBool"), + ExampleMemberInfo("MyInt", ImGuiDataType.S32, 1, "DataMyInt"), + ExampleMemberInfo("MyVec2", ImGuiDataType.Float, 2, "DataMyVec2"), +} + function ExampleTree_CreateNode(name, uid, parent) local node = ExampleTreeNode() - node.Name = string.sub(name, 1, 27) + node.Name = string.sub(name, 1, 27) -- [Port] snprintf() into char[28] node.UID = uid node.Parent = parent node.IndexInParent = parent and #parent.Childs or 0 @@ -21738,34 +22163,49 @@ function ExampleTree_CreateNode(name, uid, parent) return node end -function ExampleTree_DestroyNode(node) end -- GC +function ExampleTree_DestroyNode(node) + for _, child_node in ipairs(node.Childs) do + ExampleTree_DestroyNode(child_node) + end + -- [Port] IM_DELETE(node): nothing to do, garbage collected +end + +S.ExampleTree_CreateDemoTree = { + category_names = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" }, +} -- Create example tree data -- (warning: this can allocates MANY MANY more times than other code in all of Dear ImGui + demo combined) -- (a real application managing one million nodes would likely store its tree data differently) function ExampleTree_CreateDemoTree() + local s = S.ExampleTree_CreateDemoTree + -- 20 root nodes -> 211 total nodes, ~261 allocs. -- 1000 root nodes -> ~11K total nodes, ~14K allocs. -- 10000 root nodes -> ~123K total nodes, ~154K allocs. -- 100000 root nodes -> ~1338K total nodes, ~1666K allocs. local ROOT_ITEMS_COUNT = 20 - local category_names = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" } + + local category_names = s.category_names local category_count = #category_names + local name_buf -- [Port] Lua string, truncated to sizeof(ExampleTreeNode::Name) by ExampleTree_CreateNode() local uid = 0 uid = uid + 1 local node_L0 = ExampleTree_CreateNode("", uid, nil) for idx_L0 = 0, ROOT_ITEMS_COUNT - 1 do - local name_buf = string.format("%s %d", category_names[math.floor(idx_L0 / math.floor(ROOT_ITEMS_COUNT / category_count)) + 1], idx_L0 % math.floor(ROOT_ITEMS_COUNT / category_count)) + name_buf = string.format("%s %d", category_names[math.floor(idx_L0 / math.floor(ROOT_ITEMS_COUNT / category_count)) + 1], idx_L0 % math.floor(ROOT_ITEMS_COUNT / category_count)) uid = uid + 1 local node_L1 = ExampleTree_CreateNode(name_buf, uid, node_L0) local number_of_childs = #node_L1.Name for idx_L1 = 0, number_of_childs - 1 do + name_buf = string.format("Child %d", idx_L1) uid = uid + 1 - local node_L2 = ExampleTree_CreateNode(string.format("Child %d", idx_L1), uid, node_L1) + local node_L2 = ExampleTree_CreateNode(name_buf, uid, node_L1) node_L2.HasData = true if idx_L1 == 0 then + name_buf = string.format("Sub-child %d", 0) uid = uid + 1 - local node_L3 = ExampleTree_CreateNode(string.format("Sub-child %d", 0), uid, node_L2) + local node_L3 = ExampleTree_CreateNode(name_buf, uid, node_L2) node_L3.HasData = true end end @@ -21780,13 +22220,13 @@ end function ExampleImageViewerData() return { ImageBgColor = IM_COL32(100, 100, 100, 255), - GridColor = IM_COL32(255, 255, 255, 100), - GridEnabled = true, - ViewReset = true, - ViewOffset = ImVec2(0, 0), -- in image space - Zoom = 10.0, - ZoomMin = 1.0, - ZoomMax = 10000.0, + GridColor = IM_COL32(255, 255, 255, 100), + GridEnabled = true, + ViewReset = true, + ViewOffset = ImVec2(0.0, 0.0), -- in image space + Zoom = 10.0, + ZoomMin = 1.0, + ZoomMax = 10000.0, } end @@ -21822,7 +22262,7 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w -- Handle inputs if ImGui.SetItemKeyOwner(662 --[[ImGuiKey.MouseWheelY]]) then if io.MouseWheel ~= 0.0 then - data.Zoom = DemoClamp(data.Zoom * (1.0 + io.MouseWheel * 0.10), data.ZoomMin, data.ZoomMax) + data.Zoom = ImClamp(data.Zoom * (1.0 + io.MouseWheel * 0.10), data.ZoomMin, data.ZoomMax) end end local zoom = data.Zoom -- (float)(int)ViewZoom; @@ -21832,11 +22272,11 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w end -- Display image - local image_min = ImVec2(); local image_max = ImVec2() - image_min.x = math.floor((canvas_min.x - (data.ViewOffset.x * zoom)) + (canvas_size.x * 0.5)) - image_min.y = math.floor((canvas_min.y - (data.ViewOffset.y * zoom)) + (canvas_size.y * 0.5)) - image_max.x = math.floor(image_min.x + image_w * zoom) - image_max.y = math.floor(image_min.y + image_h * zoom) + local image_min, image_max = ImVec2(), ImVec2() + image_min.x = ImTrunc((canvas_min.x - (data.ViewOffset.x * zoom)) + (canvas_size.x * 0.5)) + image_min.y = ImTrunc((canvas_min.y - (data.ViewOffset.y * zoom)) + (canvas_size.y * 0.5)) + image_max.x = ImTrunc(image_min.x + image_w * zoom) + image_max.y = ImTrunc(image_min.y + image_h * zoom) draw_list:AddRect(ImVec2(canvas_min.x - 1.0, canvas_min.y - 1.0), ImVec2(canvas_max.x + 1.0, canvas_max.y + 1.0), IM_COL32(255, 255, 255, 255)) draw_list:PushClipRect(canvas_min, canvas_max, true) draw_list:AddRectFilled(image_min, image_max, data.ImageBgColor) @@ -21851,10 +22291,10 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w -- Display grid lines for visible pixels if data.GridEnabled and zoom > 6.0 then local step = zoom - for px = math.floor((canvas_min.x - image_min.x) / step), math.floor((canvas_max.x - image_min.x) / step) do + for px = ImTrunc((canvas_min.x - image_min.x) / step), ImTrunc((canvas_max.x - image_min.x) / step) do draw_list:AddLineV(image_min.x + px * step, canvas_min.y, canvas_max.y, data.GridColor, 1.0) end - for py = math.floor((canvas_min.y - image_min.y) / step), math.floor((canvas_max.y - image_min.y) / step) do + for py = ImTrunc((canvas_min.y - image_min.y) / step), ImTrunc((canvas_max.y - image_min.y) / step) do draw_list:AddLineH(canvas_min.x, canvas_max.x, image_min.y + py * step, data.GridColor, 1.0) end end @@ -21862,547 +22302,2834 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w end ------------------------------------------------------------------------------- --- [SECTION] Demo Window / ShowDemoWindow() +-- [SECTION] DemoWindowWidgetsBasic() ------------------------------------------------------------------------------- --- Stored data -local demo_data = ImGuiDemoWindowData() +S.DemoWindowWidgetsBasic = { + clicked = 0, + check = true, + e = 0, + counter = 0, + inputs = { + str0 = ImGui.NewTextBuffer("Hello, world!", 128), + str1 = ImGui.NewTextBuffer("", 128), + i0 = 123, + f0 = 0.001, + d0 = 999999.00000001, + f1 = 1.e10, + vec4a = { 0.10, 0.20, 0.30, 0.44 }, + }, + drags = { i1 = 50, i2 = 42, i3 = 128, f1 = 1.00, f2 = 0.0067 }, + sliders = { i1 = 0, f1 = 0.123, f2 = 0.0, angle = 0.0, elem = 0 }, + pickers = { col1 = { 1.0, 0.0, 0.2 }, col2 = { 0.4, 0.7, 0.0, 0.5 } }, + combo = { item_current = 0 }, + listbox = { item_current = 1 }, +} -local no_titlebar = false -local no_scrollbar = false -local no_menu = false -local no_move = false -local no_resize = false -local no_collapse = false -local no_close = false -local no_nav = false -local no_background = false -local no_bring_to_front = false -local no_docking = false -local unsaved_document = false - ---- Shows an example app: `if X then X.open = X(open) end`. Example apps return the new p_open. -local function RunApp(fn, key, ...) - if fn then - demo_data[key] = fn(demo_data[key], ...) - if demo_data[key] == nil then demo_data[key] = false end - else - demo_data[key] = false - end -end - -local function DemoWindowMenuBar(data) - if ImGui.BeginMenuBar() then - if ImGui.BeginMenu("Menu") then - IMGUI_DEMO_MARKER("Menu/File") - ShowExampleMenuFile() - ImGui.EndMenu() - end - if ImGui.BeginMenu("Examples") then - IMGUI_DEMO_MARKER("Menu/Examples") - _, data.ShowMainMenuBar = ImGui.MenuItem("Main menu bar", nil, data.ShowMainMenuBar) - - ImGui.SeparatorText("Mini apps") - _, data.ShowAppAssetsBrowser = ImGui.MenuItem("Assets Browser", nil, data.ShowAppAssetsBrowser) - _, data.ShowAppConsole = ImGui.MenuItem("Console", nil, data.ShowAppConsole) - _, data.ShowAppCustomRendering = ImGui.MenuItem("Custom rendering", nil, data.ShowAppCustomRendering) - _, data.ShowAppDocuments = ImGui.MenuItem("Documents", nil, data.ShowAppDocuments) - _, data.ShowAppDockSpace = ImGui.MenuItem("Dockspace", nil, data.ShowAppDockSpace) - _, data.ShowAppImageViewer = ImGui.MenuItem("Image Viewer", nil, data.ShowAppImageViewer) - _, data.ShowAppLog = ImGui.MenuItem("Log", nil, data.ShowAppLog) - _, data.ShowAppPropertyEditor = ImGui.MenuItem("Property editor", nil, data.ShowAppPropertyEditor) - _, data.ShowAppLayout = ImGui.MenuItem("Simple layout", nil, data.ShowAppLayout) - _, data.ShowAppSimpleOverlay = ImGui.MenuItem("Simple overlay", nil, data.ShowAppSimpleOverlay) - - ImGui.SeparatorText("Concepts") - _, data.ShowAppAutoResize = ImGui.MenuItem("Auto-resizing window", nil, data.ShowAppAutoResize) - _, data.ShowAppConstrainedResize = ImGui.MenuItem("Constrained-resizing window", nil, data.ShowAppConstrainedResize) - _, data.ShowAppFullscreen = ImGui.MenuItem("Fullscreen window", nil, data.ShowAppFullscreen) - _, data.ShowAppLongText = ImGui.MenuItem("Long text display", nil, data.ShowAppLongText) - _, data.ShowAppWindowTitles = ImGui.MenuItem("Manipulating window titles", nil, data.ShowAppWindowTitles) - - ImGui.EndMenu() - end - -- if ImGui.MenuItem("MenuItem") then end -- You can also use MenuItem() inside a menu bar! - if ImGui.BeginMenu("Tools") then - IMGUI_DEMO_MARKER("Menu/Tools") - local io = ImGui.GetIO() - local has_debug_tools = not IMGUI_DISABLE_DEBUG_TOOLS - _, data.ShowMetrics = ImGui.MenuItem("Metrics/Debugger", nil, data.ShowMetrics, has_debug_tools and ImGui.ShowMetricsWindow ~= nil) - if ImGui.BeginMenu("Debug Options") then - ImGui.BeginDisabled(not has_debug_tools) - _, io.ConfigDebugHighlightIdConflicts = ImGui.Checkbox("Highlight ID Conflicts", io.ConfigDebugHighlightIdConflicts) - ImGui.EndDisabled() - _, io.ConfigErrorRecoveryEnableAssert = ImGui.Checkbox("Assert on error recovery", io.ConfigErrorRecoveryEnableAssert) - ImGui.TextDisabled("(see Demo->Configuration for more)") - ImGui.EndMenu() - end - _, data.ShowDebugLog = ImGui.MenuItem("Debug Log", nil, data.ShowDebugLog, has_debug_tools and ImGui.ShowDebugLogWindow ~= nil) - _, data.ShowIDStackTool = ImGui.MenuItem("ID Stack Tool", nil, data.ShowIDStackTool, has_debug_tools and ImGui.ShowIDStackToolWindow ~= nil) - local is_debugger_present = io.ConfigDebugIsDebuggerPresent - if ImGui.MenuItem("Item Picker", nil, false, has_debug_tools and ImGui.DebugStartItemPicker ~= nil) then -- and is_debugger_present - ImGui.DebugStartItemPicker() - end - if not is_debugger_present then - ImGui.SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application.") - end - _, data.ShowStyleEditor = ImGui.MenuItem("Style Editor", nil, data.ShowStyleEditor) - _, data.ShowAbout = ImGui.MenuItem("About Dear ImGui", nil, data.ShowAbout) - - ImGui.EndMenu() - end - ImGui.EndMenuBar() - end -end - ---- Configuration header contents (split from ShowDemoWindow to keep the function small) -local function DemoWindowConfiguration(io) - local F = ImGuiConfigFlags - local function CF(label, flag) - local pressed - pressed, io.ConfigFlags = ImGui.CheckboxFlags(label, io.ConfigFlags, flag) - return pressed - end - local function CB(label, field) - local pressed - pressed, io[field] = ImGui.Checkbox(label, io[field]) - return pressed - end - local function HM(desc) ImGui.SameLine(); HelpMarker(desc) end - - if ImGui.TreeNode("Configuration##2") then - IMGUI_DEMO_MARKER("Configuration") +function DemoWindowWidgetsBasic() + local _ + if ImGui.TreeNode("Basic") then + local s = S.DemoWindowWidgetsBasic + IMGUI_DEMO_MARKER("Widgets/Basic") ImGui.SeparatorText("General") - CF("io.ConfigFlags: NavEnableKeyboard", F.NavEnableKeyboard) - HM("Enable keyboard controls.") - CF("io.ConfigFlags: NavEnableGamepad", F.NavEnableGamepad) - HM("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.") - CF("io.ConfigFlags: NoMouse", F.NoMouse) - HM("Instruct dear imgui to disable mouse inputs and interactions.") - -- The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: - if DemoHas(io.ConfigFlags, F.NoMouse) then - if (ImGui.GetTime() % 0.40) < 0.20 then + IMGUI_DEMO_MARKER("Widgets/Basic/Button") + if ImGui.Button("Button") then + s.clicked = s.clicked + 1 + end + if bit32.band(s.clicked, 1) ~= 0 then + ImGui.SameLine() + ImGui.Text("Thanks for clicking me!") + end + + IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox") + _, s.check = ImGui.Checkbox("checkbox", s.check) + + IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton") + _, s.e = ImGui.RadioButton("radio a", s.e, 0); ImGui.SameLine() + _, s.e = ImGui.RadioButton("radio b", s.e, 1); ImGui.SameLine() + _, s.e = ImGui.RadioButton("radio c", s.e, 2) + + ImGui.AlignTextToFramePadding() + ImGui.TextLinkOpenURL("Hyperlink", "https://github.com/ocornut/imgui/wiki/Error-Handling") + + -- Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)") + for i = 0, 6 do + if i > 0 then ImGui.SameLine() - ImGui.Text("<>") - end - -- Prevent both being checked - if ImGui.IsKeyPressed(524 --[[ImGuiKey.Space]]) or DemoHas(io.ConfigFlags, F.NoKeyboard) then - io.ConfigFlags = bit32.band(io.ConfigFlags, bit32.bnot(F.NoMouse)) end + ImGui.PushID(i) + ImGui.PushStyleColor(22 --[[ImGuiCol.Button]], ImColor.HSV(i / 7.0, 0.6, 0.6).Value) + ImGui.PushStyleColor(23 --[[ImGuiCol.ButtonHovered]], ImColor.HSV(i / 7.0, 0.7, 0.7).Value) + ImGui.PushStyleColor(24 --[[ImGuiCol.ButtonActive]], ImColor.HSV(i / 7.0, 0.8, 0.8).Value) + ImGui.Button("Click") + ImGui.PopStyleColor(3) + ImGui.PopID() end - CF("io.ConfigFlags: NoMouseCursorChange", F.NoMouseCursorChange) - HM("Instruct backend to not alter mouse cursor shape and visibility.") - CF("io.ConfigFlags: NoKeyboard", F.NoKeyboard) - HM("Instruct dear imgui to disable keyboard inputs and interactions.") - - CB("io.ConfigInputTrickleEventQueue", "ConfigInputTrickleEventQueue") - HM("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.") - CB("io.MouseDrawCursor", "MouseDrawCursor") - HM("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).") - - ImGui.SeparatorText("Keyboard/Gamepad Navigation") - CB("io.ConfigNavSwapGamepadButtons", "ConfigNavSwapGamepadButtons") - CB("io.ConfigNavMoveSetMousePos", "ConfigNavMoveSetMousePos") - HM("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult") - CB("io.ConfigNavCaptureKeyboard", "ConfigNavCaptureKeyboard") - CB("io.ConfigNavEscapeClearFocusItem", "ConfigNavEscapeClearFocusItem") - HM("Pressing Escape clears focused item.") - CB("io.ConfigNavEscapeClearFocusWindow", "ConfigNavEscapeClearFocusWindow") - HM("Pressing Escape clears focused window.") - CB("io.ConfigNavCursorVisibleAuto", "ConfigNavCursorVisibleAuto") - HM("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.") - CB("io.ConfigNavCursorVisibleAlways", "ConfigNavCursorVisibleAlways") - HM("Navigation cursor is always visible.") - - ImGui.SeparatorText("Docking") - CF("io.ConfigFlags: DockingEnable", F.DockingEnable) + -- Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements + -- (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) + -- See 'Demo->Layout->Text Baseline Alignment' for details. + ImGui.AlignTextToFramePadding() + ImGui.Text("Hold to repeat:") ImGui.SameLine() - if io.ConfigDockingWithShift then - HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") - else - HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") - end - if DemoHas(io.ConfigFlags, F.DockingEnable) then - ImGui.Indent() - CB("io.ConfigDockingNoSplit", "ConfigDockingNoSplit") - HM("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.") - CB("io.ConfigDockingNoDockingOver", "ConfigDockingNoDockingOver") - HM("Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows.") - CB("io.ConfigDockingWithShift", "ConfigDockingWithShift") - HM("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)") - CB("io.ConfigDockingAlwaysTabBar", "ConfigDockingAlwaysTabBar") - HM("Create a docking node and tab-bar on single floating windows.") - CB("io.ConfigDockingTransparentPayload", "ConfigDockingTransparentPayload") - HM("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.") - ImGui.Unindent() + + -- Arrow buttons with Repeater + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)") + local spacing = ImGui.GetStyle().ItemInnerSpacing.x + ImGui.PushItemFlag(8 --[[ImGuiItemFlags.ButtonRepeat]], true) + if ImGui.ArrowButton("##left", 0 --[[ImGuiDir.Left]]) then s.counter = s.counter - 1 end + ImGui.SameLine(0.0, spacing) + if ImGui.ArrowButton("##right", 1 --[[ImGuiDir.Right]]) then s.counter = s.counter + 1 end + ImGui.PopItemFlag() + ImGui.SameLine() + ImGui.Text("%d", s.counter) + + ImGui.Button("Tooltip") + ImGui.SetItemTooltip("I am a tooltip") + + ImGui.LabelText("label", "Value") + + ImGui.SeparatorText("Inputs") + + do + local s = S.DemoWindowWidgetsBasic.inputs + -- If you want to use InputText() with std::string or any custom dynamic string type: + -- - For std::string: use the wrapper in misc/cpp/imgui_stdlib.h/.cpp + -- - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize. + IMGUI_DEMO_MARKER("Widgets/Basic/InputText") + ImGui.InputText("input text", s.str0, 128) + ImGui.SameLine(); HelpMarker( + "USER:\n" .. + "Hold Shift or use mouse to select text.\n" .. + "Ctrl+Left/Right to word jump.\n" .. + "Ctrl+A or Double-Click to select all.\n" .. + "Ctrl+X,Ctrl+C,Ctrl+V for clipboard.\n" .. + "Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.\n" .. + "Escape to revert.\n\n" .. + "PROGRAMMER:\n" .. + "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " .. + "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " .. + "in imgui_demo.cpp).") + + ImGui.InputTextWithHint("input text (w/ hint)", "enter text here", s.str1, 128) + + IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat") + s.i0 = ImGui.InputInt("input int", s.i0) + + s.f0 = ImGui.InputFloat("input float", s.f0, 0.01, 1.0, "%.3f") + + s.d0 = ImGui.InputDouble("input double", s.d0, 0.01, 1.0, "%.8f") + + s.f1 = ImGui.InputFloat("input scientific", s.f1, 0.0, 0.0, "%e") + ImGui.SameLine(); HelpMarker( + "You can input value using the scientific notation,\n" .. + " e.g. \"1e+8\" becomes \"100000000\".") + + ImGui.InputFloat3("input float3", s.vec4a) end - ImGui.SeparatorText("Multi-viewports") - CF("io.ConfigFlags: ViewportsEnable", F.ViewportsEnable) - HM("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.") - if DemoHas(io.ConfigFlags, F.ViewportsEnable) then - ImGui.Indent() - DemoNotSupported() - ImGui.Unindent() + ImGui.SeparatorText("Drags") + + do + local s = S.DemoWindowWidgetsBasic.drags + IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat") + s.i1 = ImGui.DragInt("drag int", s.i1, 1) + ImGui.SameLine(); HelpMarker( + "Click and drag to edit value.\n" .. + "Hold Shift/Alt for faster/slower edit.\n" .. + "Double-Click or Ctrl+Click to input value.") + s.i2 = ImGui.DragInt("drag int 0..100", s.i2, 1, 0, 100, "%d%%", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + s.i3 = ImGui.DragInt("drag int wrap 100..200", s.i3, 1, 100, 200, "%d", 256 --[[ImGuiSliderFlags.WrapAround]]) + + s.f1 = ImGui.DragFloat("drag float", s.f1, 0.005) + s.f2 = ImGui.DragFloat("drag small float", s.f2, 0.0001, 0.0, 0.0, "%.06f ns") + --ImGui.DragFloat("drag wrap -1..1", f3, 0.005, -1.0, 1.0, nil, ImGuiSliderFlags.WrapAround) end - -- ImGui.SeparatorText("DPI/Scaling") - -- CB("io.ConfigDpiScaleFonts", "ConfigDpiScaleFonts") - -- HM("Experimental: Automatically update style.FontScaleDpi when Monitor DPI changes. This will scale fonts but NOT style sizes/padding for now.") - -- CB("io.ConfigDpiScaleViewports", "ConfigDpiScaleViewports") - -- HM("Experimental: Scale Dear ImGui and Platform Windows when Monitor DPI changes.") + ImGui.SeparatorText("Sliders") - ImGui.SeparatorText("Windows") - CB("io.ConfigWindowsResizeFromEdges", "ConfigWindowsResizeFromEdges") - HM("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.") - CB("io.ConfigWindowsMoveFromTitleBarOnly", "ConfigWindowsMoveFromTitleBarOnly") - CB("io.ConfigWindowsCopyContentsWithCtrlC", "ConfigWindowsCopyContentsWithCtrlC") -- [EXPERIMENTAL] - HM("*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.") - CB("io.ConfigScrollbarScrollByPage", "ConfigScrollbarScrollByPage") - HM("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.") + do + local s = S.DemoWindowWidgetsBasic.sliders + IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat") + s.i1 = ImGui.SliderInt("slider int", s.i1, -1, 3) + ImGui.SameLine(); HelpMarker("Ctrl+Click to input value.") - ImGui.SeparatorText("Widgets") - CB("io.ConfigInputTextCursorBlink", "ConfigInputTextCursorBlink") - HM("Enable blinking cursor (optional as some users consider it to be distracting).") - CB("io.ConfigInputTextEnterKeepActive", "ConfigInputTextEnterKeepActive") - HM("Pressing Enter will reactivate item and select all text (single-line only).") - CB("io.ConfigDragClickToInputText", "ConfigDragClickToInputText") - HM("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).") - CB("io.ConfigMacOSXBehaviors", "ConfigMacOSXBehaviors") - HM("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.") - ImGui.Text("Also see Style->Rendering for rendering options.") + s.f1 = ImGui.SliderFloat("slider float", s.f1, 0.0, 1.0, "ratio = %.3f") + s.f2 = ImGui.SliderFloat("slider float (log)", s.f2, -10.0, 10.0, "%.4f", 32 --[[ImGuiSliderFlags.Logarithmic]]) - ImGui.SeparatorText("Settings") - CB("io.ConfigIniSettingsSaveLastUsedDate", "ConfigIniSettingsSaveLastUsedDate") + IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle") + s.angle = ImGui.SliderAngle("slider angle", s.angle) - -- Also read: https://github.com/ocornut/imgui/wiki/Error-Handling - ImGui.SeparatorText("Error Handling") - - CB("io.ConfigErrorRecovery", "ConfigErrorRecovery") - HM( - "Options to configure how we handle recoverable errors.\n" .. - "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n" .. - "- You not are not supposed to rely on it in the course of a normal application run.\n" .. - "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n" .. - "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call! " .. - "Otherwise it would severely hinder your ability to catch and correct mistakes!") - CB("io.ConfigErrorRecoveryEnableAssert", "ConfigErrorRecoveryEnableAssert") - CB("io.ConfigErrorRecoveryEnableDebugLog", "ConfigErrorRecoveryEnableDebugLog") - CB("io.ConfigErrorRecoveryEnableTooltip", "ConfigErrorRecoveryEnableTooltip") - if not io.ConfigErrorRecoveryEnableAssert and not io.ConfigErrorRecoveryEnableDebugLog and not io.ConfigErrorRecoveryEnableTooltip then - io.ConfigErrorRecoveryEnableAssert = true - io.ConfigErrorRecoveryEnableDebugLog = true - io.ConfigErrorRecoveryEnableTooltip = true + -- Using the format string to display a name instead of an integer. + -- Here we completely omit '%d' from the format string, so it'll only display a name. + -- This technique can also be used with DragInt(). + IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)") + local Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT = 0, 1, 2, 3, 4 + local elems_names = { "Fire", "Earth", "Air", "Water" } + local elem_name = (s.elem >= 0 and s.elem < Element_COUNT) and elems_names[s.elem + 1] or "Unknown" + s.elem = ImGui.SliderInt("slider enum", s.elem, 0, Element_COUNT - 1, elem_name) -- Use ImGuiSliderFlags_NoInput flag to disable Ctrl+Click here. + ImGui.SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.") end - -- Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools - ImGui.SeparatorText("Debug") - CB("io.ConfigDebugIsDebuggerPresent", "ConfigDebugIsDebuggerPresent") - HM("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.") - CB("io.ConfigDebugHighlightIdConflicts", "ConfigDebugHighlightIdConflicts") - HM("Highlight and show an error message when multiple items have conflicting identifiers.") - ImGui.BeginDisabled() - CB("io.ConfigDebugBeginReturnValueOnce", "ConfigDebugBeginReturnValueOnce") - ImGui.EndDisabled() - HM("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.") - CB("io.ConfigDebugBeginReturnValueLoop", "ConfigDebugBeginReturnValueLoop") - HM("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.") - CB("io.ConfigDebugIgnoreFocusLoss", "ConfigDebugIgnoreFocusLoss") - HM("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.") - CB("io.ConfigDebugDrawListDefaultsToStrokeLegacy", "ConfigDebugDrawListDefaultsToStrokeLegacy") - HM("Option to default all ImDrawList to ImDrawFlags_StrokeLegacy mode, mimicking pre-1.93.0 rendering.") - CB("io.ConfigDebugIniSettings", "ConfigDebugIniSettings") - HM("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).") + ImGui.SeparatorText("Selectors/Pickers") + + do + local s = S.DemoWindowWidgetsBasic.pickers + IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4") + ImGui.ColorEdit3("color 1", s.col1) + ImGui.SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" .. + "Click and hold to use drag and drop.\n" .. + "Right-Click on the color square to show options.\n" .. + "Ctrl+Click on individual component to input value.\n") + + ImGui.ColorEdit4("color 2", s.col2) + end + + do + local s = S.DemoWindowWidgetsBasic.combo + -- Using the _simplified_ one-liner Combo() api here + -- See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. + IMGUI_DEMO_MARKER("Widgets/Basic/Combo") + local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" } + s.item_current = ImGui.Combo("combo", s.item_current, items, #items) + ImGui.SameLine(); HelpMarker( + "Using the simplified one-liner Combo API here.\n" .. + "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.") + end + + do + local s = S.DemoWindowWidgetsBasic.listbox + -- Using the _simplified_ one-liner ListBox() api here + -- See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. + IMGUI_DEMO_MARKER("Widgets/Basic/ListBox") + local items = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" } + s.item_current = ImGui.ListBox("listbox", s.item_current, items, #items, 4) + ImGui.SameLine(); HelpMarker( + "Using the simplified one-liner ListBox API here.\n" .. + "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.") + end + + -- Testing ImGuiOnceUponAFrame helper. + --static ImGuiOnceUponAFrame once; + --for (int i = 0; i < 5; i++) + -- if (once) + -- ImGui.Text("This will be displayed only once."); ImGui.TreePop() - ImGui.Spacing() end +end - if ImGui.TreeNode("Backend Flags") then - IMGUI_DEMO_MARKER("Configuration/Backend Flags") - HelpMarker( - "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" .. - "Here we expose them as read-only fields to avoid breaking interactions with your backend.") +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsBullets() +------------------------------------------------------------------------------- - -- Make a local copy to avoid modifying actual backend flags. - -- FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright? - local B = ImGuiBackendFlags - local backend_flags = io.BackendFlags - ImGui.BeginDisabled() - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasGamepad", backend_flags, B.HasGamepad) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseCursors", backend_flags, B.HasMouseCursors) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasSetMousePos", backend_flags, B.HasSetMousePos) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: PlatformHasViewports", backend_flags, B.PlatformHasViewports) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport", backend_flags, B.HasMouseHoveredViewport) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasParentViewport", backend_flags, B.HasParentViewport) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", backend_flags, B.RendererHasVtxOffset) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasTextures", backend_flags, B.RendererHasTextures) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasViewports", backend_flags, B.RendererHasViewports) +function DemoWindowWidgetsBullets() + if ImGui.TreeNode("Bullets") then + IMGUI_DEMO_MARKER("Widgets/Bullets") + ImGui.BulletText("Bullet point 1") + ImGui.BulletText("Bullet point 2\nOn multiple lines") + if ImGui.TreeNode("Tree node") then + ImGui.BulletText("Another bullet point") + ImGui.TreePop() + end + ImGui.Bullet(); ImGui.Text("Bullet point 3 (two calls)") + ImGui.Bullet(); ImGui.SmallButton("Button") + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsCollapsingHeaders() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsCollapsingHeaders = { + closable_group = true, +} + +function DemoWindowWidgetsCollapsingHeaders() + local _ + if ImGui.TreeNode("Collapsing Headers") then + local s = S.DemoWindowWidgetsCollapsingHeaders + IMGUI_DEMO_MARKER("Widgets/Collapsing Headers") + _, s.closable_group = ImGui.Checkbox("Show 2nd header", s.closable_group) + if ImGui.CollapsingHeader("Header", 0 --[[ImGuiTreeNodeFlags.None]]) then + ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) + for i = 0, 4 do + ImGui.Text("Some content %d", i) + end + end + local open + open, s.closable_group = ImGui.CollapsingHeader("Header with a close button", s.closable_group) + if open then + ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) + for i = 0, 4 do + ImGui.Text("More content %d", i) + end + end + --[[ + if ImGui.CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags.Bullet) then + ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered()) + end + ]] + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsColorAndPickers() +------------------------------------------------------------------------------- + +-- [Port] the library does not define the standard color payload types (ColorButton drag source is not ported yet) +IMGUI_PAYLOAD_TYPE_COLOR_3F = IMGUI_PAYLOAD_TYPE_COLOR_3F or "_COL3F" +IMGUI_PAYLOAD_TYPE_COLOR_4F = IMGUI_PAYLOAD_TYPE_COLOR_4F or "_COL4F" + +S.DemoWindowWidgetsColorAndPickers = { + color = ImVec4(114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 200.0 / 255.0), + base_flags = ImGuiColorEditFlags.None, + saved_palette_init = true, + saved_palette = {}, -- 32 x ImVec4, 1-based + backup_color = ImVec4(), + no_border = false, + ref_color = false, + ref_color_v = ImVec4(1.0, 0.0, 1.0, 0.5), + picker_mode = 0, + display_mode = 0, + color_picker_flags = ImGuiColorEditFlags.AlphaBar, + color_hsv = ImVec4(0.23, 1.0, 1.0, 1.0), -- Stored as HSV! +} + +function DemoWindowWidgetsColorAndPickers() + local _ + if ImGui.TreeNode("Color/Picker Widgets") then + local s = S.DemoWindowWidgetsColorAndPickers + IMGUI_DEMO_MARKER("Widgets/Color") + local color = s.color + + ImGui.SeparatorText("Options") + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.base_flags, 2 --[[ImGuiColorEditFlags.NoAlpha]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", s.base_flags, 4096 --[[ImGuiColorEditFlags.AlphaOpaque]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", s.base_flags, 8192 --[[ImGuiColorEditFlags.AlphaNoBg]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", s.base_flags, 16384 --[[ImGuiColorEditFlags.AlphaPreviewHalf]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoOptions", s.base_flags, 8 --[[ImGuiColorEditFlags.NoOptions]]); ImGui.SameLine(); HelpMarker("Right-click on the individual color widget to show options.") + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", s.base_flags, 512 --[[ImGuiColorEditFlags.NoDragDrop]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoColorMarkers", s.base_flags, 2048 --[[ImGuiColorEditFlags.NoColorMarkers]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_HDR", s.base_flags, 524288 --[[ImGuiColorEditFlags.HDR]]); ImGui.SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.") + local base_flags = s.base_flags + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit") + ImGui.SeparatorText("Inline color editor") + ImGui.Text("Color widget:") + ImGui.SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" .. + "Ctrl+Click on individual component to input value.\n") + ImGui.ColorEdit3("MyColor##1", color, base_flags) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)") + ImGui.Text("Color widget HSV with Alpha:") + ImGui.ColorEdit4("MyColor##2", color, bit32.bor(2097152 --[[ImGuiColorEditFlags.DisplayHSV]], base_flags)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)") + ImGui.Text("Color widget with Float Display:") + ImGui.ColorEdit4("MyColor##2f", color, bit32.bor(16777216 --[[ImGuiColorEditFlags.Float]], base_flags)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)") + ImGui.Text("Color button with Picker:") + ImGui.SameLine(); HelpMarker( + "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" .. + "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " .. + "be used for the tooltip and picker popup.") + ImGui.ColorEdit4("MyColor##3", color, bit32.bor(32 --[[ImGuiColorEditFlags.NoInputs]], 128 --[[ImGuiColorEditFlags.NoLabel]], base_flags)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)") + ImGui.Text("Color button with Custom Picker Popup:") + + -- Generate a default palette. The palette will persist and can be edited. + local saved_palette = s.saved_palette + if s.saved_palette_init then + for n = 0, 32 - 1 do + saved_palette[n + 1] = ImVec4() + saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z = ImGui.ColorConvertHSVtoRGB(n / 31.0, 0.8, 0.8) + saved_palette[n + 1].w = 1.0 -- Alpha + end + s.saved_palette_init = false + end + + local open_popup = ImGui.ColorButton("MyColor##3b", color, base_flags) + ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.x) + open_popup = ImGui.Button("Palette") or open_popup + if open_popup then + ImGui.OpenPopup("mypicker") + ImVec4_Copy(s.backup_color, color) + end + if ImGui.BeginPopup("mypicker") then + ImGui.Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!") + ImGui.Separator() + ImGui.ColorPicker4("##picker", color, bit32.bor(base_flags, 256 --[[ImGuiColorEditFlags.NoSidePreview]], 16 --[[ImGuiColorEditFlags.NoSmallPreview]])) + ImGui.SameLine() + + ImGui.BeginGroup() -- Lock X position + ImGui.Text("Current") + ImGui.ColorButton("##current", color, bit32.bor(4 --[[ImGuiColorEditFlags.NoPicker]], 16384 --[[ImGuiColorEditFlags.AlphaPreviewHalf]]), ImVec2(60, 40)) + ImGui.Text("Previous") + if ImGui.ColorButton("##previous", s.backup_color, bit32.bor(4 --[[ImGuiColorEditFlags.NoPicker]], 16384 --[[ImGuiColorEditFlags.AlphaPreviewHalf]]), ImVec2(60, 40)) then + ImVec4_Copy(color, s.backup_color) + end + ImGui.Separator() + ImGui.Text("Palette") + for n = 0, #saved_palette - 1 do + ImGui.PushID(n) + if (n % 8) ~= 0 then + ImGui.SameLine(0.0, ImGui.GetStyle().ItemSpacing.y) + end + + local palette_button_flags = bit32.bor(2 --[[ImGuiColorEditFlags.NoAlpha]], 4 --[[ImGuiColorEditFlags.NoPicker]], 64 --[[ImGuiColorEditFlags.NoTooltip]]) + if ImGui.ColorButton("##palette", saved_palette[n + 1], palette_button_flags, ImVec2(20, 20)) then + color.x, color.y, color.z = saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z -- Preserve alpha! + end + + -- Allow user to drop colors into each palette entry. Note that ColorButton() is already a + -- drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. + if ImGui.BeginDragDropTarget() then + local payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F) + if payload then + local d = payload.Data -- [Port] memcpy -> copy components (Data is a 1-based float array or ImVec4) + saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z = d[1], d[2], d[3] + end + payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F) + if payload then + local d = payload.Data -- [Port] memcpy -> copy components + saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z, saved_palette[n + 1].w = d[1], d[2], d[3], d[4] + end + ImGui.EndDragDropTarget() + end + + ImGui.PopID() + end + ImGui.EndGroup() + ImGui.EndPopup() + end + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)") + ImGui.Text("Color button only:") + _, s.no_border = ImGui.Checkbox("ImGuiColorEditFlags_NoBorder", s.no_border) + ImGui.ColorButton("MyColor##3c", color, bit32.bor(base_flags, s.no_border and 1024 --[[ImGuiColorEditFlags.NoBorder]] or 0), ImVec2(80, 80)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker") + ImGui.SeparatorText("Color picker") + + ImGui.PushID("Color picker") + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.color_picker_flags, 2 --[[ImGuiColorEditFlags.NoAlpha]]) + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaBar", s.color_picker_flags, 262144 --[[ImGuiColorEditFlags.AlphaBar]]) + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", s.color_picker_flags, 256 --[[ImGuiColorEditFlags.NoSidePreview]]) + if bit32.band(s.color_picker_flags, 256 --[[ImGuiColorEditFlags.NoSidePreview]]) ~= 0 then + ImGui.SameLine() + _, s.ref_color = ImGui.Checkbox("With Ref Color", s.ref_color) + if s.ref_color then + ImGui.SameLine() + ImGui.ColorEdit4("##RefColor", s.ref_color_v, bit32.bor(32 --[[ImGuiColorEditFlags.NoInputs]], base_flags)) + end + end + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_PickerNoRotate", s.color_picker_flags, 134217728 --[[ImGuiColorEditFlags.PickerNoRotate]]) + + s.picker_mode = ImGui.Combo("Picker Mode", s.picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0") + ImGui.SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode.") + + s.display_mode = ImGui.Combo("Display Mode", s.display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0") + ImGui.SameLine(); HelpMarker( + "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " .. + "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex " .. + "if you don't specify a display mode.\n\nYou can change the defaults using io.ConfigColorEditFlags.") + + local flags = bit32.bor(base_flags, s.color_picker_flags) + if s.picker_mode == 1 then flags = bit32.bor(flags, 33554432 --[[ImGuiColorEditFlags.PickerHueBar]]) end + if s.picker_mode == 2 then flags = bit32.bor(flags, 67108864 --[[ImGuiColorEditFlags.PickerHueWheel]]) end + if s.display_mode == 1 then flags = bit32.bor(flags, 32 --[[ImGuiColorEditFlags.NoInputs]]) end -- Disable all RGB/HSV/Hex displays + if s.display_mode == 2 then flags = bit32.bor(flags, 1048576 --[[ImGuiColorEditFlags.DisplayRGB]]) end -- Override display mode + if s.display_mode == 3 then flags = bit32.bor(flags, 2097152 --[[ImGuiColorEditFlags.DisplayHSV]]) end + if s.display_mode == 4 then flags = bit32.bor(flags, 4194304 --[[ImGuiColorEditFlags.DisplayHex]]) end + ImGui.ColorPicker4("MyColor##4", color, flags, s.ref_color and s.ref_color_v or nil) + + ImGui.Text("Set defaults in code:") + ImGui.SameLine(); HelpMarker( + "io.ConfigColorEditFlags is designed to allow you to set boot-time default.\n" .. + "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " .. + "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " .. + "encouraging you to persistently save values that aren't forward-compatible.") + if ImGui.Button("Overwrite default: Uint8 + HSV + Hue Bar") then + ImGui.GetIO().ConfigColorEditFlags = bit32.bor(8388608 --[[ImGuiColorEditFlags.Uint8]], 2097152 --[[ImGuiColorEditFlags.DisplayHSV]], 33554432 --[[ImGuiColorEditFlags.PickerHueBar]], 268435456 --[[ImGuiColorEditFlags.InputRGB]]) -- [Port] + InputRGB: without it ColorEdit4's InputMask_ power-of-two assert trips + end + if ImGui.Button("Overwrite default: Float + HDR + Hue Wheel") then + ImGui.GetIO().ConfigColorEditFlags = bit32.bor(16777216 --[[ImGuiColorEditFlags.Float]], 524288 --[[ImGuiColorEditFlags.HDR]], 67108864 --[[ImGuiColorEditFlags.PickerHueWheel]], 1048576 --[[ImGuiColorEditFlags.DisplayRGB]], 268435456 --[[ImGuiColorEditFlags.InputRGB]]) -- [Port] + DisplayRGB + InputRGB: same asserts (DisplayMask_/InputMask_) + end + + -- Always display a small version of both types of pickers + -- (that's in order to make it more visible in the demo to people who are skimming quickly through it) + ImGui.Text("Both types:") + local w = (ImGui.GetContentRegionAvail().x - ImGui.GetStyle().ItemSpacing.y) * 0.40 + ImGui.SetNextItemWidth(w) + ImGui.ColorPicker3("##MyColor##5", color, bit32.bor(33554432 --[[ImGuiColorEditFlags.PickerHueBar]], 256 --[[ImGuiColorEditFlags.NoSidePreview]], 32 --[[ImGuiColorEditFlags.NoInputs]], 2 --[[ImGuiColorEditFlags.NoAlpha]])) + ImGui.SameLine() + ImGui.SetNextItemWidth(w) + ImGui.ColorPicker3("##MyColor##6", color, bit32.bor(67108864 --[[ImGuiColorEditFlags.PickerHueWheel]], 256 --[[ImGuiColorEditFlags.NoSidePreview]], 32 --[[ImGuiColorEditFlags.NoInputs]], 2 --[[ImGuiColorEditFlags.NoAlpha]])) + ImGui.PopID() + + -- HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) + local color_hsv = s.color_hsv -- Stored as HSV! + ImGui.Spacing() + ImGui.Text("HSV encoded colors") + ImGui.SameLine(); HelpMarker( + "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV " .. + "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the " .. + "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.") + ImGui.Text("Color widget with InputHSV:") + ImGui.ColorEdit4("HSV shown as RGB##1", color_hsv, bit32.bor(1048576 --[[ImGuiColorEditFlags.DisplayRGB]], 536870912 --[[ImGuiColorEditFlags.InputHSV]], 16777216 --[[ImGuiColorEditFlags.Float]])) + ImGui.ColorEdit4("HSV shown as HSV##1", color_hsv, bit32.bor(2097152 --[[ImGuiColorEditFlags.DisplayHSV]], 536870912 --[[ImGuiColorEditFlags.InputHSV]], 16777216 --[[ImGuiColorEditFlags.Float]])) + ImGui.DragFloat4("Raw HSV values", color_hsv, 0.01, 0.0, 1.0) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsComboBoxes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsComboBoxes = { + flags = 0, + item_selected_idx = 0, -- Here we store our selection data as an index. + filter = nil, -- ImGuiTextFilter, created lazily + item_current_2 = 0, + item_current_3 = -1, -- If the selection isn't within 0..count, Combo won't display a preview + item_current_4 = 0, +} + +function DemoWindowWidgetsComboBoxes() + local _, pressed + if ImGui.TreeNode("Combo") then + local s = S.DemoWindowWidgetsComboBoxes + IMGUI_DEMO_MARKER("Widgets/Combo") + -- Combo Boxes are also called "Dropdown" in other systems + -- Expose flags as checkbox for the demo + _, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", s.flags, 1 --[[ImGuiComboFlags.PopupAlignLeft]]) + ImGui.SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo") + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoArrowButton", s.flags, 32 --[[ImGuiComboFlags.NoArrowButton]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(64 --[[ImGuiComboFlags.NoPreview]])) -- Clear incompatible flags + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoPreview", s.flags, 64 --[[ImGuiComboFlags.NoPreview]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.bor(32 --[[ImGuiComboFlags.NoArrowButton]], 128 --[[ImGuiComboFlags.WidthFitPreview]]))) -- Clear incompatible flags + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_WidthFitPreview", s.flags, 128 --[[ImGuiComboFlags.WidthFitPreview]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(64 --[[ImGuiComboFlags.NoPreview]])) + end + + -- Override default popup height + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_HeightSmall", s.flags, 2 --[[ImGuiComboFlags.HeightSmall]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(30 --[[ImGuiComboFlags.HeightMask_]], bit32.bnot(2 --[[ImGuiComboFlags.HeightSmall]])))) + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_HeightRegular", s.flags, 4 --[[ImGuiComboFlags.HeightRegular]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(30 --[[ImGuiComboFlags.HeightMask_]], bit32.bnot(4 --[[ImGuiComboFlags.HeightRegular]])))) + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_HeightLargest", s.flags, 16 --[[ImGuiComboFlags.HeightLargest]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(30 --[[ImGuiComboFlags.HeightMask_]], bit32.bnot(16 --[[ImGuiComboFlags.HeightLargest]])))) + end + + -- Using the generic BeginCombo() API, you have full control over how to display the combo contents. + -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + -- stored in the object itself, etc.) + local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } + + -- Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) + local combo_preview_value = items[s.item_selected_idx + 1] + if ImGui.BeginCombo("combo 1", combo_preview_value, s.flags) then + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + if ImGui.Selectable(items[n + 1], is_selected) then + s.item_selected_idx = n + end + + -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if is_selected then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndCombo() + end + + -- Show case embedding a filter using a simple trick: displaying the filter inside combo contents. + -- See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives. + if ImGui.BeginCombo("combo 2 (w/ filter)", combo_preview_value, s.flags) then + if s.filter == nil then s.filter = ImGuiTextFilter() end + local filter = s.filter + if ImGui.IsWindowAppearing() then + ImGui.SetKeyboardFocusHere() + filter:Clear() + end + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 551 --[[ImGuiKey.F]])) + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + filter:DrawWithHint("##Filter", "Filter (incl -excl)") + + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + if filter:PassFilter(items[n + 1]) then + if ImGui.Selectable(items[n + 1], is_selected) then + s.item_selected_idx = n + end + end + end + ImGui.EndCombo() + end + + ImGui.Spacing() + ImGui.SeparatorText("One-liner variants") + HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section.") + + -- Simplified one-liner Combo() API, using values packed in a single constant string + -- This is a convenience for when the selection set is small and known at compile-time. + s.item_current_2 = ImGui.Combo("combo 3 (one-liner)", s.item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0") + + -- Simplified one-liner Combo() using an array of const char* + -- This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. + s.item_current_3 = ImGui.Combo("combo 4 (array)", s.item_current_3, items, #items) + + -- Simplified one-liner Combo() using an accessor function + s.item_current_4 = ImGui.Combo("combo 5 (function)", s.item_current_4, function(data, n) return data[n + 1] end, items, #items) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDataTypes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsDataTypes = { + -- State + s8_v = 127, + u8_v = 255, + s16_v = 32767, + u16_v = 65535, + s32_v = -1, + u32_v = 4294967295, -- (ImU32)-1 + -- [Port] s64_v / u64_v: 64-bit integer types are not supported (Lua numbers are doubles) + f32_v = 0.123, + f64_v = 90000.01234567890123456789, + drag_clamp = false, + inputs_step = true, + flags = ImGuiInputTextFlags.None, +} + +function DemoWindowWidgetsDataTypes() + local _ + if ImGui.TreeNode("Data Types") then + local s = S.DemoWindowWidgetsDataTypes + IMGUI_DEMO_MARKER("Widgets/Data Types") + -- DragScalar/InputScalar/SliderScalar functions allow various data types + -- - signed/unsigned + -- - 8/16/32/64-bits + -- - integer/float/double + -- To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum + -- to pass the type, and passing all arguments by pointer. + -- This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type. + -- In practice, if you frequently use a given type that is not covered by the normal API entry points, + -- you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, + -- and then pass their address to the generic function. For example: + -- bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") + -- { + -- return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); + -- } + -- [Port] in this port the value is passed and returned by value: `v = ImGui.SliderScalar(label, data_type, v, min, max, format)` + + -- Setup limits (as helper variables so we can take their address, as explained above) + -- Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. + -- [Port] LLONG_MIN/LLONG_MAX/ULLONG_MAX fallback block dropped: no 64-bit integer types + local s8_zero, s8_one, s8_fifty, s8_min, s8_max = 0, 1, 50, -128, 127 + local u8_zero, u8_one, u8_fifty, u8_min, u8_max = 0, 1, 50, 0, 255 + local s16_zero, s16_one, s16_fifty, s16_min, s16_max = 0, 1, 50, -32768, 32767 + local u16_zero, u16_one, u16_fifty, u16_min, u16_max = 0, 1, 50, 0, 65535 + local s32_zero, s32_one, s32_fifty, s32_min, s32_max, s32_hi_a, s32_hi_b = 0, 1, 50, -1073741824, 1073741823, 1073741823 - 100, 1073741823 -- INT_MIN/2, INT_MAX/2 + local u32_zero, u32_one, u32_fifty, u32_min, u32_max, u32_hi_a, u32_hi_b = 0, 1, 50, 0, 2147483647, 2147483647 - 100, 2147483647 -- UINT_MAX/2 + -- [Port] s64_* / u64_* limits: ImGuiDataType.S64/U64 are not supported + local f32_zero, f32_one, f32_lo_a, f32_hi_a = 0.0, 1.0, -10000000000.0, 10000000000.0 + local f64_zero, f64_one, f64_lo_a, f64_hi_a = 0.0, 1.0, -1000000000000000.0, 1000000000000000.0 + + -- State + -- (see S.DemoWindowWidgetsDataTypes) + + local drag_speed = 0.2 + IMGUI_DEMO_MARKER("Widgets/Data Types/Drags") + ImGui.SeparatorText("Drags") + _, s.drag_clamp = ImGui.Checkbox("Clamp integers to 0..50", s.drag_clamp) + ImGui.SameLine(); HelpMarker( + "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" .. + "You can override the clamping limits by using Ctrl+Click to input a value.") + local drag_clamp = s.drag_clamp + s.s8_v = ImGui.DragScalar("drag s8", 0 --[[ImGuiDataType.S8]], s.s8_v, drag_speed, drag_clamp and s8_zero or nil, drag_clamp and s8_fifty or nil) + s.u8_v = ImGui.DragScalar("drag u8", 1 --[[ImGuiDataType.U8]], s.u8_v, drag_speed, drag_clamp and u8_zero or nil, drag_clamp and u8_fifty or nil, "%u ms") + s.s16_v = ImGui.DragScalar("drag s16", 2 --[[ImGuiDataType.S16]], s.s16_v, drag_speed, drag_clamp and s16_zero or nil, drag_clamp and s16_fifty or nil) + s.u16_v = ImGui.DragScalar("drag u16", 3 --[[ImGuiDataType.U16]], s.u16_v, drag_speed, drag_clamp and u16_zero or nil, drag_clamp and u16_fifty or nil, "%u ms") + s.s32_v = ImGui.DragScalar("drag s32", 4 --[[ImGuiDataType.S32]], s.s32_v, drag_speed, drag_clamp and s32_zero or nil, drag_clamp and s32_fifty or nil) + s.s32_v = ImGui.DragScalar("drag s32 hex", 4 --[[ImGuiDataType.S32]], s.s32_v, drag_speed, drag_clamp and s32_zero or nil, drag_clamp and s32_fifty or nil, "0x%08X") + s.u32_v = ImGui.DragScalar("drag u32", 5 --[[ImGuiDataType.U32]], s.u32_v, drag_speed, drag_clamp and u32_zero or nil, drag_clamp and u32_fifty or nil, "%u ms") + -- [Port] ImGui.DragScalar("drag s64", ImGuiDataType.S64, s64_v, ...) -- 64-bit types not supported + -- [Port] ImGui.DragScalar("drag u64", ImGuiDataType.U64, u64_v, ...) -- 64-bit types not supported + s.f32_v = ImGui.DragScalar("drag float", 6 --[[ImGuiDataType.Float]], s.f32_v, 0.005, f32_zero, f32_one, "%f") + s.f32_v = ImGui.DragScalar("drag float log", 6 --[[ImGuiDataType.Float]], s.f32_v, 0.005, f32_zero, f32_one, "%f", 32 --[[ImGuiSliderFlags.Logarithmic]]) + s.f64_v = ImGui.DragScalar("drag double", 7 --[[ImGuiDataType.Double]], s.f64_v, 0.0005, f64_zero, nil, "%.10f grams") + s.f64_v = ImGui.DragScalar("drag double log",7 --[[ImGuiDataType.Double]], s.f64_v, 0.0005, f64_zero, f64_one, "0 < %.10f < 1", 32 --[[ImGuiSliderFlags.Logarithmic]]) + + IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders") + ImGui.SeparatorText("Sliders") + s.s8_v = ImGui.SliderScalar("slider s8 full", 0 --[[ImGuiDataType.S8]], s.s8_v, s8_min, s8_max, "%d") + s.u8_v = ImGui.SliderScalar("slider u8 full", 1 --[[ImGuiDataType.U8]], s.u8_v, u8_min, u8_max, "%u") + s.s16_v = ImGui.SliderScalar("slider s16 full", 2 --[[ImGuiDataType.S16]], s.s16_v, s16_min, s16_max, "%d") + s.u16_v = ImGui.SliderScalar("slider u16 full", 3 --[[ImGuiDataType.U16]], s.u16_v, u16_min, u16_max, "%u") + s.s32_v = ImGui.SliderScalar("slider s32 low", 4 --[[ImGuiDataType.S32]], s.s32_v, s32_zero, s32_fifty,"%d") + s.s32_v = ImGui.SliderScalar("slider s32 high", 4 --[[ImGuiDataType.S32]], s.s32_v, s32_hi_a, s32_hi_b, "%d") + s.s32_v = ImGui.SliderScalar("slider s32 full", 4 --[[ImGuiDataType.S32]], s.s32_v, s32_min, s32_max, "%d") + s.s32_v = ImGui.SliderScalar("slider s32 hex", 4 --[[ImGuiDataType.S32]], s.s32_v, s32_zero, s32_fifty, "0x%04X") + s.u32_v = ImGui.SliderScalar("slider u32 low", 5 --[[ImGuiDataType.U32]], s.u32_v, u32_zero, u32_fifty,"%u") + s.u32_v = ImGui.SliderScalar("slider u32 high", 5 --[[ImGuiDataType.U32]], s.u32_v, u32_hi_a, u32_hi_b, "%u") + s.u32_v = ImGui.SliderScalar("slider u32 full", 5 --[[ImGuiDataType.U32]], s.u32_v, u32_min, u32_max, "%u") + -- [Port] "slider s64 low" / "slider s64 high" / "slider s64 full" (ImGuiDataType.S64): 64-bit types not supported + -- [Port] "slider u64 low" / "slider u64 high" / "slider u64 full" (ImGuiDataType.U64): 64-bit types not supported + s.f32_v = ImGui.SliderScalar("slider float low", 6 --[[ImGuiDataType.Float]], s.f32_v, f32_zero, f32_one) + s.f32_v = ImGui.SliderScalar("slider float low log", 6 --[[ImGuiDataType.Float]], s.f32_v, f32_zero, f32_one, "%.10f", 32 --[[ImGuiSliderFlags.Logarithmic]]) + s.f32_v = ImGui.SliderScalar("slider float high", 6 --[[ImGuiDataType.Float]], s.f32_v, f32_lo_a, f32_hi_a, "%e") + s.f64_v = ImGui.SliderScalar("slider double low", 7 --[[ImGuiDataType.Double]], s.f64_v, f64_zero, f64_one, "%.10f grams") + s.f64_v = ImGui.SliderScalar("slider double low log",7 --[[ImGuiDataType.Double]], s.f64_v, f64_zero, f64_one, "%.10f", 32 --[[ImGuiSliderFlags.Logarithmic]]) + s.f64_v = ImGui.SliderScalar("slider double high", 7 --[[ImGuiDataType.Double]], s.f64_v, f64_lo_a, f64_hi_a, "%e grams") + + ImGui.SeparatorText("Sliders (reverse)") + s.s8_v = ImGui.SliderScalar("slider s8 reverse", 0 --[[ImGuiDataType.S8]], s.s8_v, s8_max, s8_min, "%d") + s.u8_v = ImGui.SliderScalar("slider u8 reverse", 1 --[[ImGuiDataType.U8]], s.u8_v, u8_max, u8_min, "%u") + s.s32_v = ImGui.SliderScalar("slider s32 reverse", 4 --[[ImGuiDataType.S32]], s.s32_v, s32_fifty, s32_zero, "%d") + s.u32_v = ImGui.SliderScalar("slider u32 reverse", 5 --[[ImGuiDataType.U32]], s.u32_v, u32_fifty, u32_zero, "%u") + -- [Port] "slider s64 reverse" / "slider u64 reverse": 64-bit types not supported + + IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs") + ImGui.SeparatorText("Inputs") + _, s.inputs_step = ImGui.Checkbox("Show step buttons", s.inputs_step) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, 512 --[[ImGuiInputTextFlags.ReadOnly]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", s.flags, 8192 --[[ImGuiInputTextFlags.ParseEmptyRefVal]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", s.flags, 16384 --[[ImGuiInputTextFlags.DisplayEmptyRefVal]]) + local inputs_step, flags = s.inputs_step, s.flags + s.s8_v = ImGui.InputScalar("input s8", 0 --[[ImGuiDataType.S8]], s.s8_v, inputs_step and s8_one or nil, nil, "%d", flags) + s.u8_v = ImGui.InputScalar("input u8", 1 --[[ImGuiDataType.U8]], s.u8_v, inputs_step and u8_one or nil, nil, "%u", flags) + s.s16_v = ImGui.InputScalar("input s16", 2 --[[ImGuiDataType.S16]], s.s16_v, inputs_step and s16_one or nil, nil, "%d", flags) + s.u16_v = ImGui.InputScalar("input u16", 3 --[[ImGuiDataType.U16]], s.u16_v, inputs_step and u16_one or nil, nil, "%u", flags) + s.s32_v = ImGui.InputScalar("input s32", 4 --[[ImGuiDataType.S32]], s.s32_v, inputs_step and s32_one or nil, nil, "%d", flags) + s.s32_v = ImGui.InputScalar("input s32 hex", 4 --[[ImGuiDataType.S32]], s.s32_v, inputs_step and s32_one or nil, nil, "%04X", flags) + s.u32_v = ImGui.InputScalar("input u32", 5 --[[ImGuiDataType.U32]], s.u32_v, inputs_step and u32_one or nil, nil, "%u", flags) + s.u32_v = ImGui.InputScalar("input u32 hex", 5 --[[ImGuiDataType.U32]], s.u32_v, inputs_step and u32_one or nil, nil, "%08X", flags) + -- [Port] ImGui.InputScalar("input s64", ImGuiDataType.S64, ...) -- 64-bit types not supported + -- [Port] ImGui.InputScalar("input u64", ImGuiDataType.U64, ...) -- 64-bit types not supported + s.f32_v = ImGui.InputScalar("input float", 6 --[[ImGuiDataType.Float]], s.f32_v, inputs_step and f32_one or nil, nil, nil, flags) + s.f64_v = ImGui.InputScalar("input double", 7 --[[ImGuiDataType.Double]], s.f64_v, inputs_step and f64_one or nil, nil, nil, flags) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDisableBlocks() +------------------------------------------------------------------------------- + +function DemoWindowWidgetsDisableBlocks(demo_data) + local _ + if ImGui.TreeNode("Disable Blocks") then + IMGUI_DEMO_MARKER("Widgets/Disable Blocks") + _, demo_data.DisableSections = ImGui.Checkbox("Disable entire section above", demo_data.DisableSections) + ImGui.SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections.") + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDragAndDrop() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsDragAndDrop = { + col1 = { 1.0, 0.0, 0.2 }, + col2 = { 0.4, 0.7, 0.0, 0.5 }, + mode = 0, + names = { -- 1-based + "Bobby", "Beatrice", "Betty", + "Brianna", "Barry", "Bernard", + "Bibi", "Blaine", "Bryn" + }, + item_names = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }, -- 1-based + col4 = ImVec4(1.0, 0.0, 0.2, 1.0), +} + +function DemoWindowWidgetsDragAndDrop() + if ImGui.TreeNode("Drag and Drop") then + local s = S.DemoWindowWidgetsDragAndDrop + IMGUI_DEMO_MARKER("Widgets/Drag and drop") + if ImGui.TreeNode("Drag and drop in standard widgets") then + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets") + -- ColorEdit widgets automatically act as drag source and drag target. + -- They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F + -- to allow your own widgets to use colors in their drag and drop interaction. + -- Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. + HelpMarker("You can drag from the color squares.") + ImGui.ColorEdit3("color 1", s.col1) + ImGui.ColorEdit4("color 2", s.col2) + ImGui.TreePop() + end + + if ImGui.TreeNode("Drag and drop to copy/swap items") then + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items") + local Mode_Copy, Mode_Move, Mode_Swap = 0, 1, 2 + if ImGui.RadioButtonEx("Copy", s.mode == Mode_Copy) then s.mode = Mode_Copy end ImGui.SameLine() + if ImGui.RadioButtonEx("Move", s.mode == Mode_Move) then s.mode = Mode_Move end ImGui.SameLine() + if ImGui.RadioButtonEx("Swap", s.mode == Mode_Swap) then s.mode = Mode_Swap end + local names = s.names + for n = 0, #names - 1 do + ImGui.PushID(n) + if (n % 3) ~= 0 then + ImGui.SameLine() + end + ImGui.Button(names[n + 1], ImVec2(60, 60)) + + -- Our buttons are both drag sources and drag targets here! + if ImGui.BeginDragDropSource(0 --[[ImGuiDragDropFlags.None]]) then + -- Set payload to carry the index of our item (could be anything) + ImGui.SetDragDropPayload("DND_DEMO_CELL", n, 4) -- [Port] sizeof(int) -> 4, payload carries the Lua value + + -- Display preview (could be anything, e.g. when dragging an image we could decide to display + -- the filename and a small preview of the image, etc.) + if s.mode == Mode_Copy then ImGui.Text("Copy %s", names[n + 1]) end + if s.mode == Mode_Move then ImGui.Text("Move %s", names[n + 1]) end + if s.mode == Mode_Swap then ImGui.Text("Swap %s", names[n + 1]) end + ImGui.EndDragDropSource() + end + if ImGui.BeginDragDropTarget() then + local payload = ImGui.AcceptDragDropPayload("DND_DEMO_CELL") + if payload then + assert(payload.DataSize == 4) + local payload_n = payload.Data + if s.mode == Mode_Copy then + names[n + 1] = names[payload_n + 1] + end + if s.mode == Mode_Move then + names[n + 1] = names[payload_n + 1] + names[payload_n + 1] = "" + end + if s.mode == Mode_Swap then + local tmp = names[n + 1] + names[n + 1] = names[payload_n + 1] + names[payload_n + 1] = tmp + end + end + ImGui.EndDragDropTarget() + end + ImGui.PopID() + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Drag to reorder items (simple)") then + IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)") + -- FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. + -- This code was always slightly faulty but in a way which was not easily noticeable. + -- Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue. + ImGui.PushItemFlag(32 --[[ImGuiItemFlags.AllowDuplicateId]], true) + + -- Simple reordering + HelpMarker( + "We don't use the drag and drop api at all here! " .. + "Instead we query when the item is held but not hovered, and order items accordingly.") + local item_names = s.item_names + for n = 0, #item_names - 1 do + local item = item_names[n + 1] + ImGui.Selectable(item) + + if ImGui.IsItemActive() and not ImGui.IsItemHovered() then + local n_next = n + ((ImGui.GetMouseDragDelta(0).y < 0.0) and -1 or 1) + if n_next >= 0 and n_next < #item_names then + item_names[n + 1] = item_names[n_next + 1] + item_names[n_next + 1] = item + ImGui.ResetMouseDragDelta() + end + end + end + + ImGui.PopItemFlag() + ImGui.TreePop() + end + + if ImGui.TreeNode("Tooltip at target location") then + IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location") + for n = 0, 1 do + -- Drop targets + ImGui.Button((n ~= 0) and "drop here##1" or "drop here##0") + if ImGui.BeginDragDropTarget() then + local drop_target_flags = bit32.bor(1024 --[[ImGuiDragDropFlags.AcceptBeforeDelivery]], 4096 --[[ImGuiDragDropFlags.AcceptNoPreviewTooltip]]) + local payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags) + if payload then + -- IM_UNUSED(payload) + ImGui.SetMouseCursor(10 --[[ImGuiMouseCursor.NotAllowed]]) + ImGui.SetTooltip("Cannot drop here!") + end + ImGui.EndDragDropTarget() + end + + -- Drop source + if n == 0 then + ImGui.ColorButton("drag me", s.col4) + end + + end + ImGui.TreePop() + end + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDragsAndSliders() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsDragsAndSliders = { + flags = ImGuiSliderFlags.None, + -- Drags + drag_f = 0.5, + drag_f4 = { 0.0, 0.0, 0.0, 0.0 }, + drag_i = 50, + -- Sliders + slider_f = 0.5, + slider_f4 = { 0.0, 0.0, 0.0, 0.0 }, + slider_i = 50, +} + +function DemoWindowWidgetsDragsAndSliders() + local _ + if ImGui.TreeNode("Drag/Slider Flags") then + local s = S.DemoWindowWidgetsDragsAndSliders + IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags") + -- Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", s.flags, 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ClampOnInput", s.flags, 512 --[[ImGuiSliderFlags.ClampOnInput]]) + ImGui.SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with Ctrl+Click. By default Ctrl+Click allows going out of bounds.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", s.flags, 1024 --[[ImGuiSliderFlags.ClampZeroRange]]) + ImGui.SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_Logarithmic", s.flags, 32 --[[ImGuiSliderFlags.Logarithmic]]) + ImGui.SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", s.flags, 64 --[[ImGuiSliderFlags.NoRoundToFormat]]) + ImGui.SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_NoInput", s.flags, 128 --[[ImGuiSliderFlags.NoInput]]) + ImGui.SameLine(); HelpMarker("Disable Ctrl+Click or Enter key allowing to input text directly into the widget.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_NoSpeedTweaks", s.flags, 2048 --[[ImGuiSliderFlags.NoSpeedTweaks]]) + ImGui.SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_WrapAround", s.flags, 256 --[[ImGuiSliderFlags.WrapAround]]) + ImGui.SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ColorMarkers", s.flags, 4096 --[[ImGuiSliderFlags.ColorMarkers]]) + local flags = s.flags + + -- Drags + ImGui.Text("Underlying float value: %f", s.drag_f) + s.drag_f = ImGui.DragFloat("DragFloat (0 -> 1)", s.drag_f, 0.005, 0.0, 1.0, "%.3f", flags) + s.drag_f = ImGui.DragFloat("DragFloat (0 -> +inf)", s.drag_f, 0.005, 0.0, 3.4028234663853e+38 --[[FLT_MAX]], "%.3f", flags) + s.drag_f = ImGui.DragFloat("DragFloat (-inf -> 1)", s.drag_f, 0.005, -3.4028234663853e+38 --[[FLT_MAX]], 1.0, "%.3f", flags) + s.drag_f = ImGui.DragFloat("DragFloat (-inf -> +inf)", s.drag_f, 0.005, -3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]], "%.3f", flags) + --ImGui.DragFloat("DragFloat (0 -> 0)", drag_f, 0.005, 0.0, 0.0, "%.3f", flags) -- To test ClampZeroRange + --ImGui.DragFloat("DragFloat (100 -> 100)", drag_f, 0.005, 100.0, 100.0, "%.3f", flags) + s.drag_i = ImGui.DragInt("DragInt (0 -> 100)", s.drag_i, 0.5, 0, 100, "%d", flags) + ImGui.DragFloat4("DragFloat4 (0 -> 1)", s.drag_f4, 0.005, 0.0, 1.0, "%.3f", flags) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers. + + -- Sliders + local flags_for_sliders = bit32.band(flags, bit32.bnot(256 --[[ImGuiSliderFlags.WrapAround]])) + ImGui.Text("Underlying float value: %f", s.slider_f) + s.slider_f = ImGui.SliderFloat("SliderFloat (0 -> 1)", s.slider_f, 0.0, 1.0, "%.3f", flags_for_sliders) + s.slider_i = ImGui.SliderInt("SliderInt (0 -> 100)", s.slider_i, 0, 100, "%d", flags_for_sliders) + ImGui.SliderFloat4("SliderFloat4 (0 -> 1)", s.slider_f4, 0.0, 1.0, "%.3f", flags_for_sliders) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers. -- [Port] flags_for_sliders: upstream passes `flags`, which trips SliderScalar's WrapAround assert + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsFonts() +------------------------------------------------------------------------------- + +function DemoWindowWidgetsFonts() + if ImGui.TreeNode("Fonts") then + IMGUI_DEMO_MARKER("Widgets/Fonts") + local atlas = ImGui.GetIO().Fonts + ImGui.ShowFontAtlas(atlas) + -- FIXME-NEWATLAS: Provide a demo to add/create a procedural font? + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsImages() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsImages = { + image_viewer = ExampleImageViewerData(), + pressed_count = 0, +} +function DemoWindowWidgetsImages() + local s = S.DemoWindowWidgetsImages + if ImGui.TreeNode("Images") then + IMGUI_DEMO_MARKER("Widgets/Images") + local io = ImGui.GetIO() + ImGui.TextWrapped( + "Below we are displaying the font texture (which is the only texture we have access to in this demo). " .. + "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " .. + "Hover the texture for a zoomed view!") + + -- Below we are displaying the font texture because it is the only texture we have access to inside the demo! + -- Read description about ImTextureID/ImTextureRef and FAQ for details about texture identifiers. + -- If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top + -- of their respective source file to specify what they are using as texture identifier, for example: + -- - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. + -- - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. + -- So with the DirectX11 backend, you call ImGui.Image() with a 'ID3D11ShaderResourceView*' cast to ImTextureID. + -- - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers + -- to ImGui.Image(), and gather width/height through your own functions, etc. + -- - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, + -- it will help you debug issues if you are confused about it. + -- - Consider using the lower-level ImDrawList::AddImage() API, via ImGui.GetWindowDrawList():AddImage(). + -- - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md + -- - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + + -- Grab the current texture identifier used by the font atlas. + local atlas = io.Fonts + local my_tex_id = atlas.TexRef + local my_tex_w = atlas.TexData.Width -- Regular user code should never have to care about TexData-> fields, but since we want to display the entire texture here, we pull Width/Height from it. + local my_tex_h = atlas.TexData.Height + ImGui.Text("%.0fx%.0f", my_tex_w, my_tex_h) + + -- Basic drawing + ImGui.SeparatorText("Image()/ImageWithBg() function") + local uv_min = ImVec2(0.0, 0.0) -- Top-left + local uv_max = ImVec2(1.0, 1.0) -- Lower-right + ImGui.PushStyleVar(24 --[[ImGuiStyleVar.ImageBorderSize]], ImMax(1.0, ImGui.GetStyle().ImageBorderSize)) + ImGui.ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0, 0.0, 0.0, 1.0)) + ImGui.PopStyleVar() + + -- Fancy widget + ImGui.SeparatorText("Interactive Image Viewer") + local canvas_size = ImVec2(ImGui.GetContentRegionAvail().x, my_tex_h * 2.0) + ExampleImageViewer_DrawOptions(s.image_viewer) + ExampleImageViewer_DrawCanvas(s.image_viewer, canvas_size, my_tex_id, math.floor(my_tex_w), math.floor(my_tex_h)) + + IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons") + ImGui.SeparatorText("Textured Buttons") + ImGui.TextWrapped("And now some textured buttons..") + for i = 0, 7 do + -- UV coordinates are often (0.0, 0.0) and (1.0, 1.0) to display an entire textures. + -- Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation. + -- Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + ImGui.PushID(i) + if i > 0 then + ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(i - 1.0, i - 1.0)) + end + local size = ImVec2(32.0, 32.0) -- Size of the image we want to make visible + local uv0 = ImVec2(0.0, 0.0) -- UV coordinates for lower-left + local uv1 = ImVec2(32.0 / my_tex_w, 32.0 / my_tex_h) -- UV coordinates for (32,32) in our texture + local bg_col = ImVec4(0.0, 0.0, 0.0, 1.0) -- Black background + local tint_col = ImVec4(1.0, 1.0, 1.0, 1.0) -- No tint + if ImGui.ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col) then + s.pressed_count = s.pressed_count + 1 + end + if i > 0 then + ImGui.PopStyleVar() + end + ImGui.PopID() + ImGui.SameLine() + end + ImGui.NewLine() + ImGui.Text("Pressed %d times.", s.pressed_count) + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsListBoxes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsListBoxes = { + item_selected_idx = 0, -- Here we store our selected data as an index. + item_highlight = false, +} +function DemoWindowWidgetsListBoxes() + local s = S.DemoWindowWidgetsListBoxes + if ImGui.TreeNode("List Boxes") then + IMGUI_DEMO_MARKER("Widgets/List Boxes") + -- BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() + -- using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. + -- You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild() + -- to always be called (inconsistent with BeginListBox()/EndListBox()). + + -- Using the generic BeginListBox() API, you have full control over how to display the combo contents. + -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + -- stored in the object itself, etc.) + local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } + -- static int item_selected_idx = 0; // Here we store our selected data as an index. + + local item_highlighted_idx = -1 -- Here we store our highlighted data as an index. + _, s.item_highlight = ImGui.Checkbox("Highlight hovered item in second listbox", s.item_highlight) + + if ImGui.BeginListBox("listbox 1") then + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + if ImGui.Selectable(items[n + 1], is_selected) then + s.item_selected_idx = n + end + + if s.item_highlight and ImGui.IsItemHovered() then + item_highlighted_idx = n + end + + -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if is_selected then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndListBox() + end + ImGui.SameLine(); HelpMarker("Here we are sharing selection state between both boxes.") + + -- Custom size: use all width, 5 items tall + ImGui.Text("Full-width:") + if ImGui.BeginListBox("##listbox 2", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 5 * ImGui.GetTextLineHeightWithSpacing())) then + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + local flags = 0 + if item_highlighted_idx == n then flags = 32 --[[ImGuiSelectableFlags.Highlight]] end + if ImGui.Selectable(items[n + 1], is_selected, flags) then + s.item_selected_idx = n + end + + -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if is_selected then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndListBox() + end + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsLiveEdit() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsLiveEdit = { + str = ImGui.NewTextBuffer("", 32), + i = 0, + f = 0.0, +} +function DemoWindowWidgetsLiveEdit(demo_data) + local s = S.DemoWindowWidgetsLiveEdit + if ImGui.TreeNode("Live Edit Flags") then + IMGUI_DEMO_MARKER("Widgets/Live Edit Flags") + + ImGui.TextWrapped("Select whether to apply keyboard edits to backing variables _while_ typing.") + + _, demo_data.LiveEditOverride = ImGui.Checkbox("Override Live Edit Flags in Demo Window", demo_data.LiveEditOverride) + if not demo_data.LiveEditOverride then + demo_data.LiveEditFlags = ImGui.GetItemFlags() + end + + ImGui.BeginDisabled(demo_data.LiveEditOverride == false) + ImGui.Indent() + _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputText", demo_data.LiveEditFlags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) + _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputScalar", demo_data.LiveEditFlags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) + ImGui.Unindent() ImGui.EndDisabled() - ImGui.TreePop() - ImGui.Spacing() - end + ImGui.Text("Try typing '123' and seeing effect on backing value:") + ImGui.InputText("str", s.str, 32) + ImGui.Text("Backing value: \"%s\"", ImGui.TextBufferToString(s.str)) + s.i = ImGui.InputInt("int", s.i, 0, 0) + ImGui.Text("Backing value: %d", s.i) + s.f = ImGui.SliderFloat("float", s.f, 0.0, 100.0) + ImGui.Text("Backing value: %f", s.f) - if ImGui.TreeNode("Style, Fonts") then - IMGUI_DEMO_MARKER("Configuration/Style, Fonts") - _, demo_data.ShowStyleEditor = ImGui.Checkbox("Style Editor", demo_data.ShowStyleEditor) + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsMixedValues() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsMixedValues = { + use_liveedit = false, + items = { 12.0, 0.0, 0.0 }, +} +function DemoWindowWidgetsMixedValues() + local s = S.DemoWindowWidgetsMixedValues + if ImGui.TreeNode("Mixed Values") then + -- This is designed for advanced property editors which are generally reusable and data-driven. + HelpMarker("Using ImGuiItemFlags_MixedValue.") + + local items = s.items + local item_ref = 1 -- [Port] index of the reference item (C++: float* item_ref = &items[0]) + _, s.use_liveedit = ImGui.Checkbox("ImGuiItemFlags_LiveEditOnInput", s.use_liveedit) + + ImGui.SeparatorText("Scalar/Text Widgets") + local is_mixed = items[1] ~= items[2] or items[1] ~= items[3] + + -- Demonstrate Drags, Sliders, Inputs + ImGui.PushItemFlag(384 --[[ImGuiItemFlags.LiveEditOnInput]], s.use_liveedit) + ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], is_mixed) + local edited = false + local changed + items[item_ref], changed = ImGui.DragFloat("DragFloat", items[item_ref]); edited = edited or changed + items[item_ref], changed = ImGui.SliderFloat("SliderFloat", items[item_ref], 0.0, 100.0); edited = edited or changed + items[item_ref], changed = ImGui.InputFloat("InputFloat", items[item_ref], 1.0); edited = edited or changed + if edited then + for n = 1, #items do + if n ~= item_ref then + items[n] = items[item_ref] + end + end + end + ImGui.PopItemFlag() + + ImGui.Text("Underlying data:") + items[1] = ImGui.InputFloat("item 0 (ref)", items[1]) + items[2] = ImGui.InputFloat("item 1", items[2]) + items[3] = ImGui.InputFloat("item 2", items[3]) + ImGui.PopItemFlag() + + -- Demonstrate Checkbox(), RadioButton(), Combo(), ColorEdit4() + ImGui.SeparatorText("Others Widgets") + ImGui.Text("(note: edits are not applied in this demo)") -- <-- Would need more state tracking. + local b_on, b_off = true, false + _, b_on = ImGui.Checkbox("Checkbox On", b_on) + _, b_off = ImGui.Checkbox("Checkbox Off", b_off) + ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], true) + _, b_off = ImGui.Checkbox("Checkbox Mixed", b_off) + ImGui.RadioButtonEx("RadioButton Mixed", true) -- [Port] RadioButton(label, bool active) overload is RadioButtonEx ImGui.SameLine() - HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.") - ImGui.TreePop() - ImGui.Spacing() - end + ImGui.RadioButtonEx("RadioButton Mixed##2", true) -- Showing 2 radio buttons makes the example more clear + local combo_idx = 0 + combo_idx = ImGui.Combo("Combo", combo_idx, "One\0Two\0Three\0") + local color = ImVec4(0.5, 0.5, 0.5, 0.5) + ImGui.ColorEdit4("ColorEdit4", color) + ImGui.PopItemFlag() - if ImGui.TreeNode("Capture/Logging") then - IMGUI_DEMO_MARKER("Configuration/Capture, Logging") - HelpMarker( - "The logging API redirects all text output so you can easily capture the content of " .. - "a window or a block. Tree nodes can be automatically expanded.\n" .. - "Try opening any of the contents below in this window and then click one of the \"Log To\" button.") - if ImGui.LogButtons then - ImGui.LogButtons() - else - DemoNotPorted("LogButtons") + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsMultiComponents() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsMultiComponents = { + vec4f = { 0.10, 0.20, 0.30, 0.44 }, + vec4i = { 1, 5, 100, 255 }, + flags = 0, + begin = 10, ["end"] = 90, + begin_i = 100, end_i = 1000, +} +function DemoWindowWidgetsMultiComponents() + local s = S.DemoWindowWidgetsMultiComponents + if ImGui.TreeNode("Multi-component Widgets") then + IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets") + local vec4f = s.vec4f + local vec4i = s.vec4i + + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ColorMarkers", s.flags, 4096 --[[ImGuiSliderFlags.ColorMarkers]]) -- Only passing this to Drag/Sliders + local flags = s.flags + + ImGui.SeparatorText("2-wide") + ImGui.InputFloat2("input float2", vec4f) + ImGui.InputInt2("input int2", vec4i) + ImGui.DragFloat2("drag float2", vec4f, 0.01, 0.0, 1.0, nil, flags) + ImGui.DragInt2("drag int2", vec4i, 1, 0, 255, nil, flags) + ImGui.SliderFloat2("slider float2", vec4f, 0.0, 1.0, nil, flags) + ImGui.SliderInt2("slider int2", vec4i, 0, 255, nil, flags) + + ImGui.SeparatorText("3-wide") + ImGui.InputFloat3("input float3", vec4f) + ImGui.InputInt3("input int3", vec4i) + ImGui.DragFloat3("drag float3", vec4f, 0.01, 0.0, 1.0, nil, flags) + ImGui.DragInt3("drag int3", vec4i, 1, 0, 255, nil, flags) + ImGui.SliderFloat3("slider float3", vec4f, 0.0, 1.0, nil, flags) + ImGui.SliderInt3("slider int3", vec4i, 0, 255, nil, flags) + + ImGui.SeparatorText("4-wide") + ImGui.InputFloat4("input float4", vec4f) + ImGui.InputInt4("input int4", vec4i) + ImGui.DragFloat4("drag float4", vec4f, 0.01, 0.0, 1.0, nil, flags) + ImGui.DragInt4("drag int4", vec4i, 1, 0, 255, nil, flags) + ImGui.SliderFloat4("slider float4", vec4f, 0.0, 1.0, nil, flags) + ImGui.SliderInt4("slider int4", vec4i, 0, 255, nil, flags) + + ImGui.SeparatorText("Ranges") + s.begin, s["end"] = ImGui.DragFloatRange2("range float", s.begin, s["end"], 0.25, 0.0, 100.0, "Min: %.1f %%", "Max: %.1f %%", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + s.begin_i, s.end_i = ImGui.DragIntRange2("range int", s.begin_i, s.end_i, 5, 0, 1000, "Min: %d units", "Max: %d units") + s.begin_i, s.end_i = ImGui.DragIntRange2("range int (no bounds)", s.begin_i, s.end_i, 5, 0, 0, "Min: %d units", "Max: %d units") + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsPlotting() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsPlotting = { + animate = true, + arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, + values = {}, -- 90 zeros, filled below + values_offset = 0, + refresh_time = 0.0, + phase = 0.0, + func_type = 0, display_count = 70, +} +for n = 1, 90 do S.DemoWindowWidgetsPlotting.values[n] = 0.0 end + +-- Use functions to generate output +-- [Port] struct Funcs hoisted out of the function to avoid per-frame closures. +-- Plot getters receive a 1-based index in this port: convert back to upstream's 0-based i. +local DemoPlottingFuncs = { + Sin = function(_, idx) local i = idx - 1; return math.sin(i * 0.1) end, + Saw = function(_, idx) local i = idx - 1; if bit32.band(i, 1) ~= 0 then return 1.0 end return -1.0 end, +} + +function DemoWindowWidgetsPlotting() + local s = S.DemoWindowWidgetsPlotting + -- Plot/Graph widgets are not very good. + -- Consider using a third-party library such as ImPlot: https://github.com/epezent/implot + -- (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) + if ImGui.TreeNode("Plotting") then + IMGUI_DEMO_MARKER("Widgets/Plotting") + ImGui.Text("Need better plotting and graphing? Consider using ImPlot:") + ImGui.TextLinkOpenURL("https://github.com/epezent/implot") + ImGui.Separator() + + _, s.animate = ImGui.Checkbox("Animate", s.animate) + + -- Plot as lines and plot as histogram + local arr = s.arr + ImGui.PlotLines("Frame Times", arr, nil, #arr) + ImGui.PlotHistogram("Histogram", arr, nil, #arr, 0, nil, 0.0, 1.0, ImVec2(0, 80.0)) + -- ImGui.SameLine(); HelpMarker("Consider using ImPlot instead!") + + -- Fill an array of contiguous float values to plot + -- Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float + -- and the sizeof() of your structure in the "stride" parameter. + local values = s.values + if not s.animate or s.refresh_time == 0.0 then + s.refresh_time = ImGui.GetTime() + end + while s.refresh_time < ImGui.GetTime() do -- Create data at fixed 60 Hz rate for the demo + values[s.values_offset + 1] = math.cos(s.phase) + s.values_offset = (s.values_offset + 1) % #values + s.phase = s.phase + 0.10 * s.values_offset + s.refresh_time = s.refresh_time + 1.0 / 60.0 end - HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.") - if ImGui.Button("Copy \"Hello, world!\" to clipboard") then - if ImGui.LogToClipboard then - ImGui.LogToClipboard() - ImGui.LogText("Hello, world!") - ImGui.LogFinish() - else - ImGui.SetClipboardText("Hello, world!") -- internal clipboard only on Roblox + -- Plots can display overlay texts + -- (in this example, we will display an average value) + do + local average = 0.0 + for n = 0, #values - 1 do + average = average + values[n + 1] end + average = average / #values + local overlay = string.format("avg %f", average) + ImGui.PlotLines("Lines", values, nil, #values, s.values_offset, overlay, -1.0, 1.0, ImVec2(0, 80.0)) + end + + -- Use functions to generate output + -- FIXME: This is actually VERY awkward because current plot API only pass in indices. + -- We probably want an API passing floats and user provide sample rate/count. + local Funcs = DemoPlottingFuncs + ImGui.SeparatorText("Functions") + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.func_type = ImGui.Combo("func", s.func_type, "Sin\0Saw\0") + ImGui.SameLine() + s.display_count = ImGui.SliderInt("Sample count", s.display_count, 1, 400) + local func = Funcs.Saw + if s.func_type == 0 then func = Funcs.Sin end + ImGui.PlotLines("Lines##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) + ImGui.PlotHistogram("Histogram##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsProgressBars() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsProgressBars = { + progress_accum = 0.0, progress_dir = 1.0, +} +function DemoWindowWidgetsProgressBars() + local s = S.DemoWindowWidgetsProgressBars + if ImGui.TreeNode("Progress Bars") then + IMGUI_DEMO_MARKER("Widgets/Progress Bars") + -- Animate a simple progress bar + s.progress_accum = s.progress_accum + s.progress_dir * 0.4 * ImGui.GetIO().DeltaTime + if s.progress_accum >= 1.1 then s.progress_accum = 1.1; s.progress_dir = s.progress_dir * -1.0 end + if s.progress_accum <= -0.1 then s.progress_accum = -0.1; s.progress_dir = s.progress_dir * -1.0 end + + local progress = ImClamp(s.progress_accum, 0.0, 1.0) + + -- Typically we would use ImVec2(-1.0,0.0) or ImVec2(-FLT_MIN,0.0) to use all available width, + -- or ImVec2(width,0.0) for a specified width. ImVec2(0.0,0.0) uses ItemWidth. + ImGui.ProgressBar(progress, ImVec2(0.0, 0.0)) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + ImGui.Text("Progress Bar") + + local buf = string.format("%d/%d", math.floor(progress * 1753), 1753) + ImGui.ProgressBar(progress, ImVec2(0.0, 0.0), buf) + + -- Pass an animated negative value, e.g. -1.0 * ImGui.GetTime() is the recommended value. + -- Adjust the factor if you want to adjust the animation speed. + ImGui.ProgressBar(-1.0 * ImGui.GetTime(), ImVec2(0.0, 0.0), "Searching..") + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + ImGui.Text("Indeterminate") + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsQueryingStatuses() +------------------------------------------------------------------------------- + +-- [Port] C++ passes bools to "%d"; string.format needs numbers. +local function DemoBoolToInt(b) if b then return 1 end return 0 end + +S.DemoWindowWidgetsQueryingStatuses = { + item_type = 4, + item_disabled = false, + item_mixedvalue = false, + liveedit_flags_override = false, + liveedit_flags = 0, + b = false, + col4f = { 1.0, 0.5, 0.0, 1.0 }, + str = ImGui.NewTextBuffer("", 16), + current = 1, -- item_type == 14 + current_2 = 1, -- item_type == 15 + embed_all_inside_a_child_window = false, + test_window = false, +} +function DemoWindowWidgetsQueryingStatuses() + local s = S.DemoWindowWidgetsQueryingStatuses + local B = DemoBoolToInt + if ImGui.TreeNode("Querying Item Status (Edited/Active/Hovered etc.)") then + IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)") + -- Select an item type + local item_names = + { + "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", + "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" + } + s.item_type = ImGui.Combo("Item Type", s.item_type, item_names, #item_names, #item_names) + ImGui.SameLine() + HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().") + _, s.item_disabled = ImGui.Checkbox("Item Disabled", s.item_disabled) + _, s.item_mixedvalue = ImGui.Checkbox("Item MixedValue", s.item_mixedvalue) + _, s.liveedit_flags_override = ImGui.Checkbox("Override LiveEdit:", s.liveedit_flags_override) + ImGui.SameLine() + if not s.liveedit_flags_override then + s.liveedit_flags = ImGui.GetItemFlags() + end + ImGui.BeginDisabled(s.liveedit_flags_override == false) + _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInput", s.liveedit_flags, 384 --[[ImGuiItemFlags.LiveEditOnInput]]) + ImGui.SameLine() + _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputText", s.liveedit_flags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) + ImGui.SameLine() + _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputScalar", s.liveedit_flags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) + ImGui.EndDisabled() + if s.liveedit_flags_override then + ImGui.PushItemFlag(128 --[[ImGuiItemFlags.LiveEditOnInputText]], bit32.band(s.liveedit_flags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) ~= 0) + ImGui.PushItemFlag(256 --[[ImGuiItemFlags.LiveEditOnInputScalar]], bit32.band(s.liveedit_flags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) ~= 0) + end + + -- Submit selected items so we can query their status in the code following it. + local ret = false + local item_type = s.item_type + local col4f = s.col4f + if s.item_disabled then + ImGui.BeginDisabled(true) + end + if s.item_mixedvalue then + ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], true) + end + if item_type == 0 then ImGui.Text("ITEM: Text") end -- Testing text items with no identifier/interaction + if item_type == 1 then ret = ImGui.Button("ITEM: Button") end -- Testing button + if item_type == 2 then ImGui.PushItemFlag(8 --[[ImGuiItemFlags.ButtonRepeat]], true); ret = ImGui.Button("ITEM: Button"); ImGui.PopItemFlag() end -- Testing button (with repeater) + if item_type == 3 then ret, s.b = ImGui.Checkbox("ITEM: Checkbox", s.b) end -- Testing checkbox + if item_type == 4 then col4f[1], ret = ImGui.SliderFloat("ITEM: SliderFloat", col4f[1], 0.0, 1.0) end -- Testing basic item + if item_type == 5 then ret = ImGui.InputText("ITEM: InputText", s.str, 16) end -- Testing input text (which handles tabbing) + if item_type == 6 then ret = ImGui.InputTextMultiline("ITEM: InputTextMultiline", s.str, 16) end -- Testing input text (which uses a child window) + if item_type == 7 then col4f[1], ret = ImGui.InputFloat("ITEM: InputFloat", col4f[1], 1.0) end -- Testing +/- buttons on scalar input + if item_type == 8 then ret = ImGui.InputFloat3("ITEM: InputFloat3", col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) + if item_type == 9 then ret = ImGui.ColorEdit4("ITEM: ColorEdit4", col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) + if item_type == 10 then ret = ImGui.Selectable("ITEM: Selectable") end -- Testing selectable item + if item_type == 11 then ret = ImGui.MenuItem("ITEM: MenuItem") end -- Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) + if item_type == 12 then ret = ImGui.TreeNode("ITEM: TreeNode"); if ret then ImGui.TreePop() end end -- Testing tree node + if item_type == 13 then ret = ImGui.TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", bit32.bor(64 --[[ImGuiTreeNodeFlags.OpenOnDoubleClick]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]])) end -- Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if item_type == 14 then local items = { "Apple", "Banana", "Cherry", "Kiwi" }; s.current, ret = ImGui.Combo("ITEM: Combo", s.current, items, #items) end + if item_type == 15 then local items = { "Apple", "Banana", "Cherry", "Kiwi" }; s.current_2, ret = ImGui.ListBox("ITEM: ListBox", s.current_2, items, #items, #items) end + + local hovered_delay_none = ImGui.IsItemHovered() + local hovered_delay_stationary = ImGui.IsItemHovered(8192 --[[ImGuiHoveredFlags.Stationary]]) + local hovered_delay_short = ImGui.IsItemHovered(32768 --[[ImGuiHoveredFlags.DelayShort]]) + local hovered_delay_normal = ImGui.IsItemHovered(65536 --[[ImGuiHoveredFlags.DelayNormal]]) + local hovered_delay_tooltip = ImGui.IsItemHovered(4096 --[[ImGuiHoveredFlags.ForTooltip]]) -- = Normal + Stationary + + -- Display the values of IsItemHovered() and other common item state functions. + -- Note that the ImGuiHoveredFlags_XXX flags can be combined. + -- Because BulletText is an item itself and that would affect the output of IsItemXXX functions, + -- we query every state in a single call to avoid storing them and to simplify the code. + ImGui.BulletText( + "Return value = %d\n" .. + "IsItemFocused() = %d\n" .. + "IsItemHovered() = %d\n" .. + "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" .. + "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" .. + "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n" .. + "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n" .. + "IsItemHovered(_AllowWhenDisabled) = %d\n" .. + "IsItemHovered(_RectOnly) = %d\n" .. + "IsItemActive() = %d\n" .. + "IsItemEdited() = %d\n" .. + "IsItemActivated() = %d\n" .. + "IsItemDeactivated() = %d\n" .. + "IsItemDeactivatedAfterEdit() = %d\n" .. + "IsItemVisible() = %d\n" .. + "IsItemClicked() = %d\n" .. + "IsItemToggledOpen() = %d\n" .. + "GetItemRectMin() = (%.1f, %.1f)\n" .. + "GetItemRectMax() = (%.1f, %.1f)\n" .. + "GetItemRectSize() = (%.1f, %.1f)", + B(ret), + B(ImGui.IsItemFocused()), + B(ImGui.IsItemHovered()), + B(ImGui.IsItemHovered(32 --[[ImGuiHoveredFlags.AllowWhenBlockedByPopup]])), + B(ImGui.IsItemHovered(128 --[[ImGuiHoveredFlags.AllowWhenBlockedByActiveItem]])), + B(ImGui.IsItemHovered(256 --[[ImGuiHoveredFlags.AllowWhenOverlappedByItem]])), + B(ImGui.IsItemHovered(512 --[[ImGuiHoveredFlags.AllowWhenOverlappedByWindow]])), + B(ImGui.IsItemHovered(1024 --[[ImGuiHoveredFlags.AllowWhenDisabled]])), + B(ImGui.IsItemHovered(928 --[[ImGuiHoveredFlags.RectOnly]])), + B(ImGui.IsItemActive()), + B(ImGui.IsItemEdited()), + B(ImGui.IsItemActivated()), + B(ImGui.IsItemDeactivated()), + B(ImGui.IsItemDeactivatedAfterEdit()), + B(ImGui.IsItemVisible()), + B(ImGui.IsItemClicked()), + B(ImGui.IsItemToggledOpen()), + ImGui.GetItemRectMin().x, ImGui.GetItemRectMin().y, + ImGui.GetItemRectMax().x, ImGui.GetItemRectMax().y, + ImGui.GetItemRectSize().x, ImGui.GetItemRectSize().y + ) + ImGui.BulletText( + "with Hovering Delay or Stationary test:\n" .. + "IsItemHovered() = %d\n" .. + "IsItemHovered(_Stationary) = %d\n" .. + "IsItemHovered(_DelayShort) = %d\n" .. + "IsItemHovered(_DelayNormal) = %d\n" .. + "IsItemHovered(_Tooltip) = %d", + B(hovered_delay_none), B(hovered_delay_stationary), B(hovered_delay_short), B(hovered_delay_normal), B(hovered_delay_tooltip)) + + if s.liveedit_flags_override then + ImGui.PopItemFlag() + ImGui.PopItemFlag() + end + if s.item_mixedvalue then + ImGui.PopItemFlag() + end + if s.item_disabled then + ImGui.EndDisabled() + end + + local buf = ImGui.NewTextBuffer("", 1) + ImGui.InputText("unused", buf, 1, 512 --[[ImGuiInputTextFlags.ReadOnly]]) + ImGui.SameLine() + HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.") + + ImGui.TreePop() + end + + if ImGui.TreeNode("Querying Window Status (Focused/Hovered etc.)") then + IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)") + _, s.embed_all_inside_a_child_window = ImGui.Checkbox("Embed everything inside a child window for testing _RootWindow flag.", s.embed_all_inside_a_child_window) + if s.embed_all_inside_a_child_window then + ImGui.BeginChild("outer_child", ImVec2(0, ImGui.GetFontSize() * 20.0), 1 --[[ImGuiChildFlags.Borders]]) + end + + -- Testing IsWindowFocused() function with its various flags. + ImGui.BulletText( + "IsWindowFocused() = %d\n" .. + "IsWindowFocused(_ChildWindows) = %d\n" .. + "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" .. + "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n" .. + "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" .. + "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowFocused(_RootWindow) = %d\n" .. + "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowFocused(_AnyWindow) = %d\n", + B(ImGui.IsWindowFocused()), + B(ImGui.IsWindowFocused(1 --[[ImGuiFocusedFlags.ChildWindows]])), + B(ImGui.IsWindowFocused(bit32.bor(1 --[[ImGuiFocusedFlags.ChildWindows]], 8 --[[ImGuiFocusedFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowFocused(bit32.bor(1 --[[ImGuiFocusedFlags.ChildWindows]], 16 --[[ImGuiFocusedFlags.DockHierarchy]]))), + B(ImGui.IsWindowFocused(bit32.bor(1 --[[ImGuiFocusedFlags.ChildWindows]], 2 --[[ImGuiFocusedFlags.RootWindow]]))), + B(ImGui.IsWindowFocused(bit32.bor(1 --[[ImGuiFocusedFlags.ChildWindows]], 2 --[[ImGuiFocusedFlags.RootWindow]], 8 --[[ImGuiFocusedFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowFocused(bit32.bor(1 --[[ImGuiFocusedFlags.ChildWindows]], 2 --[[ImGuiFocusedFlags.RootWindow]], 16 --[[ImGuiFocusedFlags.DockHierarchy]]))), + B(ImGui.IsWindowFocused(2 --[[ImGuiFocusedFlags.RootWindow]])), + B(ImGui.IsWindowFocused(bit32.bor(2 --[[ImGuiFocusedFlags.RootWindow]], 8 --[[ImGuiFocusedFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowFocused(bit32.bor(2 --[[ImGuiFocusedFlags.RootWindow]], 16 --[[ImGuiFocusedFlags.DockHierarchy]]))), + B(ImGui.IsWindowFocused(4 --[[ImGuiFocusedFlags.AnyWindow]]))) + + -- Testing IsWindowHovered() function with its various flags. + ImGui.BulletText( + "IsWindowHovered() = %d\n" .. + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" .. + "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" .. + "IsWindowHovered(_ChildWindows) = %d\n" .. + "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" .. + "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowHovered(_RootWindow) = %d\n" .. + "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" .. + "IsWindowHovered(_AnyWindow) = %d\n" .. + "IsWindowHovered(_Stationary) = %d\n", + B(ImGui.IsWindowHovered()), + B(ImGui.IsWindowHovered(32 --[[ImGuiHoveredFlags.AllowWhenBlockedByPopup]])), + B(ImGui.IsWindowHovered(128 --[[ImGuiHoveredFlags.AllowWhenBlockedByActiveItem]])), + B(ImGui.IsWindowHovered(1 --[[ImGuiHoveredFlags.ChildWindows]])), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 8 --[[ImGuiHoveredFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 16 --[[ImGuiHoveredFlags.DockHierarchy]]))), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 2 --[[ImGuiHoveredFlags.RootWindow]]))), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 2 --[[ImGuiHoveredFlags.RootWindow]], 8 --[[ImGuiHoveredFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 2 --[[ImGuiHoveredFlags.RootWindow]], 16 --[[ImGuiHoveredFlags.DockHierarchy]]))), + B(ImGui.IsWindowHovered(2 --[[ImGuiHoveredFlags.RootWindow]])), + B(ImGui.IsWindowHovered(bit32.bor(2 --[[ImGuiHoveredFlags.RootWindow]], 8 --[[ImGuiHoveredFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowHovered(bit32.bor(2 --[[ImGuiHoveredFlags.RootWindow]], 16 --[[ImGuiHoveredFlags.DockHierarchy]]))), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 32 --[[ImGuiHoveredFlags.AllowWhenBlockedByPopup]]))), + B(ImGui.IsWindowHovered(4 --[[ImGuiHoveredFlags.AnyWindow]])), + B(ImGui.IsWindowHovered(8192 --[[ImGuiHoveredFlags.Stationary]]))) + + ImGui.BeginChild("child", ImVec2(0, 50), 1 --[[ImGuiChildFlags.Borders]]) + ImGui.Text("This is another child window for testing the _ChildWindows flag.") + ImGui.EndChild() + if s.embed_all_inside_a_child_window then + ImGui.EndChild() + end + + -- Calling IsItemHovered() after begin returns the hovered status of the title bar. + -- This is useful in particular if you want to create a context menu associated to the title bar of a window. + -- This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties). + _, s.test_window = ImGui.Checkbox("Hovered/Active tests after Begin() for title bar testing", s.test_window) + if s.test_window then + -- FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. + -- Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? + s.test_window = ImGui.Begin("Title bar Hovered/Active tests", s.test_window) + if ImGui.BeginPopupContextItem() then -- <-- This is using IsItemHovered() + if ImGui.MenuItem("Close") then s.test_window = false end + ImGui.EndPopup() + end + ImGui.Text( + "IsItemHovered() after begin = %d (== is title bar hovered)\n" .. + "IsItemActive() after begin = %d (== is window being clicked/moved)\n", + B(ImGui.IsItemHovered()), B(ImGui.IsItemActive())) + ImGui.End() + end + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsSelectables() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsSelectables = { + selection = { false, true, false, false, false }, -- Basic + selected_multi = { false, false, false }, -- Multiple items on the same line (1) + checked = { false, false, false, false, false }, -- Multiple items on the same line (2) + selected_n = 0, + selected_tables = { false, false, false, false, false, false, false, false, false, false }, -- In Tables + selected_grid = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }, -- Grid + selected_align = { true, false, true, false, true, false, true, false, true }, -- Alignment +} +-- [Port] The Selectable(label, bool* p_selected) overload doesn't exist in this port (Selectable returns pressed, selected +-- without toggling): written as `if ImGui.Selectable(label, sel) then sel = not sel end`. +function DemoWindowWidgetsSelectables() + local s = S.DemoWindowWidgetsSelectables + -- ImGui.SetNextItemOpen(true, ImGuiCond.Once) + if ImGui.TreeNode("Selectables") then + IMGUI_DEMO_MARKER("Widgets/Selectables") + -- Selectable() has 2 overloads: + -- - The one taking "bool selected" as a read-only selection information. + -- When Selectable() has been clicked it returns true and you can alter selection state accordingly. + -- - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) + -- The earlier is more flexible, as in real application your selection may be stored in many different ways + -- and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). + IMGUI_DEMO_MARKER("Widgets/Selectables/Basic") + if ImGui.TreeNode("Basic") then + local selection = s.selection + if ImGui.Selectable("1. I am selectable", selection[1]) then selection[1] = not selection[1] end + if ImGui.Selectable("2. I am selectable", selection[2]) then selection[2] = not selection[2] end + if ImGui.Selectable("3. I am selectable", selection[3]) then selection[3] = not selection[3] end + if ImGui.Selectable("4. I am double clickable", selection[4], 4 --[[ImGuiSelectableFlags.AllowDoubleClick]]) then + if ImGui.IsMouseDoubleClicked(0) then + selection[4] = not selection[4] + end + end + ImGui.TreePop() + end + + IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line") + if ImGui.TreeNode("Multiple items on the same line") then + IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple items on the same line") + -- - Using SetNextItemAllowOverlap() + -- - Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. + do + local selected = s.selected_multi + ImGui.SetNextItemAllowOverlap(); if ImGui.Selectable("main.c", selected[1]) then selected[1] = not selected[1] end; ImGui.SameLine(); ImGui.SmallButton("Link 1") + ImGui.SetNextItemAllowOverlap(); if ImGui.Selectable("hello.cpp", selected[2]) then selected[2] = not selected[2] end; ImGui.SameLine(); ImGui.SmallButton("Link 2") + ImGui.SetNextItemAllowOverlap(); if ImGui.Selectable("hello.h", selected[3]) then selected[3] = not selected[3] end; ImGui.SameLine(); ImGui.SmallButton("Link 3") + end + + -- (2) + -- - Using ImGuiSelectableFlags_AllowOverlap is a shortcut for calling SetNextItemAllowOverlap() + -- - No visible label, display contents inside the selectable bounds. + -- - We don't maintain actual selection in this example to keep things simple. + ImGui.Spacing() + do + local checked = s.checked + local color_marker_w = ImGui.CalcTextSize("x").x + for n = 0, 4 do + ImGui.PushID(n) + ImGui.AlignTextToFramePadding() + if ImGui.Selectable("##selectable", s.selected_n == n, 16 --[[ImGuiSelectableFlags.AllowOverlap]]) then + s.selected_n = n + end + ImGui.SameLine(0, 0) + _, checked[n + 1] = ImGui.Checkbox("##check", checked[n + 1]) + ImGui.SameLine() + local color = ImVec4(bit32.band(n, 1) ~= 0 and 1.0 or 0.2, bit32.band(n, 2) ~= 0 and 1.0 or 0.2, 0.2, 1.0) + ImGui.ColorButton("##color", color, 64 --[[ImGuiColorEditFlags.NoTooltip]], ImVec2(color_marker_w, 0)) + ImGui.SameLine() + ImGui.Text("Some label") + ImGui.PopID() + end + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("In Tables") then + IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables") + local selected = s.selected_tables + + if ImGui.BeginTable("split1", 3, bit32.bor(1 --[[ImGuiTableFlags.Resizable]], 16 --[[ImGuiTableFlags.NoSavedSettings]], 1920 --[[ImGuiTableFlags.Borders]])) then + for i = 0, 9 do + local label = string.format("Item %d", i) + ImGui.TableNextColumn() + if ImGui.Selectable(label, selected[i + 1]) then selected[i + 1] = not selected[i + 1] end -- FIXME-TABLE: Selection overlap + end + ImGui.EndTable() + end + ImGui.Spacing() + if ImGui.BeginTable("split2", 3, bit32.bor(1 --[[ImGuiTableFlags.Resizable]], 16 --[[ImGuiTableFlags.NoSavedSettings]], 1920 --[[ImGuiTableFlags.Borders]])) then + for i = 0, 9 do + local label = string.format("Item %d", i) + ImGui.TableNextRow() + ImGui.TableNextColumn() + if ImGui.Selectable(label, selected[i + 1], 2 --[[ImGuiSelectableFlags.SpanAllColumns]]) then selected[i + 1] = not selected[i + 1] end + ImGui.TableNextColumn() + ImGui.Text("Some other contents") + ImGui.TableNextColumn() + ImGui.Text("123456") + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Grid") then + IMGUI_DEMO_MARKER("Widgets/Selectables/Grid") + local selected = s.selected_grid + + -- Add in a bit of silly fun... + local time = ImGui.GetTime() + local winning_state = true -- If all cells are selected... + for y = 1, 4 do for x = 1, 4 do if selected[y][x] == 0 then winning_state = false end end end -- [Port] memchr(selected, 0, sizeof(selected)) == NULL + if winning_state then + ImGui.PushStyleVar(39 --[[ImGuiStyleVar.SelectableTextAlign]], ImVec2(0.5 + 0.5 * math.cos(time * 2.0), 0.5 + 0.5 * math.sin(time * 3.0))) + end + + local size = ImGui.CalcTextSize("Sailor").x + for y = 0, 3 do + for x = 0, 3 do + if x > 0 then + ImGui.SameLine() + end + ImGui.PushID(y * 4 + x) + if ImGui.Selectable("Sailor", selected[y + 1][x + 1] ~= 0, 0, ImVec2(size, size)) then + -- Toggle clicked cell + toggle neighbors + selected[y + 1][x + 1] = bit32.bxor(selected[y + 1][x + 1], 1) + if x > 0 then selected[y + 1][x] = bit32.bxor(selected[y + 1][x], 1) end + if x < 3 then selected[y + 1][x + 2] = bit32.bxor(selected[y + 1][x + 2], 1) end + if y > 0 then selected[y][x + 1] = bit32.bxor(selected[y][x + 1], 1) end + if y < 3 then selected[y + 2][x + 1] = bit32.bxor(selected[y + 2][x + 1], 1) end + end + ImGui.PopID() + end + end + + if winning_state then + ImGui.PopStyleVar() + end + ImGui.TreePop() + end + if ImGui.TreeNode("Alignment") then + IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment") + HelpMarker( + "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " .. + "basis using PushStyleVar(). You'll probably want to always keep your default situation to " .. + "left-align otherwise it becomes difficult to layout multiple items on a same line") + + local selected = s.selected_align + local size = ImGui.CalcTextSize("(1.0,1.0)").x + for y = 0, 2 do + for x = 0, 2 do + local alignment = ImVec2(x / 2.0, y / 2.0) + local name = string.format("(%.1f,%.1f)", alignment.x, alignment.y) + if x > 0 then ImGui.SameLine() end + ImGui.PushStyleVar(39 --[[ImGuiStyleVar.SelectableTextAlign]], alignment) + local idx = 3 * y + x + 1 + if ImGui.Selectable(name, selected[idx], 0 --[[ImGuiSelectableFlags.None]], ImVec2(size, size)) then selected[idx] = not selected[idx] end + ImGui.PopStyleVar() + end + end + ImGui.TreePop() end ImGui.TreePop() end end --- Demonstrate most Dear ImGui features (this is big function!) --- You may execute this function to experiment with the UI and understand what it does. --- You may then search for keywords in the code when you are interested by a specific feature. ---- @param p_open? bool ---- @return bool? p_open -function ImGui.ShowDemoWindow(p_open) - -- Exceptionally add an extra assert here for people confused about initial Dear ImGui setup - -- Most functions would normally just assert/crash if the context is missing. - assert(ImGui.GetCurrentContext() ~= nil, "Missing Dear ImGui context. Refer to examples app!") +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsSelectionAndMultiSelect() +------------------------------------------------------------------------------- +-- Multi-selection demos +-- Also read: https://github.com/ocornut/imgui/wiki/Multi-Select +------------------------------------------------------------------------------- - local data = demo_data +ExampleNames = +{ + "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper", + "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava", + "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber" +} - -- Examples Apps (accessible from the "Examples" menu) - if data.ShowMainMenuBar then - if ShowExampleAppMainMenuBar then ShowExampleAppMainMenuBar() end +function DemoWindowWidgetsSelectionAndMultiSelect(demo_data) + if ImGui.TreeNode("Selection State & Multi-Select") then + IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select") + HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.") + ImGui.TextDisabled("(multi-select API not ported yet)") -- [Port] TODO: BeginMultiSelect()/EndMultiSelect() + ImGui.TreePop() end - if data.ShowAppDockSpace then RunApp(ShowExampleAppDockSpace, "ShowAppDockSpace") end -- Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) - if data.ShowAppDocuments then RunApp(ShowExampleAppDocuments, "ShowAppDocuments") end -- ...process the Document app next, as it may also use a DockSpace() - if data.ShowAppAssetsBrowser then RunApp(ShowExampleAppAssetsBrowser, "ShowAppAssetsBrowser") end - if data.ShowAppConsole then RunApp(ShowExampleAppConsole, "ShowAppConsole") end - if data.ShowAppCustomRendering then RunApp(ShowExampleAppCustomRendering, "ShowAppCustomRendering") end - if data.ShowAppImageViewer then RunApp(ShowExampleAppImageViewer, "ShowAppImageViewer") end - if data.ShowAppLog then RunApp(ShowExampleAppLog, "ShowAppLog") end - if data.ShowAppLayout then RunApp(ShowExampleAppLayout, "ShowAppLayout") end - if data.ShowAppPropertyEditor then RunApp(ShowExampleAppPropertyEditor, "ShowAppPropertyEditor", data) end - if data.ShowAppSimpleOverlay then RunApp(ShowExampleAppSimpleOverlay, "ShowAppSimpleOverlay") end - if data.ShowAppAutoResize then RunApp(ShowExampleAppAutoResize, "ShowAppAutoResize") end - if data.ShowAppConstrainedResize then RunApp(ShowExampleAppConstrainedResize, "ShowAppConstrainedResize") end - if data.ShowAppFullscreen then RunApp(ShowExampleAppFullscreen, "ShowAppFullscreen") end - if data.ShowAppLongText then RunApp(ShowExampleAppLongText, "ShowAppLongText") end - if data.ShowAppWindowTitles then RunApp(ShowExampleAppWindowTitles, "ShowAppWindowTitles") end +end - -- Dear ImGui Tools (accessible from the "Tools" menu) - if data.ShowMetrics then RunApp(ImGui.ShowMetricsWindow, "ShowMetrics") end - if data.ShowDebugLog then RunApp(ImGui.ShowDebugLogWindow, "ShowDebugLog") end - if data.ShowIDStackTool then RunApp(ImGui.ShowIDStackToolWindow, "ShowIDStackTool") end - if data.ShowAbout then RunApp(ImGui.ShowAboutWindow, "ShowAbout") end - if data.ShowStyleEditor then - local visible - data.ShowStyleEditor, visible = ImGui.Begin("Dear ImGui Style Editor", data.ShowStyleEditor) - if visible then - ImGui.ShowStyleEditor() +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTabs() +------------------------------------------------------------------------------- + +-- [Port] ImGuiTabBarFlags* p_flags -> takes flags, returns the new flags +function EditTabBarFittingPolicyFlags(p_flags) + if bit32.band(p_flags, 896 --[[ImGuiTabBarFlags.FittingPolicyMask_]]) == 0 then + p_flags = bit32.bor(p_flags, 128 --[[ImGuiTabBarFlags.FittingPolicyDefault_]]) + end + local pressed + pressed, p_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyMixed", p_flags, 128 --[[ImGuiTabBarFlags.FittingPolicyMixed]]) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(896 --[[ImGuiTabBarFlags.FittingPolicyMask_]], 128 --[[ImGuiTabBarFlags.FittingPolicyMixed]]))) + end + pressed, p_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyShrink", p_flags, 256 --[[ImGuiTabBarFlags.FittingPolicyShrink]]) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(896 --[[ImGuiTabBarFlags.FittingPolicyMask_]], 256 --[[ImGuiTabBarFlags.FittingPolicyShrink]]))) + end + pressed, p_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", p_flags, 512 --[[ImGuiTabBarFlags.FittingPolicyScroll]]) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(896 --[[ImGuiTabBarFlags.FittingPolicyMask_]], 512 --[[ImGuiTabBarFlags.FittingPolicyScroll]]))) + end + return p_flags +end + +S.DemoWindowWidgetsTabs = { + tab_bar_flags = ImGuiTabBarFlags.Reorderable, + opened = { true, true, true, true }, -- Persistent user state + active_tabs = ImVector(), + next_tab_id = 0, + show_leading_button = true, + show_trailing_button = true, + show_leading_trailing_tabs = false, + tab_bar_flags_2 = bit32.bor(ImGuiTabBarFlags.AutoSelectNewTabs, ImGuiTabBarFlags.Reorderable, ImGuiTabBarFlags.FittingPolicyMixed), +} +function DemoWindowWidgetsTabs() + local s = S.DemoWindowWidgetsTabs + if ImGui.TreeNode("Tabs") then + IMGUI_DEMO_MARKER("Widgets/Tabs") + if ImGui.TreeNode("Basic") then + IMGUI_DEMO_MARKER("Widgets/Tabs/Basic") + local tab_bar_flags = 0 --[[ImGuiTabBarFlags.None]] + if ImGui.BeginTabBar("MyTabBar", tab_bar_flags) then + if ImGui.BeginTabItem("Avocado") then + ImGui.Text("This is the Avocado tab!\nblah blah blah blah blah") + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Broccoli") then + ImGui.Text("This is the Broccoli tab!\nblah blah blah blah blah") + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Cucumber") then + ImGui.Text("This is the Cucumber tab!\nblah blah blah blah blah") + ImGui.EndTabItem() + end + ImGui.EndTabBar() + end + ImGui.Separator() + ImGui.TreePop() end - ImGui.End() - end - -- Demonstrate the various window flags. Typically you would just use the default! - local W = ImGuiWindowFlags - local window_flags = 0 - if no_titlebar then window_flags = bit32.bor(window_flags, W.NoTitleBar) end - if no_scrollbar then window_flags = bit32.bor(window_flags, W.NoScrollbar) end - if not no_menu then window_flags = bit32.bor(window_flags, W.MenuBar) end - if no_move then window_flags = bit32.bor(window_flags, W.NoMove) end - if no_resize then window_flags = bit32.bor(window_flags, W.NoResize) end - if no_collapse then window_flags = bit32.bor(window_flags, W.NoCollapse) end - if no_nav then window_flags = bit32.bor(window_flags, W.NoNav) end - if no_background then window_flags = bit32.bor(window_flags, W.NoBackground) end - if no_bring_to_front then window_flags = bit32.bor(window_flags, W.NoBringToFrontOnFocus) end - if no_docking then window_flags = bit32.bor(window_flags, W.NoDocking) end - if unsaved_document then window_flags = bit32.bor(window_flags, W.UnsavedDocument) end - if no_close then p_open = nil end -- Don't pass our bool* to Begin + if ImGui.TreeNode("Advanced & Close Button") then + IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button") + -- Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_Reorderable", s.tab_bar_flags, 1 --[[ImGuiTabBarFlags.Reorderable]]) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", s.tab_bar_flags, 2 --[[ImGuiTabBarFlags.AutoSelectNewTabs]]) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", s.tab_bar_flags, 4 --[[ImGuiTabBarFlags.TabListPopupButton]]) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", s.tab_bar_flags, 8 --[[ImGuiTabBarFlags.NoCloseWithMiddleMouseButton]]) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", s.tab_bar_flags, 64 --[[ImGuiTabBarFlags.DrawSelectedOverline]]) + s.tab_bar_flags = EditTabBarFittingPolicyFlags(s.tab_bar_flags) - -- We specify a default position/size in case there's no data in the .ini file. - -- We only do it to make the demo applications a little more welcoming, but typically this isn't required. - local main_viewport = ImGui.GetMainViewport() - ImGui.SetNextWindowPos(ImVec2(main_viewport.WorkPos.x + 650, main_viewport.WorkPos.y + 20), 4 --[[ImGuiCond.FirstUseEver]]) - ImGui.SetNextWindowSize(ImVec2(550, 680), 4 --[[ImGuiCond.FirstUseEver]]) + -- Tab Bar + ImGui.AlignTextToFramePadding() + ImGui.Text("Opened:") + local names = { "Artichoke", "Beetroot", "Celery", "Daikon" } + local opened = s.opened -- Persistent user state + for n = 0, #opened - 1 do + ImGui.SameLine() + _, opened[n + 1] = ImGui.Checkbox(names[n + 1], opened[n + 1]) + end - -- Main body of the Demo window starts here. - local visible - p_open, visible = ImGui.Begin("Dear ImGui Demo", p_open, window_flags) - if no_close then p_open = nil end - if not visible then - -- Early out if the window is collapsed, as an optimization. - ImGui.End() - return p_open - end - - -- Most framed widgets share a common width settings. Remaining width is used for the label. - -- The width of the frame may be changed with PushItemWidth() or SetNextItemWidth(). - -- - Positive value for absolute size, negative value for right-alignment. - -- - The default value is about GetWindowWidth() * 0.65f. - -- - See 'Demo->Layout->Widgets Width' for details. - -- Here we change the frame width based on how much width we want to give to the label. - local label_width_base = ImGui.GetFontSize() * 12 -- Some amount of width for label, based on font size. - local label_width_max = ImGui.GetContentRegionAvail().x * 0.40 -- ...but always leave some room for framed widgets. - local label_width = math.min(label_width_base, label_width_max) - ImGui.PushItemWidth(-label_width) -- Right-align: framed items will leave 'label_width' available for the label. - -- ImGui.PushItemWidth(ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for framed widgets, leaving 60% width for labels. - -- ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for labels, leaving 60% width for framed widgets. - -- ImGui.PushItemWidth(ImGui.GetFontSize() * -12) -- e.g. Use XXX width for labels, leaving the rest for framed widgets. - - -- Menu Bar - DemoWindowMenuBar(data) - - ImGui.Text("Dear ImGui says hello! (%s) (%d)", IMGUI_VERSION or "WIP", 19298 --[[IMGUI_VERSION_NUM]] or 0) - ImGui.Spacing() - - if ImGui.CollapsingHeader("Help") then - IMGUI_DEMO_MARKER("Help") - ImGui.SeparatorText("ABOUT THIS DEMO:") - ImGui.BulletText("Sections below are demonstrating many aspects of the library.") - ImGui.BulletText("The \"Examples\" menu above leads to more demo contents.") - ImGui.BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" .. - "and Metrics/Debugger (general purpose Dear ImGui debugging tool).") - ImGui.BulletText("Web demo (w/ source code browser): ") - ImGui.SameLine(0, 0) - ImGui.TextLinkOpenURL("https://pthom.github.io/imgui_explorer") - - ImGui.SeparatorText("PROGRAMMER GUIDE:") - ImGui.BulletText("See the ShowDemoWindow() code in imgui_demo.lua. <- you are here!") - ImGui.BulletText("See comments in imgui.lua.") - ImGui.BulletText("See example applications in the examples/ folder.") - ImGui.BulletText("Read the FAQ at ") - ImGui.SameLine(0, 0) - ImGui.TextLinkOpenURL("https://www.dearimgui.com/faq/") - ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.") - ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.") - - ImGui.SeparatorText("USER GUIDE:") - ImGui.ShowUserGuide() - end - - if ImGui.CollapsingHeader("Configuration") then - DemoWindowConfiguration(ImGui.GetIO()) - end - - if ImGui.CollapsingHeader("Window options") then - IMGUI_DEMO_MARKER("Window options") - if ImGui.BeginTable("split", 3) then - ImGui.TableNextColumn(); _, no_titlebar = ImGui.Checkbox("No titlebar", no_titlebar) - ImGui.TableNextColumn(); _, no_scrollbar = ImGui.Checkbox("No scrollbar", no_scrollbar) - ImGui.TableNextColumn(); _, no_menu = ImGui.Checkbox("No menu", no_menu) - ImGui.TableNextColumn(); _, no_move = ImGui.Checkbox("No move", no_move) - ImGui.TableNextColumn(); _, no_resize = ImGui.Checkbox("No resize", no_resize) - ImGui.TableNextColumn(); _, no_collapse = ImGui.Checkbox("No collapse", no_collapse) - ImGui.TableNextColumn(); _, no_close = ImGui.Checkbox("No close", no_close) - ImGui.TableNextColumn(); _, no_nav = ImGui.Checkbox("No nav", no_nav) - ImGui.TableNextColumn(); _, no_background = ImGui.Checkbox("No background", no_background) - ImGui.TableNextColumn(); _, no_bring_to_front = ImGui.Checkbox("No bring to front", no_bring_to_front) - ImGui.TableNextColumn(); _, no_docking = ImGui.Checkbox("No docking", no_docking) - ImGui.TableNextColumn(); _, unsaved_document = ImGui.Checkbox("Unsaved document", unsaved_document) - ImGui.EndTable() + -- Passing a bool* to BeginTabItem() is similar to passing one to Begin(): + -- the underlying bool will be set to false when the tab is closed. + if ImGui.BeginTabBar("MyTabBar", s.tab_bar_flags) then + for n = 0, #opened - 1 do + if opened[n + 1] then + local visible + visible, opened[n + 1] = ImGui.BeginTabItem(names[n + 1], opened[n + 1], 0 --[[ImGuiTabItemFlags.None]]) + if visible then + ImGui.Text("This is the %s tab!", names[n + 1]) + if bit32.band(n, 1) ~= 0 then + ImGui.Text("I am an odd tab.") + end + ImGui.EndTabItem() + end + end + end + ImGui.EndTabBar() + end + ImGui.Separator() + ImGui.TreePop() end + + if ImGui.TreeNode("TabItemButton & Leading/Trailing flags") then + IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags") + local active_tabs = s.active_tabs + if s.next_tab_id == 0 then -- Initialize with some default tabs + for i = 0, 2 do + active_tabs:push_back(s.next_tab_id); s.next_tab_id = s.next_tab_id + 1 + end + end + + -- TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. + -- (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... + -- but they tend to make more sense together) + _, s.show_leading_button = ImGui.Checkbox("Show Leading TabItemButton()", s.show_leading_button) + _, s.show_trailing_button = ImGui.Checkbox("Show Trailing TabItemButton()", s.show_trailing_button) + _, s.show_leading_trailing_tabs = ImGui.Checkbox("Show Leading+Trailing TabItem()", s.show_leading_trailing_tabs) + + -- Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs + s.tab_bar_flags_2 = EditTabBarFittingPolicyFlags(s.tab_bar_flags_2) + + if ImGui.BeginTabBar("MyTabBar", s.tab_bar_flags_2) then + -- Demo a Leading TabItemButton(): click the "?" button to open a menu + if s.show_leading_button then + if ImGui.TabItemButton("?", bit32.bor(64 --[[ImGuiTabItemFlags.Leading]], 16 --[[ImGuiTabItemFlags.NoTooltip]])) then + ImGui.OpenPopup("MyHelpMenu") + end + end + if ImGui.BeginPopup("MyHelpMenu") then + ImGui.Selectable("Hello!") + ImGui.EndPopup() + end + + -- Demo Leading/Trailing Tabs + if s.show_leading_trailing_tabs then + if ImGui.BeginTabItem("Leading", nil, 64 --[[ImGuiTabItemFlags.Leading]]) then + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Trailing", nil, 128 --[[ImGuiTabItemFlags.Trailing]]) then + ImGui.EndTabItem() + end + end + + -- Demo Trailing Tabs: click the "+" button to add a new tab. + -- (In your app you may want to use a font icon instead of the "+") + -- We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end. + if s.show_trailing_button then + if ImGui.TabItemButton("+", bit32.bor(128 --[[ImGuiTabItemFlags.Trailing]], 16 --[[ImGuiTabItemFlags.NoTooltip]])) then + active_tabs:push_back(s.next_tab_id); s.next_tab_id = s.next_tab_id + 1 -- Add new tab + end + end + + -- Submit our regular tabs + local n = 0 + while n < active_tabs.Size do + local open = true + local name = string.format("%04d", active_tabs.Data[n + 1]) + local visible + visible, open = ImGui.BeginTabItem(name, open, 0 --[[ImGuiTabItemFlags.None]]) + if visible then + ImGui.Text("This is the %s tab!", name) + ImGui.EndTabItem() + end + + if not open then + active_tabs:erase(n + 1) + else + n = n + 1 + end + end + + ImGui.EndTabBar() + end + ImGui.Separator() + ImGui.TreePop() + end + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsText() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsText = { + custom_size = 16.0, + custom_scale = 1.0, + wrap_width = 200.0, + buf = ImGui.NewTextBuffer("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e", 32), +} +function DemoWindowWidgetsText() + local s = S.DemoWindowWidgetsText + if ImGui.TreeNode("Text") then + IMGUI_DEMO_MARKER("Widgets/Text") + if ImGui.TreeNode("Colorful Text") then + IMGUI_DEMO_MARKER("Widgets/Text/Colored Text") + -- Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. + ImGui.TextColored(ImVec4(1.0, 0.0, 1.0, 1.0), "Pink") + ImGui.TextColored(ImVec4(1.0, 1.0, 0.0, 1.0), "Yellow") + ImGui.TextDisabled("Disabled") + ImGui.SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.") + ImGui.TreePop() + end + + if ImGui.TreeNode("Font Size") then + IMGUI_DEMO_MARKER("Widgets/Text/Font Size") + local style = ImGui.GetStyle() + local global_scale = style.FontScaleMain * style.FontScaleDpi + ImGui.Text("style.FontScaleMain = %0.2f", style.FontScaleMain) + ImGui.Text("style.FontScaleDpi = %0.2f", style.FontScaleDpi) + ImGui.Text("global_scale = ~%0.2f", global_scale) -- This is not technically accurate as internal scales may apply, but conceptually let's pretend it is. + ImGui.Text("FontSize = %0.2f", ImGui.GetFontSize()) + + ImGui.SeparatorText("") + s.custom_size = ImGui.SliderFloat("custom_size", s.custom_size, 10.0, 100.0, "%.0f") + ImGui.Text("ImGui::PushFont(nullptr, custom_size);") + ImGui.PushFont(nil, s.custom_size) + ImGui.Text("FontSize = %.2f (== %.2f * global_scale)", ImGui.GetFontSize(), s.custom_size) + ImGui.PopFont() + + ImGui.SeparatorText("") + s.custom_scale = ImGui.SliderFloat("custom_scale", s.custom_scale, 0.5, 4.0, "%.2f") + ImGui.Text("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scale);") + ImGui.PushFont(nil, style.FontSizeBase * s.custom_scale) + ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), s.custom_scale) + ImGui.PopFont() + + ImGui.SeparatorText("") + local scaling = 0.5 + while scaling <= 4.0 do + ImGui.PushFont(nil, style.FontSizeBase * scaling) + ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), scaling) + ImGui.PopFont() + scaling = scaling + 0.5 + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Word Wrapping") then + IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping") + -- Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. + ImGui.TextWrapped( + "This text should automatically wrap on the edge of the window. The current implementation " .. + "for text wrapping follows simple rules suitable for English and possibly other languages.") + ImGui.Spacing() + + s.wrap_width = ImGui.SliderFloat("Wrap width", s.wrap_width, -20, 600, "%.0f") + + local draw_list = ImGui.GetWindowDrawList() + for n = 0, 1 do + ImGui.Text("Test paragraph %d:", n) + local pos = ImGui.GetCursorScreenPos() + local marker_min = ImVec2(pos.x + s.wrap_width, pos.y) + local marker_max = ImVec2(pos.x + s.wrap_width + 10, pos.y + ImGui.GetTextLineHeight()) + ImGui.PushTextWrapPos(ImGui.GetCursorPos().x + s.wrap_width) + if n == 0 then + ImGui.Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", s.wrap_width) + else + ImGui.Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh") + end + + -- Draw actual text bounding box, following by marker of our expected limit (should not overlap!) + draw_list:AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), IM_COL32(255, 255, 0, 255)) + draw_list:AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)) + ImGui.PopTextWrapPos() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("UTF-8 Text") then + IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text") + -- UTF-8 test with Japanese characters + -- (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) + -- - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 + -- - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you + -- can save your source files as 'UTF-8 without signature'). + -- - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 + -- CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. + -- Don't do this in your application! Please use u8"text in any language" in your application! + -- Note that characters values are preserved even by InputText() if the font cannot be displayed, + -- so you can safely copy & paste garbled characters into another application. + ImGui.TextWrapped( + "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. " .. + "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. " .. + "Read docs/FONTS.md for details.") + ImGui.Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)") + ImGui.Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)") + --static char buf[32] = u8"NIHONGO"; -- <- this is how you would write it with C++11, using real kanjis + ImGui.InputText("UTF-8 input", s.buf, 32) + ImGui.TreePop() + end + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTextFilter() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTextFilter = { + filter = ImGuiTextFilter(), +} +function DemoWindowWidgetsTextFilter() + local s = S.DemoWindowWidgetsTextFilter + if ImGui.TreeNode("Text Filter") then + IMGUI_DEMO_MARKER("Widgets/Text Filter") + -- Helper class to easy setup a text filter. + -- You may want to implement a more feature-full filtering scheme in your own application. + HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.") + local filter = s.filter + ImGui.Text("Filter usage:\n" .. + " \"\" display all lines\n" .. + " xxx display lines containing \"xxx\"\n" .. + " xxx yyy display lines containing \"xxx\" and \"yyy\"\n" .. + " \"xxx yyy\" display lines containing \"xxx yyy\"\n" .. + " xxx,yyy display lines containing \"xxx\" or \"yyy\"\n" .. + " -xxx hide lines containing \"xxx\"") + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + filter:DrawWithHint("##Filter", "Filter (incl -excl)") + if ImGui.BeginChild("##items", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeightWithSpacing() * 15), 128 --[[ImGuiChildFlags.FrameStyle]]) then + local lines = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" } + for _, item in ipairs(lines) do + if filter:PassFilter(item) then + ImGui.TextUnformatted(item) + end + end + for _, item in ipairs(ExampleNames) do + if filter:PassFilter(item) then + ImGui.TextUnformatted(item) + end + end + end + ImGui.EndChild() + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTextInput() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTextInput = { + -- "Multi-line Text Input" + ml = { + text = ImGui.NewTextBuffer( + "/*\n" .. + " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" .. + " the hexadecimal encoding of one offending instruction,\n" .. + " more formally, the invalid operand with locked CMPXCHG8B\n" .. + " instruction bug, is a design flaw in the majority of\n" .. + " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" .. + " processors (all in the P5 microarchitecture).\n" .. + "*/\n\n" .. + "label:\n" .. + "\tlock cmpxchg8b eax\n", 1024 * 16), + flags = ImGuiInputTextFlags.AllowTabInput, + }, + -- "Filtered Text Input" + filtered = { + buf1 = ImGui.NewTextBuffer("", 32), buf2 = ImGui.NewTextBuffer("", 32), buf3 = ImGui.NewTextBuffer("", 32), + buf4 = ImGui.NewTextBuffer("", 32), buf5 = ImGui.NewTextBuffer("", 32), buf6 = ImGui.NewTextBuffer("", 32), + buf7 = ImGui.NewTextBuffer("", 32), + }, + -- "Password Input" + password = { password = ImGui.NewTextBuffer("password123", 64) }, + -- "Completion, History, Edit Callbacks" + callbacks = { + buf1 = ImGui.NewTextBuffer("", 64), buf2 = ImGui.NewTextBuffer("", 64), buf3 = ImGui.NewTextBuffer("", 64), + edit_count = 0, + }, + -- "Resize Callback" + resize = { flags = ImGuiInputTextFlags.None, my_str = ImVector() }, + -- "Eliding, Alignment" + eliding = { buf1 = ImGui.NewTextBuffer("/path/to/some/folder/with/long/filename.cpp", 128), flags = ImGuiInputTextFlags.ElideLeft }, + -- "Miscellaneous" + misc = { buf1 = ImGui.NewTextBuffer("", 16), flags = ImGuiInputTextFlags.EscapeClearsAll }, +} +function DemoWindowWidgetsTextInput() + local S_ti = S.DemoWindowWidgetsTextInput + -- To wire InputText() with std::string or any other custom string type, + -- see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + if ImGui.TreeNode("Text Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input") + if ImGui.TreeNode("Multi-line Text Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input") + local s = S_ti.ml + -- WE ARE USING A FIXED-SIZE BUFFER FOR SIMPLICITY HERE. + -- If you want to use InputText() with std::string or any custom dynamic string type: + -- - For std::string: use the wrapper in misc/cpp/imgui_stdlib.h/.cpp + -- - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize. + HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include in here)") + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, 512 --[[ImGuiInputTextFlags.ReadOnly]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_WordWrap", s.flags, 16777216 --[[ImGuiInputTextFlags.WordWrap]]) + ImGui.SameLine(); HelpMarker("Feature is currently in Beta. Please read comments in imgui.h") + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", s.flags, 32 --[[ImGuiInputTextFlags.AllowTabInput]]) + ImGui.SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets.") + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", s.flags, 256 --[[ImGuiInputTextFlags.CtrlEnterForNewLine]]) + ImGui.InputTextMultiline("##source", s.text, 1024 * 16, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeight() * 16), s.flags) + ImGui.TreePop() + end + + if ImGui.TreeNode("Filtered Text Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input") + local s = S_ti.filtered + local TextFilters = {} + -- Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback) + function TextFilters.FilterCasingSwap(data) + if data.EventChar >= string.byte('a') and data.EventChar <= string.byte('z') then data.EventChar = data.EventChar - (string.byte('a') - string.byte('A')) -- Lowercase becomes uppercase + elseif data.EventChar >= string.byte('A') and data.EventChar <= string.byte('Z') then data.EventChar = data.EventChar + (string.byte('a') - string.byte('A')) end -- Uppercase becomes lowercase + return 0 + end + + -- Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) + function TextFilters.FilterImGuiLetters(data) + if data.EventChar < 256 and string.find("imgui", string.char(data.EventChar), 1, true) then + return 0 + end + return 1 + end + + ImGui.InputText("default", s.buf1, 32) + ImGui.InputText("decimal", s.buf2, 32, 1 --[[ImGuiInputTextFlags.CharsDecimal]]) + ImGui.InputText("hexadecimal", s.buf3, 32, bit32.bor(2 --[[ImGuiInputTextFlags.CharsHexadecimal]], 8 --[[ImGuiInputTextFlags.CharsUppercase]])) + ImGui.InputText("uppercase", s.buf4, 32, 8 --[[ImGuiInputTextFlags.CharsUppercase]]) + ImGui.InputText("no blank", s.buf5, 32, 16 --[[ImGuiInputTextFlags.CharsNoBlank]]) + ImGui.InputText("casing swap", s.buf6, 32, 2097152 --[[ImGuiInputTextFlags.CallbackCharFilter]], TextFilters.FilterCasingSwap) -- Use CharFilter callback to replace characters. + ImGui.InputText("\"imgui\"", s.buf7, 32, 2097152 --[[ImGuiInputTextFlags.CallbackCharFilter]], TextFilters.FilterImGuiLetters) -- Use CharFilter callback to disable some characters. + ImGui.TreePop() + end + + if ImGui.TreeNode("Password Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Password input") + local s = S_ti.password + ImGui.InputText("password", s.password, 64, 1024 --[[ImGuiInputTextFlags.Password]]) + ImGui.SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n") + ImGui.InputTextWithHint("password (w/ hint)", "", s.password, 64, 1024 --[[ImGuiInputTextFlags.Password]]) + ImGui.InputText("password (clear)", s.password, 64) + ImGui.TreePop() + end + + if ImGui.TreeNode("Completion, History, Edit Callbacks") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks") + local s = S_ti.callbacks + local Funcs = {} + function Funcs.MyCallback(data) + if data.EventFlag == 262144 --[[ImGuiInputTextFlags.CallbackCompletion]] then + data:InsertChars(data.CursorPos, "..") + elseif data.EventFlag == 524288 --[[ImGuiInputTextFlags.CallbackHistory]] then + if data.EventKey == 515 --[[ImGuiKey.UpArrow]] then + data:DeleteChars(0, data.BufTextLen) + data:InsertChars(0, "Pressed Up!") + data:SelectAll() + elseif data.EventKey == 516 --[[ImGuiKey.DownArrow]] then + data:DeleteChars(0, data.BufTextLen) + data:InsertChars(0, "Pressed Down!") + data:SelectAll() + end + elseif data.EventFlag == 8388608 --[[ImGuiInputTextFlags.CallbackEdit]] then + -- Toggle casing of first character + local c = data.Buf[1] + if (c >= string.byte('a') and c <= string.byte('z')) or (c >= string.byte('A') and c <= string.byte('Z')) then data.Buf[1] = bit32.bxor(data.Buf[1], 32) end + data.BufDirty = true + + -- Increment a counter + local p_int = data.UserData -- [Port] int* -> the statics table, counter in .edit_count + p_int.edit_count = p_int.edit_count + 1 + end + return 0 + end + ImGui.InputText("Completion", s.buf1, 64, 262144 --[[ImGuiInputTextFlags.CallbackCompletion]], Funcs.MyCallback) + ImGui.SameLine(); HelpMarker( + "Here we append \"..\" each time Tab is pressed. " .. + "See 'Examples>Console' for a more meaningful demonstration of using this callback.") + + ImGui.InputText("History", s.buf2, 64, 524288 --[[ImGuiInputTextFlags.CallbackHistory]], Funcs.MyCallback) + ImGui.SameLine(); HelpMarker( + "Here we replace and select text each time Up/Down are pressed. " .. + "See 'Examples>Console' for a more meaningful demonstration of using this callback.") + + ImGui.InputText("Edit", s.buf3, 64, 8388608 --[[ImGuiInputTextFlags.CallbackEdit]], Funcs.MyCallback, s) -- [Port] (void*)&edit_count -> s + ImGui.SameLine(); HelpMarker( + "Here we toggle the casing of the first character on every edit + count edits.") + ImGui.SameLine(); ImGui.Text("(%d)", s.edit_count) + + ImGui.TreePop() + end + + if ImGui.TreeNode("Resize Callback") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback") + local s = S_ti.resize + -- To wire InputText() with std::string or any other custom string type, + -- you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper + -- using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. + HelpMarker( + "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" .. + "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.") + local Funcs = {} + function Funcs.MyResizeCallback(data) + if data.EventFlag == 4194304 --[[ImGuiInputTextFlags.CallbackResize]] then + local my_str = data.UserData + assert(my_str.Data == data.Buf) + my_str:resize(data.BufSize, 0) -- NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 -- [Port] new bytes filled with 0 + data.Buf = my_str.Data + end + return 0 + end + + -- Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. + -- For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' + function Funcs.MyInputTextMultiline(label, my_str, size, flags) + if size == nil then size = ImVec2(0, 0) end + if flags == nil then flags = 0 end + assert(bit32.band(flags, 4194304 --[[ImGuiInputTextFlags.CallbackResize]]) == 0) + return ImGui.InputTextMultiline(label, my_str.Data, my_str.Size, size, bit32.bor(flags, 4194304 --[[ImGuiInputTextFlags.CallbackResize]]), Funcs.MyResizeCallback, my_str) + end + + -- For this demo we are using ImVector as a string container. + -- Note that because we need to store a terminating zero character, our size/capacity are 1 more + -- than usually reported by a typical string class. + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_WordWrap", s.flags, 16777216 --[[ImGuiInputTextFlags.WordWrap]]) + + local my_str = s.my_str + if my_str:empty() then + my_str:push_back(0) + end + Funcs.MyInputTextMultiline("##MyStr", my_str, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeight() * 16), s.flags) + ImGui.Text("Data: %s\nSize: %d\nCapacity: %d", tostring(my_str.Data), my_str.Size, my_str.Capacity) -- [Port] %p -> %s + tostring + ImGui.TreePop() + end + + if ImGui.TreeNode("Eliding, Alignment") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment") + local s = S_ti.eliding + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ElideLeft", s.flags, 131072 --[[ImGuiInputTextFlags.ElideLeft]]) + ImGui.InputText("Path", s.buf1, 128, s.flags) + ImGui.TreePop() + end + + if ImGui.TreeNode("Miscellaneous") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous") + local s = S_ti.misc + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", s.flags, 128 --[[ImGuiInputTextFlags.EscapeClearsAll]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, 512 --[[ImGuiInputTextFlags.ReadOnly]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", s.flags, 65536 --[[ImGuiInputTextFlags.NoUndoRedo]]) + ImGui.InputText("Hello", s.buf1, 16, s.flags) + ImGui.TreePop() + end + + ImGui.TreePop() end - -- All demo contents - DemoWindowWidgets(data) - if DemoWindowLayout then DemoWindowLayout() end - if DemoWindowPopups then DemoWindowPopups() end - if DemoWindowTables then DemoWindowTables() end - if DemoWindowInputs then DemoWindowInputs() end +end - -- End of ShowDemoWindow() - ImGui.PopItemWidth() - ImGui.End() - return p_open +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTooltips() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTooltips = { + arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, + always_on = 0, +} +function DemoWindowWidgetsTooltips() + local s = S.DemoWindowWidgetsTooltips + if ImGui.TreeNode("Tooltips") then + IMGUI_DEMO_MARKER("Widgets/Tooltips") + -- Tooltips are windows following the mouse. They do not take focus away. + ImGui.SeparatorText("General") + + -- Typical use cases: + -- - Short-form (text only): SetItemTooltip("Hello"); + -- - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); } + + -- - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); } + -- - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); } + + HelpMarker( + "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n" .. + "We provide a helper SetItemTooltip() function to perform the two with standards flags.") + + local sz = ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0) + + ImGui.Button("Basic", sz) + ImGui.SetItemTooltip("I am a tooltip") + + ImGui.Button("Fancy", sz) + if ImGui.BeginItemTooltip() then + ImGui.Text("I am a fancy tooltip") + ImGui.PlotLines("Curve", s.arr, nil, #s.arr) + ImGui.Text("Sin(time) = %f", math.sin(ImGui.GetTime())) + ImGui.EndTooltip() + end + + ImGui.SeparatorText("Always On") + + -- Showcase NOT relying on a IsItemHovered() to emit a tooltip. + -- Here the tooltip is always emitted when 'always_on == true'. + _, s.always_on = ImGui.RadioButton("Off", s.always_on, 0) + ImGui.SameLine() + _, s.always_on = ImGui.RadioButton("Always On (Simple)", s.always_on, 1) + ImGui.SameLine() + _, s.always_on = ImGui.RadioButton("Always On (Advanced)", s.always_on, 2) + if s.always_on == 1 then + ImGui.SetTooltip("I am following you around.") + elseif s.always_on == 2 and ImGui.BeginTooltip() then + ImGui.ProgressBar(math.sin(ImGui.GetTime()) * 0.5 + 0.5, ImVec2(ImGui.GetFontSize() * 25, 0.0)) + ImGui.EndTooltip() + end + + ImGui.SeparatorText("Custom") + + HelpMarker( + "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize " .. + "tooltip activation details across your application. You may however decide to use custom " .. + "flags for a specific tooltip instance.") + + -- The following examples are passed for documentation purpose but may not be useful to most users. + -- Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from + -- 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. + -- With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. + ImGui.Button("Manual", sz) + if ImGui.IsItemHovered(4096 --[[ImGuiHoveredFlags.ForTooltip]]) then + ImGui.SetTooltip("I am a manually emitted tooltip.") + end + + ImGui.Button("DelayNone", sz) + if ImGui.IsItemHovered(16384 --[[ImGuiHoveredFlags.DelayNone]]) then + ImGui.SetTooltip("I am a tooltip with no delay.") + end + + ImGui.Button("DelayShort", sz) + if ImGui.IsItemHovered(bit32.bor(32768 --[[ImGuiHoveredFlags.DelayShort]], 131072 --[[ImGuiHoveredFlags.NoSharedDelay]])) then + ImGui.SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui.GetStyle().HoverDelayShort) + end + + ImGui.Button("DelayLong", sz) + if ImGui.IsItemHovered(bit32.bor(65536 --[[ImGuiHoveredFlags.DelayNormal]], 131072 --[[ImGuiHoveredFlags.NoSharedDelay]])) then + ImGui.SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui.GetStyle().HoverDelayNormal) + end + + ImGui.Button("Stationary", sz) + if ImGui.IsItemHovered(8192 --[[ImGuiHoveredFlags.Stationary]]) then + ImGui.SetTooltip("I am a tooltip requiring mouse to be stationary before activating.") + end + + -- Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav', + -- which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag. + ImGui.BeginDisabled() + ImGui.Button("Disabled item", sz) + if ImGui.IsItemHovered(4096 --[[ImGuiHoveredFlags.ForTooltip]]) then + ImGui.SetTooltip("I am a tooltip for a disabled item.") + end + ImGui.EndDisabled() + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTreeNodes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTreeNodes = { + base_flags = bit32.bor(ImGuiTreeNodeFlags.DrawLinesFull, ImGuiTreeNodeFlags.DefaultOpen), -- "Hierarchy Lines" + selection_mask = 0x00, + base_flags_2 = bit32.bor(ImGuiTreeNodeFlags.OpenOnArrow, ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.SpanAvailWidth), -- "Advanced" + align_label_with_current_x_position = false, + use_drag_and_drop = false, +} +function DemoWindowWidgetsTreeNodes() + local s = S.DemoWindowWidgetsTreeNodes + if ImGui.TreeNode("Tree Nodes") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes") + -- See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree. + if ImGui.TreeNode("Basic Trees") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic Trees") + for i = 0, 4 do + -- Use SetNextItemOpen() so set the default state of a node to be open. We could + -- also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! + if i == 0 then + ImGui.SetNextItemOpen(true, 2 --[[ImGuiCond.Once]]) + end + + -- Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict. + -- An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)', + -- aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine. + ImGui.PushID(i) + if ImGui.TreeNode("", "Child %d", i) then + ImGui.Text("blah blah") + ImGui.SameLine() + if ImGui.SmallButton("button") then end + ImGui.TreePop() + end + ImGui.PopID() + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Hierarchy Lines") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy Lines") + HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") + _, s.base_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", s.base_flags, 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", s.base_flags, 524288 --[[ImGuiTreeNodeFlags.DrawLinesFull]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", s.base_flags, 1048576 --[[ImGuiTreeNodeFlags.DrawLinesToNodes]]) + + if ImGui.TreeNodeEx("Parent", s.base_flags) then + if ImGui.TreeNodeEx("Child 1", s.base_flags) then + ImGui.Button("Button for Child 1") + ImGui.TreePop() + end + if ImGui.TreeNodeEx("Child 2", s.base_flags) then + ImGui.Button("Button for Child 2") + ImGui.TreePop() + end + ImGui.Text("Remaining contents") + ImGui.Text("Remaining contents") + ImGui.TreePop() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Clipping Large Trees") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Clipping Large Trees") + ImGui.TextWrapped( + "- Using ImGuiListClipper with trees is a less easy than on arrays or grids.\n" .. + "- Refer to 'Demo->Examples->Property Editor' for an example of how to do that.\n" .. + "- Discuss in #3823") + ImGui.TreePop() + end + + if ImGui.TreeNode("Selectable Nodes") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Selectable Nodes") + HelpMarker( + "Manually implemented selectable nodes.\n" .. + "Click to select, Ctrl+Click to toggle, click on arrows or double-click to open.\n\n" .. + "You may also use the multi-select API (see 'Demo->Widgets->Selection State & Multi-Select') for more advanced multi-selection features.") + + -- Hold in 'selection_mask' a simple representation of what may be user-side selection state. + -- - You may retain selection state inside or outside your objects in whatever format you see fit. + -- You may use ImGuiSelectionBasicStorage which is conceptually close to a set<> of identifiers. + -- - We record which node was clicked and then apply selection at the end of the loop. + -- - This is a manual and simplified reimplementation of multi-selection, which the full + -- BeginMultiSelect() API implements better, but which is not trivial to wire for trees. + local node_clicked_idx = -1 + for node_n = 0, 5 do + -- Disable the default "open on single-click behavior" + set Selected flag according to our selection. + -- To alter selection we use if 'IsItemClicked() && !IsItemToggledOpen()', so clicking on an arrow doesn't alter selection. + -- In a BeginMultiSelect()/EndMultiSelect() we could use IsItemToggledSelection() but here we reimplement and use our own logic. + local flags = bit32.bor(128 --[[ImGuiTreeNodeFlags.OpenOnArrow]], 64 --[[ImGuiTreeNodeFlags.OpenOnDoubleClick]], 2048 --[[ImGuiTreeNodeFlags.SpanAvailWidth]]) + if bit32.band(s.selection_mask, bit32.lshift(1, node_n)) ~= 0 then + flags = bit32.bor(flags, 1 --[[ImGuiTreeNodeFlags.Selected]]) + end + + local is_open = ImGui.TreeNodeEx(node_n, flags, "Selectable Node %d", node_n) -- [Port] (void*)(intptr_t)node_n -> node_n + if ImGui.IsItemClicked() and not ImGui.IsItemToggledOpen() then + node_clicked_idx = node_n + end + if is_open then + ImGui.BulletText("") + ImGui.TreePop() + end + end + if node_clicked_idx ~= -1 then + -- Update selection state (process outside of tree loop to avoid visual inconsistencies during the clicking frame) + if ImGui.GetIO().KeyCtrl then + s.selection_mask = bit32.bxor(s.selection_mask, bit32.lshift(1, node_clicked_idx)) -- Ctrl+Click to toggle + else --if (!(selection_mask & (1 << node_clicked_idx))) -- Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection + s.selection_mask = bit32.lshift(1, node_clicked_idx) -- Click to single-select + end + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Advanced") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", s.base_flags_2, 128 --[[ImGuiTreeNodeFlags.OpenOnArrow]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", s.base_flags_2, 64 --[[ImGuiTreeNodeFlags.OpenOnDoubleClick]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", s.base_flags_2, 2048 --[[ImGuiTreeNodeFlags.SpanAvailWidth]]); ImGui.SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", s.base_flags_2, 4096 --[[ImGuiTreeNodeFlags.SpanFullWidth]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", s.base_flags_2, 8192 --[[ImGuiTreeNodeFlags.SpanLabelWidth]]); ImGui.SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin.") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", s.base_flags_2, 16384 --[[ImGuiTreeNodeFlags.SpanAllColumns]]); ImGui.SameLine(); HelpMarker("For use in Tables only.") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", s.base_flags_2, 4 --[[ImGuiTreeNodeFlags.AllowOverlap]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_Framed", s.base_flags_2, 2 --[[ImGuiTreeNodeFlags.Framed]]); ImGui.SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_FramePadding", s.base_flags_2, 1024 --[[ImGuiTreeNodeFlags.FramePadding]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsToParent", s.base_flags_2, 131072 --[[ImGuiTreeNodeFlags.NavLeftJumpsToParent]]) + + HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", s.base_flags_2, 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", s.base_flags_2, 524288 --[[ImGuiTreeNodeFlags.DrawLinesFull]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", s.base_flags_2, 1048576 --[[ImGuiTreeNodeFlags.DrawLinesToNodes]]) + + _, s.align_label_with_current_x_position = ImGui.Checkbox("Align label with current X position", s.align_label_with_current_x_position) + _, s.use_drag_and_drop = ImGui.Checkbox("Make Tree Nodes as drag & drop sources", s.use_drag_and_drop) + if s.align_label_with_current_x_position then + ImGui.Unindent(ImGui.GetTreeNodeToLabelSpacing()) + end + + for node_n = 0, 5 do + local node_flags = s.base_flags_2 + if node_n < 3 then + -- Items 0..2 are Tree Node + local is_open = ImGui.TreeNodeEx(node_n, node_flags, "Selectable Node %d", node_n) + if s.use_drag_and_drop and ImGui.BeginDragDropSource() then + ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) + ImGui.Text("This is a drag and drop source") + ImGui.EndDragDropSource() + end + if node_n == 2 and bit32.band(s.base_flags_2, 8192 --[[ImGuiTreeNodeFlags.SpanLabelWidth]]) ~= 0 then + -- Item 2 has an additional inline button to help demonstrate SpanLabelWidth. + ImGui.SameLine() + if ImGui.SmallButton("button") then end + end + if is_open then + ImGui.BulletText("Blah blah\nBlah Blah") + ImGui.SameLine() + ImGui.SmallButton("Button") + ImGui.TreePop() + end + else + -- Items 3..5 are Tree Leaves + -- The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can + -- use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). + node_flags = bit32.bor(node_flags, 256 --[[ImGuiTreeNodeFlags.Leaf]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]]) -- ImGuiTreeNodeFlags_Bullet + ImGui.TreeNodeEx(node_n, node_flags, "Selectable Leaf %d", node_n) + if s.use_drag_and_drop and ImGui.BeginDragDropSource() then + ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) + ImGui.Text("This is a drag and drop source") + ImGui.EndDragDropSource() + end + end + end + if s.align_label_with_current_x_position then + ImGui.Indent(ImGui.GetTreeNodeToLabelSpacing()) + end + ImGui.TreePop() + end + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsVerticalSliders() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsVerticalSliders = { + int_value = 0, + values = { 0.0, 0.60, 0.35, 0.9, 0.70, 0.20, 0.0 }, + values2 = { 0.20, 0.80, 0.40, 0.25 }, +} +function DemoWindowWidgetsVerticalSliders() + local s = S.DemoWindowWidgetsVerticalSliders + if ImGui.TreeNode("Vertical Sliders") then + IMGUI_DEMO_MARKER("Widgets/Vertical Sliders") + local spacing = 4 + ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(spacing, spacing)) + + s.int_value = ImGui.VSliderInt("##int", ImVec2(18, 160), s.int_value, 0, 5) + ImGui.SameLine() + + local values = s.values + ImGui.PushID("set1") + for i = 0, 6 do + if i > 0 then ImGui.SameLine() end + ImGui.PushID(i) + ImGui.PushStyleColor(7 --[[ImGuiCol.FrameBg]], ImColor.HSV(i / 7.0, 0.5, 0.5).Value) + ImGui.PushStyleColor(8 --[[ImGuiCol.FrameBgHovered]], ImColor.HSV(i / 7.0, 0.6, 0.5).Value) + ImGui.PushStyleColor(9 --[[ImGuiCol.FrameBgActive]], ImColor.HSV(i / 7.0, 0.7, 0.5).Value) + ImGui.PushStyleColor(20 --[[ImGuiCol.SliderGrab]], ImColor.HSV(i / 7.0, 0.9, 0.9).Value) + values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(18, 160), values[i + 1], 0.0, 1.0, "") + if ImGui.IsItemActive() or ImGui.IsItemHovered() then + ImGui.SetTooltip("%.3f", values[i + 1]) + end + ImGui.PopStyleColor(4) + ImGui.PopID() + end + ImGui.PopID() + + ImGui.SameLine() + ImGui.PushID("set2") + local values2 = s.values2 + local rows = 3 + local small_slider_size = ImVec2(18, math.floor((160.0 - (rows - 1) * spacing) / rows)) + for nx = 0, 3 do + if nx > 0 then ImGui.SameLine() end + ImGui.BeginGroup() + for ny = 0, rows - 1 do + ImGui.PushID(nx * rows + ny) + values2[nx + 1] = ImGui.VSliderFloat("##v", small_slider_size, values2[nx + 1], 0.0, 1.0, "") + if ImGui.IsItemActive() or ImGui.IsItemHovered() then + ImGui.SetTooltip("%.3f", values2[nx + 1]) + end + ImGui.PopID() + end + ImGui.EndGroup() + end + ImGui.PopID() + + ImGui.SameLine() + ImGui.PushID("set3") + for i = 0, 3 do + if i > 0 then ImGui.SameLine() end + ImGui.PushID(i) + ImGui.PushStyleVar(21 --[[ImGuiStyleVar.GrabMinSize]], 40) + values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(40, 160), values[i + 1], 0.0, 1.0, "%.2f\nsec") + ImGui.PopStyleVar() + ImGui.PopID() + end + ImGui.PopID() + ImGui.PopStyleVar() + ImGui.TreePop() + end end ------------------------------------------------------------------------------- -- [SECTION] DemoWindowWidgets() ------------------------------------------------------------------------------- ---- Calls a (global) demo section if it exists, otherwise shows a placeholder -local function Sub(fn, title, ...) - if fn then fn(...) else - if ImGui.TreeNode(title) then DemoNotPorted(title) ImGui.TreePop() end - end -end - -function DemoWindowWidgets(data) - -- ImGui.SetNextItemOpen(true, ImGuiCond.Once) +function DemoWindowWidgets(demo_data) + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) if not ImGui.CollapsingHeader("Widgets") then return end - -- IMGUI_DEMO_MARKER("Widgets") + -- IMGUI_DEMO_MARKER("Widgets"); - local disable_all = data.DisableSections -- The Checkbox for that is inside the "Disabled" section at the bottom - local override_liveedit = data.LiveEditOverride + local disable_all = demo_data.DisableSections -- The Checkbox for that is inside the "Disabled" section at the bottom + local override_liveedit = demo_data.LiveEditOverride if disable_all then ImGui.BeginDisabled() end if override_liveedit then - ImGui.PushItemFlag(128 --[[ImGuiItemFlags.LiveEditOnInputText]], DemoHas(data.LiveEditFlags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]])) - ImGui.PushItemFlag(256 --[[ImGuiItemFlags.LiveEditOnInputScalar]], DemoHas(data.LiveEditFlags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]])) + ImGui.PushItemFlag(128 --[[ImGuiItemFlags.LiveEditOnInputText]], bit32.band(demo_data.LiveEditFlags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) ~= 0) + ImGui.PushItemFlag(256 --[[ImGuiItemFlags.LiveEditOnInputScalar]], bit32.band(demo_data.LiveEditFlags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) ~= 0) end - Sub(DemoWindowWidgetsBasic, "Basic") - Sub(DemoWindowWidgetsBullets, "Bullets") - Sub(DemoWindowWidgetsCollapsingHeaders, "Collapsing Headers") - Sub(DemoWindowWidgetsComboBoxes, "Combo") - Sub(DemoWindowWidgetsColorAndPickers, "Color/Picker Widgets") - Sub(DemoWindowWidgetsDataTypes, "Data Types") + DemoWindowWidgetsBasic() + DemoWindowWidgetsBullets() + DemoWindowWidgetsCollapsingHeaders() + DemoWindowWidgetsComboBoxes() + DemoWindowWidgetsColorAndPickers() + DemoWindowWidgetsDataTypes() if disable_all then ImGui.EndDisabled() end - Sub(DemoWindowWidgetsDisableBlocks, "Disable Blocks", data) + DemoWindowWidgetsDisableBlocks(demo_data) if disable_all then ImGui.BeginDisabled() end - Sub(DemoWindowWidgetsDragAndDrop, "Drag and Drop") - Sub(DemoWindowWidgetsDragsAndSliders, "Drag/Slider Flags") - Sub(DemoWindowWidgetsFonts, "Fonts") - Sub(DemoWindowWidgetsImages, "Images") - Sub(DemoWindowWidgetsListBoxes, "List Boxes") - Sub(DemoWindowWidgetsLiveEdit, "Live Edit Flags", data) - Sub(DemoWindowWidgetsMixedValues, "Mixed Values") - Sub(DemoWindowWidgetsMultiComponents, "Multi-component Widgets") - Sub(DemoWindowWidgetsPlotting, "Plotting") - Sub(DemoWindowWidgetsProgressBars, "Progress Bars") - Sub(DemoWindowWidgetsQueryingStatuses, "Querying Item Status (Edited/Active/Hovered etc.)") - Sub(DemoWindowWidgetsSelectables, "Selectables") - Sub(DemoWindowWidgetsSelectionAndMultiSelect, "Selection State & Multi-Select", data) - Sub(DemoWindowWidgetsTabs, "Tabs") - Sub(DemoWindowWidgetsText, "Text") - Sub(DemoWindowWidgetsTextFilter, "Text Filter") - Sub(DemoWindowWidgetsTextInput, "Text Input") - Sub(DemoWindowWidgetsTooltips, "Tooltips") - Sub(DemoWindowWidgetsTreeNodes, "Tree Nodes") - Sub(DemoWindowWidgetsVerticalSliders, "Vertical Sliders") + DemoWindowWidgetsDragAndDrop() + DemoWindowWidgetsDragsAndSliders() + DemoWindowWidgetsFonts() + DemoWindowWidgetsImages() + DemoWindowWidgetsListBoxes() + DemoWindowWidgetsLiveEdit(demo_data) + DemoWindowWidgetsMixedValues() + DemoWindowWidgetsMultiComponents() + DemoWindowWidgetsPlotting() + DemoWindowWidgetsProgressBars() + DemoWindowWidgetsQueryingStatuses() + DemoWindowWidgetsSelectables() + DemoWindowWidgetsSelectionAndMultiSelect(demo_data) + DemoWindowWidgetsTabs() + DemoWindowWidgetsText() + DemoWindowWidgetsTextFilter() + DemoWindowWidgetsTextInput() + DemoWindowWidgetsTooltips() + DemoWindowWidgetsTreeNodes() + DemoWindowWidgetsVerticalSliders() if override_liveedit then ImGui.PopItemFlag() @@ -22413,1237 +25140,897 @@ function DemoWindowWidgets(data) end end -------------------------------------------------------------------------------- --- [SECTION] User Guide / ShowUserGuide() -------------------------------------------------------------------------------- - -function ImGui.ShowUserGuide() - local io = ImGui.GetIO() - ImGui.BulletText("Double-click on title bar to collapse window.") - ImGui.BulletText( - "Click and drag on lower corner or border to resize window.\n" .. - "(double-click to auto fit window to its contents)") - ImGui.BulletText("Ctrl+Click on a slider or drag box to input value as text.") - ImGui.BulletText("Tab/Shift+Tab to cycle through keyboard editable fields.") - ImGui.BulletText("Ctrl+Tab/Ctrl+Shift+Tab to focus windows.") - if io.FontAllowUserScaling then - ImGui.BulletText("Ctrl+Mouse Wheel to zoom window contents.") - end - ImGui.BulletText("While inputting text:\n") - ImGui.Indent() - ImGui.BulletText("Ctrl+Left/Right to word jump.") - ImGui.BulletText("Ctrl+A or double-click to select all.") - ImGui.BulletText("Ctrl+X/C/V to use clipboard cut/copy/paste.") - ImGui.BulletText("Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.") - ImGui.BulletText("Escape to revert.") - ImGui.Unindent() - ImGui.BulletText("With Keyboard controls enabled:") - ImGui.Indent() - ImGui.BulletText("Arrow keys or Home/End/PageUp/PageDown to navigate.") - ImGui.BulletText("Space to activate a widget.") - ImGui.BulletText("Return to input text into a widget.") - ImGui.BulletText("Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus.") - ImGui.BulletText("Alt to jump to the menu layer of a window.") - ImGui.BulletText("Menu or Shift+F10 to open a context menu.") - ImGui.Unindent() - ImGui.BulletText("With Gamepad controls enabled:") - ImGui.Indent() - ImGui.BulletText("D-Pad: Navigate / Tweak / Resize (in Windowing mode).") - ImGui.BulletText("%s Face button: Activate / Open / Toggle. Hold: activate with text input.", io.ConfigNavSwapGamepadButtons and "East" or "South") - ImGui.BulletText("%s Face button: Cancel / Close / Exit.", io.ConfigNavSwapGamepadButtons and "South" or "East") - ImGui.BulletText("West Face button: Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows).") - ImGui.BulletText("North Face button: Open Context Menu.") - ImGui.BulletText("L1/R1: Tweak Slower/Faster, Focus Previous/Next (in Windowing Mode).") - ImGui.Unindent() -end -end --[[ imgui_demo.lua ]] - -do --[[ imgui_demo_2.lua ]] ---- Dear ImGui WIP --- (Demo Code, part 2): DemoWindowLayout(), DemoWindowPopups(), DemoWindowTables(), DemoWindowColumns(), --- DemoWindowInputs() and all ShowExampleAppXXX() example apps. --- Port of imgui_demo.cpp (docking branch). Globals are shared with imgui_demo.lua (HelpMarker, ShowExampleMenuFile, ...) - --- Helpers macros --- We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, --- but making an exception here as those are largely simplifying code... --- In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. -local IM_MIN = math.min -local IM_MAX = math.max -local function IM_CLAMP(V, MN, MX) return (V < MN) and MN or (V > MX) and MX or V end -local _ -local function IMGUI_DEMO_MARKER(_) end -- upstream hook, no-op here - ---- `char buf[size] = "str"` -> zero-terminated byte table -local function Buf(str, size) - local t = {} - for i = 1, #str do t[i] = string.byte(str, i) end - t[#str + 1] = 0 - if size then for i = #str + 2, size do t[i] = 0 end end - return t -end ---- byte table -> Lua string (up to the zero terminator) -local function BufStr(buf) - local n = 0 - while buf[n + 1] ~= nil and buf[n + 1] ~= 0 do n = n + 1 end - return ImGui._ByteArrayToString(buf, 1, n + 1) -end -local function BufSet(buf, str) - for i = 1, #str do buf[i] = string.byte(str, i) end - buf[#str + 1] = 0 -end - ---- ImColor::HSV() as ImVec4 -local function HSV(h, s, v, a) - local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v) - return ImVec4(r, g, b, a or 1.0) -end -local function B2I(b) return b and 1 or 0 end - -local function Has(flags, f) return bit32.band(flags, f) ~= 0 end -local function NotSupported() ImGui.TextDisabled("(not supported on Roblox)") end -local function NotPorted(what) ImGui.TextDisabled("(not ported yet%s)", what and (": " .. what) or "") end - -local function DemoHelpMarker(desc) - if HelpMarker then HelpMarker(desc) return end - ImGui.TextDisabled("(?)") - if ImGui.BeginItemTooltip() then - ImGui.PushTextWrapPos(ImGui.GetFontSize() * 35.0) - ImGui.TextUnformatted(desc) - ImGui.PopTextWrapPos() - ImGui.EndTooltip() - end -end -local function DemoMenuFile() if ShowExampleMenuFile then ShowExampleMenuFile() end end - ---- Minimal ImGuiTextFilter stand-in when the library one isn't available -local function MakeTextFilter() - if ImGuiTextFilter then return ImGuiTextFilter() end - local f = { InputBuf = Buf("", 256) } - function f:Draw(label, width) - if width and width ~= 0 then ImGui.SetNextItemWidth(width) end - return ImGui.InputText(label or "Filter (inc,-exc)", self.InputBuf, 256) - end - function f:IsActive() return self.InputBuf[1] ~= 0 end - function f:Clear() self.InputBuf[1] = 0 end - function f:Build() end - function f:PassFilter(text, text_end) - if text_end then text = string.sub(text, 1, text_end - 1) end - local s = BufStr(self.InputBuf) - if s == "" then return true end - local any_inc, pass_inc = false, false - for tok in string.gmatch(s, "[^,]+") do - tok = string.match(tok, "^%s*(.-)%s*$") - if tok ~= "" then - if string.sub(tok, 1, 1) == "-" then - if #tok > 1 and string.find(string.lower(text), string.lower(string.sub(tok, 2)), 1, true) then return false end - else - any_inc = true - if string.find(string.lower(text), string.lower(tok), 1, true) then pass_inc = true end - end - end - end - return (not any_inc) or pass_inc - end - return f -end - --- ImGuiInputTextCallbackData helpers (the port's callback data has no methods). Buf is a 1-based zero-terminated --- byte table, positions are 0-based like C++. -local function CB_DeleteChars(data, pos, bytes_count) - local buf = data.Buf - local len = data.BufTextLen - for i = pos + 1, len - bytes_count + 1 do buf[i] = buf[i + bytes_count] end - for i = len - bytes_count + 2, len + 1 do buf[i] = 0 end - if data.CursorPos >= pos + bytes_count then data.CursorPos = data.CursorPos - bytes_count - elseif data.CursorPos >= pos then data.CursorPos = pos end - data.SelectionStart = data.CursorPos; data.SelectionEnd = data.CursorPos - data.BufDirty = true - data.BufTextLen = len - bytes_count -end -local function CB_InsertChars(data, pos, text) - local n = #text - if n == 0 then return end - if data.BufTextLen + n >= data.BufSize then return end - local buf = data.Buf - for i = data.BufTextLen + 1, pos + 1, -1 do buf[i + n] = buf[i] end - for i = 1, n do buf[pos + i] = string.byte(text, i) end - if data.CursorPos >= pos then data.CursorPos = data.CursorPos + n end - data.SelectionStart = data.CursorPos; data.SelectionEnd = data.CursorPos - data.BufDirty = true - data.BufTextLen = data.BufTextLen + n -end -local function CB_SelectAll(data) data.SelectionStart = 0; data.SelectionEnd = data.BufTextLen end - ---- ImGui::BeginChild() wrapper accepting upstream args -local function BeginChild(id, size, child_flags, window_flags) - return ImGui.BeginChild(id, size or ImVec2(0, 0), child_flags or 0, window_flags or 0) -end - ------------------------------------------------------------------------------- -- [SECTION] DemoWindowLayout() ------------------------------------------------------------------------------- -local SL = { - disable_mouse_wheel = false, disable_menu = false, - draw_lines = 3, max_height_in_lines = 10, - offset_x = 0, override_bg_color = true, child_flags = nil, - f = 0.0, show_indented_items = true, +S.DemoWindowLayout = { + -- Child windows + disable_mouse_wheel = false, + disable_menu = false, + draw_lines = 3, + max_height_in_lines = 10, + offset_x = 0, + override_bg_color = true, + child_flags = bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.ResizeX, ImGuiChildFlags.ResizeY), + -- Widgets Width + f = 0.0, + show_indented_items = true, + -- Basic Horizontal Layout c1 = false, c2 = false, c3 = false, c4 = false, - f0 = 1.0, f1 = 2.0, f2 = 3.0, item = -1, selection = { 0, 1, 2, 3 }, - track_item = 50, enable_track = true, enable_extra_decorations = false, scroll_to_off_px = 0.0, scroll_to_pos_px = 200.0, - lines = 7, show_horizontal_contents_size_demo_window = false, - show_h_scrollbar = true, show_button = true, show_tree_nodes = true, show_text_wrapped = false, show_columns = true, - show_tab_bar = true, show_child = false, explicit_content_size = false, contents_size_x = 300.0, - clip_size = nil, clip_offset = nil, + f0 = 1.0, f1 = 2.0, f2 = 3.0, + item = -1, + selection = { 0, 1, 2, 3 }, + -- Scrolling + track_item = 50, + enable_track = true, + enable_extra_decorations = false, + scroll_to_off_px = 0.0, + scroll_to_pos_px = 200.0, + lines = 7, + show_horizontal_contents_size_demo_window = false, + show_h_scrollbar = true, + show_button = true, + show_tree_nodes = true, + show_text_wrapped = false, + show_columns = true, + show_tab_bar = true, + show_child = false, + explicit_content_size = false, + contents_size_x = 300.0, + -- Text Clipping + size = ImVec2(100.0, 100.0), + offset = ImVec2(30.0, 30.0), + -- Overlap Mode enable_allow_overlap = true, } -local function DemoWindowLayout_ChildWindows() - IMGUI_DEMO_MARKER("Layout/Child windows") - ImGui.SeparatorText("Child windows") - - DemoHelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.") - _, SL.disable_mouse_wheel = ImGui.Checkbox("Disable Mouse Wheel", SL.disable_mouse_wheel) - _, SL.disable_menu = ImGui.Checkbox("Disable Menu", SL.disable_menu) - - -- Child 1: no border, enable horizontal scrollbar - do - local window_flags = 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]] - if SL.disable_mouse_wheel then - window_flags = bit32.bor(window_flags, 16 --[[ImGuiWindowFlags.NoScrollWithMouse]]) - end - BeginChild("ChildL", ImVec2(ImGui.GetContentRegionAvail().x * 0.5, 260), 0 --[[ImGuiChildFlags.None]], window_flags) - for i = 0, 99 do - ImGui.Text("%04d: scrollable region", i) - end - ImGui.EndChild() +function DemoWindowLayout() + local s = S.DemoWindowLayout + if not ImGui.CollapsingHeader("Layout & Scrolling") then + return end - ImGui.SameLine() + if ImGui.TreeNode("Child windows") then + IMGUI_DEMO_MARKER("Layout/Child windows") + ImGui.SeparatorText("Child windows") - -- Child 2: rounded border - do - local window_flags = 0 --[[ImGuiWindowFlags.None]] - if SL.disable_mouse_wheel then - window_flags = bit32.bor(window_flags, 16 --[[ImGuiWindowFlags.NoScrollWithMouse]]) - end - if not SL.disable_menu then - window_flags = bit32.bor(window_flags, 1024 --[[ImGuiWindowFlags.MenuBar]]) - end - ImGui.PushStyleVar(7 --[[ImGuiStyleVar.ChildRounding]], 5.0) - BeginChild("ChildR", ImVec2(0, 260), 1 --[[ImGuiChildFlags.Borders]], window_flags) - if not SL.disable_menu and ImGui.BeginMenuBar() then - if ImGui.BeginMenu("Menu") then - DemoMenuFile() - ImGui.EndMenu() + HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.") + _, s.disable_mouse_wheel = ImGui.Checkbox("Disable Mouse Wheel", s.disable_mouse_wheel) + _, s.disable_menu = ImGui.Checkbox("Disable Menu", s.disable_menu) + + -- Child 1: no border, enable horizontal scrollbar + do + local window_flags = 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]] + if s.disable_mouse_wheel then + window_flags = bit32.bor(window_flags, 16 --[[ImGuiWindowFlags.NoScrollWithMouse]]) end - ImGui.EndMenuBar() - end - if ImGui.BeginTable("split", 2, bit32.bor(1 --[[ImGuiTableFlags.Resizable]], 16 --[[ImGuiTableFlags.NoSavedSettings]])) then + ImGui.BeginChild("ChildL", ImVec2(ImGui.GetContentRegionAvail().x * 0.5, 260), 0 --[[ImGuiChildFlags.None]], window_flags) for i = 0, 99 do - local buf = string.format("%03d", i) - ImGui.TableNextColumn() - ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + ImGui.Text("%04d: scrollable region", i) end - ImGui.EndTable() + ImGui.EndChild() end - ImGui.EndChild() - ImGui.PopStyleVar() - end - -- Child 3: manual-resize - ImGui.SeparatorText("Manual-resize") - do - DemoHelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.") - -- if ImGui.Button("Set Height to 200") then - -- ImGui.SetNextWindowSize(ImVec2(-FLT_MIN, 200.0)) - -- end + ImGui.SameLine() - ImGui.PushStyleColor(3 --[[ImGuiCol.ChildBg]], ImGui.GetStyleColorVec4(7 --[[ImGuiCol.FrameBg]])) - if BeginChild("ResizableChild", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeightWithSpacing() * 8), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 8 --[[ImGuiChildFlags.ResizeY]])) then - for n = 0, 9 do - ImGui.Text("Line %04d", n) + -- Child 2: rounded border + do + local window_flags = 0 --[[ImGuiWindowFlags.None]] + if s.disable_mouse_wheel then + window_flags = bit32.bor(window_flags, 16 --[[ImGuiWindowFlags.NoScrollWithMouse]]) end - end - ImGui.PopStyleColor() - ImGui.EndChild() - end - - -- Child 4: auto-resizing height with a limit - ImGui.SeparatorText("Auto-resize with constraints") - do - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - SL.draw_lines = ImGui.DragInt("Lines Count", SL.draw_lines, 0.2) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - SL.max_height_in_lines = ImGui.DragInt("Max Height (in Lines)", SL.max_height_in_lines, 0.2) - - ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 1), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], ImGui.GetTextLineHeightWithSpacing() * SL.max_height_in_lines)) - if BeginChild("ConstrainedChild", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 32 --[[ImGuiChildFlags.AutoResizeY]])) then - for n = 0, SL.draw_lines - 1 do - ImGui.Text("Line %04d", n) + if not s.disable_menu then + window_flags = bit32.bor(window_flags, 1024 --[[ImGuiWindowFlags.MenuBar]]) end - end - ImGui.EndChild() - end - - ImGui.SeparatorText("Misc/Advanced") - - -- Demonstrate a few extra things - -- - Changing ImGuiCol.ChildBg (which is transparent black in default styles) - -- - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) - -- You can also call SetNextWindowPos() to position the child window. The parent window will effectively - -- layout from this position. - -- - Using ImGui.GetItemRectMin/Max() to query the "item" state (because the child window is an item from - -- the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details. - do - if SL.child_flags == nil then SL.child_flags = bit32.bor(1 --[[ImGuiChildFlags.Borders]], 4 --[[ImGuiChildFlags.ResizeX]], 8 --[[ImGuiChildFlags.ResizeY]]) end - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - SL.offset_x = ImGui.DragInt("Offset X", SL.offset_x, 1.0, -1000, 1000) - _, SL.override_bg_color = ImGui.Checkbox("Override ChildBg color", SL.override_bg_color) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_Borders", SL.child_flags, 1 --[[ImGuiChildFlags.Borders]]) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", SL.child_flags, 2 --[[ImGuiChildFlags.AlwaysUseWindowPadding]]) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeX", SL.child_flags, 4 --[[ImGuiChildFlags.ResizeX]]) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeY", SL.child_flags, 8 --[[ImGuiChildFlags.ResizeY]]) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_FrameStyle", SL.child_flags, 128 --[[ImGuiChildFlags.FrameStyle]]) - ImGui.SameLine(); DemoHelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.") - if Has(SL.child_flags, 128 --[[ImGuiChildFlags.FrameStyle]]) then - SL.override_bg_color = false + ImGui.PushStyleVar(7 --[[ImGuiStyleVar.ChildRounding]], 5.0) + ImGui.BeginChild("ChildR", ImVec2(0, 260), 1 --[[ImGuiChildFlags.Borders]], window_flags) + if not s.disable_menu and ImGui.BeginMenuBar() then + if ImGui.BeginMenu("Menu") then + ShowExampleMenuFile() + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end + if ImGui.BeginTable("split", 2, bit32.bor(1 --[[ImGuiTableFlags.Resizable]], 16 --[[ImGuiTableFlags.NoSavedSettings]])) then + for i = 0, 99 do + local buf = string.format("%03d", i) + ImGui.TableNextColumn() + ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + end + ImGui.EndTable() + end + ImGui.EndChild() + ImGui.PopStyleVar() end - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + SL.offset_x) - if SL.override_bg_color then - ImGui.PushStyleColor(3 --[[ImGuiCol.ChildBg]], IM_COL32(255, 0, 0, 100)) - end - BeginChild("Red", ImVec2(200, 100), SL.child_flags, 0 --[[ImGuiWindowFlags.None]]) - if SL.override_bg_color then + -- Child 3: manual-resize + ImGui.SeparatorText("Manual-resize") + do + HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.") + --if (ImGui.Button("Set Height to 200")) + -- ImGui.SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f)); + + ImGui.PushStyleColor(3 --[[ImGuiCol.ChildBg]], ImGui.GetStyleColorVec4(7 --[[ImGuiCol.FrameBg]])) + if ImGui.BeginChild("ResizableChild", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeightWithSpacing() * 8), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 8 --[[ImGuiChildFlags.ResizeY]])) then + for n = 0, 9 do + ImGui.Text("Line %04d", n) + end + end ImGui.PopStyleColor() + ImGui.EndChild() end - for n = 0, 49 do - ImGui.Text("Some test %d", n) + -- Child 4: auto-resizing height with a limit + ImGui.SeparatorText("Auto-resize with constraints") + do + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.draw_lines = ImGui.DragInt("Lines Count", s.draw_lines, 0.2) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.max_height_in_lines = ImGui.DragInt("Max Height (in Lines)", s.max_height_in_lines, 0.2) + + ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 1), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], ImGui.GetTextLineHeightWithSpacing() * s.max_height_in_lines)) + if ImGui.BeginChild("ConstrainedChild", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 32 --[[ImGuiChildFlags.AutoResizeY]])) then + for n = 0, s.draw_lines - 1 do + ImGui.Text("Line %04d", n) + end + end + ImGui.EndChild() end - ImGui.EndChild() - local child_is_hovered = ImGui.IsItemHovered() - local child_rect_min = ImGui.GetItemRectMin() - local child_rect_max = ImGui.GetItemRectMax() - ImGui.Text("Hovered: %d", B2I(child_is_hovered)) - ImGui.Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y) + + ImGui.SeparatorText("Misc/Advanced") + + -- Demonstrate a few extra things + -- - Changing ImGuiCol.ChildBg (which is transparent black in default styles) + -- - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) + -- You can also call SetNextWindowPos() to position the child window. The parent window will effectively + -- layout from this position. + -- - Using ImGui.GetItemRectMin/Max() to query the "item" state (because the child window is an item from + -- the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details. + do + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.offset_x = ImGui.DragInt("Offset X", s.offset_x, 1.0, -1000, 1000) + _, s.override_bg_color = ImGui.Checkbox("Override ChildBg color", s.override_bg_color) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_Borders", s.child_flags, 1 --[[ImGuiChildFlags.Borders]]) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", s.child_flags, 2 --[[ImGuiChildFlags.AlwaysUseWindowPadding]]) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeX", s.child_flags, 4 --[[ImGuiChildFlags.ResizeX]]) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeY", s.child_flags, 8 --[[ImGuiChildFlags.ResizeY]]) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_FrameStyle", s.child_flags, 128 --[[ImGuiChildFlags.FrameStyle]]) + ImGui.SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.") + if bit32.band(s.child_flags, 128 --[[ImGuiChildFlags.FrameStyle]]) ~= 0 then + s.override_bg_color = false + end + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + s.offset_x) + if s.override_bg_color then + ImGui.PushStyleColor(3 --[[ImGuiCol.ChildBg]], IM_COL32(255, 0, 0, 100)) + end + ImGui.BeginChild("Red", ImVec2(200, 100), s.child_flags, 0 --[[ImGuiWindowFlags.None]]) + if s.override_bg_color then + ImGui.PopStyleColor() + end + + for n = 0, 49 do + ImGui.Text("Some test %d", n) + end + ImGui.EndChild() + local child_is_hovered = ImGui.IsItemHovered() + local child_rect_min = ImGui.GetItemRectMin() + local child_rect_max = ImGui.GetItemRectMax() + ImGui.Text("Hovered: %d", child_is_hovered and 1 or 0) + ImGui.Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y) + end + + ImGui.TreePop() end -end -local function DemoWindowLayout_WidgetsWidth() - IMGUI_DEMO_MARKER("Layout/Widgets Width") - _, SL.show_indented_items = ImGui.Checkbox("Show indented items", SL.show_indented_items) + if ImGui.TreeNode("Widgets Width") then + IMGUI_DEMO_MARKER("Layout/Widgets Width") + _, s.show_indented_items = ImGui.Checkbox("Show indented items", s.show_indented_items) - -- Use SetNextItemWidth() to set the width of a single upcoming item. - -- Use PushItemWidth()/PopItemWidth() to set the width of a group of items. - -- In real code use you'll probably want to choose width values that are proportional to your font size - -- e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. + -- Use SetNextItemWidth() to set the width of a single upcoming item. + -- Use PushItemWidth()/PopItemWidth() to set the width of a group of items. + -- In real code use you'll probably want to choose width values that are proportional to your font size + -- e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. - local function block(text, help, width, l1, l2) - ImGui.Text(text) - if help then ImGui.SameLine(); DemoHelpMarker(help) end - ImGui.PushItemWidth(width) - SL.f = ImGui.DragFloat(l1, SL.f) - if SL.show_indented_items then + ImGui.Text("SetNextItemWidth/PushItemWidth(100)") + ImGui.SameLine(); HelpMarker("Fixed width.") + ImGui.PushItemWidth(100) + s.f = ImGui.DragFloat("float##1b", s.f) + if s.show_indented_items then ImGui.Indent() - SL.f = ImGui.DragFloat(l2, SL.f) + s.f = ImGui.DragFloat("float (indented)##1b", s.f) ImGui.Unindent() end ImGui.PopItemWidth() - end - block("SetNextItemWidth/PushItemWidth(100)", "Fixed width.", 100, "float##1b", "float (indented)##1b") - block("SetNextItemWidth/PushItemWidth(-100)", "Align to right edge minus 100", -100, "float##2a", "float (indented)##2b") - block("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)", "Half of available width.\n(~ right-cursor_pos)\n(works within a column set)", ImGui.GetContentRegionAvail().x * 0.5, "float##3a", "float (indented)##3b") - block("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)", "Align to right edge minus half", -ImGui.GetContentRegionAvail().x * 0.5, "float##4a", "float (indented)##4b") - block("SetNextItemWidth/PushItemWidth(-Min(GetContentRegionAvail().x * 0.40f, GetFontSize() * 12))", nil, -IM_MIN(ImGui.GetFontSize() * 12, ImGui.GetContentRegionAvail().x * 0.40), "float##5a", "float (indented)##5b") - -- Demonstrate using PushItemWidth to surround three items. - -- Calling SetNextItemWidth() before each of them would have the same effect. - block("SetNextItemWidth/PushItemWidth(-FLT_MIN)", "Align to right edge", -1.1754943508223e-38 --[[FLT_MIN]], "##float6a", "float (indented)##6b") -end -local function DemoWindowLayout_BasicHorizontal() - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout") - ImGui.TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)") - - -- Text - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine") - ImGui.Text("Two items: Hello"); ImGui.SameLine() - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") - - -- Adjust spacing - ImGui.Text("More spacing: Hello"); ImGui.SameLine(0, 20) - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") - - -- Button - ImGui.AlignTextToFramePadding() - ImGui.Text("Normal buttons"); ImGui.SameLine() - ImGui.Button("Banana"); ImGui.SameLine() - ImGui.Button("Apple"); ImGui.SameLine() - ImGui.Button("Corniflower") - - -- Button - ImGui.Text("Small buttons"); ImGui.SameLine() - ImGui.SmallButton("Like this one"); ImGui.SameLine() - ImGui.Text("can fit within a text block.") - - -- Aligned to arbitrary position. Easy/cheap column. - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)") - ImGui.Text("Aligned") - ImGui.SameLine(150); ImGui.Text("x=150") - ImGui.SameLine(300); ImGui.Text("x=300") - ImGui.Text("Aligned") - ImGui.SameLine(150); ImGui.SmallButton("x=150") - ImGui.SameLine(300); ImGui.SmallButton("x=300") - - -- Checkbox - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)") - _, SL.c1 = ImGui.Checkbox("My", SL.c1); ImGui.SameLine() - _, SL.c2 = ImGui.Checkbox("Tailor", SL.c2); ImGui.SameLine() - _, SL.c3 = ImGui.Checkbox("Is", SL.c3); ImGui.SameLine() - _, SL.c4 = ImGui.Checkbox("Rich", SL.c4) - - -- Various - ImGui.PushItemWidth(ImGui.CalcTextSize("AAAAAAA").x) - local items = { "AAAA", "BBBB", "CCCC", "DDDD" } - if ImGui.Combo then - SL.item = ImGui.Combo("Combo", SL.item, items, #items) - else - NotPorted("Combo") - end - ImGui.SameLine() - SL.f0 = ImGui.SliderFloat("X", SL.f0, 0.0, 5.0); ImGui.SameLine() - SL.f1 = ImGui.SliderFloat("Y", SL.f1, 0.0, 5.0); ImGui.SameLine() - SL.f2 = ImGui.SliderFloat("Z", SL.f2, 0.0, 5.0) - - ImGui.Text("Lists:") - for i = 1, 4 do - if i > 1 then ImGui.SameLine() end - ImGui.PushID(i - 1) - if ImGui.ListBox then - SL.selection[i] = ImGui.ListBox("", SL.selection[i], items, #items) - else - NotPorted("ListBox") + ImGui.Text("SetNextItemWidth/PushItemWidth(-100)") + ImGui.SameLine(); HelpMarker("Align to right edge minus 100") + ImGui.PushItemWidth(-100) + s.f = ImGui.DragFloat("float##2a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##2b", s.f) + ImGui.Unindent() end - ImGui.PopID() - -- ImGui.SetItemTooltip("ListBox %d hovered", i) + ImGui.PopItemWidth() + + ImGui.Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)") + ImGui.SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)") + ImGui.PushItemWidth(ImGui.GetContentRegionAvail().x * 0.5) + s.f = ImGui.DragFloat("float##3a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##3b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + ImGui.Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)") + ImGui.SameLine(); HelpMarker("Align to right edge minus half") + ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.5) + s.f = ImGui.DragFloat("float##4a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##4b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + ImGui.Text("SetNextItemWidth/PushItemWidth(-Min(GetContentRegionAvail().x * 0.40f, GetFontSize() * 12))") + ImGui.PushItemWidth(-ImMin(ImGui.GetFontSize() * 12, ImGui.GetContentRegionAvail().x * 0.40)) + s.f = ImGui.DragFloat("float##5a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##5b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + -- Demonstrate using PushItemWidth to surround three items. + -- Calling SetNextItemWidth() before each of them would have the same effect. + ImGui.Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)") + ImGui.SameLine(); HelpMarker("Align to right edge") + ImGui.PushItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + s.f = ImGui.DragFloat("##float6a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##6b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + ImGui.TreePop() end - ImGui.PopItemWidth() - -- Dummy - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy") - local button_sz = ImVec2(40, 40) - ImGui.Button("A", button_sz); ImGui.SameLine() - ImGui.Dummy(button_sz); ImGui.SameLine() - ImGui.Button("B", button_sz) + if ImGui.TreeNode("Basic Horizontal Layout") then + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout") + ImGui.TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)") - -- Manually wrapping - -- (we should eventually provide this as an automatic layout feature, but for now you can do it manually) - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping") - ImGui.Text("Manual wrapping:") - local style = ImGui.GetStyle() - local buttons_count = 20 - local window_visible_x2 = ImGui.GetCursorScreenPos().x + ImGui.GetContentRegionAvail().x - for n = 0, buttons_count - 1 do - ImGui.PushID(n) - ImGui.Button("Box", button_sz) - local last_button_x2 = ImGui.GetItemRectMax().x - local next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x -- Expected position if next button was on same line - if n + 1 < buttons_count and next_button_x2 < window_visible_x2 then + -- Text + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine") + ImGui.Text("Two items: Hello"); ImGui.SameLine() + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") + + -- Adjust spacing + ImGui.Text("More spacing: Hello"); ImGui.SameLine(0, 20) + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") + + -- Button + ImGui.AlignTextToFramePadding() + ImGui.Text("Normal buttons"); ImGui.SameLine() + ImGui.Button("Banana"); ImGui.SameLine() + ImGui.Button("Apple"); ImGui.SameLine() + ImGui.Button("Corniflower") + + -- Button + ImGui.Text("Small buttons"); ImGui.SameLine() + ImGui.SmallButton("Like this one"); ImGui.SameLine() + ImGui.Text("can fit within a text block.") + + -- Aligned to arbitrary position. Easy/cheap column. + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)") + ImGui.Text("Aligned") + ImGui.SameLine(150); ImGui.Text("x=150") + ImGui.SameLine(300); ImGui.Text("x=300") + ImGui.Text("Aligned") + ImGui.SameLine(150); ImGui.SmallButton("x=150") + ImGui.SameLine(300); ImGui.SmallButton("x=300") + + -- Checkbox + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)") + _, s.c1 = ImGui.Checkbox("My", s.c1); ImGui.SameLine() + _, s.c2 = ImGui.Checkbox("Tailor", s.c2); ImGui.SameLine() + _, s.c3 = ImGui.Checkbox("Is", s.c3); ImGui.SameLine() + _, s.c4 = ImGui.Checkbox("Rich", s.c4) + + -- Various + ImGui.PushItemWidth(ImGui.CalcTextSize("AAAAAAA").x) + local items = { "AAAA", "BBBB", "CCCC", "DDDD" } + s.item = ImGui.Combo("Combo", s.item, items, #items); ImGui.SameLine() + s.f0 = ImGui.SliderFloat("X", s.f0, 0.0, 5.0); ImGui.SameLine() + s.f1 = ImGui.SliderFloat("Y", s.f1, 0.0, 5.0); ImGui.SameLine() + s.f2 = ImGui.SliderFloat("Z", s.f2, 0.0, 5.0) + + ImGui.Text("Lists:") + for i = 0, 3 do + if i > 0 then ImGui.SameLine() end + ImGui.PushID(i) + s.selection[i + 1] = ImGui.ListBox("", s.selection[i + 1], items, #items) + ImGui.PopID() + --ImGui.SetItemTooltip("ListBox %d hovered", i); + end + ImGui.PopItemWidth() + + -- Dummy + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy") + local button_sz = ImVec2(40, 40) + ImGui.Button("A", button_sz); ImGui.SameLine() + ImGui.Dummy(button_sz); ImGui.SameLine() + ImGui.Button("B", button_sz) + + -- Manually wrapping + -- (we should eventually provide this as an automatic layout feature, but for now you can do it manually) + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping") + ImGui.Text("Manual wrapping:") + local style = ImGui.GetStyle() + local buttons_count = 20 + local window_visible_x2 = ImGui.GetCursorScreenPos().x + ImGui.GetContentRegionAvail().x + for n = 0, buttons_count - 1 do + ImGui.PushID(n) + ImGui.Button("Box", button_sz) + local last_button_x2 = ImGui.GetItemRectMax().x + local next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x -- Expected position if next button was on same line + if n + 1 < buttons_count and next_button_x2 < window_visible_x2 then + ImGui.SameLine() + end + ImGui.PopID() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Groups") then + IMGUI_DEMO_MARKER("Layout/Groups") + HelpMarker( + "BeginGroup() basically locks the horizontal position for new line. " .. + "EndGroup() bundles the whole group so that you can use \"item\" functions such as " .. + "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.") + ImGui.BeginGroup() + do + ImGui.BeginGroup() + ImGui.Button("AAA") ImGui.SameLine() + ImGui.Button("BBB") + ImGui.SameLine() + ImGui.BeginGroup() + ImGui.Button("CCC") + ImGui.Button("DDD") + ImGui.EndGroup() + ImGui.SameLine() + ImGui.Button("EEE") + ImGui.EndGroup() + ImGui.SetItemTooltip("First group hovered") end - ImGui.PopID() - end -end + -- Capture the group size and create widgets using the same size + local size = ImGui.GetItemRectSize() + local values = { 0.5, 0.20, 0.80, 0.60, 0.25 } + ImGui.PlotHistogram("##values", values, nil, #values, 0, nil, 0.0, 1.0, size) -local function DemoWindowLayout_Groups() - IMGUI_DEMO_MARKER("Layout/Groups") - DemoHelpMarker( - "BeginGroup() basically locks the horizontal position for new line. " .. - "EndGroup() bundles the whole group so that you can use \"item\" functions such as " .. - "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.") - ImGui.BeginGroup() - do - ImGui.BeginGroup() - ImGui.Button("AAA") + ImGui.Button("ACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) ImGui.SameLine() - ImGui.Button("BBB") - ImGui.SameLine() - ImGui.BeginGroup() - ImGui.Button("CCC") - ImGui.Button("DDD") + ImGui.Button("REACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) ImGui.EndGroup() ImGui.SameLine() - ImGui.Button("EEE") - ImGui.EndGroup() - ImGui.SetItemTooltip("First group hovered") - end - -- Capture the group size and create widgets using the same size - local size = ImGui.GetItemRectSize() - local values = { 0.5, 0.20, 0.80, 0.60, 0.25 } - ImGui.PlotHistogram("##values", values, nil, #values, 0, nil, 0.0, 1.0, size) - ImGui.Button("ACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) - ImGui.SameLine() - ImGui.Button("REACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) - ImGui.EndGroup() - ImGui.SameLine() - - ImGui.Button("LEVERAGE\nBUZZWORD", size) - ImGui.SameLine() - - if ImGui.BeginListBox and ImGui.BeginListBox("List", size) then - ImGui.Selectable("Selected", true) - ImGui.Selectable("Not Selected", false) - ImGui.EndListBox() - end -end - -local function DemoWindowLayout_TextBaseline() - IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment") - do - ImGui.BulletText("Text baseline:") - ImGui.SameLine(); DemoHelpMarker( - "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " .. - "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.") - ImGui.Indent() - - ImGui.Text("KO Blahblah"); ImGui.SameLine() - ImGui.Button("Some framed item"); ImGui.SameLine() - DemoHelpMarker("Baseline of button will look misaligned with text..") - - -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. - -- (because we don't know what's coming after the Text() statement, we need to move the text baseline - -- down by FramePadding.y ahead of time) - ImGui.AlignTextToFramePadding() - ImGui.Text("OK Blahblah"); ImGui.SameLine() - ImGui.Button("Some framed item##2"); ImGui.SameLine() - DemoHelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y") - - -- SmallButton() uses the same vertical padding as Text - ImGui.Button("TEST##1"); ImGui.SameLine() - ImGui.Text("TEST"); ImGui.SameLine() - ImGui.SmallButton("TEST##2") - - -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. - ImGui.AlignTextToFramePadding() - ImGui.Text("Text aligned to framed item"); ImGui.SameLine() - ImGui.Button("Item##1"); ImGui.SameLine() - ImGui.Text("Item"); ImGui.SameLine() - ImGui.SmallButton("Item##2"); ImGui.SameLine() - ImGui.Button("Item##3") - - ImGui.Unindent() - end - - ImGui.Spacing() - - do - ImGui.BulletText("Multi-line text:") - ImGui.Indent() - ImGui.Text("One\nTwo\nThree"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("Banana") - - ImGui.Text("Banana"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("One\nTwo\nThree") - - ImGui.Button("HOP##1"); ImGui.SameLine() - ImGui.Text("Banana"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("Banana") - - ImGui.Button("HOP##2"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("Banana") - ImGui.Unindent() - end - - ImGui.Spacing() - - do - ImGui.BulletText("Misc items:") - ImGui.Indent() - - -- SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. - ImGui.Button("80x80", ImVec2(80, 80)) + ImGui.Button("LEVERAGE\nBUZZWORD", size) ImGui.SameLine() - ImGui.Button("50x50", ImVec2(50, 50)) - ImGui.SameLine() - ImGui.Button("Button()") - ImGui.SameLine() - ImGui.SmallButton("SmallButton()") - -- Tree - -- (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags.DrawLinesNone to disable hierarchy outline) - local spacing = ImGui.GetStyle().ItemInnerSpacing.x - ImGui.Button("Button##1") -- Will make line higher - ImGui.SameLine(0.0, spacing) - if ImGui.TreeNodeEx("Node##1", 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) then - -- Placeholder tree data - for i = 0, 5 do - ImGui.BulletText("Item %d..", i) - end - ImGui.TreePop() + if ImGui.BeginListBox("List", size) then + ImGui.Selectable("Selected", true) + ImGui.Selectable("Not Selected", false) + ImGui.EndListBox() end - local padding = math.floor(ImGui.GetFontSize() * 1.20) -- Large padding - ImGui.PushStyleVarY(11 --[[ImGuiStyleVar.FramePadding]], padding) - ImGui.Button("Button##2") - ImGui.PopStyleVar() - ImGui.SameLine(0.0, spacing) - if ImGui.TreeNodeEx("Node##2", 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) then - ImGui.TreePop() + ImGui.TreePop() + end + + if ImGui.TreeNode("Text Baseline Alignment") then + IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment") + do + ImGui.BulletText("Text baseline:") + ImGui.SameLine(); HelpMarker( + "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " .. + "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.") + ImGui.Indent() + + ImGui.Text("KO Blahblah"); ImGui.SameLine() + ImGui.Button("Some framed item"); ImGui.SameLine() + HelpMarker("Baseline of button will look misaligned with text..") + + -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. + -- (because we don't know what's coming after the Text() statement, we need to move the text baseline + -- down by FramePadding.y ahead of time) + ImGui.AlignTextToFramePadding() + ImGui.Text("OK Blahblah"); ImGui.SameLine() + ImGui.Button("Some framed item##2"); ImGui.SameLine() + HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y") + + -- SmallButton() uses the same vertical padding as Text + ImGui.Button("TEST##1"); ImGui.SameLine() + ImGui.Text("TEST"); ImGui.SameLine() + ImGui.SmallButton("TEST##2") + + -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. + ImGui.AlignTextToFramePadding() + ImGui.Text("Text aligned to framed item"); ImGui.SameLine() + ImGui.Button("Item##1"); ImGui.SameLine() + ImGui.Text("Item"); ImGui.SameLine() + ImGui.SmallButton("Item##2"); ImGui.SameLine() + ImGui.Button("Item##3") + + ImGui.Unindent() end - -- Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. - -- Otherwise you can use SmallButton() (smaller fit). - ImGui.AlignTextToFramePadding() + ImGui.Spacing() - -- Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add - -- other contents "inside" the node. - local node_open = ImGui.TreeNode("Node##3") - ImGui.SameLine(0.0, spacing); ImGui.Button("Button##3") - if node_open then - -- Placeholder tree data - for i = 0, 5 do - ImGui.BulletText("Item %d..", i) - end - ImGui.TreePop() + do + ImGui.BulletText("Multi-line text:") + ImGui.Indent() + ImGui.Text("One\nTwo\nThree"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("Banana") + + ImGui.Text("Banana"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("One\nTwo\nThree") + + ImGui.Button("HOP##1"); ImGui.SameLine() + ImGui.Text("Banana"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("Banana") + + ImGui.Button("HOP##2"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("Banana") + ImGui.Unindent() end - -- Bullet - ImGui.Button("Button##4") - ImGui.SameLine(0.0, spacing) - ImGui.BulletText("Bullet text") + ImGui.Spacing() - ImGui.AlignTextToFramePadding() - ImGui.BulletText("Node") - ImGui.SameLine(0.0, spacing); ImGui.Button("Button##5") - ImGui.Unindent() - end -end + do + ImGui.BulletText("Misc items:") + ImGui.Indent() -local function DemoWindowLayout_HorizontalContentsSizeWindow() - if SL.explicit_content_size then - ImGui.SetNextWindowContentSize(ImVec2(SL.contents_size_x, 0.0)) - end - SL.show_horizontal_contents_size_demo_window = ImGui.Begin("Horizontal contents size demo window", SL.show_horizontal_contents_size_demo_window, SL.show_h_scrollbar and 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]] or 0) - IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window") - ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(2, 0)) - ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(2, 0)) - DemoHelpMarker( - "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n" .. - "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.") - _, SL.show_h_scrollbar = ImGui.Checkbox("H-scrollbar", SL.show_h_scrollbar) - _, SL.show_button = ImGui.Checkbox("Button", SL.show_button) -- Will grow contents size (unless explicitly overwritten) - _, SL.show_tree_nodes = ImGui.Checkbox("Tree nodes", SL.show_tree_nodes) -- Will grow contents size and display highlight over full width - _, SL.show_text_wrapped = ImGui.Checkbox("Text wrapped", SL.show_text_wrapped) -- Will grow and use contents size - _, SL.show_columns = ImGui.Checkbox("Columns", SL.show_columns) -- Will use contents size - _, SL.show_tab_bar = ImGui.Checkbox("Tab bar", SL.show_tab_bar) -- Will use contents size - _, SL.show_child = ImGui.Checkbox("Child", SL.show_child) -- Will grow and use contents size - _, SL.explicit_content_size = ImGui.Checkbox("Explicit content size", SL.explicit_content_size) - ImGui.Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui.GetScrollX(), ImGui.GetScrollMaxX(), ImGui.GetScrollY(), ImGui.GetScrollMaxY()) - if SL.explicit_content_size then - ImGui.SameLine() - ImGui.SetNextItemWidth(ImGui.CalcTextSize("123456").x) - SL.contents_size_x = ImGui.DragFloat("##csx", SL.contents_size_x) - local p = ImGui.GetCursorScreenPos() - ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), 4294967295 --[[IM_COL32_WHITE]]) - ImGui.GetWindowDrawList():AddRectFilled(ImVec2(p.x + SL.contents_size_x - 10, p.y), ImVec2(p.x + SL.contents_size_x, p.y + 10), 4294967295 --[[IM_COL32_WHITE]]) - ImGui.Dummy(ImVec2(0, 10)) - end - ImGui.PopStyleVar(2) - ImGui.Separator() - if SL.show_button then - ImGui.Button("this is a 300-wide button", ImVec2(300, 0)) - end - if SL.show_tree_nodes then - local open = true - if ImGui.TreeNode("this is a tree node") then - if ImGui.TreeNode("another one of those tree node...") then - ImGui.Text("Some tree contents") + -- SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. + ImGui.Button("80x80", ImVec2(80, 80)) + ImGui.SameLine() + ImGui.Button("50x50", ImVec2(50, 50)) + ImGui.SameLine() + ImGui.Button("Button()") + ImGui.SameLine() + ImGui.SmallButton("SmallButton()") + + -- Tree + -- (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags.DrawLinesNone to disable hierarchy outline) + local spacing = ImGui.GetStyle().ItemInnerSpacing.x + ImGui.Button("Button##1") -- Will make line higher + ImGui.SameLine(0.0, spacing) + if ImGui.TreeNodeEx("Node##1", 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) then + -- Placeholder tree data + for i = 0, 5 do + ImGui.BulletText("Item %d..", i) + end ImGui.TreePop() end - ImGui.TreePop() - end - ImGui.CollapsingHeader("CollapsingHeader", open) - end - if SL.show_text_wrapped then - ImGui.TextWrapped("This text should automatically wrap on the edge of the work rectangle.") - end - if SL.show_columns then - ImGui.Text("Tables:") - if ImGui.BeginTable("table", 4, 1920 --[[ImGuiTableFlags.Borders]]) then - for n = 0, 3 do - ImGui.TableNextColumn() - ImGui.Text("Width %.2f", ImGui.GetContentRegionAvail().x) + + local padding = math.floor(ImGui.GetFontSize() * 1.20) -- Large padding + ImGui.PushStyleVarY(11 --[[ImGuiStyleVar.FramePadding]], padding) + ImGui.Button("Button##2") + ImGui.PopStyleVar() + ImGui.SameLine(0.0, spacing) + if ImGui.TreeNodeEx("Node##2", 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) then + ImGui.TreePop() end - ImGui.EndTable() - end - ImGui.Text("Columns:") - if ImGui.Columns then - ImGui.Columns(4) - for n = 0, 3 do - ImGui.Text("Width %.2f", ImGui.GetColumnWidth()) - ImGui.NextColumn() + + -- Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. + -- Otherwise you can use SmallButton() (smaller fit). + ImGui.AlignTextToFramePadding() + + -- Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add + -- other contents "inside" the node. + local node_open = ImGui.TreeNode("Node##3") + ImGui.SameLine(0.0, spacing); ImGui.Button("Button##3") + if node_open then + -- Placeholder tree data + for i = 0, 5 do + ImGui.BulletText("Item %d..", i) + end + ImGui.TreePop() end - ImGui.Columns(1) - else - NotPorted("Columns") + + -- Bullet + ImGui.Button("Button##4") + ImGui.SameLine(0.0, spacing) + ImGui.BulletText("Bullet text") + + ImGui.AlignTextToFramePadding() + ImGui.BulletText("Node") + ImGui.SameLine(0.0, spacing); ImGui.Button("Button##5") + ImGui.Unindent() end - end - if SL.show_tab_bar and ImGui.BeginTabBar and ImGui.BeginTabBar("Hello") then - if ImGui.BeginTabItem("OneOneOne") then ImGui.EndTabItem() end - if ImGui.BeginTabItem("TwoTwoTwo") then ImGui.EndTabItem() end - if ImGui.BeginTabItem("ThreeThreeThree") then ImGui.EndTabItem() end - if ImGui.BeginTabItem("FourFourFour") then ImGui.EndTabItem() end - ImGui.EndTabBar() - end - if SL.show_child then - BeginChild("child", ImVec2(0, 0), 1 --[[ImGuiChildFlags.Borders]]) - ImGui.EndChild() - end - ImGui.End() -end -local function DemoWindowLayout_Scrolling() - IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical") - -- Vertical scroll functions - DemoHelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.") - - _, SL.enable_extra_decorations = ImGui.Checkbox("Decoration", SL.enable_extra_decorations) - - ImGui.PushItemWidth(ImGui.GetFontSize() * 10) - local changed - SL.track_item, changed = ImGui.DragInt("##item", SL.track_item, 0.25, 0, 99, "Item = %d") - SL.enable_track = SL.enable_track or changed - ImGui.SameLine() - _, SL.enable_track = ImGui.Checkbox("Track", SL.enable_track) - - local scroll_to_off - SL.scroll_to_off_px, scroll_to_off = ImGui.DragFloat("##off", SL.scroll_to_off_px, 1.00, 0, 3.4028234663853e+38 --[[FLT_MAX]], "+%.0f px") - ImGui.SameLine() - scroll_to_off = ImGui.Button("Scroll Offset") or scroll_to_off - - local scroll_to_pos - SL.scroll_to_pos_px, scroll_to_pos = ImGui.DragFloat("##pos", SL.scroll_to_pos_px, 1.00, -10, 3.4028234663853e+38 --[[FLT_MAX]], "X/Y = %.0f px") - ImGui.SameLine() - scroll_to_pos = ImGui.Button("Scroll To Pos") or scroll_to_pos - ImGui.PopItemWidth() - - if scroll_to_off or scroll_to_pos then - SL.enable_track = false + ImGui.TreePop() end - local style = ImGui.GetStyle() - local child_w = (ImGui.GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5 - if child_w < 1.0 then - child_w = 1.0 - end - ImGui.PushID("##VerticalScrolling") - local vnames = { "Top", "25%", "Center", "75%", "Bottom" } - for i = 0, 4 do - if i > 0 then ImGui.SameLine() end - ImGui.BeginGroup() - ImGui.TextUnformatted(vnames[i + 1]) + if ImGui.TreeNode("Scrolling") then + IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical") + -- Vertical scroll functions + HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.") - local child_flags = SL.enable_extra_decorations and 1024 --[[ImGuiWindowFlags.MenuBar]] or 0 - local child_id = ImGui.GetID(i) - local child_is_visible = BeginChild(child_id, ImVec2(child_w, 200.0), 1 --[[ImGuiChildFlags.Borders]], child_flags) - if ImGui.BeginMenuBar() then - ImGui.TextUnformatted("abc") - ImGui.EndMenuBar() + _, s.enable_extra_decorations = ImGui.Checkbox("Decoration", s.enable_extra_decorations) + + ImGui.PushItemWidth(ImGui.GetFontSize() * 10) + local track_changed + s.track_item, track_changed = ImGui.DragInt("##item", s.track_item, 0.25, 0, 99, "Item = %d") + s.enable_track = s.enable_track or track_changed + ImGui.SameLine() + _, s.enable_track = ImGui.Checkbox("Track", s.enable_track) + + local scroll_to_off + s.scroll_to_off_px, scroll_to_off = ImGui.DragFloat("##off", s.scroll_to_off_px, 1.00, 0, 3.4028234663853e+38 --[[FLT_MAX]], "+%.0f px") + ImGui.SameLine() + scroll_to_off = ImGui.Button("Scroll Offset") or scroll_to_off + + local scroll_to_pos + s.scroll_to_pos_px, scroll_to_pos = ImGui.DragFloat("##pos", s.scroll_to_pos_px, 1.00, -10, 3.4028234663853e+38 --[[FLT_MAX]], "X/Y = %.0f px") + ImGui.SameLine() + scroll_to_pos = ImGui.Button("Scroll To Pos") or scroll_to_pos + ImGui.PopItemWidth() + + if scroll_to_off or scroll_to_pos then + s.enable_track = false end - if scroll_to_off then - ImGui.SetScrollY(SL.scroll_to_off_px) + + local style = ImGui.GetStyle() + local child_w = (ImGui.GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5 + if child_w < 1.0 then + child_w = 1.0 end - if scroll_to_pos then - ImGui.SetScrollFromPosY(ImGui.GetCursorStartPos().y + SL.scroll_to_pos_px, i * 0.25) - end - if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items - for item = 0, 99 do - if SL.enable_track and item == SL.track_item then - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) - ImGui.SetScrollHereY(i * 0.25) -- 0.0f:top, 0.5f:center, 1.0f:bottom - else - ImGui.Text("Item %d", item) + ImGui.PushID("##VerticalScrolling") + for i = 0, 4 do + if i > 0 then ImGui.SameLine() end + ImGui.BeginGroup() + local names = { "Top", "25%", "Center", "75%", "Bottom" } + ImGui.TextUnformatted(names[i + 1]) + + local child_flags = 0 + if s.enable_extra_decorations then child_flags = 1024 --[[ImGuiWindowFlags.MenuBar]] end + local child_id = ImGui.GetID(i) + local child_is_visible = ImGui.BeginChild(child_id, ImVec2(child_w, 200.0), 1 --[[ImGuiChildFlags.Borders]], child_flags) + if ImGui.BeginMenuBar() then + ImGui.TextUnformatted("abc") + ImGui.EndMenuBar() + end + if scroll_to_off then + ImGui.SetScrollY(s.scroll_to_off_px) + end + if scroll_to_pos then + ImGui.SetScrollFromPosY(ImGui.GetCursorStartPos().y + s.scroll_to_pos_px, i * 0.25) + end + if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items + for item = 0, 99 do + if s.enable_track and item == s.track_item then + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) + ImGui.SetScrollHereY(i * 0.25) -- 0.0f:top, 0.5f:center, 1.0f:bottom + else + ImGui.Text("Item %d", item) + end end end + local scroll_y = ImGui.GetScrollY() + local scroll_max_y = ImGui.GetScrollMaxY() + ImGui.EndChild() + ImGui.Text("%.0f/%.0f", scroll_y, scroll_max_y) + ImGui.EndGroup() end - local scroll_y = ImGui.GetScrollY() - local scroll_max_y = ImGui.GetScrollMaxY() - ImGui.EndChild() - ImGui.Text("%.0f/%.0f", scroll_y, scroll_max_y) - ImGui.EndGroup() - end - ImGui.PopID() + ImGui.PopID() - -- Horizontal scroll functions - IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal") - ImGui.Spacing() - DemoHelpMarker( - "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" .. - "Because the clipping rectangle of most window hides half worth of WindowPadding on the " .. - "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " .. - "equivalent SetScrollFromPosY(+1) wouldn't.") - ImGui.PushID("##HorizontalScrolling") - local hnames = { "Left", "25%", "Center", "75%", "Right" } - for i = 0, 4 do - local child_height = ImGui.GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0 - local child_flags = bit32.bor(2048 --[[ImGuiWindowFlags.HorizontalScrollbar]], SL.enable_extra_decorations and 16384 --[[ImGuiWindowFlags.AlwaysVerticalScrollbar]] or 0) - local child_id = ImGui.GetID(i) - local child_is_visible = BeginChild(child_id, ImVec2(-100, child_height), 1 --[[ImGuiChildFlags.Borders]], child_flags) - if scroll_to_off then - ImGui.SetScrollX(SL.scroll_to_off_px) - end - if scroll_to_pos then - ImGui.SetScrollFromPosX(ImGui.GetCursorStartPos().x + SL.scroll_to_pos_px, i * 0.25) - end - if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items - for item = 0, 99 do - if item > 0 then - ImGui.SameLine() - end - if SL.enable_track and item == SL.track_item then - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) - ImGui.SetScrollHereX(i * 0.25) -- 0.0f:left, 0.5f:center, 1.0f:right - else - ImGui.Text("Item %d", item) + -- Horizontal scroll functions + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal") + ImGui.Spacing() + HelpMarker( + "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" .. + "Because the clipping rectangle of most window hides half worth of WindowPadding on the " .. + "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " .. + "equivalent SetScrollFromPosY(+1) wouldn't.") + ImGui.PushID("##HorizontalScrolling") + for i = 0, 4 do + local child_height = ImGui.GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0 + local child_flags = 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]] + if s.enable_extra_decorations then child_flags = bit32.bor(child_flags, 16384 --[[ImGuiWindowFlags.AlwaysVerticalScrollbar]]) end + local child_id = ImGui.GetID(i) + local child_is_visible = ImGui.BeginChild(child_id, ImVec2(-100, child_height), 1 --[[ImGuiChildFlags.Borders]], child_flags) + if scroll_to_off then + ImGui.SetScrollX(s.scroll_to_off_px) + end + if scroll_to_pos then + ImGui.SetScrollFromPosX(ImGui.GetCursorStartPos().x + s.scroll_to_pos_px, i * 0.25) + end + if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items + for item = 0, 99 do + if item > 0 then + ImGui.SameLine() + end + if s.enable_track and item == s.track_item then + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) + ImGui.SetScrollHereX(i * 0.25) -- 0.0f:left, 0.5f:center, 1.0f:right + else + ImGui.Text("Item %d", item) + end end end + local scroll_x = ImGui.GetScrollX() + local scroll_max_x = ImGui.GetScrollMaxX() + ImGui.EndChild() + ImGui.SameLine() + local names = { "Left", "25%", "Center", "75%", "Right" } + ImGui.Text("%s\n%.0f/%.0f", names[i + 1], scroll_x, scroll_max_x) + ImGui.Spacing() + end + ImGui.PopID() + + -- Miscellaneous Horizontal Scrolling Demo + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)") + HelpMarker( + "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" .. + "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().") + s.lines = ImGui.SliderInt("Lines", s.lines, 1, 15) + ImGui.PushStyleVar(12 --[[ImGuiStyleVar.FrameRounding]], 3.0) + ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(2.0, 1.0)) + local scrolling_child_size = ImVec2(0, ImGui.GetFrameHeightWithSpacing() * 7 + 30) + ImGui.BeginChild("scrolling", scrolling_child_size, 1 --[[ImGuiChildFlags.Borders]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) + for line = 0, s.lines - 1 do + -- Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() + -- If you want to create your own time line for a real application you may be better off manipulating + -- the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets + -- yourself. You may also want to use the lower-level ImDrawList API. + local num_buttons = 10 + ((line % 2 == 1) and line * 9 or line * 3) + local base_w = ImGui.GetFontSize() * 3 + for n = 0, num_buttons - 1 do + if n > 0 then ImGui.SameLine() end + ImGui.PushID(n + line * 1000) + local num_buf = string.format("%d", n) + local label = num_buf + if n % 15 == 0 then label = "FizzBuzz" elseif n % 3 == 0 then label = "Fizz" elseif n % 5 == 0 then label = "Buzz" end + local hue = n * 0.05 + ImGui.PushStyleColor(22 --[[ImGuiCol.Button]], ImColor.HSV(hue, 0.6, 0.6).Value) + ImGui.PushStyleColor(23 --[[ImGuiCol.ButtonHovered]], ImColor.HSV(hue, 0.7, 0.7).Value) + ImGui.PushStyleColor(24 --[[ImGuiCol.ButtonActive]], ImColor.HSV(hue, 0.8, 0.8).Value) + ImGui.Button(label, ImVec2(base_w + math.sin(line + n) * base_w * 0.5, 0.0)) + ImGui.PopStyleColor(3) + ImGui.PopID() + end end local scroll_x = ImGui.GetScrollX() local scroll_max_x = ImGui.GetScrollMaxX() ImGui.EndChild() + ImGui.PopStyleVar(2) + local scroll_x_delta = 0.0 + ImGui.SmallButton("<<") + if ImGui.IsItemActive() then + scroll_x_delta = -ImGui.GetIO().DeltaTime * 1000.0 + end ImGui.SameLine() - ImGui.Text("%s\n%.0f/%.0f", hnames[i + 1], scroll_x, scroll_max_x) + ImGui.Text("Scroll from code"); ImGui.SameLine() + ImGui.SmallButton(">>") + if ImGui.IsItemActive() then + scroll_x_delta = ImGui.GetIO().DeltaTime * 1000.0 + end + ImGui.SameLine() + ImGui.Text("%.0f/%.0f", scroll_x, scroll_max_x) + if scroll_x_delta ~= 0.0 then + -- Demonstrate a trick: you can use Begin to set yourself in the context of another window + -- (here we are already out of your child window) + ImGui.BeginChild("scrolling") + ImGui.SetScrollX(ImGui.GetScrollX() + scroll_x_delta) + ImGui.EndChild() + end ImGui.Spacing() - end - ImGui.PopID() - -- Miscellaneous Horizontal Scrolling Demo - IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)") - DemoHelpMarker( - "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" .. - "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().") - SL.lines = ImGui.SliderInt("Lines", SL.lines, 1, 15) - ImGui.PushStyleVar(12 --[[ImGuiStyleVar.FrameRounding]], 3.0) - ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(2.0, 1.0)) - local scrolling_child_size = ImVec2(0, ImGui.GetFrameHeightWithSpacing() * 7 + 30) - BeginChild("scrolling", scrolling_child_size, 1 --[[ImGuiChildFlags.Borders]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) - for line = 0, SL.lines - 1 do - -- Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() - -- If you want to create your own time line for a real application you may be better off manipulating - -- the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets - -- yourself. You may also want to use the lower-level ImDrawList API. - local num_buttons = 10 + ((line % 2 == 1) and line * 9 or line * 3) - local base_w = ImGui.GetFontSize() * 3 - for n = 0, num_buttons - 1 do - if n > 0 then ImGui.SameLine() end - ImGui.PushID(n + line * 1000) - local label = (n % 15 == 0) and "FizzBuzz" or (n % 3 == 0) and "Fizz" or (n % 5 == 0) and "Buzz" or tostring(n) - local hue = n * 0.05 - ImGui.PushStyleColor(22 --[[ImGuiCol.Button]], HSV(hue, 0.6, 0.6)) - ImGui.PushStyleColor(23 --[[ImGuiCol.ButtonHovered]], HSV(hue, 0.7, 0.7)) - ImGui.PushStyleColor(24 --[[ImGuiCol.ButtonActive]], HSV(hue, 0.8, 0.8)) - ImGui.Button(label, ImVec2(base_w + math.sin(line + n) * base_w * 0.5, 0.0)) - ImGui.PopStyleColor(3) + _, s.show_horizontal_contents_size_demo_window = ImGui.Checkbox("Show Horizontal contents size demo window", s.show_horizontal_contents_size_demo_window) + + if s.show_horizontal_contents_size_demo_window then + if s.explicit_content_size then + ImGui.SetNextWindowContentSize(ImVec2(s.contents_size_x, 0.0)) + end + local window_flags = 0 + if s.show_h_scrollbar then window_flags = 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]] end + s.show_horizontal_contents_size_demo_window = ImGui.Begin("Horizontal contents size demo window", s.show_horizontal_contents_size_demo_window, window_flags) + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window") + ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(2, 0)) + ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(2, 0)) + HelpMarker( + "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n" .. + "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.") + _, s.show_h_scrollbar = ImGui.Checkbox("H-scrollbar", s.show_h_scrollbar) + _, s.show_button = ImGui.Checkbox("Button", s.show_button) -- Will grow contents size (unless explicitly overwritten) + _, s.show_tree_nodes = ImGui.Checkbox("Tree nodes", s.show_tree_nodes) -- Will grow contents size and display highlight over full width + _, s.show_text_wrapped = ImGui.Checkbox("Text wrapped", s.show_text_wrapped)-- Will grow and use contents size + _, s.show_columns = ImGui.Checkbox("Columns", s.show_columns) -- Will use contents size + _, s.show_tab_bar = ImGui.Checkbox("Tab bar", s.show_tab_bar) -- Will use contents size + _, s.show_child = ImGui.Checkbox("Child", s.show_child) -- Will grow and use contents size + _, s.explicit_content_size = ImGui.Checkbox("Explicit content size", s.explicit_content_size) + ImGui.Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui.GetScrollX(), ImGui.GetScrollMaxX(), ImGui.GetScrollY(), ImGui.GetScrollMaxY()) + if s.explicit_content_size then + ImGui.SameLine() + ImGui.SetNextItemWidth(ImGui.CalcTextSize("123456").x) + s.contents_size_x = ImGui.DragFloat("##csx", s.contents_size_x) + local p = ImGui.GetCursorScreenPos() + ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), 4294967295 --[[IM_COL32_WHITE]]) + ImGui.GetWindowDrawList():AddRectFilled(ImVec2(p.x + s.contents_size_x - 10, p.y), ImVec2(p.x + s.contents_size_x, p.y + 10), 4294967295 --[[IM_COL32_WHITE]]) + ImGui.Dummy(ImVec2(0, 10)) + end + ImGui.PopStyleVar(2) + ImGui.Separator() + if s.show_button then + ImGui.Button("this is a 300-wide button", ImVec2(300, 0)) + end + if s.show_tree_nodes then + local open = true + if ImGui.TreeNode("this is a tree node") then + if ImGui.TreeNode("another one of those tree node...") then + ImGui.Text("Some tree contents") + ImGui.TreePop() + end + ImGui.TreePop() + end + _, open = ImGui.CollapsingHeader("CollapsingHeader", open) + end + if s.show_text_wrapped then + ImGui.TextWrapped("This text should automatically wrap on the edge of the work rectangle.") + end + if s.show_columns then + ImGui.Text("Tables:") + if ImGui.BeginTable("table", 4, 1920 --[[ImGuiTableFlags.Borders]]) then + for n = 0, 3 do + ImGui.TableNextColumn() + ImGui.Text("Width %.2f", ImGui.GetContentRegionAvail().x) + end + ImGui.EndTable() + end + ImGui.Text("Columns:") + ImGui.Columns(4) + for n = 0, 3 do + ImGui.Text("Width %.2f", ImGui.GetColumnWidth()) + ImGui.NextColumn() + end + ImGui.Columns(1) + end + if s.show_tab_bar and ImGui.BeginTabBar("Hello") then + if ImGui.BeginTabItem("OneOneOne") then ImGui.EndTabItem() end + if ImGui.BeginTabItem("TwoTwoTwo") then ImGui.EndTabItem() end + if ImGui.BeginTabItem("ThreeThreeThree") then ImGui.EndTabItem() end + if ImGui.BeginTabItem("FourFourFour") then ImGui.EndTabItem() end + ImGui.EndTabBar() + end + if s.show_child then + ImGui.BeginChild("child", ImVec2(0, 0), 1 --[[ImGuiChildFlags.Borders]]) + ImGui.EndChild() + end + ImGui.End() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Text Clipping") then + IMGUI_DEMO_MARKER("Layout/Text Clipping") + local size = s.size + local offset = s.offset + ImGui.DragFloat2("size", size, 0.5, 1.0, 200.0, "%.0f") + ImGui.TextWrapped("(Click and drag to scroll)") + + HelpMarker( + "(Left) Using ImGui::PushClipRect():\n" .. + "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" .. + "(use this if you want your clipping rectangle to affect interactions)\n\n" .. + "(Center) Using ImDrawList::PushClipRect():\n" .. + "Will alter ImDrawList rendering only.\n" .. + "(use this as a shortcut if you are only using ImDrawList calls)\n\n" .. + "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n" .. + "Will alter only this specific ImDrawList::AddText() rendering.\n" .. + "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.") + + for n = 0, 2 do repeat + if n > 0 then + ImGui.SameLine() + end + + ImGui.PushID(n) + ImGui.InvisibleButton("##canvas", size) + if ImGui.IsItemActive() and ImGui.IsMouseDragging(0 --[[ImGuiMouseButton.Left]]) then + offset.x = offset.x + ImGui.GetIO().MouseDelta.x + offset.y = offset.y + ImGui.GetIO().MouseDelta.y + end ImGui.PopID() + if not ImGui.IsItemVisible() then -- Skip rendering as ImDrawList elements are not clipped. + break -- continue + end + + local p0 = ImGui.GetItemRectMin() + local p1 = ImGui.GetItemRectMax() + local text_str = "Line 1 hello\nLine 2 clip me!" + local text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y) + local draw_list = ImGui.GetWindowDrawList() + if n == 0 then + ImGui.PushClipRect(p0, p1, true) + draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) + draw_list:AddText(text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str) + ImGui.PopClipRect() + elseif n == 1 then + draw_list:PushClipRect(p0, p1, true) + draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) + draw_list:AddText(text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str) + draw_list:PopClipRect() + elseif n == 2 then + local clip_rect = ImVec4(p0.x, p0.y, p1.x, p1.y) -- AddText() takes a ImVec4* here so let's convert. + draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) + draw_list:AddText(ImGui.GetFont(), ImGui.GetFontSize(), text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str, 1, #text_str + 1, 0.0, clip_rect) -- [Port] explicit text_begin/text_end (port's AddText needs text_end) + end + until true end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Overlap Mode") then + IMGUI_DEMO_MARKER("Layout/Overlap Mode") + + HelpMarker( + "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n" .. + "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. " .. + "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.") + _, s.enable_allow_overlap = ImGui.Checkbox("Enable AllowOverlap", s.enable_allow_overlap) + + local button1_pos = ImGui.GetCursorScreenPos() + local button2_pos = ImVec2(button1_pos.x + 50.0, button1_pos.y + 50.0) + if s.enable_allow_overlap then + ImGui.SetNextItemAllowOverlap() end - end - local scroll_x = ImGui.GetScrollX() - local scroll_max_x = ImGui.GetScrollMaxX() - ImGui.EndChild() - ImGui.PopStyleVar(2) - local scroll_x_delta = 0.0 - ImGui.SmallButton("<<") - if ImGui.IsItemActive() then - scroll_x_delta = -ImGui.GetIO().DeltaTime * 1000.0 - end - ImGui.SameLine() - ImGui.Text("Scroll from code"); ImGui.SameLine() - ImGui.SmallButton(">>") - if ImGui.IsItemActive() then - scroll_x_delta = ImGui.GetIO().DeltaTime * 1000.0 - end - ImGui.SameLine() - ImGui.Text("%.0f/%.0f", scroll_x, scroll_max_x) - if scroll_x_delta ~= 0.0 then - -- Demonstrate a trick: you can use Begin to set yourself in the context of another window - -- (here we are already out of your child window) - BeginChild("scrolling") - ImGui.SetScrollX(ImGui.GetScrollX() + scroll_x_delta) - ImGui.EndChild() - end - ImGui.Spacing() + ImGui.Button("Button 1", ImVec2(80, 80)) + ImGui.SetCursorScreenPos(button2_pos) + ImGui.Button("Button 2", ImVec2(80, 80)) - _, SL.show_horizontal_contents_size_demo_window = ImGui.Checkbox("Show Horizontal contents size demo window", SL.show_horizontal_contents_size_demo_window) - - if SL.show_horizontal_contents_size_demo_window then - DemoWindowLayout_HorizontalContentsSizeWindow() - end -end - -local function DemoWindowLayout_TextClipping() - IMGUI_DEMO_MARKER("Layout/Text Clipping") - if SL.clip_size == nil then SL.clip_size = { 100.0, 100.0 }; SL.clip_offset = ImVec2(30.0, 30.0) end - ImGui.DragFloat2("size", SL.clip_size, 0.5, 1.0, 200.0, "%.0f") - ImGui.TextWrapped("(Click and drag to scroll)") - - DemoHelpMarker( - "(Left) Using ImGui::PushClipRect():\n" .. - "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" .. - "(use this if you want your clipping rectangle to affect interactions)\n\n" .. - "(Center) Using ImDrawList::PushClipRect():\n" .. - "Will alter ImDrawList rendering only.\n" .. - "(use this as a shortcut if you are only using ImDrawList calls)\n\n" .. - "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n" .. - "Will alter only this specific ImDrawList::AddText() rendering.\n" .. - "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.") - - local size = ImVec2(SL.clip_size[1], SL.clip_size[2]) - local offset = SL.clip_offset - for n = 0, 2 do repeat - if n > 0 then - ImGui.SameLine() + -- This is typically used with width-spanning items. + -- (note that Selectable() has a dedicated flag ImGuiSelectableFlags.AllowOverlap, which is a shortcut + -- for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.) + if s.enable_allow_overlap then + ImGui.SetNextItemAllowOverlap() end + ImGui.Selectable("Some Selectable", false) + ImGui.SameLine() + ImGui.SmallButton("++") - ImGui.PushID(n) - ImGui.InvisibleButton("##canvas", size) - if ImGui.IsItemActive() and ImGui.IsMouseDragging(0 --[[ImGuiMouseButton.Left]]) then - offset.x = offset.x + ImGui.GetIO().MouseDelta.x - offset.y = offset.y + ImGui.GetIO().MouseDelta.y - end - ImGui.PopID() - if not ImGui.IsItemVisible() then -- Skip rendering as ImDrawList elements are not clipped. - break - end - - local p0 = ImGui.GetItemRectMin() - local p1 = ImGui.GetItemRectMax() - local text_str = "Line 1 hello\nLine 2 clip me!" - local text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y) - local draw_list = ImGui.GetWindowDrawList() - if n == 0 then - ImGui.PushClipRect(p0, p1, true) - draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) - draw_list:AddText(text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str) - ImGui.PopClipRect() - elseif n == 1 then - draw_list:PushClipRect(p0, p1, true) - draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) - draw_list:AddText(text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str) - draw_list:PopClipRect() - else - local clip_rect = ImVec4(p0.x, p0.y, p1.x, p1.y) -- AddText() takes a ImVec4 here so let's convert. - draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) - draw_list:AddText(ImGui.GetFont(), ImGui.GetFontSize(), text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str, 1, #text_str + 1, 0.0, clip_rect) - end - until true end -end - -local function DemoWindowLayout_OverlapMode() - IMGUI_DEMO_MARKER("Layout/Overlap Mode") - DemoHelpMarker( - "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n" .. - "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. " .. - "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.") - _, SL.enable_allow_overlap = ImGui.Checkbox("Enable AllowOverlap", SL.enable_allow_overlap) - - local button1_pos = ImGui.GetCursorScreenPos() - local button2_pos = ImVec2(button1_pos.x + 50.0, button1_pos.y + 50.0) - if SL.enable_allow_overlap then - ImGui.SetNextItemAllowOverlap() + ImGui.TreePop() end - ImGui.Button("Button 1", ImVec2(80, 80)) - ImGui.SetCursorScreenPos(button2_pos) - ImGui.Button("Button 2", ImVec2(80, 80)) - - -- This is typically used with width-spanning items. - -- (note that Selectable() has a dedicated flag ImGuiSelectableFlags.AllowOverlap, which is a shortcut - -- for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.) - if SL.enable_allow_overlap then - ImGui.SetNextItemAllowOverlap() - end - ImGui.Selectable("Some Selectable", false) - ImGui.SameLine() - ImGui.SmallButton("++") -end - -function DemoWindowLayout() - if not ImGui.CollapsingHeader("Layout & Scrolling") then - return - end - if ImGui.TreeNode("Child windows") then DemoWindowLayout_ChildWindows(); ImGui.TreePop() end - if ImGui.TreeNode("Widgets Width") then DemoWindowLayout_WidgetsWidth(); ImGui.TreePop() end - if ImGui.TreeNode("Basic Horizontal Layout") then DemoWindowLayout_BasicHorizontal(); ImGui.TreePop() end - if ImGui.TreeNode("Groups") then DemoWindowLayout_Groups(); ImGui.TreePop() end - if ImGui.TreeNode("Text Baseline Alignment") then DemoWindowLayout_TextBaseline(); ImGui.TreePop() end - if ImGui.TreeNode("Scrolling") then DemoWindowLayout_Scrolling(); ImGui.TreePop() end - if ImGui.TreeNode("Text Clipping") then DemoWindowLayout_TextClipping(); ImGui.TreePop() end - if ImGui.TreeNode("Overlap Mode") then DemoWindowLayout_OverlapMode(); ImGui.TreePop() end end ------------------------------------------------------------------------------- -- [SECTION] DemoWindowPopups() ------------------------------------------------------------------------------- -local SP = { - selected_fish = -1, toggles = { true, false, false, false, false }, - ctx_selected = -1, value = 0.5, name = nil, - dont_ask_me_next_time = false, item = 1, color = { 0.4, 0.7, 0.0, 0.5 }, +S.DemoWindowPopups = { + selected_fish = -1, -- static int selected_fish = -1; + toggles = { true, false, false, false, false }, -- static bool toggles[] = { true, false, false, false, false }; + selected = -1, -- static int selected = -1; + value = 0.5, -- static float value = 0.5f; + name = ImGui.NewTextBuffer("Label1", 32), -- static char name[32] = "Label1"; + dont_ask_me_next_time = false, -- static bool dont_ask_me_next_time = false; + item = 1, -- static int item = 1; + color = { 0.4, 0.7, 0.0, 0.5 }, -- static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; } - -local function DemoWindowPopups_Popups() - IMGUI_DEMO_MARKER("Popups/Popups") - ImGui.TextWrapped( - "When a popup is active, it inhibits interacting with windows that are behind the popup. " .. - "Clicking outside the popup closes it.") - - local names = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" } - local toggles = SP.toggles - - -- Simple selection popup (if you want to show the current selection inside the Button itself, - -- you may want to build a string using the "###" operator to preserve a constant ID with a variable label) - if ImGui.Button("Select..") then - ImGui.OpenPopup("my_select_popup") - end - ImGui.SameLine() - ImGui.TextUnformatted(SP.selected_fish == -1 and "" or names[SP.selected_fish + 1]) - if ImGui.BeginPopup("my_select_popup") then - ImGui.SeparatorText("Aquarium") - for i = 1, #names do - if ImGui.Selectable(names[i]) then - SP.selected_fish = i - 1 - end - end - ImGui.EndPopup() - end - - -- Showing a menu with toggles - if ImGui.Button("Toggle..") then - ImGui.OpenPopup("my_toggle_popup") - end - if ImGui.BeginPopup("my_toggle_popup") then - for i = 1, #names do - _, toggles[i] = ImGui.MenuItem(names[i], "", toggles[i]) - end - if ImGui.BeginMenu("Sub-menu") then - ImGui.MenuItem("Click me") - ImGui.EndMenu() - end - - ImGui.Separator() - ImGui.Text("Tooltip here") - ImGui.SetItemTooltip("I am a tooltip over a popup") - - if ImGui.Button("Stacked Popup") then - ImGui.OpenPopup("another popup") - end - if ImGui.BeginPopup("another popup") then - for i = 1, #names do - _, toggles[i] = ImGui.MenuItem(names[i], "", toggles[i]) - end - if ImGui.BeginMenu("Sub-menu") then - ImGui.MenuItem("Click me") - if ImGui.Button("Stacked Popup") then - ImGui.OpenPopup("another popup") - end - if ImGui.BeginPopup("another popup") then - ImGui.Text("I am the last one here.") - ImGui.EndPopup() - end - ImGui.EndMenu() - end - ImGui.EndPopup() - end - ImGui.EndPopup() - end - - -- Call the more complete ShowExampleMenuFile which we use in various places of this demo - if ImGui.Button("With a menu..") then - ImGui.OpenPopup("my_file_popup") - end - if ImGui.BeginPopup("my_file_popup", 1024 --[[ImGuiWindowFlags.MenuBar]]) then - if ImGui.BeginMenuBar() then - if ImGui.BeginMenu("File") then - DemoMenuFile() - ImGui.EndMenu() - end - if ImGui.BeginMenu("Edit") then - ImGui.MenuItem("Dummy") - ImGui.EndMenu() - end - ImGui.EndMenuBar() - end - ImGui.Text("Hello from popup!") - ImGui.Button("This is a dummy button..") - ImGui.EndPopup() - end -end - -local function DemoWindowPopups_ContextMenus() - IMGUI_DEMO_MARKER("Popups/Context menus") - DemoHelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.") - - -- BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: - -- if id == 0 then - -- id = GetItemID() -- Use last item id - -- end - -- if IsItemHovered() and IsMouseReleased(ImGuiMouseButton.Right) then - -- OpenPopup(id) - -- end - -- return BeginPopup(id) - -- For advanced uses you may want to replicate and customize this code. - -- See more details in BeginPopupContextItem(). - - -- Example 1 - -- When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(), - -- and BeginPopupContextItem() will use the last item ID as the popup ID. - do - local names = { "Label1", "Label2", "Label3", "Label4", "Label5" } - for n = 0, 4 do - if ImGui.Selectable(names[n + 1], SP.ctx_selected == n) then - SP.ctx_selected = n - end - if ImGui.BeginPopupContextItem() then -- <-- use last item id as popup id - SP.ctx_selected = n - ImGui.Text("This is a popup for \"%s\"!", names[n + 1]) - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - ImGui.SetItemTooltip("Right-click to open popup") - end - end - - -- Example 2 - -- Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem(). - -- Using an explicit identifier is also convenient if you want to activate the popups from different locations. - do - DemoHelpMarker("Text() elements don't have stable identifiers so we need to provide one.") - ImGui.Text("Value = %.3f <-- (1) right-click this text", SP.value) - if ImGui.BeginPopupContextItem("my popup") then - if ImGui.Selectable("Set to zero") then SP.value = 0.0 end - if ImGui.Selectable("Set to PI") then SP.value = 3.1415 end - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - SP.value = ImGui.DragFloat("##Value", SP.value, 0.1, 0.0, 0.0) - ImGui.EndPopup() - end - - -- We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup. - -- Here we make it that right-clicking this other text element opens the same popup as above. - -- The popup itself will be submitted by the code above. - ImGui.Text("(2) Or right-click this text") - ImGui.OpenPopupOnItemClick("my popup", 8 --[[ImGuiPopupFlags.MouseButtonRight]]) - - -- Back to square one: manually open the same popup. - if ImGui.Button("(3) Or click this button") then - ImGui.OpenPopup("my popup") - end - end - - -- Example 3 - -- When using BeginPopupContextItem() with an implicit identifier (nil == use last item ID), - -- we need to make sure your item identifier is stable. - -- In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ). - do - DemoHelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.") - if SP.name == nil then SP.name = Buf("Label1", 32) end - local buf = string.format("Button: %s###Button", BufStr(SP.name)) -- ### operator override ID ignoring the preceding label - ImGui.Button(buf) - if ImGui.BeginPopupContextItem() then - ImGui.Text("Edit name:") - ImGui.InputText("##edit", SP.name, 32) - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - ImGui.SameLine(); ImGui.Text("(<-- right-click here)") - end -end - -local function DemoWindowPopups_Modals() - IMGUI_DEMO_MARKER("Popups/Modals") - ImGui.TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.") - - if ImGui.Button("Delete..") then - ImGui.OpenPopup("Delete?") - end - - -- Always center this window when appearing - local center = ImGui.GetMainViewport():GetCenter() - ImGui.SetNextWindowPos(center, 8 --[[ImGuiCond.Appearing]], ImVec2(0.5, 0.5)) - - if ImGui.BeginPopupModal("Delete?", nil, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) then - ImGui.Text("All those beautiful files will be deleted.\nThis operation cannot be undone!") - ImGui.Separator() - - -- local unused_i = 0 - -- unused_i = ImGui.Combo("Combo", unused_i, "Delete\0Delete harder\0") - - ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(0, 0)) - _, SP.dont_ask_me_next_time = ImGui.Checkbox("Don't ask me next time", SP.dont_ask_me_next_time) - ImGui.PopStyleVar() - - if ImGui.Button("OK", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end - ImGui.SetItemDefaultFocus() - ImGui.SameLine() - if ImGui.Button("Cancel", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end - ImGui.EndPopup() - end - - if ImGui.Button("Stacked modals..") then - ImGui.OpenPopup("Stacked 1") - end - if ImGui.BeginPopupModal("Stacked 1", nil, 1024 --[[ImGuiWindowFlags.MenuBar]]) then - if ImGui.BeginMenuBar() then - if ImGui.BeginMenu("File") then - if ImGui.MenuItem("Some menu item") then end - ImGui.EndMenu() - end - ImGui.EndMenuBar() - end - ImGui.Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.") - - -- Testing behavior of widgets stacking their own regular popups over the modal. - if ImGui.Combo then - SP.item = ImGui.Combo("Combo", SP.item, { "aaaa", "bbbb", "cccc", "dddd", "eeee" }, 5) - else - NotPorted("Combo") - end - ImGui.ColorEdit4("Color", SP.color) - - if ImGui.Button("Add another modal..") then - ImGui.OpenPopup("Stacked 2") - end - - -- Also demonstrate passing a p_open bool to BeginPopupModal(), this will create a regular close button which - -- will close the popup. Note that the visibility state of popups is owned by imgui, so the input value - -- of the bool actually doesn't matter here. - local unused_open = true - if ImGui.BeginPopupModal("Stacked 2", unused_open) then - ImGui.Text("Hello from Stacked The Second!") - ImGui.ColorEdit4("Color", SP.color) -- Allow opening another nested popup - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end -end - function DemoWindowPopups() + local s = S.DemoWindowPopups if not ImGui.CollapsingHeader("Popups & Modal windows") then return end @@ -23659,17 +26046,259 @@ function DemoWindowPopups() -- popups at any time. -- Typical use for regular windows: - -- local my_tool_is_active = false; if ImGui.Button("Open") then my_tool_is_active = true end; [...] if my_tool_is_active then my_tool_is_active, visible = ImGui.Begin("My Tool", my_tool_is_active); [...] ImGui.End() end + -- bool my_tool_is_active = false; if (ImGui.Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", my_tool_is_active) { [...] } End(); -- Typical use for popups: - -- if ImGui.Button("Open") then ImGui.OpenPopup("MyPopup") end; if ImGui.BeginPopup("MyPopup") then [...] ImGui.EndPopup() end + -- if (ImGui.Button("Open")) ImGui.OpenPopup("MyPopup"); if (ImGui.BeginPopup("MyPopup")) { [...] EndPopup(); } -- With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. -- This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. - if ImGui.TreeNode("Popups") then DemoWindowPopups_Popups(); ImGui.TreePop() end - if ImGui.TreeNode("Context menus") then DemoWindowPopups_ContextMenus(); ImGui.TreePop() end + if ImGui.TreeNode("Popups") then + IMGUI_DEMO_MARKER("Popups/Popups") + ImGui.TextWrapped( + "When a popup is active, it inhibits interacting with windows that are behind the popup. " .. + "Clicking outside the popup closes it.") + + local names = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" } + local toggles = s.toggles + + -- Simple selection popup (if you want to show the current selection inside the Button itself, + -- you may want to build a string using the "###" operator to preserve a constant ID with a variable label) + if ImGui.Button("Select..") then + ImGui.OpenPopup("my_select_popup") + end + ImGui.SameLine() + local fish_name = "" + if s.selected_fish ~= -1 then fish_name = names[s.selected_fish + 1] end + ImGui.TextUnformatted(fish_name) + if ImGui.BeginPopup("my_select_popup") then + ImGui.SeparatorText("Aquarium") + for i = 0, #names - 1 do + if ImGui.Selectable(names[i + 1]) then + s.selected_fish = i + end + end + ImGui.EndPopup() + end + + -- Showing a menu with toggles + if ImGui.Button("Toggle..") then + ImGui.OpenPopup("my_toggle_popup") + end + if ImGui.BeginPopup("my_toggle_popup") then + for i = 0, #names - 1 do + _, toggles[i + 1] = ImGui.MenuItem(names[i + 1], "", toggles[i + 1]) + end + if ImGui.BeginMenu("Sub-menu") then + ImGui.MenuItem("Click me") + ImGui.EndMenu() + end + + ImGui.Separator() + ImGui.Text("Tooltip here") + ImGui.SetItemTooltip("I am a tooltip over a popup") + + if ImGui.Button("Stacked Popup") then + ImGui.OpenPopup("another popup") + end + if ImGui.BeginPopup("another popup") then + for i = 0, #names - 1 do + _, toggles[i + 1] = ImGui.MenuItem(names[i + 1], "", toggles[i + 1]) + end + if ImGui.BeginMenu("Sub-menu") then + ImGui.MenuItem("Click me") + if ImGui.Button("Stacked Popup") then + ImGui.OpenPopup("another popup") + end + if ImGui.BeginPopup("another popup") then + ImGui.Text("I am the last one here.") + ImGui.EndPopup() + end + ImGui.EndMenu() + end + ImGui.EndPopup() + end + ImGui.EndPopup() + end + + -- Call the more complete ShowExampleMenuFile which we use in various places of this demo + if ImGui.Button("With a menu..") then + ImGui.OpenPopup("my_file_popup") + end + if ImGui.BeginPopup("my_file_popup", 1024 --[[ImGuiWindowFlags.MenuBar]]) then + if ImGui.BeginMenuBar() then + if ImGui.BeginMenu("File") then + ShowExampleMenuFile() + ImGui.EndMenu() + end + if ImGui.BeginMenu("Edit") then + ImGui.MenuItem("Dummy") + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end + ImGui.Text("Hello from popup!") + ImGui.Button("This is a dummy button..") + ImGui.EndPopup() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Context menus") then + IMGUI_DEMO_MARKER("Popups/Context menus") + HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.") + + -- BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: + -- if (id == 0) + -- id = GetItemID(); -- Use last item id + -- if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton.Right)) + -- OpenPopup(id); + -- return BeginPopup(id); + -- For advanced uses you may want to replicate and customize this code. + -- See more details in BeginPopupContextItem(). + + -- Example 1 + -- When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(), + -- and BeginPopupContextItem() will use the last item ID as the popup ID. + do + local names = { "Label1", "Label2", "Label3", "Label4", "Label5" } + for n = 0, 4 do + if ImGui.Selectable(names[n + 1], s.selected == n) then + s.selected = n + end + if ImGui.BeginPopupContextItem() then -- <-- use last item id as popup id + s.selected = n + ImGui.Text("This is a popup for \"%s\"!", names[n + 1]) + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.SetItemTooltip("Right-click to open popup") + end + end + + -- Example 2 + -- Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem(). + -- Using an explicit identifier is also convenient if you want to activate the popups from different locations. + do + HelpMarker("Text() elements don't have stable identifiers so we need to provide one.") + ImGui.Text("Value = %.3f <-- (1) right-click this text", s.value) + if ImGui.BeginPopupContextItem("my popup") then + if ImGui.Selectable("Set to zero") then s.value = 0.0 end + if ImGui.Selectable("Set to PI") then s.value = 3.1415 end + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + s.value = ImGui.DragFloat("##Value", s.value, 0.1, 0.0, 0.0) + ImGui.EndPopup() + end + + -- We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup. + -- Here we make it that right-clicking this other text element opens the same popup as above. + -- The popup itself will be submitted by the code above. + ImGui.Text("(2) Or right-click this text") + ImGui.OpenPopupOnItemClick("my popup", 8 --[[ImGuiPopupFlags.MouseButtonRight]]) + + -- Back to square one: manually open the same popup. + if ImGui.Button("(3) Or click this button") then + ImGui.OpenPopup("my popup") + end + end + + -- Example 3 + -- When using BeginPopupContextItem() with an implicit identifier (nil == use last item ID), + -- we need to make sure your item identifier is stable. + -- In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ). + do + HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.") + local buf = string.format("Button: %s###Button", ImGui.TextBufferToString(s.name)) -- ### operator override ID ignoring the preceding label + ImGui.Button(buf) + if ImGui.BeginPopupContextItem() then + ImGui.Text("Edit name:") + ImGui.InputText("##edit", s.name, 32) + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.SameLine(); ImGui.Text("(<-- right-click here)") + end + + ImGui.TreePop() + end + if ImGui.TreeNode("Modals") then - if ImGui.BeginPopupModal then DemoWindowPopups_Modals() else NotPorted("BeginPopupModal") end + IMGUI_DEMO_MARKER("Popups/Modals") + ImGui.TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.") + + if ImGui.Button("Delete..") then + ImGui.OpenPopup("Delete?") + end + + -- Always center this window when appearing + local center = ImGui.GetMainViewport():GetCenter() + ImGui.SetNextWindowPos(center, 8 --[[ImGuiCond.Appearing]], ImVec2(0.5, 0.5)) + + if ImGui.BeginPopupModal("Delete?", nil, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) then + ImGui.Text("All those beautiful files will be deleted.\nThis operation cannot be undone!") + ImGui.Separator() + + --static int unused_i = 0; + --ImGui.Combo("Combo", unused_i, "Delete\0Delete harder\0"); + + ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(0, 0)) + _, s.dont_ask_me_next_time = ImGui.Checkbox("Don't ask me next time", s.dont_ask_me_next_time) + ImGui.PopStyleVar() + + if ImGui.Button("OK", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end + ImGui.SetItemDefaultFocus() + ImGui.SameLine() + if ImGui.Button("Cancel", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end + ImGui.EndPopup() + end + + if ImGui.Button("Stacked modals..") then + ImGui.OpenPopup("Stacked 1") + end + if ImGui.BeginPopupModal("Stacked 1", nil, 1024 --[[ImGuiWindowFlags.MenuBar]]) then + if ImGui.BeginMenuBar() then + if ImGui.BeginMenu("File") then + if ImGui.MenuItem("Some menu item") then end + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end + ImGui.Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.") + + -- Testing behavior of widgets stacking their own regular popups over the modal. + s.item = ImGui.Combo("Combo", s.item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0") + ImGui.ColorEdit4("Color", s.color) + + if ImGui.Button("Add another modal..") then + ImGui.OpenPopup("Stacked 2") + end + + -- Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which + -- will close the popup. Note that the visibility state of popups is owned by imgui, so the input value + -- of the bool actually doesn't matter here. + local unused_open = true + local visible + visible, unused_open = ImGui.BeginPopupModal("Stacked 2", unused_open) + if visible then + ImGui.Text("Hello from Stacked The Second!") + ImGui.ColorEdit4("Color", s.color) -- Allow opening another nested popup + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.TreePop() end @@ -23680,7 +26309,7 @@ function DemoWindowPopups() ImGui.MenuItem("Menu item", "Ctrl+M") if ImGui.BeginMenu("Menu inside a regular window") then - DemoMenuFile() + ShowExampleMenuFile() ImGui.EndMenu() end ImGui.Separator() @@ -23688,99 +26317,123 @@ function DemoWindowPopups() end end -------------------------------------------------------------------------------- --- [SECTION] DemoWindowTables() -------------------------------------------------------------------------------- - -- Dummy data structure that we use for the Table demo. +-- (pre-C++11 doesn't allow us to instantiate ImVector template if this structure is defined inside the demo function) +-- [Port] namespace { ... } -> globals with a MyItem prefix (part 08_tables uses them). -- We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code. -- This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID. -- But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex) -- If you don't use sorting, you will generally never care about giving column an ID! --- MyItemColumnID -local MyItemColumnID_ID, MyItemColumnID_Name, MyItemColumnID_Action, MyItemColumnID_Quantity, MyItemColumnID_Description = 0, 1, 2, 3, 4 +-- enum MyItemColumnID +MyItemColumnID_ID = 0 +MyItemColumnID_Name = 1 +MyItemColumnID_Action = 2 +MyItemColumnID_Quantity = 3 +MyItemColumnID_Description = 4 -local function MyItem(id, name, quantity) return { ID = id, Name = name, Quantity = quantity } end +-- struct MyItem: [Port] constructor; fields ID (int), Name (string), Quantity (int) +function MyItem(ID, Name, Quantity) + return { ID = ID, Name = Name, Quantity = Quantity } +end ---- Sort a Lua array (1-based) of MyItem with ImGuiTableSortSpecs (Specs is 1-based array or ImVector) -local function MyItem_SortWithSortSpecs(sort_specs, items, items_count) - if items_count <= 1 then return end - local specs = sort_specs.Specs - local function get_spec(n) -- n: 0-based - if specs.Data then return specs.Data[n + 1] end - return specs[n + 1] - end - local function cmp(a, b) -- returns <0, 0, >0 - for n = 0, sort_specs.SpecsCount - 1 do - -- Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn() - -- We could also choose to identify columns based on their index (sort_spec.ColumnIndex), which is simpler! - local sort_spec = get_spec(n) - local delta = 0 - local uid = sort_spec.ColumnUserID - if uid == MyItemColumnID_ID then delta = a.ID - b.ID - elseif uid == MyItemColumnID_Name then delta = (a.Name < b.Name) and -1 or (a.Name > b.Name) and 1 or 0 - elseif uid == MyItemColumnID_Quantity then delta = a.Quantity - b.Quantity - elseif uid == MyItemColumnID_Description then delta = (a.Name < b.Name) and -1 or (a.Name > b.Name) and 1 or 0 - else assert(false) end - if delta > 0 then - return (sort_spec.SortDirection == 1 --[[ImGuiSortDirection.Ascending]]) and 1 or -1 - end - if delta < 0 then - return (sort_spec.SortDirection == 1 --[[ImGuiSortDirection.Ascending]]) and -1 or 1 - end +-- We have a problem which is affecting _only this demo_ and should not affect your code: +-- As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(), +-- however qsort doesn't allow passing user data to comparing function. +-- As a workaround, we are storing the sort specs in a static/global for the comparing function to access. +-- In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global. +-- We could technically call ImGui.TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called +-- very often by the sorting algorithm it would be a little wasteful. +MyItem_s_current_sort_specs = nil + +-- [Port] items: 1-based Lua array of MyItem (e.g. ImVector .Data), sorted in place over [1, items_count]. +local function MyItem_Less(a, b) return MyItem_CompareWithSortSpecs(a, b) < 0 end -- [Port] table.sort wants a "less than" predicate +function MyItem_SortWithSortSpecs(sort_specs, items, items_count) + MyItem_s_current_sort_specs = sort_specs -- Store in variable accessible by the sort function. + if items_count > 1 then + if items_count == #items then + table.sort(items, MyItem_Less) + else -- [Port] sort only the used range + local tmp = {} + for i = 1, items_count do tmp[i] = items[i] end + table.sort(tmp, MyItem_Less) + for i = 1, items_count do items[i] = tmp[i] end end + end + MyItem_s_current_sort_specs = nil +end - -- table.sort() is instable so always return a way to differentiate items. - -- Your own compare function may want to avoid fallback on implicit sort specs. - -- e.g. a Name compare if it wasn't already part of the sort specs. - return a.ID - b.ID - end - local arr = items.Data or items - if items.Data then - -- ImVector: sort only the used range - local tmp = {} - for i = 1, items_count do tmp[i] = arr[i] end - table.sort(tmp, function(a, b) return cmp(a, b) < 0 end) - for i = 1, items_count do arr[i] = tmp[i] end - else - table.sort(arr, function(a, b) return cmp(a, b) < 0 end) +-- Compare function to be used by qsort() +-- [Port] strcmp -> Lua string comparison; returns <0, 0, >0 like upstream (strict weak order via the ID fallback). +function MyItem_CompareWithSortSpecs(a, b) + for n = 0, MyItem_s_current_sort_specs.SpecsCount - 1 do + -- Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn() + -- We could also choose to identify columns based on their index (sort_spec.ColumnIndex), which is simpler! + local sort_spec = MyItem_s_current_sort_specs.Specs[n + 1] -- [Port] Specs is a 1-based array + local delta = 0 + local id = sort_spec.ColumnUserID + if id == MyItemColumnID_ID then delta = (a.ID - b.ID) + elseif id == MyItemColumnID_Name then delta = (a.Name < b.Name and -1 or (a.Name > b.Name and 1 or 0)) + elseif id == MyItemColumnID_Quantity then delta = (a.Quantity - b.Quantity) + elseif id == MyItemColumnID_Description then delta = (a.Name < b.Name and -1 or (a.Name > b.Name and 1 or 0)) + else assert(false) end + if delta > 0 then + return (sort_spec.SortDirection == 1 --[[ImGuiSortDirection.Ascending]]) and 1 or -1 + end + if delta < 0 then + return (sort_spec.SortDirection == 1 --[[ImGuiSortDirection.Ascending]]) and -1 or 1 + end end + + -- qsort() is instable so always return a way to differentiate items. + -- Your own compare function may want to avoid fallback on implicit sort specs. + -- e.g. a Name compare if it wasn't already part of the sort specs. + return a.ID - b.ID end -- Make the UI compact because there are so many fields -local function PushStyleCompact() +function PushStyleCompact() local style = ImGui.GetStyle() ImGui.PushStyleVarY(11 --[[ImGuiStyleVar.FramePadding]], math.floor(style.FramePadding.y * 0.60)) ImGui.PushStyleVarY(14 --[[ImGuiStyleVar.ItemSpacing]], math.floor(style.ItemSpacing.y * 0.60)) end -local function PopStyleCompact() +function PopStyleCompact() ImGui.PopStyleVar(2) end -local table_sizing_policies = nil +S.EditTableSizingFlags = { policies = nil } -- Show a combo box with a choice of sizing policies -local function EditTableSizingFlags(flags) - if table_sizing_policies == nil then - table_sizing_policies = { - { Value = 0 --[[ImGuiTableFlags.None]], Name = "Default", Tooltip = "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." }, - { Value = 8192 --[[ImGuiTableFlags.SizingFixedFit]], Name = "ImGuiTableFlags_SizingFixedFit", Tooltip = "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." }, - { Value = 16384 --[[ImGuiTableFlags.SizingFixedSame]], Name = "ImGuiTableFlags_SizingFixedSame", Tooltip = "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." }, - { Value = 24576 --[[ImGuiTableFlags.SizingStretchProp]], Name = "ImGuiTableFlags_SizingStretchProp", Tooltip = "Columns default to _WidthStretch with weights proportional to their widths." }, - { Value = 32768 --[[ImGuiTableFlags.SizingStretchSame]], Name = "ImGuiTableFlags_SizingStretchSame", Tooltip = "Columns default to _WidthStretch with same weights." }, +-- [Port] p_flags -> takes flags, returns the new flags. +function EditTableSizingFlags(p_flags) + local s = S.EditTableSizingFlags + -- struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; }; + if s.policies == nil then + s.policies = + { + { Value = 0 --[[ImGuiTableFlags.None]], Name = "Default", Tooltip = "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." }, + { Value = 8192 --[[ImGuiTableFlags.SizingFixedFit]], Name = "ImGuiTableFlags_SizingFixedFit", Tooltip = "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." }, + { Value = 16384 --[[ImGuiTableFlags.SizingFixedSame]], Name = "ImGuiTableFlags_SizingFixedSame", Tooltip = "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." }, + { Value = 24576 --[[ImGuiTableFlags.SizingStretchProp]], Name = "ImGuiTableFlags_SizingStretchProp", Tooltip = "Columns default to _WidthStretch with weights proportional to their widths." }, + { Value = 32768 --[[ImGuiTableFlags.SizingStretchSame]], Name = "ImGuiTableFlags_SizingStretchSame", Tooltip = "Columns default to _WidthStretch with same weights." }, } end - local policies = table_sizing_policies - local idx = 1 - while idx <= #policies do - if policies[idx].Value == bit32.band(flags, 57344 --[[ImGuiTableFlags.SizingMask_]]) then break end + local policies = s.policies + local idx = 0 + while idx < #policies do + if policies[idx + 1].Value == bit32.band(p_flags, 57344 --[[ImGuiTableFlags.SizingMask_]]) then + break + end idx = idx + 1 end - local preview_text = (idx <= #policies) and (idx > 1 and string.sub(policies[idx].Name, #"ImGuiTableFlags" + 1) or policies[idx].Name) or "" + local preview_text = "" + if idx < #policies then + preview_text = policies[idx + 1].Name + if idx > 0 then preview_text = string.sub(preview_text, #"ImGuiTableFlags" + 1) end + end if ImGui.BeginCombo("Sizing Policy", preview_text) then - for n = 1, #policies do - if ImGui.Selectable(policies[n].Name, idx == n) then - flags = bit32.bor(bit32.band(flags, bit32.bnot(57344 --[[ImGuiTableFlags.SizingMask_]])), policies[n].Value) + for n = 0, #policies - 1 do + if ImGui.Selectable(policies[n + 1].Name, idx == n) then + p_flags = bit32.bor(bit32.band(p_flags, bit32.bnot(57344 --[[ImGuiTableFlags.SizingMask_]])), policies[n + 1].Value) end end ImGui.EndCombo() @@ -23789,1256 +26442,1507 @@ local function EditTableSizingFlags(flags) ImGui.TextDisabled("(?)") if ImGui.BeginItemTooltip() then ImGui.PushTextWrapPos(ImGui.GetFontSize() * 50.0) - for m = 1, #policies do + for m = 0, #policies - 1 do ImGui.Separator() - ImGui.Text("%s:", policies[m].Name) + ImGui.Text("%s:", policies[m + 1].Name) ImGui.Separator() ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().IndentSpacing * 0.5) - ImGui.TextUnformatted(policies[m].Tooltip) + ImGui.TextUnformatted(policies[m + 1].Tooltip) end ImGui.PopTextWrapPos() ImGui.EndTooltip() end - return flags + return p_flags end -local function EditTableColumnsFlags(f) - local p - local F = ImGuiTableColumnFlags - _, f = ImGui.CheckboxFlags("_Disabled", f, F.Disabled); ImGui.SameLine(); DemoHelpMarker("Master disable flag (also hide from context menu)") - _, f = ImGui.CheckboxFlags("_DefaultHide", f, F.DefaultHide) - _, f = ImGui.CheckboxFlags("_DefaultSort", f, F.DefaultSort) - p, f = ImGui.CheckboxFlags("_WidthStretch", f, F.WidthStretch) - if p then f = bit32.band(f, bit32.bnot(bit32.bxor(F.WidthMask_, F.WidthStretch))) end - p, f = ImGui.CheckboxFlags("_WidthFixed", f, F.WidthFixed) - if p then f = bit32.band(f, bit32.bnot(bit32.bxor(F.WidthMask_, F.WidthFixed))) end - _, f = ImGui.CheckboxFlags("_NoResize", f, F.NoResize) - _, f = ImGui.CheckboxFlags("_NoReorder", f, F.NoReorder) - _, f = ImGui.CheckboxFlags("_NoHide", f, F.NoHide) - _, f = ImGui.CheckboxFlags("_NoClip", f, F.NoClip) - _, f = ImGui.CheckboxFlags("_NoSort", f, F.NoSort) - _, f = ImGui.CheckboxFlags("_NoSortAscending", f, F.NoSortAscending) - _, f = ImGui.CheckboxFlags("_NoSortDescending", f, F.NoSortDescending) - _, f = ImGui.CheckboxFlags("_NoHeaderLabel", f, F.NoHeaderLabel) - _, f = ImGui.CheckboxFlags("_NoHeaderWidth", f, F.NoHeaderWidth) - _, f = ImGui.CheckboxFlags("_PreferSortAscending", f, F.PreferSortAscending) - _, f = ImGui.CheckboxFlags("_PreferSortDescending", f, F.PreferSortDescending) - _, f = ImGui.CheckboxFlags("_IndentEnable", f, F.IndentEnable); ImGui.SameLine(); DemoHelpMarker("Default for column 0") - _, f = ImGui.CheckboxFlags("_IndentDisable", f, F.IndentDisable); ImGui.SameLine(); DemoHelpMarker("Default for column >0") - _, f = ImGui.CheckboxFlags("_AngledHeader", f, F.AngledHeader) - return f +-- [Port] p_flags -> takes flags, returns the new flags. +function EditTableColumnsFlags(p_flags) + local pressed + _, p_flags = ImGui.CheckboxFlags("_Disabled", p_flags, 1 --[[ImGuiTableColumnFlags.Disabled]]); ImGui.SameLine(); HelpMarker("Master disable flag (also hide from context menu)") + _, p_flags = ImGui.CheckboxFlags("_DefaultHide", p_flags, 2 --[[ImGuiTableColumnFlags.DefaultHide]]) + _, p_flags = ImGui.CheckboxFlags("_DefaultSort", p_flags, 4 --[[ImGuiTableColumnFlags.DefaultSort]]) + pressed, p_flags = ImGui.CheckboxFlags("_WidthStretch", p_flags, 8 --[[ImGuiTableColumnFlags.WidthStretch]]) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(24 --[[ImGuiTableColumnFlags.WidthMask_]], 8 --[[ImGuiTableColumnFlags.WidthStretch]]))) + end + pressed, p_flags = ImGui.CheckboxFlags("_WidthFixed", p_flags, 16 --[[ImGuiTableColumnFlags.WidthFixed]]) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(24 --[[ImGuiTableColumnFlags.WidthMask_]], 16 --[[ImGuiTableColumnFlags.WidthFixed]]))) + end + _, p_flags = ImGui.CheckboxFlags("_NoResize", p_flags, 32 --[[ImGuiTableColumnFlags.NoResize]]) + _, p_flags = ImGui.CheckboxFlags("_NoReorder", p_flags, 64 --[[ImGuiTableColumnFlags.NoReorder]]) + _, p_flags = ImGui.CheckboxFlags("_NoHide", p_flags, 128 --[[ImGuiTableColumnFlags.NoHide]]) + _, p_flags = ImGui.CheckboxFlags("_NoClip", p_flags, 256 --[[ImGuiTableColumnFlags.NoClip]]) + _, p_flags = ImGui.CheckboxFlags("_NoSort", p_flags, 512 --[[ImGuiTableColumnFlags.NoSort]]) + _, p_flags = ImGui.CheckboxFlags("_NoSortAscending", p_flags, 1024 --[[ImGuiTableColumnFlags.NoSortAscending]]) + _, p_flags = ImGui.CheckboxFlags("_NoSortDescending", p_flags, 2048 --[[ImGuiTableColumnFlags.NoSortDescending]]) + _, p_flags = ImGui.CheckboxFlags("_NoHeaderLabel", p_flags, 4096 --[[ImGuiTableColumnFlags.NoHeaderLabel]]) + _, p_flags = ImGui.CheckboxFlags("_NoHeaderWidth", p_flags, 8192 --[[ImGuiTableColumnFlags.NoHeaderWidth]]) + _, p_flags = ImGui.CheckboxFlags("_PreferSortAscending", p_flags, 16384 --[[ImGuiTableColumnFlags.PreferSortAscending]]) + _, p_flags = ImGui.CheckboxFlags("_PreferSortDescending", p_flags, 32768 --[[ImGuiTableColumnFlags.PreferSortDescending]]) + _, p_flags = ImGui.CheckboxFlags("_IndentEnable", p_flags, 65536 --[[ImGuiTableColumnFlags.IndentEnable]]); ImGui.SameLine(); HelpMarker("Default for column 0") + _, p_flags = ImGui.CheckboxFlags("_IndentDisable", p_flags, 131072 --[[ImGuiTableColumnFlags.IndentDisable]]); ImGui.SameLine(); HelpMarker("Default for column >0") + _, p_flags = ImGui.CheckboxFlags("_AngledHeader", p_flags, 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) + return p_flags end -local function ShowTableColumnsStatusFlags(flags) +function ShowTableColumnsStatusFlags(flags) ImGui.CheckboxFlags("_IsEnabled", flags, 16777216 --[[ImGuiTableColumnFlags.IsEnabled]]) ImGui.CheckboxFlags("_IsVisible", flags, 33554432 --[[ImGuiTableColumnFlags.IsVisible]]) ImGui.CheckboxFlags("_IsSorted", flags, 67108864 --[[ImGuiTableColumnFlags.IsSorted]]) ImGui.CheckboxFlags("_IsHovered", flags, 134217728 --[[ImGuiTableColumnFlags.IsHovered]]) end -local function bor(...) return bit32.bor(...) end -local TF = setmetatable({}, { __index = function(_, k) return ImGuiTableFlags[k] end }) +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowTables() +------------------------------------------------------------------------------- -local ST = {} -- statics for DemoWindowTables (one sub-table per section) --- Using those as a base value to create width/height that are factor of the size of our font -local TEXT_BASE_WIDTH, TEXT_BASE_HEIGHT = 0, 0 +S.DemoWindowTables = { -- statics of DemoWindowTables(), one sub-table per TreeNode + disable_indent = false, + BordersBackground = { + flags = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg), + display_headers = false, + contents_type = 0, -- CT_Text + }, + ResizableStretch = { + flags = bit32.bor(ImGuiTableFlags.SizingStretchSame, ImGuiTableFlags.Resizable, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.ContextMenuInBody), + }, + ResizableFixed = { + flags = bit32.bor(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.Resizable, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.ContextMenuInBody), + }, + ResizableMixed = { + flags = bit32.bor(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.RowBg, ImGuiTableFlags.Borders, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable), + }, + Reorderable = { + flags = bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV), + }, + Padding = { + flags1 = ImGuiTableFlags.BordersV, + show_headers = false, + flags2 = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg), + cell_padding = ImVec2(0.0, 0.0), + show_widget_frame_bg = true, + text_bufs = {}, -- 1-based, cell + 1 + init = true, + }, + SizingPolicies = { + flags1 = bit32.bor(ImGuiTableFlags.BordersV, ImGuiTableFlags.BordersOuterH, ImGuiTableFlags.RowBg, ImGuiTableFlags.ContextMenuInBody), + sizing_policy_flags = { ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.SizingFixedSame, ImGuiTableFlags.SizingStretchProp, ImGuiTableFlags.SizingStretchSame }, + flags = bit32.bor(ImGuiTableFlags.ScrollY, ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg, ImGuiTableFlags.Resizable), + contents_type = 0, -- CT_ShowWidth + column_count = 3, + text_buf = ImGui.NewTextBuffer("", 32), + }, + VerticalScrolling = { + flags = bit32.bor(ImGuiTableFlags.ScrollY, ImGuiTableFlags.RowBg, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable), + }, + HorizontalScrolling = { + flags = bit32.bor(ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, ImGuiTableFlags.RowBg, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable), + freeze_cols = 1, + freeze_rows = 1, + flags2 = bit32.bor(ImGuiTableFlags.SizingStretchSame, ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.RowBg, ImGuiTableFlags.ContextMenuInBody), + inner_width = 1000.0, + }, + ColumnsFlags = { + column_flags = { ImGuiTableColumnFlags.DefaultSort, ImGuiTableColumnFlags.None, ImGuiTableColumnFlags.DefaultHide }, + column_flags_out = { 0, 0, 0 }, -- Output from TableGetColumnFlags() + }, + ColumnsWidths = { + flags1 = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.NoBordersInBodyUntilResize), + flags2 = ImGuiTableFlags.None, + }, + OuterSize = { + flags = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.Resizable, ImGuiTableFlags.ContextMenuInBody, ImGuiTableFlags.RowBg, ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.NoHostExtendX), + }, + BackgroundColor = { + flags = ImGuiTableFlags.RowBg, + row_bg_type = 1, + row_bg_target = 1, + cell_bg_type = 1, + }, + TreeView = { + table_flags = bit32.bor(ImGuiTableFlags.BordersV, ImGuiTableFlags.BordersOuterH, ImGuiTableFlags.Resizable, ImGuiTableFlags.RowBg, ImGuiTableFlags.NoBordersInBody), + tree_node_flags_base = bit32.bor(ImGuiTreeNodeFlags.SpanAllColumns, ImGuiTreeNodeFlags.DefaultOpen, ImGuiTreeNodeFlags.DrawLinesFull), + MyTreeNode = nil, -- [Port] local struct, created once on first use + nodes = { -- 1-based; ChildIdx stays 0-based like upstream + { Name = "Root with Long Name", Type = "Folder", Size = -1, ChildIdx = 1, ChildCount = 3 }, -- 0 + { Name = "Music", Type = "Folder", Size = -1, ChildIdx = 4, ChildCount = 2 }, -- 1 + { Name = "Textures", Type = "Folder", Size = -1, ChildIdx = 6, ChildCount = 3 }, -- 2 + { Name = "desktop.ini", Type = "System file", Size = 1024, ChildIdx = -1, ChildCount = -1 }, -- 3 + { Name = "File1_a.wav", Type = "Audio file", Size = 123000, ChildIdx = -1, ChildCount = -1 }, -- 4 + { Name = "File1_b.wav", Type = "Audio file", Size = 456000, ChildIdx = -1, ChildCount = -1 }, -- 5 + { Name = "Image001.png", Type = "Image file", Size = 203128, ChildIdx = -1, ChildCount = -1 }, -- 6 + { Name = "Copy of Image001.png", Type = "Image file", Size = 203256, ChildIdx = -1, ChildCount = -1 }, -- 7 + { Name = "Copy of Image001 (Final2).png", Type = "Image file", Size = 203512, ChildIdx = -1, ChildCount = -1 }, -- 8 + }, + }, + ItemWidth = { + dummy_f = 0.0, + }, + CustomHeaders = { + column_selected = { false, false, false }, + }, + AngledHeaders = { + table_flags = bit32.bor(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersInnerH, ImGuiTableFlags.Hideable, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.HighlightHoveredColumn), + column_flags = bit32.bor(ImGuiTableColumnFlags.AngledHeader, ImGuiTableColumnFlags.WidthFixed), + bools = {}, -- 1-based, filled with false on first use + frozen_cols = 1, + frozen_rows = 2, + }, + ContextMenus = { + flags1 = bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Borders, ImGuiTableFlags.ContextMenuInBody), + }, + SyncedInstances = { + flags = bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Borders, ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.NoSavedSettings), + }, + template_items_names = { + "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango", + "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot" + }, + Sorting = { + items = ImVector(), + flags = bit32.bor( + ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Sortable, ImGuiTableFlags.SortMulti, + ImGuiTableFlags.RowBg, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.NoBordersInBody, + ImGuiTableFlags.ScrollY), + }, + Advanced = { + flags = bit32.bor( + ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, + ImGuiTableFlags.Sortable, ImGuiTableFlags.SortMulti, + ImGuiTableFlags.RowBg, ImGuiTableFlags.Borders, ImGuiTableFlags.NoBordersInBody, + ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, + ImGuiTableFlags.SizingFixedFit), + columns_base_flags = ImGuiTableColumnFlags.None, + contents_type = 5, -- CT_SelectableSpanRow + freeze_cols = 1, + freeze_rows = 1, + items_count = 0, -- IM_COUNTOF(template_items_names) * 2, set below + outer_size_value = nil, -- ImVec2(0.0f, TEXT_BASE_HEIGHT * 12), set lazily (needs font) + row_min_height = 0.0, -- Auto + inner_width_with_scroll = 0.0, -- Auto-extend + outer_size_enabled = true, + show_headers = true, + show_wrapped_text = false, + items = ImVector(), + selection = ImVector(), + items_need_sort = false, + show_debug_details = false, + }, +} +S.DemoWindowTables.Advanced.items_count = #S.DemoWindowTables.template_items_names * 2 -local function Tables_Basic() - IMGUI_DEMO_MARKER("Tables/Basic") - -- Here we will showcase three different ways to output a table. - -- They are very simple variations of a same thing! - - -- [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. - -- In many situations, this is the most flexible and easy to use pattern. - DemoHelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.") - if ImGui.BeginTable("table1", 3) then - for row = 0, 3 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Row %d Column %d", row, column) - end - end - ImGui.EndTable() +function DemoWindowTables() + local _ + local s = S.DemoWindowTables + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) + if not ImGui.CollapsingHeader("Tables & Columns") then + return end - -- [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). - -- This is generally more convenient when you have code manually submitting the contents of each column. - DemoHelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.") - if ImGui.BeginTable("table2", 3) then - for row = 0, 3 do - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.Text("Row %d", row) - ImGui.TableNextColumn() - ImGui.Text("Some contents") - ImGui.TableNextColumn() - ImGui.Text("123.456") - end - ImGui.EndTable() + -- Using those as a base value to create width/height that are factor of the size of our font + local TEXT_BASE_WIDTH = ImGui.CalcTextSize("A").x + local TEXT_BASE_HEIGHT = ImGui.GetTextLineHeightWithSpacing() + + ImGui.PushID("Tables") + + local open_action = -1 + if ImGui.Button("Expand all") then + open_action = 1 end - - -- [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), - -- as TableNextColumn() will automatically wrap around and create new rows as needed. - -- This is generally more convenient when your cells all contains the same type of data. - DemoHelpMarker( - "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains " .. - "the same type of contents.\n This is also more similar to the old NextColumn() function of the " .. - "Columns API, and provided to facilitate the Columns->Tables API transition.") - if ImGui.BeginTable("table3", 3) then - for item = 0, 13 do - ImGui.TableNextColumn() - ImGui.Text("Item %d", item) - end - ImGui.EndTable() - end -end - -local function Tables_BordersBackground() - IMGUI_DEMO_MARKER("Tables/Borders, background") - -- Expose a few Borders related flags interactively - local CT_Text, CT_FillButton = 0, 1 - local s = ST.borders - if s == nil then s = { flags = bor(TF.Borders, TF.RowBg), display_headers = false, contents_type = CT_Text }; ST.borders = s end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, TF.RowBg) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, TF.Borders) - ImGui.SameLine(); DemoHelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH") - ImGui.Indent() - - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, TF.BordersH) - ImGui.Indent() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, TF.BordersOuterH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, TF.BordersInnerH) - ImGui.Unindent() - - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, TF.BordersV) - ImGui.Indent() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, TF.BordersOuterV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, TF.BordersInnerV) - ImGui.Unindent() - - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags, TF.BordersOuter) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags, TF.BordersInner) - ImGui.Unindent() - - ImGui.AlignTextToFramePadding(); ImGui.Text("Cell contents:") - ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("Text", s.contents_type, CT_Text) - ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("FillButton", s.contents_type, CT_FillButton) - _, s.display_headers = ImGui.Checkbox("Display headers", s.display_headers) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, TF.NoBordersInBody); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") - PopStyleCompact() - - if ImGui.BeginTable("table1", 3, s.flags) then - -- Display headers so we can inspect their interaction with borders - -- (Headers are not the main purpose of this section of the demo, so we are not elaborating on them now. See other sections for details) - if s.display_headers then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - end - - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - local buf = string.format("Hello %d,%d", column, row) - if s.contents_type == CT_Text then - ImGui.TextUnformatted(buf) - elseif s.contents_type == CT_FillButton then - ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) - end - end - end - ImGui.EndTable() - end -end - -local function Tables_HelloGrid(id, flags, rows, cols, fmt) - if ImGui.BeginTable(id, cols, flags) then - for row = 0, rows - 1 do - ImGui.TableNextRow() - for column = 0, cols - 1 do - ImGui.TableSetColumnIndex(column) - ImGui.Text(fmt or "Hello %d,%d", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_ResizableStretch() - IMGUI_DEMO_MARKER("Tables/Resizable, stretch") - -- By default, if we don't enable ScrollX the sizing policy for each column is "Stretch" - -- All columns maintain a sizing weight, and they will occupy all available width. - local s = ST.rstretch - if s == nil then s = { flags = bor(TF.SizingStretchSame, TF.Resizable, TF.BordersOuter, TF.BordersV, TF.ContextMenuInBody) }; ST.rstretch = s end - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, TF.BordersV) - ImGui.SameLine(); DemoHelpMarker( - "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, " .. - "this is why the resize borders are still showing when unchecking this.") - PopStyleCompact() - - Tables_HelloGrid("table1", s.flags, 5, 3) -end - -local function Tables_ResizableFixed() - IMGUI_DEMO_MARKER("Tables/Resizable, fixed") - -- Here we use ImGuiTableFlags.SizingFixedFit (even though _ScrollX is not set) - -- So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) - -- If there is not enough available width to fit all columns, they will however be resized down. - -- FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings - DemoHelpMarker( - "Using _Resizable + _SizingFixedFit flags.\n" .. - "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" .. - "Double-click a column border to auto-fit the column to its contents.") - PushStyleCompact() - local s = ST.rfixed - if s == nil then s = { flags = bor(TF.SizingFixedFit, TF.Resizable, TF.BordersOuter, TF.BordersV, TF.ContextMenuInBody) }; ST.rfixed = s end - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, TF.NoHostExtendX) - PopStyleCompact() - - Tables_HelloGrid("table1", s.flags, 5, 3) -end - -local function Tables_ResizableMixed() - IMGUI_DEMO_MARKER("Tables/Resizable, mixed") - DemoHelpMarker( - "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" .. - "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.") - local flags = bor(TF.SizingFixedFit, TF.RowBg, TF.Borders, TF.Resizable, TF.Reorderable, TF.Hideable) - local CF = ImGuiTableColumnFlags - - if ImGui.BeginTable("table1", 3, flags) then - ImGui.TableSetupColumn("AAA", CF.WidthFixed) - ImGui.TableSetupColumn("BBB", CF.WidthFixed) - ImGui.TableSetupColumn("CCC", CF.WidthStretch) - ImGui.TableHeadersRow() - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s %d,%d", (column == 2) and "Stretch" or "Fixed", column, row) - end - end - ImGui.EndTable() - end - if ImGui.BeginTable("table2", 6, flags) then - ImGui.TableSetupColumn("AAA", CF.WidthFixed) - ImGui.TableSetupColumn("BBB", CF.WidthFixed) - ImGui.TableSetupColumn("CCC", bor(CF.WidthFixed, CF.DefaultHide)) - ImGui.TableSetupColumn("DDD", CF.WidthStretch) - ImGui.TableSetupColumn("EEE", CF.WidthStretch) - ImGui.TableSetupColumn("FFF", bor(CF.WidthStretch, CF.DefaultHide)) - ImGui.TableHeadersRow() - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 5 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s %d,%d", (column >= 3) and "Stretch" or "Fixed", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_Reorderable() - IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers") - DemoHelpMarker( - "Click and drag column headers to reorder columns.\n\n" .. - "Right-click on a header to open a context menu.") - local s = ST.reorder - if s == nil then s = { flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.BordersOuter, TF.BordersV) }; ST.reorder = s end - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, TF.Reorderable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, TF.Hideable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, TF.NoBordersInBody) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, TF.NoBordersInBodyUntilResize); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, TF.HighlightHoveredColumn) - PopStyleCompact() - - if ImGui.BeginTable("table1", 3, s.flags) then - -- Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column. - -- (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.) - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - for row = 0, 5 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Hello %d,%d", column, row) - end - end - ImGui.EndTable() - end - - -- Use outer_size.x == 0.0f instead of default to make the table as tight as possible - -- (only valid when no scrolling and no stretch column) - if ImGui.BeginTable("table2", 3, bor(s.flags, TF.SizingFixedFit), ImVec2(0.0, 0.0)) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - for row = 0, 5 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Fixed %d,%d", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_Padding() - IMGUI_DEMO_MARKER("Tables/Padding") - -- First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding. - -- We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding. - DemoHelpMarker( - "We often want outer padding activated when any using features which makes the edges of a column visible:\n" .. - "e.g.:\n" .. - "- BorderOuterV\n" .. - "- any form of row selection\n" .. - "Because of this, activating BorderOuterV sets the default to PadOuterX. " .. - "Using PadOuterX or NoPadOuterX you can override the default.\n\n" .. - "Actual padding values are using style.CellPadding.\n\n" .. - "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.") - - local s = ST.padding - if s == nil then - s = { flags1 = TF.BordersV, show_headers = false, flags2 = bor(TF.Borders, TF.RowBg), cell_padding = ImVec2(0.0, 0.0), - show_widget_frame_bg = true, text_bufs = {}, init = true } -- text_bufs: Mini text storage for 3x5 cells - ST.padding = s - end - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags1, TF.PadOuterX) - ImGui.SameLine(); DemoHelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)") - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags1, TF.NoPadOuterX) - ImGui.SameLine(); DemoHelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)") - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags1, TF.NoPadInnerX) - ImGui.SameLine(); DemoHelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)") - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags1, TF.BordersOuterV) - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags1, TF.BordersInnerV) - _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) - PopStyleCompact() - - if ImGui.BeginTable("table_padding", 3, s.flags1) then - if s.show_headers then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - end - - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - if row == 0 then - ImGui.Text("Avail %.2f", ImGui.GetContentRegionAvail().x) - else - local buf = string.format("Hello %d,%d", column, row) - ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) - end - -- if bit32.band(ImGui.TableGetColumnFlags(), ImGuiTableColumnFlags.IsHovered) ~= 0 then - -- ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, IM_COL32(0, 100, 0, 255)) - -- end - end - end - ImGui.EndTable() - end - - -- Second example: set style.CellPadding to (0.0) or a custom value. - -- FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one... - DemoHelpMarker("Setting style.CellPadding to (0,0) or a custom value.") - - PushStyleCompact() - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags2, TF.Borders) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags2, TF.BordersH) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags2, TF.BordersV) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags2, TF.BordersInner) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags2, TF.BordersOuter) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags2, TF.RowBg) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags2, TF.Resizable) - _, s.show_widget_frame_bg = ImGui.Checkbox("show_widget_frame_bg", s.show_widget_frame_bg) - ImGui.SliderFloat2("CellPadding", s.cell_padding, 0.0, 10.0, "%.0f") - PopStyleCompact() - - ImGui.PushStyleVar(17 --[[ImGuiStyleVar.CellPadding]], s.cell_padding) - if ImGui.BeginTable("table_padding_2", 3, s.flags2) then - if not s.show_widget_frame_bg then - ImGui.PushStyleColor(7 --[[ImGuiCol.FrameBg]], 0) - end - for cell = 0, 3 * 5 - 1 do - ImGui.TableNextColumn() - if s.init then - s.text_bufs[cell + 1] = Buf("edit me", 16) - end - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - ImGui.PushID(cell) - ImGui.InputText("##cell", s.text_bufs[cell + 1], 16) - ImGui.PopID() - end - if not s.show_widget_frame_bg then - ImGui.PopStyleColor() - end - s.init = false - ImGui.EndTable() - end - ImGui.PopStyleVar() -end - -local function Tables_SizingPolicies() - IMGUI_DEMO_MARKER("Tables/Explicit widths") - local s = ST.sizing - if s == nil then - s = { flags1 = bor(TF.BordersV, TF.BordersOuterH, TF.RowBg, TF.ContextMenuInBody), - sizing_policy_flags = { TF.SizingFixedFit, TF.SizingFixedSame, TF.SizingStretchProp, TF.SizingStretchSame }, - flags = bor(TF.ScrollY, TF.Borders, TF.RowBg, TF.Resizable), contents_type = 0, column_count = 3, text_buf = Buf("", 32) } - ST.sizing = s - end - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, TF.Resizable) - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags1, TF.NoHostExtendX) - PopStyleCompact() - - for table_n = 0, 3 do - ImGui.PushID(table_n) - ImGui.SetNextItemWidth(TEXT_BASE_WIDTH * 30) - s.sizing_policy_flags[table_n + 1] = EditTableSizingFlags(s.sizing_policy_flags[table_n + 1]) - - -- To make it easier to understand the different sizing policy, - -- For each policy: we display one table where the columns have equal contents width, - -- and one where the columns have different contents width. - if ImGui.BeginTable("table1", 3, bor(s.sizing_policy_flags[table_n + 1], s.flags1)) then - for row = 0, 2 do - ImGui.TableNextRow() - ImGui.TableNextColumn(); ImGui.Text("Oh dear") - ImGui.TableNextColumn(); ImGui.Text("Oh dear") - ImGui.TableNextColumn(); ImGui.Text("Oh dear") - end - ImGui.EndTable() - end - if ImGui.BeginTable("table2", 3, bor(s.sizing_policy_flags[table_n + 1], s.flags1)) then - for row = 0, 2 do - ImGui.TableNextRow() - ImGui.TableNextColumn(); ImGui.Text("AAAA") - ImGui.TableNextColumn(); ImGui.Text("BBBBBBBB") - ImGui.TableNextColumn(); ImGui.Text("CCCCCCCCCCCC") - end - ImGui.EndTable() - end - ImGui.PopID() - end - - ImGui.Spacing() - ImGui.TextUnformatted("Advanced") ImGui.SameLine() - DemoHelpMarker( - "This section allows you to interact and see the effect of various sizing policies " .. - "depending on whether Scroll is enabled and the contents of your columns.") - - local CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText = 0, 1, 2, 3, 4, 5 - - PushStyleCompact() - ImGui.PushID("Advanced") - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) - s.flags = EditTableSizingFlags(s.flags) - if ImGui.Combo then - s.contents_type = ImGui.Combo("Contents", s.contents_type, { "Show width", "Short Text", "Long Text", "Button", "Fill Button", "InputText" }, 6) - else - NotPorted("Combo") + if ImGui.Button("Collapse all") then + open_action = 0 end - if s.contents_type == CT_FillButton then - ImGui.SameLine() - DemoHelpMarker( - "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop " .. - "where contents width can feed into auto-column width can feed into contents width.") + ImGui.SameLine() + + -- Options + _, s.disable_indent = ImGui.Checkbox("Disable tree indentation", s.disable_indent) + ImGui.SameLine() + HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.") + ImGui.Separator() + if s.disable_indent then + ImGui.PushStyleVar(16 --[[ImGuiStyleVar.IndentSpacing]], 0.0) end - s.column_count = ImGui.DragInt("Columns", s.column_count, 0.1, 1, 64, "%d", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, TF.PreciseWidths) - ImGui.SameLine(); DemoHelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, TF.ScrollX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, TF.NoClip) - ImGui.PopItemWidth() - ImGui.PopID() - PopStyleCompact() - if ImGui.BeginTable("table2", s.column_count, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 7)) then - for cell = 0, 10 * s.column_count - 1 do - ImGui.TableNextColumn() - local column = ImGui.TableGetColumnIndex() - local row = ImGui.TableGetRowIndex() + -- About Styling of tables + -- Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs. + -- There are however a few settings that a shared and part of the ImGuiStyle structure: + -- style.CellPadding -- Padding within each cell + -- style.Colors[ImGuiCol.TableHeaderBg] -- Table header background + -- style.Colors[ImGuiCol.TableBorderStrong] -- Table outer and header borders + -- style.Colors[ImGuiCol.TableBorderLight] -- Table inner borders + -- style.Colors[ImGuiCol.TableRowBg] -- Table row background when ImGuiTableFlags_RowBg is enabled (even rows) + -- style.Colors[ImGuiCol.TableRowBgAlt] -- Table row background when ImGuiTableFlags_RowBg is enabled (odds rows) - ImGui.PushID(cell) - local label = string.format("Hello %d,%d", column, row) - local ct = s.contents_type - if ct == CT_ShortText then ImGui.TextUnformatted(label) - elseif ct == CT_LongText then ImGui.Text("Some %s text %d,%d\nOver two lines..", column == 0 and "long" or "longeeer", column, row) - elseif ct == CT_ShowWidth then ImGui.Text("W: %.1f", ImGui.GetContentRegionAvail().x) - elseif ct == CT_Button then ImGui.Button(label) - elseif ct == CT_FillButton then ImGui.Button(label, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) - elseif ct == CT_InputText then ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]); ImGui.InputText("##", s.text_buf, 32) - end - ImGui.PopID() - end - ImGui.EndTable() + -- Demos + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) end -end + if ImGui.TreeNode("Basic") then + IMGUI_DEMO_MARKER("Tables/Basic") + -- Here we will showcase three different ways to output a table. + -- They are very simple variations of a same thing! -local function Tables_VerticalScrolling() - IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping") - DemoHelpMarker( - "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n" .. - "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.") - local s = ST.vscroll - if s == nil then s = { flags = bor(TF.ScrollY, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.Resizable, TF.Reorderable, TF.Hideable) }; ST.vscroll = s end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - PopStyleCompact() - - -- When using ScrollX or ScrollY we need to specify a size for our table container! - -- Otherwise by default the table will fit all available space, like a BeginChild() call. - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) - if ImGui.BeginTable("table_scrolly", 3, s.flags, outer_size) then - ImGui.TableSetupScrollFreeze(0, 1) -- Make top row always visible - ImGui.TableSetupColumn("One", 0 --[[ImGuiTableColumnFlags.None]]) - ImGui.TableSetupColumn("Two", 0 --[[ImGuiTableColumnFlags.None]]) - ImGui.TableSetupColumn("Three", 0 --[[ImGuiTableColumnFlags.None]]) - ImGui.TableHeadersRow() - - -- Demonstrate using clipper for large vertical lists - local clipper = ImGuiListClipper() - clipper:Begin(1000) - while clipper:Step() do - for row = clipper.DisplayStart, clipper.DisplayEnd - 1 do + -- [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. + -- In many situations, this is the most flexible and easy to use pattern. + HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.") + if ImGui.BeginTable("table1", 3) then + for row = 0, 4 - 1 do ImGui.TableNextRow() - for column = 0, 2 do + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Row %d Column %d", row, column) + end + end + ImGui.EndTable() + end + + -- [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). + -- This is generally more convenient when you have code manually submitting the contents of each column. + HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.") + if ImGui.BeginTable("table2", 3) then + for row = 0, 4 - 1 do + ImGui.TableNextRow() + ImGui.TableNextColumn() + ImGui.Text("Row %d", row) + ImGui.TableNextColumn() + ImGui.Text("Some contents") + ImGui.TableNextColumn() + ImGui.Text("123.456") + end + ImGui.EndTable() + end + + -- [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), + -- as TableNextColumn() will automatically wrap around and create new rows as needed. + -- This is generally more convenient when your cells all contains the same type of data. + HelpMarker( + "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains " .. + "the same type of contents.\n This is also more similar to the old NextColumn() function of the " .. + "Columns API, and provided to facilitate the Columns->Tables API transition.") + if ImGui.BeginTable("table3", 3) then + for item = 0, 14 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Item %d", item) + end + ImGui.EndTable() + end + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Borders, background") then + IMGUI_DEMO_MARKER("Tables/Borders, background") + -- Expose a few Borders related flags interactively + local CT_Text, CT_FillButton = 0, 1 -- enum ContentsType + local s = s.BordersBackground + + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, 64 --[[ImGuiTableFlags.RowBg]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, 1920 --[[ImGuiTableFlags.Borders]]) + ImGui.SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH") + ImGui.Indent() + + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, 384 --[[ImGuiTableFlags.BordersH]]) + ImGui.Indent() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, 256 --[[ImGuiTableFlags.BordersOuterH]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, 128 --[[ImGuiTableFlags.BordersInnerH]]) + ImGui.Unindent() + + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, 1536 --[[ImGuiTableFlags.BordersV]]) + ImGui.Indent() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, 1024 --[[ImGuiTableFlags.BordersOuterV]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, 512 --[[ImGuiTableFlags.BordersInnerV]]) + ImGui.Unindent() + + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags, 1280 --[[ImGuiTableFlags.BordersOuter]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags, 640 --[[ImGuiTableFlags.BordersInner]]) + ImGui.Unindent() + + ImGui.AlignTextToFramePadding(); ImGui.Text("Cell contents:") + ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("Text", s.contents_type, CT_Text) + ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("FillButton", s.contents_type, CT_FillButton) + _, s.display_headers = ImGui.Checkbox("Display headers", s.display_headers) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, 2048 --[[ImGuiTableFlags.NoBordersInBody]]); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") + PopStyleCompact() + + if ImGui.BeginTable("table1", 3, s.flags) then + -- Display headers so we can inspect their interaction with borders + -- (Headers are not the main purpose of this section of the demo, so we are not elaborating on them now. See other sections for details) + if s.display_headers then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + end + + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + local buf = string.format("Hello %d,%d", column, row) + if s.contents_type == CT_Text then + ImGui.TextUnformatted(buf) + elseif s.contents_type == CT_FillButton then + ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Resizable, stretch") then + IMGUI_DEMO_MARKER("Tables/Resizable, stretch") + -- By default, if we don't enable ScrollX the sizing policy for each column is "Stretch" + -- All columns maintain a sizing weight, and they will occupy all available width. + local s = s.ResizableStretch + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, 1536 --[[ImGuiTableFlags.BordersV]]) + ImGui.SameLine(); HelpMarker( + "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, " .. + "this is why the resize borders are still showing when unchecking this.") + PopStyleCompact() + + if ImGui.BeginTable("table1", 3, s.flags) then + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do ImGui.TableSetColumnIndex(column) ImGui.Text("Hello %d,%d", column, row) end end + ImGui.EndTable() end - ImGui.EndTable() - end -end - -local function Tables_HorizontalScrolling() - IMGUI_DEMO_MARKER("Tables/Horizontal scrolling") - DemoHelpMarker( - "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " .. - "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" .. - "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, " .. - "because the container window won't automatically extend vertically to fix contents " .. - "(this may be improved in future versions).") - local s = ST.hscroll - if s == nil then - s = { flags = bor(TF.ScrollX, TF.ScrollY, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.Resizable, TF.Reorderable, TF.Hideable), - freeze_cols = 1, freeze_rows = 1, - flags2 = bor(TF.SizingStretchSame, TF.ScrollX, TF.ScrollY, TF.BordersOuter, TF.RowBg, TF.ContextMenuInBody), inner_width = 1000.0 } - ST.hscroll = s - end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, TF.ScrollX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) - PopStyleCompact() - - -- When using ScrollX or ScrollY we need to specify a size for our table container! - -- Otherwise by default the table will fit all available space, like a BeginChild() call. - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) - if ImGui.BeginTable("table_scrollx", 7, s.flags, outer_size) then - ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) - ImGui.TableSetupColumn("Line #", 128 --[[ImGuiTableColumnFlags.NoHide]]) -- Make the first column not hideable to match our use of TableSetupScrollFreeze() - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableSetupColumn("Four") - ImGui.TableSetupColumn("Five") - ImGui.TableSetupColumn("Six") - ImGui.TableHeadersRow() - for row = 0, 19 do - ImGui.TableNextRow() - for column = 0, 6 do repeat - -- Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement. - -- Because here we know that: - -- - A) all our columns are contributing the same to row height - -- - B) column 0 is always visible, - -- We only always submit this one column and can skip others. - -- More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags(). - if not ImGui.TableSetColumnIndex(column) and column > 0 then - break -- continue - end - if column == 0 then - ImGui.Text("Line %d", row) - else - ImGui.Text("Hello world %d,%d", column, row) - end - until true end - end - ImGui.EndTable() - end - - ImGui.Spacing() - ImGui.TextUnformatted("Stretch + ScrollX") - ImGui.SameLine() - DemoHelpMarker( - "Showcase using Stretch columns + ScrollX together: " .. - "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" .. - "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns " .. - "along with ScrollX doesn't make sense.") - PushStyleCompact() - ImGui.PushID("flags3") - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags2, TF.ScrollX) - s.inner_width = ImGui.DragFloat("inner_width", s.inner_width, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]], "%.1f") - ImGui.PopItemWidth() - ImGui.PopID() - PopStyleCompact() - if ImGui.BeginTable("table2", 7, s.flags2, outer_size, s.inner_width) then - for cell = 0, 20 * 7 - 1 do - ImGui.TableNextColumn() - ImGui.Text("Hello world %d,%d", ImGui.TableGetColumnIndex(), ImGui.TableGetRowIndex()) - end - ImGui.EndTable() - end -end - -local function Tables_ColumnsFlags() - IMGUI_DEMO_MARKER("Tables/Columns flags") - -- Create a first table just to show all the options/flags we want to make visible in our example! - local column_count = 3 - local column_names = { "One", "Two", "Three" } - local s = ST.colflags - if s == nil then - s = { column_flags = { 4 --[[ImGuiTableColumnFlags.DefaultSort]], 0 --[[ImGuiTableColumnFlags.None]], 2 --[[ImGuiTableColumnFlags.DefaultHide]] }, column_flags_out = { 0, 0, 0 } } -- column_flags_out: Output from TableGetColumnFlags() - ST.colflags = s - end - - if ImGui.BeginTable("table_columns_flags_checkboxes", column_count, 0 --[[ImGuiTableFlags.None]]) then - PushStyleCompact() - for column = 1, column_count do - ImGui.TableNextColumn() - ImGui.PushID(column - 1) - ImGui.AlignTextToFramePadding() -- FIXME-TABLE: Workaround for wrong text baseline propagation across columns - ImGui.Text("'%s'", column_names[column]) - ImGui.Spacing() - ImGui.Text("Input flags:") - s.column_flags[column] = EditTableColumnsFlags(s.column_flags[column]) - ImGui.Spacing() - ImGui.Text("Output flags:") - ImGui.BeginDisabled() - ShowTableColumnsStatusFlags(s.column_flags_out[column]) - ImGui.EndDisabled() - ImGui.PopID() - end - PopStyleCompact() - ImGui.EndTable() - end - - -- Create the real table we care about for the example! - -- We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, - -- otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible - -- + resizing the parent window down). - local flags = bor(TF.SizingFixedFit, TF.ScrollX, TF.ScrollY, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.Resizable, TF.Reorderable, TF.Hideable, TF.Sortable) - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 9) - if ImGui.BeginTable("table_columns_flags", column_count, flags, outer_size) then - local has_angled_header = false - for column = 1, column_count do - has_angled_header = has_angled_header or Has(s.column_flags[column], 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) - ImGui.TableSetupColumn(column_names[column], s.column_flags[column]) - end - if has_angled_header then - ImGui.TableAngledHeadersRow() - end - ImGui.TableHeadersRow() - for column = 1, column_count do - s.column_flags_out[column] = ImGui.TableGetColumnFlags(column - 1) - end - local indent_step = math.floor(math.floor(TEXT_BASE_WIDTH) / 2) - for row = 0, 7 do - -- Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags. - ImGui.Indent(indent_step) - ImGui.TableNextRow() - for column = 0, column_count - 1 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s %s", (column == 0) and "Indented" or "Hello", ImGui.TableGetColumnName(column)) - end - end - ImGui.Unindent(indent_step * 8.0) - - ImGui.EndTable() - end -end - -local function Tables_ColumnsWidths() - IMGUI_DEMO_MARKER("Tables/Columns widths") - DemoHelpMarker("Using TableSetupColumn() to setup default width.") - local s = ST.colwidths - if s == nil then s = { flags1 = bor(TF.Borders, TF.NoBordersInBodyUntilResize), flags2 = TF.None }; ST.colwidths = s end - local CF = ImGuiTableColumnFlags - - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, TF.Resizable) - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags1, TF.NoBordersInBodyUntilResize) - PopStyleCompact() - if ImGui.BeginTable("table1", 3, s.flags1) then - -- We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. - ImGui.TableSetupColumn("one", CF.WidthFixed, 100.0) -- Default to 100.0f - ImGui.TableSetupColumn("two", CF.WidthFixed, 200.0) -- Default to 200.0f - ImGui.TableSetupColumn("three", CF.WidthFixed) -- Default to auto - ImGui.TableHeadersRow() - for row = 0, 3 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - if row == 0 then - ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) - else - ImGui.Text("Hello %d,%d", column, row) - end - end - end - ImGui.EndTable() - end - - DemoHelpMarker( - "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, " .. - "fixed columns with set width may still be shrunk down if there's not enough space in the host.") - - PushStyleCompact() - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags2, TF.NoKeepColumnsVisible) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags2, TF.BordersInnerV) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags2, TF.BordersOuterV) - PopStyleCompact() - if ImGui.BeginTable("table2", 4, s.flags2) then - -- We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns - -- will default to ImGuiTableColumnFlags_WidthFixed. - ImGui.TableSetupColumn("", CF.WidthFixed, 100.0) - ImGui.TableSetupColumn("", CF.WidthFixed, TEXT_BASE_WIDTH * 15.0) - ImGui.TableSetupColumn("", CF.WidthFixed, TEXT_BASE_WIDTH * 30.0) - ImGui.TableSetupColumn("", CF.WidthFixed, TEXT_BASE_WIDTH * 15.0) - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 3 do - ImGui.TableSetColumnIndex(column) - if row == 0 then - ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) - else - ImGui.Text("Hello %d,%d", column, row) - end - end - end - ImGui.EndTable() - end -end - -local function Tables_Nested() - IMGUI_DEMO_MARKER("Tables/Nested tables") - DemoHelpMarker("This demonstrates embedding a table into another table cell.") - - if ImGui.BeginTable("table_nested1", 2, bor(TF.Borders, TF.Resizable, TF.Reorderable, TF.Hideable)) then - ImGui.TableSetupColumn("A0") - ImGui.TableSetupColumn("A1") - ImGui.TableHeadersRow() - - ImGui.TableNextColumn() - ImGui.Text("A0 Row 0") - do - local rows_height = (TEXT_BASE_HEIGHT * 2.0) + (ImGui.GetStyle().CellPadding.y * 2.0) - if ImGui.BeginTable("table_nested2", 2, bor(TF.Borders, TF.Resizable, TF.Reorderable, TF.Hideable)) then - ImGui.TableSetupColumn("B0") - ImGui.TableSetupColumn("B1") - ImGui.TableHeadersRow() - - ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], rows_height) - ImGui.TableNextColumn() - ImGui.Text("B0 Row 0") - ImGui.TableNextColumn() - ImGui.Text("B1 Row 0") - ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], rows_height) - ImGui.TableNextColumn() - ImGui.Text("B0 Row 1") - ImGui.TableNextColumn() - ImGui.Text("B1 Row 1") - - ImGui.EndTable() - end - end - ImGui.TableNextColumn(); ImGui.Text("A1 Row 0") - ImGui.TableNextColumn(); ImGui.Text("A0 Row 1") - ImGui.TableNextColumn(); ImGui.Text("A1 Row 1") - ImGui.EndTable() - end -end - -local function Tables_RowHeight() - IMGUI_DEMO_MARKER("Tables/Row height") - DemoHelpMarker( - "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, " .. - "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n" .. - "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.") - if ImGui.BeginTable("table_row_height", 1, TF.Borders) then - for row = 0, 7 do - local min_row_height = math.floor(TEXT_BASE_HEIGHT * 0.30 * row + ImGui.GetStyle().CellPadding.y * 2.0) - ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], min_row_height) - ImGui.TableNextColumn() - ImGui.Text("min_row_height = %.2f", min_row_height) - end - ImGui.EndTable() - end - - DemoHelpMarker( - "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n" .. - "Please note that Tables Row Height is not the same thing as Current Line Height, " .. - "as a table cell may contains multiple lines.") - if ImGui.BeginTable("table_share_lineheight", 2, TF.Borders) then - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.ColorButton("##1", ImVec4(0.13, 0.26, 0.40, 1.0), 0 --[[ImGuiColorEditFlags.None]], ImVec2(40, 40)) - ImGui.TableNextColumn() - ImGui.Text("Line 1") - ImGui.Text("Line 2") - - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.ColorButton("##2", ImVec4(0.13, 0.26, 0.40, 1.0), 0 --[[ImGuiColorEditFlags.None]], ImVec2(40, 40)) - ImGui.TableNextColumn() - ImGui.SameLine(0.0, 0.0) -- Reuse line height from previous column - ImGui.Text("Line 1, with SameLine(0,0)") - ImGui.Text("Line 2") - - ImGui.EndTable() - end - - DemoHelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.") - if ImGui.BeginTable("table_changing_cellpadding_y", 1, TF.Borders) then - local style = ImGui.GetStyle() - for row = 0, 7 do - if (row % 3) == 2 then - ImGui.PushStyleVarY(17 --[[ImGuiStyleVar.CellPadding]], 20.0) - end - ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]]) - ImGui.TableNextColumn() - ImGui.Text("CellPadding.y = %.2f", style.CellPadding.y) - if (row % 3) == 2 then - ImGui.PopStyleVar() - end - end - ImGui.EndTable() - end -end - -local function Tables_OuterSize() - IMGUI_DEMO_MARKER("Tables/Outer size") - -- Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY - -- Important to that note how the two flags have slightly different behaviors! - ImGui.Text("Using NoHostExtendX and NoHostExtendY:") - PushStyleCompact() - local s = ST.outer - if s == nil then s = { flags = bor(TF.Borders, TF.Resizable, TF.ContextMenuInBody, TF.RowBg, TF.SizingFixedFit, TF.NoHostExtendX) }; ST.outer = s end - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, TF.NoHostExtendX) - ImGui.SameLine(); DemoHelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, TF.NoHostExtendY) - ImGui.SameLine(); DemoHelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") - PopStyleCompact() - - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 5.5) - if ImGui.BeginTable("table1", 3, s.flags, outer_size) then - for row = 0, 9 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableNextColumn() - ImGui.Text("Cell %d,%d", column, row) - end - end - ImGui.EndTable() - end - ImGui.SameLine() - ImGui.Text("Hello!") - - ImGui.Spacing() - - ImGui.Text("Using explicit size:") - if ImGui.BeginTable("table2", 3, bor(TF.Borders, TF.RowBg), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableNextColumn() - ImGui.Text("Cell %d,%d", column, row) - end - end - ImGui.EndTable() - end - ImGui.SameLine() - if ImGui.BeginTable("table3", 3, bor(TF.Borders, TF.RowBg), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then - local rows_height = TEXT_BASE_HEIGHT * 1.5 + ImGui.GetStyle().CellPadding.y * 2.0 - for row = 0, 2 do - ImGui.TableNextRow(0, rows_height) - for column = 0, 2 do - ImGui.TableNextColumn() - ImGui.Text("Cell %d,%d", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_BackgroundColor() - IMGUI_DEMO_MARKER("Tables/Background color") - local s = ST.bgcolor - if s == nil then s = { flags = TF.RowBg, row_bg_type = 1, row_bg_target = 1, cell_bg_type = 1 }; ST.bgcolor = s end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, TF.Borders) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, TF.RowBg) - ImGui.SameLine(); DemoHelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.") - if ImGui.Combo then - s.row_bg_type = ImGui.Combo("row bg type", s.row_bg_type, { "None", "Red", "Gradient" }, 3) - s.row_bg_target = ImGui.Combo("row bg target", s.row_bg_target, { "RowBg0", "RowBg1" }, 2); ImGui.SameLine(); DemoHelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.") - s.cell_bg_type = ImGui.Combo("cell bg type", s.cell_bg_type, { "None", "Blue" }, 2); ImGui.SameLine(); DemoHelpMarker("We are colorizing cells to B1->C2 here.") - else - NotPorted("Combo") - end - assert(s.row_bg_type >= 0 and s.row_bg_type <= 2) - assert(s.row_bg_target >= 0 and s.row_bg_target <= 1) - assert(s.cell_bg_type >= 0 and s.cell_bg_type <= 1) - PopStyleCompact() - - if ImGui.BeginTable("table1", 5, s.flags) then - for row = 0, 5 do - ImGui.TableNextRow() - - -- Demonstrate setting a row background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBgX, ...)' - -- We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag. - if s.row_bg_type ~= 0 then - local row_bg_color = ImGui.GetColorU32(s.row_bg_type == 1 and ImVec4(0.7, 0.3, 0.3, 0.65) or ImVec4(0.2 + row * 0.1, 0.2, 0.2, 0.65)) -- Flat or Gradient? - ImGui.TableSetBgColor(1 --[[ImGuiTableBgTarget.RowBg0]] + s.row_bg_target, row_bg_color) - end - - -- Fill cells - for column = 0, 4 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s%s", string.char(65 + row), string.char(48 + column)) - - -- Change background of Cells B1->C2 - -- Demonstrate setting a cell background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ...)' - -- (the CellBg color will be blended over the RowBg and ColumnBg colors) - -- We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop. - if row >= 1 and row <= 2 and column >= 1 and column <= 2 and s.cell_bg_type == 1 then - local cell_bg_color = ImGui.GetColorU32(ImVec4(0.3, 0.3, 0.7, 0.65)) - ImGui.TableSetBgColor(3 --[[ImGuiTableBgTarget.CellBg]], cell_bg_color) - end - end - end - ImGui.EndTable() - end -end - --- Simple storage to output a dummy file-system. -local tree_view_nodes = { - { Name = "Root with Long Name", Type = "Folder", Size = -1, ChildIdx = 1, ChildCount = 3 }, -- 0 - { Name = "Music", Type = "Folder", Size = -1, ChildIdx = 4, ChildCount = 2 }, -- 1 - { Name = "Textures", Type = "Folder", Size = -1, ChildIdx = 6, ChildCount = 3 }, -- 2 - { Name = "desktop.ini", Type = "System file", Size = 1024, ChildIdx = -1, ChildCount = -1 }, -- 3 - { Name = "File1_a.wav", Type = "Audio file", Size = 123000, ChildIdx = -1, ChildCount = -1 }, -- 4 - { Name = "File1_b.wav", Type = "Audio file", Size = 456000, ChildIdx = -1, ChildCount = -1 }, -- 5 - { Name = "Image001.png", Type = "Image file", Size = 203128, ChildIdx = -1, ChildCount = -1 }, -- 6 - { Name = "Copy of Image001.png", Type = "Image file", Size = 203256, ChildIdx = -1, ChildCount = -1 }, -- 7 - { Name = "Copy of Image001 (Final2).png", Type = "Image file", Size = 203512, ChildIdx = -1, ChildCount = -1 }, -- 8 -} - -local function MyTreeNode_DisplayNode(node, all_nodes, tree_node_flags_base) - ImGui.TableNextRow() - ImGui.TableNextColumn() - local is_folder = (node.ChildCount > 0) - - local node_flags = tree_node_flags_base - if node ~= all_nodes[1] then - node_flags = bit32.band(node_flags, bit32.bnot(32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]])) -- Only demonstrate this on the root node. - end - - if is_folder then - local open = ImGui.TreeNodeEx(node.Name, node_flags) - if bit32.band(node_flags, 32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]]) == 0 then - ImGui.TableNextColumn() - ImGui.TextDisabled("--") - ImGui.TableNextColumn() - ImGui.TextUnformatted(node.Type) - end - if open then - for child_n = 0, node.ChildCount - 1 do - MyTreeNode_DisplayNode(all_nodes[node.ChildIdx + child_n + 1], all_nodes, tree_node_flags_base) - end - ImGui.TreePop() - end - else - ImGui.TreeNodeEx(node.Name, bor(node_flags, 256 --[[ImGuiTreeNodeFlags.Leaf]], 512 --[[ImGuiTreeNodeFlags.Bullet]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]])) - ImGui.TableNextColumn() - ImGui.Text("%d", node.Size) - ImGui.TableNextColumn() - ImGui.TextUnformatted(node.Type) - end -end - -local function Tables_TreeView() - IMGUI_DEMO_MARKER("Tables/Tree view") - local s = ST.treeview - if s == nil then - s = { table_flags = bor(TF.BordersV, TF.BordersOuterH, TF.Resizable, TF.RowBg, TF.NoBordersInBody), - tree_node_flags_base = bor(16384 --[[ImGuiTreeNodeFlags.SpanAllColumns]], 32 --[[ImGuiTreeNodeFlags.DefaultOpen]], 524288 --[[ImGuiTreeNodeFlags.DrawLinesFull]]) } - ST.treeview = s - end - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", s.tree_node_flags_base, 4096 --[[ImGuiTreeNodeFlags.SpanFullWidth]]) - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", s.tree_node_flags_base, 8192 --[[ImGuiTreeNodeFlags.SpanLabelWidth]]) - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", s.tree_node_flags_base, 16384 --[[ImGuiTreeNodeFlags.SpanAllColumns]]) - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", s.tree_node_flags_base, 32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]]) - ImGui.SameLine(); DemoHelpMarker("Useful if you know that you aren't displaying contents in other columns") - - DemoHelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.") - if ImGui.BeginTable("3ways", 3, s.table_flags) then - -- The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On - ImGui.TableSetupColumn("Name", 128 --[[ImGuiTableColumnFlags.NoHide]]) - ImGui.TableSetupColumn("Size", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 12.0) - ImGui.TableSetupColumn("Type", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 18.0) - ImGui.TableHeadersRow() - - MyTreeNode_DisplayNode(tree_view_nodes[1], tree_view_nodes, s.tree_node_flags_base) - - ImGui.EndTable() - end -end - -local function Tables_ItemWidth() - IMGUI_DEMO_MARKER("Tables/Item width") - DemoHelpMarker( - "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" .. - "Note that on auto-resizing non-resizable fixed columns, querying the content width for " .. - "e.g. right-alignment doesn't make sense.") - if ImGui.BeginTable("table_item_width", 3, TF.Borders) then - ImGui.TableSetupColumn("small") - ImGui.TableSetupColumn("half") - ImGui.TableSetupColumn("right-align") - ImGui.TableHeadersRow() - - for row = 0, 2 do - ImGui.TableNextRow() - if row == 0 then - -- Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient) - ImGui.TableSetColumnIndex(0) - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 3.0) -- Small - ImGui.TableSetColumnIndex(1) - ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.5) - ImGui.TableSetColumnIndex(2) - ImGui.PushItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) -- Right-aligned - end - - -- Draw our contents - ImGui.PushID(row) - ImGui.TableSetColumnIndex(0) - ST.dummy_f = ImGui.SliderFloat("float0", ST.dummy_f or 0.0, 0.0, 1.0) - ImGui.TableSetColumnIndex(1) - ST.dummy_f = ImGui.SliderFloat("float1", ST.dummy_f, 0.0, 1.0) - ImGui.TableSetColumnIndex(2) - ST.dummy_f = ImGui.SliderFloat("##float2", ST.dummy_f, 0.0, 1.0) -- No visible label since right-aligned - ImGui.PopID() - end - ImGui.EndTable() - end -end - --- Demonstrate using TableHeader() calls instead of TableHeadersRow() -local function Tables_CustomHeaders() - IMGUI_DEMO_MARKER("Tables/Custom headers") - local COLUMNS_COUNT = 3 - if ImGui.BeginTable("table_custom_headers", COLUMNS_COUNT, bor(TF.Borders, TF.Reorderable, TF.Hideable)) then - ImGui.TableSetupColumn("Apricot") - ImGui.TableSetupColumn("Banana") - ImGui.TableSetupColumn("Cherry") - - -- Dummy entire-column selection storage - -- FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. - if ST.column_selected == nil then ST.column_selected = { false, false, false } end - local column_selected = ST.column_selected - - -- Instead of calling TableHeadersRow() we'll submit custom headers ourselves. - -- (A different approach is also possible: - -- - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call. - -- - Call TableHeadersRow() normally. This will submit TableHeader() with no name. - -- - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().) - ImGui.TableNextRow(1 --[[ImGuiTableRowFlags.Headers]]) - for column = 0, COLUMNS_COUNT - 1 do - ImGui.TableSetColumnIndex(column) - local column_name = ImGui.TableGetColumnName(column) -- Retrieve name passed to TableSetupColumn() - ImGui.PushID(column) - ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(0, 0)) - _, column_selected[column + 1] = ImGui.Checkbox("##checkall", column_selected[column + 1]) - ImGui.PopStyleVar() - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - ImGui.TableHeader(column_name) - ImGui.PopID() - end - - -- Submit table contents - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - local buf = string.format("Cell %d,%d", column, row) - ImGui.TableSetColumnIndex(column) - ImGui.Selectable(buf, column_selected[column + 1]) - end - end - ImGui.EndTable() - end -end - --- Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers -local function Tables_AngledHeaders() - IMGUI_DEMO_MARKER("Tables/Angled headers") - local column_names = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" } - local columns_count = #column_names - local rows_count = 12 - - local s = ST.angled - if s == nil then - s = { table_flags = bor(TF.SizingFixedFit, TF.ScrollX, TF.ScrollY, TF.BordersOuter, TF.BordersInnerH, TF.Hideable, TF.Resizable, TF.Reorderable, TF.HighlightHoveredColumn), - column_flags = bor(262144 --[[ImGuiTableColumnFlags.AngledHeader]], 16 --[[ImGuiTableColumnFlags.WidthFixed]]), - bools = {}, frozen_cols = 1, frozen_rows = 2 } -- bools: Dummy storage selection storage - for i = 1, columns_count * rows_count do s.bools[i] = false end - ST.angled = s - end - _, s.table_flags = ImGui.CheckboxFlags("_ScrollX", s.table_flags, TF.ScrollX) - _, s.table_flags = ImGui.CheckboxFlags("_ScrollY", s.table_flags, TF.ScrollY) - _, s.table_flags = ImGui.CheckboxFlags("_Resizable", s.table_flags, TF.Resizable) - _, s.table_flags = ImGui.CheckboxFlags("_Sortable", s.table_flags, TF.Sortable) - _, s.table_flags = ImGui.CheckboxFlags("_NoBordersInBody", s.table_flags, TF.NoBordersInBody) - _, s.table_flags = ImGui.CheckboxFlags("_HighlightHoveredColumn", s.table_flags, TF.HighlightHoveredColumn) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - s.frozen_cols = ImGui.SliderInt("Frozen columns", s.frozen_cols, 0, 2) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - s.frozen_rows = ImGui.SliderInt("Frozen rows", s.frozen_rows, 0, 2) - _, s.column_flags = ImGui.CheckboxFlags("Disable header contributing to column width", s.column_flags, 8192 --[[ImGuiTableColumnFlags.NoHeaderWidth]]) - - if ImGui.TreeNode("Style settings") then - ImGui.SameLine() - DemoHelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.") - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - local style = ImGui.GetStyle() - style.TableAngledHeadersAngle = ImGui.SliderAngle("style.TableAngledHeadersAngle", style.TableAngledHeadersAngle, -50.0, 50.0) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - ImGui.SliderFloat2("style.TableAngledHeadersTextAlign", style.TableAngledHeadersTextAlign, 0.0, 1.0, "%.2f") ImGui.TreePop() end - if ImGui.BeginTable("table_angled_headers", columns_count, s.table_flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 12)) then - ImGui.TableSetupColumn(column_names[1], bor(128 --[[ImGuiTableColumnFlags.NoHide]], 64 --[[ImGuiTableColumnFlags.NoReorder]])) - for n = 2, columns_count do - ImGui.TableSetupColumn(column_names[n], s.column_flags) - end - ImGui.TableSetupScrollFreeze(s.frozen_cols, s.frozen_rows) + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Resizable, fixed") then + IMGUI_DEMO_MARKER("Tables/Resizable, fixed") + -- Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set) + -- So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) + -- If there is not enough available width to fit all columns, they will however be resized down. + -- FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings + HelpMarker( + "Using _Resizable + _SizingFixedFit flags.\n" .. + "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" .. + "Double-click a column border to auto-fit the column to its contents.") + PushStyleCompact() + local s = s.ResizableFixed + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, 65536 --[[ImGuiTableFlags.NoHostExtendX]]) + PopStyleCompact() - ImGui.TableAngledHeadersRow() -- Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag. - ImGui.TableHeadersRow() -- Draw remaining headers and allow access to context-menu and other functions. - for row = 0, rows_count - 1 do - ImGui.PushID(row) - ImGui.TableNextRow() - ImGui.TableSetColumnIndex(0) - ImGui.AlignTextToFramePadding() - ImGui.Text("Track %d", row) - for column = 1, columns_count - 1 do - if ImGui.TableSetColumnIndex(column) then - ImGui.PushID(column) - local idx = row * columns_count + column + 1 - _, s.bools[idx] = ImGui.Checkbox("", s.bools[idx]) - ImGui.PopID() + if ImGui.BeginTable("table1", 3, s.flags) then + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Hello %d,%d", column, row) end end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Resizable, mixed") then + IMGUI_DEMO_MARKER("Tables/Resizable, mixed") + HelpMarker( + "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" .. + "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.") + local s = s.ResizableMixed + + if ImGui.BeginTable("table1", 3, s.flags) then + ImGui.TableSetupColumn("AAA", 16 --[[ImGuiTableColumnFlags.WidthFixed]]) + ImGui.TableSetupColumn("BBB", 16 --[[ImGuiTableColumnFlags.WidthFixed]]) + ImGui.TableSetupColumn("CCC", 8 --[[ImGuiTableColumnFlags.WidthStretch]]) + ImGui.TableHeadersRow() + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%s %d,%d", (column == 2) and "Stretch" or "Fixed", column, row) + end + end + ImGui.EndTable() + end + if ImGui.BeginTable("table2", 6, s.flags) then + ImGui.TableSetupColumn("AAA", 16 --[[ImGuiTableColumnFlags.WidthFixed]]) + ImGui.TableSetupColumn("BBB", 16 --[[ImGuiTableColumnFlags.WidthFixed]]) + ImGui.TableSetupColumn("CCC", bit32.bor(16 --[[ImGuiTableColumnFlags.WidthFixed]], 2 --[[ImGuiTableColumnFlags.DefaultHide]])) + ImGui.TableSetupColumn("DDD", 8 --[[ImGuiTableColumnFlags.WidthStretch]]) + ImGui.TableSetupColumn("EEE", 8 --[[ImGuiTableColumnFlags.WidthStretch]]) + ImGui.TableSetupColumn("FFF", bit32.bor(8 --[[ImGuiTableColumnFlags.WidthStretch]], 2 --[[ImGuiTableColumnFlags.DefaultHide]])) + ImGui.TableHeadersRow() + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 6 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%s %d,%d", (column >= 3) and "Stretch" or "Fixed", column, row) + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Reorderable, hideable, with headers") then + IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers") + HelpMarker( + "Click and drag column headers to reorder columns.\n\n" .. + "Right-click on a header to open a context menu.") + local s = s.Reorderable + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, 2 --[[ImGuiTableFlags.Reorderable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, 4 --[[ImGuiTableFlags.Hideable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, 2048 --[[ImGuiTableFlags.NoBordersInBody]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, 4096 --[[ImGuiTableFlags.NoBordersInBodyUntilResize]]); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, 268435456 --[[ImGuiTableFlags.HighlightHoveredColumn]]) + PopStyleCompact() + + if ImGui.BeginTable("table1", 3, s.flags) then + -- Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column. + -- (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.) + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + for row = 0, 6 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Hello %d,%d", column, row) + end + end + ImGui.EndTable() + end + + -- Use outer_size.x == 0.0f instead of default to make the table as tight as possible + -- (only valid when no scrolling and no stretch column) + if ImGui.BeginTable("table2", 3, bit32.bor(s.flags, 8192 --[[ImGuiTableFlags.SizingFixedFit]]), ImVec2(0.0, 0.0)) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + for row = 0, 6 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Fixed %d,%d", column, row) + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Padding") then + IMGUI_DEMO_MARKER("Tables/Padding") + -- First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding. + -- We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding. + HelpMarker( + "We often want outer padding activated when any using features which makes the edges of a column visible:\n" .. + "e.g.:\n" .. + "- BorderOuterV\n" .. + "- any form of row selection\n" .. + "Because of this, activating BorderOuterV sets the default to PadOuterX. " .. + "Using PadOuterX or NoPadOuterX you can override the default.\n\n" .. + "Actual padding values are using style.CellPadding.\n\n" .. + "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.") + + local s = s.Padding + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags1, 2097152 --[[ImGuiTableFlags.PadOuterX]]) + ImGui.SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)") + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags1, 4194304 --[[ImGuiTableFlags.NoPadOuterX]]) + ImGui.SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)") + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags1, 8388608 --[[ImGuiTableFlags.NoPadInnerX]]) + ImGui.SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)") + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags1, 1024 --[[ImGuiTableFlags.BordersOuterV]]) + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags1, 512 --[[ImGuiTableFlags.BordersInnerV]]) + _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) + PopStyleCompact() + + if ImGui.BeginTable("table_padding", 3, s.flags1) then + if s.show_headers then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + end + + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + if row == 0 then + ImGui.Text("Avail %.2f", ImGui.GetContentRegionAvail().x) + else + local buf = string.format("Hello %d,%d", column, row) + ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + end + --if bit32.band(ImGui.TableGetColumnFlags(), ImGuiTableColumnFlags.IsHovered) ~= 0 then + -- ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, IM_COL32(0, 100, 0, 255)) end + end + end + ImGui.EndTable() + end + + -- Second example: set style.CellPadding to (0.0) or a custom value. + -- FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one... + HelpMarker("Setting style.CellPadding to (0,0) or a custom value.") + + PushStyleCompact() + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags2, 1920 --[[ImGuiTableFlags.Borders]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags2, 384 --[[ImGuiTableFlags.BordersH]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags2, 1536 --[[ImGuiTableFlags.BordersV]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags2, 640 --[[ImGuiTableFlags.BordersInner]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags2, 1280 --[[ImGuiTableFlags.BordersOuter]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags2, 64 --[[ImGuiTableFlags.RowBg]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags2, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.show_widget_frame_bg = ImGui.Checkbox("show_widget_frame_bg", s.show_widget_frame_bg) + ImGui.SliderFloat2("CellPadding", s.cell_padding, 0.0, 10.0, "%.0f") + PopStyleCompact() + + ImGui.PushStyleVar(17 --[[ImGuiStyleVar.CellPadding]], s.cell_padding) + if ImGui.BeginTable("table_padding_2", 3, s.flags2) then + -- static char text_bufs[3 * 5][16] -- Mini text storage for 3x5 cells + if not s.show_widget_frame_bg then + ImGui.PushStyleColor(7 --[[ImGuiCol.FrameBg]], 0) + end + for cell = 0, 3 * 5 - 1 do + ImGui.TableNextColumn() + if s.init then + s.text_bufs[cell + 1] = ImGui.NewTextBuffer("edit me", 16) -- [Port] strcpy() -> new buffer + end + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + ImGui.PushID(cell) + ImGui.InputText("##cell", s.text_bufs[cell + 1], 16) + ImGui.PopID() + end + if not s.show_widget_frame_bg then + ImGui.PopStyleColor() + end + s.init = false + ImGui.EndTable() + end + ImGui.PopStyleVar() + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Sizing policies") then + IMGUI_DEMO_MARKER("Tables/Explicit widths") + local s = s.SizingPolicies + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags1, 65536 --[[ImGuiTableFlags.NoHostExtendX]]) + PopStyleCompact() + + local sizing_policy_flags = s.sizing_policy_flags -- 1-based + for table_n = 0, 4 - 1 do + ImGui.PushID(table_n) + ImGui.SetNextItemWidth(TEXT_BASE_WIDTH * 30) + sizing_policy_flags[table_n + 1] = EditTableSizingFlags(sizing_policy_flags[table_n + 1]) + + -- To make it easier to understand the different sizing policy, + -- For each policy: we display one table where the columns have equal contents width, + -- and one where the columns have different contents width. + if ImGui.BeginTable("table1", 3, bit32.bor(sizing_policy_flags[table_n + 1], s.flags1)) then + for row = 0, 3 - 1 do + ImGui.TableNextRow() + ImGui.TableNextColumn(); ImGui.Text("Oh dear") + ImGui.TableNextColumn(); ImGui.Text("Oh dear") + ImGui.TableNextColumn(); ImGui.Text("Oh dear") + end + ImGui.EndTable() + end + if ImGui.BeginTable("table2", 3, bit32.bor(sizing_policy_flags[table_n + 1], s.flags1)) then + for row = 0, 3 - 1 do + ImGui.TableNextRow() + ImGui.TableNextColumn(); ImGui.Text("AAAA") + ImGui.TableNextColumn(); ImGui.Text("BBBBBBBB") + ImGui.TableNextColumn(); ImGui.Text("CCCCCCCCCCCC") + end + ImGui.EndTable() + end ImGui.PopID() end - ImGui.EndTable() - end -end --- Demonstrate creating custom context menus inside columns, --- while playing it nice with context menus provided by TableHeadersRow()/TableHeader() -local function Tables_ContextMenus() - IMGUI_DEMO_MARKER("Tables/Context menus") - DemoHelpMarker( - "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n" .. - "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.") - local s = ST.ctxmenu - if s == nil then s = { flags1 = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Borders, TF.ContextMenuInBody) }; ST.ctxmenu = s end + ImGui.Spacing() + ImGui.TextUnformatted("Advanced") + ImGui.SameLine() + HelpMarker( + "This section allows you to interact and see the effect of various sizing policies " .. + "depending on whether Scroll is enabled and the contents of your columns.") - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags1, TF.ContextMenuInBody) - PopStyleCompact() + local CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText = 0, 1, 2, 3, 4, 5 -- enum ContentsType - -- Context Menus: first example - -- [1.1] Right-click on the TableHeadersRow() line to open the default table context menu. - -- [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set) - local COLUMNS_COUNT = 3 - if ImGui.BeginTable("table_context_menu", COLUMNS_COUNT, s.flags1) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - - -- [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu. - ImGui.TableHeadersRow() - - -- Submit dummy contents - for row = 0, 3 do - ImGui.TableNextRow() - for column = 0, COLUMNS_COUNT - 1 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Cell %d,%d", column, row) - end + PushStyleCompact() + ImGui.PushID("Advanced") + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) + s.flags = EditTableSizingFlags(s.flags) + s.contents_type = ImGui.Combo("Contents", s.contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0") + if s.contents_type == CT_FillButton then + ImGui.SameLine() + HelpMarker( + "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop " .. + "where contents width can feed into auto-column width can feed into contents width.") end - ImGui.EndTable() + s.column_count = ImGui.DragInt("Columns", s.column_count, 0.1, 1, 64, "%d", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, 524288 --[[ImGuiTableFlags.PreciseWidths]]) + ImGui.SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, 16777216 --[[ImGuiTableFlags.ScrollX]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, 1048576 --[[ImGuiTableFlags.NoClip]]) + ImGui.PopItemWidth() + ImGui.PopID() + PopStyleCompact() + + if ImGui.BeginTable("table2", s.column_count, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 7)) then + for cell = 0, 10 * s.column_count - 1 do + ImGui.TableNextColumn() + local column = ImGui.TableGetColumnIndex() + local row = ImGui.TableGetRowIndex() + + ImGui.PushID(cell) + local label = string.format("Hello %d,%d", column, row) + local contents_type = s.contents_type + if contents_type == CT_ShortText then ImGui.TextUnformatted(label) + elseif contents_type == CT_LongText then ImGui.Text("Some %s text %d,%d\nOver two lines..", (column == 0) and "long" or "longeeer", column, row) + elseif contents_type == CT_ShowWidth then ImGui.Text("W: %.1f", ImGui.GetContentRegionAvail().x) + elseif contents_type == CT_Button then ImGui.Button(label) + elseif contents_type == CT_FillButton then ImGui.Button(label, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + elseif contents_type == CT_InputText then ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]); ImGui.InputText("##", s.text_buf, 32) + end + ImGui.PopID() + end + ImGui.EndTable() + end + ImGui.TreePop() end - -- Context Menus: second example - -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. - -- [2.2] Right-click on the ".." to open a custom popup - -- [2.3] Right-click in columns to open another custom popup - DemoHelpMarker( - "Demonstrate mixing table context menu (over header), item context button (over button) " .. - "and custom per-column context menu (over column body).") - local flags2 = bor(TF.Resizable, TF.SizingFixedFit, TF.Reorderable, TF.Hideable, TF.Borders) - if ImGui.BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Vertical scrolling, with clipping") then + IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping") + HelpMarker( + "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n" .. + "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.") + local s = s.VerticalScrolling - -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. - ImGui.TableHeadersRow() - for row = 0, 3 do + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + PopStyleCompact() + + -- When using ScrollX or ScrollY we need to specify a size for our table container! + -- Otherwise by default the table will fit all available space, like a BeginChild() call. + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) + if ImGui.BeginTable("table_scrolly", 3, s.flags, outer_size) then + ImGui.TableSetupScrollFreeze(0, 1) -- Make top row always visible + ImGui.TableSetupColumn("One", 0 --[[ImGuiTableColumnFlags.None]]) + ImGui.TableSetupColumn("Two", 0 --[[ImGuiTableColumnFlags.None]]) + ImGui.TableSetupColumn("Three", 0 --[[ImGuiTableColumnFlags.None]]) + ImGui.TableHeadersRow() + + -- Demonstrate using clipper for large vertical lists + local clipper = ImGuiListClipper() + clipper:Begin(1000) + while clipper:Step() do + for row = clipper.DisplayStart, clipper.DisplayEnd - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Hello %d,%d", column, row) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Horizontal scrolling") then + IMGUI_DEMO_MARKER("Tables/Horizontal scrolling") + HelpMarker( + "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " .. + "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" .. + "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, " .. + "because the container window won't automatically extend vertically to fix contents " .. + "(this may be improved in future versions).") + local s = s.HorizontalScrolling + + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, 16777216 --[[ImGuiTableFlags.ScrollX]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) + PopStyleCompact() + + -- When using ScrollX or ScrollY we need to specify a size for our table container! + -- Otherwise by default the table will fit all available space, like a BeginChild() call. + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) + if ImGui.BeginTable("table_scrollx", 7, s.flags, outer_size) then + ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) + ImGui.TableSetupColumn("Line #", 128 --[[ImGuiTableColumnFlags.NoHide]]) -- Make the first column not hideable to match our use of TableSetupScrollFreeze() + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableSetupColumn("Four") + ImGui.TableSetupColumn("Five") + ImGui.TableSetupColumn("Six") + ImGui.TableHeadersRow() + for row = 0, 20 - 1 do + ImGui.TableNextRow() + for column = 0, 7 - 1 do repeat + -- Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement. + -- Because here we know that: + -- - A) all our columns are contributing the same to row height + -- - B) column 0 is always visible, + -- We only always submit this one column and can skip others. + -- More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags(). + if not ImGui.TableSetColumnIndex(column) and column > 0 then + break -- continue + end + if column == 0 then + ImGui.Text("Line %d", row) + else + ImGui.Text("Hello world %d,%d", column, row) + end + until true end + end + ImGui.EndTable() + end + + ImGui.Spacing() + ImGui.TextUnformatted("Stretch + ScrollX") + ImGui.SameLine() + HelpMarker( + "Showcase using Stretch columns + ScrollX together: " .. + "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" .. + "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns " .. + "along with ScrollX doesn't make sense.") + PushStyleCompact() + ImGui.PushID("flags3") + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags2, 16777216 --[[ImGuiTableFlags.ScrollX]]) + s.inner_width = ImGui.DragFloat("inner_width", s.inner_width, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]], "%.1f") + ImGui.PopItemWidth() + ImGui.PopID() + PopStyleCompact() + if ImGui.BeginTable("table2", 7, s.flags2, outer_size, s.inner_width) then + for cell = 0, 20 * 7 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Hello world %d,%d", ImGui.TableGetColumnIndex(), ImGui.TableGetRowIndex()) + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Columns flags") then + IMGUI_DEMO_MARKER("Tables/Columns flags") + -- Create a first table just to show all the options/flags we want to make visible in our example! + local column_count = 3 + local column_names = { "One", "Two", "Three" } -- 1-based + local column_flags = s.ColumnsFlags.column_flags -- 1-based + local column_flags_out = s.ColumnsFlags.column_flags_out -- Output from TableGetColumnFlags() + + if ImGui.BeginTable("table_columns_flags_checkboxes", column_count, 0 --[[ImGuiTableFlags.None]]) then + PushStyleCompact() + for column = 0, column_count - 1 do + ImGui.TableNextColumn() + ImGui.PushID(column) + ImGui.AlignTextToFramePadding() -- FIXME-TABLE: Workaround for wrong text baseline propagation across columns + ImGui.Text("'%s'", column_names[column + 1]) + ImGui.Spacing() + ImGui.Text("Input flags:") + column_flags[column + 1] = EditTableColumnsFlags(column_flags[column + 1]) + ImGui.Spacing() + ImGui.Text("Output flags:") + ImGui.BeginDisabled() + ShowTableColumnsStatusFlags(column_flags_out[column + 1]) + ImGui.EndDisabled() + ImGui.PopID() + end + PopStyleCompact() + ImGui.EndTable() + end + + -- Create the real table we care about for the example! + -- We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, + -- otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + -- + resizing the parent window down). + local flags + = bit32.bor(8192 --[[ImGuiTableFlags.SizingFixedFit]], 16777216 --[[ImGuiTableFlags.ScrollX]], 33554432 --[[ImGuiTableFlags.ScrollY]] + , 64 --[[ImGuiTableFlags.RowBg]], 1280 --[[ImGuiTableFlags.BordersOuter]], 1536 --[[ImGuiTableFlags.BordersV]] + , 1 --[[ImGuiTableFlags.Resizable]], 2 --[[ImGuiTableFlags.Reorderable]], 4 --[[ImGuiTableFlags.Hideable]], 8 --[[ImGuiTableFlags.Sortable]]) + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 9) + if ImGui.BeginTable("table_columns_flags", column_count, flags, outer_size) then + local has_angled_header = false + for column = 0, column_count - 1 do + has_angled_header = has_angled_header or (bit32.band(column_flags[column + 1], 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) ~= 0) + ImGui.TableSetupColumn(column_names[column + 1], column_flags[column + 1]) + end + if has_angled_header then + ImGui.TableAngledHeadersRow() + end + ImGui.TableHeadersRow() + for column = 0, column_count - 1 do + column_flags_out[column + 1] = ImGui.TableGetColumnFlags(column) + end + local indent_step = math.floor(math.floor(TEXT_BASE_WIDTH) / 2) + for row = 0, 8 - 1 do + -- Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags. + ImGui.Indent(indent_step) + ImGui.TableNextRow() + for column = 0, column_count - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%s %s", (column == 0) and "Indented" or "Hello", ImGui.TableGetColumnName(column)) + end + end + ImGui.Unindent(indent_step * 8.0) + + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Columns widths") then + IMGUI_DEMO_MARKER("Tables/Columns widths") + HelpMarker("Using TableSetupColumn() to setup default width.") + + local s = s.ColumnsWidths + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags1, 4096 --[[ImGuiTableFlags.NoBordersInBodyUntilResize]]) + PopStyleCompact() + if ImGui.BeginTable("table1", 3, s.flags1) then + -- We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. + ImGui.TableSetupColumn("one", 16 --[[ImGuiTableColumnFlags.WidthFixed]], 100.0) -- Default to 100.0f + ImGui.TableSetupColumn("two", 16 --[[ImGuiTableColumnFlags.WidthFixed]], 200.0) -- Default to 200.0f + ImGui.TableSetupColumn("three", 16 --[[ImGuiTableColumnFlags.WidthFixed]]) -- Default to auto + ImGui.TableHeadersRow() + for row = 0, 4 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + if row == 0 then + ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) + else + ImGui.Text("Hello %d,%d", column, row) + end + end + end + ImGui.EndTable() + end + + HelpMarker( + "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, " .. + "fixed columns with set width may still be shrunk down if there's not enough space in the host.") + + PushStyleCompact() + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags2, 262144 --[[ImGuiTableFlags.NoKeepColumnsVisible]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags2, 512 --[[ImGuiTableFlags.BordersInnerV]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags2, 1024 --[[ImGuiTableFlags.BordersOuterV]]) + PopStyleCompact() + if ImGui.BeginTable("table2", 4, s.flags2) then + -- We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns + -- will default to ImGuiTableColumnFlags_WidthFixed. + ImGui.TableSetupColumn("", 16 --[[ImGuiTableColumnFlags.WidthFixed]], 100.0) + ImGui.TableSetupColumn("", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 15.0) + ImGui.TableSetupColumn("", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 30.0) + ImGui.TableSetupColumn("", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 15.0) + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 4 - 1 do + ImGui.TableSetColumnIndex(column) + if row == 0 then + ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) + else + ImGui.Text("Hello %d,%d", column, row) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Nested tables") then + IMGUI_DEMO_MARKER("Tables/Nested tables") + HelpMarker("This demonstrates embedding a table into another table cell.") + + if ImGui.BeginTable("table_nested1", 2, bit32.bor(1920 --[[ImGuiTableFlags.Borders]], 1 --[[ImGuiTableFlags.Resizable]], 2 --[[ImGuiTableFlags.Reorderable]], 4 --[[ImGuiTableFlags.Hideable]])) then + ImGui.TableSetupColumn("A0") + ImGui.TableSetupColumn("A1") + ImGui.TableHeadersRow() + + ImGui.TableNextColumn() + ImGui.Text("A0 Row 0") + do + local rows_height = (TEXT_BASE_HEIGHT * 2.0) + (ImGui.GetStyle().CellPadding.y * 2.0) + if ImGui.BeginTable("table_nested2", 2, bit32.bor(1920 --[[ImGuiTableFlags.Borders]], 1 --[[ImGuiTableFlags.Resizable]], 2 --[[ImGuiTableFlags.Reorderable]], 4 --[[ImGuiTableFlags.Hideable]])) then + ImGui.TableSetupColumn("B0") + ImGui.TableSetupColumn("B1") + ImGui.TableHeadersRow() + + ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], rows_height) + ImGui.TableNextColumn() + ImGui.Text("B0 Row 0") + ImGui.TableNextColumn() + ImGui.Text("B1 Row 0") + ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], rows_height) + ImGui.TableNextColumn() + ImGui.Text("B0 Row 1") + ImGui.TableNextColumn() + ImGui.Text("B1 Row 1") + + ImGui.EndTable() + end + end + ImGui.TableNextColumn(); ImGui.Text("A1 Row 0") + ImGui.TableNextColumn(); ImGui.Text("A0 Row 1") + ImGui.TableNextColumn(); ImGui.Text("A1 Row 1") + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Row height") then + IMGUI_DEMO_MARKER("Tables/Row height") + HelpMarker( + "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, " .. + "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n" .. + "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.") + if ImGui.BeginTable("table_row_height", 1, 1920 --[[ImGuiTableFlags.Borders]]) then + for row = 0, 8 - 1 do + local min_row_height = math.floor(TEXT_BASE_HEIGHT * 0.30 * row + ImGui.GetStyle().CellPadding.y * 2.0) + ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], min_row_height) + ImGui.TableNextColumn() + ImGui.Text("min_row_height = %.2f", min_row_height) + end + ImGui.EndTable() + end + + HelpMarker( + "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n" .. + "Please note that Tables Row Height is not the same thing as Current Line Height, " .. + "as a table cell may contains multiple lines.") + if ImGui.BeginTable("table_share_lineheight", 2, 1920 --[[ImGuiTableFlags.Borders]]) then ImGui.TableNextRow() - for column = 0, COLUMNS_COUNT - 1 do - -- Submit dummy contents - ImGui.TableSetColumnIndex(column) - ImGui.Text("Cell %d,%d", column, row) - ImGui.SameLine() + ImGui.TableNextColumn() + ImGui.ColorButton("##1", ImVec4(0.13, 0.26, 0.40, 1.0), 0 --[[ImGuiColorEditFlags.None]], ImVec2(40, 40)) + ImGui.TableNextColumn() + ImGui.Text("Line 1") + ImGui.Text("Line 2") - -- [2.2] Right-click on the ".." to open a custom popup - ImGui.PushID(row * COLUMNS_COUNT + column) - ImGui.SmallButton("..") - if ImGui.BeginPopupContextItem() then - ImGui.Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row) + ImGui.TableNextRow() + ImGui.TableNextColumn() + ImGui.ColorButton("##2", ImVec4(0.13, 0.26, 0.40, 1.0), 0 --[[ImGuiColorEditFlags.None]], ImVec2(40, 40)) + ImGui.TableNextColumn() + ImGui.SameLine(0.0, 0.0) -- Reuse line height from previous column + ImGui.Text("Line 1, with SameLine(0,0)") + ImGui.Text("Line 2") + + ImGui.EndTable() + end + + HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.") + if ImGui.BeginTable("table_changing_cellpadding_y", 1, 1920 --[[ImGuiTableFlags.Borders]]) then + local style = ImGui.GetStyle() + for row = 0, 8 - 1 do + if (row % 3) == 2 then + ImGui.PushStyleVarY(17 --[[ImGuiStyleVar.CellPadding]], 20.0) + end + ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]]) + ImGui.TableNextColumn() + ImGui.Text("CellPadding.y = %.2f", style.CellPadding.y) + if (row % 3) == 2 then + ImGui.PopStyleVar() + end + end + ImGui.EndTable() + end + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Outer size") then + IMGUI_DEMO_MARKER("Tables/Outer size") + -- Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY + -- Important to that note how the two flags have slightly different behaviors! + ImGui.Text("Using NoHostExtendX and NoHostExtendY:") + PushStyleCompact() + local s = s.OuterSize + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, 65536 --[[ImGuiTableFlags.NoHostExtendX]]) + ImGui.SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, 131072 --[[ImGuiTableFlags.NoHostExtendY]]) + ImGui.SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") + PopStyleCompact() + + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 5.5) + if ImGui.BeginTable("table1", 3, s.flags, outer_size) then + for row = 0, 10 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + ImGui.SameLine() + ImGui.Text("Hello!") + + ImGui.Spacing() + + ImGui.Text("Using explicit size:") + if ImGui.BeginTable("table2", 3, bit32.bor(1920 --[[ImGuiTableFlags.Borders]], 64 --[[ImGuiTableFlags.RowBg]]), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + ImGui.SameLine() + if ImGui.BeginTable("table3", 3, bit32.bor(1920 --[[ImGuiTableFlags.Borders]], 64 --[[ImGuiTableFlags.RowBg]]), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then + local rows_height = TEXT_BASE_HEIGHT * 1.5 + ImGui.GetStyle().CellPadding.y * 2.0 + for row = 0, 3 - 1 do + ImGui.TableNextRow(0, rows_height) + for column = 0, 3 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Background color") then + IMGUI_DEMO_MARKER("Tables/Background color") + local s = s.BackgroundColor + + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, 1920 --[[ImGuiTableFlags.Borders]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, 64 --[[ImGuiTableFlags.RowBg]]) + ImGui.SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.") + s.row_bg_type = ImGui.Combo("row bg type", s.row_bg_type, "None\0Red\0Gradient\0") + s.row_bg_target = ImGui.Combo("row bg target", s.row_bg_target, "RowBg0\0RowBg1\0"); ImGui.SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.") + s.cell_bg_type = ImGui.Combo("cell bg type", s.cell_bg_type, "None\0Blue\0"); ImGui.SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.") + assert(s.row_bg_type >= 0 and s.row_bg_type <= 2) + assert(s.row_bg_target >= 0 and s.row_bg_target <= 1) + assert(s.cell_bg_type >= 0 and s.cell_bg_type <= 1) + PopStyleCompact() + + if ImGui.BeginTable("table1", 5, s.flags) then + for row = 0, 6 - 1 do + ImGui.TableNextRow() + + -- Demonstrate setting a row background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBgX, ...)' + -- We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag. + if s.row_bg_type ~= 0 then + local row_bg_color = ImGui.GetColorU32((s.row_bg_type == 1) and ImVec4(0.7, 0.3, 0.3, 0.65) or ImVec4(0.2 + row * 0.1, 0.2, 0.2, 0.65)) -- Flat or Gradient? + ImGui.TableSetBgColor(1 --[[ImGuiTableBgTarget.RowBg0]] + s.row_bg_target, row_bg_color) + end + + -- Fill cells + for column = 0, 5 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%c%c", string.byte("A") + row, string.byte("0") + column) + + -- Change background of Cells B1->C2 + -- Demonstrate setting a cell background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ...)' + -- (the CellBg color will be blended over the RowBg and ColumnBg colors) + -- We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop. + if row >= 1 and row <= 2 and column >= 1 and column <= 2 and s.cell_bg_type == 1 then + local cell_bg_color = ImGui.GetColorU32(ImVec4(0.3, 0.3, 0.7, 0.65)) + ImGui.TableSetBgColor(3 --[[ImGuiTableBgTarget.CellBg]], cell_bg_color) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Tree view") then + IMGUI_DEMO_MARKER("Tables/Tree view") + local s = s.TreeView + + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", s.tree_node_flags_base, 4096 --[[ImGuiTreeNodeFlags.SpanFullWidth]]) + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", s.tree_node_flags_base, 8192 --[[ImGuiTreeNodeFlags.SpanLabelWidth]]) + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", s.tree_node_flags_base, 16384 --[[ImGuiTreeNodeFlags.SpanAllColumns]]) + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", s.tree_node_flags_base, 32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]]) + ImGui.SameLine(); HelpMarker("Useful if you know that you aren't displaying contents in other columns") + + HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.") + if ImGui.BeginTable("3ways", 3, s.table_flags) then + -- The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On + ImGui.TableSetupColumn("Name", 128 --[[ImGuiTableColumnFlags.NoHide]]) + ImGui.TableSetupColumn("Size", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 12.0) + ImGui.TableSetupColumn("Type", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 18.0) + ImGui.TableHeadersRow() + + -- Simple storage to output a dummy file-system. + -- struct MyTreeNode { Name, Type, Size, ChildIdx, ChildCount } (see s.nodes) + local MyTreeNode = s.MyTreeNode + if MyTreeNode == nil then -- [Port] local struct with a static method, created once and kept in statics + MyTreeNode = {} + function MyTreeNode.DisplayNode(node, all_nodes) + ImGui.TableNextRow() + ImGui.TableNextColumn() + local is_folder = (node.ChildCount > 0) + + local node_flags = s.tree_node_flags_base + if node ~= all_nodes[1] then + node_flags = bit32.band(node_flags, bit32.bnot(32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]])) -- Only demonstrate this on the root node. + end + + if is_folder then + local open = ImGui.TreeNodeEx(node.Name, node_flags) + if bit32.band(node_flags, 32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]]) == 0 then + ImGui.TableNextColumn() + ImGui.TextDisabled("--") + ImGui.TableNextColumn() + ImGui.TextUnformatted(node.Type) + end + if open then + for child_n = 0, node.ChildCount - 1 do + MyTreeNode.DisplayNode(all_nodes[node.ChildIdx + child_n + 1], all_nodes) + end + ImGui.TreePop() + end + else + ImGui.TreeNodeEx(node.Name, bit32.bor(node_flags, 256 --[[ImGuiTreeNodeFlags.Leaf]], 512 --[[ImGuiTreeNodeFlags.Bullet]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]])) + ImGui.TableNextColumn() + ImGui.Text("%d", node.Size) + ImGui.TableNextColumn() + ImGui.TextUnformatted(node.Type) + end + end + s.MyTreeNode = MyTreeNode + end + local nodes = s.nodes + + MyTreeNode.DisplayNode(nodes[1], nodes) + + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Item width") then + IMGUI_DEMO_MARKER("Tables/Item width") + HelpMarker( + "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" .. + "Note that on auto-resizing non-resizable fixed columns, querying the content width for " .. + "e.g. right-alignment doesn't make sense.") + if ImGui.BeginTable("table_item_width", 3, 1920 --[[ImGuiTableFlags.Borders]]) then + ImGui.TableSetupColumn("small") + ImGui.TableSetupColumn("half") + ImGui.TableSetupColumn("right-align") + ImGui.TableHeadersRow() + + for row = 0, 3 - 1 do + ImGui.TableNextRow() + if row == 0 then + -- Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient) + ImGui.TableSetColumnIndex(0) + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 3.0) -- Small + ImGui.TableSetColumnIndex(1) + ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.5) + ImGui.TableSetColumnIndex(2) + ImGui.PushItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) -- Right-aligned + end + + -- Draw our contents + local s = s.ItemWidth + ImGui.PushID(row) + ImGui.TableSetColumnIndex(0) + s.dummy_f = ImGui.SliderFloat("float0", s.dummy_f, 0.0, 1.0) + ImGui.TableSetColumnIndex(1) + s.dummy_f = ImGui.SliderFloat("float1", s.dummy_f, 0.0, 1.0) + ImGui.TableSetColumnIndex(2) + s.dummy_f = ImGui.SliderFloat("##float2", s.dummy_f, 0.0, 1.0) -- No visible label since right-aligned + ImGui.PopID() + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + -- Demonstrate using TableHeader() calls instead of TableHeadersRow() + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Custom headers") then + IMGUI_DEMO_MARKER("Tables/Custom headers") + local COLUMNS_COUNT = 3 + if ImGui.BeginTable("table_custom_headers", COLUMNS_COUNT, bit32.bor(1920 --[[ImGuiTableFlags.Borders]], 2 --[[ImGuiTableFlags.Reorderable]], 4 --[[ImGuiTableFlags.Hideable]])) then + ImGui.TableSetupColumn("Apricot") + ImGui.TableSetupColumn("Banana") + ImGui.TableSetupColumn("Cherry") + + -- Dummy entire-column selection storage + -- FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. + local column_selected = s.CustomHeaders.column_selected -- 1-based + + -- Instead of calling TableHeadersRow() we'll submit custom headers ourselves. + -- (A different approach is also possible: + -- - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call. + -- - Call TableHeadersRow() normally. This will submit TableHeader() with no name. + -- - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().) + ImGui.TableNextRow(1 --[[ImGuiTableRowFlags.Headers]]) + for column = 0, COLUMNS_COUNT - 1 do + ImGui.TableSetColumnIndex(column) + local column_name = ImGui.TableGetColumnName(column) -- Retrieve name passed to TableSetupColumn() + ImGui.PushID(column) + ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(0, 0)) + _, column_selected[column + 1] = ImGui.Checkbox("##checkall", column_selected[column + 1]) + ImGui.PopStyleVar() + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + ImGui.TableHeader(column_name) + ImGui.PopID() + end + + -- Submit table contents + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + local buf = string.format("Cell %d,%d", column, row) + ImGui.TableSetColumnIndex(column) + ImGui.Selectable(buf, column_selected[column + 1]) + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + -- Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Angled headers") then + IMGUI_DEMO_MARKER("Tables/Angled headers") + local column_names = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" } -- 1-based + local columns_count = #column_names + local rows_count = 12 + + local s = s.AngledHeaders + -- static bool bools[columns_count * rows_count] = {} -- Dummy storage selection storage + local bools = s.bools -- 1-based + if #bools == 0 then + for n = 1, columns_count * rows_count do bools[n] = false end + end + _, s.table_flags = ImGui.CheckboxFlags("_ScrollX", s.table_flags, 16777216 --[[ImGuiTableFlags.ScrollX]]) + _, s.table_flags = ImGui.CheckboxFlags("_ScrollY", s.table_flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + _, s.table_flags = ImGui.CheckboxFlags("_Resizable", s.table_flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.table_flags = ImGui.CheckboxFlags("_Sortable", s.table_flags, 8 --[[ImGuiTableFlags.Sortable]]) + _, s.table_flags = ImGui.CheckboxFlags("_NoBordersInBody", s.table_flags, 2048 --[[ImGuiTableFlags.NoBordersInBody]]) + _, s.table_flags = ImGui.CheckboxFlags("_HighlightHoveredColumn", s.table_flags, 268435456 --[[ImGuiTableFlags.HighlightHoveredColumn]]) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.frozen_cols = ImGui.SliderInt("Frozen columns", s.frozen_cols, 0, 2) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.frozen_rows = ImGui.SliderInt("Frozen rows", s.frozen_rows, 0, 2) + _, s.column_flags = ImGui.CheckboxFlags("Disable header contributing to column width", s.column_flags, 8192 --[[ImGuiTableColumnFlags.NoHeaderWidth]]) + + if ImGui.TreeNode("Style settings") then + ImGui.SameLine() + HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.") + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + ImGui.GetStyle().TableAngledHeadersAngle = ImGui.SliderAngle("style.TableAngledHeadersAngle", ImGui.GetStyle().TableAngledHeadersAngle, -50.0, 50.0) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + ImGui.SliderFloat2("style.TableAngledHeadersTextAlign", ImGui.GetStyle().TableAngledHeadersTextAlign, 0.0, 1.0, "%.2f") + ImGui.TreePop() + end + + if ImGui.BeginTable("table_angled_headers", columns_count, s.table_flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 12)) then + ImGui.TableSetupColumn(column_names[1], bit32.bor(128 --[[ImGuiTableColumnFlags.NoHide]], 64 --[[ImGuiTableColumnFlags.NoReorder]])) + for n = 1, columns_count - 1 do + ImGui.TableSetupColumn(column_names[n + 1], s.column_flags) + end + ImGui.TableSetupScrollFreeze(s.frozen_cols, s.frozen_rows) + + ImGui.TableAngledHeadersRow() -- Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag. + ImGui.TableHeadersRow() -- Draw remaining headers and allow access to context-menu and other functions. + for row = 0, rows_count - 1 do + ImGui.PushID(row) + ImGui.TableNextRow() + ImGui.TableSetColumnIndex(0) + ImGui.AlignTextToFramePadding() + ImGui.Text("Track %d", row) + for column = 1, columns_count - 1 do + if ImGui.TableSetColumnIndex(column) then + ImGui.PushID(column) + _, bools[row * columns_count + column + 1] = ImGui.Checkbox("", bools[row * columns_count + column + 1]) + ImGui.PopID() + end + end + ImGui.PopID() + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + -- Demonstrate creating custom context menus inside columns, + -- while playing it nice with context menus provided by TableHeadersRow()/TableHeader() + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Context menus") then + IMGUI_DEMO_MARKER("Tables/Context menus") + HelpMarker( + "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n" .. + "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.") + local s = s.ContextMenus + + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags1, 32 --[[ImGuiTableFlags.ContextMenuInBody]]) + PopStyleCompact() + + -- Context Menus: first example + -- [1.1] Right-click on the TableHeadersRow() line to open the default table context menu. + -- [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set) + local COLUMNS_COUNT = 3 + if ImGui.BeginTable("table_context_menu", COLUMNS_COUNT, s.flags1) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + + -- [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu. + ImGui.TableHeadersRow() + + -- Submit dummy contents + for row = 0, 4 - 1 do + ImGui.TableNextRow() + for column = 0, COLUMNS_COUNT - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + + -- Context Menus: second example + -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. + -- [2.2] Right-click on the ".." to open a custom popup + -- [2.3] Right-click in columns to open another custom popup + HelpMarker( + "Demonstrate mixing table context menu (over header), item context button (over button) " .. + "and custom per-column context menu (over column body).") + local flags2 = bit32.bor(1 --[[ImGuiTableFlags.Resizable]], 8192 --[[ImGuiTableFlags.SizingFixedFit]], 2 --[[ImGuiTableFlags.Reorderable]], 4 --[[ImGuiTableFlags.Hideable]], 1920 --[[ImGuiTableFlags.Borders]]) + if ImGui.BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + + -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. + ImGui.TableHeadersRow() + for row = 0, 4 - 1 do + ImGui.TableNextRow() + for column = 0, COLUMNS_COUNT - 1 do + -- Submit dummy contents + ImGui.TableSetColumnIndex(column) + ImGui.Text("Cell %d,%d", column, row) + ImGui.SameLine() + + -- [2.2] Right-click on the ".." to open a custom popup + ImGui.PushID(row * COLUMNS_COUNT + column) + ImGui.SmallButton("..") + if ImGui.BeginPopupContextItem() then + ImGui.Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row) + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.PopID() + end + end + + -- [2.3] Right-click anywhere in columns to open another custom popup + -- (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup + -- to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping) + local hovered_column = -1 + for column = 0, COLUMNS_COUNT + 1 - 1 do + ImGui.PushID(column) + if bit32.band(ImGui.TableGetColumnFlags(column), 134217728 --[[ImGuiTableColumnFlags.IsHovered]]) ~= 0 then + hovered_column = column + end + if hovered_column == column and not ImGui.IsAnyItemHovered() and ImGui.IsMouseReleased(1) then + ImGui.OpenPopup("MyPopup") + end + if ImGui.BeginPopup("MyPopup") then + if column == COLUMNS_COUNT then + ImGui.Text("This is a custom popup for unused space after the last column.") + else + ImGui.Text("This is a custom popup for Column %d", column) + end if ImGui.Button("Close") then ImGui.CloseCurrentPopup() end @@ -25046,442 +27950,434 @@ local function Tables_ContextMenus() end ImGui.PopID() end - end - -- [2.3] Right-click anywhere in columns to open another custom popup - -- (instead of testing for not IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup - -- to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping) - local hovered_column = -1 - for column = 0, COLUMNS_COUNT do - ImGui.PushID(column) - if Has(ImGui.TableGetColumnFlags(column), 134217728 --[[ImGuiTableColumnFlags.IsHovered]]) then - hovered_column = column - end - if hovered_column == column and not ImGui.IsAnyItemHovered() and ImGui.IsMouseReleased(1) then - ImGui.OpenPopup("MyPopup") - end - if ImGui.BeginPopup("MyPopup") then - if column == COLUMNS_COUNT then - ImGui.Text("This is a custom popup for unused space after the last column.") - else - ImGui.Text("This is a custom popup for Column %d", column) - end - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - ImGui.PopID() + ImGui.EndTable() + ImGui.Text("Hovered column: %d", hovered_column) end - - ImGui.EndTable() - ImGui.Text("Hovered column: %d", hovered_column) + ImGui.TreePop() end -end --- Demonstrate creating multiple tables with the same ID -local function Tables_SyncedInstances() - IMGUI_DEMO_MARKER("Tables/Synced instances") - DemoHelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.") + -- Demonstrate creating multiple tables with the same ID + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Synced instances") then + IMGUI_DEMO_MARKER("Tables/Synced instances") + HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.") - local s = ST.synced - if s == nil then s = { flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Borders, TF.SizingFixedFit, TF.NoSavedSettings) }; ST.synced = s end - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SizingFixedFit", s.flags, TF.SizingFixedFit) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, TF.HighlightHoveredColumn) - for n = 0, 2 do - local buf = string.format("Synced Table %d", n) - local open = ImGui.CollapsingHeader(buf, 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) - if open and ImGui.BeginTable("Table", 3, s.flags, ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 5)) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") + local s = s.SyncedInstances + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SizingFixedFit", s.flags, 8192 --[[ImGuiTableFlags.SizingFixedFit]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, 268435456 --[[ImGuiTableFlags.HighlightHoveredColumn]]) + for n = 0, 3 - 1 do + local buf = string.format("Synced Table %d", n) + local open = ImGui.CollapsingHeader(buf, 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) + if open and ImGui.BeginTable("Table", 3, s.flags, ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 5)) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + local cell_count = (n == 1) and 27 or 9 -- Make second table have a scrollbar to verify that additional decoration is not affecting column positions. + for cell = 0, cell_count - 1 do + ImGui.TableNextColumn() + ImGui.Text("this cell %d", cell) + end + ImGui.EndTable() + end + end + ImGui.TreePop() + end + + -- Demonstrate using Sorting facilities + -- This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting. + -- Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified) + local template_items_names = s.template_items_names -- 1-based + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Sorting") then + IMGUI_DEMO_MARKER("Tables/Sorting") + local s = s.Sorting + -- Create item list + local items = s.items + if items.Size == 0 then + items:resize(50) + for n = 0, items.Size - 1 do + local template_n = n % #template_items_names + local item = MyItem(); items.Data[n + 1] = item -- [Port] resize(50, MyItem()) would share one table + item.ID = n + item.Name = template_items_names[template_n + 1] + item.Quantity = (n * n - n) % 20 -- Assign default quantities + end + end + + -- Options + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, 67108864 --[[ImGuiTableFlags.SortMulti]]) + ImGui.SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, 134217728 --[[ImGuiTableFlags.SortTristate]]) + ImGui.SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") + PopStyleCompact() + + if ImGui.BeginTable("table_sorting", 4, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 15), 0.0) then + -- Declare columns + -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. + -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! + -- Demonstrate using a mixture of flags among available sort-related flags: + -- - ImGuiTableColumnFlags_DefaultSort + -- - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending + -- - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending + ImGui.TableSetupColumn("ID", bit32.bor(4 --[[ImGuiTableColumnFlags.DefaultSort]], 16 --[[ImGuiTableColumnFlags.WidthFixed]]), 0.0, MyItemColumnID_ID) + ImGui.TableSetupColumn("Name", 16 --[[ImGuiTableColumnFlags.WidthFixed]], 0.0, MyItemColumnID_Name) + ImGui.TableSetupColumn("Action", bit32.bor(512 --[[ImGuiTableColumnFlags.NoSort]], 16 --[[ImGuiTableColumnFlags.WidthFixed]]), 0.0, MyItemColumnID_Action) + ImGui.TableSetupColumn("Quantity", bit32.bor(32768 --[[ImGuiTableColumnFlags.PreferSortDescending]], 8 --[[ImGuiTableColumnFlags.WidthStretch]]), 0.0, MyItemColumnID_Quantity) + ImGui.TableSetupScrollFreeze(0, 1) -- Make row always visible ImGui.TableHeadersRow() - local cell_count = (n == 1) and 27 or 9 -- Make second table have a scrollbar to verify that additional decoration is not affecting column positions. - for cell = 0, cell_count - 1 do - ImGui.TableNextColumn() - ImGui.Text("this cell %d", cell) + + -- Sort our data if sort specs have been changed! + local sort_specs = ImGui.TableGetSortSpecs() + if sort_specs then + if sort_specs.SpecsDirty then + MyItem_SortWithSortSpecs(sort_specs, items.Data, items.Size) + sort_specs.SpecsDirty = false + end + end + + -- Demonstrate using clipper for large vertical lists + local clipper = ImGuiListClipper() + clipper:Begin(items.Size) + while clipper:Step() do + for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do + -- Display a data item + local item = items.Data[row_n + 1] + ImGui.PushID(item.ID) + ImGui.TableNextRow() + ImGui.TableNextColumn() + ImGui.Text("%04d", item.ID) + ImGui.TableNextColumn() + ImGui.TextUnformatted(item.Name) + ImGui.TableNextColumn() + ImGui.SmallButton("None") + ImGui.TableNextColumn() + ImGui.Text("%d", item.Quantity) + ImGui.PopID() + end end ImGui.EndTable() end + ImGui.TreePop() end -end --- Demonstrate using Sorting facilities --- This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting. --- Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified) -local template_items_names = { - "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango", - "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot" -} - -local function Tables_Sorting() - IMGUI_DEMO_MARKER("Tables/Sorting") - -- Create item list - local s = ST.sorting - if s == nil then - s = { items = {}, - flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Sortable, TF.SortMulti, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.NoBordersInBody, TF.ScrollY) } - for n = 0, 49 do - local template_n = n % #template_items_names - s.items[n + 1] = MyItem(n, template_items_names[template_n + 1], (n * n - n) % 20) -- Assign default quantities - end - ST.sorting = s + -- In this example we'll expose most table flags and settings. + -- For specific flags and settings refer to the corresponding section for more detailed explanation. + -- This section is mostly useful to experiment with combining certain flags or settings with each others. + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) -- [DEBUG] + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) end - local items = s.items + if ImGui.TreeNode("Advanced") then + IMGUI_DEMO_MARKER("Tables/Advanced") + local s = s.Advanced - -- Options - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, TF.SortMulti) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, TF.SortTristate) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") - PopStyleCompact() + local CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow = 0, 1, 2, 3, 4, 5 -- enum ContentsType + local contents_type_names = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" } + if s.outer_size_value == nil then s.outer_size_value = ImVec2(0.0, TEXT_BASE_HEIGHT * 12) end + -- static float row_min_height = 0.0f -- Auto + -- static float inner_width_with_scroll = 0.0f -- Auto-extend + --static ImGuiTextFilter filter + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) -- FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing + if ImGui.TreeNode("Options") then + -- Make the UI compact because there are so many fields + PushStyleCompact() + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 28.0) - if ImGui.BeginTable("table_sorting", 4, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 15), 0.0) then - local CF = ImGuiTableColumnFlags - -- Declare columns - -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. - -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! - -- Demonstrate using a mixture of flags among available sort-related flags: - -- - ImGuiTableColumnFlags_DefaultSort - -- - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending - -- - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending - ImGui.TableSetupColumn("ID", bor(CF.DefaultSort, CF.WidthFixed), 0.0, MyItemColumnID_ID) - ImGui.TableSetupColumn("Name", CF.WidthFixed, 0.0, MyItemColumnID_Name) - ImGui.TableSetupColumn("Action", bor(CF.NoSort, CF.WidthFixed), 0.0, MyItemColumnID_Action) - ImGui.TableSetupColumn("Quantity", bor(CF.PreferSortDescending, CF.WidthStretch), 0.0, MyItemColumnID_Quantity) - ImGui.TableSetupScrollFreeze(0, 1) -- Make row always visible - ImGui.TableHeadersRow() + if ImGui.TreeNodeEx("Features:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, 2 --[[ImGuiTableFlags.Reorderable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, 4 --[[ImGuiTableFlags.Hideable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Sortable", s.flags, 8 --[[ImGuiTableFlags.Sortable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoSavedSettings", s.flags, 16 --[[ImGuiTableFlags.NoSavedSettings]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags, 32 --[[ImGuiTableFlags.ContextMenuInBody]]) + ImGui.TreePop() + end - -- Sort our data if sort specs have been changed! - local sort_specs = ImGui.TableGetSortSpecs() - if sort_specs and sort_specs.SpecsDirty then - MyItem_SortWithSortSpecs(sort_specs, items, #items) - sort_specs.SpecsDirty = false + if ImGui.TreeNodeEx("Decorations:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, 64 --[[ImGuiTableFlags.RowBg]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, 1536 --[[ImGuiTableFlags.BordersV]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, 1024 --[[ImGuiTableFlags.BordersOuterV]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, 512 --[[ImGuiTableFlags.BordersInnerV]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, 384 --[[ImGuiTableFlags.BordersH]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, 256 --[[ImGuiTableFlags.BordersOuterH]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, 128 --[[ImGuiTableFlags.BordersInnerH]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, 2048 --[[ImGuiTableFlags.NoBordersInBody]]); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, 4096 --[[ImGuiTableFlags.NoBordersInBodyUntilResize]]); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Sizing:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + s.flags = EditTableSizingFlags(s.flags) + ImGui.SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, 65536 --[[ImGuiTableFlags.NoHostExtendX]]) + ImGui.SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, 131072 --[[ImGuiTableFlags.NoHostExtendY]]) + ImGui.SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags, 262144 --[[ImGuiTableFlags.NoKeepColumnsVisible]]) + ImGui.SameLine(); HelpMarker("Only available if ScrollX is disabled.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, 524288 --[[ImGuiTableFlags.PreciseWidths]]) + ImGui.SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, 1048576 --[[ImGuiTableFlags.NoClip]]) + ImGui.SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Padding:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags, 2097152 --[[ImGuiTableFlags.PadOuterX]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags, 4194304 --[[ImGuiTableFlags.NoPadOuterX]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags, 8388608 --[[ImGuiTableFlags.NoPadInnerX]]) + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Scrolling:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, 16777216 --[[ImGuiTableFlags.ScrollX]]) + ImGui.SameLine() + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + ImGui.SameLine() + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Sorting:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, 67108864 --[[ImGuiTableFlags.SortMulti]]) + ImGui.SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, 134217728 --[[ImGuiTableFlags.SortTristate]]) + ImGui.SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Headers:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, 268435456 --[[ImGuiTableFlags.HighlightHoveredColumn]]) + _, s.columns_base_flags = ImGui.CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", s.columns_base_flags, 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) + ImGui.SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Other:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.show_wrapped_text = ImGui.Checkbox("show_wrapped_text", s.show_wrapped_text) + + ImGui.DragFloat2("##OuterSize", s.outer_size_value) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + _, s.outer_size_enabled = ImGui.Checkbox("outer_size", s.outer_size_enabled) + ImGui.SameLine() + HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n" .. + "- The table is output directly in the parent window.\n" .. + "- OuterSize.x < 0.0f will right-align the table.\n" .. + "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n" .. + "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).") + + -- From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling. + -- To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled. + s.inner_width_with_scroll = ImGui.DragFloat("inner_width (when ScrollX active)", s.inner_width_with_scroll, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]]) + + s.row_min_height = ImGui.DragFloat("row_min_height", s.row_min_height, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]]) + ImGui.SameLine(); HelpMarker("Specify height of the Selectable item.") + + s.items_count = ImGui.DragInt("items_count", s.items_count, 0.1, 0, 9999) + s.contents_type = ImGui.Combo("items_type (first column)", s.contents_type, contents_type_names, #contents_type_names) + --filter.Draw("filter") + ImGui.TreePop() + end + + ImGui.PopItemWidth() + PopStyleCompact() + ImGui.Spacing() + ImGui.TreePop() end - -- Demonstrate using clipper for large vertical lists - local clipper = ImGuiListClipper() - clipper:Begin(#items) - while clipper:Step() do - for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do - -- Display a data item - local item = items[row_n + 1] - ImGui.PushID(item.ID) - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.Text("%04d", item.ID) - ImGui.TableNextColumn() - ImGui.TextUnformatted(item.Name) - ImGui.TableNextColumn() - ImGui.SmallButton("None") - ImGui.TableNextColumn() - ImGui.Text("%d", item.Quantity) - ImGui.PopID() + -- Update item list if we changed the number of items + local items = s.items + local selection = s.selection + if items.Size ~= s.items_count then + items:resize(s.items_count) + for n = 0, s.items_count - 1 do + local template_n = n % #template_items_names + local item = items.Data[n + 1] + if item == nil then item = MyItem(); items.Data[n + 1] = item end -- [Port] resize(n, MyItem()) would share one table + item.ID = n + item.Name = template_items_names[template_n + 1] + item.Quantity = (template_n == 3) and 10 or (template_n == 4) and 20 or 0 -- Assign default quantities end end - ImGui.EndTable() - end -end -local function Tables_AdvancedOptions(s) - -- Make the UI compact because there are so many fields - PushStyleCompact() - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 28.0) + local parent_draw_list = ImGui.GetWindowDrawList() + local parent_draw_list_draw_cmd_count = parent_draw_list.CmdBuffer.Size + local table_scroll_cur, table_scroll_max -- For debug display + local table_draw_list = nil -- " - if ImGui.TreeNodeEx("Features:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, TF.Reorderable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, TF.Hideable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Sortable", s.flags, TF.Sortable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoSavedSettings", s.flags, TF.NoSavedSettings) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags, TF.ContextMenuInBody) - ImGui.TreePop() - end + -- Submit table + local flags = s.flags + local columns_base_flags = s.columns_base_flags + local inner_width_to_use = (bit32.band(flags, 16777216 --[[ImGuiTableFlags.ScrollX]]) ~= 0) and s.inner_width_with_scroll or 0.0 + if ImGui.BeginTable("table_advanced", 6, flags, s.outer_size_enabled and s.outer_size_value or ImVec2(0, 0), inner_width_to_use) then + -- Declare columns + -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. + -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! + ImGui.TableSetupColumn("ID", bit32.bor(columns_base_flags, 4 --[[ImGuiTableColumnFlags.DefaultSort]], 16 --[[ImGuiTableColumnFlags.WidthFixed]], 128 --[[ImGuiTableColumnFlags.NoHide]]), 0.0, MyItemColumnID_ID) + ImGui.TableSetupColumn("Name", bit32.bor(columns_base_flags, 16 --[[ImGuiTableColumnFlags.WidthFixed]]), 0.0, MyItemColumnID_Name) + ImGui.TableSetupColumn("Action", bit32.bor(columns_base_flags, 512 --[[ImGuiTableColumnFlags.NoSort]], 16 --[[ImGuiTableColumnFlags.WidthFixed]]), 0.0, MyItemColumnID_Action) + ImGui.TableSetupColumn("Quantity", bit32.bor(columns_base_flags, 32768 --[[ImGuiTableColumnFlags.PreferSortDescending]]), 0.0, MyItemColumnID_Quantity) + ImGui.TableSetupColumn("Description", bit32.bor(columns_base_flags, (bit32.band(flags, 65536 --[[ImGuiTableFlags.NoHostExtendX]]) ~= 0) and 0 or 8 --[[ImGuiTableColumnFlags.WidthStretch]]), 0.0, MyItemColumnID_Description) + ImGui.TableSetupColumn("Hidden", bit32.bor(columns_base_flags, 2 --[[ImGuiTableColumnFlags.DefaultHide]], 512 --[[ImGuiTableColumnFlags.NoSort]])) + ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) - if ImGui.TreeNodeEx("Decorations:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, TF.RowBg) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, TF.BordersV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, TF.BordersOuterV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, TF.BordersInnerV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, TF.BordersH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, TF.BordersOuterH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, TF.BordersInnerH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, TF.NoBordersInBody); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, TF.NoBordersInBodyUntilResize); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") - ImGui.TreePop() - end + -- Sort our data if sort specs have been changed! + local sort_specs = ImGui.TableGetSortSpecs() + if sort_specs and sort_specs.SpecsDirty then + s.items_need_sort = true + end + if sort_specs and s.items_need_sort and items.Size > 1 then + MyItem_SortWithSortSpecs(sort_specs, items.Data, items.Size) + sort_specs.SpecsDirty = false + end + s.items_need_sort = false - if ImGui.TreeNodeEx("Sizing:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - s.flags = EditTableSizingFlags(s.flags) - ImGui.SameLine(); DemoHelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, TF.NoHostExtendX) - ImGui.SameLine(); DemoHelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, TF.NoHostExtendY) - ImGui.SameLine(); DemoHelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags, TF.NoKeepColumnsVisible) - ImGui.SameLine(); DemoHelpMarker("Only available if ScrollX is disabled.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, TF.PreciseWidths) - ImGui.SameLine(); DemoHelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, TF.NoClip) - ImGui.SameLine(); DemoHelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.") - ImGui.TreePop() - end + -- Take note of whether we are currently sorting based on the Quantity field, + -- we will use this to trigger sorting when we know the data of this column has been modified. + local sorts_specs_using_quantity = bit32.band(ImGui.TableGetColumnFlags(3), 67108864 --[[ImGuiTableColumnFlags.IsSorted]]) ~= 0 - if ImGui.TreeNodeEx("Padding:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags, TF.PadOuterX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags, TF.NoPadOuterX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags, TF.NoPadInnerX) - ImGui.TreePop() - end + -- Show headers + if s.show_headers and bit32.band(columns_base_flags, 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) ~= 0 then + ImGui.TableAngledHeadersRow() + end + if s.show_headers then + ImGui.TableHeadersRow() + end - if ImGui.TreeNodeEx("Scrolling:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, TF.ScrollX) - ImGui.SameLine() - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - ImGui.SameLine() - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) - ImGui.TreePop() - end + -- Show data + -- FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here? + -- Demonstrate using clipper for large vertical lists + local clipper = ImGuiListClipper() + clipper:Begin(items.Size) + while clipper:Step() do + for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do + local item = items.Data[row_n + 1] + --if not filter:PassFilter(item.Name) then + -- continue - if ImGui.TreeNodeEx("Sorting:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, TF.SortMulti) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, TF.SortTristate) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") - ImGui.TreePop() - end + local item_is_selected = selection:contains(item.ID) + ImGui.PushID(item.ID) + ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], s.row_min_height) - if ImGui.TreeNodeEx("Headers:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, TF.HighlightHoveredColumn) - _, s.columns_base_flags = ImGui.CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", s.columns_base_flags, 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) - ImGui.SameLine(); DemoHelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).") - ImGui.TreePop() - end - - if ImGui.TreeNodeEx("Other:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.show_wrapped_text = ImGui.Checkbox("show_wrapped_text", s.show_wrapped_text) - - ImGui.DragFloat2("##OuterSize", s.outer_size_value) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - _, s.outer_size_enabled = ImGui.Checkbox("outer_size", s.outer_size_enabled) - ImGui.SameLine() - DemoHelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n" .. - "- The table is output directly in the parent window.\n" .. - "- OuterSize.x < 0.0f will right-align the table.\n" .. - "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n" .. - "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).") - - -- From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling. - -- To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled. - s.inner_width_with_scroll = ImGui.DragFloat("inner_width (when ScrollX active)", s.inner_width_with_scroll, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]]) - - s.row_min_height = ImGui.DragFloat("row_min_height", s.row_min_height, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]]) - ImGui.SameLine(); DemoHelpMarker("Specify height of the Selectable item.") - - s.items_count = ImGui.DragInt("items_count", s.items_count, 0.1, 0, 9999) - local contents_type_names = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" } - if ImGui.Combo then - s.contents_type = ImGui.Combo("items_type (first column)", s.contents_type, contents_type_names, #contents_type_names) - else - NotPorted("Combo") - end - ImGui.TreePop() - end - - ImGui.PopItemWidth() - PopStyleCompact() - ImGui.Spacing() -end - --- In this example we'll expose most table flags and settings. --- For specific flags and settings refer to the corresponding section for more detailed explanation. --- This section is mostly useful to experiment with combining certain flags or settings with each others. -local function Tables_Advanced() - IMGUI_DEMO_MARKER("Tables/Advanced") - local CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow = 0, 1, 2, 3, 4, 5 - local s = ST.advanced - if s == nil then - s = { flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Sortable, TF.SortMulti, TF.RowBg, TF.Borders, TF.NoBordersInBody, TF.ScrollX, TF.ScrollY, TF.SizingFixedFit), - columns_base_flags = 0 --[[ImGuiTableColumnFlags.None]], contents_type = CT_SelectableSpanRow, - freeze_cols = 1, freeze_rows = 1, items_count = #template_items_names * 2, - outer_size_value = ImVec2(0.0, TEXT_BASE_HEIGHT * 12), row_min_height = 0.0, inner_width_with_scroll = 0.0, - outer_size_enabled = true, show_headers = true, show_wrapped_text = false, - items = {}, selection = {}, items_need_sort = false, show_debug_details = false } - ST.advanced = s - end - --ImGui.SetNextItemOpen(true, ImGuiCond.Once) -- FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing - if ImGui.TreeNode("Options") then - Tables_AdvancedOptions(s) - ImGui.TreePop() - end - - -- Update item list if we changed the number of items - local items = s.items - local selection = s.selection - if #items ~= s.items_count then - for n = #items, s.items_count + 1, -1 do items[n] = nil end - for n = 0, s.items_count - 1 do - local template_n = n % #template_items_names - items[n + 1] = MyItem(n, template_items_names[template_n + 1], (template_n == 3) and 10 or (template_n == 4) and 20 or 0) -- Assign default quantities - end - end - - local parent_draw_list = ImGui.GetWindowDrawList() - local parent_draw_list_draw_cmd_count = parent_draw_list.CmdBuffer.Size - local table_scroll_cur, table_scroll_max -- For debug display - local table_draw_list = nil -- " - - -- Submit table - local flags = s.flags - local columns_base_flags = s.columns_base_flags - local inner_width_to_use = Has(flags, TF.ScrollX) and s.inner_width_with_scroll or 0.0 - local CF = ImGuiTableColumnFlags - if ImGui.BeginTable("table_advanced", 6, flags, s.outer_size_enabled and s.outer_size_value or ImVec2(0, 0), inner_width_to_use) then - -- Declare columns - -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. - -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! - ImGui.TableSetupColumn("ID", bor(columns_base_flags, CF.DefaultSort, CF.WidthFixed, CF.NoHide), 0.0, MyItemColumnID_ID) - ImGui.TableSetupColumn("Name", bor(columns_base_flags, CF.WidthFixed), 0.0, MyItemColumnID_Name) - ImGui.TableSetupColumn("Action", bor(columns_base_flags, CF.NoSort, CF.WidthFixed), 0.0, MyItemColumnID_Action) - ImGui.TableSetupColumn("Quantity", bor(columns_base_flags, CF.PreferSortDescending), 0.0, MyItemColumnID_Quantity) - ImGui.TableSetupColumn("Description", bor(columns_base_flags, Has(flags, TF.NoHostExtendX) and 0 or CF.WidthStretch), 0.0, MyItemColumnID_Description) - ImGui.TableSetupColumn("Hidden", bor(columns_base_flags, CF.DefaultHide, CF.NoSort)) - ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) - - -- Sort our data if sort specs have been changed! - local sort_specs = ImGui.TableGetSortSpecs() - if sort_specs and sort_specs.SpecsDirty then - s.items_need_sort = true - end - if sort_specs and s.items_need_sort and #items > 1 then - MyItem_SortWithSortSpecs(sort_specs, items, #items) - sort_specs.SpecsDirty = false - end - s.items_need_sort = false - - -- Take note of whether we are currently sorting based on the Quantity field, - -- we will use this to trigger sorting when we know the data of this column has been modified. - local sorts_specs_using_quantity = Has(ImGui.TableGetColumnFlags(3), CF.IsSorted) - - -- Show headers - if s.show_headers and Has(columns_base_flags, CF.AngledHeader) then - ImGui.TableAngledHeadersRow() - end - if s.show_headers then - ImGui.TableHeadersRow() - end - - -- Show data - -- FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here? - -- Demonstrate using clipper for large vertical lists - local clipper = ImGuiListClipper() - clipper:Begin(#items) - while clipper:Step() do - for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do - local item = items[row_n + 1] - - local item_is_selected = table.find(selection, item.ID) ~= nil - ImGui.PushID(item.ID) - ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], s.row_min_height) - - -- For the demo purpose we can select among different type of items submitted in the first column - ImGui.TableSetColumnIndex(0) - local label = string.format("%04d", item.ID) - local ct = s.contents_type - if ct == CT_Text then - ImGui.TextUnformatted(label) - elseif ct == CT_Button then - ImGui.Button(label) - elseif ct == CT_SmallButton then - ImGui.SmallButton(label) - elseif ct == CT_FillButton then - ImGui.Button(label, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) - elseif ct == CT_Selectable or ct == CT_SelectableSpanRow then - local selectable_flags = (ct == CT_SelectableSpanRow) and bor(2 --[[ImGuiSelectableFlags.SpanAllColumns]], 16 --[[ImGuiSelectableFlags.AllowOverlap]]) or 0 --[[ImGuiSelectableFlags.None]] - if ImGui.Selectable(label, item_is_selected, selectable_flags, ImVec2(0, s.row_min_height)) then - if ImGui.GetIO().KeyCtrl then - if item_is_selected then - table.remove(selection, table.find(selection, item.ID)) + -- For the demo purpose we can select among different type of items submitted in the first column + ImGui.TableSetColumnIndex(0) + local label = string.format("%04d", item.ID) + local contents_type = s.contents_type + if contents_type == CT_Text then + ImGui.TextUnformatted(label) + elseif contents_type == CT_Button then + ImGui.Button(label) + elseif contents_type == CT_SmallButton then + ImGui.SmallButton(label) + elseif contents_type == CT_FillButton then + ImGui.Button(label, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + elseif contents_type == CT_Selectable or contents_type == CT_SelectableSpanRow then + local selectable_flags = (contents_type == CT_SelectableSpanRow) and bit32.bor(2 --[[ImGuiSelectableFlags.SpanAllColumns]], 16 --[[ImGuiSelectableFlags.AllowOverlap]]) or 0 --[[ImGuiSelectableFlags.None]] + if ImGui.Selectable(label, item_is_selected, selectable_flags, ImVec2(0, s.row_min_height)) then + if ImGui.GetIO().KeyCtrl then + if item_is_selected then + selection:find_erase_unsorted(item.ID) + else + selection:push_back(item.ID) + end else - table.insert(selection, item.ID) + selection:clear() + selection:push_back(item.ID) end - else - table.clear(selection) - table.insert(selection, item.ID) end end - end - if ImGui.TableSetColumnIndex(1) then - ImGui.TextUnformatted(item.Name) - end + if ImGui.TableSetColumnIndex(1) then + ImGui.TextUnformatted(item.Name) + end - -- Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity, - -- and we are currently sorting on the column showing the Quantity. - -- To avoid triggering a sort while holding the button, we only trigger it when the button has been released. - -- You will probably need some extra logic if you want to automatically sort when a specific entry changes. - if ImGui.TableSetColumnIndex(2) then - if ImGui.SmallButton("Chop") then item.Quantity = item.Quantity + 1 end - if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end - ImGui.SameLine() - if ImGui.SmallButton("Eat") then item.Quantity = item.Quantity - 1 end - if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end - end + -- Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity, + -- and we are currently sorting on the column showing the Quantity. + -- To avoid triggering a sort while holding the button, we only trigger it when the button has been released. + -- You will probably need some extra logic if you want to automatically sort when a specific entry changes. + if ImGui.TableSetColumnIndex(2) then + if ImGui.SmallButton("Chop") then item.Quantity = item.Quantity + 1 end + if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end + ImGui.SameLine() + if ImGui.SmallButton("Eat") then item.Quantity = item.Quantity - 1 end + if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end + end - if ImGui.TableSetColumnIndex(3) then - ImGui.Text("%d", item.Quantity) - end + if ImGui.TableSetColumnIndex(3) then + ImGui.Text("%d", item.Quantity) + end - ImGui.TableSetColumnIndex(4) - if s.show_wrapped_text then - ImGui.TextWrapped("Lorem ipsum dolor sit amet") - else - ImGui.Text("Lorem ipsum dolor sit amet") - end + ImGui.TableSetColumnIndex(4) + if s.show_wrapped_text then + ImGui.TextWrapped("Lorem ipsum dolor sit amet") + else + ImGui.Text("Lorem ipsum dolor sit amet") + end - if ImGui.TableSetColumnIndex(5) then - ImGui.Text("1234") - end + if ImGui.TableSetColumnIndex(5) then + ImGui.Text("1234") + end - ImGui.PopID() + ImGui.PopID() + end + end + + -- Store some info to display debug details below + table_scroll_cur = ImVec2(ImGui.GetScrollX(), ImGui.GetScrollY()) + table_scroll_max = ImVec2(ImGui.GetScrollMaxX(), ImGui.GetScrollMaxY()) + table_draw_list = ImGui.GetWindowDrawList() + ImGui.EndTable() + end + _, s.show_debug_details = ImGui.Checkbox("Debug details", s.show_debug_details) + if s.show_debug_details and table_draw_list then + ImGui.SameLine(0.0, 0.0) + local table_draw_list_draw_cmd_count = table_draw_list.CmdBuffer.Size + if table_draw_list == parent_draw_list then + ImGui.Text(": DrawCmd: +%d (in same window)", + table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count) + else + ImGui.Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", + table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y) end end - - -- Store some info to display debug details below - table_scroll_cur = ImVec2(ImGui.GetScrollX(), ImGui.GetScrollY()) - table_scroll_max = ImVec2(ImGui.GetScrollMaxX(), ImGui.GetScrollMaxY()) - table_draw_list = ImGui.GetWindowDrawList() - ImGui.EndTable() + ImGui.TreePop() end - _, s.show_debug_details = ImGui.Checkbox("Debug details", s.show_debug_details) - if s.show_debug_details and table_draw_list then - ImGui.SameLine(0.0, 0.0) - local table_draw_list_draw_cmd_count = table_draw_list.CmdBuffer.Size - if table_draw_list == parent_draw_list then - ImGui.Text(": DrawCmd: +%d (in same window)", - table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count) - else - ImGui.Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", - table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y) - end + + ImGui.PopID() + + DemoWindowColumns() + + if s.disable_indent then + ImGui.PopStyleVar() end end -local DCS = { selected = -1, h_borders = true, v_borders = true, columns_count = 4, foo = 1.0, bar = 1.0 } - --- Demonstrate old/legacy Columns API! --- [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!] -local function DemoWindowColumns() +S.DemoWindowColumns = { + selected = -1, + h_borders = true, + v_borders = true, + columns_count = 4, + foo = 1.0, + bar = 1.0, +} +function DemoWindowColumns() + local s = S.DemoWindowColumns local open = ImGui.TreeNode("Legacy Columns API") ImGui.SameLine() - DemoHelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!") + HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!") if not open then return end @@ -25490,12 +28386,12 @@ local function DemoWindowColumns() if ImGui.TreeNode("Basic") then IMGUI_DEMO_MARKER("Columns (legacy API)/Basic") ImGui.Text("Without border:") - ImGui.Columns(3, "mycolumns3", false) -- 3-ways, no border + ImGui.Columns(3, "mycolumns3", false) -- 3-ways, no border ImGui.Separator() for n = 0, 13 do local label = string.format("Item %d", n) if ImGui.Selectable(label) then end - --if ImGui.Button(label, ImVec2(-FLT_MIN,0.0)) then end + --if (ImGui.Button(label, ImVec2(-FLT_MIN,0.0))) {} ImGui.NextColumn() end ImGui.Columns(1) @@ -25513,8 +28409,8 @@ local function DemoWindowColumns() local paths = { "/path/one", "/path/two", "/path/three" } for i = 0, 2 do local label = string.format("%04d", i) - if ImGui.Selectable(label, DCS.selected == i, 2 --[[ImGuiSelectableFlags.SpanAllColumns]]) then - DCS.selected = i + if ImGui.Selectable(label, s.selected == i, 2 --[[ImGuiSelectableFlags.SpanAllColumns]]) then + s.selected = i end local hovered = ImGui.IsItemHovered() ImGui.NextColumn() @@ -25532,17 +28428,17 @@ local function DemoWindowColumns() -- NB: Future columns API should allow automatic horizontal borders. local lines_count = 3 ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - DCS.columns_count = ImGui.DragInt("##columns_count", DCS.columns_count, 0.1, 2, 10, "%d columns") - if DCS.columns_count < 2 then - DCS.columns_count = 2 + s.columns_count = ImGui.DragInt("##columns_count", s.columns_count, 0.1, 2, 10, "%d columns") + if s.columns_count < 2 then + s.columns_count = 2 end ImGui.SameLine() - _, DCS.h_borders = ImGui.Checkbox("horizontal", DCS.h_borders) + _, s.h_borders = ImGui.Checkbox("horizontal", s.h_borders) ImGui.SameLine() - _, DCS.v_borders = ImGui.Checkbox("vertical", DCS.v_borders) - ImGui.Columns(DCS.columns_count, nil, DCS.v_borders) - for i = 0, DCS.columns_count * lines_count - 1 do - if DCS.h_borders and ImGui.GetColumnIndex() == 0 then + _, s.v_borders = ImGui.Checkbox("vertical", s.v_borders) + ImGui.Columns(s.columns_count, nil, s.v_borders) + for i = 0, s.columns_count * lines_count - 1 do + if s.h_borders and ImGui.GetColumnIndex() == 0 then ImGui.Separator() end ImGui.PushID(i) @@ -25557,7 +28453,7 @@ local function DemoWindowColumns() ImGui.NextColumn() end ImGui.Columns(1) - if DCS.h_borders then + if s.h_borders then ImGui.Separator() end ImGui.TreePop() @@ -25575,13 +28471,13 @@ local function DemoWindowColumns() ImGui.Text("ImGui") ImGui.Button("Apple") - DCS.foo = ImGui.InputFloat("red", DCS.foo, 0.05, 0, "%.3f") + s.foo = ImGui.InputFloat("red", s.foo, 0.05, 0, "%.3f") ImGui.Text("An extra line here.") ImGui.NextColumn() ImGui.Text("Sailor") ImGui.Button("Corniflower") - DCS.bar = ImGui.InputFloat("blue", DCS.bar, 0.05, 0, "%.3f") + s.bar = ImGui.InputFloat("blue", s.bar, 0.05, 0, "%.3f") ImGui.NextColumn() if ImGui.CollapsingHeader("Category A") then ImGui.Text("Blah blah blah") end ImGui.NextColumn() @@ -25666,104 +28562,1045 @@ local function DemoWindowColumns() ImGui.TreePop() end -local tables_sections = { - { "Basic", Tables_Basic }, - { "Borders, background", Tables_BordersBackground }, - { "Resizable, stretch", Tables_ResizableStretch }, - { "Resizable, fixed", Tables_ResizableFixed }, - { "Resizable, mixed", Tables_ResizableMixed }, - { "Reorderable, hideable, with headers", Tables_Reorderable }, - { "Padding", Tables_Padding }, - { "Sizing policies", Tables_SizingPolicies }, - { "Vertical scrolling, with clipping", Tables_VerticalScrolling }, - { "Horizontal scrolling", Tables_HorizontalScrolling }, - { "Columns flags", Tables_ColumnsFlags }, - { "Columns widths", Tables_ColumnsWidths }, - { "Nested tables", Tables_Nested }, - { "Row height", Tables_RowHeight }, - { "Outer size", Tables_OuterSize }, - { "Background color", Tables_BackgroundColor }, - { "Tree view", Tables_TreeView }, - { "Item width", Tables_ItemWidth }, - { "Custom headers", Tables_CustomHeaders }, - { "Angled headers", Tables_AngledHeaders }, - { "Context menus", Tables_ContextMenus }, - { "Synced instances", Tables_SyncedInstances }, - { "Sorting", Tables_Sorting }, - { "Advanced", Tables_Advanced }, +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowInputs() +------------------------------------------------------------------------------- + +S.DemoWindowInputs = { + funcs = { IsLegacyNativeDupe = function(key) return false end }, -- struct funcs (hoisted to avoid a per-frame closure) -- [Port] + capture_override_mouse = -1, + capture_override_keyboard = -1, + route_options = ImGuiInputFlags.Repeat, + route_type = ImGuiInputFlags.RouteFocused, + f = 0.5, + tabbing_buf = ImGui.NewTextBuffer("hello", 32), + focus_buf = ImGui.NewTextBuffer("click on a button to set focus", 128), + f3 = { 0.0, 0.0, 0.0 }, } +S.DemoWindowInputs.mouse_cursors_names = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "Wait", "Progress", "NotAllowed" } +function DemoWindowInputs() + local s = S.DemoWindowInputs + if ImGui.CollapsingHeader("Inputs & Focus") then + local io = ImGui.GetIO() -function DemoWindowTables() - --ImGui.SetNextItemOpen(true, ImGuiCond.Once) - if not ImGui.CollapsingHeader("Tables & Columns") then - return - end + -- Display inputs submitted to ImGuiIO + ImGui.SetNextItemOpen(true, 2 --[[ImGuiCond.Once]]) + local inputs_opened = ImGui.TreeNode("Inputs") + ImGui.SameLine() + HelpMarker( + "This is a simplified view. See more detailed input state:\n" .. + "- in 'Tools->Metrics/Debugger->Inputs'.\n" .. + "- in 'Tools->Debug Log->IO'.") + if inputs_opened then + IMGUI_DEMO_MARKER("Inputs & Focus/Inputs") + if ImGui.IsMousePosValid() then + ImGui.Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y) + else + ImGui.Text("Mouse pos: ") + end + ImGui.Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y) + ImGui.Text("Mouse down:") + for i = 0, 2 do if ImGui.IsMouseDown(i) then ImGui.SameLine(); ImGui.Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]) end end -- IM_COUNTOF(io.MouseDown) == 3, 0-based + ImGui.Text("Mouse wheel: %.1f", io.MouseWheel) + ImGui.Text("Mouse clicked count:") + for i = 0, 2 do if io.MouseClickedCount[i] > 0 then ImGui.SameLine(); ImGui.Text("b%d: %d", i, io.MouseClickedCount[i]) end end - -- Using those as a base value to create width/height that are factor of the size of our font - TEXT_BASE_WIDTH = ImGui.CalcTextSize("A").x - TEXT_BASE_HEIGHT = ImGui.GetTextLineHeightWithSpacing() + -- We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows + -- displaying the data for old/new backends. + -- User code should never have to go through such hoops! + -- You can generally iterate between ImGuiKey.NamedKey_BEGIN and ImGuiKey.NamedKey_END. + local funcs = s.funcs + local start_key = 512 --[[ImGuiKey.NamedKey_BEGIN]] + ImGui.Text("Keys down:") for key = start_key, 667 --[[ImGuiKey.NamedKey_END]] - 1 do repeat if funcs.IsLegacyNativeDupe(key) or not ImGui.IsKeyDown(key) then break end ImGui.SameLine(); if key < 512 --[[ImGuiKey.NamedKey_BEGIN]] then ImGui.Text("\"%s\"", ImGui.GetKeyName(key)) else ImGui.Text("\"%s\" %d", ImGui.GetKeyName(key), key) end until true end + ImGui.Text("Keys mods: %s%s%s%s", io.KeyCtrl and "CTRL " or "", io.KeyShift and "SHIFT " or "", io.KeyAlt and "ALT " or "", io.KeySuper and "SUPER " or "") + ImGui.Text("Chars queue:") for i = 0, io.InputQueueCharacters.Size - 1 do local c = io.InputQueueCharacters.Data[i + 1]; ImGui.SameLine(); ImGui.Text("\'%s\' (0x%04X)", (c > 32 and c <= 255) and string.char(c) or '?', c) end -- FIXME: We should convert 'c' to UTF-8 here but the functions are not public. - ImGui.PushID("Tables") - - local open_action = -1 - if ImGui.Button("Expand all") then - open_action = 1 - end - ImGui.SameLine() - if ImGui.Button("Collapse all") then - open_action = 0 - end - ImGui.SameLine() - - -- Options - _, ST.disable_indent = ImGui.Checkbox("Disable tree indentation", ST.disable_indent or false) - ImGui.SameLine() - DemoHelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.") - ImGui.Separator() - local disable_indent = ST.disable_indent - if disable_indent then - ImGui.PushStyleVar(16 --[[ImGuiStyleVar.IndentSpacing]], 0.0) - end - - -- About Styling of tables - -- Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs. - -- There are however a few settings that a shared and part of the ImGuiStyle structure: - -- style.CellPadding -- Padding within each cell - -- style.Colors[ImGuiCol.TableHeaderBg] -- Table header background - -- style.Colors[ImGuiCol.TableBorderStrong] -- Table outer and header borders - -- style.Colors[ImGuiCol.TableBorderLight] -- Table inner borders - -- style.Colors[ImGuiCol.TableRowBg] -- Table row background when ImGuiTableFlags_RowBg is enabled (even rows) - -- style.Colors[ImGuiCol.TableRowBgAlt] -- Table row background when ImGuiTableFlags_RowBg is enabled (odds rows) - - -- Demos - for _, sec in ipairs(tables_sections) do - if open_action ~= -1 then - ImGui.SetNextItemOpen(open_action ~= 0) + ImGui.TreePop() end - if ImGui.TreeNode(sec[1]) then - sec[2]() + + -- Display ImGuiIO output flags + ImGui.SetNextItemOpen(true, 2 --[[ImGuiCond.Once]]) + local outputs_opened = ImGui.TreeNode("Outputs") + ImGui.SameLine() + HelpMarker( + "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui " .. + "to instruct your application of how to route inputs. Typically, when a value is true, it means " .. + "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n" .. + "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, " .. + "and underlying application should ignore mouse inputs (in practice there are many and more subtle " .. + "rules leading to how those flags are set).") + if outputs_opened then + IMGUI_DEMO_MARKER("Inputs & Focus/Outputs") + ImGui.Text("io.WantCaptureMouse: %d", io.WantCaptureMouse and 1 or 0) + ImGui.Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose and 1 or 0) + ImGui.Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard and 1 or 0) + ImGui.Text("io.WantTextInput: %d", io.WantTextInput and 1 or 0) + ImGui.Text("io.WantSetMousePos: %d", io.WantSetMousePos and 1 or 0) + ImGui.Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive and 1 or 0, io.NavVisible and 1 or 0) + + IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override") + if ImGui.TreeNode("WantCapture override") then + HelpMarker( + "Hovering the colored canvas will override io.WantCaptureXXX fields.\n" .. + "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering " .. + "and true when clicking.") + local capture_override_desc = { "None", "Set to false", "Set to true" } + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 15) + s.capture_override_mouse = ImGui.SliderInt("SetNextFrameWantCaptureMouse() on hover", s.capture_override_mouse, -1, 1, capture_override_desc[s.capture_override_mouse + 2], 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 15) + s.capture_override_keyboard = ImGui.SliderInt("SetNextFrameWantCaptureKeyboard() on hover", s.capture_override_keyboard, -1, 1, capture_override_desc[s.capture_override_keyboard + 2], 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + + ImGui.ColorButton("##panel", ImVec4(0.7, 0.1, 0.7, 1.0), bit32.bor(64 --[[ImGuiColorEditFlags.NoTooltip]], 512 --[[ImGuiColorEditFlags.NoDragDrop]]), ImVec2(128.0, 96.0)) -- Dummy item + if ImGui.IsItemHovered() and s.capture_override_mouse ~= -1 then + ImGui.SetNextFrameWantCaptureMouse(s.capture_override_mouse == 1) + end + if ImGui.IsItemHovered() and s.capture_override_keyboard ~= -1 then + ImGui.SetNextFrameWantCaptureKeyboard(s.capture_override_keyboard == 1) + end + + ImGui.TreePop() + end + ImGui.TreePop() + end + + -- Demonstrate using Shortcut() and Routing Policies. + -- The general flow is: + -- - Code interested in a chord (e.g. "Ctrl+A") declares their intent. + -- - Multiple locations may be interested in same chord! Routing helps find a winner. + -- - Every frame, we resolve all claims and assign one owner if the modifiers are matching. + -- - The lower-level function is 'bool SetShortcutRouting()', returns true when caller got the route. + -- - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing flags. + -- - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags.RouteFocused. + -- TL;DR: Most uses will simply be: + -- - Shortcut(ImGuiMod_Ctrl | ImGuiKey.A); -- Use ImGuiInputFlags.RouteFocused policy. + if ImGui.TreeNode("Shortcuts") then + IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts") + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_Repeat", s.route_options, 1 --[[ImGuiInputFlags.Repeat]]) + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteActive", s.route_type, 1024 --[[ImGuiInputFlags.RouteActive]]) + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteFocused (default)", s.route_type, 2048 --[[ImGuiInputFlags.RouteFocused]]) + ImGui.Indent() + ImGui.BeginDisabled(s.route_type ~= 2048 --[[ImGuiInputFlags.RouteFocused]]) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteOverActive##0", s.route_options, 32768 --[[ImGuiInputFlags.RouteOverActive]]) + ImGui.EndDisabled() + ImGui.Unindent() + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteGlobal", s.route_type, 4096 --[[ImGuiInputFlags.RouteGlobal]]) + ImGui.Indent() + ImGui.BeginDisabled(s.route_type ~= 4096 --[[ImGuiInputFlags.RouteGlobal]]) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteOverFocused", s.route_options, 16384 --[[ImGuiInputFlags.RouteOverFocused]]) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteOverActive", s.route_options, 32768 --[[ImGuiInputFlags.RouteOverActive]]) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", s.route_options, 65536 --[[ImGuiInputFlags.RouteUnlessBgFocused]]) + ImGui.EndDisabled() + ImGui.Unindent() + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteAlways", s.route_type, 8192 --[[ImGuiInputFlags.RouteAlways]]) + local flags = bit32.bor(s.route_type, s.route_options) -- Merged flags + if s.route_type ~= 4096 --[[ImGuiInputFlags.RouteGlobal]] then + flags = bit32.band(flags, bit32.bnot(bit32.bor(16384 --[[ImGuiInputFlags.RouteOverFocused]], 32768 --[[ImGuiInputFlags.RouteOverActive]], 65536 --[[ImGuiInputFlags.RouteUnlessBgFocused]]))) + end + + ImGui.SeparatorText("Using SetNextItemShortcut()") + ImGui.Text("Ctrl+S") + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 564 --[[ImGuiKey.S]]), bit32.bor(flags, 262144 --[[ImGuiInputFlags.Tooltip]])) + ImGui.Button("Save") + ImGui.Text("Alt+F") + ImGui.SetNextItemShortcut(bit32.bor(16384 --[[ImGuiMod_Alt]], 551 --[[ImGuiKey.F]]), bit32.bor(flags, 262144 --[[ImGuiInputFlags.Tooltip]])) + s.f = ImGui.SliderFloat("Factor", s.f, 0.0, 1.0) + + ImGui.SeparatorText("Using Shortcut()") + local line_height = ImGui.GetTextLineHeightWithSpacing() + local key_chord = bit32.bor(4096 --[[ImGuiMod_Ctrl]], 546 --[[ImGuiKey.A]]) + + -- [Port] ImGui.Shortcut() has no owner_id default (upstream public overload passes ImGuiKeyOwner_Any): pass it explicitly. + ImGui.Text("Ctrl+A") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, 0 --[[ImGuiKeyOwner_Any]]) and "PRESSED" or "...") + + ImGui.PushStyleColor(3 --[[ImGuiCol.ChildBg]], ImVec4(1.0, 0.0, 1.0, 0.1)) + + ImGui.BeginChild("WindowA", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], line_height * 14), true) + ImGui.Text("Press Ctrl+A and see who receives it!") + ImGui.Separator() + + -- 1: Window polling for Ctrl+A + ImGui.Text("(in WindowA)") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, 0 --[[ImGuiKeyOwner_Any]]) and "PRESSED" or "...") + + -- 2: InputText also polling for Ctrl+A: it always uses _RouteFocused internally (gets priority when active) + -- (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h) + --char str[16] = "Press Ctrl+A"; + --ImGui.Spacing(); + --ImGui.InputText("InputTextB", str, IM_COUNTOF(str), ImGuiInputTextFlags.ReadOnly); + --ImGuiID item_id = ImGui.GetItemID(); + --ImGui.SameLine(); HelpMarker("Internal widgets always use _RouteFocused"); + --ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused(), ImGui.Shortcut(key_chord, flags, item_id) ? "PRESSED" : "..."); + + -- 3: Dummy child is not claiming the route: focusing them shouldn't steal route away from WindowA + ImGui.BeginChild("ChildD", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], line_height * 4), true) + ImGui.Text("(in ChildD: not using same Shortcut)") + ImGui.Text("IsWindowFocused: %d", ImGui.IsWindowFocused() and 1 or 0) + ImGui.EndChild() + + -- 4: Child window polling for Ctrl+A. It is deeper than WindowA and gets priority when focused. + ImGui.BeginChild("ChildE", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], line_height * 4), true) + ImGui.Text("(in ChildE: using same Shortcut)") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, 0 --[[ImGuiKeyOwner_Any]]) and "PRESSED" or "...") + ImGui.EndChild() + + -- 5: In a popup + if ImGui.Button("Open Popup") then + ImGui.OpenPopup("PopupF") + end + if ImGui.BeginPopup("PopupF") then + ImGui.Text("(in PopupF)") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, 0 --[[ImGuiKeyOwner_Any]]) and "PRESSED" or "...") + -- (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h) + --ImGui.InputText("InputTextG", str, IM_COUNTOF(str), ImGuiInputTextFlags.ReadOnly); + --ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused(), ImGui.Shortcut(key_chord, flags, ImGui.GetItemID()) ? "PRESSED" : "..."); + ImGui.EndPopup() + end + ImGui.EndChild() + ImGui.PopStyleColor() + + ImGui.TreePop() + end + + -- Display mouse cursors + if ImGui.TreeNode("Mouse Cursors") then + IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors") + local mouse_cursors_names = s.mouse_cursors_names -- 1-based + assert(#mouse_cursors_names == 11 --[[ImGuiMouseCursor.COUNT]]) + + local current = ImGui.GetMouseCursor() + local cursor_name = "N/A" + if (current >= 0 --[[ImGuiMouseCursor.Arrow]]) and (current < 11 --[[ImGuiMouseCursor.COUNT]]) then cursor_name = mouse_cursors_names[current + 1] end + ImGui.Text("Current mouse cursor = %d: %s", current, cursor_name) + ImGui.BeginDisabled(true) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseCursors", io.BackendFlags, 2 --[[ImGuiBackendFlags.HasMouseCursors]]) + ImGui.EndDisabled() + + ImGui.Text("Hover to see mouse cursors:") + ImGui.SameLine(); HelpMarker( + "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " .. + "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " .. + "otherwise your backend needs to handle it.") + for i = 0, 11 --[[ImGuiMouseCursor.COUNT]] - 1 do + local label = string.format("Mouse cursor %d: %s", i, mouse_cursors_names[i + 1]) + ImGui.Bullet(); ImGui.Selectable(label, false) + if ImGui.IsItemHovered() then + ImGui.SetMouseCursor(i) + end + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Tabbing") then + IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing") + ImGui.Text("Use Tab/Shift+Tab to cycle through keyboard editable fields.") + local buf = s.tabbing_buf + ImGui.InputText("1", buf, 32) + ImGui.InputText("2", buf, 32) + ImGui.InputText("3", buf, 32) + ImGui.PushItemFlag(1 --[[ImGuiItemFlags.NoTabStop]], true) + ImGui.InputText("4 (tab skip)", buf, 32) + ImGui.SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.") + ImGui.PopItemFlag() + ImGui.InputText("5", buf, 32) + ImGui.TreePop() + end + + if ImGui.TreeNode("Focus from code") then + IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code") + local focus_1 = ImGui.Button("Focus on 1"); ImGui.SameLine() + local focus_2 = ImGui.Button("Focus on 2"); ImGui.SameLine() + local focus_3 = ImGui.Button("Focus on 3") + local has_focus = 0 + local buf = s.focus_buf + + if focus_1 then ImGui.SetKeyboardFocusHere() end + ImGui.InputText("1", buf, 128) + if ImGui.IsItemActive() then has_focus = 1 end + + if focus_2 then ImGui.SetKeyboardFocusHere() end + ImGui.InputText("2", buf, 128) + if ImGui.IsItemActive() then has_focus = 2 end + + ImGui.PushItemFlag(1 --[[ImGuiItemFlags.NoTabStop]], true) + if focus_3 then ImGui.SetKeyboardFocusHere() end + ImGui.InputText("3 (tab skip)", buf, 128) + if ImGui.IsItemActive() then has_focus = 3 end + ImGui.SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.") + ImGui.PopItemFlag() + + if has_focus ~= 0 then + ImGui.Text("Item with focus: %d", has_focus) + else + ImGui.Text("Item with focus: ") + end + + -- Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item + local f3 = s.f3 + local focus_ahead = -1 + if ImGui.Button("Focus on X") then focus_ahead = 0 end ImGui.SameLine() + if ImGui.Button("Focus on Y") then focus_ahead = 1 end ImGui.SameLine() + if ImGui.Button("Focus on Z") then focus_ahead = 2 end + if focus_ahead ~= -1 then ImGui.SetKeyboardFocusHere(focus_ahead) end + ImGui.SliderFloat3("Float3", f3, 0.0, 1.0) + + ImGui.TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.") + ImGui.TreePop() + end + + if ImGui.TreeNode("Dragging") then + IMGUI_DEMO_MARKER("Inputs & Focus/Dragging") + ImGui.TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.") + for button = 0, 2 do + ImGui.Text("IsMouseDragging(%d):", button) + ImGui.Text(" w/ default threshold: %d,", ImGui.IsMouseDragging(button) and 1 or 0) + ImGui.Text(" w/ zero threshold: %d,", ImGui.IsMouseDragging(button, 0.0) and 1 or 0) + ImGui.Text(" w/ large threshold: %d,", ImGui.IsMouseDragging(button, 20.0) and 1 or 0) + end + + ImGui.Button("Drag Me") + if ImGui.IsItemActive() then + ImGui.GetForegroundDrawList():AddLine(io.MouseClickedPos[0], io.MousePos, ImGui.GetColorU32(22 --[[ImGuiCol.Button]]), 4.0) -- Draw a line between the button and the mouse cursor + end + + -- Drag operations gets "unlocked" when the mouse has moved past a certain threshold + -- (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher + -- threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta(). + local value_raw = ImGui.GetMouseDragDelta(0, 0.0) + local value_with_lock_threshold = ImGui.GetMouseDragDelta(0) + local mouse_delta = io.MouseDelta + ImGui.Text("GetMouseDragDelta(0):") + ImGui.Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y) + ImGui.Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y) + ImGui.Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y) ImGui.TreePop() end end +end - ImGui.PopID() +------------------------------------------------------------------------------- +-- [SECTION] About Window / ShowAboutWindow() +-- Access from Dear ImGui Demo -> Tools -> About +------------------------------------------------------------------------------- - DemoWindowColumns() +S.ShowAboutWindow = { + show_config_info = false, +} +function ImGui.ShowAboutWindow(p_open) + local s = S.ShowAboutWindow + local _, visible + p_open, visible = ImGui.Begin("About Dear ImGui", p_open, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Tools/About Dear ImGui") + ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, 19298 --[[IMGUI_VERSION_NUM]]) - if disable_indent then - ImGui.PopStyleVar() + ImGui.TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui") + ImGui.SameLine() + ImGui.TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Extensions", "https://github.com/ocornut/imgui/wiki/Useful-Extensions") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding") + + ImGui.Separator() + ImGui.Text("(c) 2014-2026 Omar Cornut") + ImGui.Text("Developed by Omar Cornut and all Dear ImGui contributors.") + ImGui.Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.") + ImGui.Text("If your company uses this, please consider funding the project.") + + _, s.show_config_info = ImGui.Checkbox("Config/Build Information", s.show_config_info) + if s.show_config_info then + local io = ImGui.GetIO() + local style = ImGui.GetStyle() + + local copy_to_clipboard = ImGui.Button("Copy to clipboard") + local child_size = ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 18) + ImGui.BeginChild(ImGui.GetID("cfg_infos"), child_size, 128 --[[ImGuiChildFlags.FrameStyle]]) + if copy_to_clipboard then + ImGui.LogToClipboard() + ImGui.LogText("// (Copy from the next line. Keep the ``` markers for formatting.)\n") + ImGui.LogText("```cpp\n") -- Back quotes will make text appears without formatting when pasting on GitHub + end + + ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, 19298 --[[IMGUI_VERSION_NUM]]) + ImGui.Separator() + -- [Port] no sizeof()/__cplusplus/compiler/OS #defines in Lua: report the Lua runtime instead + ImGui.Text("runtime: %s", tostring(_VERSION)) + ImGui.Text("define: IMGUI_HAS_VIEWPORT") + ImGui.Text("define: IMGUI_HAS_DOCK") + + -- Heuristic to detect no-op IM_ASSERT() macros + -- - This is designed so people opening bug reports would convey and notice that they have disabled asserts for Dear ImGui code. + -- - 16 is > strlen("((void)(_EXPR))") which we suggested in our imconfig.h template as a possible way to disable. + local assert_runs_expression = 0 + assert((function() assert_runs_expression = assert_runs_expression + 1; return assert_runs_expression end)()) -- [Port] no ++ in expressions + local assert_expand_len = 17 -- [Port] IM_ASSERT is a function, not a macro: nothing to stringify, it cannot be expanded to a no-op + local assert_maybe_disabled = (assert_runs_expression == 0 or assert_expand_len <= 16) + ImGui.Text("IM_ASSERT: runs expression: %s. expand size: %s%s", + (assert_runs_expression ~= 0) and "OK" or "KO", (assert_expand_len > 16) and "OK" or "KO", assert_maybe_disabled and " (MAYBE DISABLED?!)" or "") + if assert_maybe_disabled then + ImGui.SameLine() + HelpMarker("IM_ASSERT() calls assert() by default. Compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes!") + end + + ImGui.Separator() + ImGui.Text("io.BackendPlatformName: %s", io.BackendPlatformName or "NULL") + ImGui.Text("io.BackendRendererName: %s", io.BackendRendererName or "NULL") + ImGui.Text("io.ConfigFlags: 0x%08X", io.ConfigFlags) + if bit32.band(io.ConfigFlags, 1 --[[ImGuiConfigFlags.NavEnableKeyboard]]) ~= 0 then ImGui.Text(" NavEnableKeyboard") end + if bit32.band(io.ConfigFlags, 2 --[[ImGuiConfigFlags.NavEnableGamepad]]) ~= 0 then ImGui.Text(" NavEnableGamepad") end + if bit32.band(io.ConfigFlags, 16 --[[ImGuiConfigFlags.NoMouse]]) ~= 0 then ImGui.Text(" NoMouse") end + if bit32.band(io.ConfigFlags, 32 --[[ImGuiConfigFlags.NoMouseCursorChange]]) ~= 0 then ImGui.Text(" NoMouseCursorChange") end + if bit32.band(io.ConfigFlags, 64 --[[ImGuiConfigFlags.NoKeyboard]]) ~= 0 then ImGui.Text(" NoKeyboard") end + if bit32.band(io.ConfigFlags, 128 --[[ImGuiConfigFlags.DockingEnable]]) ~= 0 then ImGui.Text(" DockingEnable") end + if bit32.band(io.ConfigFlags, 1024 --[[ImGuiConfigFlags.ViewportsEnable]]) ~= 0 then ImGui.Text(" ViewportsEnable") end + if io.MouseDrawCursor then ImGui.Text("io.MouseDrawCursor") end + if io.ConfigDpiScaleFonts then ImGui.Text("io.ConfigDpiScaleFonts") end + if io.ConfigDpiScaleViewports then ImGui.Text("io.ConfigDpiScaleViewports") end + if io.ConfigViewportsNoAutoMerge then ImGui.Text("io.ConfigViewportsNoAutoMerge") end + if io.ConfigViewportsNoTaskBarIcon then ImGui.Text("io.ConfigViewportsNoTaskBarIcon") end + if io.ConfigViewportsNoDecoration then ImGui.Text("io.ConfigViewportsNoDecoration") end + if io.ConfigViewportsNoDefaultParent then ImGui.Text("io.ConfigViewportsNoDefaultParent") end + if io.ConfigDockingNoSplit then ImGui.Text("io.ConfigDockingNoSplit") end + if io.ConfigDockingNoDockingOver then ImGui.Text("io.ConfigDockingNoDockingOver") end + if io.ConfigDockingWithShift then ImGui.Text("io.ConfigDockingWithShift") end + if io.ConfigDockingAlwaysTabBar then ImGui.Text("io.ConfigDockingAlwaysTabBar") end + if io.ConfigDockingTransparentPayload then ImGui.Text("io.ConfigDockingTransparentPayload") end + if io.ConfigMacOSXBehaviors then ImGui.Text("io.ConfigMacOSXBehaviors") end + if io.ConfigNavMoveSetMousePos then ImGui.Text("io.ConfigNavMoveSetMousePos") end + if io.ConfigNavCaptureKeyboard then ImGui.Text("io.ConfigNavCaptureKeyboard") end + if io.ConfigInputTextCursorBlink then ImGui.Text("io.ConfigInputTextCursorBlink") end + if io.ConfigWindowsResizeFromEdges then ImGui.Text("io.ConfigWindowsResizeFromEdges") end + if io.ConfigWindowsMoveFromTitleBarOnly then ImGui.Text("io.ConfigWindowsMoveFromTitleBarOnly") end + if io.ConfigMemoryCompactTimer >= 0.0 then ImGui.Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer) end + ImGui.Text("io.BackendFlags: 0x%08X", io.BackendFlags) + if bit32.band(io.BackendFlags, 1 --[[ImGuiBackendFlags.HasGamepad]]) ~= 0 then ImGui.Text(" HasGamepad") end + if bit32.band(io.BackendFlags, 2 --[[ImGuiBackendFlags.HasMouseCursors]]) ~= 0 then ImGui.Text(" HasMouseCursors") end + if bit32.band(io.BackendFlags, 4 --[[ImGuiBackendFlags.HasSetMousePos]]) ~= 0 then ImGui.Text(" HasSetMousePos") end + if bit32.band(io.BackendFlags, 2048 --[[ImGuiBackendFlags.PlatformHasViewports]]) ~= 0 then ImGui.Text(" PlatformHasViewports") end + if bit32.band(io.BackendFlags, 4096 --[[ImGuiBackendFlags.HasMouseHoveredViewport]]) ~= 0 then ImGui.Text(" HasMouseHoveredViewport") end + if bit32.band(io.BackendFlags, 8192 --[[ImGuiBackendFlags.HasParentViewport]]) ~= 0 then ImGui.Text(" HasParentViewport") end + if bit32.band(io.BackendFlags, 8 --[[ImGuiBackendFlags.RendererHasVtxOffset]]) ~= 0 then ImGui.Text(" RendererHasVtxOffset") end + if bit32.band(io.BackendFlags, 16 --[[ImGuiBackendFlags.RendererHasTextures]]) ~= 0 then ImGui.Text(" RendererHasTextures") end + if bit32.band(io.BackendFlags, 1024 --[[ImGuiBackendFlags.RendererHasViewports]]) ~= 0 then ImGui.Text(" RendererHasViewports") end + ImGui.Separator() + ImGui.Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts.Fonts.Size, io.Fonts.Flags, io.Fonts.TexData.Width, io.Fonts.TexData.Height) + ImGui.Text("io.Fonts->FontLoaderName: %s", io.Fonts.FontLoaderName or "NULL") + ImGui.Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y) + ImGui.Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y) + ImGui.Separator() + ImGui.Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y) + ImGui.Text("style.WindowBorderSize: %.2f", style.WindowBorderSize) + ImGui.Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y) + ImGui.Text("style.FrameRounding: %.2f", style.FrameRounding) + ImGui.Text("style.FrameBorderSize: %.2f", style.FrameBorderSize) + ImGui.Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y) + ImGui.Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y) + + if copy_to_clipboard then + ImGui.LogText("\n```\n") + ImGui.LogFinish() + end + ImGui.EndChild() + end + ImGui.End() + return p_open +end + +------------------------------------------------------------------------------- +-- [SECTION] Style Editor / ShowStyleEditor() +------------------------------------------------------------------------------- +-- - ShowStyleSelector() +-- - ShowStyleEditor() +------------------------------------------------------------------------------- + +-- [Port] C++ copies ImGuiStyle by value (`dst = src`). Copy fields in place so ImVec2/ImVec4 objects of `dst` keep +-- their identity (the live style's vectors may be referenced elsewhere) and are never aliased with `src`. +function ImGuiStyle_Copy(dst, src) + for k, v in pairs(src) do + if k == "Colors" then + local dst_colors = dst.Colors + for i, col in pairs(v) do + if dst_colors[i] then ImVec4_Copy(dst_colors[i], col) else dst_colors[i] = ImVec4(col.x, col.y, col.z, col.w) end + end + elseif type(v) == "table" then -- ImVec2 + if dst[k] then ImVec2_Copy(dst[k], v) else dst[k] = ImVec2(v.x, v.y) end + else + dst[k] = v + end + end + return dst +end + +S.ShowStyleSelector = { + style_idx = -1, +} +-- Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. +function ImGui.ShowStyleSelector(label) + -- FIXME: This is a bit tricky to get right as style are functions, they don't register a name nor the fact that one is active. + -- So we keep track of last active one among our limited selection. + local s = S.ShowStyleSelector + local style_names = { "Dark", "Light", "Classic" } + local ret = false + if ImGui.BeginCombo(label, (s.style_idx >= 0 and s.style_idx < #style_names) and style_names[s.style_idx + 1] or "") then + for n = 0, #style_names - 1 do + if ImGui.Selectable(style_names[n + 1], s.style_idx == n, 64 --[[ImGuiSelectableFlags.SelectOnNav]]) then + s.style_idx = n + ret = true + if s.style_idx == 0 then ImGui.StyleColorsDark() + elseif s.style_idx == 1 then ImGui.StyleColorsLight() + elseif s.style_idx == 2 then ImGui.StyleColorsClassic() + end + elseif s.style_idx == n then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndCombo() + end + return ret +end + +function GetTreeLinesFlagsName(flags) + if flags == 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]] then return "DrawLinesNone" end + if flags == 524288 --[[ImGuiTreeNodeFlags.DrawLinesFull]] then return "DrawLinesFull" end + if flags == 1048576 --[[ImGuiTreeNodeFlags.DrawLinesToNodes]] then return "DrawLinesToNodes" end + return "" +end + +S.ShowStyleEditor = { + ref_saved_style = nil, -- static ImGuiStyle ref_saved_style; (created lazily) + init = true, + output_dest = 0, + output_only_modified = true, + alpha_flags = 0, + filter = nil, -- static ImGuiTextFilter filter; (created lazily) +} +-- We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code. +-- [Port] Lua has no `using namespace`: calls keep the ImGui. prefix +function ImGui.ShowStyleEditor(ref) + local s = S.ShowStyleEditor + local _, changed + IMGUI_DEMO_MARKER("Tools/Style Editor") + -- You can pass in a reference ImGuiStyle structure to compare to, revert to and save to + -- (without a reference style pointer, we will use one compared locally as a reference) + local style = ImGui.GetStyle() + if s.ref_saved_style == nil then s.ref_saved_style = ImGuiStyle() end + + -- Default to using internal storage as reference + if s.init and ref == nil then + ImGuiStyle_Copy(s.ref_saved_style, style) + end + s.init = false + if ref == nil then + ref = s.ref_saved_style + end + + -- The logic behind dynamically changing 'max_border_size' is to not encourage people to increase border size too much: it'll likely reveal lots of subtle rendering artifacts and this isn't a priority right now. + -- Note that _MainScale is currently internal PLEASE DO NOT USE IN YOUR CODE. + local default_border_size = math.floor(style._MainScale) + local max_border_size = ImMax(default_border_size, 2.0) + + ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50) + + do + -- General + ImGui.SeparatorText("General") + if bit32.band(ImGui.GetIO().BackendFlags, 16 --[[ImGuiBackendFlags.RendererHasTextures]]) == 0 then + ImGui.BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!") + ImGui.BulletText("For instructions, see:") + ImGui.SameLine() + ImGui.TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md") + end + + if ImGui.ShowStyleSelector("Colors##Selector") then + ImGuiStyle_Copy(s.ref_saved_style, style) + end + ImGui.ShowFontSelector("Fonts##Selector") + style.FontSizeBase, changed = ImGui.DragFloat("FontSizeBase", style.FontSizeBase, 0.20, 5.0, 100.0, "%.0f") + if changed then + style._NextFrameFontSizeBase = style.FontSizeBase -- FIXME: Temporary hack until we finish remaining work. + end + ImGui.SameLine(0.0, 0.0); ImGui.Text(" (out %.2f)", ImGui.GetFontSize()) + style.FontScaleMain = ImGui.DragFloat("FontScaleMain", style.FontScaleMain, 0.02, 0.5, 4.0) + ImGui.BeginDisabled(ImGui.GetIO().ConfigDpiScaleFonts == true) -- [Port] field is nil in the port's ImGuiIO (nil would mean "disabled") + style.FontScaleDpi = ImGui.DragFloat("FontScaleDpi", style.FontScaleDpi, 0.02, 0.5, 4.0) + ImGui.SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.") + ImGui.EndDisabled() + + -- Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) + style.FrameRounding, changed = ImGui.SliderFloat("FrameRounding", style.FrameRounding, 0.0, 12.0, "%.0f") + if changed then + style.GrabRounding = style.FrameRounding -- Make GrabRounding always the same value as FrameRounding + end + do local pressed, border = ImGui.Checkbox("WindowBorder", style.WindowBorderSize > 0.0); if pressed then if border then style.WindowBorderSize = default_border_size else style.WindowBorderSize = 0.0 end end end + ImGui.SameLine() + do local pressed, border = ImGui.Checkbox("FrameBorder", style.FrameBorderSize > 0.0); if pressed then if border then style.FrameBorderSize = default_border_size else style.FrameBorderSize = 0.0 end end end + ImGui.SameLine() + do local pressed, border = ImGui.Checkbox("PopupBorder", style.PopupBorderSize > 0.0); if pressed then if border then style.PopupBorderSize = default_border_size else style.PopupBorderSize = 0.0 end end end + end + + -- Save/Revert button + if ImGui.Button("Save Ref") then + ImGuiStyle_Copy(ref, ImGuiStyle_Copy(s.ref_saved_style, style)) + end + ImGui.SameLine() + if ImGui.Button("Revert Ref") then + ImGuiStyle_Copy(style, ref) + end + ImGui.SameLine() + HelpMarker( + "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " .. + "Use \"Export\" below to save them somewhere.") + + ImGui.SeparatorText("Details") + if ImGui.BeginTabBar("##tabs", 0 --[[ImGuiTabBarFlags.None]]) then + if ImGui.BeginTabItem("Sizes") then + ImGui.SeparatorText("Main") + ImGui.SliderFloat2("WindowPadding", style.WindowPadding, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("FramePadding", style.FramePadding, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("ItemSpacing", style.ItemSpacing, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("ItemInnerSpacing", style.ItemInnerSpacing, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("TouchExtraPadding", style.TouchExtraPadding, 0.0, 10.0, "%.0f") + style.IndentSpacing = ImGui.SliderFloat("IndentSpacing", style.IndentSpacing, 0.0, 30.0, "%.0f") + style.GrabMinSize = ImGui.SliderFloat("GrabMinSize", style.GrabMinSize, 1.0, 20.0, "%.0f") + + ImGui.SeparatorText("Borders") + style.WindowBorderSize = ImGui.SliderFloat("WindowBorderSize", style.WindowBorderSize, 0.0, max_border_size, "%.0f") + style.ChildBorderSize = ImGui.SliderFloat("ChildBorderSize", style.ChildBorderSize, 0.0, max_border_size, "%.0f") + style.PopupBorderSize = ImGui.SliderFloat("PopupBorderSize", style.PopupBorderSize, 0.0, max_border_size, "%.0f") + style.FrameBorderSize = ImGui.SliderFloat("FrameBorderSize", style.FrameBorderSize, 0.0, max_border_size, "%.0f") + + ImGui.SeparatorText("Rounding") + style.WindowRounding = ImGui.SliderFloat("WindowRounding", style.WindowRounding, 0.0, 12.0, "%.0f") + style.ChildRounding = ImGui.SliderFloat("ChildRounding", style.ChildRounding, 0.0, 12.0, "%.0f") + style.FrameRounding = ImGui.SliderFloat("FrameRounding", style.FrameRounding, 0.0, 12.0, "%.0f") + style.PopupRounding = ImGui.SliderFloat("PopupRounding", style.PopupRounding, 0.0, 12.0, "%.0f") + style.GrabRounding = ImGui.SliderFloat("GrabRounding", style.GrabRounding, 0.0, 12.0, "%.0f") + style.MenuItemRounding = ImGui.SliderFloat("MenuItemRounding", style.MenuItemRounding, 0.0, 12.0, "%.0f") + -- NB: SelectableRounding is intentionally NOT made visible here. We don't want to encourage people using that. + + ImGui.SeparatorText("Scrollbar") + style.ScrollbarSize = ImGui.SliderFloat("ScrollbarSize", style.ScrollbarSize, 1.0, 20.0, "%.0f") + style.ScrollbarRounding = ImGui.SliderFloat("ScrollbarRounding", style.ScrollbarRounding, 0.0, 12.0, "%.0f") + style.ScrollbarPadding = ImGui.SliderFloat("ScrollbarPadding", style.ScrollbarPadding, 0.0, 10.0, "%.0f") + + ImGui.SeparatorText("Tabs") + style.TabBorderSize = ImGui.SliderFloat("TabBorderSize", style.TabBorderSize, 0.0, max_border_size, "%.0f") + style.TabBarBorderSize = ImGui.SliderFloat("TabBarBorderSize", style.TabBarBorderSize, 0.0, max_border_size, "%.0f") + style.TabBarOverlineSize = ImGui.SliderFloat("TabBarOverlineSize", style.TabBarOverlineSize, 0.0, ImMax(3.0, max_border_size), "%.0f") + ImGui.SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.") + style.TabMinWidthBase = ImGui.DragFloat("TabMinWidthBase", style.TabMinWidthBase, 0.5, 1.0, 500.0, "%.0f") + style.TabMinWidthShrink = ImGui.DragFloat("TabMinWidthShrink", style.TabMinWidthShrink, 0.5, 1.0, 500.0, "%0.f") + style.TabCloseButtonMinWidthSelected = ImGui.DragFloat("TabCloseButtonMinWidthSelected", style.TabCloseButtonMinWidthSelected, 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthSelected < 0.0) and "%.0f (Always)" or "%.0f") + style.TabCloseButtonMinWidthUnselected = ImGui.DragFloat("TabCloseButtonMinWidthUnselected", style.TabCloseButtonMinWidthUnselected, 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthUnselected < 0.0) and "%.0f (Always)" or "%.0f") + style.TabRounding = ImGui.SliderFloat("TabRounding", style.TabRounding, 0.0, 12.0, "%.0f") + + ImGui.SeparatorText("Tables") + ImGui.SliderFloat2("CellPadding", style.CellPadding, 0.0, 20.0, "%.0f") + style.TableAngledHeadersAngle = ImGui.SliderAngle("TableAngledHeadersAngle", style.TableAngledHeadersAngle, -50.0, 50.0) + ImGui.SliderFloat2("TableAngledHeadersTextAlign", style.TableAngledHeadersTextAlign, 0.0, 1.0, "%.2f") + + ImGui.SeparatorText("Trees") + local combo_open = ImGui.BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)) + ImGui.SameLine() + HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode.") + if combo_open then + local options = { 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]], 524288 --[[ImGuiTreeNodeFlags.DrawLinesFull]], 1048576 --[[ImGuiTreeNodeFlags.DrawLinesToNodes]] } + for _, option in ipairs(options) do + if ImGui.Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option) then + style.TreeLinesFlags = option + end + end + ImGui.EndCombo() + end + style.TreeLinesSize = ImGui.SliderFloat("TreeLinesSize", style.TreeLinesSize, 0.0, max_border_size, "%.0f") + style.TreeLinesRounding = ImGui.SliderFloat("TreeLinesRounding", style.TreeLinesRounding, 0.0, 12.0, "%.0f") + + ImGui.SeparatorText("Windows") + ImGui.SliderFloat2("WindowTitleAlign", style.WindowTitleAlign, 0.0, 1.0, "%.2f") + style.WindowBorderHoverPadding = ImGui.SliderFloat("WindowBorderHoverPadding", style.WindowBorderHoverPadding, 1.0, 20.0, "%.0f") + local window_menu_button_position = style.WindowMenuButtonPosition + 1 + window_menu_button_position, changed = ImGui.Combo("WindowMenuButtonPosition", window_menu_button_position, "None\0Left\0Right\0") + if changed then + style.WindowMenuButtonPosition = window_menu_button_position - 1 + end + + ImGui.SeparatorText("Widgets") + style.ColorMarkerSize = ImGui.SliderFloat("ColorMarkerSize", style.ColorMarkerSize, 0.0, 8.0, "%.0f") + style.ColorButtonPosition = ImGui.Combo("ColorButtonPosition", style.ColorButtonPosition, "Left\0Right\0") + ImGui.SliderFloat2("ButtonTextAlign", style.ButtonTextAlign, 0.0, 1.0, "%.2f") + ImGui.SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.") + ImGui.SliderFloat2("SelectableTextAlign", style.SelectableTextAlign, 0.0, 1.0, "%.2f") + ImGui.SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.") + style.SeparatorSize = ImGui.SliderFloat("SeparatorSize", style.SeparatorSize, 0.0, 10.0, "%.0f") + style.SeparatorTextBorderSize = ImGui.SliderFloat("SeparatorTextBorderSize", style.SeparatorTextBorderSize, 0.0, 10.0, "%.0f") + ImGui.SliderFloat2("SeparatorTextAlign", style.SeparatorTextAlign, 0.0, 1.0, "%.2f") + ImGui.SliderFloat2("SeparatorTextPadding", style.SeparatorTextPadding, 0.0, 40.0, "%.0f") + style.LogSliderDeadzone = ImGui.SliderFloat("LogSliderDeadzone", style.LogSliderDeadzone, 0.0, 12.0, "%.0f") + style.ImageRounding = ImGui.SliderFloat("ImageRounding", style.ImageRounding, 0.0, 12.0, "%.0f") + style.ImageBorderSize = ImGui.SliderFloat("ImageBorderSize", style.ImageBorderSize, 0.0, max_border_size, "%.0f") + + ImGui.SeparatorText("Docking") + --SetCursorPosX(GetCursorPosX() + CalcItemWidth() - GetFrameHeight()); + _, style.DockingNodeHasCloseButton = ImGui.Checkbox("DockingNodeHasCloseButton", style.DockingNodeHasCloseButton) + style.DockingSeparatorSize = ImGui.SliderFloat("DockingSeparatorSize", style.DockingSeparatorSize, 0.0, 12.0, "%.0f") + + ImGui.SeparatorText("Tooltips") + for n = 0, 1 do + if ImGui.TreeNodeEx(n == 0 and "HoverFlagsForTooltipMouse" or "HoverFlagsForTooltipNav") then + local p = (n == 0) and "HoverFlagsForTooltipMouse" or "HoverFlagsForTooltipNav" -- [Port] pointer -> field name + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_DelayNone", style[p], 16384 --[[ImGuiHoveredFlags.DelayNone]]) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_DelayShort", style[p], 32768 --[[ImGuiHoveredFlags.DelayShort]]) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_DelayNormal", style[p], 65536 --[[ImGuiHoveredFlags.DelayNormal]]) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_Stationary", style[p], 8192 --[[ImGuiHoveredFlags.Stationary]]) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", style[p], 131072 --[[ImGuiHoveredFlags.NoSharedDelay]]) + ImGui.TreePop() + end + end + + ImGui.SeparatorText("Misc") + ImGui.SliderFloat2("DisplayWindowPadding", style.DisplayWindowPadding, 0.0, 30.0, "%.0f"); ImGui.SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.") + ImGui.SliderFloat2("DisplaySafeAreaPadding", style.DisplaySafeAreaPadding, 0.0, 30.0, "%.0f"); ImGui.SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).") + + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Colors") then + if ImGui.Button("Export") then + if s.output_dest == 0 then + ImGui.LogToClipboard() + else + ImGui.LogToTTY() + end + ImGui.LogText("ImVec4* colors = GetStyle().Colors;" .. "\n") -- [Port] IM_NEWLINE == "\n" + for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do + local col = style.Colors[i] + local name = ImGui.GetStyleColorName(i) + if not s.output_only_modified or col ~= ref.Colors[i] then -- [Port] memcmp -> ImVec4 __eq + ImGui.LogText("colors[ImGuiCol_%s]%s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" .. "\n", + name, string.rep(" ", 23 - #name), col.x, col.y, col.z, col.w) -- [Port] "%*s" -> string.rep + end + end + ImGui.LogFinish() + end + ImGui.SameLine(); ImGui.SetNextItemWidth(ImGui.GetFontSize() * 10); s.output_dest = ImGui.Combo("##output_type", s.output_dest, "To Clipboard\0To TTY\0") + ImGui.SameLine(); _, s.output_only_modified = ImGui.Checkbox("Only Modified Colors", s.output_only_modified) + + -- [Port] RadioButton(label, bool active) overload is RadioButtonEx() in the port + if ImGui.RadioButtonEx("Opaque", s.alpha_flags == 4096 --[[ImGuiColorEditFlags.AlphaOpaque]]) then s.alpha_flags = 4096 --[[ImGuiColorEditFlags.AlphaOpaque]] end ImGui.SameLine() + if ImGui.RadioButtonEx("Alpha", s.alpha_flags == 0 --[[ImGuiColorEditFlags.None]]) then s.alpha_flags = 0 --[[ImGuiColorEditFlags.None]] end ImGui.SameLine() + if ImGui.RadioButtonEx("Both", s.alpha_flags == 16384 --[[ImGuiColorEditFlags.AlphaPreviewHalf]]) then s.alpha_flags = 16384 --[[ImGuiColorEditFlags.AlphaPreviewHalf]] end ImGui.SameLine() + HelpMarker( + "In the color list:\n" .. + "Left-click on color square to open color picker,\n" .. + "Right-click to open edit options menu.") + + if s.filter == nil then s.filter = ImGuiTextFilter() end + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + s.filter:DrawWithHint("##FilterColors", "Filter Colors (incl -excl)") + + ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 10), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]])) + ImGui.BeginChild("##colors", ImVec2(0, 0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 256 --[[ImGuiChildFlags.NavFlattened]]), bit32.bor(16384 --[[ImGuiWindowFlags.AlwaysVerticalScrollbar]], 32768 --[[ImGuiWindowFlags.AlwaysHorizontalScrollbar]])) + ImGui.PushItemWidth(ImGui.GetFontSize() * -12) + for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do repeat + local name = ImGui.GetStyleColorName(i) + if not s.filter:PassFilter(name) then + break -- continue + end + ImGui.PushID(i) + if ImGui.Button("?") then + if ImGui.DebugFlashStyleColor then ImGui.DebugFlashStyleColor(i) end -- [Port] DebugFlashStyleColor() is not in the library yet + end + ImGui.SetItemTooltip("Flash given color to identify places where it is used.") + ImGui.SameLine() + ImGui.ColorEdit4("##color", style.Colors[i], bit32.bor(262144 --[[ImGuiColorEditFlags.AlphaBar]], s.alpha_flags)) + if style.Colors[i] ~= ref.Colors[i] then -- [Port] memcmp -> ImVec4 __eq + -- Tips: in a real user application, you may want to merge and use an icon font into the main font, + -- so instead of "Save"/"Revert" you'd use icons! + -- Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! + ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Save") then ImVec4_Copy(ref.Colors[i], style.Colors[i]) end + ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Revert") then ImVec4_Copy(style.Colors[i], ref.Colors[i]) end + end + ImGui.SameLine(0.0, style.ItemInnerSpacing.x) + ImGui.TextUnformatted(name) + ImGui.PopID() + until true end + ImGui.PopItemWidth() + ImGui.EndChild() + + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Fonts") then + local io = ImGui.GetIO() + local atlas = io.Fonts + ImGui.ShowFontAtlas(atlas) + + -- Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. + -- (we enforce hard clamping manually as by default DragFloat/SliderFloat allows Ctrl+Click text to get out of bounds). + --[[ + SeparatorText("Legacy Scaling"); + const float MIN_SCALE = 0.3f; + const float MAX_SCALE = 2.0f; + HelpMarker( + "Those are old settings provided for convenience.\n" + "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, " + "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" + "Using those settings here will give you poor quality results."); + PushItemWidth(GetFontSize() * 8); + DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything + //static float window_scale = 1.0f; + //if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window + // SetWindowFontScale(window_scale); + PopItemWidth(); + ]] + + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Rendering") then + _, style.AntiAliasedLines = ImGui.Checkbox("Anti-aliased lines", style.AntiAliasedLines) + ImGui.SameLine() + HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.") + ImGui.BeginDisabled(style.AntiAliasedLines == false) + _, style.AntiAliasedLineEnds = ImGui.Checkbox("Anti-aliased line ends", style.AntiAliasedLineEnds) + ImGui.EndDisabled() + + ImGui.BeginDisabled() + _, style.AntiAliasedLinesUseTex = ImGui.Checkbox("Anti-aliased lines use texture", style.AntiAliasedLinesUseTex) + ImGui.SameLine() + HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).") + ImGui.EndDisabled() + + _, style.AntiAliasedFill = ImGui.Checkbox("Anti-aliased fill", style.AntiAliasedFill) + local io = ImGui.GetIO() + _, io.ConfigDebugDrawListDefaultsToStrokeLegacy = ImGui.Checkbox("Debug: DrawList Defaults to _StrokeLegacy", io.ConfigDebugDrawListDefaultsToStrokeLegacy == true) -- [Port] field not declared in the port's ImGuiIO + + ImGui.PushItemWidth(ImGui.GetFontSize() * 8) + -- [Port] the library still stores the older style.CurveTessellationTol (== MaxError * MaxError) instead of style.CurveTessellationMaxError + local curve_tessellation_max_error + curve_tessellation_max_error, changed = ImGui.DragFloat("Curve Tessellation Max Error", math.sqrt(style.CurveTessellationTol), 0.02, 0.10, 10.0, "%.2f") + if curve_tessellation_max_error < 0.10 then + curve_tessellation_max_error = 0.10 + changed = true + end + if changed then style.CurveTessellationTol = curve_tessellation_max_error * curve_tessellation_max_error end -- [Port] only write back on change (sqrt/square round-trip is not exact) + + -- When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. + style.CircleTessellationMaxError = ImGui.DragFloat("Circle Tessellation Max Error", style.CircleTessellationMaxError, 0.005, 0.10, 5.0, "%.2f", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + local show_samples = ImGui.IsItemActive() + if show_samples then + ImGui.SetNextWindowPos(ImGui.GetCursorScreenPos()) + end + if show_samples and ImGui.BeginTooltip() then + ImGui.TextUnformatted("(R = radius, N = approx number of segments)") + ImGui.Spacing() + local draw_list = ImGui.GetWindowDrawList() + local min_widget_width = ImGui.CalcTextSize("R: MMM\nN: MMM").x + for n = 0, 7 do + local RAD_MIN = 5.0 + local RAD_MAX = 70.0 + local rad = RAD_MIN + (RAD_MAX - RAD_MIN) * n / (8.0 - 1.0) + + ImGui.BeginGroup() + + -- N is not always exact here due to how PathArcTo() function work internally + ImGui.Text("R: %.f\nN: %d", rad, draw_list:_CalcCircleAutoSegmentCount(rad)) + + local canvas_width = ImMax(min_widget_width, rad * 2.0) + local offset_x = math.floor(canvas_width * 0.5) + local offset_y = math.floor(RAD_MAX) + + local p1 = ImGui.GetCursorScreenPos() + draw_list:AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui.GetColorU32(0 --[[ImGuiCol.Text]])) + ImGui.Dummy(ImVec2(canvas_width, RAD_MAX * 2)) + + --[[ + const ImVec2 p2 = GetCursorScreenPos(); + draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, GetColorU32(ImGuiCol_Text)); + Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + ]] + + ImGui.EndGroup() + ImGui.SameLine() + end + ImGui.EndTooltip() + end + ImGui.SameLine() + HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically.") + + style.Alpha = ImGui.DragFloat("Global Alpha", style.Alpha, 0.005, 0.20, 1.0, "%.2f") -- Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. + style.DisabledAlpha = ImGui.DragFloat("Disabled Alpha", style.DisabledAlpha, 0.005, 0.0, 1.0, "%.2f"); ImGui.SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).") + ImGui.PopItemWidth() + + ImGui.EndTabItem() + end + + ImGui.EndTabBar() + end + ImGui.PopItemWidth() +end + +------------------------------------------------------------------------------- +-- [SECTION] User Guide / ShowUserGuide() +------------------------------------------------------------------------------- + +-- We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code. +function ImGui.ShowUserGuide() + local io = ImGui.GetIO() + ImGui.BulletText("Double-click on title bar to collapse window.") + ImGui.BulletText( + "Click and drag on lower corner or border to resize window.\n" .. + "(double-click to auto fit window to its contents)") + ImGui.BulletText("Ctrl+Click on a slider or drag box to input value as text.") + ImGui.BulletText("Tab/Shift+Tab to cycle through keyboard editable fields.") + ImGui.BulletText("Ctrl+Tab/Ctrl+Shift+Tab to focus windows.") + if io.FontAllowUserScaling then + ImGui.BulletText("Ctrl+Mouse Wheel to zoom window contents.") + end + ImGui.BulletText("While inputting text:\n") + ImGui.Indent() + ImGui.BulletText("Ctrl+Left/Right to word jump.") + ImGui.BulletText("Ctrl+A or double-click to select all.") + ImGui.BulletText("Ctrl+X/C/V to use clipboard cut/copy/paste.") + ImGui.BulletText("Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.") + ImGui.BulletText("Escape to revert.") + ImGui.Unindent() + ImGui.BulletText("With Keyboard controls enabled:") + ImGui.Indent() + ImGui.BulletText("Arrow keys or Home/End/PageUp/PageDown to navigate.") + ImGui.BulletText("Space to activate a widget.") + ImGui.BulletText("Return to input text into a widget.") + ImGui.BulletText("Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus.") + ImGui.BulletText("Alt to jump to the menu layer of a window.") + ImGui.BulletText("Menu or Shift+F10 to open a context menu.") + ImGui.Unindent() + ImGui.BulletText("With Gamepad controls enabled:") + ImGui.Indent() + ImGui.BulletText("D-Pad: Navigate / Tweak / Resize (in Windowing mode).") + ImGui.BulletText("%s Face button: Activate / Open / Toggle. Hold: activate with text input.", io.ConfigNavSwapGamepadButtons and "East" or "South") + ImGui.BulletText("%s Face button: Cancel / Close / Exit.", io.ConfigNavSwapGamepadButtons and "South" or "East") + ImGui.BulletText("West Face button: Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows).") + ImGui.BulletText("North Face button: Open Context Menu.") + ImGui.BulletText("L1/R1: Tweak Slower/Faster, Focus Previous/Next (in Windowing Mode).") + ImGui.Unindent() +end + +------------------------------------------------------------------------------- +-- [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +------------------------------------------------------------------------------- +-- - ShowExampleAppMainMenuBar() +-- - ShowExampleMenuFile() +------------------------------------------------------------------------------- + +-- Demonstrate creating a "main" fullscreen menu bar and populating it. +-- Note the difference between BeginMainMenuBar() and BeginMenuBar(): +-- - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags.MenuBar flag!) +-- - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. +function ShowExampleAppMainMenuBar() + if ImGui.BeginMainMenuBar() then + if ImGui.BeginMenu("File") then + IMGUI_DEMO_MARKER("Menu/File") + ShowExampleMenuFile() + ImGui.EndMenu() + end + if ImGui.BeginMenu("Edit") then + IMGUI_DEMO_MARKER("Menu/Edit") + if ImGui.MenuItem("Undo", "Ctrl+Z") then end + if ImGui.MenuItem("Redo", "Ctrl+Y", false, false) then end -- Disabled item + ImGui.Separator() + if ImGui.MenuItem("Cut", "Ctrl+X") then end + if ImGui.MenuItem("Copy", "Ctrl+C") then end + if ImGui.MenuItem("Paste", "Ctrl+V") then end + ImGui.EndMenu() + end + ImGui.EndMainMenuBar() end end -end --[[ imgui_demo_2.lua ]] -do --[[ imgui_demo_apps.lua ]] --- Demo: Example apps (port of imgui_demo.cpp "Example App" sections). Each ShowExampleAppXXX(p_open) returns the new p_open. -local _ -local Buf, BufStr = DemoBuf, DemoBufStr +-- Note that shortcuts are currently provided for display only +-- (future version will add explicit flags to BeginMenu() to request processing shortcuts) +S.ShowExampleMenuFile = { + enabled = true, + f = 0.5, + n = 0, + b = true, +} +function ShowExampleMenuFile() + local s = S.ShowExampleMenuFile + IMGUI_DEMO_MARKER("Examples/Menu") + ImGui.MenuItem("(demo menu)", nil, false, false) + if ImGui.MenuItem("New") then end + if ImGui.MenuItem("Open", "Ctrl+O") then end + if ImGui.BeginMenu("Open Recent") then + ImGui.MenuItem("fish_hat.c") + ImGui.MenuItem("fish_hat.inl") + ImGui.MenuItem("fish_hat.h") + if ImGui.BeginMenu("More..") then + ImGui.MenuItem("Hello") + ImGui.MenuItem("Sailor") + if ImGui.BeginMenu("Recurse..") then + ShowExampleMenuFile() + ImGui.EndMenu() + end + ImGui.EndMenu() + end + ImGui.EndMenu() + end + if ImGui.MenuItem("Save", "Ctrl+S") then end + if ImGui.MenuItem("Save As..") then end -local function BufSet(buf, str) - for i = 1, #str do buf[i] = string.byte(str, i) end - buf[#str + 1] = 0 + ImGui.Separator() + if ImGui.BeginMenu("Options") then + IMGUI_DEMO_MARKER("Examples/Menu/Options") + _, s.enabled = ImGui.MenuItem("Enabled", "", s.enabled) + ImGui.BeginChild("child", ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 5.0), 1 --[[ImGuiChildFlags.Borders]]) + for i = 0, 10 - 1 do + ImGui.Text("Scrolling Text %d", i) + end + ImGui.EndChild() + s.f = ImGui.SliderFloat("Value", s.f, 0.0, 1.0) + s.f = ImGui.InputFloat("Input", s.f, 0.1) + s.n = ImGui.Combo("Combo", s.n, "Yes\0No\0Maybe\0\0") + ImGui.EndMenu() + end + + if ImGui.BeginMenu("Colors") then + IMGUI_DEMO_MARKER("Examples/Menu/Colors") + local sz = ImGui.GetTextLineHeight() + for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do + local name = ImGui.GetStyleColorName(i) + local p = ImGui.GetCursorScreenPos() + ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui.GetColorU32(i)) + ImGui.Dummy(ImVec2(sz, sz)) + ImGui.SameLine() + ImGui.MenuItem(name) + end + ImGui.EndMenu() + end + + -- Here we demonstrate appending again to the "Options" menu (which we already created above) + -- Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. + -- In a real code-base using it would make senses to use this feature from very different code locations. + if ImGui.BeginMenu("Options") then -- <-- Append! + IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu") + _, s.b = ImGui.Checkbox("SomeOption", s.b) + ImGui.EndMenu() + end + + if ImGui.BeginMenu("Disabled", false) then -- Disabled + assert(false) + end + if ImGui.MenuItem("Checked", nil, true) then end + ImGui.Separator() + if ImGui.MenuItem("Quit", "Alt+F4") then end end ------------------------------------------------------------------------------- @@ -25772,245 +29609,383 @@ end -- Demonstrate creating a simple console window, with scrolling, filtering, completion and history. -- For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. -local Console = nil -local function ConsoleNew() - -- HistoryPos: -1: new line, 0..#History-1 browsing history. +ExampleAppConsoleMT = {} +ExampleAppConsoleMT.__index = ExampleAppConsoleMT +function ExampleAppConsole() + local self = setmetatable({}, ExampleAppConsoleMT) + self.InputBuf = nil -- char InputBuf[256] + self.Items = ImVector() -- ImVector + self.Commands = ImVector() -- ImVector + self.History = ImVector() -- ImVector + self.HistoryPos = 0 -- -1: new line, 0..History.Size-1 browsing history. + self.Filter = ImGuiTextFilter() + self.AutoScroll = false + self.ScrollToBottom = false + + self:ClearLog() + self.InputBuf = ImGui.NewTextBuffer("", 256) -- memset(InputBuf, 0, sizeof(InputBuf)) + self.HistoryPos = -1 + -- "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches. - local c = { InputBuf = Buf("", 256), Items = {}, Commands = { "HELP", "HISTORY", "CLEAR", "CLASSIFY" }, History = {}, - HistoryPos = -1, Filter = ImGuiTextFilter(), AutoScroll = true, ScrollToBottom = false } - function c:ClearLog() self.Items = {} end - function c:AddLog(fmt, ...) - -- FIXME-OPT - local s = (select("#", ...) > 0) and string.format(fmt, ...) or fmt - self.Items[#self.Items + 1] = s - end - function c:ExecCommand(command_line) - self:AddLog("# %s\n", command_line) + self.Commands:push_back("HELP") + self.Commands:push_back("HISTORY") + self.Commands:push_back("CLEAR") + self.Commands:push_back("CLASSIFY") + self.AutoScroll = true + self.ScrollToBottom = false + self:AddLog("Welcome to Dear ImGui!") + return self +end +-- [Port] ~ExampleAppConsole(): nothing to free (GC) - -- Insert into history. First find match and delete it so it can be pushed to the back. - -- This isn't trying to be smart or optimal. - self.HistoryPos = -1 - for i = #self.History, 1, -1 do - if string.upper(self.History[i]) == string.upper(command_line) then table.remove(self.History, i); break end - end - self.History[#self.History + 1] = command_line +-- Portable helpers +do + local function toupper(c) if c >= 97 and c <= 122 then return c - 32 end return c end -- [Port] C toupper() on bytes + function ExampleAppConsoleMT.Stricmp(s1, s2) local i = 1; local d; while true do local c1 = string.byte(s1, i) or 0; d = toupper(string.byte(s2, i) or 0) - toupper(c1); if d ~= 0 or c1 == 0 then break end; i = i + 1 end; return d end + function ExampleAppConsoleMT.Strnicmp(s1, s2, n) local i = 1; local d = 0; while n > 0 do local c1 = string.byte(s1, i) or 0; d = toupper(string.byte(s2, i) or 0) - toupper(c1); if d ~= 0 or c1 == 0 then break end; i = i + 1; n = n - 1 end; return d end + function ExampleAppConsoleMT.Strdup(s) assert(s); return s end -- [Port] Lua strings are immutable values + function ExampleAppConsoleMT.Strtrimblanks(s) local str_end = 0; while s[str_end + 1] ~= nil and s[str_end + 1] ~= 0 do str_end = str_end + 1 end; while str_end > 0 and s[str_end] == 32 do str_end = str_end - 1 end; s[str_end + 1] = 0 end + ExampleAppConsoleMT.toupper = toupper -- [Port] used by TextEditCallback() +end - -- Process command - local cmd = string.upper(command_line) - if cmd == "CLEAR" then - self:ClearLog() - elseif cmd == "HELP" then - self:AddLog("Commands:") - for i = 1, #self.Commands do self:AddLog("- %s", self.Commands[i]) end - elseif cmd == "HISTORY" then - local first = #self.History - 10 - for i = math.max(first, 0), #self.History - 1 do self:AddLog("%3d: %s\n", i, self.History[i + 1]) end - else - self:AddLog("Unknown command: '%s'\n", command_line) - end +function ExampleAppConsoleMT:ClearLog() + -- [Port] ImGui::MemFree(Items[i]) not needed (GC) + self.Items:clear() +end - -- On command input, we scroll to bottom even if AutoScroll==false - self.ScrollToBottom = true - end - function c:TextEditCallback(data) - --self:AddLog("cursor: %d, selection: %d-%d", data.CursorPos, data.SelectionStart, data.SelectionEnd) - if data.EventFlag == 262144 --[[ImGuiInputTextFlags.CallbackCompletion]] then - -- Example of TEXT COMPLETION +function ExampleAppConsoleMT:AddLog(fmt, ...) + -- FIXME-OPT + local buf = string.format(fmt, ...) + buf = string.sub(buf, 1, 1024 - 1) -- [Port] vsnprintf() into char buf[1024] + self.Items:push_back(ExampleAppConsoleMT.Strdup(buf)) +end - -- Locate beginning of current word (positions are 0-based offsets into data.Buf) - local word_end = data.CursorPos - local word_start = word_end - while word_start > 0 do - local ch = data.Buf[word_start] - if ch == 32 or ch == 9 or ch == 44 or ch == 59 then break end - word_start = word_start - 1 - end - local word = "" - for i = word_start + 1, word_end do word = word .. string.char(data.Buf[i]) end - - -- Build a list of candidates - local candidates = {} - for i = 1, #self.Commands do - if string.upper(string.sub(self.Commands[i], 1, #word)) == string.upper(word) then candidates[#candidates + 1] = self.Commands[i] end - end - if #candidates == 0 then - -- No match - self:AddLog("No match for \"%s\"!\n", word) - elseif #candidates == 1 then - -- Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. - data:DeleteChars(word_start, word_end - word_start) - data:InsertChars(data.CursorPos, candidates[1]) - data:InsertChars(data.CursorPos, " ") - else - -- Multiple matches. Complete as much as we can.. - -- So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. - local match_len = word_end - word_start - while true do - local ch, all_match = nil, true - for i = 1, #candidates do - local cc = string.upper(string.sub(candidates[i], match_len + 1, match_len + 1)) - if i == 1 then ch = cc elseif ch == "" or ch ~= cc then all_match = false; break end - end - if not all_match or ch == "" then break end - match_len = match_len + 1 - end - if match_len > 0 then - data:DeleteChars(word_start, word_end - word_start) - data:InsertChars(data.CursorPos, string.sub(candidates[1], 1, match_len)) - end - - -- List matches - self:AddLog("Possible matches:\n") - for i = 1, #candidates do self:AddLog("- %s\n", candidates[i]) end - end - elseif data.EventFlag == 524288 --[[ImGuiInputTextFlags.CallbackHistory]] then - -- Example of HISTORY - local prev_history_pos = self.HistoryPos - if data.EventKey == 515 --[[ImGuiKey.UpArrow]] then - if self.HistoryPos == -1 then self.HistoryPos = #self.History - 1 - elseif self.HistoryPos > 0 then self.HistoryPos = self.HistoryPos - 1 end - elseif data.EventKey == 516 --[[ImGuiKey.DownArrow]] then - if self.HistoryPos ~= -1 then - self.HistoryPos = self.HistoryPos + 1 - if self.HistoryPos >= #self.History then self.HistoryPos = -1 end - end - end - - -- A better implementation would preserve the data on the current input line along with cursor position. - if prev_history_pos ~= self.HistoryPos then - local history_str = (self.HistoryPos >= 0) and self.History[self.HistoryPos + 1] or "" - data:DeleteChars(0, data.BufTextLen) - data:InsertChars(0, history_str) - end - end - return 0 - end - function c:Draw(title, p_open) - ImGui.SetNextWindowSize(ImVec2(520, 600), 4 --[[ImGuiCond.FirstUseEver]]) - local visible - p_open, visible = ImGui.Begin(title, p_open) - if not visible then ImGui.End(); return p_open end - - -- As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. - -- So e.g. IsItemHovered() will return true when hovering the title bar. - -- Here we create a context menu only available from the title bar. - if ImGui.BeginPopupContextItem() then - if ImGui.MenuItem("Close Console") then p_open = false end - ImGui.EndPopup() - end - ImGui.TextWrapped("This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc.") - ImGui.TextWrapped("Enter 'HELP' for help.") - - -- TODO: display items starting from the bottom - - if ImGui.SmallButton("Add Debug Text") then self:AddLog("%d some text", #self.Items); self:AddLog("some more text"); self:AddLog("display very important message here!") end - ImGui.SameLine() - if ImGui.SmallButton("Add Debug Error") then self:AddLog("[error] something went wrong") end - ImGui.SameLine() - if ImGui.SmallButton("Clear") then self:ClearLog() end - ImGui.SameLine() - local copy_to_clipboard = ImGui.SmallButton("Copy") - --local t = 0.0; if ImGui.GetTime() - t > 0.02 then t = ImGui.GetTime(); self:AddLog("Spam %f", t) end - - ImGui.Separator() - - -- Options menu - if ImGui.BeginPopup("Options") then - _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) - ImGui.EndPopup() - end - - -- Options, Filter - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 560 --[[ImGuiKey.O]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - if ImGui.Button("Options") then ImGui.OpenPopup("Options") end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 551 --[[ImGuiKey.F]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") - ImGui.Separator() - - -- Reserve enough left-over height for 1 separator + 1 input text - local style = ImGui.GetStyle() - local footer_height_to_reserve = (style.SeparatorSize or 1.0) + style.ItemSpacing.y + ImGui.GetFrameHeightWithSpacing() - if ImGui.BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), 256 --[[ImGuiChildFlags.NavFlattened]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) then - if ImGui.BeginPopupContextWindow() then - if ImGui.Selectable("Clear") then self:ClearLog() end - ImGui.EndPopup() - end - - -- Display every line as a separate entry so we can change their color or add custom widgets. - -- If you only want raw text you can use ImGui.TextUnformatted(log.begin(), log.end()) - -- NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping - -- to only process visible items. The clipper will automatically measure the height of your first item and then - -- "seek" to display only items in the visible area. - -- To use the clipper we can replace your standard loop: - -- for i = 1, #Items do - -- With: - -- local clipper = ImGuiListClipper() - -- clipper:Begin(#Items) - -- while clipper:Step() do - -- for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do - -- - That your items are evenly spaced (same height) - -- - That you have cheap random access to your elements (you can access them given their index, - -- without processing all the ones before) - -- You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. - -- We would need random-access on the post-filtered list. - -- A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices - -- or offsets of items that passed the filtering test, recomputing this array when user changes the filter, - -- and appending newly elements as they are inserted. This is left as a task to the user until we can manage - -- to improve this example code! - -- If your items are of variable height: - -- - Split them into same height items would be simpler and facilitate random-seeking into your list. - -- - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. - ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(4, 1)) -- Tighten spacing - if copy_to_clipboard then ImGui.LogToClipboard() end - for _, item in ipairs(self.Items) do - if self.Filter:PassFilter(item) then - -- Normally you would store more information in your item than just a string. - -- (e.g. make Items[] an array of structure, store color/type etc.) - local color - if string.find(item, "[error]", 1, true) then color = ImVec4(1.0, 0.4, 0.4, 1.0) - elseif string.sub(item, 1, 2) == "# " then color = ImVec4(1.0, 0.8, 0.6, 1.0) end - if color then ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], color) end - ImGui.TextUnformatted(item) - if color then ImGui.PopStyleColor() end - end - end - if copy_to_clipboard then ImGui.LogFinish() end - - -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. - -- Using a scrollbar or mouse-wheel will take away from the bottom edge. - if self.ScrollToBottom or (self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY()) then ImGui.SetScrollHereY(1.0) end - self.ScrollToBottom = false - ImGui.PopStyleVar() - end - ImGui.EndChild() - ImGui.Separator() - - -- Command-line - local reclaim_focus = false - local IT = ImGuiInputTextFlags - local input_text_flags = bit32.bor(IT.EnterReturnsTrue, IT.EscapeClearsAll, IT.CallbackCompletion, IT.CallbackHistory) - if ImGui.InputText("Input", self.InputBuf, 256, input_text_flags, function(data) return self:TextEditCallback(data) end) then - local s = string.gsub(BufStr(self.InputBuf), " +$", "") - if s ~= "" then self:ExecCommand(s) end - self.InputBuf[1] = 0 - reclaim_focus = true - end - - -- Auto-focus on window apparition - ImGui.SetItemDefaultFocus() - if reclaim_focus then ImGui.SetKeyboardFocusHere(-1) end -- Auto focus previous widget +function ExampleAppConsoleMT:Draw(title, p_open) + ImGui.SetNextWindowSize(ImVec2(520, 600), 4 --[[ImGuiCond.FirstUseEver]]) + local visible + p_open, visible = ImGui.Begin(title, p_open) + if not visible then ImGui.End() return p_open end - c:AddLog("Welcome to Dear ImGui!") - return c + IMGUI_DEMO_MARKER("Examples/Console") + + -- As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. + -- So e.g. IsItemHovered() will return true when hovering the title bar. + -- Here we create a context menu only available from the title bar. + if ImGui.BeginPopupContextItem() then + if ImGui.MenuItem("Close Console") then + p_open = false + end + ImGui.EndPopup() + end + + ImGui.TextWrapped( + "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " .. + "implementation may want to store entries along with extra data such as timestamp, emitter, etc.") + ImGui.TextWrapped("Enter 'HELP' for help.") + + -- TODO: display items starting from the bottom + + if ImGui.SmallButton("Add Debug Text") then self:AddLog("%d some text", self.Items.Size); self:AddLog("some more text"); self:AddLog("display very important message here!") end + ImGui.SameLine() + if ImGui.SmallButton("Add Debug Error") then self:AddLog("[error] something went wrong") end + ImGui.SameLine() + if ImGui.SmallButton("Clear") then self:ClearLog() end + ImGui.SameLine() + local copy_to_clipboard = ImGui.SmallButton("Copy") + --static float t = 0.0f; if (ImGui.GetTime() - t > 0.02f) { t = ImGui.GetTime(); AddLog("Spam %f", t); } + + ImGui.Separator() + + -- Options menu + if ImGui.BeginPopup("Options") then + _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) + ImGui.EndPopup() + end + + -- Options, Filter + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 560 --[[ImGuiKey.O]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + if ImGui.Button("Options") then + ImGui.OpenPopup("Options") + end + ImGui.SameLine() + + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 551 --[[ImGuiKey.F]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") + ImGui.Separator() + + -- Reserve enough left-over height for 1 separator + 1 input text + local style = ImGui.GetStyle() + local footer_height_to_reserve = style.SeparatorSize + style.ItemSpacing.y + ImGui.GetFrameHeightWithSpacing() + if ImGui.BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), 256 --[[ImGuiChildFlags.NavFlattened]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) then + if ImGui.BeginPopupContextWindow() then + if ImGui.Selectable("Clear") then self:ClearLog() end + ImGui.EndPopup() + end + + -- Display every line as a separate entry so we can change their color or add custom widgets. + -- If you only want raw text you can use ImGui.TextUnformatted(log.begin(), log.end()); + -- NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping + -- to only process visible items. The clipper will automatically measure the height of your first item and then + -- "seek" to display only items in the visible area. + -- To use the clipper we can replace your standard loop: + -- for (int i = 0; i < Items.Size; i++) + -- With: + -- ImGuiListClipper clipper; + -- clipper.Begin(Items.Size); + -- while (clipper.Step()) + -- for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + -- - That your items are evenly spaced (same height) + -- - That you have cheap random access to your elements (you can access them given their index, + -- without processing all the ones before) + -- You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. + -- We would need random-access on the post-filtered list. + -- A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices + -- or offsets of items that passed the filtering test, recomputing this array when user changes the filter, + -- and appending newly elements as they are inserted. This is left as a task to the user until we can manage + -- to improve this example code! + -- If your items are of variable height: + -- - Split them into same height items would be simpler and facilitate random-seeking into your list. + -- - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. + ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(4, 1)) -- Tighten spacing + if copy_to_clipboard then + ImGui.LogToClipboard() + end + for _, item in self.Items:iter() do repeat + if not self.Filter:PassFilter(item) then + break -- continue + end + + -- Normally you would store more information in your item than just a string. + -- (e.g. make Items[] an array of structure, store color/type etc.) + local color + local has_color = false + if string.find(item, "[error]", 1, true) then color = ImVec4(1.0, 0.4, 0.4, 1.0); has_color = true + elseif string.sub(item, 1, 2) == "# " then color = ImVec4(1.0, 0.8, 0.6, 1.0); has_color = true end + if has_color then + ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], color) + end + ImGui.TextUnformatted(item) + if has_color then + ImGui.PopStyleColor() + end + until true end + if copy_to_clipboard then + ImGui.LogFinish() + end + + -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. + -- Using a scrollbar or mouse-wheel will take away from the bottom edge. + if self.ScrollToBottom or (self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY()) then + ImGui.SetScrollHereY(1.0) + end + self.ScrollToBottom = false + + ImGui.PopStyleVar() + end + ImGui.EndChild() + ImGui.Separator() + + -- Command-line + local reclaim_focus = false + local input_text_flags = bit32.bor(64 --[[ImGuiInputTextFlags.EnterReturnsTrue]], 128 --[[ImGuiInputTextFlags.EscapeClearsAll]], 262144 --[[ImGuiInputTextFlags.CallbackCompletion]], 524288 --[[ImGuiInputTextFlags.CallbackHistory]]) + if ImGui.InputText("Input", self.InputBuf, 256, input_text_flags, ExampleAppConsoleMT.TextEditCallbackStub, self) then + local s = self.InputBuf + ExampleAppConsoleMT.Strtrimblanks(s) + if s[1] ~= 0 then + self:ExecCommand(ImGui.TextBufferToString(s)) + end + s[1] = 0 + reclaim_focus = true + end + + -- Auto-focus on window apparition + ImGui.SetItemDefaultFocus() + if reclaim_focus then + ImGui.SetKeyboardFocusHere(-1) -- Auto focus previous widget + end + + ImGui.End() + return p_open end +function ExampleAppConsoleMT:ExecCommand(command_line) + local Stricmp = ExampleAppConsoleMT.Stricmp + self:AddLog("# %s\n", command_line) + + -- Insert into history. First find match and delete it so it can be pushed to the back. + -- This isn't trying to be smart or optimal. + self.HistoryPos = -1 + for i = self.History.Size - 1, 0, -1 do + if Stricmp(self.History.Data[i + 1], command_line) == 0 then + self.History:erase(i + 1) + break + end + end + self.History:push_back(ExampleAppConsoleMT.Strdup(command_line)) + + -- Process command + if Stricmp(command_line, "CLEAR") == 0 then + self:ClearLog() + elseif Stricmp(command_line, "HELP") == 0 then + self:AddLog("Commands:") + for i = 0, self.Commands.Size - 1 do + self:AddLog("- %s", self.Commands.Data[i + 1]) + end + elseif Stricmp(command_line, "HISTORY") == 0 then + local first = self.History.Size - 10 + for i = (first > 0) and first or 0, self.History.Size - 1 do + self:AddLog("%3d: %s\n", i, self.History.Data[i + 1]) + end + else + self:AddLog("Unknown command: '%s'\n", command_line) + end + + -- On command input, we scroll to bottom even if AutoScroll==false + self.ScrollToBottom = true +end + +-- In C++11 you'd be better off using lambdas for this sort of forwarding callbacks +function ExampleAppConsoleMT.TextEditCallbackStub(data) + local console = data.UserData + return console:TextEditCallback(data) +end + +-- [Port] data.Buf is a 1-based byte table; positions (CursorPos, word_start, word_end) are 0-based offsets like upstream. +function ExampleAppConsoleMT:TextEditCallback(data) + local toupper = ExampleAppConsoleMT.toupper + --AddLog("cursor: %d, selection: %d-%d", data.CursorPos, data.SelectionStart, data.SelectionEnd) + if data.EventFlag == 262144 --[[ImGuiInputTextFlags.CallbackCompletion]] then + -- Example of TEXT COMPLETION + + -- Locate beginning of current word + local word_end = data.CursorPos + local word_start = word_end + while word_start > 0 do + local c = data.Buf[word_start] -- word_start[-1] + if c == 32 or c == 9 or c == 44 or c == 59 then -- ' ', '\t', ',', ';' + break + end + word_start = word_start - 1 + end + local word = string.char(table.unpack(data.Buf, word_start + 1, word_end)) -- [Port] word_start..word_end as a string + + -- Build a list of candidates + local candidates = ImVector() + for i = 0, self.Commands.Size - 1 do + if ExampleAppConsoleMT.Strnicmp(self.Commands.Data[i + 1], word, word_end - word_start) == 0 then + candidates:push_back(self.Commands.Data[i + 1]) + end + end + + if candidates.Size == 0 then + -- No match + self:AddLog("No match for \"%s\"!\n", word) -- [Port] "%.*s" -> "%s" + elseif candidates.Size == 1 then + -- Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. + data:DeleteChars(word_start, word_end - word_start) + data:InsertChars(data.CursorPos, candidates.Data[1]) + data:InsertChars(data.CursorPos, " ") + else + -- Multiple matches. Complete as much as we can.. + -- So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. + local match_len = word_end - word_start + while true do + local c = 0 + local all_candidates_matches = true + local i = 0 + while i < candidates.Size and all_candidates_matches do + if i == 0 then + c = toupper(string.byte(candidates.Data[i + 1], match_len + 1) or 0) + elseif c == 0 or c ~= toupper(string.byte(candidates.Data[i + 1], match_len + 1) or 0) then + all_candidates_matches = false + end + i = i + 1 + end + if not all_candidates_matches then + break + end + match_len = match_len + 1 + end + + if match_len > 0 then + data:DeleteChars(word_start, word_end - word_start) + data:InsertChars(data.CursorPos, string.sub(candidates.Data[1], 1, match_len)) -- [Port] InsertChars() has no text_end parameter + end + + -- List matches + self:AddLog("Possible matches:\n") + for i = 0, candidates.Size - 1 do + self:AddLog("- %s\n", candidates.Data[i + 1]) + end + end + + elseif data.EventFlag == 524288 --[[ImGuiInputTextFlags.CallbackHistory]] then + -- Example of HISTORY + local prev_history_pos = self.HistoryPos + if data.EventKey == 515 --[[ImGuiKey.UpArrow]] then + if self.HistoryPos == -1 then + self.HistoryPos = self.History.Size - 1 + elseif self.HistoryPos > 0 then + self.HistoryPos = self.HistoryPos - 1 + end + elseif data.EventKey == 516 --[[ImGuiKey.DownArrow]] then + if self.HistoryPos ~= -1 then + self.HistoryPos = self.HistoryPos + 1 + if self.HistoryPos >= self.History.Size then + self.HistoryPos = -1 + end + end + end + + -- A better implementation would preserve the data on the current input line along with cursor position. + if prev_history_pos ~= self.HistoryPos then + local history_str = "" + if self.HistoryPos >= 0 then history_str = self.History.Data[self.HistoryPos + 1] end + data:DeleteChars(0, data.BufTextLen) + data:InsertChars(0, history_str) + end + end + return 0 +end + +S.ShowExampleAppConsole = { + console = nil, -- ExampleAppConsole, created on first use +} function ShowExampleAppConsole(p_open) - Console = Console or ConsoleNew() - return Console:Draw("Example: Console", p_open) + local s = S.ShowExampleAppConsole + if s.console == nil then s.console = ExampleAppConsole() end + return s.console:Draw("Example: Console", p_open) +end + +------------------------------------------------------------------------------- +-- [SECTION] Example App: Image Viewer / ShowExampleAppImageViewer() +------------------------------------------------------------------------------- + +S.ShowExampleAppImageViewer = { + image_viewer = nil, -- ExampleImageViewerData, created on first use +} +function ShowExampleAppImageViewer(p_open) + local s = S.ShowExampleAppImageViewer + local atlas = ImGui.GetIO().Fonts + local tex_ref = atlas.TexRef -- We don't have access to other textures in this demo! + local tex_w = atlas.TexData.Width + local tex_h = atlas.TexData.Height + local visible + p_open, visible = ImGui.Begin("Example: Image Viewer", p_open) + if visible then + if s.image_viewer == nil then s.image_viewer = ExampleImageViewerData() end + ExampleImageViewer_DrawOptions(s.image_viewer) + local canvas_size = ImGui.GetContentRegionAvail() + local canvas_min_size + if ImGui.IsWindowAppearing() then canvas_min_size = ImVec2(3.0 * tex_w, 4.0 * tex_h) else canvas_min_size = ImVec2(1.0, 1.0) end + canvas_size = ImVec2(ImMax(canvas_size.x, canvas_min_size.x), ImMax(canvas_size.y, canvas_min_size.y)) + ExampleImageViewer_DrawCanvas(s.image_viewer, canvas_size, tex_ref, tex_w, tex_h) + end + ImGui.End() + return p_open end ------------------------------------------------------------------------------- @@ -26018,115 +29993,166 @@ end ------------------------------------------------------------------------------- -- Usage: --- local my_log = ExampleAppLog() --- my_log:AddLog("Hello %d world\n", 123) --- my_log:Draw("title") --- Lines are stored as a Lua array (equivalent of Buf + LineOffsets) -local function ExampleAppLog() - local l = { Lines = { "" }, Filter = ImGuiTextFilter(), AutoScroll = true } -- AutoScroll: Keep scrolling if already at the bottom. - function l:Clear() self.Lines = { "" } end - function l:AddLog(fmt, ...) - local s = (select("#", ...) > 0) and string.format(fmt, ...) or fmt - local lines = self.Lines - for part, nl in string.gmatch(s, "([^\n]*)(\n?)") do - lines[#lines] = lines[#lines] .. part - if nl ~= "" then lines[#lines + 1] = "" end - if part == "" and nl == "" then break end +-- static ExampleAppLog my_log; +-- my_log.AddLog("Hello %d world\n", 123); +-- my_log.Draw("title"); +ExampleAppLogMT = {} +ExampleAppLogMT.__index = ExampleAppLogMT +function ExampleAppLog() + local self = setmetatable({}, ExampleAppLogMT) + self.Buf = ImGuiTextBuffer() + self.Filter = ImGuiTextFilter() + self.LineOffsets = ImVector() -- Index to lines offset. We maintain this with AddLog() calls. + self.AutoScroll = false -- Keep scrolling if already at the bottom. + + self.AutoScroll = true + self:Clear() + return self +end + +function ExampleAppLogMT:Clear() + self.Buf:clear() + self.LineOffsets:clear() + self.LineOffsets:push_back(0) +end + +function ExampleAppLogMT:AddLog(fmt, ...) + local old_size = self.Buf:size() + self.Buf:appendf(fmt, ...) + local buf = self.Buf:c_str() -- [Port] Buf[] byte access + local new_size = #buf + while old_size < new_size do + if string.byte(buf, old_size + 1) == 10 then -- '\n' + self.LineOffsets:push_back(old_size + 1) end + old_size = old_size + 1 end - function l:Draw(title, p_open) - local visible - p_open, visible = ImGui.Begin(title, p_open) - if not visible then ImGui.End(); return p_open end +end - -- Options menu - if ImGui.BeginPopup("Options") then - _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) - ImGui.EndPopup() - end - - -- Main window - if ImGui.Button("Options") then ImGui.OpenPopup("Options") end - ImGui.SameLine() - local clear = ImGui.Button("Clear") - ImGui.SameLine() - local copy = ImGui.Button("Copy") - ImGui.SameLine() - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") - ImGui.Separator() - if ImGui.BeginChild("scrolling", ImVec2(0, 0), 0 --[[ImGuiChildFlags.None]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) then - if clear then self:Clear() end - if copy then ImGui.LogToClipboard() end - ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(0, 0)) - local lines = self.Lines - if self.Filter:IsActive() then - -- In this example we don't use the clipper when Filter is enabled. - -- This is because we don't have random access to the result of our filter. - -- A real application processing logs with ten of thousands of entries may want to store the result of - -- search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). - for line_no = 1, #lines do - if self.Filter:PassFilter(lines[line_no]) then ImGui.TextUnformatted(lines[line_no]) end - end - else - -- The simplest and easy way to display the entire buffer: - -- ImGui.TextUnformatted(buf_begin, buf_end) - -- And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward - -- to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are - -- within the visible area. - -- If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them - -- on your side is recommended. Using ImGuiListClipper requires - -- - A) random access into your data - -- - B) items all being the same height, - -- both of which we can handle since we have an array pointing to the beginning of each line of text. - -- When using the filter (in the block of code above) we don't have random access into the data to display - -- anymore, which is why we don't use the clipper. Storing or skimming through the search result would make - -- it possible (and would be recommended if you want to search through tens of thousands of entries). - local clipper = ImGuiListClipper() - clipper:Begin(#lines) - while clipper:Step() do - for line_no = clipper.DisplayStart, clipper.DisplayEnd - 1 do ImGui.TextUnformatted(lines[line_no + 1]) end - end - clipper:End() - end - ImGui.PopStyleVar() - if copy then ImGui.LogFinish() end - - -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. - -- Using a scrollbar or mouse-wheel will take away from the bottom edge. - if self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY() then ImGui.SetScrollHereY(1.0) end - end - ImGui.EndChild() +-- [Port] line offsets are 0-based like upstream; a line is string.sub(buf, line_start + 1, line_end) (TextUnformatted()/PassFilter() have no text_begin) +function ExampleAppLogMT:Draw(title, p_open) + local visible + p_open, visible = ImGui.Begin(title, p_open) + if not visible then ImGui.End() return p_open end - return l + + -- Options menu + if ImGui.BeginPopup("Options") then + _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) + ImGui.EndPopup() + end + + -- Main window + if ImGui.Button("Options") then + ImGui.OpenPopup("Options") + end + ImGui.SameLine() + local clear = ImGui.Button("Clear") + ImGui.SameLine() + local copy = ImGui.Button("Copy") + ImGui.SameLine() + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") + + ImGui.Separator() + + if ImGui.BeginChild("scrolling", ImVec2(0, 0), 0 --[[ImGuiChildFlags.None]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) then + if clear then + self:Clear() + end + if copy then + ImGui.LogToClipboard() + end + + ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(0, 0)) + local buf = self.Buf:c_str() + local buf_end = #buf + local LineOffsets = self.LineOffsets + if self.Filter:IsActive() then + -- In this example we don't use the clipper when Filter is enabled. + -- This is because we don't have random access to the result of our filter. + -- A real application processing logs with ten of thousands of entries may want to store the result of + -- search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). + for line_no = 0, LineOffsets.Size - 1 do + local line_start = LineOffsets.Data[line_no + 1] + local line_end + if line_no + 1 < LineOffsets.Size then line_end = LineOffsets.Data[line_no + 2] - 1 else line_end = buf_end end + local line = string.sub(buf, line_start + 1, line_end) + if self.Filter:PassFilter(line) then + ImGui.TextUnformatted(line) + end + end + else + -- The simplest and easy way to display the entire buffer: + -- ImGui.TextUnformatted(buf_begin, buf_end); + -- And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward + -- to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are + -- within the visible area. + -- If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them + -- on your side is recommended. Using ImGuiListClipper requires + -- - A) random access into your data + -- - B) items all being the same height, + -- both of which we can handle since we have an array pointing to the beginning of each line of text. + -- When using the filter (in the block of code above) we don't have random access into the data to display + -- anymore, which is why we don't use the clipper. Storing or skimming through the search result would make + -- it possible (and would be recommended if you want to search through tens of thousands of entries). + local clipper = ImGuiListClipper() + clipper:Begin(LineOffsets.Size) + while clipper:Step() do + for line_no = clipper.DisplayStart, clipper.DisplayEnd - 1 do + local line_start = LineOffsets.Data[line_no + 1] + local line_end + if line_no + 1 < LineOffsets.Size then line_end = LineOffsets.Data[line_no + 2] - 1 else line_end = buf_end end + ImGui.TextUnformatted(string.sub(buf, line_start + 1, line_end)) + end + end + clipper:End() + end + ImGui.PopStyleVar() + + -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. + -- Using a scrollbar or mouse-wheel will take away from the bottom edge. + if self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY() then + ImGui.SetScrollHereY(1.0) + end + end + ImGui.EndChild() + ImGui.End() + return p_open end -- Demonstrate creating a simple log window with basic filtering. -local AppLog, AppLogCounter = nil, 0 +S.ShowExampleAppLog = { + log = nil, -- ExampleAppLog, created on first use + counter = 0, +} function ShowExampleAppLog(p_open) - AppLog = AppLog or ExampleAppLog() + local s = S.ShowExampleAppLog + if s.log == nil then s.log = ExampleAppLog() end -- For the demo: add a debug button _BEFORE_ the normal log window contents -- We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. - -- Most of the contents of the window will be added by the log:Draw() call. + -- Most of the contents of the window will be added by the log.Draw() call. ImGui.SetNextWindowSize(ImVec2(500, 400), 4 --[[ImGuiCond.FirstUseEver]]) p_open = ImGui.Begin("Example: Log", p_open) + IMGUI_DEMO_MARKER("Examples/Log") if ImGui.SmallButton("[Debug] Add 5 entries") then local categories = { "info", "warn", "error" } local words = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" } - for _ = 1, 5 do - local category = categories[AppLogCounter % #categories + 1] - local word = words[AppLogCounter % #words + 1] - AppLog:AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", ImGui.GetFrameCount(), category, ImGui.GetTime(), word) - AppLogCounter = AppLogCounter + 1 + for n = 0, 5 - 1 do + local category = categories[s.counter % #categories + 1] + local word = words[s.counter % #words + 1] + s.log:AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", + ImGui.GetFrameCount(), category, ImGui.GetTime(), word) + s.counter = s.counter + 1 end end ImGui.End() -- Actually call in the regular Log helper (which will Begin() into the same window as we just did) - return AppLog:Draw("Example: Log", p_open) + return s.log:Draw("Example: Log", p_open) end ------------------------------------------------------------------------------- @@ -26134,12 +30160,16 @@ end ------------------------------------------------------------------------------- -- Demonstrate create a window with multiple child windows. -local LayoutSelected = 0 +S.ShowExampleAppLayout = { + selected = 0, +} function ShowExampleAppLayout(p_open) + local s = S.ShowExampleAppLayout ImGui.SetNextWindowSize(ImVec2(500, 440), 4 --[[ImGuiCond.FirstUseEver]]) local visible p_open, visible = ImGui.Begin("Example: Simple layout", p_open, 1024 --[[ImGuiWindowFlags.MenuBar]]) if visible then + IMGUI_DEMO_MARKER("Examples/Simple layout") if ImGui.BeginMenuBar() then if ImGui.BeginMenu("File") then if ImGui.MenuItem("Close", "Ctrl+W") then p_open = false end @@ -26149,34 +30179,41 @@ function ShowExampleAppLayout(p_open) end -- Left - ImGui.BeginChild("left pane", ImVec2(150, 0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 4 --[[ImGuiChildFlags.ResizeX]])) - for i = 0, 99 do - if ImGui.Selectable(string.format("MyObject %d", i), LayoutSelected == i, 64 --[[ImGuiSelectableFlags.SelectOnNav]]) then LayoutSelected = i end + do + ImGui.BeginChild("left pane", ImVec2(150, 0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 4 --[[ImGuiChildFlags.ResizeX]])) + for i = 0, 100 - 1 do + local label = string.format("MyObject %d", i) + if ImGui.Selectable(label, s.selected == i, 64 --[[ImGuiSelectableFlags.SelectOnNav]]) then + s.selected = i + end + end + ImGui.EndChild() end - ImGui.EndChild() ImGui.SameLine() -- Right - ImGui.BeginGroup() - ImGui.BeginChild("item view", ImVec2(0, -ImGui.GetFrameHeightWithSpacing())) -- Leave room for 1 line below us - ImGui.Text("MyObject: %d", LayoutSelected) - ImGui.Separator() - if ImGui.BeginTabBar("##Tabs", 0 --[[ImGuiTabBarFlags.None]]) then - if ImGui.BeginTabItem("Description") then - ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ") - ImGui.EndTabItem() + do + ImGui.BeginGroup() + ImGui.BeginChild("item view", ImVec2(0, -ImGui.GetFrameHeightWithSpacing())) -- Leave room for 1 line below us + ImGui.Text("MyObject: %d", s.selected) + ImGui.Separator() + if ImGui.BeginTabBar("##Tabs", 0 --[[ImGuiTabBarFlags.None]]) then + if ImGui.BeginTabItem("Description") then + ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ") + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Details") then + ImGui.Text("ID: 0123456789") + ImGui.EndTabItem() + end + ImGui.EndTabBar() end - if ImGui.BeginTabItem("Details") then - ImGui.Text("ID: 0123456789") - ImGui.EndTabItem() - end - ImGui.EndTabBar() + ImGui.EndChild() + if ImGui.Button("Revert") then end + ImGui.SameLine() + if ImGui.Button("Save") then end + ImGui.EndGroup() end - ImGui.EndChild() - if ImGui.Button("Revert") then end - ImGui.SameLine() - if ImGui.Button("Save") then end - ImGui.EndGroup() end ImGui.End() return p_open @@ -26191,121 +30228,20 @@ end -- - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties. ------------------------------------------------------------------------------- --- ExampleMemberInfo equivalent: field name, data type, component count -local ExampleTreeNodeMemberInfos = { - { Name = "MyName", DataType = ImGuiDataType.String, DataCount = 1, Field = "Name" }, - { Name = "MyBool", DataType = ImGuiDataType.Bool, DataCount = 1, Field = "DataMyBool" }, - { Name = "MyInt", DataType = ImGuiDataType.S32, DataCount = 1, Field = "DataMyInt" }, - { Name = "MyVec2", DataType = ImGuiDataType.Float, DataCount = 2, Field = "DataMyVec2" }, -} - -local PropEd = { Filter = nil, SelectedNode = nil, UseClipper = false, NameBufs = setmetatable({}, { __mode = "k" }) } - --- Custom search filter --- - Here we apply on root node only. --- - This does a case insensitive stristr which is pretty heavy. In a real large-scale app you would likely store a filtered list which in turns would be trivial to linearize. -function PropEd:IsNodePassingFilter(node) - return node.Parent.Parent ~= nil or self.Filter:PassFilter(node.Name) +ExampleAppPropertyEditorMT = {} +ExampleAppPropertyEditorMT.__index = ExampleAppPropertyEditorMT +function ExampleAppPropertyEditor() + local self = setmetatable({}, ExampleAppPropertyEditorMT) + self.Filter = ImGuiTextFilter() + self.SelectedNode = nil + self.UseClipper = false + self.StringBufs = setmetatable({}, { __mode = "k" }) -- [Port] node -> 28-byte edit buffer for ImGuiDataType.String fields (node.Name is a Lua string) + return self end --- To support node with same name we incorporate node.UID into the item ID. --- (this would more naturally be done using PushID(node.UID) + TreeNodeEx(node.Name, tree_flags), --- but it would require in DrawClippedTreeNodeAndAdvanceToNext() to add PushID() before TreePush(), and PopID() after TreePop(), --- so instead we use TreeNodeEx(node.UID, tree_flags, "%s", node.Name) here) -function PropEd:DrawTreeNode(node) - local TN = ImGuiTreeNodeFlags - ImGui.TableNextRow() - ImGui.TableNextColumn() - -- OpenOnArrow | OpenOnDoubleClick: Standard opening mode as we are likely to want to add selection afterwards - -- NavLeftJumpsToParent: Left arrow support - -- SpanFullWidth: Span full width for easier mouse reach - -- DrawLinesToNodes: Always draw hierarchy outlines - local tree_flags = bit32.bor(TN.OpenOnArrow, TN.OpenOnDoubleClick, TN.NavLeftJumpsToParent, TN.SpanFullWidth, TN.DrawLinesToNodes) - if node == self.SelectedNode then tree_flags = bit32.bor(tree_flags, TN.Selected) end -- Draw selection highlight - if #node.Childs == 0 then tree_flags = bit32.bor(tree_flags, TN.Leaf, TN.Bullet, TN.NoTreePushOnOpen) end -- Use _NoTreePushOnOpen + set is_open=false to avoid unnecessarily push/pop on leaves. - if node.DataMyBool == false then ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], ImGui.GetStyle().Colors[1 --[[ImGuiCol.TextDisabled]]]) end - ImGui.SetNextItemStorageID(node.UID) -- Use node.UID as storage id - local is_open = ImGui.TreeNodeEx(node.UID, tree_flags, "%s", node.Name) - if #node.Childs == 0 then is_open = false end - if node.DataMyBool == false then ImGui.PopStyleColor() end - if ImGui.IsItemFocused() then self.SelectedNode = node end - return is_open -end +function ExampleAppPropertyEditorMT:Draw(root_node) + IMGUI_DEMO_MARKER("Examples/Property editor") --- Basic version, recursive. This is how you would generally draw a tree. --- - Simple but going to be noticeably costly if you have a large amount of nodes as DrawTreeNode() is called for all of them. --- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~1.2 ms --- - Unlike arrays or grids which are very easy to clip, trees are currently more difficult to clip. -function PropEd:DrawTree(node) - for _, child in ipairs(node.Childs) do - if self:IsNodePassingFilter(child) and self:DrawTreeNode(child) then - self:DrawTree(child) - ImGui.TreePop() - end - end -end - -function PropEd:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) - if self:IsNodePassingFilter(node) then - -- Draw node if within visible range - local is_open - if clipper.UserIndex >= clipper.DisplayStart and clipper.UserIndex < clipper.DisplayEnd then - is_open = self:DrawTreeNode(node) - else - is_open = (#node.Childs > 0 and ImGui.TreeNodeGetOpen(node.UID)) - if is_open then ImGui.TreePush(node.Name) end - end - clipper.UserIndex = clipper.UserIndex + 1 - - -- Next node: recurse into childs - if is_open then return node.Childs[1] end - end - - -- Next node: next sibling, otherwise move back to parent - while node ~= nil do - if node.IndexInParent + 1 < #node.Parent.Childs then - return node.Parent.Childs[node.IndexInParent + 2] - end - node = node.Parent - if node.Parent == nil then break end - ImGui.TreePop() - end - return nil -end - --- More advanced version. Use a alternative clipping technique: fast-forwarding through non-visible chunks. --- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~0.1 ms --- (in ExampleTree_CreateDemoTree(), change 'ROOT_ITEMS_COUNT = 10000' to try with this amount of root nodes). --- - 1. Use clipper with indeterminate count (items_count = INT_MAX): we need to call SeekCursorForItem() at the end once we know the count. --- - 2. Use SetNextItemStorageID() to specify ID used for open/close storage, making it easy to call TreeNodeGetOpen() on any arbitrary node. --- - 3. Linearize tree during traversal: our tree data structure makes it easy to access sibling and parents. --- - Unlike clipping for a regular array or grid which may be done using random access limited to visible areas, --- this technique requires traversing most accessible nodes. This could be made more optimal with extra work, --- but this is a decent simplicity<>speed trade-off. --- See https://github.com/ocornut/imgui/issues/3823 for discussions about this. -function PropEd:DrawClippedTree(root_node) - local node = root_node.Childs[1] -- First node - local clipper = ImGuiListClipper() - clipper:Begin(2147483647 --[[INT_MAX]]) - while clipper:Step() do - while clipper.UserIndex < clipper.DisplayEnd and node ~= nil do - node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) - end - end - - -- Keep going to count nodes and submit final count so we have a reliable scrollbar. - -- - One could consider caching this value and only refreshing it occasionally e.g. window is focused and an action occurs. - -- - Incorrect but cheap approximation would be to use 'clipper_current_idx = IM_MAX(clipper_current_idx, #root_node.Childs)' instead. - -- - If either of those is implemented, the general cost will approach zero when scrolling is at the top of the tree. - while node ~= nil do - node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) - end - --clipper.UserIndex = math.max(clipper.UserIndex, #root_node.Childs) -- <-- Cheap approximation instead of while() loop above. - clipper:SeekCursorForItem(clipper.UserIndex) -end - -function PropEd:Draw(root_node) - self.Filter = self.Filter or ImGuiTextFilter() -- Left side: draw tree -- - Currently using a table to benefit from RowBg feature -- - Our tree node are all of equal height, facilitating the use of a clipper. @@ -26320,8 +30256,13 @@ function PropEd:Draw(root_node) self.Filter:Build() end ImGui.PopItemFlag() + if ImGui.BeginTable("##list", 1, 64 --[[ImGuiTableFlags.RowBg]]) then - if self.UseClipper then self:DrawClippedTree(root_node) else self:DrawTree(root_node) end + if self.UseClipper then + self:DrawClippedTree(root_node) + else + self:DrawTree(root_node) + end ImGui.EndTable() end end @@ -26352,19 +30293,26 @@ function PropEd:Draw(root_node) ImGui.AlignTextToFramePadding() ImGui.TextUnformatted(field_desc.Name) ImGui.TableNextColumn() - local DT = ImGuiDataType - if field_desc.DataType == DT.Bool then - _, node[field_desc.Field] = ImGui.Checkbox("##Editor", node[field_desc.Field]) - elseif field_desc.DataType == DT.S32 then + local field_ptr = field_desc.Offset -- [Port] Offset is the field name inside ExampleTreeNode + if field_desc.DataType == 8 --[[ImGuiDataType.Bool]] then + assert(field_desc.DataCount == 1) + _, node[field_ptr] = ImGui.Checkbox("##Editor", node[field_ptr]) + elseif field_desc.DataType == 4 --[[ImGuiDataType.S32]] then + local v_min, v_max = (-2147483648) --[[INT_MIN]], 2147483647 --[[INT_MAX]] ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - node[field_desc.Field] = ImGui.DragScalar("##Editor", DT.S32, node[field_desc.Field], 1.0, (-2147483648) --[[INT_MIN]] or -2147483648, 2147483647 --[[INT_MAX]]) - elseif field_desc.DataType == DT.Float then + if field_desc.DataCount == 1 then -- [Port] scalar fields are plain Lua values: DragScalar() returns the new value + node[field_ptr] = ImGui.DragScalar("##Editor", field_desc.DataType, node[field_ptr], 1.0, v_min, v_max) + else + ImGui.DragScalarN("##Editor", field_desc.DataType, node[field_ptr], field_desc.DataCount, 1.0, v_min, v_max) + end + elseif field_desc.DataType == 6 --[[ImGuiDataType.Float]] then + local v_min, v_max = 0.0, 1.0 ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - ImGui.SliderScalarN("##Editor", DT.Float, node[field_desc.Field], field_desc.DataCount, 0.0, 1.0) - elseif field_desc.DataType == DT.String then - local b = self.NameBufs[node] - if b == nil then b = Buf(node.Name, 28); self.NameBufs[node] = b end - if ImGui.InputText("##Editor", b, 28) then node.Name = BufStr(b) end + ImGui.SliderScalarN("##Editor", field_desc.DataType, node[field_ptr], field_desc.DataCount, v_min, v_max) + elseif field_desc.DataType == 9 --[[ImGuiDataType.String]] then + local buf = self.StringBufs[node] -- [Port] edit the Lua string through a 28-byte buffer + if buf == nil then buf = ImGui.NewTextBuffer(node[field_ptr], 28); self.StringBufs[node] = buf end + if ImGui.InputText("##Editor", buf, 28) then node[field_ptr] = ImGui.TextBufferToString(buf) end end ImGui.PopID() end @@ -26376,16 +30324,152 @@ function PropEd:Draw(root_node) ImGui.EndGroup() end +-- Custom search filter +-- - Here we apply on root node only. +-- - This does a case insensitive stristr which is pretty heavy. In a real large-scale app you would likely store a filtered list which in turns would be trivial to linearize. +function ExampleAppPropertyEditorMT:IsNodePassingFilter(node) + return node.Parent.Parent ~= nil or self.Filter:PassFilter(node.Name) +end + +-- Basic version, recursive. This is how you would generally draw a tree. +-- - Simple but going to be noticeably costly if you have a large amount of nodes as DrawTreeNode() is called for all of them. +-- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~1.2 ms +-- - Unlike arrays or grids which are very easy to clip, trees are currently more difficult to clip. +function ExampleAppPropertyEditorMT:DrawTree(node) + for _, child in ipairs(node.Childs) do + if self:IsNodePassingFilter(child) and self:DrawTreeNode(child) then + self:DrawTree(child) + ImGui.TreePop() + end + end +end + +-- More advanced version. Use a alternative clipping technique: fast-forwarding through non-visible chunks. +-- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~0.1 ms +-- (in ExampleTree_CreateDemoTree(), change 'int ROOT_ITEMS_COUNT = 10000' to try with this amount of root nodes). +-- - 1. Use clipper with indeterminate count (items_count = INT_MAX): we need to call SeekCursorForItem() at the end once we know the count. +-- - 2. Use SetNextItemStorageID() to specify ID used for open/close storage, making it easy to call TreeNodeGetOpen() on any arbitrary node. +-- - 3. Linearize tree during traversal: our tree data structure makes it easy to access sibling and parents. +-- - Unlike clipping for a regular array or grid which may be done using random access limited to visible areas, +-- this technique requires traversing most accessible nodes. This could be made more optimal with extra work, +-- but this is a decent simplicity<>speed trade-off. +-- See https://github.com/ocornut/imgui/issues/3823 for discussions about this. +function ExampleAppPropertyEditorMT:DrawClippedTree(root_node) + local node = root_node.Childs[1] -- First node + local clipper = ImGuiListClipper() + clipper:Begin(2147483647 --[[INT_MAX]]) + while clipper:Step() do + while clipper.UserIndex < clipper.DisplayEnd and node ~= nil do + node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) + end + end + + -- Keep going to count nodes and submit final count so we have a reliable scrollbar. + -- - One could consider caching this value and only refreshing it occasionally e.g. window is focused and an action occurs. + -- - Incorrect but cheap approximation would be to use 'clipper_current_idx = IM_MAX(clipper_current_idx, root_node.Childs.Size)' instead. + -- - If either of those is implemented, the general cost will approach zero when scrolling is at the top of the tree. + while node ~= nil do + node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) + end + --clipper.UserIndex = IM_MAX(clipper.UserIndex, root_node.Childs.Size); // <-- Cheap approximation instead of while() loop above. + clipper:SeekCursorForItem(clipper.UserIndex) +end + +function ExampleAppPropertyEditorMT:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) + if self:IsNodePassingFilter(node) then + -- Draw node if within visible range + local is_open = false + if clipper.UserIndex >= clipper.DisplayStart and clipper.UserIndex < clipper.DisplayEnd then + is_open = self:DrawTreeNode(node) + else + is_open = (#node.Childs > 0 and ImGui.TreeNodeGetOpen(node.UID)) + if is_open then + ImGui.TreePush(node.Name) + end + end + clipper.UserIndex = clipper.UserIndex + 1 + + -- Next node: recurse into childs + if is_open then + return node.Childs[1] + end + end + + -- Next node: next sibling, otherwise move back to parent + while node ~= nil do + if node.IndexInParent + 1 < #node.Parent.Childs then + return node.Parent.Childs[node.IndexInParent + 1 + 1] -- [Port] Childs is 1-based, IndexInParent 0-based + end + node = node.Parent + if node.Parent == nil then + break + end + ImGui.TreePop() + end + return nil +end + +-- To support node with same name we incorporate node.UID into the item ID. +-- (this would more naturally be done using PushID(node.UID) + TreeNodeEx(node.Name, tree_flags), +-- but it would require in DrawClippedTreeNodeAndAdvanceToNext() to add PushID() before TreePush(), and PopID() after TreePop(), +-- so instead we use TreeNodeEx(node.UID, tree_flags, "%s", node.Name) here) +function ExampleAppPropertyEditorMT:DrawTreeNode(node) + ImGui.TableNextRow() + ImGui.TableNextColumn() + local tree_flags = 0 --[[ImGuiTreeNodeFlags.None]] + tree_flags = bit32.bor(tree_flags, 128 --[[ImGuiTreeNodeFlags.OpenOnArrow]], 64 --[[ImGuiTreeNodeFlags.OpenOnDoubleClick]]) -- Standard opening mode as we are likely to want to add selection afterwards + tree_flags = bit32.bor(tree_flags, 131072 --[[ImGuiTreeNodeFlags.NavLeftJumpsToParent]]) -- Left arrow support + tree_flags = bit32.bor(tree_flags, 4096 --[[ImGuiTreeNodeFlags.SpanFullWidth]]) -- Span full width for easier mouse reach + tree_flags = bit32.bor(tree_flags, 1048576 --[[ImGuiTreeNodeFlags.DrawLinesToNodes]]) -- Always draw hierarchy outlines + if node == self.SelectedNode then + tree_flags = bit32.bor(tree_flags, 1 --[[ImGuiTreeNodeFlags.Selected]]) -- Draw selection highlight + end + if #node.Childs == 0 then + tree_flags = bit32.bor(tree_flags, 256 --[[ImGuiTreeNodeFlags.Leaf]], 512 --[[ImGuiTreeNodeFlags.Bullet]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]]) -- Use _NoTreePushOnOpen + set is_open=false to avoid unnecessarily push/pop on leaves. + end + if node.DataMyBool == false then + ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], ImGui.GetStyle().Colors[1 --[[ImGuiCol.TextDisabled]]]) + end + ImGui.SetNextItemStorageID(node.UID) -- Use node.UID as storage id + local is_open = ImGui.TreeNodeEx(node.UID, tree_flags, "%s", node.Name) + if #node.Childs == 0 then + is_open = false + end + if node.DataMyBool == false then + ImGui.PopStyleColor() + end + if ImGui.IsItemFocused() then + self.SelectedNode = node + end + return is_open +end + -- Demonstrate creating a simple property editor. -local DemoTree = nil +S.ShowExampleAppPropertyEditor = { + property_editor = nil, -- ExampleAppPropertyEditor, created on first use + demo_data = nil, -- [Port] fallback when called without demo_data +} function ShowExampleAppPropertyEditor(p_open, demo_data) + local s = S.ShowExampleAppPropertyEditor ImGui.SetNextWindowSize(ImVec2(430, 450), 4 --[[ImGuiCond.FirstUseEver]]) local visible p_open, visible = ImGui.Begin("Example: Property editor", p_open) - if not visible then ImGui.End(); return p_open end - if demo_data and demo_data.DemoTree == nil then demo_data.DemoTree = ExampleTree_CreateDemoTree() end - DemoTree = (demo_data and demo_data.DemoTree) or DemoTree or ExampleTree_CreateDemoTree() - PropEd:Draw(DemoTree) + if not visible then + ImGui.End() + return p_open + end + + IMGUI_DEMO_MARKER("Examples/Property Editor") + if s.property_editor == nil then s.property_editor = ExampleAppPropertyEditor() end + if demo_data == nil then -- [Port] tolerate callers without demo_data (test harness) + if s.demo_data == nil then s.demo_data = {} end + demo_data = s.demo_data + end + if demo_data.DemoTree == nil then + demo_data.DemoTree = ExampleTree_CreateDemoTree() + end + s.property_editor:Draw(demo_data.DemoTree) + ImGui.End() return p_open end @@ -26395,44 +30479,57 @@ end ------------------------------------------------------------------------------- -- Demonstrate/test rendering huge amount of text, and the incidence of clipping. -local LT = { test_type = 0, log = {}, lines = 0, bytes = 0 } +S.ShowExampleAppLongText = { + test_type = 0, + log = ImGuiTextBuffer(), + lines = 0, +} function ShowExampleAppLongText(p_open) + local s = S.ShowExampleAppLongText ImGui.SetNextWindowSize(ImVec2(520, 600), 4 --[[ImGuiCond.FirstUseEver]]) local visible p_open, visible = ImGui.Begin("Example: Long text display", p_open) - if not visible then ImGui.End(); return p_open end + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Examples/Long text display") + ImGui.Text("Printing unusually long amount of text.") - LT.test_type = ImGui.Combo("Test type", LT.test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped\0Multiple calls to Text(), not clipped (slow)\0") - ImGui.Text("Buffer contents: %d lines, %d bytes", LT.lines, LT.bytes) - if ImGui.Button("Clear") then LT.log = {}; LT.lines = 0; LT.bytes = 0; LT.text = nil end + s.test_type = ImGui.Combo("Test type", s.test_type, + "Single call to TextUnformatted()\0" .. + "Multiple calls to Text(), clipped\0" .. + "Multiple calls to Text(), not clipped (slow)\0") + ImGui.Text("Buffer contents: %d lines, %d bytes", s.lines, s.log:size()) + if ImGui.Button("Clear") then s.log:clear(); s.lines = 0 end ImGui.SameLine() if ImGui.Button("Add 1000 lines") then - for i = 0, 999 do - local line = string.format("%i The quick brown fox jumps over the lazy dog\n", LT.lines + i) - LT.log[#LT.log + 1] = line - LT.bytes = LT.bytes + #line + for i = 0, 1000 - 1 do + s.log:appendf("%i The quick brown fox jumps over the lazy dog\n", s.lines + i) end - LT.lines = LT.lines + 1000 - LT.text = nil + s.lines = s.lines + 1000 end ImGui.BeginChild("Log") - if LT.test_type == 0 then + if s.test_type == 0 then -- Single call to TextUnformatted() with a big buffer - LT.text = LT.text or table.concat(LT.log) - ImGui.TextUnformatted(LT.text) - elseif LT.test_type == 1 then + ImGui.TextUnformatted(s.log:c_str()) -- [Port] ImGuiTextBuffer is a chunk list: c_str() instead of begin()/end() + elseif s.test_type == 1 then -- Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(0, 0)) local clipper = ImGuiListClipper() - clipper:Begin(LT.lines) + clipper:Begin(s.lines) while clipper:Step() do - for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) end + for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do + ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) + end end ImGui.PopStyleVar() - else + elseif s.test_type == 2 then -- Multiple calls to Text(), not clipped (slow) ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(0, 0)) - for i = 0, LT.lines - 1 do ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) end + for i = 0, s.lines - 1 do + ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) + end ImGui.PopStyleVar() end ImGui.EndChild() @@ -26445,14 +30542,27 @@ end ------------------------------------------------------------------------------- -- Demonstrate creating a window which gets auto-resized according to its content. -local AutoResizeLines = 10 +S.ShowExampleAppAutoResize = { + lines = 10, +} function ShowExampleAppAutoResize(p_open) + local s = S.ShowExampleAppAutoResize local visible p_open, visible = ImGui.Begin("Example: Auto-resizing window", p_open, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) - if not visible then ImGui.End(); return p_open end - ImGui.TextUnformatted("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop.") - AutoResizeLines = ImGui.SliderInt("Number of lines", AutoResizeLines, 1, 20) - for i = 0, AutoResizeLines - 1 do ImGui.Text("%sThis is line %d", string.rep(" ", i * 4), i) end -- Pad with space to extend size horizontally + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Examples/Auto-resizing window") + + ImGui.TextUnformatted( + "Window will resize every-frame to the size of its content.\n" .. + "Note that you probably don't want to query the window size to\n" .. + "output your content because that would create a feedback loop.") + s.lines = ImGui.SliderInt("Number of lines", s.lines, 1, 20) + for i = 0, s.lines - 1 do + ImGui.Text("%sThis is line %d", string.rep(" ", i * 4), i) -- Pad with space to extend size horizontally -- [Port] "%*s" -> string.rep + end ImGui.End() return p_open end @@ -26463,38 +30573,69 @@ end -- Demonstrate creating a window with custom resize constraints. -- Note that size constraints currently don't work on a docked window (when in 'docking' branch) --- Options -local CR = { auto_resize = false, window_padding = true, type = 6, display_lines = 10 } -- type 6: Aspect Ratio +CustomConstraints = {} +-- Helper functions to demonstrate programmatic constraints +-- FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier. +-- FIXME: None of the three demos works consistently when resizing from borders. +function CustomConstraints.AspectRatio(data) + local aspect_ratio = data.UserData -- [Port] UserData is the number itself (no float*) + data.DesiredSize.y = math.floor(data.DesiredSize.x / aspect_ratio) +end +function CustomConstraints.Square(data) + local m = ImMax(data.DesiredSize.x, data.DesiredSize.y) -- [Port] IM_MAX -> ImMax + data.DesiredSize.x = m; data.DesiredSize.y = m +end +function CustomConstraints.Step(data) + local step = data.UserData + data.DesiredSize = ImVec2(math.floor(data.DesiredSize.x / step + 0.5) * step, math.floor(data.DesiredSize.y / step + 0.5) * step) +end + +S.ShowExampleAppConstrainedResize = { + -- Options + auto_resize = false, + window_padding = true, + type = 6, -- Aspect Ratio + display_lines = 10, +} function ShowExampleAppConstrainedResize(p_open) - -- Helper functions to demonstrate programmatic constraints - -- FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier. - -- FIXME: None of the three demos works consistently when resizing from borders. - local function AspectRatio(data) data.DesiredSize.y = math.floor(data.DesiredSize.x / data.UserData) end - local function Square(data) local m = math.max(data.DesiredSize.x, data.DesiredSize.y); data.DesiredSize.x = m; data.DesiredSize.y = m end - local function Step(data) - local step = data.UserData - data.DesiredSize = ImVec2(math.floor(data.DesiredSize.x / step + 0.5) * step, math.floor(data.DesiredSize.y / step + 0.5) * step) - end - local test_desc = { "Between 100x100 and 500x500", "At least 100x100", "Resize vertical + lock current width", "Resize horizontal + lock current height", - "Width Between 400 and 500", "Height at least 400", "Custom: Aspect Ratio 16:9", "Custom: Always Square", "Custom: Fixed Steps (100)" } + local s = S.ShowExampleAppConstrainedResize + local test_desc = + { + "Between 100x100 and 500x500", + "At least 100x100", + "Resize vertical + lock current width", + "Resize horizontal + lock current height", + "Width Between 400 and 500", + "Height at least 400", + "Custom: Aspect Ratio 16:9", + "Custom: Always Square", + "Custom: Fixed Steps (100)", + } + -- Submit constraint - local t = CR.type - if t == 0 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)) end -- Between 100x100 and 500x500 - if t == 1 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]])) end -- Width > 100, Height > 100 - if t == 2 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, 3.4028234663853e+38 --[[FLT_MAX]])) end -- Resize vertical + lock current width - if t == 3 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], -1)) end -- Resize horizontal + lock current height - if t == 4 then ImGui.SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)) end -- Width Between and 400 and 500 - if t == 5 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 3.4028234663853e+38 --[[FLT_MAX]])) end -- Height at least 400 - if t == 6 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), AspectRatio, 16.0 / 9.0) end -- Aspect ratio - if t == 7 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), Square) end -- Always Square - if t == 8 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), Step, 100.0) end -- Fixed Step + local aspect_ratio = 16.0 / 9.0 + local fixed_step = 100.0 + if s.type == 0 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)) end -- Between 100x100 and 500x500 + if s.type == 1 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]])) end -- Width > 100, Height > 100 + if s.type == 2 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, 3.4028234663853e+38 --[[FLT_MAX]])) end -- Resize vertical + lock current width + if s.type == 3 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], -1)) end -- Resize horizontal + lock current height + if s.type == 4 then ImGui.SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)) end -- Width Between and 400 and 500 + if s.type == 5 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 3.4028234663853e+38 --[[FLT_MAX]])) end -- Height at least 400 + if s.type == 6 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), CustomConstraints.AspectRatio, aspect_ratio) end -- Aspect ratio + if s.type == 7 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), CustomConstraints.Square) end -- Always Square + if s.type == 8 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), CustomConstraints.Step, fixed_step) end -- Fixed Step -- Submit window - if not CR.window_padding then ImGui.PushStyleVar(2 --[[ImGuiStyleVar.WindowPadding]], ImVec2(0.0, 0.0)) end - local window_flags = CR.auto_resize and 64 --[[ImGuiWindowFlags.AlwaysAutoResize]] or 0 + if not s.window_padding then + ImGui.PushStyleVar(2 --[[ImGuiStyleVar.WindowPadding]], ImVec2(0.0, 0.0)) + end + local window_flags = s.auto_resize and 64 --[[ImGuiWindowFlags.AlwaysAutoResize]] or 0 local window_open p_open, window_open = ImGui.Begin("Example: Constrained Resize", p_open, window_flags) - if not CR.window_padding then ImGui.PopStyleVar() end + if not s.window_padding then + ImGui.PopStyleVar() + end + IMGUI_DEMO_MARKER("Examples/Constrained Resizing window") if window_open then if ImGui.GetIO().KeyShift then -- Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture) @@ -26505,17 +30646,21 @@ function ShowExampleAppConstrainedResize(p_open) ImGui.Text("%.2f x %.2f", avail_size.x, avail_size.y) else ImGui.Text("(Hold Shift to display a dummy viewport)") - if ImGui.IsWindowDocked() then ImGui.Text("Warning: Sizing Constraints won't work if the window is docked!") end + if ImGui.IsWindowDocked() then + ImGui.Text("Warning: Sizing Constraints won't work if the window is docked!") + end if ImGui.Button("Set 200x200") then ImGui.SetWindowSize(ImVec2(200, 200)) end ImGui.SameLine() if ImGui.Button("Set 500x500") then ImGui.SetWindowSize(ImVec2(500, 500)) end ImGui.SameLine() if ImGui.Button("Set 800x200") then ImGui.SetWindowSize(ImVec2(800, 200)) end ImGui.SetNextItemWidth(ImGui.GetFontSize() * 20) - CR.type = ImGui.Combo("Constraint", CR.type, test_desc, #test_desc) + s.type = ImGui.Combo("Constraint", s.type, test_desc, #test_desc) ImGui.SetNextItemWidth(ImGui.GetFontSize() * 20) - CR.display_lines = ImGui.DragInt("Lines", CR.display_lines, 0.2, 1, 100) - _, CR.auto_resize = ImGui.Checkbox("Auto-resize", CR.auto_resize) - _, CR.window_padding = ImGui.Checkbox("Window padding", CR.window_padding) - for i = 0, CR.display_lines - 1 do ImGui.Text("%sHello, sailor! Making this line long enough for the example.", string.rep(" ", i * 4)) end + s.display_lines = ImGui.DragInt("Lines", s.display_lines, 0.2, 1, 100) + _, s.auto_resize = ImGui.Checkbox("Auto-resize", s.auto_resize) + _, s.window_padding = ImGui.Checkbox("Window padding", s.window_padding) + for i = 0, s.display_lines - 1 do + ImGui.Text("%sHello, sailor! Making this line long enough for the example.", string.rep(" ", i * 4)) -- [Port] "%*s" -> string.rep + end end end ImGui.End() @@ -26528,40 +30673,50 @@ end -- Demonstrate creating a simple static window with no decoration -- + a context-menu to choose which corner of the screen to use. -local OverlayLocation = 0 +S.ShowExampleAppSimpleOverlay = { + location = 0, +} function ShowExampleAppSimpleOverlay(p_open) + local s = S.ShowExampleAppSimpleOverlay local io = ImGui.GetIO() - local W = ImGuiWindowFlags - local window_flags = bit32.bor(W.NoDecoration, W.NoDocking, W.AlwaysAutoResize, W.NoSavedSettings, W.NoFocusOnAppearing, W.NoNav) - if OverlayLocation >= 0 then + local window_flags = bit32.bor(43 --[[ImGuiWindowFlags.NoDecoration]], 524288 --[[ImGuiWindowFlags.NoDocking]], 64 --[[ImGuiWindowFlags.AlwaysAutoResize]], 256 --[[ImGuiWindowFlags.NoSavedSettings]], 4096 --[[ImGuiWindowFlags.NoFocusOnAppearing]], 196608 --[[ImGuiWindowFlags.NoNav]]) + if s.location >= 0 then local PAD = 10.0 local viewport = ImGui.GetMainViewport() - local work_pos, work_size = viewport.WorkPos, viewport.WorkSize -- Use work area to avoid menu-bar/task-bar, if any! - local right, bottom = OverlayLocation % 2 == 1, OverlayLocation >= 2 - local window_pos = ImVec2(right and (work_pos.x + work_size.x - PAD) or (work_pos.x + PAD), bottom and (work_pos.y + work_size.y - PAD) or (work_pos.y + PAD)) - local window_pos_pivot = ImVec2(right and 1.0 or 0.0, bottom and 1.0 or 0.0) + local work_pos = viewport.WorkPos -- Use work area to avoid menu-bar/task-bar, if any! + local work_size = viewport.WorkSize + local window_pos, window_pos_pivot = ImVec2(), ImVec2() + window_pos.x = (bit32.band(s.location, 1) ~= 0) and (work_pos.x + work_size.x - PAD) or (work_pos.x + PAD) + window_pos.y = (bit32.band(s.location, 2) ~= 0) and (work_pos.y + work_size.y - PAD) or (work_pos.y + PAD) + window_pos_pivot.x = (bit32.band(s.location, 1) ~= 0) and 1.0 or 0.0 + window_pos_pivot.y = (bit32.band(s.location, 2) ~= 0) and 1.0 or 0.0 ImGui.SetNextWindowPos(window_pos, 1 --[[ImGuiCond.Always]], window_pos_pivot) ImGui.SetNextWindowViewport(viewport.ID) - window_flags = bit32.bor(window_flags, W.NoMove) - elseif OverlayLocation == -2 then + window_flags = bit32.bor(window_flags, 4 --[[ImGuiWindowFlags.NoMove]]) + elseif s.location == -2 then -- Center window ImGui.SetNextWindowPos(ImGui.GetMainViewport():GetCenter(), 1 --[[ImGuiCond.Always]], ImVec2(0.5, 0.5)) - window_flags = bit32.bor(window_flags, W.NoMove) + window_flags = bit32.bor(window_flags, 4 --[[ImGuiWindowFlags.NoMove]]) end ImGui.SetNextWindowBgAlpha(0.35) -- Transparent background local visible p_open, visible = ImGui.Begin("Example: Simple overlay", p_open, window_flags) if visible then - ImGui.Text("Simple overlay\n(right-click to change position)") + IMGUI_DEMO_MARKER("Examples/Simple overlay") -- Scroll up to the beginning of this function to see overlay flags + ImGui.Text("Simple overlay\n" .. "(right-click to change position)") ImGui.Separator() - if ImGui.IsMousePosValid() then ImGui.Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y) else ImGui.Text("Mouse Position: ") end + if ImGui.IsMousePosValid() then + ImGui.Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y) + else + ImGui.Text("Mouse Position: ") + end if ImGui.BeginPopupContextWindow() then - if ImGui.MenuItem("Custom", nil, OverlayLocation == -1) then OverlayLocation = -1 end - if ImGui.MenuItem("Center", nil, OverlayLocation == -2) then OverlayLocation = -2 end - if ImGui.MenuItem("Top-left", nil, OverlayLocation == 0) then OverlayLocation = 0 end - if ImGui.MenuItem("Top-right", nil, OverlayLocation == 1) then OverlayLocation = 1 end - if ImGui.MenuItem("Bottom-left", nil, OverlayLocation == 2) then OverlayLocation = 2 end - if ImGui.MenuItem("Bottom-right", nil, OverlayLocation == 3) then OverlayLocation = 3 end + if ImGui.MenuItem("Custom", nil, s.location == -1) then s.location = -1 end + if ImGui.MenuItem("Center", nil, s.location == -2) then s.location = -2 end + if ImGui.MenuItem("Top-left", nil, s.location == 0) then s.location = 0 end + if ImGui.MenuItem("Top-right", nil, s.location == 1) then s.location = 1 end + if ImGui.MenuItem("Bottom-left", nil, s.location == 2) then s.location = 2 end + if ImGui.MenuItem("Bottom-right", nil, s.location == 3) then s.location = 3 end if p_open ~= nil and ImGui.MenuItem("Close") then p_open = false end ImGui.EndPopup() end @@ -26575,28 +30730,38 @@ end ------------------------------------------------------------------------------- -- Demonstrate creating a window covering the entire screen/viewport -local FS = { use_work_area = true, flags = bit32.bor(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings) } +S.ShowExampleAppFullscreen = { + use_work_area = true, + flags = bit32.bor(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings), +} function ShowExampleAppFullscreen(p_open) + local s = S.ShowExampleAppFullscreen + -- We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.) -- Based on your use case you may want one or the other. local viewport = ImGui.GetMainViewport() - ImGui.SetNextWindowPos(FS.use_work_area and viewport.WorkPos or viewport.Pos) - ImGui.SetNextWindowSize(FS.use_work_area and viewport.WorkSize or viewport.Size) + ImGui.SetNextWindowPos(s.use_work_area and viewport.WorkPos or viewport.Pos) + ImGui.SetNextWindowSize(s.use_work_area and viewport.WorkSize or viewport.Size) + local visible - p_open, visible = ImGui.Begin("Example: Fullscreen window", p_open, FS.flags) + p_open, visible = ImGui.Begin("Example: Fullscreen window", p_open, s.flags) if visible then - _, FS.use_work_area = ImGui.Checkbox("Use work area instead of main area", FS.use_work_area) + IMGUI_DEMO_MARKER("Examples/Fullscreen window") + _, s.use_work_area = ImGui.Checkbox("Use work area instead of main area", s.use_work_area) ImGui.SameLine() HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference.") - local W = ImGuiWindowFlags - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoBackground", FS.flags, W.NoBackground) - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoDecoration", FS.flags, W.NoDecoration) + + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoBackground", s.flags, 128 --[[ImGuiWindowFlags.NoBackground]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoDecoration", s.flags, 43 --[[ImGuiWindowFlags.NoDecoration]]) ImGui.Indent() - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoTitleBar", FS.flags, W.NoTitleBar) - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoCollapse", FS.flags, W.NoCollapse) - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoScrollbar", FS.flags, W.NoScrollbar) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoTitleBar", s.flags, 1 --[[ImGuiWindowFlags.NoTitleBar]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoCollapse", s.flags, 32 --[[ImGuiWindowFlags.NoCollapse]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoScrollbar", s.flags, 8 --[[ImGuiWindowFlags.NoScrollbar]]) ImGui.Unindent() - if p_open ~= nil and ImGui.Button("Close this window") then p_open = false end + + if p_open ~= nil and ImGui.Button("Close this window") then + p_open = false + end end ImGui.End() return p_open @@ -26619,19 +30784,22 @@ function ShowExampleAppWindowTitles(p_open) -- Using "##" to display same title but have unique identifier. ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), 4 --[[ImGuiCond.FirstUseEver]]) ImGui.Begin("Same title as another window##1") + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##1") ImGui.Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.") ImGui.End() + ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), 4 --[[ImGuiCond.FirstUseEver]]) ImGui.Begin("Same title as another window##2") + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##2") ImGui.Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.") ImGui.End() -- Using "###" to display a changing title but keep a static identifier "AnimatedTitle" - local spin = "|/-\\" - local k = math.floor(ImGui.GetTime() / 0.25) % 4 + 1 - local buf = string.format("Animated title %s %d###AnimatedTitle", string.sub(spin, k, k), ImGui.GetFrameCount()) + local spin_i = bit32.band(math.floor(ImGui.GetTime() / 0.25), 3) + 1 + local buf = string.format("Animated title %s %d###AnimatedTitle", string.sub("|/-\\", spin_i, spin_i), ImGui.GetFrameCount()) ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), 4 --[[ImGuiCond.FirstUseEver]]) ImGui.Begin(buf) + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##3") ImGui.Text("This window has a changing title.") ImGui.End() return p_open @@ -26646,297 +30814,406 @@ end -- - Pixel Perfect Anti-aliased Rendering: https://github.com/ocornut/imgui/wiki/Pixel-Perfect-Rendering -- - How Anti-aliased Polyline Rendering is Implemented: https://github.com/ocornut/imgui/wiki/Polyline-Rendering -local CRS = { sz = 42.0, base_rounding = 8.0, base_thickness = 3.0, animate_rounding = false, animate_thickness = false, ngon_segments = 6, - circle_override = false, circle_override_v = 12, curve_override = false, curve_override_v = 8, - colf_stroke = ImVec4(1.000, 0.384, 0.169, 1.000), colf_fill = ImVec4(0.416, 0.378, 0.420, 1.000), - points = {}, scrolling = ImVec2(0.0, 0.0), opt_enable_grid = true, opt_enable_context_menu = true, adding_line = false, - draw_bg = true, draw_fg = true } - -local function CustomRenderingPrimitives() - local s = CRS - ImGui.PushItemWidth(-ImGui.GetFontSize() * 15) - ImGui.PushItemFlag(384 --[[ImGuiItemFlags.LiveEditOnInput]], true) - local draw_list = ImGui.GetWindowDrawList() - - -- Draw gradients - -- (note that those are currently exacerbating our sRGB/Linear issues) - -- Calling ImGui.GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. - ImGui.Text("Gradients") - local gradient_size = ImVec2(ImGui.CalcItemWidth(), ImGui.GetFrameHeight()) - ImGui.InvisibleButton("##gradient1", gradient_size) - local col_a, col_b = ImGui.GetColorU32(IM_COL32(0, 0, 0, 255), nil, true), ImGui.GetColorU32(IM_COL32(255, 255, 255, 255), nil, true) - draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) - ImGui.InvisibleButton("##gradient2", gradient_size) - col_a, col_b = ImGui.GetColorU32(IM_COL32(0, 255, 0, 255), nil, true), ImGui.GetColorU32(IM_COL32(255, 0, 0, 255), nil, true) - draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) - - -- Draw a bunch of primitives - ImGui.Text("All primitives") - s.sz = ImGui.DragFloat("Size", s.sz, 0.2, 0.2, 100.0, "%.0f") - local t = ImGui.GetTime() - local rounding_wave = 1.0 - math.abs((t % 3.0) * (2.0 / 3.0) - 1.0) - local rounding = s.animate_rounding and (math.floor(rounding_wave * s.base_rounding * 10.0) / 10.0) or s.base_rounding -- Sub-integer rounding works but has discontinuities in small values, so best disable we - s.base_rounding = ImGui.DragFloat("Rounding", s.base_rounding, 0.02, 0.0, 32.0, "%.1f"); ImGui.SameLine() - _, s.animate_rounding = ImGui.Checkbox("Animate##rounding", s.animate_rounding); ImGui.SameLine() - ImGui.Text("%.2f", rounding) - local thickness_wave = 1.0 - math.abs((t % 5.0) * (2.0 / 5.0) - 1.0) - local thickness = s.animate_thickness and (thickness_wave * s.base_thickness) or s.base_thickness - s.base_thickness = ImGui.DragFloat("Thickness", s.base_thickness, 0.02, 0.0, 32.0, "%.02f"); ImGui.SameLine() - _, s.animate_thickness = ImGui.Checkbox("Animate##thickness", s.animate_thickness); ImGui.SameLine() - ImGui.Text("%.2f", thickness) - s.ngon_segments = ImGui.SliderInt("N-gon sides", s.ngon_segments, 3, 12) - local changed - _, s.circle_override = ImGui.Checkbox("##CircleSegmentOverride", s.circle_override) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - s.circle_override_v, changed = ImGui.SliderInt("Circle segments override", s.circle_override_v, 3, 30) - s.circle_override = s.circle_override or changed - _, s.curve_override = ImGui.Checkbox("##CurvesSegmentOverride", s.curve_override) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - s.curve_override_v, changed = ImGui.SliderInt("Curves segments override", s.curve_override_v, 3, 30) - s.curve_override = s.curve_override or changed - ImGui.ColorEdit4("Stroke Color", s.colf_stroke) - ImGui.ColorEdit4("Fill Color", s.colf_fill) - ImGui.SeparatorText("Per primitive flags (AddXXX functions)") - ImGui.TextDisabled("(stroke placement/AA flags: not ported, this port uses the 1.92 stroker)") - ImGui.Spacing() - - local sz = s.sz - local start_pos = ImGui.GetCursorScreenPos() - local pi = 3.141592 - local step = sz + 10.0 - local corners_tl_br = bit32.bor(16 --[[ImDrawFlags.RoundCornersTopLeft]], 128 --[[ImDrawFlags.RoundCornersBottomRight]]) - local half_sz = sz * 0.5 - local circle_segments = s.circle_override and s.circle_override_v or 0 - local curve_segments = s.curve_override and s.curve_override_v or 0 - local cp3 = { ImVec2(0.0, sz * 0.6), ImVec2(sz * 0.5, -sz * 0.4), ImVec2(sz, sz) } -- Control points for curves - local cp4 = { ImVec2(0.0, 0.0), ImVec2(sz * 1.3, sz * 0.3), ImVec2(sz - sz * 1.3, sz - sz * 0.3), ImVec2(sz, sz) } - local concave_shape = { { 0.0, 0.0 }, { 0.3, 0.0 }, { 0.3, 0.7 }, { 0.7, 0.7 }, { 0.7, 0.0 }, { 1.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 1.0 } } -- |_| looking shape. Normalized. - local zigzag_shape = { { 0.0, 0.0 }, { 0.9, 0.0 }, { 1.0, 0.1 }, { 1.0, 0.9 }, { 0.9, 1.0 }, { 0.3, 1.0 }, { 0.3, 0.4 }, { 0.9, 0.4 } } - local rotating_square = {} - for side = 0, 3 do - local a = t * 0.1 + side * pi * 0.5 - rotating_square[side + 1] = ImVec2(math.cos(a) * half_sz, math.sin(a) * half_sz) - end - local function Shape(shape, x, y) - for _, p in ipairs(shape) do draw_list:PathLineTo(ImVec2(x + math.floor(sz * p[1]), y + math.floor(sz * p[2]))) end - end - - local y = start_pos.y - for row = 0, 3 do - local x = start_pos.x - local draw_fill = (row == 2 or row == 3) - local draw_strokes = (row == 0 or row == 1 or row == 3) - if draw_fill then - -- FILLED SHAPES - local col = ImGui.ColorConvertFloat4ToU32(s.colf_fill) - draw_list:AddNgonFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments); x = x + step -- N-gon - draw_list:AddCircleFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments); x = x + step -- Circle - draw_list:AddEllipseFilled(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments); x = x + step -- Ellipse - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x = x + step -- Square - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding); x = x + step -- Square with all rounded corners - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br); x = x + step -- Square with two rounded corners - draw_list:AddTriangleFilled(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col); x = x + step -- Triangle - draw_list:AddTriangleFilled(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col); x = x + step - math.floor(sz * 0.6) -- Thin triangle - - -- Concave shape: U - Shape(concave_shape, x, y); draw_list:PathFillConcave(col); x = x + step - - -- Concave shape: Zig-Zag with sharp angles - Shape(zigzag_shape, x, y); draw_list:PathFillConcave(col); x = x + step - - -- Horizontal/Vertical lines - -- (here for consistency with the strokes section. AddRectFilled() is roughly close to AddLineH(), AddLineV() - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x = x + step - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x = x + step - math.floor(half_sz) - if not (draw_fill and draw_strokes) then - local block_sz, off = 1, 0 - while block_sz < 16 and off + block_sz <= sz do - draw_list:AddRectFilled(ImVec2(x, y + off), ImVec2(x + block_sz, y + off + block_sz), col) - off = off + block_sz + 1 - block_sz = block_sz + 1 - end - end - x = x + step - math.floor(half_sz) - - -- Rotating square - for n = 1, 4 do draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y)) end - draw_list:PathFillConvex(col); x = x + step - - -- Path - draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) - draw_list:PathFillConvex(col); x = x + step - - -- Quadratic Bezier Curve (3 control points) - draw_list:PathLineTo(ImVec2(x + cp3[1].x, y + cp3[1].y)) - draw_list:PathBezierQuadraticCurveTo(ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), curve_segments) - draw_list:PathFillConvex(col); x = x + step - if not (draw_fill and draw_strokes) then - draw_list:AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)) - x = x + step - end - end - if draw_fill and draw_strokes then x = start_pos.x end - if draw_strokes then - -- STROKES - -- First row uses a thickness of 1.0f, second row uses the configurable thickness - local col = ImGui.ColorConvertFloat4ToU32(s.colf_stroke) - local th = (row == 0) and 1.0 or thickness - draw_list:AddNgon(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments, th); x = x + step -- N-gon - draw_list:AddCircle(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments, th); x = x + step -- Circle - draw_list:AddEllipse(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments, th); x = x + step -- Ellipse - draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, th); x = x + step -- Square - draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th); x = x + step -- Square with all rounded corners - draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, corners_tl_br); x = x + step -- Square with two rounded corners - draw_list:AddTriangle(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col, th); x = x + step -- Triangle - draw_list:AddTriangle(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col, th); x = x + step - math.floor(sz * 0.6) -- Thin triangle - - -- Concave shape: U - Shape(concave_shape, x, y); draw_list:PathStroke(col, th, 512 --[[ImDrawFlags.Closed]]); x = x + step - - -- Concave shape: Zig-Zag with sharp angles - Shape(zigzag_shape, x, y); draw_list:PathStroke(col, th, 512 --[[ImDrawFlags.Closed]]); x = x + step - - -- Horizontal/Vertical/Diagonal lines - local off = math.floor(sz * 0.4) - draw_list:AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th) - draw_list:AddLine(ImVec2(x, y + off), ImVec2(x + sz, y + off), col, th); x = x + step - draw_list:AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th) - draw_list:AddLine(ImVec2(x + off, y + sz), ImVec2(x + off, y), col, th); x = x + step - math.floor(half_sz) - if not (draw_fill and draw_strokes) then - draw_list:AddLine(ImVec2(x, y), ImVec2(x + half_sz, y + sz), col, th) - draw_list:AddLine(ImVec2(x, y + sz), ImVec2(x + half_sz, y), col, th) - end - x = x + step - math.floor(half_sz) - - -- Rotating square - for n = 1, 4 do draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y)) end - draw_list:PathStroke(col, th, 512 --[[ImDrawFlags.Closed]]); x = x + step - - -- Path - draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) - draw_list:PathStroke(col, th); x = x + step - - -- Quadratic Bezier Curve (3 control points) - draw_list:AddBezierQuadratic(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), col, th, curve_segments); x = x + step - - -- Cubic Bezier Curve (4 control points) - if not (draw_fill and draw_strokes) then - draw_list:AddBezierCubic(ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), ImVec2(x + cp4[4].x, y + cp4[4].y), col, th, curve_segments) - x = x + step - end - end - y = y + step - end - ImGui.Dummy(ImVec2(step * 15.5, step * 4.0)) - ImGui.Text("ImDrawList Vector Rendering Reference:") - ImGui.TextLinkOpenURL("https://github.com/ocornut/imgui/wiki/Draw-List") - ImGui.PopItemFlag() - ImGui.PopItemWidth() -end - -local function CustomRenderingCanvas() - local s = CRS - _, s.opt_enable_grid = ImGui.Checkbox("Enable grid", s.opt_enable_grid) - _, s.opt_enable_context_menu = ImGui.Checkbox("Enable context menu", s.opt_enable_context_menu) - ImGui.Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.") - - -- Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. - -- Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. - -- To use a child window instead we could use, e.g: - -- ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0, 0)) -- Disable padding - -- ImGui.PushStyleColor(ImGuiCol.ChildBg, IM_COL32(50, 50, 50, 255)) -- Set a background color - -- ImGui.BeginChild("canvas", ImVec2(0.0, 0.0), ImGuiChildFlags.Borders, ImGuiWindowFlags.NoMove) - -- ImGui.PopStyleColor() - -- ImGui.PopStyleVar() - -- [...] - -- ImGui.EndChild() - - -- Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() - local canvas_p0 = ImGui.GetCursorScreenPos() -- ImDrawList API uses screen coordinates! - local canvas_sz = ImGui.GetContentRegionAvail() -- Resize canvas to what's available - if canvas_sz.x < 50.0 then canvas_sz.x = 50.0 end - if canvas_sz.y < 50.0 then canvas_sz.y = 50.0 end - local canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y) - - -- Draw border and background color - local io = ImGui.GetIO() - local draw_list = ImGui.GetWindowDrawList() - draw_list:AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)) - draw_list:AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)) - - -- This will catch our interactions - ImGui.InvisibleButton("canvas", canvas_sz, bit32.bor(1 --[[ImGuiButtonFlags.MouseButtonLeft]], 2 --[[ImGuiButtonFlags.MouseButtonRight]])) - local is_hovered = ImGui.IsItemHovered() -- Hovered - local is_active = ImGui.IsItemActive() -- Held - local origin = ImVec2(canvas_p0.x + s.scrolling.x, canvas_p0.y + s.scrolling.y) -- Lock scrolled origin - local mouse_pos_in_canvas = ImVec2(io.MousePos.x - origin.x, io.MousePos.y - origin.y) - local points = s.points - - -- Add first and second point - if is_hovered and not s.adding_line and ImGui.IsMouseClicked(0 --[[ImGuiMouseButton.Left]]) then - points[#points + 1] = ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y) - points[#points + 1] = ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y) - s.adding_line = true - end - if s.adding_line then - points[#points] = ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y) - if not ImGui.IsMouseDown(0 --[[ImGuiMouseButton.Left]]) then s.adding_line = false end - end - - -- Pan (we use a zero mouse threshold when there's no context menu) - -- You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. - local mouse_threshold_for_pan = s.opt_enable_context_menu and -1.0 or 0.0 - if is_active and ImGui.IsMouseDragging(1 --[[ImGuiMouseButton.Right]], mouse_threshold_for_pan) then - s.scrolling.x = s.scrolling.x + io.MouseDelta.x - s.scrolling.y = s.scrolling.y + io.MouseDelta.y - end - - -- Context menu (under default mouse threshold) - local drag_delta = ImGui.GetMouseDragDelta(1 --[[ImGuiMouseButton.Right]]) - if s.opt_enable_context_menu and drag_delta.x == 0.0 and drag_delta.y == 0.0 then - ImGui.OpenPopupOnItemClick("context", 8 --[[ImGuiPopupFlags.MouseButtonRight]]) - end - if ImGui.BeginPopup("context") then - if s.adding_line then points[#points] = nil; points[#points] = nil end - s.adding_line = false - if ImGui.MenuItem("Remove one", nil, false, #points > 0) then points[#points] = nil; points[#points] = nil end - if ImGui.MenuItem("Remove all", nil, false, #points > 0) then table.clear(points) end - ImGui.EndPopup() - end - - -- Draw grid + all lines in the canvas - draw_list:PushClipRect(canvas_p0, canvas_p1, true) - if s.opt_enable_grid then - local GRID_STEP = 64.0 - local x = math.fmod(s.scrolling.x, GRID_STEP) - while x < canvas_sz.x do draw_list:AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40)); x = x + GRID_STEP end - local y = math.fmod(s.scrolling.y, GRID_STEP) - while y < canvas_sz.y do draw_list:AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40)); y = y + GRID_STEP end - end - for n = 1, #points - 1, 2 do - draw_list:AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0) - end - draw_list:PopClipRect() -end - -- Demonstrate using the low-level ImDrawList to draw custom shapes. +S.ShowExampleAppCustomRendering = { + -- Primitives + sz = 42.0, + base_rounding = 8.0, + base_thickness = 3.0, + animate_rounding = false, + animate_thickness = false, + ngon_segments = 6, + circle_segments_override = false, + circle_segments_override_v = 12, + curve_segments_override = false, + curve_segments_override_v = 8, + colf_stroke = ImVec4(1.000, 0.384, 0.169, 1.000), + colf_fill = ImVec4(0.416, 0.378, 0.420, 1.000), + -- Canvas + points = ImVector(), + scrolling = ImVec2(0.0, 0.0), + opt_enable_grid = true, + opt_enable_context_menu = true, + adding_line = false, + -- BG/FG draw lists + draw_bg = true, + draw_fg = true, +} function ShowExampleAppCustomRendering(p_open) + local s = S.ShowExampleAppCustomRendering local visible p_open, visible = ImGui.Begin("Example: Custom rendering", p_open) - if not visible then ImGui.End(); return p_open end - local s = CRS + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Examples/Custom rendering") + + -- Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of + -- overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your + -- types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not + -- exposed outside (to avoid messing with your types) In this example we are not using the maths operators! + if ImGui.BeginTabBar("##TabBar") then - if ImGui.BeginTabItem("Primitives") then CustomRenderingPrimitives(); ImGui.EndTabItem() end - if ImGui.BeginTabItem("Canvas") then CustomRenderingCanvas(); ImGui.EndTabItem() end + if ImGui.BeginTabItem("Primitives") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/Primitives") + ImGui.PushItemWidth(-ImGui.GetFontSize() * 15) + ImGui.PushItemFlag(384 --[[ImGuiItemFlags.LiveEditOnInput]], true) + local draw_list = ImGui.GetWindowDrawList() + + -- Draw gradients + -- (note that those are currently exacerbating our sRGB/Linear issues) + -- Calling ImGui.GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. + -- [Port] GetColorU32(u32, nil, true): the ImU32 overload is selected explicitly + ImGui.Text("Gradients") + local gradient_size = ImVec2(ImGui.CalcItemWidth(), ImGui.GetFrameHeight()) + do + ImGui.InvisibleButton("##gradient1", gradient_size) + local col_a = ImGui.GetColorU32(IM_COL32(0, 0, 0, 255), nil, true) + local col_b = ImGui.GetColorU32(IM_COL32(255, 255, 255, 255), nil, true) + draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) + end + do + ImGui.InvisibleButton("##gradient2", gradient_size) + local col_a = ImGui.GetColorU32(IM_COL32(0, 255, 0, 255), nil, true) + local col_b = ImGui.GetColorU32(IM_COL32(255, 0, 0, 255), nil, true) + draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) + end + + -- Draw a bunch of primitives + ImGui.Text("All primitives") + + s.sz = ImGui.DragFloat("Size", s.sz, 0.2, 0.2, 100.0, "%.0f") + + local rounding_anim_period = 3.0 + local rounding_wave = 1.0 - math.abs(math.fmod(ImGui.GetTime(), rounding_anim_period) * (2.0 / rounding_anim_period) - 1.0) + local rounding = s.animate_rounding and math.floor(rounding_wave * s.base_rounding * 10.0) / 10.0 or s.base_rounding -- Sub-integer rounding works but has discontinuities in small values, so best disable we + s.base_rounding = ImGui.DragFloat("Rounding", s.base_rounding, 0.02, 0.0, 32.0, "%.1f"); ImGui.SameLine() + _, s.animate_rounding = ImGui.Checkbox("Animate##rounding", s.animate_rounding); ImGui.SameLine() + ImGui.Text("%.2f", rounding) + + local thickness_anim_period = 5.0 + local thickness_wave = 1.0 - math.abs(math.fmod(ImGui.GetTime(), thickness_anim_period) * (2.0 / thickness_anim_period) - 1.0) + local thickness = s.animate_thickness and thickness_wave * s.base_thickness or s.base_thickness + s.base_thickness = ImGui.DragFloat("Thickness", s.base_thickness, 0.02, 0.0, 32.0, "%.02f"); ImGui.SameLine() + _, s.animate_thickness = ImGui.Checkbox("Animate##thickness", s.animate_thickness); ImGui.SameLine() + ImGui.Text("%.2f", thickness) + + local changed + s.ngon_segments = ImGui.SliderInt("N-gon sides", s.ngon_segments, 3, 12) + _, s.circle_segments_override = ImGui.Checkbox("##CircleSegmentOverride", s.circle_segments_override) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + s.circle_segments_override_v, changed = ImGui.SliderInt("Circle segments override", s.circle_segments_override_v, 3, 30) + s.circle_segments_override = s.circle_segments_override or changed + _, s.curve_segments_override = ImGui.Checkbox("##CurvesSegmentOverride", s.curve_segments_override) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + s.curve_segments_override_v, changed = ImGui.SliderInt("Curves segments override", s.curve_segments_override_v, 3, 30) + s.curve_segments_override = s.curve_segments_override or changed + ImGui.ColorEdit4("Stroke Color", s.colf_stroke) + ImGui.ColorEdit4("Fill Color", s.colf_fill) + + -- [Port] ImDrawFlags_StrokeInside/StrokeCenter/StrokeCenterBiased/StrokeOutside/StrokeLegacy, AAFill/AALines/AALineEnds, + -- [Port] JoinMiter/CapSquare, AllowInPushScope_ and ImDrawList::PushDrawFlag()/PopDrawFlag() don't exist in this port + -- [Port] (1.92 stroker): prim_stroke_flags/prim_other_flags/scope_flags and their widgets are not ported, flags = None. + ImGui.SeparatorText("Per primitive flags (AddXXX functions)") + ImGui.TextDisabled("(not supported by this port)") -- [Port] + --ImGui.CheckboxFlags("UseTexForRoundCorners", &prim_other_flags, ImDrawFlags_UseTexForRoundCorners); + + ImGui.SeparatorText("Current ImDrawList flags (e.g. PushDrawFlag function)") + ImGui.PushID("ScopeFlags") + ImGui.TextDisabled("(not supported by this port)") -- [Port] + --ImGui.CheckboxFlags("UseTexForRoundCorners", &scope_flags, ImDrawFlags_UseTexForRoundCorners); + ImGui.PopID() + ImGui.Spacing() + + -- [Port] draw_list->PushDrawFlag(ImDrawFlags_AllowInPushScope_, false); // Reset all existing (very unusual: done for this demo) + -- [Port] draw_list->PushDrawFlag(scope_flags, true); + local flags = 0 --[[ImDrawFlags.None]] -- [Port] prim_stroke_flags | prim_other_flags + + -- [Port] In this port AddNgon/AddCircle/AddEllipse/AddTriangle/AddLine*/AddBezier*/PathFillConvex take no flags argument (dropped below). + local sz = s.sz + local start_pos = ImGui.GetCursorScreenPos() + local pi = 3.141592 + local step = sz + 10.0 + local corners_tl_br = bit32.bor(16 --[[ImDrawFlags.RoundCornersTopLeft]], 128 --[[ImDrawFlags.RoundCornersBottomRight]]) -- [Port] 1.92 names (upstream ImDrawFlags_RoundTopLeft/RoundBottomRight) + local half_sz = sz * 0.5 + local circle_segments = s.circle_segments_override and s.circle_segments_override_v or 0 + local curve_segments = s.curve_segments_override and s.curve_segments_override_v or 0 + local cp3 = { ImVec2(0.0, sz * 0.6), ImVec2(sz * 0.5, -sz * 0.4), ImVec2(sz, sz) } -- Control points for curves + local cp4 = { ImVec2(0.0, 0.0), ImVec2(sz * 1.3, sz * 0.3), ImVec2(sz - sz * 1.3, sz - sz * 0.3), ImVec2(sz, sz) } + local concave_shape = { ImVec2(0.0, 0.0), ImVec2(0.3, 0.0), ImVec2(0.3, 0.7), ImVec2(0.7, 0.7), ImVec2(0.7, 0.0), ImVec2(1.0, 0.0), ImVec2(1.0, 1.0), ImVec2(0.0, 1.0) } -- |_| looking shape. Normalized. + local zigzag_shape = { ImVec2(0.0, 0.0), ImVec2(0.9, 0.0), ImVec2(1.0, 0.1), ImVec2(1.0, 0.9), ImVec2(0.9, 1.0), ImVec2(0.3, 1.0), ImVec2(0.3, 0.4), ImVec2(0.9, 0.4) } + local rotating_square = {} -- 1-based + for side = 0, 4 - 1 do + local t = ImGui.GetTime() * 0.1 + side * pi * 0.5 + rotating_square[side + 1] = ImVec2(math.cos(t) * half_sz, math.sin(t) * half_sz) + end + + local x = start_pos.x + local y = start_pos.y + for row = 0, 4 - 1 do + x = start_pos.x + local draw_fill = (row == 2 or row == 3) + local draw_strokes = (row == 0 or row == 1 or row == 3) + if draw_fill then + -- FILLED SHAPES + local col = ImColor(s.colf_fill):U32() + draw_list:AddNgonFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments); x = x + step -- N-gon + draw_list:AddCircleFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments); x = x + step -- Circle + draw_list:AddEllipseFilled(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments); x = x + step -- Ellipse + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, flags); x = x + step -- Square + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, flags); x = x + step -- Square with all rounded corners + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, bit32.bor(flags, corners_tl_br)); x = x + step -- Square with two rounded corners + draw_list:AddTriangleFilled(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col); x = x + step -- Triangle + draw_list:AddTriangleFilled(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col); x = x + step - math.floor(sz * 0.6) -- Thin triangle + + -- Concave shape: U + for _, p in ipairs(concave_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathFillConcave(col) + x = x + step + + -- Concave shape: Zig-Zag with sharp angles (see difference with/without JoinMiter) + for _, p in ipairs(zigzag_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathFillConcave(col) + x = x + step + + -- Horizontal/Vertical lines + -- (here for consistency with the strokes section. AddRectFilled() is roughly close to AddLineH(), AddLineV() + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x = x + step + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x = x + step - math.floor(half_sz) + if not (draw_fill and draw_strokes) then -- -V560 + local block_sz, off = 1, 0 + while block_sz < 16 and off + block_sz <= sz do + draw_list:AddRectFilled(ImVec2(x, y + off), ImVec2(x + block_sz, y + off + block_sz), col) + off = off + block_sz + 1; block_sz = block_sz + 1 + end + end + x = x + step - math.floor(half_sz) + + -- Rotating square + for n = 0, 4 - 1 do + draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n + 1].x, y + half_sz + rotating_square[n + 1].y)) + end + draw_list:PathFillConvex(col) -- [Port] no flags argument + x = x + step + + -- Path + draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) + draw_list:PathFillConvex(col) + x = x + step + + -- Quadratic Bezier Curve (3 control points) + draw_list:PathLineTo(ImVec2(x + cp3[1].x, y + cp3[1].y)) + draw_list:PathBezierQuadraticCurveTo(ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), curve_segments) + draw_list:PathFillConvex(col) + x = x + step + + if not (draw_fill and draw_strokes) then -- -V560 + draw_list:AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)) + x = x + step + end + end + if draw_fill and draw_strokes then + x = start_pos.x + end + if draw_strokes then + -- STROKES + -- First row uses a thickness of 1.0f, second row uses the configurable thickness + local col = ImColor(s.colf_stroke):U32() + local th = (row == 0) and 1.0 or thickness + draw_list:AddNgon(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments, th); x = x + step -- N-gon + draw_list:AddCircle(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments, th); x = x + step -- Circle + draw_list:AddEllipse(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments, th); x = x + step -- Ellipse + draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, th, flags); x = x + step -- Square + draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, flags); x = x + step -- Square with all rounded corners + draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, bit32.bor(flags, corners_tl_br)); x = x + step -- Square with two rounded corners + draw_list:AddTriangle(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col, th); x = x + step -- Triangle + draw_list:AddTriangle(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col, th); x = x + step - math.floor(sz * 0.6) -- Thin triangle + + -- Concave shape: U + for _, p in ipairs(concave_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathStroke(col, th, bit32.bor(flags, 512 --[[ImDrawFlags.Closed]])) + x = x + step + + -- Concave shape: Zig-Zag with sharp angles (see difference with/without JoinMiter) + for _, p in ipairs(zigzag_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathStroke(col, th, bit32.bor(flags, 512 --[[ImDrawFlags.Closed]])) + x = x + step + + -- Horizontal/Vertical/Diagonal lines + local off = math.floor(sz * 0.4) + draw_list:AddLineH(x, x + sz, y, col, th) + draw_list:AddLine(ImVec2(x, y + off), ImVec2(x + sz, y + off), col, th) + x = x + step + draw_list:AddLineV(x, y, y + sz, col, th) + draw_list:AddLine(ImVec2(x + off, y + sz), ImVec2(x + off, y), col, th) + x = x + step - math.floor(half_sz) + if not (draw_fill and draw_strokes) then -- -V560 + draw_list:AddLine(ImVec2(x, y), ImVec2(x + half_sz, y + sz), col, th) + draw_list:AddLine(ImVec2(x, y + sz), ImVec2(x + half_sz, y), col, th) + end + x = x + step - math.floor(half_sz) + + -- Rotating square + for n = 0, 4 - 1 do + draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n + 1].x, y + half_sz + rotating_square[n + 1].y)) + end + draw_list:PathStroke(col, th, bit32.bor(flags, 512 --[[ImDrawFlags.Closed]])) + --for (int n = 0; n < 4; n++) // ...made of individual line + -- draw_list->AddLine({ x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y }, { x + half_sz + rotating_square[(n + 1) & 3].x, y + half_sz + rotating_square[(n + 1) & 3].y }, col, th, flags); + x = x + step + + -- Path + draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) + draw_list:PathStroke(col, th, flags) + x = x + step + + -- Quadratic Bezier Curve (3 control points) + draw_list:AddBezierQuadratic(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), col, th, curve_segments) + x = x + step + + -- Cubic Bezier Curve (4 control points) + if not (draw_fill and draw_strokes) then -- -V560 + draw_list:AddBezierCubic(ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), ImVec2(x + cp4[4].x, y + cp4[4].y), col, th, curve_segments) + x = x + step + end + end + y = y + step + end + + ImGui.Dummy(ImVec2(step * 15.5, step * 4.0)) + -- [Port] draw_list->PopDrawFlag(); x2 + + ImGui.Text("ImDrawList Vector Rendering Reference:") + ImGui.TextLinkOpenURL("https://github.com/ocornut/imgui/wiki/Draw-List") + + ImGui.PopItemFlag() + ImGui.PopItemWidth() + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Canvas") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/Canvas") + local points = s.points + local scrolling = s.scrolling + + _, s.opt_enable_grid = ImGui.Checkbox("Enable grid", s.opt_enable_grid) + _, s.opt_enable_context_menu = ImGui.Checkbox("Enable context menu", s.opt_enable_context_menu) + ImGui.Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.") + + -- Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. + -- Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. + -- To use a child window instead we could use, e.g: + -- ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0, 0)) -- Disable padding + -- ImGui.PushStyleColor(ImGuiCol.ChildBg, IM_COL32(50, 50, 50, 255)) -- Set a background color + -- ImGui.BeginChild("canvas", ImVec2(0.0, 0.0), ImGuiChildFlags.Borders, ImGuiWindowFlags.NoMove) + -- ImGui.PopStyleColor() + -- ImGui.PopStyleVar() + -- [...] + -- ImGui.EndChild() + + -- Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() + local canvas_p0 = ImGui.GetCursorScreenPos() -- ImDrawList API uses screen coordinates! + local canvas_sz = ImGui.GetContentRegionAvail() -- Resize canvas to what's available + if canvas_sz.x < 50.0 then canvas_sz.x = 50.0 end + if canvas_sz.y < 50.0 then canvas_sz.y = 50.0 end + local canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y) + + -- Draw border and background color + local io = ImGui.GetIO() + local draw_list = ImGui.GetWindowDrawList() + draw_list:AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)) + draw_list:AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)) + + -- This will catch our interactions + ImGui.InvisibleButton("canvas", canvas_sz, bit32.bor(1 --[[ImGuiButtonFlags.MouseButtonLeft]], 2 --[[ImGuiButtonFlags.MouseButtonRight]])) + local is_hovered = ImGui.IsItemHovered() -- Hovered + local is_active = ImGui.IsItemActive() -- Held + local origin = ImVec2(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y) -- Lock scrolled origin + local mouse_pos_in_canvas = ImVec2(io.MousePos.x - origin.x, io.MousePos.y - origin.y) + + -- Add first and second point + if is_hovered and not s.adding_line and ImGui.IsMouseClicked(0 --[[ImGuiMouseButton.Left]]) then + points:push_back(ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y)) -- [Port] copies: ImVector stores references + points:push_back(ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y)) + s.adding_line = true + end + if s.adding_line then + ImVec2_Copy(points:back(), mouse_pos_in_canvas) + if not ImGui.IsMouseDown(0 --[[ImGuiMouseButton.Left]]) then + s.adding_line = false + end + end + + -- Pan (we use a zero mouse threshold when there's no context menu) + -- You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. + local mouse_threshold_for_pan = s.opt_enable_context_menu and -1.0 or 0.0 + if is_active and ImGui.IsMouseDragging(1 --[[ImGuiMouseButton.Right]], mouse_threshold_for_pan) then + scrolling.x = scrolling.x + io.MouseDelta.x + scrolling.y = scrolling.y + io.MouseDelta.y + end + + -- Context menu (under default mouse threshold) + local drag_delta = ImGui.GetMouseDragDelta(1 --[[ImGuiMouseButton.Right]]) + if s.opt_enable_context_menu and drag_delta.x == 0.0 and drag_delta.y == 0.0 then + ImGui.OpenPopupOnItemClick("context", 8 --[[ImGuiPopupFlags.MouseButtonRight]]) + end + if ImGui.BeginPopup("context") then + if s.adding_line then + points:resize(points.Size - 2) + end + s.adding_line = false + if ImGui.MenuItem("Remove one", nil, false, points.Size > 0) then points:resize(points.Size - 2) end + if ImGui.MenuItem("Remove all", nil, false, points.Size > 0) then points:clear() end + ImGui.EndPopup() + end + + -- Draw grid + all lines in the canvas + draw_list:PushClipRect(canvas_p0, canvas_p1, true) + if s.opt_enable_grid then + local GRID_STEP = 64.0 + local x = math.fmod(scrolling.x, GRID_STEP) + while x < canvas_sz.x do + draw_list:AddLineV(canvas_p0.x + x, canvas_p0.y, canvas_p1.y, IM_COL32(200, 200, 200, 40)) + x = x + GRID_STEP + end + local y = math.fmod(scrolling.y, GRID_STEP) + while y < canvas_sz.y do + draw_list:AddLineH(canvas_p0.x, canvas_p1.x, canvas_p0.y + y, IM_COL32(200, 200, 200, 40)) + y = y + GRID_STEP + end + end + for n = 0, points.Size - 1, 2 do + draw_list:AddLine(ImVec2(origin.x + points.Data[n + 1].x, origin.y + points.Data[n + 1].y), ImVec2(origin.x + points.Data[n + 2].x, origin.y + points.Data[n + 2].y), IM_COL32(255, 255, 0, 255), 2.0) + end + draw_list:PopClipRect() + + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("BG/FG draw lists") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/BG & FG draw lists") _, s.draw_bg = ImGui.Checkbox("Draw in Background draw list", s.draw_bg) ImGui.SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.") _, s.draw_fg = ImGui.Checkbox("Draw in Foreground draw list", s.draw_fg) ImGui.SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.") - local window_pos, window_size = ImGui.GetWindowPos(), ImGui.GetWindowSize() + local window_pos = ImGui.GetWindowPos() + local window_size = ImGui.GetWindowSize() local window_center = ImVec2(window_pos.x + window_size.x * 0.5, window_pos.y + window_size.y * 0.5) - if s.draw_bg then ImGui.GetBackgroundDrawList():AddCircle(window_center, window_size.x * 0.6, IM_COL32(255, 0, 0, 200), 0, 10 + 4) end - if s.draw_fg then ImGui.GetForegroundDrawList():AddCircle(window_center, window_size.y * 0.6, IM_COL32(0, 255, 0, 200), 0, 10) end + if s.draw_bg then + ImGui.GetBackgroundDrawList():AddCircle(window_center, window_size.x * 0.6, IM_COL32(255, 0, 0, 200), 0, 10 + 4) + end + if s.draw_fg then + ImGui.GetForegroundDrawList():AddCircle(window_center, window_size.y * 0.6, IM_COL32(0, 255, 0, 200), 0, 10) + end ImGui.EndTabItem() end @@ -26944,35 +31221,42 @@ function ShowExampleAppCustomRendering(p_open) -- We use functions in ImDrawList as each draw list contains a convenience splitter, -- but you can also instantiate your own ImDrawListSplitter if you need to nest them. if ImGui.BeginTabItem("Draw Channels") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/Draw Channels") local draw_list = ImGui.GetWindowDrawList() - ImGui.Text("Blue shape is drawn first: appears in back") - ImGui.Text("Red shape is drawn after: appears in front") - local p0 = ImGui.GetCursorScreenPos() - draw_list:AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue - draw_list:AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)) -- Red - ImGui.Dummy(ImVec2(75, 75)) + do + ImGui.Text("Blue shape is drawn first: appears in back") + ImGui.Text("Red shape is drawn after: appears in front") + local p0 = ImGui.GetCursorScreenPos() + draw_list:AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue + draw_list:AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)) -- Red + ImGui.Dummy(ImVec2(75, 75)) + end ImGui.Separator() - ImGui.Text("Blue shape is drawn first, into channel 1: appears in front") - ImGui.Text("Red shape is drawn after, into channel 0: appears in back") - local p1 = ImGui.GetCursorScreenPos() + do + ImGui.Text("Blue shape is drawn first, into channel 1: appears in front") + ImGui.Text("Red shape is drawn after, into channel 0: appears in back") + local p1 = ImGui.GetCursorScreenPos() - -- Create 2 channels and draw a Blue shape THEN a Red shape. - -- You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls. - draw_list:ChannelsSplit(2) - draw_list:ChannelsSetCurrent(1) - draw_list:AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue - draw_list:ChannelsSetCurrent(0) - draw_list:AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)) -- Red + -- Create 2 channels and draw a Blue shape THEN a Red shape. + -- You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls. + draw_list:ChannelsSplit(2) + draw_list:ChannelsSetCurrent(1) + draw_list:AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue + draw_list:ChannelsSetCurrent(0) + draw_list:AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)) -- Red - -- Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1. - -- This works by copying draw indices only (vertices are not copied). - draw_list:ChannelsMerge() - ImGui.Dummy(ImVec2(75, 75)) - ImGui.Text("After reordering, contents of channel 0 appears below channel 1.") + -- Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1. + -- This works by copying draw indices only (vertices are not copied). + draw_list:ChannelsMerge() + ImGui.Dummy(ImVec2(75, 75)) + ImGui.Text("After reordering, contents of channel 0 appears below channel 1.") + end ImGui.EndTabItem() end + ImGui.EndTabBar() end + ImGui.End() return p_open end @@ -26981,14 +31265,19 @@ end -- [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() ------------------------------------------------------------------------------- --- KeepWindowPadding: Keep WindowPadding to help understand that DockSpace() is a widget inside the window. -local DSA = { IsFullscreen = true, KeepWindowPadding = false, DockSpaceFlags = 0, opt_demo_mode = 0, opt_demo_mode_changed = false } +function ImGuiDemoDockspaceArgs() + return { + IsFullscreen = true, + KeepWindowPadding = false, -- Keep WindowPadding to help understand that DockSpace() is a widget inside the window. + DockSpaceFlags = 0 --[[ImGuiDockNodeFlags.None]], + } +end -- THIS IS A DEMO FOR ADVANCED USAGE OF DockSpace(). -- MOST REGULAR APPLICATIONS WANTING TO ALLOW DOCKING WINDOWS ON THE EDGE OF YOUR SCREEN CAN SIMPLY USE: --- ImGui.NewFrame() + ImGui.DockSpaceOverViewport() -- Create a dockspace in main viewport +-- ImGui.NewFrame(); + ImGui.DockSpaceOverViewport(); -- Create a dockspace in main viewport -- OR: --- ImGui.NewFrame() + ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode) -- Create a dockspace in main viewport, where central node is transparent. +-- ImGui.NewFrame(); + ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode); -- Create a dockspace in main viewport, where central node is transparent. -- Demonstrate using DockSpace() to create an explicit docking node within an existing window, with various options. -- Read https://github.com/ocornut/imgui/wiki/Docking for details. -- The reasons we do not use DockSpaceOverViewport() in this demo is because: @@ -26997,22 +31286,23 @@ local DSA = { IsFullscreen = true, KeepWindowPadding = false, DockSpaceFlags = 0 -- Also see 'Demo->Examples->Documents' for a less abstract version of this. -- - (2) we allow the host window to have padding (when args.UsePadding == true) -- - (3) we expose variety of other flags. -local function ShowExampleAppDockSpaceAdvanced(args, p_open) +function ShowExampleAppDockSpaceAdvanced(args, p_open) local dockspace_flags = args.DockSpaceFlags - -- We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, + -- We are using the ImGuiWindowFlags.NoDocking flag to make the parent window not dockable into, -- because it would be confusing to have two docking targets within each others. - local W = ImGuiWindowFlags - local window_flags = W.NoDocking + local window_flags = 524288 --[[ImGuiWindowFlags.NoDocking]] if args.IsFullscreen then - -- Fullscreen dockspace: practically the same as calling DockSpaceOverViewport() + -- Fullscreen dockspace: practically the same as calling DockSpaceOverViewport(); local viewport = ImGui.GetMainViewport() ImGui.SetNextWindowPos(viewport.WorkPos) ImGui.SetNextWindowSize(viewport.WorkSize) ImGui.SetNextWindowViewport(viewport.ID) ImGui.PushStyleVar(3 --[[ImGuiStyleVar.WindowRounding]], 0.0) ImGui.PushStyleVar(4 --[[ImGuiStyleVar.WindowBorderSize]], 0.0) - window_flags = bit32.bor(window_flags, W.NoTitleBar, W.NoCollapse, W.NoResize, W.NoMove, W.NoBringToFrontOnFocus, W.NoNavFocus, W.NoBackground) + window_flags = bit32.bor(window_flags, 1 --[[ImGuiWindowFlags.NoTitleBar]], 32 --[[ImGuiWindowFlags.NoCollapse]], 2 --[[ImGuiWindowFlags.NoResize]], 4 --[[ImGuiWindowFlags.NoMove]]) + window_flags = bit32.bor(window_flags, 8192 --[[ImGuiWindowFlags.NoBringToFrontOnFocus]], 131072 --[[ImGuiWindowFlags.NoNavFocus]]) + window_flags = bit32.bor(window_flags, 128 --[[ImGuiWindowFlags.NoBackground]]) else -- Floating dockspace dockspace_flags = bit32.band(dockspace_flags, bit32.bnot(8 --[[ImGuiDockNodeFlags.PassthruCentralNode]])) @@ -27023,70 +31313,102 @@ local function ShowExampleAppDockSpaceAdvanced(args, p_open) -- all active windows docked into it will lose their parent and become undocked. -- We cannot preserve the docking relationship between an active window and an inactive docking, otherwise -- any change of dockspace/settings would lead to windows being stuck in limbo and never being visible. - if not args.KeepWindowPadding then ImGui.PushStyleVar(2 --[[ImGuiStyleVar.WindowPadding]], ImVec2(0.0, 0.0)) end + if not args.KeepWindowPadding then + ImGui.PushStyleVar(2 --[[ImGuiStyleVar.WindowPadding]], ImVec2(0.0, 0.0)) + end p_open = ImGui.Begin("Window with a DockSpace", p_open, window_flags) - if not args.KeepWindowPadding then ImGui.PopStyleVar() end + if not args.KeepWindowPadding then + ImGui.PopStyleVar() + end - if args.IsFullscreen then ImGui.PopStyleVar(2) end + if args.IsFullscreen then + ImGui.PopStyleVar(2) + end -- Submit the DockSpace widget inside our window -- - Note that the id here is different from the one used by DockSpaceOverViewport(), so docking state won't get transfered between "Basic" and "Advanced" demos. -- - If we made the ShowExampleAppDockSpaceBasic() calculate its own ID and pass it to DockSpaceOverViewport() the ID could easily match. local dockspace_id = ImGui.GetID("MyDockSpace") ImGui.DockSpace(dockspace_id, ImVec2(0.0, 0.0), dockspace_flags) + ImGui.End() return p_open end +function ShowExampleAppDockSpaceBasic(flags) + -- Basic version which you can use in many apps: + -- e.g: + -- ImGui.DockSpaceOverViewport(); + -- or: + -- ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode); -- Central node will be transparent + -- or: + -- local viewport = ImGui.GetMainViewport(); + -- ImGui.DockSpaceOverViewport(0, viewport, ImGuiDockNodeFlags.None); + + ImGui.DockSpaceOverViewport(0, nil, flags) +end + +S.ShowExampleAppDockSpace = { + opt_demo_mode = 0, + opt_demo_mode_changed = false, + args = ImGuiDemoDockspaceArgs(), +} function ShowExampleAppDockSpace(p_open) - local args = DSA - if args.opt_demo_mode == 0 then - -- Basic version which you can use in many apps: - -- e.g: - -- ImGui.DockSpaceOverViewport() - -- or: - -- ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode) -- Central node will be transparent - -- or: - -- local viewport = ImGui.GetMainViewport() - -- ImGui.DockSpaceOverViewport(0, viewport, ImGuiDockNodeFlags.None) - ImGui.DockSpaceOverViewport(0, nil, args.DockSpaceFlags) + local s = S.ShowExampleAppDockSpace + local args = s.args + + if s.opt_demo_mode == 0 then + ShowExampleAppDockSpaceBasic(args.DockSpaceFlags) else p_open = ShowExampleAppDockSpaceAdvanced(args, p_open) end -- Refocus our window to minimize perceived loss of focus when changing mode (caused by the fact that each use a different window, which would not happen in a real app) - if args.opt_demo_mode_changed then ImGui.SetNextWindowFocus() end + if s.opt_demo_mode_changed then + ImGui.SetNextWindowFocus() + end p_open = ImGui.Begin("Examples: Dockspace", p_open, 1024 --[[ImGuiWindowFlags.MenuBar]]) - local c1, c2 - c1, args.opt_demo_mode = ImGui.RadioButton("Basic demo mode", args.opt_demo_mode, 0) - c2, args.opt_demo_mode = ImGui.RadioButton("Advanced demo mode", args.opt_demo_mode, 1) - args.opt_demo_mode_changed = c1 or c2 + s.opt_demo_mode_changed = false + local pressed + pressed, s.opt_demo_mode = ImGui.RadioButton("Basic demo mode", s.opt_demo_mode, 0) + s.opt_demo_mode_changed = s.opt_demo_mode_changed or pressed + pressed, s.opt_demo_mode = ImGui.RadioButton("Advanced demo mode", s.opt_demo_mode, 1) + s.opt_demo_mode_changed = s.opt_demo_mode_changed or pressed + ImGui.SeparatorText("Options") - local D = ImGuiDockNodeFlags + if bit32.band(ImGui.GetIO().ConfigFlags, 128 --[[ImGuiConfigFlags.DockingEnable]]) == 0 then ShowDockingDisabledMessage() - elseif args.opt_demo_mode == 0 then - args.DockSpaceFlags = bit32.band(args.DockSpaceFlags, D.PassthruCentralNode) -- Allowed flags - _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, D.PassthruCentralNode) - else + elseif s.opt_demo_mode == 0 then + args.DockSpaceFlags = bit32.band(args.DockSpaceFlags, 8 --[[ImGuiDockNodeFlags.PassthruCentralNode]]) -- Allowed flags + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, 8 --[[ImGuiDockNodeFlags.PassthruCentralNode]]) + elseif s.opt_demo_mode == 1 then _, args.IsFullscreen = ImGui.Checkbox("Fullscreen", args.IsFullscreen) _, args.KeepWindowPadding = ImGui.Checkbox("Keep Window Padding", args.KeepWindowPadding) ImGui.SameLine() HelpMarker("This is mostly exposed to facilitate understanding that a DockSpace() is _inside_ a window.") ImGui.BeginDisabled(args.IsFullscreen == false) - _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, D.PassthruCentralNode) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, 8 --[[ImGuiDockNodeFlags.PassthruCentralNode]]) ImGui.EndDisabled() - for _, n in ipairs({ "NoDockingOverCentralNode", "NoDockingSplit", "NoUndocking", "NoResize", "AutoHideTabBar" }) do - if D[n] then _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: " .. n, args.DockSpaceFlags, D[n]) end - end + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoDockingOverCentralNode", args.DockSpaceFlags, 4 --[[ImGuiDockNodeFlags.NoDockingOverCentralNode]]) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoDockingSplit", args.DockSpaceFlags, 16 --[[ImGuiDockNodeFlags.NoDockingSplit]]) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoUndocking", args.DockSpaceFlags, 128 --[[ImGuiDockNodeFlags.NoUndocking]]) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoResize", args.DockSpaceFlags, 32 --[[ImGuiDockNodeFlags.NoResize]]) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: AutoHideTabBar", args.DockSpaceFlags, 64 --[[ImGuiDockNodeFlags.AutoHideTabBar]]) end -- Show demo options and help if ImGui.BeginMenuBar() then if ImGui.BeginMenu("Help") then - ImGui.TextUnformatted("This demonstrates the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window.\nThe \"Basic\" version uses the ImGui::DockSpaceOverViewport() helper. Most applications can probably use this.") + ImGui.TextUnformatted( + "This demonstrates the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window." .. "\n" .. + "The \"Basic\" version uses the ImGui::DockSpaceOverViewport() helper. Most applications can probably use this.") ImGui.Separator() - ImGui.TextUnformatted("When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!\n- Drag from window title bar or their tab to dock/undock.\n- Drag from window menu button (upper-left button) to undock an entire node (all windows).\n- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)\n- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)") + ImGui.TextUnformatted("When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" .. "\n" .. + "- Drag from window title bar or their tab to dock/undock." .. "\n" .. + "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." .. "\n" .. + "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" .. "\n" .. + "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)") ImGui.Separator() ImGui.TextUnformatted("More details:"); ImGui.Bullet(); ImGui.SameLine(); ImGui.TextLinkOpenURL("Docking Wiki page", "https://github.com/ocornut/imgui/wiki/Docking") ImGui.BulletText("Read comments in ShowExampleAppDockSpace()") @@ -27094,6 +31416,7 @@ function ShowExampleAppDockSpace(p_open) end ImGui.EndMenuBar() end + ImGui.End() return p_open end @@ -27103,93 +31426,139 @@ end ------------------------------------------------------------------------------- -- Simplified structure to mimic a Document model --- NameBuf: Document title --- UID: Unique ID (necessary as we can change title) --- Open: Set when open (we keep an array of all available documents to simplify demo code!) --- OpenPrev: Copy of Open from last update. --- Dirty: Set when the document has been modified --- Color: An arbitrary variable associated to the document -local function MyDocument(uid, name, open, color) +-- Name Document title -- [Port] char[32] text buffer, read with ImGui.TextBufferToString() +-- UID Unique ID (necessary as we can change title) +-- Open Set when open (we keep an array of all available documents to simplify demo code!) +-- OpenPrev Copy of Open from last update. +-- Dirty Set when the document has been modified +-- Color An arbitrary variable associated to the document +local MyDocumentMT = {} +MyDocumentMT.__index = MyDocumentMT +function MyDocument(uid, name, open, color) if open == nil then open = true end - local d = { UID = uid, NameBuf = Buf(name, 32), Open = open, OpenPrev = open, Dirty = false, Color = color or ImVec4(1.0, 1.0, 1.0, 1.0) } - function d:Name() return BufStr(self.NameBuf) end - function d:DoOpen() self.Open = true end - function d:DoForceClose() self.Open = false; self.Dirty = false end - function d:DoSave() self.Dirty = false end - return d + if color == nil then color = ImVec4(1.0, 1.0, 1.0, 1.0) end + local self = setmetatable({}, MyDocumentMT) + self.UID = uid + self.Name = ImGui.NewTextBuffer(name, 32) + self.Open = open; self.OpenPrev = open + self.Dirty = false + self.Color = color + return self +end +function MyDocumentMT:DoOpen() self.Open = true end +function MyDocumentMT:DoForceClose() self.Open = false; self.Dirty = false end +function MyDocumentMT:DoSave() self.Dirty = false end + +local ExampleAppDocumentsMT = {} +ExampleAppDocumentsMT.__index = ExampleAppDocumentsMT +function ExampleAppDocuments() + local self = setmetatable({}, ExampleAppDocumentsMT) + self.Documents = ImVector() + self.CloseQueue = ImVector() + self.RenamingDoc = nil + self.RenamingStarted = false + + self.Documents:push_back(MyDocument(0, "Lettuce", true, ImVec4(0.4, 0.8, 0.4, 1.0))) + self.Documents:push_back(MyDocument(1, "Eggplant", true, ImVec4(0.8, 0.5, 1.0, 1.0))) + self.Documents:push_back(MyDocument(2, "Carrot", true, ImVec4(1.0, 0.8, 0.5, 1.0))) + self.Documents:push_back(MyDocument(3, "Tomato", false, ImVec4(1.0, 0.3, 0.4, 1.0))) + self.Documents:push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4, 0.8, 0.8, 1.0))) + self.Documents:push_back(MyDocument(5, "Some Document", false, ImVec4(0.8, 0.8, 1.0, 1.0))) + return self end -local Docs = nil -local function DocsInit() - local app = { Documents = { - MyDocument(0, "Lettuce", true, ImVec4(0.4, 0.8, 0.4, 1.0)), - MyDocument(1, "Eggplant", true, ImVec4(0.8, 0.5, 1.0, 1.0)), - MyDocument(2, "Carrot", true, ImVec4(1.0, 0.8, 0.5, 1.0)), - MyDocument(3, "Tomato", false, ImVec4(1.0, 0.3, 0.4, 1.0)), - MyDocument(4, "A Rather Long Title", false, ImVec4(0.4, 0.8, 0.8, 1.0)), - MyDocument(5, "Some Document", false, ImVec4(0.8, 0.8, 1.0, 1.0)), - }, CloseQueue = {}, RenamingDoc = nil, RenamingStarted = false, - opt_target = 1, opt_reorderable = true, opt_fitting_flags = 128 --[[ImGuiTabBarFlags.FittingPolicyDefault_]] } - function app:QueueClose(doc) - for _, d in ipairs(self.CloseQueue) do if d == doc then return end end - self.CloseQueue[#self.CloseQueue + 1] = doc - end - -- As we allow to change document name, we append a never-changing document ID so tabs are stable - function app:GetTabName(doc) return string.format("%s###doc%d", doc:Name(), doc.UID) end - -- Display placeholder contents for the Document - function app:DisplayDocContents(doc) - ImGui.PushID("doc" .. doc.UID) - ImGui.Text("Document \"%s\"", doc:Name()) - ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], doc.Color) - ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") - ImGui.PopStyleColor() +-- As we allow to change document name, we append a never-changing document ID so tabs are stable +function ExampleAppDocumentsMT:GetTabName(doc) -- [Port] returns the string instead of filling out_buf + return string.format("%s###doc%d", ImGui.TextBufferToString(doc.Name), doc.UID) +end - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 563 --[[ImGuiKey.R]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - if ImGui.Button("Rename..") then self.RenamingDoc = doc; self.RenamingStarted = true end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 558 --[[ImGuiKey.M]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - if ImGui.Button("Modify") then doc.Dirty = true end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 564 --[[ImGuiKey.S]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - if ImGui.Button("Save") then doc:DoSave() end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 568 --[[ImGuiKey.W]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - if ImGui.Button("Close") then self:QueueClose(doc) end - ImGui.ColorEdit3("color", doc.Color) -- Useful to test drag and drop and hold-dragged-to-open-tab behavior. - ImGui.PopID() +-- Display placeholder contents for the Document +function ExampleAppDocumentsMT:DisplayDocContents(doc) + ImGui.PushID(doc.UID) -- [Port] PushID(doc): no pointer IDs, UID is unique + ImGui.Text("Document \"%s\"", ImGui.TextBufferToString(doc.Name)) + ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], doc.Color) + ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") + ImGui.PopStyleColor() + + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 563 --[[ImGuiKey.R]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + if ImGui.Button("Rename..") then + self.RenamingDoc = doc + self.RenamingStarted = true end - -- Display context menu for the Document - function app:DisplayDocContextMenu(doc) - if not ImGui.BeginPopupContextItem() then return end - if ImGui.MenuItem("Save " .. doc:Name(), "Ctrl+S", false, doc.Open) then doc:DoSave() end - if ImGui.MenuItem("Rename...", "Ctrl+R", false, doc.Open) then self.RenamingDoc = doc end - if ImGui.MenuItem("Close", "Ctrl+W", false, doc.Open) then self:QueueClose(doc) end - ImGui.EndPopup() + ImGui.SameLine() + + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 558 --[[ImGuiKey.M]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + if ImGui.Button("Modify") then + doc.Dirty = true end - -- [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. - -- If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, - -- as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for - -- the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has - -- disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively - -- give the impression of a flicker for one frame. - -- We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. - -- Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags.Reorderable flag. - function app:NotifyOfDocumentsClosedElsewhere() - for _, doc in ipairs(self.Documents) do - if not doc.Open and doc.OpenPrev then ImGui.SetTabItemClosed(doc:Name()) end - doc.OpenPrev = doc.Open + + ImGui.SameLine() + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 564 --[[ImGuiKey.S]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + if ImGui.Button("Save") then + doc:DoSave() + end + + ImGui.SameLine() + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 568 --[[ImGuiKey.W]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + if ImGui.Button("Close") then + self.CloseQueue:push_back(doc) + end + ImGui.ColorEdit3("color", doc.Color) -- Useful to test drag and drop and hold-dragged-to-open-tab behavior. + ImGui.PopID() +end + +-- Display context menu for the Document +function ExampleAppDocumentsMT:DisplayDocContextMenu(doc) + if not ImGui.BeginPopupContextItem() then + return + end + + local buf = string.format("Save %s", ImGui.TextBufferToString(doc.Name)) + if ImGui.MenuItem(buf, "Ctrl+S", false, doc.Open) then + doc:DoSave() + end + if ImGui.MenuItem("Rename...", "Ctrl+R", false, doc.Open) then + self.RenamingDoc = doc + end + if ImGui.MenuItem("Close", "Ctrl+W", false, doc.Open) then + self.CloseQueue:push_back(doc) + end + ImGui.EndPopup() +end + +-- [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. +-- If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, +-- as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for +-- the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has +-- disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively +-- give the impression of a flicker for one frame. +-- We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. +-- Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags.Reorderable flag. +function ExampleAppDocumentsMT:NotifyOfDocumentsClosedElsewhere() + for _, doc in self.Documents:iter() do + if not doc.Open and doc.OpenPrev then + ImGui.SetTabItemClosed(ImGui.TextBufferToString(doc.Name)) end + doc.OpenPrev = doc.Open end - return app end +S.ShowExampleAppDocuments = { + app = ExampleAppDocuments(), + opt_target = nil, -- set below to Target_Tab + opt_reorderable = true, + opt_fitting_flags = nil, -- set below to ImGuiTabBarFlags.FittingPolicyDefault_ +} function ShowExampleAppDocuments(p_open) - Docs = Docs or DocsInit() - local app = Docs + local s = S.ShowExampleAppDocuments + local app = s.app + -- Options - -- Target_Tab: Create documents as local tab into a local tab bar - -- Target_DockSpaceAndWindow: Create documents as regular windows, and create an embedded dockspace - local Target_Tab, Target_DockSpaceAndWindow = 1, 2 + local Target_None = 0 + local Target_Tab = 1 -- Create documents as local tab into a local tab bar + local Target_DockSpaceAndWindow = 2 -- Create documents as regular windows, and create an embedded dockspace + if s.opt_target == nil then s.opt_target = Target_Tab end + if s.opt_fitting_flags == nil then s.opt_fitting_flags = 128 --[[ImGuiTabBarFlags.FittingPolicyDefault_]] end -- When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant") -- that we emit gets docked into the same spot as the parent window ("Example: Documents"). @@ -27200,46 +31569,64 @@ function ShowExampleAppDocuments(p_open) local window_contents_visible p_open, window_contents_visible = ImGui.Begin("Example: Documents", p_open, 1024 --[[ImGuiWindowFlags.MenuBar]]) - if not window_contents_visible and app.opt_target ~= Target_DockSpaceAndWindow then + if not window_contents_visible and s.opt_target ~= Target_DockSpaceAndWindow then ImGui.End() return p_open end + IMGUI_DEMO_MARKER("Examples/Documents") -- Menu if ImGui.BeginMenuBar() then if ImGui.BeginMenu("File") then local open_count = 0 - for _, doc in ipairs(app.Documents) do if doc.Open then open_count = open_count + 1 end end - if ImGui.BeginMenu("Open", open_count < #app.Documents) then - for _, doc in ipairs(app.Documents) do - if not doc.Open and ImGui.MenuItem(doc:Name()) then doc:DoOpen() end + for _, doc in app.Documents:iter() do + open_count = open_count + (doc.Open and 1 or 0) + end + + if ImGui.BeginMenu("Open", open_count < app.Documents.Size) then + for _, doc in app.Documents:iter() do + if not doc.Open and ImGui.MenuItem(ImGui.TextBufferToString(doc.Name)) then + doc:DoOpen() + end end ImGui.EndMenu() end if ImGui.MenuItem("Close All Documents", nil, false, open_count > 0) then - for _, doc in ipairs(app.Documents) do app:QueueClose(doc) end + for _, doc in app.Documents:iter() do + app.CloseQueue:push_back(doc) + end + end + if ImGui.MenuItem("Exit") and p_open ~= nil then + p_open = false end - if ImGui.MenuItem("Exit") and p_open ~= nil then p_open = false end ImGui.EndMenu() end ImGui.EndMenuBar() end -- [Debug] List documents with one checkbox for each - for doc_n, doc in ipairs(app.Documents) do - if doc_n > 1 then ImGui.SameLine() end - ImGui.PushID("doc" .. doc.UID) + for doc_n = 0, app.Documents.Size - 1 do + local doc = app.Documents.Data[doc_n + 1] + if doc_n > 0 then + ImGui.SameLine() + end + ImGui.PushID(doc.UID) -- [Port] PushID(&doc): no pointer IDs, UID is unique local pressed - pressed, doc.Open = ImGui.Checkbox(doc:Name(), doc.Open) - if pressed and not doc.Open then doc:DoForceClose() end + pressed, doc.Open = ImGui.Checkbox(ImGui.TextBufferToString(doc.Name), doc.Open) + if pressed then + if not doc.Open then + doc:DoForceClose() + end + end ImGui.PopID() end ImGui.PushItemWidth(ImGui.GetFontSize() * 12) - app.opt_target = ImGui.Combo("Output", app.opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0") + s.opt_target = ImGui.Combo("Output", s.opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0") ImGui.PopItemWidth() local redock_all = false - if app.opt_target == Target_Tab then ImGui.SameLine(); _, app.opt_reorderable = ImGui.Checkbox("Reorderable Tabs", app.opt_reorderable) end - if app.opt_target == Target_DockSpaceAndWindow then ImGui.SameLine(); redock_all = ImGui.Button("Redock all") end + if s.opt_target == Target_Tab then ImGui.SameLine(); _, s.opt_reorderable = ImGui.Checkbox("Reorderable Tabs", s.opt_reorderable) end + if s.opt_target == Target_DockSpaceAndWindow then ImGui.SameLine(); redock_all = ImGui.Button("Redock all") end + ImGui.Separator() -- About the ImGuiWindowFlags.UnsavedDocument / ImGuiTabItemFlags.UnsavedDocument flags. @@ -27253,34 +31640,46 @@ function ShowExampleAppDocuments(p_open) -- The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole. -- Tabs - if app.opt_target == Target_Tab then - local tab_bar_flags = bit32.bor(app.opt_fitting_flags, app.opt_reorderable and 1 --[[ImGuiTabBarFlags.Reorderable]] or 0, 64 --[[ImGuiTabBarFlags.DrawSelectedOverline]]) + if s.opt_target == Target_Tab then + local tab_bar_flags = bit32.bor(s.opt_fitting_flags, s.opt_reorderable and 1 --[[ImGuiTabBarFlags.Reorderable]] or 0) + tab_bar_flags = bit32.bor(tab_bar_flags, 64 --[[ImGuiTabBarFlags.DrawSelectedOverline]]) if ImGui.BeginTabBar("##tabs", tab_bar_flags) then - if app.opt_reorderable then app:NotifyOfDocumentsClosedElsewhere() end + if s.opt_reorderable then + app:NotifyOfDocumentsClosedElsewhere() + end + + -- [DEBUG] Stress tests + --if ((ImGui.GetFrameCount() % 30) == 0) docs[1].Open ^= 1; -- [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. + --if (ImGui.GetIO().KeyCtrl) ImGui.SetTabItemSelected(docs[1].Name); -- [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. -- Submit Tabs - for _, doc in ipairs(app.Documents) do - if doc.Open then - -- As we allow to change document name, we append a never-changing document id so tabs are stable - local tab_flags = doc.Dirty and 1 --[[ImGuiTabItemFlags.UnsavedDocument]] or 0 - local visible - visible, doc.Open = ImGui.BeginTabItem(app:GetTabName(doc), doc.Open, tab_flags) - - -- Cancel attempt to close when unsaved add to save queue so we can display a popup. - if not doc.Open and doc.Dirty then - doc.Open = true - app:QueueClose(doc) - end - app:DisplayDocContextMenu(doc) - if visible then - app:DisplayDocContents(doc) - ImGui.EndTabItem() - end + for _, doc in app.Documents:iter() do repeat + if not doc.Open then + break -- continue end - end + + -- As we allow to change document name, we append a never-changing document id so tabs are stable + local doc_name_buf = app:GetTabName(doc) + local tab_flags = (doc.Dirty and 1 --[[ImGuiTabItemFlags.UnsavedDocument]] or 0) + local visible + visible, doc.Open = ImGui.BeginTabItem(doc_name_buf, doc.Open, tab_flags) + + -- Cancel attempt to close when unsaved add to save queue so we can display a popup. + if not doc.Open and doc.Dirty then + doc.Open = true + app.CloseQueue:push_back(doc) + end + + app:DisplayDocContextMenu(doc) + if visible then + app:DisplayDocContents(doc) + ImGui.EndTabItem() + end + until true end + ImGui.EndTabBar() end - elseif app.opt_target == Target_DockSpaceAndWindow then + elseif s.opt_target == Target_DockSpaceAndWindow then if bit32.band(ImGui.GetIO().ConfigFlags, 128 --[[ImGuiConfigFlags.DockingEnable]]) ~= 0 then app:NotifyOfDocumentsClosedElsewhere() @@ -27289,23 +31688,30 @@ function ShowExampleAppDocuments(p_open) ImGui.DockSpace(dockspace_id) -- Create Windows - for _, doc in ipairs(app.Documents) do - if doc.Open then - ImGui.SetNextWindowDockID(dockspace_id, redock_all and 1 --[[ImGuiCond.Always]] or 4 --[[ImGuiCond.FirstUseEver]]) - local window_flags = doc.Dirty and 262144 --[[ImGuiWindowFlags.UnsavedDocument]] or 0 - local visible - doc.Open, visible = ImGui.Begin(doc:Name(), doc.Open, window_flags) - - -- Cancel attempt to close when unsaved add to save queue so we can display a popup. - if not doc.Open and doc.Dirty then - doc.Open = true - app:QueueClose(doc) - end - app:DisplayDocContextMenu(doc) - if visible then app:DisplayDocContents(doc) end - ImGui.End() + for doc_n = 0, app.Documents.Size - 1 do repeat + local doc = app.Documents.Data[doc_n + 1] + if not doc.Open then + break -- continue end - end + + ImGui.SetNextWindowDockID(dockspace_id, redock_all and 1 --[[ImGuiCond.Always]] or 4 --[[ImGuiCond.FirstUseEver]]) + local window_flags = (doc.Dirty and 262144 --[[ImGuiWindowFlags.UnsavedDocument]] or 0) + local visible + doc.Open, visible = ImGui.Begin(ImGui.TextBufferToString(doc.Name), doc.Open, window_flags) + + -- Cancel attempt to close when unsaved add to save queue so we can display a popup. + if not doc.Open and doc.Dirty then + doc.Open = true + app.CloseQueue:push_back(doc) + end + + app:DisplayDocContextMenu(doc) + if visible then + app:DisplayDocContents(doc) + end + + ImGui.End() + until true end else ShowDockingDisabledMessage() end @@ -27319,14 +31725,18 @@ function ShowExampleAppDocuments(p_open) -- Display renaming UI if app.RenamingDoc ~= nil then - if app.RenamingStarted then ImGui.OpenPopup("Rename") end + if app.RenamingStarted then + ImGui.OpenPopup("Rename") + end if ImGui.BeginPopup("Rename") then ImGui.SetNextItemWidth(ImGui.GetFontSize() * 30) - if ImGui.InputText("###Name", app.RenamingDoc.NameBuf, 32, 64 --[[ImGuiInputTextFlags.EnterReturnsTrue]]) then + if ImGui.InputText("###Name", app.RenamingDoc.Name, 32, 64 --[[ImGuiInputTextFlags.EnterReturnsTrue]]) then ImGui.CloseCurrentPopup() app.RenamingDoc = nil end - if app.RenamingStarted then ImGui.SetKeyboardFocusHere(-1) end + if app.RenamingStarted then + ImGui.SetKeyboardFocusHere(-1) + end ImGui.EndPopup() else app.RenamingDoc = nil @@ -27335,2476 +31745,81 @@ function ShowExampleAppDocuments(p_open) end -- Display closing confirmation UI - if #app.CloseQueue > 0 then + if not app.CloseQueue:empty() then local close_queue_unsaved_documents = 0 - for _, doc in ipairs(app.CloseQueue) do if doc.Dirty then close_queue_unsaved_documents = close_queue_unsaved_documents + 1 end end + for n = 0, app.CloseQueue.Size - 1 do + if app.CloseQueue.Data[n + 1].Dirty then + close_queue_unsaved_documents = close_queue_unsaved_documents + 1 + end + end + if close_queue_unsaved_documents == 0 then -- Close documents when all are unsaved - for _, doc in ipairs(app.CloseQueue) do doc:DoForceClose() end - app.CloseQueue = {} + for n = 0, app.CloseQueue.Size - 1 do + app.CloseQueue.Data[n + 1]:DoForceClose() + end + app.CloseQueue:clear() else - if not ImGui.IsPopupOpen("Save?") then ImGui.OpenPopup("Save?") end + if not ImGui.IsPopupOpen("Save?") then + ImGui.OpenPopup("Save?") + end if ImGui.BeginPopupModal("Save?", nil, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) then ImGui.Text("Save change to the following items?") local item_height = ImGui.GetTextLineHeightWithSpacing() if ImGui.BeginChild(ImGui.GetID("frame"), ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 6.25 * item_height), 128 --[[ImGuiChildFlags.FrameStyle]]) then - for _, doc in ipairs(app.CloseQueue) do if doc.Dirty then ImGui.Text("%s", doc:Name()) end end + for _, doc in app.CloseQueue:iter() do + if doc.Dirty then + ImGui.Text("%s", ImGui.TextBufferToString(doc.Name)) + end + end end ImGui.EndChild() + local button_size = ImVec2(ImGui.GetFontSize() * 7.0, 0.0) if ImGui.Button("Yes", button_size) then - for _, doc in ipairs(app.CloseQueue) do - if doc.Dirty then doc:DoSave() end + for _, doc in app.CloseQueue:iter() do + if doc.Dirty then + doc:DoSave() + end doc:DoForceClose() end - app.CloseQueue = {} + app.CloseQueue:clear() ImGui.CloseCurrentPopup() end ImGui.SameLine() if ImGui.Button("No", button_size) then - for _, doc in ipairs(app.CloseQueue) do doc:DoForceClose() end - app.CloseQueue = {} + for _, doc in app.CloseQueue:iter() do + doc:DoForceClose() + end + app.CloseQueue:clear() ImGui.CloseCurrentPopup() end ImGui.SameLine() if ImGui.Button("Cancel", button_size) then - app.CloseQueue = {} + app.CloseQueue:clear() ImGui.CloseCurrentPopup() end ImGui.EndPopup() end end end + ImGui.End() return p_open end -end --[[ imgui_demo_apps.lua ]] - -do --[[ imgui_demo_widgets.lua ]] --- Demo: DemoWindowWidgets*() sections (port of imgui_demo.cpp). Globals picked up by DemoWindowWidgets() in imgui_demo.lua. -local _ -local function HSV(h, s, v, a) local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v) return ImVec4(r, g, b, a or 1.0) end -local Buf, BufStr = DemoBuf, DemoBufStr -local S = {} -- statics, one subtable per section - -local ExampleNames = { - "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper", - "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava", - "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber" } ------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsBasic() +-- [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser() ------------------------------------------------------------------------------- -S.basic = { clicked = 0, check = true, e = 0, counter = 0, str0 = Buf("Hello, world!", 128), str1 = Buf("", 128), - i0 = 123, f0 = 0.001, d0 = 999999.00000001, f1 = 1.e10, vec4a = { 0.10, 0.20, 0.30, 0.44 }, - di1 = 50, di2 = 42, di3 = 128, df1 = 1.0, df2 = 0.0067, si1 = 0, sf1 = 0.123, sf2 = 0.0, angle = 0.0, elem = 0, - col1 = { 1.0, 0.0, 0.2 }, col2 = { 0.4, 0.7, 0.0, 0.5 }, combo = 0, listbox = 1 } - -function DemoWindowWidgetsBasic() - if not ImGui.TreeNode("Basic") then return end - local s = S.basic - ImGui.SeparatorText("General") - if ImGui.Button("Button") then s.clicked = s.clicked + 1 end - if s.clicked % 2 == 1 then ImGui.SameLine(); ImGui.Text("Thanks for clicking me!") end - _, s.check = ImGui.Checkbox("checkbox", s.check) - _, s.e = ImGui.RadioButton("radio a", s.e, 0); ImGui.SameLine() - _, s.e = ImGui.RadioButton("radio b", s.e, 1); ImGui.SameLine() - _, s.e = ImGui.RadioButton("radio c", s.e, 2) - ImGui.AlignTextToFramePadding() - ImGui.TextLinkOpenURL("Hyperlink", "https://github.com/ocornut/imgui/wiki/Error-Handling") - - -- Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. - for i = 0, 6 do - if i > 0 then ImGui.SameLine() end - ImGui.PushID(i) - ImGui.PushStyleColor(22 --[[ImGuiCol.Button]], HSV(i / 7.0, 0.6, 0.6)) - ImGui.PushStyleColor(23 --[[ImGuiCol.ButtonHovered]], HSV(i / 7.0, 0.7, 0.7)) - ImGui.PushStyleColor(24 --[[ImGuiCol.ButtonActive]], HSV(i / 7.0, 0.8, 0.8)) - ImGui.Button("Click") - ImGui.PopStyleColor(3) - ImGui.PopID() - end - - -- Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements - -- (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) - -- See 'Demo->Layout->Text Baseline Alignment' for details. - ImGui.AlignTextToFramePadding() - ImGui.Text("Hold to repeat:") - ImGui.SameLine() - - -- Arrow buttons with Repeater - local spacing = ImGui.GetStyle().ItemInnerSpacing.x - ImGui.PushItemFlag(8 --[[ImGuiItemFlags.ButtonRepeat]], true) - if ImGui.ArrowButton("##left", 0 --[[ImGuiDir.Left]]) then s.counter = s.counter - 1 end - ImGui.SameLine(0.0, spacing) - if ImGui.ArrowButton("##right", 1 --[[ImGuiDir.Right]]) then s.counter = s.counter + 1 end - ImGui.PopItemFlag() - ImGui.SameLine() - ImGui.Text("%d", s.counter) - ImGui.Button("Tooltip") - ImGui.SetItemTooltip("I am a tooltip") - ImGui.LabelText("label", "Value") - - ImGui.SeparatorText("Inputs") - ImGui.InputText("input text", s.str0, 128) - ImGui.SameLine(); HelpMarker("USER:\nHold Shift or use mouse to select text.\nCtrl+Left/Right to word jump.\nCtrl+A or Double-Click to select all.\nCtrl+X,Ctrl+C,Ctrl+V for clipboard.\nCtrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.\nEscape to revert.") - ImGui.InputTextWithHint("input text (w/ hint)", "enter text here", s.str1, 128) - s.i0 = ImGui.InputInt("input int", s.i0) - s.f0 = ImGui.InputFloat("input float", s.f0, 0.01, 1.0, "%.3f") - s.d0 = ImGui.InputDouble("input double", s.d0, 0.01, 1.0, "%.8f") - s.f1 = ImGui.InputFloat("input scientific", s.f1, 0.0, 0.0, "%e") - ImGui.SameLine(); HelpMarker("You can input value using the scientific notation,\n e.g. \"1e+8\" becomes \"100000000\".") - ImGui.InputFloat3("input float3", s.vec4a) - - ImGui.SeparatorText("Drags") - s.di1 = ImGui.DragInt("drag int", s.di1, 1) - ImGui.SameLine(); HelpMarker("Click and drag to edit value.\nHold Shift/Alt for faster/slower edit.\nDouble-Click or Ctrl+Click to input value.") - s.di2 = ImGui.DragInt("drag int 0..100", s.di2, 1, 0, 100, "%d%%", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) - s.di3 = ImGui.DragInt("drag int wrap 100..200", s.di3, 1, 100, 200, "%d", 256 --[[ImGuiSliderFlags.WrapAround]]) - s.df1 = ImGui.DragFloat("drag float", s.df1, 0.005) - s.df2 = ImGui.DragFloat("drag small float", s.df2, 0.0001, 0.0, 0.0, "%.06f ns") - -- ImGui.DragFloat("drag wrap -1..1", f3, 0.005, -1.0, 1.0, nil, ImGuiSliderFlags.WrapAround) - - ImGui.SeparatorText("Sliders") - s.si1 = ImGui.SliderInt("slider int", s.si1, -1, 3) - ImGui.SameLine(); HelpMarker("Ctrl+Click to input value.") - s.sf1 = ImGui.SliderFloat("slider float", s.sf1, 0.0, 1.0, "ratio = %.3f") - s.sf2 = ImGui.SliderFloat("slider float (log)", s.sf2, -10.0, 10.0, "%.4f", 32 --[[ImGuiSliderFlags.Logarithmic]]) - s.angle = ImGui.SliderAngle("slider angle", s.angle) - - -- Using the format string to display a name instead of an integer. - -- Here we completely omit '%d' from the format string, so it'll only display a name. - -- This technique can also be used with DragInt(). - local elems_names = { "Fire", "Earth", "Air", "Water" } - local elem_name = elems_names[s.elem + 1] or "Unknown" - s.elem = ImGui.SliderInt("slider enum", s.elem, 0, 3, elem_name) -- Use ImGuiSliderFlags.NoInput flag to disable Ctrl+Click here. - ImGui.SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.") - - ImGui.SeparatorText("Selectors/Pickers") - ImGui.ColorEdit3("color 1", s.col1) - ImGui.SameLine(); HelpMarker("Click on the color square to open a color picker.\nClick and hold to use drag and drop.\nRight-Click on the color square to show options.\nCtrl+Click on individual component to input value.\n") - ImGui.ColorEdit4("color 2", s.col2) - - -- Using the _simplified_ one-liner Combo() api here - -- See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. - s.combo = ImGui.Combo("combo", s.combo, { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }) - ImGui.SameLine(); HelpMarker("Using the simplified one-liner Combo API here.") - - -- Using the _simplified_ one-liner ListBox() api here - -- See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. - s.listbox = ImGui.ListBox("listbox", s.listbox, { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }, 9, 4) - ImGui.SameLine(); HelpMarker("Using the simplified one-liner ListBox API here.") - ImGui.TreePop() -end - -S.chdr = { closable_group = true } - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsBullets() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsBullets() - if not ImGui.TreeNode("Bullets") then return end - ImGui.BulletText("Bullet point 1") - ImGui.BulletText("Bullet point 2\nOn multiple lines") - if ImGui.TreeNode("Tree node") then ImGui.BulletText("Another bullet point"); ImGui.TreePop() end - ImGui.Bullet(); ImGui.Text("Bullet point 3 (two calls)") - ImGui.Bullet(); ImGui.SmallButton("Button") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsCollapsingHeaders() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsCollapsingHeaders() - if not ImGui.TreeNode("Collapsing Headers") then return end - local s = S.chdr - _, s.closable_group = ImGui.Checkbox("Show 2nd header", s.closable_group) - if ImGui.CollapsingHeader("Header", 0 --[[ImGuiTreeNodeFlags.None]]) then - ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) - for i = 0, 4 do ImGui.Text("Some content %d", i) end - end - local open - open, s.closable_group = ImGui.CollapsingHeader("Header with a close button", s.closable_group) - if open then - ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) - for i = 0, 4 do ImGui.Text("More content %d", i) end - end - -- if ImGui.CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags.Bullet) then - -- ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered()) - -- end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsColorAndPickers() -------------------------------------------------------------------------------- - -IMGUI_PAYLOAD_TYPE_COLOR_3F = IMGUI_PAYLOAD_TYPE_COLOR_3F or "_COL3F" -IMGUI_PAYLOAD_TYPE_COLOR_4F = IMGUI_PAYLOAD_TYPE_COLOR_4F or "_COL4F" - -S.color = { color = ImVec4(114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 200.0 / 255.0), base_flags = 0, palette = nil, - backup = ImVec4(), no_border = false, ref_color = false, ref_color_v = ImVec4(1.0, 0.0, 1.0, 0.5), picker_mode = 0, - display_mode = 0, picker_flags = ImGuiColorEditFlags.AlphaBar, hsv = ImVec4(0.23, 1.0, 1.0, 1.0) } - -function DemoWindowWidgetsColorAndPickers() - if not ImGui.TreeNode("Color/Picker Widgets") then return end - local s = S.color - local CE = ImGuiColorEditFlags - local color = s.color - - ImGui.SeparatorText("Options") - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.base_flags, CE.NoAlpha) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", s.base_flags, CE.AlphaOpaque) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", s.base_flags, CE.AlphaNoBg) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", s.base_flags, CE.AlphaPreviewHalf) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoOptions", s.base_flags, CE.NoOptions); ImGui.SameLine(); HelpMarker("Right-click on the individual color widget to show options.") - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", s.base_flags, CE.NoDragDrop) - if CE.NoColorMarkers then _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoColorMarkers", s.base_flags, CE.NoColorMarkers) end - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_HDR", s.base_flags, CE.HDR); ImGui.SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.") - local base_flags = s.base_flags - - ImGui.SeparatorText("Inline color editor") - ImGui.Text("Color widget:") - ImGui.SameLine(); HelpMarker("Click on the color square to open a color picker.\nCtrl+Click on individual component to input value.\n") - ImGui.ColorEdit3("MyColor##1", color, base_flags) - ImGui.Text("Color widget HSV with Alpha:") - ImGui.ColorEdit4("MyColor##2", color, bit32.bor(CE.DisplayHSV, base_flags)) - ImGui.Text("Color widget with Float Display:") - ImGui.ColorEdit4("MyColor##2f", color, bit32.bor(CE.Float, base_flags)) - ImGui.Text("Color button with Picker:") - ImGui.SameLine(); HelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup.") - ImGui.ColorEdit4("MyColor##3", color, bit32.bor(CE.NoInputs, CE.NoLabel, base_flags)) - - ImGui.Text("Color button with Custom Picker Popup:") - - -- Generate a default palette. The palette will persist and can be edited. - if s.palette == nil then - s.palette = {} - for n = 0, 31 do s.palette[n] = HSV(n / 31.0, 0.8, 0.8, 1.0) end -- Alpha = 1.0 - end - local open_popup = ImGui.ColorButton("MyColor##3b", color, base_flags) - ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.x) - open_popup = ImGui.Button("Palette") or open_popup - if open_popup then - ImGui.OpenPopup("mypicker") - ImVec4_Copy(s.backup, color) - end - if ImGui.BeginPopup("mypicker") then - ImGui.Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!") - ImGui.Separator() - ImGui.ColorPicker4("##picker", color, bit32.bor(base_flags, CE.NoSidePreview, CE.NoSmallPreview)) - ImGui.SameLine() - ImGui.BeginGroup() -- Lock X position - ImGui.Text("Current") - ImGui.ColorButton("##current", color, bit32.bor(CE.NoPicker, CE.AlphaPreviewHalf), ImVec2(60, 40)) - ImGui.Text("Previous") - if ImGui.ColorButton("##previous", s.backup, bit32.bor(CE.NoPicker, CE.AlphaPreviewHalf), ImVec2(60, 40)) then - ImVec4_Copy(color, s.backup) - end - ImGui.Separator() - ImGui.Text("Palette") - for n = 0, 31 do - ImGui.PushID(n) - if n % 8 ~= 0 then ImGui.SameLine(0.0, ImGui.GetStyle().ItemSpacing.y) end - local pal = s.palette[n] - if ImGui.ColorButton("##palette", pal, bit32.bor(CE.NoAlpha, CE.NoPicker, CE.NoTooltip), ImVec2(20, 20)) then - color.x = pal.x; color.y = pal.y; color.z = pal.z -- Preserve alpha! - end - - -- Allow user to drop colors into each palette entry. Note that ColorButton() is already a - -- drag source by default, unless specifying the ImGuiColorEditFlags.NoDragDrop flag. - if ImGui.BeginDragDropTarget() then - local payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F) - if payload and payload.Data then pal.x, pal.y, pal.z = payload.Data[1], payload.Data[2], payload.Data[3] end - payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F) - if payload and payload.Data then pal.x, pal.y, pal.z, pal.w = payload.Data[1], payload.Data[2], payload.Data[3], payload.Data[4] end - ImGui.EndDragDropTarget() - end - ImGui.PopID() - end - ImGui.EndGroup() - ImGui.EndPopup() - end - - ImGui.Text("Color button only:") - _, s.no_border = ImGui.Checkbox("ImGuiColorEditFlags_NoBorder", s.no_border) - ImGui.ColorButton("MyColor##3c", color, bit32.bor(base_flags, s.no_border and CE.NoBorder or 0), ImVec2(80, 80)) - - ImGui.SeparatorText("Color picker") - ImGui.PushID("Color picker") - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.picker_flags, CE.NoAlpha) - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaBar", s.picker_flags, CE.AlphaBar) - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", s.picker_flags, CE.NoSidePreview) - if bit32.band(s.picker_flags, CE.NoSidePreview) ~= 0 then - ImGui.SameLine() - _, s.ref_color = ImGui.Checkbox("With Ref Color", s.ref_color) - if s.ref_color then - ImGui.SameLine() - ImGui.ColorEdit4("##RefColor", s.ref_color_v, bit32.bor(CE.NoInputs, base_flags)) - end - end - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_PickerNoRotate", s.picker_flags, CE.PickerNoRotate) - s.picker_mode = ImGui.Combo("Picker Mode", s.picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0") - ImGui.SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode.") - s.display_mode = ImGui.Combo("Display Mode", s.display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0") - ImGui.SameLine(); HelpMarker("ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex if you don't specify a display mode.\n\nYou can change the defaults using io.ConfigColorEditFlags.") - local flags = bit32.bor(base_flags, s.picker_flags) - if s.picker_mode == 1 then flags = bit32.bor(flags, CE.PickerHueBar) end - if s.picker_mode == 2 then flags = bit32.bor(flags, CE.PickerHueWheel) end - if s.display_mode == 1 then flags = bit32.bor(flags, CE.NoInputs) end -- Disable all RGB/HSV/Hex displays - if s.display_mode == 2 then flags = bit32.bor(flags, CE.DisplayRGB) end -- Override display mode - if s.display_mode == 3 then flags = bit32.bor(flags, CE.DisplayHSV) end - if s.display_mode == 4 then flags = bit32.bor(flags, CE.DisplayHex) end - ImGui.ColorPicker4("MyColor##4", color, flags, s.ref_color and s.ref_color_v or nil) - - ImGui.Text("Set defaults in code:") - ImGui.SameLine(); HelpMarker("io.ConfigColorEditFlags is designed to allow you to set boot-time default.") - if ImGui.Button("Overwrite default: Uint8 + HSV + Hue Bar") then - ImGui.GetIO().ConfigColorEditFlags = bit32.bor(CE.Uint8, CE.DisplayHSV, CE.PickerHueBar, CE.InputRGB) -- [port] + InputRGB: upstream omits it and then trips its own InputMask_ assert - end - if ImGui.Button("Overwrite default: Float + HDR + Hue Wheel") then - ImGui.GetIO().ConfigColorEditFlags = bit32.bor(CE.Float, CE.HDR, CE.PickerHueWheel, CE.DisplayRGB, CE.InputRGB) - end - - -- Always display a small version of both types of pickers - -- (that's in order to make it more visible in the demo to people who are skimming quickly through it) - ImGui.Text("Both types:") - local w = (ImGui.GetContentRegionAvail().x - ImGui.GetStyle().ItemSpacing.y) * 0.40 - ImGui.SetNextItemWidth(w) - ImGui.ColorPicker3("##MyColor##5", color, bit32.bor(CE.PickerHueBar, CE.NoSidePreview, CE.NoInputs, CE.NoAlpha)) - ImGui.SameLine() - ImGui.SetNextItemWidth(w) - ImGui.ColorPicker3("##MyColor##6", color, bit32.bor(CE.PickerHueWheel, CE.NoSidePreview, CE.NoInputs, CE.NoAlpha)) - ImGui.PopID() - - -- HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) - -- (s.hsv is stored as HSV!) - ImGui.Spacing() - ImGui.Text("HSV encoded colors") - ImGui.SameLine(); HelpMarker("By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV.") - ImGui.Text("Color widget with InputHSV:") - ImGui.ColorEdit4("HSV shown as RGB##1", s.hsv, bit32.bor(CE.DisplayRGB, CE.InputHSV, CE.Float)) - ImGui.ColorEdit4("HSV shown as HSV##1", s.hsv, bit32.bor(CE.DisplayHSV, CE.InputHSV, CE.Float)) - ImGui.DragFloat4("Raw HSV values", s.hsv, 0.01, 0.0, 1.0) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsComboBoxes() -------------------------------------------------------------------------------- - -S.combo = { flags = 0, sel = 0, filter = nil, c2 = 0, c3 = -1, c4 = 0 } -- sel: Here we store our selection data as an index. -function DemoWindowWidgetsComboBoxes() - if not ImGui.TreeNode("Combo") then return end - local s = S.combo - local CF = ImGuiComboFlags - local p - -- Combo Boxes are also called "Dropdown" in other systems - -- Expose flags as checkbox for the demo - _, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", s.flags, CF.PopupAlignLeft) - ImGui.SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo") - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoArrowButton", s.flags, CF.NoArrowButton) - if p then s.flags = bit32.band(s.flags, bit32.bnot(CF.NoPreview)) end -- Clear incompatible flags - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoPreview", s.flags, CF.NoPreview) - if p then s.flags = bit32.band(s.flags, bit32.bnot(bit32.bor(CF.NoArrowButton, CF.WidthFitPreview))) end -- Clear incompatible flags - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_WidthFitPreview", s.flags, CF.WidthFitPreview) - if p then s.flags = bit32.band(s.flags, bit32.bnot(CF.NoPreview)) end - - -- Override default popup height - for _, h in ipairs({ "HeightSmall", "HeightRegular", "HeightLargest" }) do - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_" .. h, s.flags, CF[h]) - if p then s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(CF.HeightMask_, bit32.bnot(CF[h])))) end - end - - -- Using the generic BeginCombo() API, you have full control over how to display the combo contents. - -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively - -- stored in the object itself, etc.) - local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } - - -- Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) - local combo_preview_value = items[s.sel + 1] - if ImGui.BeginCombo("combo 1", combo_preview_value, s.flags) then - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - if ImGui.Selectable(items[n + 1], is_selected) then s.sel = n end - - -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndCombo() - end - - -- Show case embedding a filter using a simple trick: displaying the filter inside combo contents. - -- See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives. - if ImGui.BeginCombo("combo 2 (w/ filter)", combo_preview_value, s.flags) then - s.filter = s.filter or ImGuiTextFilter() - if ImGui.IsWindowAppearing() then - ImGui.SetKeyboardFocusHere() - s.filter:Clear() - end - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 551 --[[ImGuiKey.F]])) - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - s.filter:DrawWithHint("##Filter", "Filter (incl -excl)") - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - if s.filter:PassFilter(items[n + 1]) then - if ImGui.Selectable(items[n + 1], is_selected) then s.sel = n end - end - end - ImGui.EndCombo() - end - - ImGui.Spacing() - ImGui.SeparatorText("One-liner variants") - HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section.") - - -- Simplified one-liner Combo() API, using values packed in a single constant string - -- This is a convenience for when the selection set is small and known at compile-time. - s.c2 = ImGui.Combo("combo 3 (one-liner)", s.c2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0") - - -- Simplified one-liner Combo() using an array of strings - -- This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. - s.c3 = ImGui.Combo("combo 4 (array)", s.c3, items, #items) -- If the selection isn't within 0..count, Combo won't display a preview - - -- Simplified one-liner Combo() using an accessor function - s.c4 = ImGui.Combo("combo 5 (function)", s.c4, function(data, n) return data[n + 1] end, items, #items) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDataTypes() -------------------------------------------------------------------------------- - -S.dt = { s8 = 127, u8 = 255, s16 = 32767, u16 = 65535, s32 = -1, u32 = 0xFFFFFFFF, s64 = -1, u64 = 0, f32 = 0.123, f64 = 90000.01234567890123456789, - drag_clamp = false, inputs_step = true, flags = 0 } -function DemoWindowWidgetsDataTypes() - if not ImGui.TreeNode("Data Types") then return end - local s = S.dt - local DT = ImGuiDataType - -- DragScalar/InputScalar/SliderScalar functions allow various data types - -- - signed/unsigned - -- - 8/16/32/64-bits - -- - integer/float/double - -- To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum - -- to pass the type. - -- In practice, if you frequently use a given type that is not covered by the normal API entry points, - -- you can wrap it yourself inside a 1 line function which can take typed argument as value, - -- and then pass them to the generic function. For example: - -- local function MySliderU32(label, value, min, max, format) - -- return ImGui.SliderScalar(label, ImGuiDataType.U32, value, min or 0, max or 0, format or "%u") - -- end - - -- ponytail: Luau numbers are doubles, so S64/U64 are shown with S32/Double here (no 64-bit integer type) - -- Setup limits - -- Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. - local s32_min, s32_max = math.floor(-2147483648 / 2), math.floor(2147483647 / 2) - local u32_max = math.floor(4294967295 / 2) - local drag_speed = 0.2 - ImGui.SeparatorText("Drags") - _, s.drag_clamp = ImGui.Checkbox("Clamp integers to 0..50", s.drag_clamp) - ImGui.SameLine(); HelpMarker("As with every widget in dear imgui, we never modify values unless there is a user interaction.\nYou can override the clamping limits by using Ctrl+Click to input a value.") - local lo, hi = s.drag_clamp and 0 or nil, s.drag_clamp and 50 or nil - s.s8 = ImGui.DragScalar("drag s8", DT.S8, s.s8, drag_speed, lo, hi) - s.u8 = ImGui.DragScalar("drag u8", DT.U8, s.u8, drag_speed, lo, hi, "%u ms") - s.s16 = ImGui.DragScalar("drag s16", DT.S16, s.s16, drag_speed, lo, hi) - s.u16 = ImGui.DragScalar("drag u16", DT.U16, s.u16, drag_speed, lo, hi, "%u ms") - s.s32 = ImGui.DragScalar("drag s32", DT.S32, s.s32, drag_speed, lo, hi) - s.s32 = ImGui.DragScalar("drag s32 hex", DT.S32, s.s32, drag_speed, lo, hi, "0x%08X") - s.u32 = ImGui.DragScalar("drag u32", DT.U32, s.u32, drag_speed, lo, hi, "%u ms") - s.f32 = ImGui.DragScalar("drag float", DT.Float, s.f32, 0.005, 0.0, 1.0, "%f") - s.f32 = ImGui.DragScalar("drag float log", DT.Float, s.f32, 0.005, 0.0, 1.0, "%f", 32 --[[ImGuiSliderFlags.Logarithmic]]) - s.f64 = ImGui.DragScalar("drag double", DT.Double, s.f64, 0.0005, 0.0, nil, "%.10f grams") - s.f64 = ImGui.DragScalar("drag double log",DT.Double, s.f64, 0.0005, 0.0, 1.0, "0 < %.10f < 1", 32 --[[ImGuiSliderFlags.Logarithmic]]) - - ImGui.SeparatorText("Sliders") - s.s8 = ImGui.SliderScalar("slider s8 full", DT.S8, s.s8, -128, 127, "%d") - s.u8 = ImGui.SliderScalar("slider u8 full", DT.U8, s.u8, 0, 255, "%u") - s.s16 = ImGui.SliderScalar("slider s16 full", DT.S16, s.s16, -32768, 32767, "%d") - s.u16 = ImGui.SliderScalar("slider u16 full", DT.U16, s.u16, 0, 65535, "%u") - s.s32 = ImGui.SliderScalar("slider s32 low", DT.S32, s.s32, 0, 50, "%d") - s.s32 = ImGui.SliderScalar("slider s32 high", DT.S32, s.s32, s32_max - 100, s32_max, "%d") - s.s32 = ImGui.SliderScalar("slider s32 full", DT.S32, s.s32, s32_min, s32_max, "%d") - s.s32 = ImGui.SliderScalar("slider s32 hex", DT.S32, s.s32, 0, 50, "0x%04X") - s.u32 = ImGui.SliderScalar("slider u32 low", DT.U32, s.u32, 0, 50, "%u") - s.u32 = ImGui.SliderScalar("slider u32 high", DT.U32, s.u32, u32_max - 100, u32_max, "%u") - s.u32 = ImGui.SliderScalar("slider u32 full", DT.U32, s.u32, 0, u32_max, "%u") - s.f32 = ImGui.SliderScalar("slider float low", DT.Float, s.f32, 0.0, 1.0) - s.f32 = ImGui.SliderScalar("slider float low log", DT.Float, s.f32, 0.0, 1.0, "%.10f", 32 --[[ImGuiSliderFlags.Logarithmic]]) - s.f32 = ImGui.SliderScalar("slider float high", DT.Float, s.f32, -10000000000.0, 10000000000.0, "%e") - s.f64 = ImGui.SliderScalar("slider double low", DT.Double, s.f64, 0.0, 1.0, "%.10f grams") - s.f64 = ImGui.SliderScalar("slider double low log", DT.Double, s.f64, 0.0, 1.0, "%.10f", 32 --[[ImGuiSliderFlags.Logarithmic]]) - s.f64 = ImGui.SliderScalar("slider double high", DT.Double, s.f64, -1000000000000000.0, 1000000000000000.0, "%e grams") - - ImGui.SeparatorText("Sliders (reverse)") - s.s8 = ImGui.SliderScalar("slider s8 reverse", DT.S8, s.s8, 127, -128, "%d") - s.u8 = ImGui.SliderScalar("slider u8 reverse", DT.U8, s.u8, 255, 0, "%u") - s.s32 = ImGui.SliderScalar("slider s32 reverse", DT.S32, s.s32, 50, 0, "%d") - s.u32 = ImGui.SliderScalar("slider u32 reverse", DT.U32, s.u32, 50, 0, "%u") - - ImGui.SeparatorText("Inputs") - _, s.inputs_step = ImGui.Checkbox("Show step buttons", s.inputs_step) - _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, 512 --[[ImGuiInputTextFlags.ReadOnly]]) - if 8192 --[[ImGuiInputTextFlags.ParseEmptyRefVal]] then _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", s.flags, 8192 --[[ImGuiInputTextFlags.ParseEmptyRefVal]]) end - if 16384 --[[ImGuiInputTextFlags.DisplayEmptyRefVal]] then _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", s.flags, 16384 --[[ImGuiInputTextFlags.DisplayEmptyRefVal]]) end - local one = s.inputs_step and 1 or nil - s.s8 = ImGui.InputScalar("input s8", DT.S8, s.s8, one, nil, "%d", s.flags) - s.u8 = ImGui.InputScalar("input u8", DT.U8, s.u8, one, nil, "%u", s.flags) - s.s16 = ImGui.InputScalar("input s16", DT.S16, s.s16, one, nil, "%d", s.flags) - s.u16 = ImGui.InputScalar("input u16", DT.U16, s.u16, one, nil, "%u", s.flags) - s.s32 = ImGui.InputScalar("input s32", DT.S32, s.s32, one, nil, "%d", s.flags) - s.s32 = ImGui.InputScalar("input s32 hex", DT.S32, s.s32, one, nil, "%04X", s.flags) - s.u32 = ImGui.InputScalar("input u32", DT.U32, s.u32, one, nil, "%u", s.flags) - s.u32 = ImGui.InputScalar("input u32 hex", DT.U32, s.u32, one, nil, "%08X", s.flags) - s.f32 = ImGui.InputScalar("input float", DT.Float, s.f32, s.inputs_step and 1.0 or nil, nil, nil, s.flags) - s.f64 = ImGui.InputScalar("input double", DT.Double, s.f64, s.inputs_step and 1.0 or nil, nil, nil, s.flags) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDisableBlocks() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsDisableBlocks(demo_data) - if not ImGui.TreeNode("Disable Blocks") then return end - _, demo_data.DisableSections = ImGui.Checkbox("Disable entire section above", demo_data.DisableSections) - ImGui.SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections.") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDragAndDrop() -------------------------------------------------------------------------------- - -S.dnd = { col1 = { 1.0, 0.0, 0.2 }, col2 = { 0.4, 0.7, 0.0, 0.5 }, mode = 0, - names = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" }, - item_names = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }, col4 = ImVec4(1.0, 0.0, 0.2, 1.0) } -function DemoWindowWidgetsDragAndDrop() - if not ImGui.TreeNode("Drag and Drop") then return end - local s = S.dnd - if ImGui.TreeNode("Drag and drop in standard widgets") then - -- ColorEdit widgets automatically act as drag source and drag target. - -- They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F - -- to allow your own widgets to use colors in their drag and drop interaction. - -- Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. - HelpMarker("You can drag from the color squares.") - ImGui.ColorEdit3("color 1", s.col1) - ImGui.ColorEdit4("color 2", s.col2) - ImGui.TreePop() - end - - if ImGui.TreeNode("Drag and drop to copy/swap items") then - local Mode_Copy, Mode_Move, Mode_Swap = 0, 1, 2 - if ImGui.RadioButtonEx("Copy", s.mode == Mode_Copy) then s.mode = Mode_Copy end ImGui.SameLine() - if ImGui.RadioButtonEx("Move", s.mode == Mode_Move) then s.mode = Mode_Move end ImGui.SameLine() - if ImGui.RadioButtonEx("Swap", s.mode == Mode_Swap) then s.mode = Mode_Swap end - local names = s.names - for n = 0, #names - 1 do - ImGui.PushID(n) - if n % 3 ~= 0 then ImGui.SameLine() end - ImGui.Button(names[n + 1], ImVec2(60, 60)) - - -- Our buttons are both drag sources and drag targets here! - if ImGui.BeginDragDropSource(0 --[[ImGuiDragDropFlags.None]]) then - -- Set payload to carry the index of our item (could be anything) - ImGui.SetDragDropPayload("DND_DEMO_CELL", n, 4) - - -- Display preview (could be anything, e.g. when dragging an image we could decide to display - -- the filename and a small preview of the image, etc.) - if s.mode == Mode_Copy then ImGui.Text("Copy %s", names[n + 1]) end - if s.mode == Mode_Move then ImGui.Text("Move %s", names[n + 1]) end - if s.mode == Mode_Swap then ImGui.Text("Swap %s", names[n + 1]) end - ImGui.EndDragDropSource() - end - if ImGui.BeginDragDropTarget() then - local payload = ImGui.AcceptDragDropPayload("DND_DEMO_CELL") - if payload then - local payload_n = payload.Data - if s.mode == Mode_Copy then names[n + 1] = names[payload_n + 1] end - if s.mode == Mode_Move then names[n + 1] = names[payload_n + 1]; names[payload_n + 1] = "" end - if s.mode == Mode_Swap then names[n + 1], names[payload_n + 1] = names[payload_n + 1], names[n + 1] end - end - ImGui.EndDragDropTarget() - end - ImGui.PopID() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Drag to reorder items (simple)") then - -- FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. - -- This code was always slightly faulty but in a way which was not easily noticeable. - -- Until we fix this, enable ImGuiItemFlags.AllowDuplicateId to disable detecting the issue. - ImGui.PushItemFlag(32 --[[ImGuiItemFlags.AllowDuplicateId]], true) - - -- Simple reordering - HelpMarker("We don't use the drag and drop api at all here! Instead we query when the item is held but not hovered, and order items accordingly.") - local item_names = s.item_names - for n = 1, #item_names do - local item = item_names[n] - ImGui.Selectable(item) - if ImGui.IsItemActive() and not ImGui.IsItemHovered() then - local n_next = n + ((ImGui.GetMouseDragDelta(0).y < 0.0) and -1 or 1) - if n_next >= 1 and n_next <= #item_names then - item_names[n] = item_names[n_next] - item_names[n_next] = item - ImGui.ResetMouseDragDelta() - end - end - end - ImGui.PopItemFlag() - ImGui.TreePop() - end - - if ImGui.TreeNode("Tooltip at target location") then - for n = 0, 1 do - -- Drop targets - ImGui.Button((n == 1) and "drop here##1" or "drop here##0") - if ImGui.BeginDragDropTarget() then - local drop_target_flags = bit32.bor(1024 --[[ImGuiDragDropFlags.AcceptBeforeDelivery]], 4096 --[[ImGuiDragDropFlags.AcceptNoPreviewTooltip]]) - if ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags) then - ImGui.SetMouseCursor(10 --[[ImGuiMouseCursor.NotAllowed]]) - ImGui.SetTooltip("Cannot drop here!") - end - ImGui.EndDragDropTarget() - end - - -- Drop source - if n == 0 then ImGui.ColorButton("drag me", s.col4) end - end - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDragsAndSliders() -------------------------------------------------------------------------------- - -S.ds = { flags = 0, drag_f = 0.5, drag_f4 = { 0, 0, 0, 0 }, drag_i = 50, slider_f = 0.5, slider_f4 = { 0, 0, 0, 0 }, slider_i = 50 } -function DemoWindowWidgetsDragsAndSliders() - if not ImGui.TreeNode("Drag/Slider Flags") then return end - -- Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! - local s = S.ds - local SF = ImGuiSliderFlags - local function F(name, help) - if SF[name] == nil then return end - _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_" .. name, s.flags, SF[name]) - if help then ImGui.SameLine(); HelpMarker(help) end - end - F("AlwaysClamp") - F("ClampOnInput", "Clamp value to min/max bounds when input manually with Ctrl+Click. By default Ctrl+Click allows going out of bounds.") - F("ClampZeroRange", "Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.") - F("Logarithmic", "Enable logarithmic editing (more precision for small values).") - F("NoRoundToFormat", "Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).") - F("NoInput", "Disable Ctrl+Click or Enter key allowing to input text directly into the widget.") - F("NoSpeedTweaks", "Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.") - F("WrapAround", "Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)") - F("ColorMarkers") - local flags = s.flags - - -- Drags - ImGui.Text("Underlying float value: %f", s.drag_f) - s.drag_f = ImGui.DragFloat("DragFloat (0 -> 1)", s.drag_f, 0.005, 0.0, 1.0, "%.3f", flags) - s.drag_f = ImGui.DragFloat("DragFloat (0 -> +inf)", s.drag_f, 0.005, 0.0, 3.4028234663853e+38 --[[FLT_MAX]], "%.3f", flags) - s.drag_f = ImGui.DragFloat("DragFloat (-inf -> 1)", s.drag_f, 0.005, -3.4028234663853e+38 --[[FLT_MAX]], 1.0, "%.3f", flags) - s.drag_f = ImGui.DragFloat("DragFloat (-inf -> +inf)", s.drag_f, 0.005, -3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]], "%.3f", flags) - -- ImGui.DragFloat("DragFloat (0 -> 0)", drag_f, 0.005, 0.0, 0.0, "%.3f", flags) -- To test ClampZeroRange - -- ImGui.DragFloat("DragFloat (100 -> 100)", drag_f, 0.005, 100.0, 100.0, "%.3f", flags) - s.drag_i = ImGui.DragInt("DragInt (0 -> 100)", s.drag_i, 0.5, 0, 100, "%d", flags) - ImGui.DragFloat4("DragFloat4 (0 -> 1)", s.drag_f4, 0.005, 0.0, 1.0, "%.3f", flags) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags.ColorMarkers. - - -- Sliders - local flags_for_sliders = bit32.band(flags, bit32.bnot(SF.WrapAround)) - ImGui.Text("Underlying float value: %f", s.slider_f) - s.slider_f = ImGui.SliderFloat("SliderFloat (0 -> 1)", s.slider_f, 0.0, 1.0, "%.3f", flags_for_sliders) - s.slider_i = ImGui.SliderInt("SliderInt (0 -> 100)", s.slider_i, 0, 100, "%d", flags_for_sliders) - ImGui.SliderFloat4("SliderFloat4 (0 -> 1)", s.slider_f4, 0.0, 1.0, "%.3f", flags_for_sliders) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags.ColorMarkers. - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsFonts() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsFonts() - if not ImGui.TreeNode("Fonts") then return end - if ImGui.ShowFontAtlas then ImGui.ShowFontAtlas(ImGui.GetIO().Fonts) else DemoNotPorted("ShowFontAtlas") end - -- FIXME-NEWATLAS: Provide a demo to add/create a procedural font? - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsImages() -------------------------------------------------------------------------------- - -S.img = { viewer = nil, pressed_count = 0 } -function DemoWindowWidgetsImages() - if not ImGui.TreeNode("Images") then return end - local s = S.img - local io = ImGui.GetIO() - ImGui.TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!") - - -- Below we are displaying the font texture because it is the only texture we have access to inside the demo! - -- Read description about ImTextureID/ImTextureRef and FAQ for details about texture identifiers. - -- - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, - -- it will help you debug issues if you are confused about it. - -- - Consider using the lower-level ImDrawList:AddImage() API, via ImGui.GetWindowDrawList():AddImage(). - -- - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md - -- - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - - -- Grab the current texture identifier used by the font atlas. - local atlas = io.Fonts - local my_tex_id = atlas.TexRef - local my_tex_w = atlas.TexData and atlas.TexData.Width or 0 -- Regular user code should never have to care about TexData fields, but since we want to display the entire texture here, we pull Width/Height from it. - local my_tex_h = atlas.TexData and atlas.TexData.Height or 0 - ImGui.Text("%.0fx%.0f", my_tex_w, my_tex_h) - - -- Basic drawing - ImGui.SeparatorText("Image()/ImageWithBg() function") - ImGui.PushStyleVar(24 --[[ImGuiStyleVar.ImageBorderSize]], math.max(1.0, ImGui.GetStyle().ImageBorderSize)) - ImGui.ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0.0, 0.0), ImVec2(1.0, 1.0), ImVec4(0.0, 0.0, 0.0, 1.0)) -- uv_min: Top-left, uv_max: Lower-right - ImGui.PopStyleVar() - - -- Fancy widget - ImGui.SeparatorText("Interactive Image Viewer") - s.viewer = s.viewer or ExampleImageViewerData() - local canvas_size = ImVec2(ImGui.GetContentRegionAvail().x, my_tex_h * 2.0) - ExampleImageViewer_DrawOptions(s.viewer) - ExampleImageViewer_DrawCanvas(s.viewer, canvas_size, my_tex_id, my_tex_w, my_tex_h) - - ImGui.SeparatorText("Textured Buttons") - ImGui.TextWrapped("And now some textured buttons..") - for i = 0, 7 do - -- UV coordinates are often (0.0, 0.0) and (1.0, 1.0) to display an entire textures. - -- Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation. - -- Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - ImGui.PushID(i) - if i > 0 then ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(i - 1.0, i - 1.0)) end - local size = ImVec2(32.0, 32.0) -- Size of the image we want to make visible - local uv0 = ImVec2(0.0, 0.0) -- UV coordinates for lower-left - local uv1 = ImVec2(32.0 / my_tex_w, 32.0 / my_tex_h) -- UV coordinates for (32,32) in our texture - -- bg_col: Black background, tint_col: No tint - if ImGui.ImageButton("", my_tex_id, size, uv0, uv1, ImVec4(0.0, 0.0, 0.0, 1.0), ImVec4(1.0, 1.0, 1.0, 1.0)) then - s.pressed_count = s.pressed_count + 1 - end - if i > 0 then ImGui.PopStyleVar() end - ImGui.PopID() - ImGui.SameLine() - end - ImGui.NewLine() - ImGui.Text("Pressed %d times.", s.pressed_count) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsListBoxes() -------------------------------------------------------------------------------- - -S.lb = { sel = 0, highlight = false } -- sel: Here we store our selected data as an index. -function DemoWindowWidgetsListBoxes() - if not ImGui.TreeNode("List Boxes") then return end - -- BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() - -- using the ImGuiChildFlags.FrameStyle flag for stylistic changes + displaying a label. - -- You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild() - -- to always be called (inconsistent with BeginListBox()/EndListBox()). - - -- Using the generic BeginListBox() API, you have full control over how to display the combo contents. - -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively - -- stored in the object itself, etc.) - local s = S.lb - local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } - local item_highlighted_idx = -1 -- Here we store our highlighted data as an index. - _, s.highlight = ImGui.Checkbox("Highlight hovered item in second listbox", s.highlight) - if ImGui.BeginListBox("listbox 1") then - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - if ImGui.Selectable(items[n + 1], is_selected) then s.sel = n end - if s.highlight and ImGui.IsItemHovered() then item_highlighted_idx = n end - -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndListBox() - end - ImGui.SameLine(); HelpMarker("Here we are sharing selection state between both boxes.") - - -- Custom size: use all width, 5 items tall - ImGui.Text("Full-width:") - if ImGui.BeginListBox("##listbox 2", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 5 * ImGui.GetTextLineHeightWithSpacing())) then - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - local flags = (item_highlighted_idx == n) and 32 --[[ImGuiSelectableFlags.Highlight]] or 0 - if ImGui.Selectable(items[n + 1], is_selected, flags) then s.sel = n end - -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndListBox() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsLiveEdit() -------------------------------------------------------------------------------- - -S.le = { str = Buf("", 32), i = 0, f = 0.0 } -function DemoWindowWidgetsLiveEdit(demo_data) - if not ImGui.TreeNode("Live Edit Flags") then return end - local s = S.le - ImGui.TextWrapped("Select whether to apply keyboard edits to backing variables _while_ typing.") - _, demo_data.LiveEditOverride = ImGui.Checkbox("Override Live Edit Flags in Demo Window", demo_data.LiveEditOverride) - if not demo_data.LiveEditOverride then demo_data.LiveEditFlags = ImGui.GetItemFlags() end - ImGui.BeginDisabled(demo_data.LiveEditOverride == false) - ImGui.Indent() - _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputText", demo_data.LiveEditFlags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) - _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputScalar", demo_data.LiveEditFlags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) - ImGui.Unindent() - ImGui.EndDisabled() - ImGui.Text("Try typing '123' and seeing effect on backing value:") - ImGui.InputText("str", s.str, 32) - ImGui.Text("Backing value: \"%s\"", BufStr(s.str)) - s.i = ImGui.InputInt("int", s.i, 0, 0) - ImGui.Text("Backing value: %d", s.i) - s.f = ImGui.SliderFloat("float", s.f, 0.0, 100.0) - ImGui.Text("Backing value: %f", s.f) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsMixedValues() -------------------------------------------------------------------------------- - -S.mv = { use_liveedit = false, items = { 12.0, 0.0, 0.0 } } -function DemoWindowWidgetsMixedValues() - if not ImGui.TreeNode("Mixed Values") then return end - local s = S.mv - local items = s.items - -- This is designed for advanced property editors which are generally reusable and data-driven. - HelpMarker("Using ImGuiItemFlags_MixedValue.") - _, s.use_liveedit = ImGui.Checkbox("ImGuiItemFlags_LiveEditOnInput", s.use_liveedit) - ImGui.SeparatorText("Scalar/Text Widgets") - local is_mixed = items[1] ~= items[2] or items[1] ~= items[3] - - -- Demonstrate Drags, Sliders, Inputs - ImGui.PushItemFlag(384 --[[ImGuiItemFlags.LiveEditOnInput]], s.use_liveedit) - ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], is_mixed) - local edited, e = false, false - items[1], e = ImGui.DragFloat("DragFloat", items[1]); edited = edited or e - items[1], e = ImGui.SliderFloat("SliderFloat", items[1], 0.0, 100.0); edited = edited or e - items[1], e = ImGui.InputFloat("InputFloat", items[1], 1.0); edited = edited or e - if edited then items[2] = items[1]; items[3] = items[1] end - ImGui.PopItemFlag() - ImGui.Text("Underlying data:") - items[1] = ImGui.InputFloat("item 0 (ref)", items[1]) - items[2] = ImGui.InputFloat("item 1", items[2]) - items[3] = ImGui.InputFloat("item 2", items[3]) - ImGui.PopItemFlag() - - -- Demonstrate Checkbox(), RadioButton(), Combo(), ColorEdit4() - ImGui.SeparatorText("Others Widgets") - ImGui.Text("(note: edits are not applied in this demo)") -- <-- Would need more state tracking. - ImGui.Checkbox("Checkbox On", true) - ImGui.Checkbox("Checkbox Off", false) - ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], true) - ImGui.Checkbox("Checkbox Mixed", false) - ImGui.RadioButtonEx("RadioButton Mixed", true) - ImGui.SameLine() - ImGui.RadioButtonEx("RadioButton Mixed##2", true) -- Showing 2 radio buttons makes the example more clear - ImGui.Combo("Combo", 0, "One\0Two\0Three\0") - ImGui.ColorEdit4("ColorEdit4", ImVec4(0.5, 0.5, 0.5, 0.5)) - ImGui.PopItemFlag() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsMultiComponents() -------------------------------------------------------------------------------- - -S.mc = { vec4f = { 0.10, 0.20, 0.30, 0.44 }, vec4i = { 1, 5, 100, 255 }, flags = 0, b = 10, e = 90, bi = 100, ei = 1000 } -function DemoWindowWidgetsMultiComponents() - if not ImGui.TreeNode("Multi-component Widgets") then return end - local s = S.mc - local f, i = s.vec4f, s.vec4i - if 4096 --[[ImGuiSliderFlags.ColorMarkers]] then _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ColorMarkers", s.flags, 4096 --[[ImGuiSliderFlags.ColorMarkers]]) end -- Only passing this to Drag/Sliders - local flags = s.flags - for _, n in ipairs({ 2, 3, 4 }) do - ImGui.SeparatorText(n .. "-wide") - ImGui["InputFloat" .. n]("input float" .. n, f) - ImGui["InputInt" .. n]("input int" .. n, i) - ImGui["DragFloat" .. n]("drag float" .. n, f, 0.01, 0.0, 1.0, nil, flags) - ImGui["DragInt" .. n]("drag int" .. n, i, 1, 0, 255, nil, flags) - ImGui["SliderFloat" .. n]("slider float" .. n, f, 0.0, 1.0, nil, flags) - ImGui["SliderInt" .. n]("slider int" .. n, i, 0, 255, nil, flags) - end - ImGui.SeparatorText("Ranges") - s.b, s.e = ImGui.DragFloatRange2("range float", s.b, s.e, 0.25, 0.0, 100.0, "Min: %.1f %%", "Max: %.1f %%", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) - s.bi, s.ei = ImGui.DragIntRange2("range int", s.bi, s.ei, 5, 0, 1000, "Min: %d units", "Max: %d units") - s.bi, s.ei = ImGui.DragIntRange2("range int (no bounds)", s.bi, s.ei, 5, 0, 0, "Min: %d units", "Max: %d units") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsPlotting() -------------------------------------------------------------------------------- - --- Plot/Graph widgets are not very good. --- Consider using a third-party library such as ImPlot: https://github.com/epezent/implot --- (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) -S.plot = { animate = true, arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, values = {}, values_offset = 0, refresh_time = 0.0, phase = 0.0, - func_type = 0, display_count = 70 } -for n = 1, 90 do S.plot.values[n] = 0.0 end -function DemoWindowWidgetsPlotting() - if not ImGui.TreeNode("Plotting") then return end - local s = S.plot - ImGui.Text("Need better plotting and graphing? Consider using ImPlot:") - ImGui.TextLinkOpenURL("https://github.com/epezent/implot") - ImGui.Separator() - _, s.animate = ImGui.Checkbox("Animate", s.animate) - - -- Plot as lines and plot as histogram - ImGui.PlotLines("Frame Times", s.arr, nil, #s.arr) - ImGui.PlotHistogram("Histogram", s.arr, nil, #s.arr, 0, nil, 0.0, 1.0, ImVec2(0, 80.0)) - -- ImGui.SameLine(); HelpMarker("Consider using ImPlot instead!") - - -- Fill an array of contiguous float values to plot - local values = s.values - if not s.animate or s.refresh_time == 0.0 then s.refresh_time = ImGui.GetTime() end - while s.refresh_time < ImGui.GetTime() do -- Create data at fixed 60 Hz rate for the demo - values[s.values_offset + 1] = math.cos(s.phase) - s.values_offset = (s.values_offset + 1) % #values - s.phase = s.phase + 0.10 * s.values_offset - s.refresh_time = s.refresh_time + 1.0 / 60.0 - end - - -- Plots can display overlay texts - -- (in this example, we will display an average value) - local average = 0.0 - for n = 1, #values do average = average + values[n] end - average = average / #values - ImGui.PlotLines("Lines", values, nil, #values, s.values_offset, string.format("avg %f", average), -1.0, 1.0, ImVec2(0, 80.0)) - - -- Use functions to generate output - -- FIXME: This is actually VERY awkward because current plot API only pass in indices. - -- We probably want an API passing floats and user provide sample rate/count. - -- Getters receive a 1-based index in this port - local function Sin(_, i) return math.sin((i - 1) * 0.1) end - local function Saw(_, i) return ((i - 1) % 2 == 1) and 1.0 or -1.0 end - ImGui.SeparatorText("Functions") - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - s.func_type = ImGui.Combo("func", s.func_type, "Sin\0Saw\0") - ImGui.SameLine() - s.display_count = ImGui.SliderInt("Sample count", s.display_count, 1, 400) - local func = (s.func_type == 0) and Sin or Saw - ImGui.PlotLines("Lines##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) - ImGui.PlotHistogram("Histogram##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsProgressBars() -------------------------------------------------------------------------------- - -S.pb = { accum = 0.0, dir = 1.0 } -function DemoWindowWidgetsProgressBars() - if not ImGui.TreeNode("Progress Bars") then return end - -- Animate a simple progress bar - local s = S.pb - s.accum = s.accum + s.dir * 0.4 * ImGui.GetIO().DeltaTime - if s.accum >= 1.1 then s.accum = 1.1; s.dir = -s.dir end - if s.accum <= -0.1 then s.accum = -0.1; s.dir = -s.dir end - local progress = DemoClamp(s.accum, 0.0, 1.0) - - -- Typically we would use ImVec2(-1.0,0.0) or ImVec2(-FLT_MIN,0.0) to use all available width, - -- or ImVec2(width,0.0) for a specified width. ImVec2(0.0,0.0) uses ItemWidth. - ImGui.ProgressBar(progress, ImVec2(0.0, 0.0)) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - ImGui.Text("Progress Bar") - ImGui.ProgressBar(progress, ImVec2(0.0, 0.0), string.format("%d/%d", math.floor(progress * 1753), 1753)) - - -- Pass an animated negative value, e.g. -1.0 * ImGui.GetTime() is the recommended value. - -- Adjust the factor if you want to adjust the animation speed. - ImGui.ProgressBar(-1.0 * ImGui.GetTime(), ImVec2(0.0, 0.0), "Searching..") - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - ImGui.Text("Indeterminate") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsQueryingStatuses() -------------------------------------------------------------------------------- - --- Selectable(label, bool* p_selected) overload: toggles on press -local function SelectableP(label, sel, flags, size) - local pressed = ImGui.Selectable(label, sel, flags, size) - if pressed then sel = not sel end - return pressed, sel -end - -local function B(v) return v and 1 or 0 end - -S.qs = { item_type = 4, item_disabled = false, item_mixedvalue = false, liveedit_override = false, liveedit_flags = 0, - b = false, col4f = { 1.0, 0.5, 0.0, 1.0 }, str = Buf("", 16), combo = 1, listbox = 1, unused = Buf("", 1), - embed = false, test_window = false } -function DemoWindowWidgetsQueryingStatuses() - local s = S.qs - if ImGui.TreeNode("Querying Item Status (Edited/Active/Hovered etc.)") then - -- Select an item type - local item_names = { "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", - "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" } - s.item_type = ImGui.Combo("Item Type", s.item_type, item_names, #item_names, #item_names) - ImGui.SameLine() - HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().") - _, s.item_disabled = ImGui.Checkbox("Item Disabled", s.item_disabled) - _, s.item_mixedvalue = ImGui.Checkbox("Item MixedValue", s.item_mixedvalue) - _, s.liveedit_override = ImGui.Checkbox("Override LiveEdit:", s.liveedit_override) - ImGui.SameLine() - if not s.liveedit_override then s.liveedit_flags = ImGui.GetItemFlags() end - ImGui.BeginDisabled(s.liveedit_override == false) - _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInput", s.liveedit_flags, 384 --[[ImGuiItemFlags.LiveEditOnInput]]) - ImGui.SameLine() - _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputText", s.liveedit_flags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) - ImGui.SameLine() - _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputScalar", s.liveedit_flags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) - ImGui.EndDisabled() - if s.liveedit_override then - ImGui.PushItemFlag(128 --[[ImGuiItemFlags.LiveEditOnInputText]], bit32.band(s.liveedit_flags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) ~= 0) - ImGui.PushItemFlag(256 --[[ImGuiItemFlags.LiveEditOnInputScalar]], bit32.band(s.liveedit_flags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) ~= 0) - end - - -- Submit selected items so we can query their status in the code following it. - local ret = false - local t = s.item_type - if s.item_disabled then ImGui.BeginDisabled(true) end - if s.item_mixedvalue then ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], true) end - if t == 0 then ImGui.Text("ITEM: Text") end -- Testing text items with no identifier/interaction - if t == 1 then ret = ImGui.Button("ITEM: Button") end -- Testing button - if t == 2 then ImGui.PushItemFlag(8 --[[ImGuiItemFlags.ButtonRepeat]], true); ret = ImGui.Button("ITEM: Button"); ImGui.PopItemFlag() end -- Testing button (with repeater) - if t == 3 then ret, s.b = ImGui.Checkbox("ITEM: Checkbox", s.b) end -- Testing checkbox - if t == 4 then s.col4f[1], ret = ImGui.SliderFloat("ITEM: SliderFloat", s.col4f[1], 0.0, 1.0) end -- Testing basic item - if t == 5 then ret = ImGui.InputText("ITEM: InputText", s.str, 16) end -- Testing input text (which handles tabbing) - if t == 6 then ret = ImGui.InputTextMultiline("ITEM: InputTextMultiline", s.str, 16) end -- Testing input text (which uses a child window) - if t == 7 then s.col4f[1], ret = ImGui.InputFloat("ITEM: InputFloat", s.col4f[1], 1.0) end -- Testing +/- buttons on scalar input - if t == 8 then ret = ImGui.InputFloat3("ITEM: InputFloat3", s.col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) - if t == 9 then ret = ImGui.ColorEdit4("ITEM: ColorEdit4", s.col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) - if t == 10 then ret = ImGui.Selectable("ITEM: Selectable") end -- Testing selectable item - if t == 11 then ret = ImGui.MenuItem("ITEM: MenuItem") end -- Testing menu item (they use ImGuiButtonFlags.PressedOnRelease button policy) - if t == 12 then ret = ImGui.TreeNode("ITEM: TreeNode"); if ret then ImGui.TreePop() end end -- Testing tree node - if t == 13 then ret = ImGui.TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", bit32.bor(64 --[[ImGuiTreeNodeFlags.OpenOnDoubleClick]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]])) end -- Testing tree node with ImGuiButtonFlags.PressedOnDoubleClick button policy. - if t == 14 then s.combo, ret = ImGui.Combo("ITEM: Combo", s.combo, { "Apple", "Banana", "Cherry", "Kiwi" }) end - if t == 15 then s.listbox, ret = ImGui.ListBox("ITEM: ListBox", s.listbox, { "Apple", "Banana", "Cherry", "Kiwi" }, 4, 4) end - - local HF = ImGuiHoveredFlags - local hovered_delay_none = ImGui.IsItemHovered() - local hovered_delay_stationary = ImGui.IsItemHovered(HF.Stationary) - local hovered_delay_short = ImGui.IsItemHovered(HF.DelayShort) - local hovered_delay_normal = ImGui.IsItemHovered(HF.DelayNormal) - local hovered_delay_tooltip = ImGui.IsItemHovered(HF.ForTooltip) -- = Normal + Stationary - - -- Display the values of IsItemHovered() and other common item state functions. - -- Note that the ImGuiHoveredFlags.XXX flags can be combined. - -- Because BulletText is an item itself and that would affect the output of IsItemXXX functions, - -- we query every state in a single call to avoid storing them and to simplify the code. - local rmin, rmax, rsize = ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ImGui.GetItemRectSize() - ImGui.BulletText( - "Return value = %d\nIsItemFocused() = %d\nIsItemHovered() = %d\nIsItemHovered(_AllowWhenBlockedByPopup) = %d\n" .. - "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\nIsItemHovered(_AllowWhenOverlappedByItem) = %d\n" .. - "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\nIsItemHovered(_AllowWhenDisabled) = %d\nIsItemHovered(_RectOnly) = %d\n" .. - "IsItemActive() = %d\nIsItemEdited() = %d\nIsItemActivated() = %d\nIsItemDeactivated() = %d\nIsItemDeactivatedAfterEdit() = %d\n" .. - "IsItemVisible() = %d\nIsItemClicked() = %d\nIsItemToggledOpen() = %d\n" .. - "GetItemRectMin() = (%.1f, %.1f)\nGetItemRectMax() = (%.1f, %.1f)\nGetItemRectSize() = (%.1f, %.1f)", - B(ret), B(ImGui.IsItemFocused()), B(ImGui.IsItemHovered()), B(ImGui.IsItemHovered(HF.AllowWhenBlockedByPopup)), - B(ImGui.IsItemHovered(HF.AllowWhenBlockedByActiveItem)), B(ImGui.IsItemHovered(HF.AllowWhenOverlappedByItem)), - B(ImGui.IsItemHovered(HF.AllowWhenOverlappedByWindow)), B(ImGui.IsItemHovered(HF.AllowWhenDisabled)), B(ImGui.IsItemHovered(HF.RectOnly)), - B(ImGui.IsItemActive()), B(ImGui.IsItemEdited()), B(ImGui.IsItemActivated()), B(ImGui.IsItemDeactivated()), B(ImGui.IsItemDeactivatedAfterEdit()), - B(ImGui.IsItemVisible()), B(ImGui.IsItemClicked()), B(ImGui.IsItemToggledOpen()), - rmin.x, rmin.y, rmax.x, rmax.y, rsize.x, rsize.y) - ImGui.BulletText( - "with Hovering Delay or Stationary test:\nIsItemHovered() = %d\nIsItemHovered(_Stationary) = %d\nIsItemHovered(_DelayShort) = %d\nIsItemHovered(_DelayNormal) = %d\nIsItemHovered(_Tooltip) = %d", - B(hovered_delay_none), B(hovered_delay_stationary), B(hovered_delay_short), B(hovered_delay_normal), B(hovered_delay_tooltip)) - - if s.liveedit_override then ImGui.PopItemFlag(); ImGui.PopItemFlag() end - if s.item_mixedvalue then ImGui.PopItemFlag() end - if s.item_disabled then ImGui.EndDisabled() end - - ImGui.InputText("unused", s.unused, 1, 512 --[[ImGuiInputTextFlags.ReadOnly]]) - ImGui.SameLine() - HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.") - ImGui.TreePop() - end - - if ImGui.TreeNode("Querying Window Status (Focused/Hovered etc.)") then - _, s.embed = ImGui.Checkbox("Embed everything inside a child window for testing _RootWindow flag.", s.embed) - if s.embed then ImGui.BeginChild("outer_child", ImVec2(0, ImGui.GetFontSize() * 20.0), 1 --[[ImGuiChildFlags.Borders]]) end - local FF, HF = ImGuiFocusedFlags, ImGuiHoveredFlags - local bor = bit32.bor - -- Testing IsWindowFocused() function with its various flags. - ImGui.BulletText( - "IsWindowFocused() = %d\nIsWindowFocused(_ChildWindows) = %d\nIsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" .. - "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\nIsWindowFocused(_ChildWindows|_RootWindow) = %d\n" .. - "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\nIsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" .. - "IsWindowFocused(_RootWindow) = %d\nIsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\nIsWindowFocused(_RootWindow|_DockHierarchy) = %d\n" .. - "IsWindowFocused(_AnyWindow) = %d\n", - B(ImGui.IsWindowFocused()), B(ImGui.IsWindowFocused(FF.ChildWindows)), B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.NoPopupHierarchy))), - B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.DockHierarchy))), B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.RootWindow))), - B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.RootWindow, FF.NoPopupHierarchy))), B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.RootWindow, FF.DockHierarchy))), - B(ImGui.IsWindowFocused(FF.RootWindow)), B(ImGui.IsWindowFocused(bor(FF.RootWindow, FF.NoPopupHierarchy))), B(ImGui.IsWindowFocused(bor(FF.RootWindow, FF.DockHierarchy))), - B(ImGui.IsWindowFocused(FF.AnyWindow))) - - -- Testing IsWindowHovered() function with its various flags. - ImGui.BulletText( - "IsWindowHovered() = %d\nIsWindowHovered(_AllowWhenBlockedByPopup) = %d\nIsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" .. - "IsWindowHovered(_ChildWindows) = %d\nIsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\nIsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n" .. - "IsWindowHovered(_ChildWindows|_RootWindow) = %d\nIsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" .. - "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\nIsWindowHovered(_RootWindow) = %d\nIsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" .. - "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\nIsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\nIsWindowHovered(_AnyWindow) = %d\n" .. - "IsWindowHovered(_Stationary) = %d\n", - B(ImGui.IsWindowHovered()), B(ImGui.IsWindowHovered(HF.AllowWhenBlockedByPopup)), B(ImGui.IsWindowHovered(HF.AllowWhenBlockedByActiveItem)), - B(ImGui.IsWindowHovered(HF.ChildWindows)), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.NoPopupHierarchy))), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.DockHierarchy))), - B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.RootWindow))), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.RootWindow, HF.NoPopupHierarchy))), - B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.RootWindow, HF.DockHierarchy))), B(ImGui.IsWindowHovered(HF.RootWindow)), B(ImGui.IsWindowHovered(bor(HF.RootWindow, HF.NoPopupHierarchy))), - B(ImGui.IsWindowHovered(bor(HF.RootWindow, HF.DockHierarchy))), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.AllowWhenBlockedByPopup))), B(ImGui.IsWindowHovered(HF.AnyWindow)), - B(ImGui.IsWindowHovered(HF.Stationary))) - ImGui.BeginChild("child", ImVec2(0, 50), 1 --[[ImGuiChildFlags.Borders]]) - ImGui.Text("This is another child window for testing the _ChildWindows flag.") - ImGui.EndChild() - if s.embed then ImGui.EndChild() end - - -- Calling IsItemHovered() after begin returns the hovered status of the title bar. - -- This is useful in particular if you want to create a context menu associated to the title bar of a window. - -- This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties). - _, s.test_window = ImGui.Checkbox("Hovered/Active tests after Begin() for title bar testing", s.test_window) - if s.test_window then - -- FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. - -- Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? - s.test_window = ImGui.Begin("Title bar Hovered/Active tests", s.test_window) - if ImGui.BeginPopupContextItem() then -- <-- This is using IsItemHovered() - if ImGui.MenuItem("Close") then s.test_window = false end - ImGui.EndPopup() - end - ImGui.Text("IsItemHovered() after begin = %d (== is title bar hovered)\nIsItemActive() after begin = %d (== is window being clicked/moved)\n", - B(ImGui.IsItemHovered()), B(ImGui.IsItemActive())) - ImGui.End() - end - ImGui.TreePop() - end -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsSelectables() -------------------------------------------------------------------------------- - -S.sel = { basic = { false, true, false, false }, multi = { false, false, false }, checked = { false, false, false, false, false }, selected_n = 0, - tables = {}, grid = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }, - align = { true, false, true, false, true, false, true, false, true } } -for i = 1, 10 do S.sel.tables[i] = false end -function DemoWindowWidgetsSelectables() - -- ImGui.SetNextItemOpen(true, ImGuiCond.Once) - if not ImGui.TreeNode("Selectables") then return end - local s = S.sel - -- Selectable() has 2 overloads: - -- - The one taking "bool selected" as a read-only selection information. - -- When Selectable() has been clicked it returns true and you can alter selection state accordingly. - -- - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) - -- (in this port: the SelectableP() helper above, which returns (pressed, selected)) - -- The earlier is more flexible, as in real application your selection may be stored in many different ways - -- and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). - if ImGui.TreeNode("Basic") then - local b = s.basic - _, b[1] = SelectableP("1. I am selectable", b[1]) - _, b[2] = SelectableP("2. I am selectable", b[2]) - _, b[3] = SelectableP("3. I am selectable", b[3]) - if ImGui.Selectable("4. I am double clickable", b[4], 4 --[[ImGuiSelectableFlags.AllowDoubleClick]]) then - if ImGui.IsMouseDoubleClicked(0) then b[4] = not b[4] end - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Multiple items on the same line") then - -- - Using SetNextItemAllowOverlap() - -- - Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. - local m = s.multi - ImGui.SetNextItemAllowOverlap(); _, m[1] = SelectableP("main.c", m[1]); ImGui.SameLine(); ImGui.SmallButton("Link 1") - ImGui.SetNextItemAllowOverlap(); _, m[2] = SelectableP("hello.cpp", m[2]); ImGui.SameLine(); ImGui.SmallButton("Link 2") - ImGui.SetNextItemAllowOverlap(); _, m[3] = SelectableP("hello.h", m[3]); ImGui.SameLine(); ImGui.SmallButton("Link 3") - - -- (2) - -- - Using ImGuiSelectableFlags.AllowOverlap is a shortcut for calling SetNextItemAllowOverlap() - -- - No visible label, display contents inside the selectable bounds. - -- - We don't maintain actual selection in this example to keep things simple. - ImGui.Spacing() - local color_marker_w = ImGui.CalcTextSize("x").x - for n = 0, 4 do - ImGui.PushID(n) - ImGui.AlignTextToFramePadding() - if ImGui.Selectable("##selectable", s.selected_n == n, 16 --[[ImGuiSelectableFlags.AllowOverlap]]) then s.selected_n = n end - ImGui.SameLine(0, 0) - _, s.checked[n + 1] = ImGui.Checkbox("##check", s.checked[n + 1]) - ImGui.SameLine() - local color = ImVec4((n % 2 == 1) and 1.0 or 0.2, (math.floor(n / 2) % 2 == 1) and 1.0 or 0.2, 0.2, 1.0) - ImGui.ColorButton("##color", color, 64 --[[ImGuiColorEditFlags.NoTooltip]], ImVec2(color_marker_w, 0)) - ImGui.SameLine() - ImGui.Text("Some label") - ImGui.PopID() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("In Tables") then - local sel = s.tables - local TF = ImGuiTableFlags - if ImGui.BeginTable("split1", 3, bit32.bor(TF.Resizable, TF.NoSavedSettings, TF.Borders)) then - for i = 0, 9 do - ImGui.TableNextColumn() - _, sel[i + 1] = SelectableP(string.format("Item %d", i), sel[i + 1]) -- FIXME-TABLE: Selection overlap - end - ImGui.EndTable() - end - ImGui.Spacing() - if ImGui.BeginTable("split2", 3, bit32.bor(TF.Resizable, TF.NoSavedSettings, TF.Borders)) then - for i = 0, 9 do - ImGui.TableNextRow() - ImGui.TableNextColumn() - _, sel[i + 1] = SelectableP(string.format("Item %d", i), sel[i + 1], 2 --[[ImGuiSelectableFlags.SpanAllColumns]]) - ImGui.TableNextColumn() - ImGui.Text("Some other contents") - ImGui.TableNextColumn() - ImGui.Text("123456") - end - ImGui.EndTable() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Grid") then - local g = s.grid - - -- Add in a bit of silly fun... - local time = ImGui.GetTime() - local winning_state = true - for y = 1, 4 do for x = 1, 4 do if g[y][x] == 0 then winning_state = false end end end -- If all cells are selected... - if winning_state then - ImGui.PushStyleVar(39 --[[ImGuiStyleVar.SelectableTextAlign]], ImVec2(0.5 + 0.5 * math.cos(time * 2.0), 0.5 + 0.5 * math.sin(time * 3.0))) - end - local size = ImGui.CalcTextSize("Sailor").x - for y = 1, 4 do - for x = 1, 4 do - if x > 1 then ImGui.SameLine() end - ImGui.PushID((y - 1) * 4 + (x - 1)) - if ImGui.Selectable("Sailor", g[y][x] ~= 0, 0, ImVec2(size, size)) then - -- Toggle clicked cell + toggle neighbors - g[y][x] = 1 - g[y][x] - if x > 1 then g[y][x - 1] = 1 - g[y][x - 1] end - if x < 4 then g[y][x + 1] = 1 - g[y][x + 1] end - if y > 1 then g[y - 1][x] = 1 - g[y - 1][x] end - if y < 4 then g[y + 1][x] = 1 - g[y + 1][x] end - end - ImGui.PopID() - end - end - if winning_state then ImGui.PopStyleVar() end - ImGui.TreePop() - end - - if ImGui.TreeNode("Alignment") then - HelpMarker("By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item basis using PushStyleVar(). You'll probably want to always keep your default situation to left-align otherwise it becomes difficult to layout multiple items on a same line") - local size = ImGui.CalcTextSize("(1.0,1.0)").x - for y = 0, 2 do - for x = 0, 2 do - local alignment = ImVec2(x / 2.0, y / 2.0) - local name = string.format("(%.1f,%.1f)", alignment.x, alignment.y) - if x > 0 then ImGui.SameLine() end - ImGui.PushStyleVar(39 --[[ImGuiStyleVar.SelectableTextAlign]], alignment) - _, s.align[3 * y + x + 1] = SelectableP(name, s.align[3 * y + x + 1], 0 --[[ImGuiSelectableFlags.None]], ImVec2(size, size)) - ImGui.PopStyleVar() - end - end - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTabs() -------------------------------------------------------------------------------- - -local function EditTabBarFittingPolicyFlags(flags) - local TB = ImGuiTabBarFlags - if bit32.band(flags, TB.FittingPolicyMask_) == 0 then flags = bit32.bor(flags, TB.FittingPolicyDefault_) end - for _, n in ipairs({ "FittingPolicyMixed", "FittingPolicyShrink", "FittingPolicyScroll" }) do - local p - p, flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_" .. n, flags, TB[n]) - if p then flags = bit32.band(flags, bit32.bnot(bit32.bxor(TB.FittingPolicyMask_, TB[n]))) end - end - return flags -end - -S.tabs = { adv_flags = ImGuiTabBarFlags.Reorderable, opened = { true, true, true, true }, active_tabs = {}, next_tab_id = 0, - show_leading = true, show_trailing = true, show_lt_tabs = false, - tib_flags = bit32.bor(ImGuiTabBarFlags.AutoSelectNewTabs, ImGuiTabBarFlags.Reorderable, ImGuiTabBarFlags.FittingPolicyMixed) } -function DemoWindowWidgetsTabs() - if not ImGui.TreeNode("Tabs") then return end - local s = S.tabs - local TB, TI = ImGuiTabBarFlags, ImGuiTabItemFlags - if ImGui.TreeNode("Basic") then - if ImGui.BeginTabBar("MyTabBar", TB.None) then - if ImGui.BeginTabItem("Avocado") then ImGui.Text("This is the Avocado tab!\nblah blah blah blah blah"); ImGui.EndTabItem() end - if ImGui.BeginTabItem("Broccoli") then ImGui.Text("This is the Broccoli tab!\nblah blah blah blah blah"); ImGui.EndTabItem() end - if ImGui.BeginTabItem("Cucumber") then ImGui.Text("This is the Cucumber tab!\nblah blah blah blah blah"); ImGui.EndTabItem() end - ImGui.EndTabBar() - end - ImGui.Separator() - ImGui.TreePop() - end - - if ImGui.TreeNode("Advanced & Close Button") then - -- Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). - for _, n in ipairs({ "Reorderable", "AutoSelectNewTabs", "TabListPopupButton", "NoCloseWithMiddleMouseButton", "DrawSelectedOverline" }) do - _, s.adv_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_" .. n, s.adv_flags, TB[n]) - end - s.adv_flags = EditTabBarFittingPolicyFlags(s.adv_flags) - - -- Tab Bar - ImGui.AlignTextToFramePadding() - ImGui.Text("Opened:") - local names = { "Artichoke", "Beetroot", "Celery", "Daikon" } - for n = 1, 4 do -- s.opened: Persistent user state - ImGui.SameLine() - _, s.opened[n] = ImGui.Checkbox(names[n], s.opened[n]) - end - - -- Passing an open flag to BeginTabItem() is similar to passing one to Begin(): - -- the returned open value will be false when the tab is closed. - if ImGui.BeginTabBar("MyTabBar", s.adv_flags) then - for n = 1, 4 do - if s.opened[n] then - local visible - visible, s.opened[n] = ImGui.BeginTabItem(names[n], s.opened[n], TI.None) - if visible then - ImGui.Text("This is the %s tab!", names[n]) - if (n - 1) % 2 == 1 then ImGui.Text("I am an odd tab.") end - ImGui.EndTabItem() - end - end - end - ImGui.EndTabBar() - end - ImGui.Separator() - ImGui.TreePop() - end - - if ImGui.TreeNode("TabItemButton & Leading/Trailing flags") then - if s.next_tab_id == 0 then -- Initialize with some default tabs - for _ = 1, 3 do s.active_tabs[#s.active_tabs + 1] = s.next_tab_id; s.next_tab_id = s.next_tab_id + 1 end - end - - -- TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. - -- (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... - -- but they tend to make more sense together) - _, s.show_leading = ImGui.Checkbox("Show Leading TabItemButton()", s.show_leading) - _, s.show_trailing = ImGui.Checkbox("Show Trailing TabItemButton()", s.show_trailing) - _, s.show_lt_tabs = ImGui.Checkbox("Show Leading+Trailing TabItem()", s.show_lt_tabs) - - -- Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs - s.tib_flags = EditTabBarFittingPolicyFlags(s.tib_flags) - - if ImGui.BeginTabBar("MyTabBar", s.tib_flags) then - -- Demo a Leading TabItemButton(): click the "?" button to open a menu - if s.show_leading then - if ImGui.TabItemButton("?", bit32.bor(TI.Leading, TI.NoTooltip)) then ImGui.OpenPopup("MyHelpMenu") end - end - if ImGui.BeginPopup("MyHelpMenu") then - ImGui.Selectable("Hello!") - ImGui.EndPopup() - end - - -- Demo Leading/Trailing Tabs - if s.show_lt_tabs then - if ImGui.BeginTabItem("Leading", nil, TI.Leading) then ImGui.EndTabItem() end - if ImGui.BeginTabItem("Trailing", nil, TI.Trailing) then ImGui.EndTabItem() end - end - - -- Demo Trailing Tabs: click the "+" button to add a new tab. - -- (In your app you may want to use a font icon instead of the "+") - -- We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags.Trailing flag it will always appear at the end. - if s.show_trailing then - if ImGui.TabItemButton("+", bit32.bor(TI.Trailing, TI.NoTooltip)) then - s.active_tabs[#s.active_tabs + 1] = s.next_tab_id; s.next_tab_id = s.next_tab_id + 1 -- Add new tab - end - end - - -- Submit our regular tabs - local n = 1 - while n <= #s.active_tabs do - local name = string.format("%04d", s.active_tabs[n]) - local visible, open = ImGui.BeginTabItem(name, true, TI.None) - if visible then - ImGui.Text("This is the %s tab!", name) - ImGui.EndTabItem() - end - if open == false then table.remove(s.active_tabs, n) else n = n + 1 end - end - ImGui.EndTabBar() - end - ImGui.Separator() - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsText() -------------------------------------------------------------------------------- - -S.text = { custom_size = 16.0, custom_scale = 1.0, wrap_width = 200.0, utf8 = Buf("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e", 32) } -function DemoWindowWidgetsText() - if not ImGui.TreeNode("Text") then return end - local s = S.text - if ImGui.TreeNode("Colorful Text") then - -- Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. - ImGui.TextColored(ImVec4(1.0, 0.0, 1.0, 1.0), "Pink") - ImGui.TextColored(ImVec4(1.0, 1.0, 0.0, 1.0), "Yellow") - ImGui.TextDisabled("Disabled") - ImGui.SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.") - ImGui.TreePop() - end - - if ImGui.TreeNode("Font Size") then - local style = ImGui.GetStyle() - local global_scale = style.FontScaleMain * style.FontScaleDpi - ImGui.Text("style.FontScaleMain = %0.2f", style.FontScaleMain) - ImGui.Text("style.FontScaleDpi = %0.2f", style.FontScaleDpi) - ImGui.Text("global_scale = ~%0.2f", global_scale) -- This is not technically accurate as internal scales may apply, but conceptually let's pretend it is. - ImGui.Text("FontSize = %0.2f", ImGui.GetFontSize()) - - ImGui.SeparatorText("") - s.custom_size = ImGui.SliderFloat("custom_size", s.custom_size, 10.0, 100.0, "%.0f") - ImGui.Text("ImGui::PushFont(nullptr, custom_size);") - ImGui.PushFont(nil, s.custom_size) - ImGui.Text("FontSize = %.2f (== %.2f * global_scale)", ImGui.GetFontSize(), s.custom_size) - ImGui.PopFont() - ImGui.SeparatorText("") - s.custom_scale = ImGui.SliderFloat("custom_scale", s.custom_scale, 0.5, 4.0, "%.2f") - ImGui.Text("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scale);") - ImGui.PushFont(nil, style.FontSizeBase * s.custom_scale) - ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), s.custom_scale) - ImGui.PopFont() - ImGui.SeparatorText("") - local scaling = 0.5 - while scaling <= 4.0 do - ImGui.PushFont(nil, style.FontSizeBase * scaling) - ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), scaling) - ImGui.PopFont() - scaling = scaling + 0.5 - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Word Wrapping") then - -- Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. - ImGui.TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages.") - ImGui.Spacing() - s.wrap_width = ImGui.SliderFloat("Wrap width", s.wrap_width, -20, 600, "%.0f") - local draw_list = ImGui.GetWindowDrawList() - for n = 0, 1 do - ImGui.Text("Test paragraph %d:", n) - local pos = ImGui.GetCursorScreenPos() - local marker_min = ImVec2(pos.x + s.wrap_width, pos.y) - local marker_max = ImVec2(pos.x + s.wrap_width + 10, pos.y + ImGui.GetTextLineHeight()) - ImGui.PushTextWrapPos(ImGui.GetCursorPos().x + s.wrap_width) - if n == 0 then - ImGui.Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", s.wrap_width) - else - ImGui.Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh") - end - - -- Draw actual text bounding box, following by marker of our expected limit (should not overlap!) - draw_list:AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), IM_COL32(255, 255, 0, 255)) - draw_list:AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)) - ImGui.PopTextWrapPos() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("UTF-8 Text") then - -- UTF-8 test with Japanese characters - -- (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) - -- - FOR THIS DEMO FILE ONLY, WE ARE *NOT* INCLUDING RAW UTF-8 - -- CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal escapes. - -- Note that characters values are preserved even by InputText() if the font cannot be displayed, - -- so you can safely copy & paste garbled characters into another application. - ImGui.TextWrapped("CJK text will only appear if the font was loaded with the appropriate CJK character ranges. Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. Read docs/FONTS.md for details.") - ImGui.Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)") - ImGui.Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)") - ImGui.InputText("UTF-8 input", s.utf8, 32) - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTextFilter() -------------------------------------------------------------------------------- - -S.tf = { filter = nil } -function DemoWindowWidgetsTextFilter() - if not ImGui.TreeNode("Text Filter") then return end - -- Helper class to easy setup a text filter. - -- You may want to implement a more feature-full filtering scheme in your own application. - S.tf.filter = S.tf.filter or ImGuiTextFilter() - local filter = S.tf.filter - HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.") - ImGui.Text("Filter usage:\n \"\" display all lines\n xxx display lines containing \"xxx\"\n xxx yyy display lines containing \"xxx\" and \"yyy\"\n \"xxx yyy\" display lines containing \"xxx yyy\"\n xxx,yyy display lines containing \"xxx\" or \"yyy\"\n -xxx hide lines containing \"xxx\"") - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - filter:DrawWithHint("##Filter", "Filter (incl -excl)") - if ImGui.BeginChild("##items", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeightWithSpacing() * 15), 128 --[[ImGuiChildFlags.FrameStyle]]) then - for _, item in ipairs({ "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }) do - if filter:PassFilter(item) then ImGui.TextUnformatted(item) end - end - for _, item in ipairs(ExampleNames) do - if filter:PassFilter(item) then ImGui.TextUnformatted(item) end - end - end - ImGui.EndChild() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTextInput() -------------------------------------------------------------------------------- - -S.ti = { - text = Buf("/*\n The Pentium F00F bug, shorthand for F0 0F C7 C8,\n the hexadecimal encoding of one offending instruction,\n more formally, the invalid operand with locked CMPXCHG8B\n instruction bug, is a design flaw in the majority of\n Intel Pentium, Pentium MMX, and Pentium OverDrive\n processors (all in the P5 microarchitecture).\n*/\n\nlabel:\n\tlock cmpxchg8b eax\n", 1024 * 16), - ml_flags = ImGuiInputTextFlags.AllowTabInput, - f = { Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32) }, - password = Buf("password123", 64), cb1 = Buf("", 64), cb2 = Buf("", 64), cb3 = Buf("", 64), edit_count = { 0 }, - rs_flags = 0, rs = Buf("", 1024), - elide = Buf("/path/to/some/folder/with/long/filename.cpp", 128), elide_flags = ImGuiInputTextFlags.ElideLeft, - misc = Buf("", 16), misc_flags = ImGuiInputTextFlags.EscapeClearsAll } -function DemoWindowWidgetsTextInput() - if not ImGui.TreeNode("Text Input") then return end - local s = S.ti - local IT = ImGuiInputTextFlags - local function FlagBox(key, name) - if IT[name] then _, s[key] = ImGui.CheckboxFlags("ImGuiInputTextFlags_" .. name, s[key], IT[name]) end - end - if ImGui.TreeNode("Multi-line Text Input") then - -- WE ARE USING A FIXED-SIZE BUFFER FOR SIMPLICITY HERE. - HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type.") - FlagBox("ml_flags", "ReadOnly") - FlagBox("ml_flags", "WordWrap") - ImGui.SameLine(); HelpMarker("Feature is currently in Beta. Please read comments in imgui.h") - FlagBox("ml_flags", "AllowTabInput") - ImGui.SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets.") - FlagBox("ml_flags", "CtrlEnterForNewLine") - ImGui.InputTextMultiline("##source", s.text, 1024 * 16, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeight() * 16), s.ml_flags) - ImGui.TreePop() - end - - if ImGui.TreeNode("Filtered Text Input") then - local a, z, A, Z = string.byte("a"), string.byte("z"), string.byte("A"), string.byte("Z") - -- Modify character input by altering 'data.EventChar' (ImGuiInputTextFlags.CallbackCharFilter callback) - local function FilterCasingSwap(data) - local c = data.EventChar - if c >= a and c <= z then data.EventChar = c - (a - A) -- Lowercase becomes uppercase - elseif c >= A and c <= Z then data.EventChar = c + (a - A) end -- Uppercase becomes lowercase - return 0 - end - -- Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) - local function FilterImGuiLetters(data) - local c = data.EventChar - if c < 256 and string.find("imgui", string.char(c), 1, true) then return 0 end - return 1 - end - local f = s.f - ImGui.InputText("default", f[1], 32) - ImGui.InputText("decimal", f[2], 32, IT.CharsDecimal) - ImGui.InputText("hexadecimal", f[3], 32, bit32.bor(IT.CharsHexadecimal, IT.CharsUppercase)) - ImGui.InputText("uppercase", f[4], 32, IT.CharsUppercase) - ImGui.InputText("no blank", f[5], 32, IT.CharsNoBlank) - ImGui.InputText("casing swap", f[6], 32, IT.CallbackCharFilter, FilterCasingSwap) -- Use CharFilter callback to replace characters. - ImGui.InputText("\"imgui\"", f[7], 32, IT.CallbackCharFilter, FilterImGuiLetters) -- Use CharFilter callback to disable some characters. - ImGui.TreePop() - end - - if ImGui.TreeNode("Password Input") then - ImGui.InputText("password", s.password, 64, IT.Password) - ImGui.SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n") - ImGui.InputTextWithHint("password (w/ hint)", "", s.password, 64, IT.Password) - ImGui.InputText("password (clear)", s.password, 64) - ImGui.TreePop() - end - - if ImGui.TreeNode("Completion, History, Edit Callbacks") then - local function MyCallback(data) - if data.EventFlag == IT.CallbackCompletion then - data:InsertChars(data.CursorPos, "..") - elseif data.EventFlag == IT.CallbackHistory then - if data.EventKey == 515 --[[ImGuiKey.UpArrow]] then - data:DeleteChars(0, data.BufTextLen) - data:InsertChars(0, "Pressed Up!") - data:SelectAll() - elseif data.EventKey == 516 --[[ImGuiKey.DownArrow]] then - data:DeleteChars(0, data.BufTextLen) - data:InsertChars(0, "Pressed Down!") - data:SelectAll() - end - elseif data.EventFlag == IT.CallbackEdit then - -- Toggle casing of first character - local c = data.Buf[1] - if (c >= 97 and c <= 122) or (c >= 65 and c <= 90) then data.Buf[1] = bit32.bxor(c, 32) end - data.BufDirty = true - - -- Increment a counter - local p_int = data.UserData - p_int[1] = p_int[1] + 1 - end - return 0 - end - ImGui.InputText("Completion", s.cb1, 64, IT.CallbackCompletion, MyCallback) - ImGui.SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.") - ImGui.InputText("History", s.cb2, 64, IT.CallbackHistory, MyCallback) - ImGui.SameLine(); HelpMarker("Here we replace and select text each time Up/Down are pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.") - ImGui.InputText("Edit", s.cb3, 64, IT.CallbackEdit, MyCallback, s.edit_count) - ImGui.SameLine(); HelpMarker("Here we toggle the casing of the first character on every edit + count edits.") - ImGui.SameLine(); ImGui.Text("(%d)", s.edit_count[1]) - ImGui.TreePop() - end - - if ImGui.TreeNode("Resize Callback") then - HelpMarker("Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n(Lua port: fixed 1024 byte buffer, CallbackResize growth not supported)") - FlagBox("rs_flags", "WordWrap") - ImGui.InputTextMultiline("##MyStr", s.rs, 1024, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeight() * 16), s.rs_flags) - ImGui.Text("Size: %d\nCapacity: %d", #BufStr(s.rs) + 1, 1024) - ImGui.TreePop() - end - - if ImGui.TreeNode("Eliding, Alignment") then - FlagBox("elide_flags", "ElideLeft") - ImGui.InputText("Path", s.elide, 128, s.elide_flags) - ImGui.TreePop() - end - - if ImGui.TreeNode("Miscellaneous") then - FlagBox("misc_flags", "EscapeClearsAll") - FlagBox("misc_flags", "ReadOnly") - FlagBox("misc_flags", "NoUndoRedo") - ImGui.InputText("Hello", s.misc, 16, s.misc_flags) - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTooltips() -------------------------------------------------------------------------------- - -S.tt = { arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, always_on = 0 } -function DemoWindowWidgetsTooltips() - if not ImGui.TreeNode("Tooltips") then return end - local s = S.tt - local HF = ImGuiHoveredFlags - -- Tooltips are windows following the mouse. They do not take focus away. - ImGui.SeparatorText("General") - - -- Typical use cases: - -- - Short-form (text only): SetItemTooltip("Hello") - -- - Short-form (any contents): if BeginItemTooltip() then Text("Hello"); EndTooltip() end - - -- - Full-form (text only): if IsItemHovered(...) then SetTooltip("Hello") end - -- - Full-form (any contents): if IsItemHovered(...) and BeginTooltip() then Text("Hello"); EndTooltip() end - - HelpMarker("Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\nWe provide a helper SetItemTooltip() function to perform the two with standards flags.") - local sz = ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0) - ImGui.Button("Basic", sz) - ImGui.SetItemTooltip("I am a tooltip") - ImGui.Button("Fancy", sz) - if ImGui.BeginItemTooltip() then - ImGui.Text("I am a fancy tooltip") - ImGui.PlotLines("Curve", s.arr, nil, #s.arr) - ImGui.Text("Sin(time) = %f", math.sin(ImGui.GetTime())) - ImGui.EndTooltip() - end - - ImGui.SeparatorText("Always On") - - -- Showcase NOT relying on a IsItemHovered() to emit a tooltip. - -- Here the tooltip is always emitted when 'always_on == true'. - _, s.always_on = ImGui.RadioButton("Off", s.always_on, 0) - ImGui.SameLine() - _, s.always_on = ImGui.RadioButton("Always On (Simple)", s.always_on, 1) - ImGui.SameLine() - _, s.always_on = ImGui.RadioButton("Always On (Advanced)", s.always_on, 2) - if s.always_on == 1 then - ImGui.SetTooltip("I am following you around.") - elseif s.always_on == 2 and ImGui.BeginTooltip() then - ImGui.ProgressBar(math.sin(ImGui.GetTime()) * 0.5 + 0.5, ImVec2(ImGui.GetFontSize() * 25, 0.0)) - ImGui.EndTooltip() - end - - ImGui.SeparatorText("Custom") - HelpMarker("Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize tooltip activation details across your application. You may however decide to use custom flags for a specific tooltip instance.") - - -- The following examples are passed for documentation purpose but may not be useful to most users. - -- Passing ImGuiHoveredFlags.ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from - -- 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. - -- With default settings, ImGuiHoveredFlags.ForTooltip is equivalent to ImGuiHoveredFlags.DelayShort + ImGuiHoveredFlags.Stationary. - ImGui.Button("Manual", sz) - if ImGui.IsItemHovered(HF.ForTooltip) then ImGui.SetTooltip("I am a manually emitted tooltip.") end - ImGui.Button("DelayNone", sz) - if ImGui.IsItemHovered(HF.DelayNone) then ImGui.SetTooltip("I am a tooltip with no delay.") end - ImGui.Button("DelayShort", sz) - if ImGui.IsItemHovered(bit32.bor(HF.DelayShort, HF.NoSharedDelay)) then ImGui.SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui.GetStyle().HoverDelayShort) end - ImGui.Button("DelayLong", sz) - if ImGui.IsItemHovered(bit32.bor(HF.DelayNormal, HF.NoSharedDelay)) then ImGui.SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui.GetStyle().HoverDelayNormal) end - ImGui.Button("Stationary", sz) - if ImGui.IsItemHovered(HF.Stationary) then ImGui.SetTooltip("I am a tooltip requiring mouse to be stationary before activating.") end - - -- Using ImGuiHoveredFlags.ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav', - -- which default value include the ImGuiHoveredFlags.AllowWhenDisabled flag. - ImGui.BeginDisabled() - ImGui.Button("Disabled item", sz) - if ImGui.IsItemHovered(HF.ForTooltip) then ImGui.SetTooltip("I am a tooltip for a disabled item.") end - ImGui.EndDisabled() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTreeNodes() -------------------------------------------------------------------------------- - -S.tn = { lines_flags = bit32.bor(ImGuiTreeNodeFlags.DrawLinesFull, ImGuiTreeNodeFlags.DefaultOpen), selection_mask = 0, - adv_flags = bit32.bor(ImGuiTreeNodeFlags.OpenOnArrow, ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.SpanAvailWidth), - align_label = false, use_dnd = false } -function DemoWindowWidgetsTreeNodes() - if not ImGui.TreeNode("Tree Nodes") then return end - local s = S.tn - local TN = ImGuiTreeNodeFlags - -- See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree. - if ImGui.TreeNode("Basic Trees") then - for i = 0, 4 do - -- Use SetNextItemOpen() so set the default state of a node to be open. We could - -- also use TreeNodeEx() with the ImGuiTreeNodeFlags.DefaultOpen flag to achieve the same thing! - if i == 0 then ImGui.SetNextItemOpen(true, 2 --[[ImGuiCond.Once]]) end - - -- Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict. - -- An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode(i, ...)', - -- aka pass a number value to be hashed. The demo below uses that technique. Both are fine. - ImGui.PushID(i) - if ImGui.TreeNode("", "Child %d", i) then - ImGui.Text("blah blah") - ImGui.SameLine() - if ImGui.SmallButton("button") then end - ImGui.TreePop() - end - ImGui.PopID() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Hierarchy Lines") then - HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") - _, s.lines_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", s.lines_flags, TN.DrawLinesNone) - _, s.lines_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", s.lines_flags, TN.DrawLinesFull) - _, s.lines_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", s.lines_flags, TN.DrawLinesToNodes) - local f = s.lines_flags - if ImGui.TreeNodeEx("Parent", f) then - if ImGui.TreeNodeEx("Child 1", f) then ImGui.Button("Button for Child 1"); ImGui.TreePop() end - if ImGui.TreeNodeEx("Child 2", f) then ImGui.Button("Button for Child 2"); ImGui.TreePop() end - ImGui.Text("Remaining contents") - ImGui.Text("Remaining contents") - ImGui.TreePop() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Clipping Large Trees") then - ImGui.TextWrapped("- Using ImGuiListClipper with trees is a less easy than on arrays or grids.\n- Refer to 'Demo->Examples->Property Editor' for an example of how to do that.\n- Discuss in #3823") - ImGui.TreePop() - end - - if ImGui.TreeNode("Selectable Nodes") then - HelpMarker("Manually implemented selectable nodes.\nClick to select, Ctrl+Click to toggle, click on arrows or double-click to open.") - - -- Hold in 'selection_mask' a simple representation of what may be user-side selection state. - -- - You may retain selection state inside or outside your objects in whatever format you see fit. - -- You may use ImGuiSelectionBasicStorage which is conceptually close to a set<> of identifiers. - -- - We record which node was clicked and then apply selection at the end of the loop. - -- - This is a manual and simplified reimplementation of multi-selection, which the full - -- BeginMultiSelect() API implements better, but which is not trivial to wire for trees. - local node_clicked_idx = -1 - for node_n = 0, 5 do - -- Disable the default "open on single-click behavior" + set Selected flag according to our selection. - -- To alter selection we use if 'IsItemClicked() and not IsItemToggledOpen()', so clicking on an arrow doesn't alter selection. - -- In a BeginMultiSelect()/EndMultiSelect() we could use IsItemToggledSelection() but here we reimplement and use our own logic. - local flags = bit32.bor(TN.OpenOnArrow, TN.OpenOnDoubleClick, TN.SpanAvailWidth) - if bit32.band(s.selection_mask, bit32.lshift(1, node_n)) ~= 0 then flags = bit32.bor(flags, TN.Selected) end - local is_open = ImGui.TreeNodeEx(node_n, flags, "Selectable Node %d", node_n) - if ImGui.IsItemClicked() and not ImGui.IsItemToggledOpen() then node_clicked_idx = node_n end - if is_open then - ImGui.BulletText("") - ImGui.TreePop() - end - end - if node_clicked_idx ~= -1 then - -- Update selection state (process outside of tree loop to avoid visual inconsistencies during the clicking frame) - if ImGui.GetIO().KeyCtrl then - s.selection_mask = bit32.bxor(s.selection_mask, bit32.lshift(1, node_clicked_idx)) -- Ctrl+Click to toggle - else -- if not (selection_mask & (1 << node_clicked_idx)) -- Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection - s.selection_mask = bit32.lshift(1, node_clicked_idx) -- Click to single-select - end - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Advanced") then - local function FB(name, help) - _, s.adv_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_" .. name, s.adv_flags, TN[name]) - if help then ImGui.SameLine(); HelpMarker(help) end - end - FB("OpenOnArrow"); FB("OpenOnDoubleClick") - FB("SpanAvailWidth", "Extend hit area to all available width instead of allowing more items to be laid out after the node.") - FB("SpanFullWidth") - FB("SpanLabelWidth", "Reduce hit area to the text label and a bit of margin.") - FB("SpanAllColumns", "For use in Tables only.") - FB("AllowOverlap") - FB("Framed", "Draw frame with background (e.g. for CollapsingHeader)") - FB("FramePadding"); FB("NavLeftJumpsToParent") - HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") - FB("DrawLinesNone"); FB("DrawLinesFull"); FB("DrawLinesToNodes") - _, s.align_label = ImGui.Checkbox("Align label with current X position", s.align_label) - _, s.use_dnd = ImGui.Checkbox("Make Tree Nodes as drag & drop sources", s.use_dnd) - if s.align_label then ImGui.Unindent(ImGui.GetTreeNodeToLabelSpacing()) end - for node_n = 0, 5 do - local node_flags = s.adv_flags - if node_n < 3 then - -- Items 0..2 are Tree Node - local is_open = ImGui.TreeNodeEx(node_n, node_flags, "Selectable Node %d", node_n) - if s.use_dnd and ImGui.BeginDragDropSource() then - ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) - ImGui.Text("This is a drag and drop source") - ImGui.EndDragDropSource() - end - if node_n == 2 and bit32.band(s.adv_flags, TN.SpanLabelWidth) ~= 0 then - -- Item 2 has an additional inline button to help demonstrate SpanLabelWidth. - ImGui.SameLine() - if ImGui.SmallButton("button") then end - end - if is_open then - ImGui.BulletText("Blah blah\nBlah Blah") - ImGui.SameLine() - ImGui.SmallButton("Button") - ImGui.TreePop() - end - else - -- Items 3..5 are Tree Leaves - -- The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can - -- use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). - node_flags = bit32.bor(node_flags, TN.Leaf, TN.NoTreePushOnOpen) -- ImGuiTreeNodeFlags.Bullet - ImGui.TreeNodeEx(node_n, node_flags, "Selectable Leaf %d", node_n) - if s.use_dnd and ImGui.BeginDragDropSource() then - ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) - ImGui.Text("This is a drag and drop source") - ImGui.EndDragDropSource() - end - end - end - if s.align_label then ImGui.Indent(ImGui.GetTreeNodeToLabelSpacing()) end - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsVerticalSliders() -------------------------------------------------------------------------------- - -S.vs = { int_value = 0, values = { 0.0, 0.60, 0.35, 0.9, 0.70, 0.20, 0.0 }, values2 = { 0.20, 0.80, 0.40, 0.25 } } -function DemoWindowWidgetsVerticalSliders() - if not ImGui.TreeNode("Vertical Sliders") then return end - local s = S.vs - local spacing = 4 - ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(spacing, spacing)) - s.int_value = ImGui.VSliderInt("##int", ImVec2(18, 160), s.int_value, 0, 5) - ImGui.SameLine() - local values = s.values - ImGui.PushID("set1") - for i = 0, 6 do - if i > 0 then ImGui.SameLine() end - ImGui.PushID(i) - ImGui.PushStyleColor(7 --[[ImGuiCol.FrameBg]], HSV(i / 7.0, 0.5, 0.5)) - ImGui.PushStyleColor(8 --[[ImGuiCol.FrameBgHovered]], HSV(i / 7.0, 0.6, 0.5)) - ImGui.PushStyleColor(9 --[[ImGuiCol.FrameBgActive]], HSV(i / 7.0, 0.7, 0.5)) - ImGui.PushStyleColor(20 --[[ImGuiCol.SliderGrab]], HSV(i / 7.0, 0.9, 0.9)) - values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(18, 160), values[i + 1], 0.0, 1.0, "") - if ImGui.IsItemActive() or ImGui.IsItemHovered() then ImGui.SetTooltip("%.3f", values[i + 1]) end - ImGui.PopStyleColor(4) - ImGui.PopID() - end - ImGui.PopID() - - ImGui.SameLine() - ImGui.PushID("set2") - local rows = 3 - local small_slider_size = ImVec2(18, math.floor((160.0 - (rows - 1) * spacing) / rows)) - for nx = 0, 3 do - if nx > 0 then ImGui.SameLine() end - ImGui.BeginGroup() - for ny = 0, rows - 1 do - ImGui.PushID(nx * rows + ny) - s.values2[nx + 1] = ImGui.VSliderFloat("##v", small_slider_size, s.values2[nx + 1], 0.0, 1.0, "") - if ImGui.IsItemActive() or ImGui.IsItemHovered() then ImGui.SetTooltip("%.3f", s.values2[nx + 1]) end - ImGui.PopID() - end - ImGui.EndGroup() - end - ImGui.PopID() - - ImGui.SameLine() - ImGui.PushID("set3") - for i = 0, 3 do - if i > 0 then ImGui.SameLine() end - ImGui.PushID(i) - ImGui.PushStyleVar(21 --[[ImGuiStyleVar.GrabMinSize]], 40) - values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(40, 160), values[i + 1], 0.0, 1.0, "%.2f\nsec") - ImGui.PopStyleVar() - ImGui.PopID() - end - ImGui.PopID() - ImGui.PopStyleVar() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() -------------------------------------------------------------------------------- --- - ShowExampleAppMainMenuBar() --- - ShowExampleMenuFile() -------------------------------------------------------------------------------- - -S.menu = { enabled = true, f = 0.5, n = 0, b = true } --- Note that shortcuts are currently provided for display only --- (future version will add explicit flags to BeginMenu() to request processing shortcuts) -function ShowExampleMenuFile() - local s = S.menu - ImGui.MenuItem("(demo menu)", nil, false, false) - if ImGui.MenuItem("New") then end - if ImGui.MenuItem("Open", "Ctrl+O") then end - if ImGui.BeginMenu("Open Recent") then - ImGui.MenuItem("fish_hat.c") - ImGui.MenuItem("fish_hat.inl") - ImGui.MenuItem("fish_hat.h") - if ImGui.BeginMenu("More..") then - ImGui.MenuItem("Hello") - ImGui.MenuItem("Sailor") - if ImGui.BeginMenu("Recurse..") then - ShowExampleMenuFile() - ImGui.EndMenu() - end - ImGui.EndMenu() - end - ImGui.EndMenu() - end - if ImGui.MenuItem("Save", "Ctrl+S") then end - if ImGui.MenuItem("Save As..") then end - - ImGui.Separator() - if ImGui.BeginMenu("Options") then - _, s.enabled = ImGui.MenuItem("Enabled", "", s.enabled) - ImGui.BeginChild("child", ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 5.0), 1 --[[ImGuiChildFlags.Borders]]) - for i = 0, 9 do ImGui.Text("Scrolling Text %d", i) end - ImGui.EndChild() - s.f = ImGui.SliderFloat("Value", s.f, 0.0, 1.0) - s.f = ImGui.InputFloat("Input", s.f, 0.1) - s.n = ImGui.Combo("Combo", s.n, "Yes\0No\0Maybe\0\0") - ImGui.EndMenu() - end - - if ImGui.BeginMenu("Colors") then - local sz = ImGui.GetTextLineHeight() - for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do - local name = ImGui.GetStyleColorName(i) - local p = ImGui.GetCursorScreenPos() - ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui.GetColorU32(i)) - ImGui.Dummy(ImVec2(sz, sz)) - ImGui.SameLine() - ImGui.MenuItem(name) - end - ImGui.EndMenu() - end - - -- Here we demonstrate appending again to the "Options" menu (which we already created above) - -- Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. - -- In a real code-base using it would make senses to use this feature from very different code locations. - if ImGui.BeginMenu("Options") then -- <-- Append! - _, s.b = ImGui.Checkbox("SomeOption", s.b) - ImGui.EndMenu() - end - - if ImGui.BeginMenu("Disabled", false) then -- Disabled - assert(false) - end - if ImGui.MenuItem("Checked", nil, true) then end - ImGui.Separator() - if ImGui.MenuItem("Quit", "Alt+F4") then end -end - --- Demonstrate creating a "main" fullscreen menu bar and populating it. --- Note the difference between BeginMainMenuBar() and BeginMenuBar(): --- - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags.MenuBar flag!) --- - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. -function ShowExampleAppMainMenuBar() - if ImGui.BeginMainMenuBar() then - if ImGui.BeginMenu("File") then - ShowExampleMenuFile() - ImGui.EndMenu() - end - if ImGui.BeginMenu("Edit") then - if ImGui.MenuItem("Undo", "Ctrl+Z") then end - if ImGui.MenuItem("Redo", "Ctrl+Y", false, false) then end -- Disabled item - ImGui.Separator() - if ImGui.MenuItem("Cut", "Ctrl+X") then end - if ImGui.MenuItem("Copy", "Ctrl+C") then end - if ImGui.MenuItem("Paste", "Ctrl+V") then end - ImGui.EndMenu() - end - ImGui.EndMainMenuBar() - end -end - -------------------------------------------------------------------------------- --- [SECTION] Style Editor / ShowStyleEditor() -------------------------------------------------------------------------------- --- - ShowStyleSelector() --- - ShowStyleEditor() -------------------------------------------------------------------------------- - --- Deep copy of an ImGuiStyle (ImVec2/ImVec4 fields and Colors[] are copied by value) -local function StyleCopy(dst, src) - for k, v in pairs(src) do - if k == "Colors" then - dst.Colors = dst.Colors or {} - for i, c in pairs(v) do - if type(c) == "table" then dst.Colors[i] = dst.Colors[i] or ImVec4(); ImVec4_Copy(dst.Colors[i], c) else dst.Colors[i] = c end - end - elseif type(v) == "table" and getmetatable(v) ~= nil and type(v[1]) == "number" then - local c = dst[k] - if type(c) ~= "table" then c = setmetatable({}, getmetatable(v)); dst[k] = c end - for _, key in ipairs({ "x", "y", "z", "w" }) do if rawget(v, key) ~= nil then rawset(c, key, rawget(v, key)) end end - else - dst[k] = v - end - end - if getmetatable(dst) == nil then setmetatable(dst, getmetatable(src)) end - return dst -end - -local function ColorsEqual(a, b) return a[1] == b[1] and a[2] == b[2] and a[3] == b[3] and a[4] == b[4] end - -S.ss = { style_idx = -1 } --- Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. -function ImGui.ShowStyleSelector(label) - -- FIXME: This is a bit tricky to get right as style are functions, they don't register a name nor the fact that one is active. - -- So we keep track of last active one among our limited selection. - local s = S.ss - local style_names = { "Dark", "Light", "Classic" } - local ret = false - if ImGui.BeginCombo(label, style_names[s.style_idx + 1] or "") then - for n = 0, 2 do - if ImGui.Selectable(style_names[n + 1], s.style_idx == n, 64 --[[ImGuiSelectableFlags.SelectOnNav]]) then - s.style_idx = n - ret = true - if n == 0 then ImGui.StyleColorsDark() elseif n == 1 then ImGui.StyleColorsLight() else ImGui.StyleColorsClassic() end - elseif s.style_idx == n then - ImGui.SetItemDefaultFocus() - end - end - ImGui.EndCombo() - end - return ret -end - -local function GetTreeLinesFlagsName(flags) - local TN = ImGuiTreeNodeFlags - if flags == TN.DrawLinesNone then return "DrawLinesNone" end - if flags == TN.DrawLinesFull then return "DrawLinesFull" end - if flags == TN.DrawLinesToNodes then return "DrawLinesToNodes" end - return "" -end - -S.se = { ref_saved_style = nil, init = true, output_dest = 0, output_only_modified = true, alpha_flags = 0, filter = nil } -function ImGui.ShowStyleEditor(ref) - -- You can pass in a reference ImGuiStyle structure to compare to, revert to and save to - -- (without a reference style, we will use one compared locally as a reference) - local se = S.se - local style = ImGui.GetStyle() - if se.ref_saved_style == nil then se.ref_saved_style = {} end - - -- Default to using internal storage as reference - if se.init and ref == nil then StyleCopy(se.ref_saved_style, style) end - se.init = false - if ref == nil then ref = se.ref_saved_style end - - -- The logic behind dynamically changing 'max_border_size' is to not encourage people to increase border size too much: it'll likely reveal lots of subtle rendering artifacts and this isn't a priority right now. - -- Note that _MainScale is currently internal PLEASE DO NOT USE IN YOUR CODE. - local default_border_size = math.floor(style._MainScale or 1.0) - local max_border_size = math.max(default_border_size, 2.0) - local function SF(name, mn, mx, fmt) if style[name] ~= nil then style[name] = ImGui.SliderFloat(name, style[name], mn, mx, fmt or "%.0f") end end - local function SF2(name, mn, mx, fmt) if style[name] ~= nil then ImGui.SliderFloat2(name, style[name], mn, mx, fmt or "%.0f") end end - local function DF(name, speed, mn, mx, fmt, flags) if style[name] ~= nil then style[name] = ImGui.DragFloat(name, style[name], speed, mn, mx, fmt or "%.0f", flags) end end - - ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50) - - -- General - ImGui.SeparatorText("General") - if bit32.band(ImGui.GetIO().BackendFlags, 16 --[[ImGuiBackendFlags.RendererHasTextures]]) == 0 then - ImGui.BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!") - ImGui.BulletText("For instructions, see:") - ImGui.SameLine() - ImGui.TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md") - end - if ImGui.ShowStyleSelector("Colors##Selector") then StyleCopy(se.ref_saved_style, style) end - if ImGui.ShowFontSelector then ImGui.ShowFontSelector("Fonts##Selector") end - local changed - style.FontSizeBase, changed = ImGui.DragFloat("FontSizeBase", style.FontSizeBase, 0.20, 5.0, 100.0, "%.0f") - if changed then style._NextFrameFontSizeBase = style.FontSizeBase end -- FIXME: Temporary hack until we finish remaining work. - ImGui.SameLine(0.0, 0.0); ImGui.Text(" (out %.2f)", ImGui.GetFontSize()) - style.FontScaleMain = ImGui.DragFloat("FontScaleMain", style.FontScaleMain, 0.02, 0.5, 4.0) - ImGui.BeginDisabled(ImGui.GetIO().ConfigDpiScaleFonts == true) - style.FontScaleDpi = ImGui.DragFloat("FontScaleDpi", style.FontScaleDpi, 0.02, 0.5, 4.0) - ImGui.SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.") - ImGui.EndDisabled() - - -- Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0 or 1.0) - style.FrameRounding, changed = ImGui.SliderFloat("FrameRounding", style.FrameRounding, 0.0, 12.0, "%.0f") - if changed then style.GrabRounding = style.FrameRounding end -- Make GrabRounding always the same value as FrameRounding - local p, border - p, border = ImGui.Checkbox("WindowBorder", style.WindowBorderSize > 0.0); if p then style.WindowBorderSize = border and default_border_size or 0.0 end - ImGui.SameLine() - p, border = ImGui.Checkbox("FrameBorder", style.FrameBorderSize > 0.0); if p then style.FrameBorderSize = border and default_border_size or 0.0 end - ImGui.SameLine() - p, border = ImGui.Checkbox("PopupBorder", style.PopupBorderSize > 0.0); if p then style.PopupBorderSize = border and default_border_size or 0.0 end - - -- Save/Revert button - if ImGui.Button("Save Ref") then StyleCopy(se.ref_saved_style, style); if ref ~= se.ref_saved_style then StyleCopy(ref, style) end end - ImGui.SameLine() - if ImGui.Button("Revert Ref") then StyleCopy(style, ref) end - ImGui.SameLine() - HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export\" below to save them somewhere.") - - ImGui.SeparatorText("Details") - if ImGui.BeginTabBar("##tabs", 0 --[[ImGuiTabBarFlags.None]]) then - if ImGui.BeginTabItem("Sizes") then - ImGui.SeparatorText("Main") - SF2("WindowPadding", 0.0, 20.0); SF2("FramePadding", 0.0, 20.0); SF2("ItemSpacing", 0.0, 20.0) - SF2("ItemInnerSpacing", 0.0, 20.0); SF2("TouchExtraPadding", 0.0, 10.0) - SF("IndentSpacing", 0.0, 30.0); SF("GrabMinSize", 1.0, 20.0) - - ImGui.SeparatorText("Borders") - SF("WindowBorderSize", 0.0, max_border_size); SF("ChildBorderSize", 0.0, max_border_size) - SF("PopupBorderSize", 0.0, max_border_size); SF("FrameBorderSize", 0.0, max_border_size) - - ImGui.SeparatorText("Rounding") - SF("WindowRounding", 0.0, 12.0); SF("ChildRounding", 0.0, 12.0); SF("FrameRounding", 0.0, 12.0) - SF("PopupRounding", 0.0, 12.0); SF("GrabRounding", 0.0, 12.0); SF("MenuItemRounding", 0.0, 12.0) - -- NB: SelectableRounding is intentionally NOT made visible here. We don't want to encourage people using that. - - ImGui.SeparatorText("Scrollbar") - SF("ScrollbarSize", 1.0, 20.0); SF("ScrollbarRounding", 0.0, 12.0); SF("ScrollbarPadding", 0.0, 10.0) - - ImGui.SeparatorText("Tabs") - SF("TabBorderSize", 0.0, max_border_size); SF("TabBarBorderSize", 0.0, max_border_size) - SF("TabBarOverlineSize", 0.0, math.max(3.0, max_border_size)) - ImGui.SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.") - DF("TabMinWidthBase", 0.5, 1.0, 500.0); DF("TabMinWidthShrink", 0.5, 1.0, 500.0, "%0.f") - if style.TabCloseButtonMinWidthSelected ~= nil then - DF("TabCloseButtonMinWidthSelected", 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthSelected < 0.0) and "%.0f (Always)" or "%.0f") - DF("TabCloseButtonMinWidthUnselected", 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthUnselected < 0.0) and "%.0f (Always)" or "%.0f") - end - SF("TabRounding", 0.0, 12.0) - - ImGui.SeparatorText("Tables") - SF2("CellPadding", 0.0, 20.0) - style.TableAngledHeadersAngle = ImGui.SliderAngle("TableAngledHeadersAngle", style.TableAngledHeadersAngle, -50.0, 50.0) - SF2("TableAngledHeadersTextAlign", 0.0, 1.0, "%.2f") - - ImGui.SeparatorText("Trees") - local combo_open = ImGui.BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)) - ImGui.SameLine() - HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode.") - if combo_open then - local TN = ImGuiTreeNodeFlags - for _, option in ipairs({ TN.DrawLinesNone, TN.DrawLinesFull, TN.DrawLinesToNodes }) do - if ImGui.Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option) then style.TreeLinesFlags = option end - end - ImGui.EndCombo() - end - SF("TreeLinesSize", 0.0, max_border_size); SF("TreeLinesRounding", 0.0, 12.0) - - ImGui.SeparatorText("Windows") - SF2("WindowTitleAlign", 0.0, 1.0, "%.2f"); SF("WindowBorderHoverPadding", 1.0, 20.0) - local window_menu_button_position = style.WindowMenuButtonPosition + 1 - window_menu_button_position, changed = ImGui.Combo("WindowMenuButtonPosition", window_menu_button_position, "None\0Left\0Right\0") - if changed then style.WindowMenuButtonPosition = window_menu_button_position - 1 end - - ImGui.SeparatorText("Widgets") - SF("ColorMarkerSize", 0.0, 8.0) - style.ColorButtonPosition = ImGui.Combo("ColorButtonPosition", style.ColorButtonPosition, "Left\0Right\0") - SF2("ButtonTextAlign", 0.0, 1.0, "%.2f") - ImGui.SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.") - SF2("SelectableTextAlign", 0.0, 1.0, "%.2f") - ImGui.SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.") - SF("SeparatorSize", 0.0, 10.0); SF("SeparatorTextBorderSize", 0.0, 10.0) - SF2("SeparatorTextAlign", 0.0, 1.0, "%.2f"); SF2("SeparatorTextPadding", 0.0, 40.0) - SF("LogSliderDeadzone", 0.0, 12.0); SF("ImageRounding", 0.0, 12.0); SF("ImageBorderSize", 0.0, max_border_size) - - ImGui.SeparatorText("Docking") - -- SetCursorPosX(GetCursorPosX() + CalcItemWidth() - GetFrameHeight()) - _, style.DockingNodeHasCloseButton = ImGui.Checkbox("DockingNodeHasCloseButton", style.DockingNodeHasCloseButton) - SF("DockingSeparatorSize", 0.0, 12.0) - - ImGui.SeparatorText("Tooltips") - for n = 0, 1 do - local key = (n == 0) and "HoverFlagsForTooltipMouse" or "HoverFlagsForTooltipNav" - if ImGui.TreeNodeEx(key) then - for _, f in ipairs({ "DelayNone", "DelayShort", "DelayNormal", "Stationary", "NoSharedDelay" }) do - _, style[key] = ImGui.CheckboxFlags("ImGuiHoveredFlags_" .. f, style[key], ImGuiHoveredFlags[f]) - end - ImGui.TreePop() - end - end - - ImGui.SeparatorText("Misc") - SF2("DisplayWindowPadding", 0.0, 30.0); ImGui.SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.") - SF2("DisplaySafeAreaPadding", 0.0, 30.0); ImGui.SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).") - ImGui.EndTabItem() - end - - if ImGui.BeginTabItem("Colors") then - if ImGui.Button("Export") then - if se.output_dest == 0 then ImGui.LogToClipboard() else ImGui.LogToTTY() end - ImGui.LogText("ImVec4* colors = GetStyle().Colors;\n") - for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do - local col = style.Colors[i] - local name = ImGui.GetStyleColorName(i) - if not se.output_only_modified or not ColorsEqual(col, ref.Colors[i]) then - ImGui.LogText("colors[ImGuiCol_%s]%s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);\n", name, string.rep(" ", math.max(0, 23 - #name)), col.x, col.y, col.z, col.w) - end - end - ImGui.LogFinish() - end - ImGui.SameLine(); ImGui.SetNextItemWidth(ImGui.GetFontSize() * 10) - se.output_dest = ImGui.Combo("##output_type", se.output_dest, "To Clipboard\0To TTY\0") - ImGui.SameLine(); _, se.output_only_modified = ImGui.Checkbox("Only Modified Colors", se.output_only_modified) - - local CE = ImGuiColorEditFlags - if ImGui.RadioButtonEx("Opaque", se.alpha_flags == CE.AlphaOpaque) then se.alpha_flags = CE.AlphaOpaque end ImGui.SameLine() - if ImGui.RadioButtonEx("Alpha", se.alpha_flags == CE.None) then se.alpha_flags = CE.None end ImGui.SameLine() - if ImGui.RadioButtonEx("Both", se.alpha_flags == CE.AlphaPreviewHalf) then se.alpha_flags = CE.AlphaPreviewHalf end ImGui.SameLine() - HelpMarker("In the color list:\nLeft-click on color square to open color picker,\nRight-click to open edit options menu.") - - se.filter = se.filter or ImGuiTextFilter() - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - se.filter:DrawWithHint("##FilterColors", "Filter Colors (incl -excl)") - - ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 10), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]])) - ImGui.BeginChild("##colors", ImVec2(0, 0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 256 --[[ImGuiChildFlags.NavFlattened]]), bit32.bor(16384 --[[ImGuiWindowFlags.AlwaysVerticalScrollbar]], 32768 --[[ImGuiWindowFlags.AlwaysHorizontalScrollbar]])) - ImGui.PushItemWidth(ImGui.GetFontSize() * -12) - -- [Luau] clipped: only visible rows are submitted (upstream submits every color) - local visible_cols = {} - for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do - if se.filter:PassFilter(ImGui.GetStyleColorName(i)) then visible_cols[#visible_cols + 1] = i end - end - local clipper = ImGuiListClipper() - clipper:Begin(#visible_cols) - while clipper:Step() do for row = clipper.DisplayStart, clipper.DisplayEnd - 1 do - local i = visible_cols[row + 1] - local name = ImGui.GetStyleColorName(i) - do - ImGui.PushID(i) - if ImGui.DebugFlashStyleColor then - if ImGui.Button("?") then ImGui.DebugFlashStyleColor(i) end - ImGui.SetItemTooltip("Flash given color to identify places where it is used.") - ImGui.SameLine() - end - ImGui.ColorEdit4("##color", style.Colors[i], bit32.bor(CE.AlphaBar, se.alpha_flags)) - if not ColorsEqual(style.Colors[i], ref.Colors[i]) then - -- Tips: in a real user application, you may want to merge and use an icon font into the main font, - -- so instead of "Save"/"Revert" you'd use icons! - -- Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! - ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Save") then ImVec4_Copy(ref.Colors[i], style.Colors[i]) end - ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Revert") then ImVec4_Copy(style.Colors[i], ref.Colors[i]) end - end - ImGui.SameLine(0.0, style.ItemInnerSpacing.x) - ImGui.TextUnformatted(name) - ImGui.PopID() - end - end end - clipper:End() - ImGui.PopItemWidth() - ImGui.EndChild() - ImGui.EndTabItem() - end - - if ImGui.BeginTabItem("Fonts") then - if ImGui.ShowFontAtlas then ImGui.ShowFontAtlas(ImGui.GetIO().Fonts) else DemoNotPorted("ShowFontAtlas") end - ImGui.EndTabItem() - end - - if ImGui.BeginTabItem("Rendering") then - _, style.AntiAliasedLines = ImGui.Checkbox("Anti-aliased lines", style.AntiAliasedLines) - ImGui.SameLine() - HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.") - ImGui.BeginDisabled(style.AntiAliasedLines == false) - _, style.AntiAliasedLineEnds = ImGui.Checkbox("Anti-aliased line ends", style.AntiAliasedLineEnds) - ImGui.EndDisabled() - _, style.AntiAliasedFill = ImGui.Checkbox("Anti-aliased fill", style.AntiAliasedFill) - local io = ImGui.GetIO() - _, io.ConfigDebugDrawListDefaultsToStrokeLegacy = ImGui.Checkbox("Debug: DrawList Defaults to _StrokeLegacy", io.ConfigDebugDrawListDefaultsToStrokeLegacy == true) - - ImGui.PushItemWidth(ImGui.GetFontSize() * 8) - -- [port] library still stores the pre-1.93 CurveTessellationTol (== MaxError * MaxError) - local curve_err = ImGui.DragFloat("Curve Tessellation Max Error", math.sqrt(style.CurveTessellationTol), 0.02, 0.10, 10.0, "%.2f") - if curve_err < 0.10 then curve_err = 0.10 end - style.CurveTessellationTol = curve_err * curve_err - - -- When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. - style.CircleTessellationMaxError = ImGui.DragFloat("Circle Tessellation Max Error", style.CircleTessellationMaxError, 0.005, 0.10, 5.0, "%.2f", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) - local show_samples = ImGui.IsItemActive() - if show_samples then ImGui.SetNextWindowPos(ImGui.GetCursorScreenPos()) end - if show_samples and ImGui.BeginTooltip() then - ImGui.TextUnformatted("(R = radius, N = approx number of segments)") - ImGui.Spacing() - local draw_list = ImGui.GetWindowDrawList() - local min_widget_width = ImGui.CalcTextSize("R: MMM\nN: MMM").x - for n = 0, 7 do - local RAD_MIN, RAD_MAX = 5.0, 70.0 - local rad = RAD_MIN + (RAD_MAX - RAD_MIN) * n / (8.0 - 1.0) - ImGui.BeginGroup() - - -- N is not always exact here due to how PathArcTo() function work internally - ImGui.Text("R: %.f\nN: %d", rad, draw_list:_CalcCircleAutoSegmentCount(rad)) - local canvas_width = math.max(min_widget_width, rad * 2.0) - local offset_x = math.floor(canvas_width * 0.5) - local offset_y = math.floor(RAD_MAX) - local p1 = ImGui.GetCursorScreenPos() - draw_list:AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui.GetColorU32(0 --[[ImGuiCol.Text]])) - ImGui.Dummy(ImVec2(canvas_width, RAD_MAX * 2)) - - -- local p2 = ImGui.GetCursorScreenPos() - -- draw_list:AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui.GetColorU32(ImGuiCol.Text)) - -- ImGui.Dummy(ImVec2(canvas_width, RAD_MAX * 2)) - - ImGui.EndGroup() - ImGui.SameLine() - end - ImGui.EndTooltip() - end - ImGui.SameLine() - HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically.") - style.Alpha = ImGui.DragFloat("Global Alpha", style.Alpha, 0.005, 0.20, 1.0, "%.2f") -- Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. - style.DisabledAlpha = ImGui.DragFloat("Disabled Alpha", style.DisabledAlpha, 0.005, 0.0, 1.0, "%.2f") - ImGui.SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).") - ImGui.PopItemWidth() - ImGui.EndTabItem() - end - ImGui.EndTabBar() - end - ImGui.PopItemWidth() -end -end --[[ imgui_demo_widgets.lua ]] - -do --[[ About window ]] --- Demo tools: ShowAboutWindow(), ShowFontAtlas(), ShowFontSelector(), ShowDebugLogWindow(), ShowIDStackToolWindow() -local _ - -------------------------------------------------------------------------------- --- [SECTION] About Window / ShowAboutWindow() --- Access from Dear ImGui Demo -> Tools -> About -------------------------------------------------------------------------------- - -local show_config_info = false -function ImGui.ShowAboutWindow(p_open) - local visible - p_open, visible = ImGui.Begin("About Dear ImGui", p_open, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) - if not visible then ImGui.End(); return p_open end - ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, 19298 --[[IMGUI_VERSION_NUM]]) - ImGui.TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui"); ImGui.SameLine() - ImGui.TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Extensions", "https://github.com/ocornut/imgui/wiki/Useful-Extensions"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding") - ImGui.Separator() - ImGui.Text("(c) 2014-2026 Omar Cornut") - ImGui.Text("Developed by Omar Cornut and all Dear ImGui contributors.") - ImGui.Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.") - ImGui.Text("If your company uses this, please consider funding the project.") - ImGui.Text("Luau/Roblox port: imgui_impl_roblox (software rasterizer into EditableImage tiles).") - - _, show_config_info = ImGui.Checkbox("Config/Build Information", show_config_info) - if show_config_info then - local io = ImGui.GetIO() - local style = ImGui.GetStyle() - local copy_to_clipboard = ImGui.Button("Copy to clipboard") - local child_size = ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 18) - ImGui.BeginChild(ImGui.GetID("cfg_infos"), child_size, 128 --[[ImGuiChildFlags.FrameStyle]]) - if copy_to_clipboard then - ImGui.LogToClipboard() - ImGui.LogText("// (Copy from the next line. Keep the ``` markers for formatting.)\n") - ImGui.LogText("```cpp\n") -- Back quotes will make text appears without formatting when pasting on GitHub - end - ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, 19298 --[[IMGUI_VERSION_NUM]]) - ImGui.Separator() - ImGui.Text("define: IMGUI_HAS_VIEWPORT") - ImGui.Text("define: IMGUI_HAS_DOCK") - ImGui.Text("runtime: Luau (%s)", _VERSION or "?") - ImGui.Separator() - ImGui.Text("io.BackendPlatformName: %s", io.BackendPlatformName or "NULL") - ImGui.Text("io.BackendRendererName: %s", io.BackendRendererName or "NULL") - ImGui.Text("io.ConfigFlags: 0x%08X", io.ConfigFlags) - local CF = ImGuiConfigFlags - for _, n in ipairs({ "NavEnableKeyboard", "NavEnableGamepad", "NoMouse", "NoMouseCursorChange", "NoKeyboard", "DockingEnable", "ViewportsEnable" }) do - if CF[n] and bit32.band(io.ConfigFlags, CF[n]) ~= 0 then ImGui.Text(" %s", n) end - end - for _, n in ipairs({ "MouseDrawCursor", "ConfigDpiScaleFonts", "ConfigDpiScaleViewports", "ConfigViewportsNoAutoMerge", "ConfigViewportsNoTaskBarIcon", - "ConfigViewportsNoDecoration", "ConfigViewportsNoDefaultParent", "ConfigDockingNoSplit", "ConfigDockingNoDockingOver", "ConfigDockingWithShift", - "ConfigDockingAlwaysTabBar", "ConfigDockingTransparentPayload", "ConfigMacOSXBehaviors", "ConfigNavMoveSetMousePos", "ConfigNavCaptureKeyboard", - "ConfigInputTextCursorBlink", "ConfigWindowsResizeFromEdges", "ConfigWindowsMoveFromTitleBarOnly" }) do - if io[n] == true then ImGui.Text("io.%s", n) end - end - if (io.ConfigMemoryCompactTimer or -1) >= 0.0 then ImGui.Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer) end - ImGui.Text("io.BackendFlags: 0x%08X", io.BackendFlags) - local BF = ImGuiBackendFlags - for _, n in ipairs({ "HasGamepad", "HasMouseCursors", "HasSetMousePos", "PlatformHasViewports", "HasMouseHoveredViewport", "HasParentViewport", - "RendererHasVtxOffset", "RendererHasTextures", "RendererHasViewports" }) do - if BF[n] and bit32.band(io.BackendFlags, BF[n]) ~= 0 then ImGui.Text(" %s", n) end - end - ImGui.Separator() - local atlas = io.Fonts - ImGui.Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", atlas.Fonts.Size, atlas.Flags or 0, atlas.TexData and atlas.TexData.Width or 0, atlas.TexData and atlas.TexData.Height or 0) - ImGui.Text("io.Fonts->FontLoaderName: %s", atlas.FontLoaderName or "NULL") - ImGui.Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y) - ImGui.Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y) - ImGui.Separator() - ImGui.Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y) - ImGui.Text("style.WindowBorderSize: %.2f", style.WindowBorderSize) - ImGui.Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y) - ImGui.Text("style.FrameRounding: %.2f", style.FrameRounding) - ImGui.Text("style.FrameBorderSize: %.2f", style.FrameBorderSize) - ImGui.Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y) - ImGui.Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y) - if copy_to_clipboard then - ImGui.LogText("\n```\n") - ImGui.LogFinish() - end - ImGui.EndChild() - end +function ShowExampleAppAssetsBrowser(p_open) + IMGUI_DEMO_MARKER("Examples/Assets Browser") + -- [Port] TODO: ExampleAssetsBrowser needs BeginMultiSelect()/box-select + local open, visible = ImGui.Begin("Example: Assets Browser", p_open) + if visible then ImGui.TextDisabled("(multi-select API not ported yet)") end ImGui.End() - return p_open + return open end -end --[[ About window ]] return true end @@ -38408,6 +40423,32 @@ function ImGuiTextBufferMT:appendf(fmt, ...) self.Buf[#self.Buf + 1] = string.fo function ImGuiTextBufferMT:c_str() return table.concat(self.Buf) end function ImGuiTextBufferMT:size() return #self:c_str() end +-- Helpers: ImColor() implicitly converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float) +-- Prefer using IM_COL32() macros. Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. +-- **None of the ImGui API are using ImColor directly but you can use it as a convenience to pass colors in either ImU32 or ImVec4 formats. Explicitly cast to ImU32 or ImVec4 if needed. +-- [Luau] no implicit conversions: use :U32() / .Value (ImVec4). Overloads: ImColor(), ImColor(r, g, b, a) floats, +-- ImColor(ImVec4), ImColor(ImU32). The C++ int (0-255) overload can't be told apart from floats: use ImColor(IM_COL32(r, g, b, a)). +--- @class ImColor +local ImColorMT = {} +ImColorMT.__index = ImColorMT +ImColor = setmetatable({}, { __call = function(_, r, g, b, a) + local self = setmetatable({ Value = ImVec4() }, ImColorMT) + if type(r) == "table" then + ImVec4_Copy(self.Value, r) + elseif r ~= nil and g == nil then + local s = 1.0 / 255.0 + self.Value.x = bit32.band(bit32.rshift(r, 0 --[[IM_COL32_R_SHIFT]]), 0xFF) * s; self.Value.y = bit32.band(bit32.rshift(r, 8 --[[IM_COL32_G_SHIFT]]), 0xFF) * s + self.Value.z = bit32.band(bit32.rshift(r, 16 --[[IM_COL32_B_SHIFT]]), 0xFF) * s; self.Value.w = bit32.band(bit32.rshift(r, 24 --[[IM_COL32_A_SHIFT]]), 0xFF) * s + elseif r ~= nil then + self.Value.x = r; self.Value.y = g; self.Value.z = b; self.Value.w = a or 1.0 + end + return self +end }) +function ImColorMT:U32() return ImGui.ColorConvertFloat4ToU32(self.Value) end +-- FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. +function ImColorMT:SetHSV(h, s, v, a) self.Value.x, self.Value.y, self.Value.z = ImGui.ColorConvertHSVtoRGB(h, s, v); self.Value.w = a or 1.0 end +function ImColor.HSV(h, s, v, a) local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v); return ImColor(r, g, b, a or 1.0) end + --- @class ImGuiSettingsHandler --- Fns take (ctx, handler, ...) like upstream. ReadOpenFn(ctx, handler, name) returns entry; ReadLineFn(ctx, handler, entry, line); --- WriteAllFn(ctx, handler, buf: ImGuiTextBuffer) @@ -70863,21 +72904,12 @@ IM_INCLUDE('imgui_demo.lua') return { BuildLoadGlyphGetAdvanceOrFallback = BuildLoadGlyphGetAdvanceOrFallback, CalcNextScrollFromScrollTargetAndClamp = CalcNextScrollFromScrollTargetAndClamp, + CustomConstraints = CustomConstraints, DBL_MAX = DBL_MAX, - DemoB2I = DemoB2I, - DemoBuf = DemoBuf, - DemoBufStr = DemoBufStr, - DemoClamp = DemoClamp, - DemoCollapsingHeaderClosable = DemoCollapsingHeaderClosable, - DemoCombo = DemoCombo, - DemoHSV = DemoHSV, - DemoHas = DemoHas, - DemoItems = DemoItems, - DemoListBox = DemoListBox, - DemoNotPorted = DemoNotPorted, - DemoNotSupported = DemoNotSupported, - DemoTextFilter = DemoTextFilter, + DemoWindowColumns = DemoWindowColumns, + DemoWindowInputs = DemoWindowInputs, DemoWindowLayout = DemoWindowLayout, + DemoWindowMenuBar = DemoWindowMenuBar, DemoWindowPopups = DemoWindowPopups, DemoWindowTables = DemoWindowTables, DemoWindowWidgets = DemoWindowWidgets, @@ -70900,6 +72932,7 @@ return { DemoWindowWidgetsProgressBars = DemoWindowWidgetsProgressBars, DemoWindowWidgetsQueryingStatuses = DemoWindowWidgetsQueryingStatuses, DemoWindowWidgetsSelectables = DemoWindowWidgetsSelectables, + DemoWindowWidgetsSelectionAndMultiSelect = DemoWindowWidgetsSelectionAndMultiSelect, DemoWindowWidgetsTabs = DemoWindowWidgetsTabs, DemoWindowWidgetsText = DemoWindowWidgetsText, DemoWindowWidgetsTextFilter = DemoWindowWidgetsTextFilter, @@ -70915,10 +72948,23 @@ return { DockSettingsHandler_WriteAll = DockSettingsHandler_WriteAll, DockSettingsRemoveNodeReferences = DockSettingsRemoveNodeReferences, DockSettingsRenameNodeReferences = DockSettingsRenameNodeReferences, + EditTabBarFittingPolicyFlags = EditTabBarFittingPolicyFlags, + EditTableColumnsFlags = EditTableColumnsFlags, + EditTableSizingFlags = EditTableSizingFlags, + ExampleAppConsole = ExampleAppConsole, + ExampleAppConsoleMT = ExampleAppConsoleMT, + ExampleAppDocuments = ExampleAppDocuments, + ExampleAppLog = ExampleAppLog, + ExampleAppLogMT = ExampleAppLogMT, + ExampleAppPropertyEditor = ExampleAppPropertyEditor, + ExampleAppPropertyEditorMT = ExampleAppPropertyEditorMT, ExampleImageViewerData = ExampleImageViewerData, ExampleImageViewer_DrawCanvas = ExampleImageViewer_DrawCanvas, ExampleImageViewer_DrawOptions = ExampleImageViewer_DrawOptions, + ExampleMemberInfo = ExampleMemberInfo, + ExampleNames = ExampleNames, ExampleTreeNode = ExampleTreeNode, + ExampleTreeNodeMemberInfos = ExampleTreeNodeMemberInfos, ExampleTree_CreateDemoTree = ExampleTree_CreateDemoTree, ExampleTree_CreateNode = ExampleTree_CreateNode, ExampleTree_DestroyNode = ExampleTree_DestroyNode, @@ -70930,6 +72976,7 @@ return { GetDefaultFontDataProggyClean = GetDefaultFontDataProggyClean, GetDefaultFontDataProggyForever = GetDefaultFontDataProggyForever, GetMinimumStepAtDecimalPrecision = GetMinimumStepAtDecimalPrecision, + GetTreeLinesFlagsName = GetTreeLinesFlagsName, HelpMarker = HelpMarker, IMGUI_DEBUG_LOG_ACTIVEID = IMGUI_DEBUG_LOG_ACTIVEID, IMGUI_DEBUG_LOG_CLIPPER = IMGUI_DEBUG_LOG_CLIPPER, @@ -71008,6 +73055,7 @@ return { ImCharIsBlankW = ImCharIsBlankW, ImCharIsSeparatorW = ImCharIsSeparatorW, ImClamp = ImClamp, + ImColor = ImColor, ImCos = ImCos, ImCountSetBits = ImCountSetBits, ImDot = ImDot, @@ -71116,6 +73164,7 @@ return { ImGuiDataAuthority = ImGuiDataAuthority, ImGuiDataType = ImGuiDataType, ImGuiDebugLogFlags = ImGuiDebugLogFlags, + ImGuiDemoDockspaceArgs = ImGuiDemoDockspaceArgs, ImGuiDemoWindowData = ImGuiDemoWindowData, ImGuiDir = ImGuiDir, ImGuiDockContext = ImGuiDockContext, @@ -71212,6 +73261,7 @@ return { ImGuiStyleMod = ImGuiStyleMod, ImGuiStyleVar = ImGuiStyleVar, ImGuiStyleVarInfo = ImGuiStyleVarInfo, + ImGuiStyle_Copy = ImGuiStyle_Copy, ImGuiTabBar = ImGuiTabBar, ImGuiTabBarFlags = ImGuiTabBarFlags, ImGuiTabItem = ImGuiTabItem, @@ -71321,9 +73371,21 @@ return { ImVec4_Copy = ImVec4_Copy, ImVector = ImVector, ImWcharClass = ImWcharClass, + MyDocument = MyDocument, + MyItem = MyItem, + MyItemColumnID_Action = MyItemColumnID_Action, + MyItemColumnID_Description = MyItemColumnID_Description, + MyItemColumnID_ID = MyItemColumnID_ID, + MyItemColumnID_Name = MyItemColumnID_Name, + MyItemColumnID_Quantity = MyItemColumnID_Quantity, + MyItem_CompareWithSortSpecs = MyItem_CompareWithSortSpecs, + MyItem_SortWithSortSpecs = MyItem_SortWithSortSpecs, + MyItem_s_current_sort_specs = MyItem_s_current_sort_specs, NAV_ACTIVATE_HIGHLIGHT_TIMER = NAV_ACTIVATE_HIGHLIGHT_TIMER, NAV_ACTIVATE_INPUT_WITH_GAMEPAD_DELAY = NAV_ACTIVATE_INPUT_WITH_GAMEPAD_DELAY, NAV_WINDOWING_HIGHLIGHT_DELAY = NAV_WINDOWING_HIGHLIGHT_DELAY, + PopStyleCompact = PopStyleCompact, + PushStyleCompact = PushStyleCompact, STB_TEXTEDIT_K_BACKSPACE = STB_TEXTEDIT_K_BACKSPACE, STB_TEXTEDIT_K_DELETE = STB_TEXTEDIT_K_DELETE, STB_TEXTEDIT_K_DOWN = STB_TEXTEDIT_K_DOWN, @@ -71344,13 +73406,17 @@ return { STB_TEXTEDIT_NEWLINE = STB_TEXTEDIT_NEWLINE, STB_TexteditState = STB_TexteditState, ShowDockingDisabledMessage = ShowDockingDisabledMessage, + ShowExampleAppAssetsBrowser = ShowExampleAppAssetsBrowser, ShowExampleAppAutoResize = ShowExampleAppAutoResize, ShowExampleAppConsole = ShowExampleAppConsole, ShowExampleAppConstrainedResize = ShowExampleAppConstrainedResize, ShowExampleAppCustomRendering = ShowExampleAppCustomRendering, ShowExampleAppDockSpace = ShowExampleAppDockSpace, + ShowExampleAppDockSpaceAdvanced = ShowExampleAppDockSpaceAdvanced, + ShowExampleAppDockSpaceBasic = ShowExampleAppDockSpaceBasic, ShowExampleAppDocuments = ShowExampleAppDocuments, ShowExampleAppFullscreen = ShowExampleAppFullscreen, + ShowExampleAppImageViewer = ShowExampleAppImageViewer, ShowExampleAppLayout = ShowExampleAppLayout, ShowExampleAppLog = ShowExampleAppLog, ShowExampleAppLongText = ShowExampleAppLongText, @@ -71359,6 +73425,7 @@ return { ShowExampleAppSimpleOverlay = ShowExampleAppSimpleOverlay, ShowExampleAppWindowTitles = ShowExampleAppWindowTitles, ShowExampleMenuFile = ShowExampleMenuFile, + ShowTableColumnsStatusFlags = ShowTableColumnsStatusFlags, TILE_SIZE = TILE_SIZE, UINT_MAX = UINT_MAX, VTX_STRIDE = VTX_STRIDE, diff --git a/build/imgui_love.linemap.json b/build/imgui_love.linemap.json index b7d599c..4522254 100644 --- a/build/imgui_love.linemap.json +++ b/build/imgui_love.linemap.json @@ -1 +1 @@ -[[183, "imgui.lua"], [21532, "imgui_demo.lua"], [29950, "imgui_draw.lua"], [35893, "imgui_h.lua"], [38560, "imgui_impl_love.lua"], [39100, "imgui_internal.lua"], [42569, "imgui_tables.lua"], [47628, "imgui_widgets.lua"], [58268, "imstb_rectpack.lua"], [58932, "imstb_textedit.lua"], [60474, "imstb_truetype.lua"], [63262, "imstd_minstdio.lua"]] \ No newline at end of file +[[183, "imgui.lua"], [21532, "imgui_demo.lua"], [31965, "imgui_draw.lua"], [37908, "imgui_h.lua"], [40601, "imgui_impl_love.lua"], [41141, "imgui_internal.lua"], [44610, "imgui_tables.lua"], [49669, "imgui_widgets.lua"], [60309, "imstb_rectpack.lua"], [60973, "imstb_textedit.lua"], [62515, "imstb_truetype.lua"], [65303, "imstd_minstdio.lua"]] \ No newline at end of file diff --git a/build/imgui_love.lua b/build/imgui_love.lua index ec5b02b..b500f3f 100644 --- a/build/imgui_love.lua +++ b/build/imgui_love.lua @@ -138,7 +138,7 @@ if not utf8 then end -local ImGui, ImVec2, ImVec4, ImRect, ImVec2_Copy, ImStd, ImVector, ImGuiKey, HelpMarker, IMGUI_DEMO_MARKER, ImGuiInputFlags, ImRect_Copy, ImGuiDataType, ImStb, IM_TRUNC, ImGuiStyleVarInfo, ImVec2_CopyV, IM_ASSERT_USER_ERROR, ImGuiHoveredFlags, ImFormatString, ImHashStr, ImS32, ImGuiColorEditFlags, IM_ASSERT_USER_ERROR_RET, ImDrawFlags, ImGuiTableFlags, ImIsPowerOfTwo, ImGuiWindowFlags, ImVec4_Copy, IM_ROUND, ImGuiTreeNodeFlags, ImGuiTableColumnFlags, ImU16, ImAbs, ImGuiItemFlags, stbte, ImGuiButtonFlags, ImGuiDebugLogFlags, ImGuiLocKey, ImU32, ImCos, ImGuiTabBarFlags, ImS16, ImSin, ImUpperPowerOfTwo, ImVec2_MulVX, IM_F32_TO_INT8_SAT, ImCeil, ImFontAtlasPackGetRect, ImGuiListClipper, ImGuiMouseCursor, DockSettingsRenameNodeReferences, IM_ASSERT_PARANOID, ImGuiCol, ImGuiTextFilter, ImLengthSqr, ImS8, ImU8, _PathArcToFastExXY, ImGuiScrollFlags, ImGui_ImplLOVE_GetBackendData, ImLog, ImGuiComboFlags, ImPow, DemoHas, IMGUI_DEBUG_LOG_FONT, ImAddClampOverflow, ImFontAtlasBuildInit, ImFontCalcWordWrapPositionEx, ImGuiPopupFlags, ImGuiSliderFlags, ImTextClassifierSetCharClass, ImVec2_AddVA, ImVec2_SubVA, DemoNotPorted, ImFontAtlasBakedAddFontGlyph, ImFontAtlasPackAddRect, ImFontBaked_BuildLoadGlyph, ImGuiInputTextFlags, ShowExampleMenuFile, ExampleTree_CreateNode, ImFontAtlasBuildRenderBitmapFromString, ImFontAtlasFontDestroyOutput, ImFontAtlasFontSourceAddToFont, ImFontAtlasFontSourceInit, ImGuiFocusedFlags, ImGuiTableColumn, stb_textedit_key, stbtt_GetGlyphBitmapBoxSubpixel, IMGUI_PAYLOAD_TYPE_COLOR_4F, IM_FREE, ImDrawListSplitter, ImGuiDragDropFlags, stb_text_locate_coord, stb_text_makeundo_insert, stb_text_makeundo_replace, stb_textedit_find_charpos, stbtt_GetGlyphShape, DemoClamp, DemoItems, DemoWindowLayout, DemoWindowPopups, DemoWindowTables, ExampleTree_CreateDemoTree, IMGUI_PAYLOAD_TYPE_COLOR_3F, ImGuiTableColumnSortSpecs, ImGuiTableInstanceData, ImGuiTableSettings, ShowDockingDisabledMessage, ShowExampleAppMainMenuBar, stb_text_makeundo_delete, stb_text_redo, stb_text_undo, stb_textedit_click, stb_textedit_drag, stbtt_FindGlyphIndex, stbtt_GetFontOffsetForIndex, stbtt_GetFontVMetrics, stbtt_GetGlyphBitmapBox, stbtt_GetGlyphHMetrics, stbtt_InitFont, stbtt_MakeGlyphBitmapSubpixelPrefilter, stbtt_ScaleForPixelHeight, stbtt__GetGlyphInfoT2, stbtt__GetGlyphShapeT2, stbtt_fontinfo, DemoNotSupported, DemoWindowWidgets, DemoWindowWidgetsBasic, DemoWindowWidgetsBullets, DemoWindowWidgetsCollapsingHeaders, DemoWindowWidgetsColorAndPickers, DemoWindowWidgetsComboBoxes, DemoWindowWidgetsDataTypes, ImGuiOldColumnData, ImGuiOldColumnFlags, ImGuiOldColumns, ImGuiTable, ImGuiTableColumnSettings, ImGuiTableSortSpecs, ImGuiTableTempData, ImGui_ImplLOVE_CreateTexture, ImGui_ImplLOVE_DestroyTexture, ImGui_ImplLOVE_Init, ImGui_ImplLOVE_NewFrame, ImGui_ImplLOVE_RenderDrawData, ImGui_ImplLOVE_Shutdown, ImGui_ImplLOVE_UpdateTexture, stbrp_init_target, IMGUI_TABLE_MAX_COLUMNS, IMSTB_TEXTEDIT_UNDOSTATECOUNT, IM_COL32_DISABLE, ImGui_ImplLove, STB_TEXTEDIT_K_BACKSPACE, STB_TEXTEDIT_K_DELETE, STB_TEXTEDIT_K_DOWN, STB_TEXTEDIT_K_LEFT, STB_TEXTEDIT_K_LINEEND, STB_TEXTEDIT_K_LINESTART, STB_TEXTEDIT_K_PGDOWN +local ImGui, ImVec2, ImVec4, ImRect, HelpMarker, ImVec2_Copy, IMGUI_DEMO_MARKER, ImGuiTableFlags, ImStd, ImVector, ImGuiKey, ImGuiInputFlags, ImRect_Copy, ImGuiDataType, ImStb, IM_TRUNC, ImGuiStyleVarInfo, ImVec2_CopyV, IM_ASSERT_USER_ERROR, ImGuiHoveredFlags, ImFormatString, ImHashStr, ImS32, IM_ASSERT_USER_ERROR_RET, ImGuiColorEditFlags, ImDrawFlags, ImIsPowerOfTwo, ImVec4_Copy, ExampleAppConsoleMT, IM_ROUND, ImGuiTableColumnFlags, ImGuiTreeNodeFlags, PopStyleCompact, PushStyleCompact, ImU16, ImAbs, ImGuiWindowFlags, ImGuiItemFlags, stbte, ImGuiButtonFlags, ImGuiDebugLogFlags, ImGuiLocKey, ImU32, ImColor, ImCos, ImS16, ImGuiTabBarFlags, ImSin, ImUpperPowerOfTwo, ImVec2_MulVX, IM_F32_TO_INT8_SAT, ImCeil, ImFontAtlasPackGetRect, ImGuiMouseCursor, DockSettingsRenameNodeReferences, IM_ASSERT_PARANOID, ImGuiCol, ImGuiListClipper, ImLengthSqr, ImS8, ImU8, _PathArcToFastExXY, ExampleAppPropertyEditorMT, ImFabs, ImGuiScrollFlags, ImGui_ImplLOVE_GetBackendData, ImLog, ImPow, CustomConstraints, ExampleAppLogMT, IMGUI_DEBUG_LOG_FONT, ImFontAtlasBuildInit, ImFontCalcWordWrapPositionEx, ImGuiComboFlags, ImGuiPopupFlags, ImGuiSliderFlags, ImTextClassifierSetCharClass, ImVec2_AddVA, ImVec2_SubVA, MyDocument, ShowExampleMenuFile, ImFontAtlasBakedAddFontGlyph, ImFontAtlasPackAddRect, ImFontBaked_BuildLoadGlyph, ImGuiInputTextFlags, ImGuiStyle_Copy, ExampleMemberInfo, ExampleTree_CreateNode, ImFontAtlasBuildRenderBitmapFromString, ImFontAtlasFontDestroyOutput, ImFontAtlasFontSourceAddToFont, ImFontAtlasFontSourceInit, ImGuiTableColumn, MyItem_s_current_sort_specs, stb_textedit_key, stbtt_GetGlyphBitmapBoxSubpixel, EditTableSizingFlags, IMGUI_PAYLOAD_TYPE_COLOR_4F, IM_FREE, ImDrawListSplitter, ImGuiDragDropFlags, MyItemColumnID_ID, MyItemColumnID_Name, MyItemColumnID_Quantity, stb_text_locate_coord, stb_text_makeundo_insert, stb_text_makeundo_replace, stb_textedit_find_charpos, stbtt_GetGlyphShape, EditTabBarFittingPolicyFlags, ImGuiTableColumnSortSpecs, ImGuiTableInstanceData, ImGuiTableSettings, stb_text_makeundo_delete, stb_text_redo, stb_text_undo, stb_textedit_click, stb_textedit_drag, stbtt_FindGlyphIndex, stbtt_GetFontOffsetForIndex, stbtt_GetFontVMetrics, stbtt_GetGlyphBitmapBox, stbtt_GetGlyphHMetrics, stbtt_InitFont, stbtt_MakeGlyphBitmapSubpixelPrefilter, stbtt_ScaleForPixelHeight, stbtt__GetGlyphInfoT2, stbtt__GetGlyphShapeT2, stbtt_fontinfo, ImGuiOldColumnData, ImGuiOldColumnFlags, ImGuiOldColumns, ImGuiTable, ImGuiTableColumnSettings, ImGuiTableSortSpecs, ImGuiTableTempData, ImGui_ImplLOVE_CreateTexture, ImGui_ImplLOVE_DestroyTexture, ImGui_ImplLOVE_Init, ImGui_ImplLOVE_NewFrame, ImGui_ImplLOVE_RenderDrawData, ImGui_ImplLOVE_Shutdown, ImGui_ImplLOVE_UpdateTexture, stbrp_init_target, IMGUI_TABLE_MAX_COLUMNS, IMSTB_TEXTEDIT_UNDOSTATECOUNT, IM_COL32_DISABLE, ImGui_ImplLove, STB_TEXTEDIT_K_BACKSPACE, STB_TEXTEDIT_K_DELETE, STB_TEXTEDIT_K_DOWN, STB_TEXTEDIT_K_LEFT, STB_TEXTEDIT_K_LINEEND, STB_TEXTEDIT_K_LINESTART, STB_TEXTEDIT_K_PGDOWN, STB_TEXTEDIT_K_PGUP, STB_TEXTEDIT_K_REDO, STB_TEXTEDIT_K_RIGHT, STB_TEXTEDIT_K_SHIFT, STB_TEXTEDIT_K_TEXTEND local type, mathMin, mathMax, mathFloor, mathCeil, bitOr, bitLShift = type, math.min, math.max, math.floor, math.ceil, bit32.bor, bit32.lshift local function IM_COL32(R, G, B, A) return (bitOr(bitLShift(A, 24 --[[IM_COL32_A_SHIFT]]), bitLShift(B, 16 --[[IM_COL32_B_SHIFT]]), bitLShift(G, 8 --[[IM_COL32_G_SHIFT]]), bitLShift(R, 0 --[[IM_COL32_R_SHIFT]]))) end @@ -21530,18 +21530,15 @@ end __FILES['imgui_demo.lua'] = function() -- dear imgui demo (Luau port of imgui_demo.cpp). Optional: the library never calls into this file. - -do --[[ imgui_demo.lua ]] -- dear imgui, v1.93.0 WIP --- (demo code) Port of imgui_demo.cpp (docking branch) --- This file: shared demo helpers, ShowDemoWindow(), DemoWindowMenuBar(), DemoWindowWidgets() dispatcher, example tree/image viewer helpers. --- Other parts (all global functions, loaded from the same bundle): +-- (demo code) -- Help: -- - Read FAQ at http://dearimgui.com/faq --- - Call and read ImGui.ShowDemoWindow() in imgui_demo.lua. +-- - Call and read ImGui.ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. -- - Need help integrating Dear ImGui in your codebase? -- - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started +-- - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. -- Read top of imgui.cpp and imgui.h for many details, documentation, comments, links. -- Get the latest version at https://github.com/ocornut/imgui @@ -21559,17 +21556,20 @@ do --[[ imgui_demo.lua ]] -- Also include Metrics! ItemPicker! DebugLog! and other debug features. -- Removing this file from your project is hindering access to documentation for everyone in your team, -- likely leading you to poorer usage of the library. --- Whenever you have Dear ImGui available you probably want this to be available for reference. +-- Everything in this file will be stripped out by the linker if you don't call ImGui.ShowDemoWindow(). +-- If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be +-- linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. +-- [Port] There is no linker here: build the bundle with `tools/bundle.py --no-demo` to leave this file out. +-- In another situation, whenever you have Dear ImGui available you probably want this to be available for reference. -- Thank you, -- -Your beloved friend, imgui_demo.cpp (which you won't delete) ---------------------------------------------- -- ABOUT THE MEANING OF THE 'static' KEYWORD: ---------------------------------------------- --- In the upstream C++ demo code, 'static' variables inside functions are frequently used. +-- In this demo code, we frequently use 'static' variables inside functions. -- A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function. -- Think of "static int n = 0;" as "global int n = 0;" ! --- (PORT: Lua has no function-local statics; this port keeps them as fields of file-level tables, e.g. `S`, `SL`, `ST`.) -- We do this IN THE DEMO because we want: -- - to gather code and data in the same place. -- - to make the demo source code faster to read, faster to change, smaller in size. @@ -21577,79 +21577,150 @@ do --[[ imgui_demo.lua ]] -- doesn't need to be reentrant or used in multiple threads. -- This might be a pattern you will want to use in your code, but most of the data you would be working -- with in a complex codebase is likely going to be stored outside your functions. +-- [Port] Lua has no function-level 'static': they are fields of the file-level table S (S.FunctionName.x). ------------------------------------------- -- ABOUT THE CODING STYLE OF OUR DEMO CODE ------------------------------------------- -- The Demo code in this file is designed to be easy to copy-and-paste into your application! -- Because of this: --- - We never omit the ImGui. prefix when calling functions. +-- - We never omit the ImGui. prefix when calling functions, even though most code here is in the same namespace. +-- - We try to declare static variables in the local scope, as close as possible to the code using them. +-- - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API. +-- - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided +-- by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional +-- and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. +-- Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp. -- Navigating this file: +-- - In Visual Studio: Ctrl+Comma ("Edit.GoToAll") can follow symbols inside comments, whereas Ctrl+F12 ("Edit.GoToImplementation") cannot. +-- - In Visual Studio w/ Visual Assist installed: Alt+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. +-- - In VS Code, CLion, etc.: Ctrl+Click can follow symbols inside comments. -- - You can search/grep for all sections listed in the index to find the section. --- Index of this file: --- --- [SECTION] Helpers --- [SECTION] Demo Window / ShowDemoWindow() --- [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) --- [SECTION] Helpers: ExampleImageViewer --- [SECTION] DemoWindowWidgetsBasic() --- [SECTION] DemoWindowWidgetsBullets() --- [SECTION] DemoWindowWidgetsCollapsingHeaders() --- [SECTION] DemoWindowWidgetsComboBoxes() --- [SECTION] DemoWindowWidgetsColorAndPickers() --- [SECTION] DemoWindowWidgetsDataTypes() --- [SECTION] DemoWindowWidgetsDisableBlocks() --- [SECTION] DemoWindowWidgetsDragAndDrop() --- [SECTION] DemoWindowWidgetsDragsAndSliders() --- [SECTION] DemoWindowWidgetsFonts() --- [SECTION] DemoWindowWidgetsImages() --- [SECTION] DemoWindowWidgetsListBoxes() --- [SECTION] DemoWindowWidgetsLiveEdit() --- [SECTION] DemoWindowWidgetsMixedValues() --- [SECTION] DemoWindowWidgetsMultiComponents() --- [SECTION] DemoWindowWidgetsPlotting() --- [SECTION] DemoWindowWidgetsProgressBars() --- [SECTION] DemoWindowWidgetsQueryingStatuses() --- [SECTION] DemoWindowWidgetsSelectables() --- [SECTION] DemoWindowWidgetsTabs() --- [SECTION] DemoWindowWidgetsText() --- [SECTION] DemoWindowWidgetsTextFilter() --- [SECTION] DemoWindowWidgetsTextInput() --- [SECTION] DemoWindowWidgetsTooltips() --- [SECTION] DemoWindowWidgetsTreeNodes() --- [SECTION] DemoWindowWidgetsVerticalSliders() --- [SECTION] DemoWindowWidgets() --- [SECTION] DemoWindowLayout() --- [SECTION] DemoWindowPopups() --- [SECTION] DemoWindowTables() --- [SECTION] About Window / ShowAboutWindow() --- [SECTION] Style Editor / ShowStyleEditor() --- [SECTION] User Guide / ShowUserGuide() --- [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() --- [SECTION] Example App: Debug Console / ShowExampleAppConsole() --- [SECTION] Example App: Debug Log / ShowExampleAppLog() --- [SECTION] Example App: Simple Layout / ShowExampleAppLayout() --- [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() --- [SECTION] Example App: Long Text / ShowExampleAppLongText() --- [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() --- [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() --- [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() --- [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() --- [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() --- [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() --- [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() --- [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() +--[[ -local _ +Index of this file: + +// [SECTION] Forward Declarations +// [SECTION] Helpers +// [SECTION] Demo Window / ShowDemoWindow() +// [SECTION] DemoWindowMenuBar() +// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) +// [SECTION] Helpers: ExampleImageViewer +// [SECTION] DemoWindowWidgetsBasic() +// [SECTION] DemoWindowWidgetsBullets() +// [SECTION] DemoWindowWidgetsCollapsingHeaders() +// [SECTION] DemoWindowWidgetsComboBoxes() +// [SECTION] DemoWindowWidgetsColorAndPickers() +// [SECTION] DemoWindowWidgetsDataTypes() +// [SECTION] DemoWindowWidgetsDisableBlocks() +// [SECTION] DemoWindowWidgetsDragAndDrop() +// [SECTION] DemoWindowWidgetsDragsAndSliders() +// [SECTION] DemoWindowWidgetsFonts() +// [SECTION] DemoWindowWidgetsImages() +// [SECTION] DemoWindowWidgetsListBoxes() +// [SECTION] DemoWindowWidgetsLiveEdit() +// [SECTION] DemoWindowWidgetsMixedValues() +// [SECTION] DemoWindowWidgetsMultiComponents() +// [SECTION] DemoWindowWidgetsPlotting() +// [SECTION] DemoWindowWidgetsProgressBars() +// [SECTION] DemoWindowWidgetsQueryingStatuses() +// [SECTION] DemoWindowWidgetsSelectables() +// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect() +// [SECTION] DemoWindowWidgetsTabs() +// [SECTION] DemoWindowWidgetsText() +// [SECTION] DemoWindowWidgetsTextFilter() +// [SECTION] DemoWindowWidgetsTextInput() +// [SECTION] DemoWindowWidgetsTooltips() +// [SECTION] DemoWindowWidgetsTreeNodes() +// [SECTION] DemoWindowWidgetsVerticalSliders() +// [SECTION] DemoWindowWidgets() +// [SECTION] DemoWindowLayout() +// [SECTION] DemoWindowPopups() +// [SECTION] DemoWindowTables() +// [SECTION] DemoWindowInputs() +// [SECTION] About Window / ShowAboutWindow() +// [SECTION] Style Editor / ShowStyleEditor() +// [SECTION] User Guide / ShowUserGuide() +// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +// [SECTION] Example App: Debug Console / ShowExampleAppConsole() +// [SECTION] Example App: Image Viewer / ShowExampleAppImageViewer() +// [SECTION] Example App: Debug Log / ShowExampleAppLog() +// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() +// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() +// [SECTION] Example App: Long Text / ShowExampleAppLongText() +// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() +// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() +// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() +// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() +// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser() + +]] + +-- [Port] C includes, compiler warning pragmas, snprintf/PRId64/IMGUI_CDECL defines dropped (C only). + +-- Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) +-- [Port] IM_NEWLINE is always "\n" here. + +-- Helpers macros +-- We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, +-- but making an exception here as those are largely simplifying code... +-- In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. +-- [Port] IM_MIN/IM_MAX/IM_CLAMP -> the library globals ImMin/ImMax/ImClamp. + +------------------------------------------------------------------------------- +-- [SECTION] Forward Declarations +------------------------------------------------------------------------------- + +-- Forward Declarations +-- [Port] Not needed in Lua (globals are resolved at call time). Upstream list kept for reference: +-- struct ImGuiDemoWindowData; +-- static void ShowExampleAppMainMenuBar(); +-- static void ShowExampleAppAssetsBrowser(bool* p_open); +-- static void ShowExampleAppConsole(bool* p_open); +-- static void ShowExampleAppCustomRendering(bool* p_open); +-- static void ShowExampleAppDockSpace(bool* p_open); +-- static void ShowExampleAppDocuments(bool* p_open); +-- static void ShowExampleAppImageViewer(bool* p_open); +-- static void ShowExampleAppLog(bool* p_open); +-- static void ShowExampleAppLayout(bool* p_open); +-- static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data); +-- static void ShowExampleAppSimpleOverlay(bool* p_open); +-- static void ShowExampleAppAutoResize(bool* p_open); +-- static void ShowExampleAppConstrainedResize(bool* p_open); +-- static void ShowExampleAppFullscreen(bool* p_open); +-- static void ShowExampleAppLongText(bool* p_open); +-- static void ShowExampleAppWindowTitles(bool* p_open); +-- static void ShowExampleMenuFile(); + +-- We split the contents of the big ShowDemoWindow() function into smaller functions +-- (because the link time of very large functions tends to grow non-linearly) +-- static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data); +-- static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data); +-- static void DemoWindowLayout(); +-- static void DemoWindowPopups(); +-- static void DemoWindowTables(); +-- static void DemoWindowColumns(); +-- static void DemoWindowInputs(); + +-- Helper tree functions used by Property Editor & Multi-Select demos +-- struct ExampleTreeNode; +-- static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent); +-- static void ExampleTree_DestroyNode(ExampleTreeNode* node); ------------------------------------------------------------------------------- -- [SECTION] Helpers ------------------------------------------------------------------------------- --- Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer) -function IMGUI_DEMO_MARKER(_) end -- upstream hook, no-op here +-- [Port] Storage for C++ function-level `static` variables: one sub-table per upstream function (S.FunctionName), +-- declared right above the function. Shared by every part of this file. +local S = {} +local _ -- [Port] discard target for unused return values (`_, v = ImGui.Checkbox(...)`) -- Helper to display a little (?) mark which shows a tooltip when hovered. -- In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md) @@ -21673,138 +21744,17 @@ function ShowDockingDisabledMessage() end end -function DemoNotSupported() ImGui.TextDisabled("(not supported on Roblox)") end -function DemoNotPorted(what) ImGui.TextDisabled("(not ported yet%s)", what and (": " .. what) or "") end -function DemoB2I(b) return b and 1 or 0 end -function DemoHas(flags, f) return bit32.band(flags, f) ~= 0 end -function DemoClamp(v, mn, mx) return (v < mn) and mn or (v > mx) and mx or v end +-- Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer) +function IMGUI_DEMO_MARKER(section) end -- [Port] no ImGui.DemoMarker() hook in this port: no-op ---- `char buf[size] = "str"` -> zero-terminated byte table -function DemoBuf(str, size) - local t = {} - for i = 1, #str do t[i] = string.byte(str, i) end - t[#str + 1] = 0 - if size then for i = #str + 2, size do t[i] = 0 end end - return t -end ---- byte table -> Lua string (up to the zero terminator) -function DemoBufStr(buf) - local n = 0 - while buf[n + 1] ~= nil and buf[n + 1] ~= 0 do n = n + 1 end - if n == 0 then return "" end - return ImGui._ByteArrayToString(buf, 1, n + 1) -end - ---- "a\0b\0c\0\0" -> { "a", "b", "c" } -function DemoItems(s) - if type(s) == "table" then return s end - local t = {} - for item in string.gmatch(s, "([^%z]+)") do t[#t + 1] = item end - return t -end - ---- Combo() one-liner. `idx` is 0-based; `items` is a table of strings (1-based) or a "\0"-separated string. ---- Uses ImGui.Combo if it exists, falls back to BeginCombo/Selectable. ---- @return int idx, bool changed -function DemoCombo(label, idx, items, popup_max_height_in_items) - items = DemoItems(items) - if ImGui.Combo then - return ImGui.Combo(label, idx, items, #items, popup_max_height_in_items or -1) - end - local changed = false - local preview = (idx >= 0 and idx < #items) and items[idx + 1] or "" - if ImGui.BeginCombo(label, preview) then - for n = 0, #items - 1 do - local is_selected = (idx == n) - if ImGui.Selectable(items[n + 1], is_selected) then - idx = n - changed = true - end - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndCombo() - end - return idx, changed -end - ---- ListBox() one-liner (see DemoCombo) -function DemoListBox(label, idx, items, height_in_items) - items = DemoItems(items) - if ImGui.ListBox then - return ImGui.ListBox(label, idx, items, #items, height_in_items or -1) - end - local changed = false - if height_in_items == nil or height_in_items < 0 then height_in_items = math.min(#items, 7) end - local height_in_items_f = height_in_items + 0.25 - local height_in_pixels = math.floor(ImGui.GetTextLineHeightWithSpacing() * height_in_items_f + ImGui.GetStyle().FramePadding.y * 2.0) - if ImGui.BeginListBox and ImGui.BeginListBox(label, ImVec2(0.0, height_in_pixels)) then - for n = 0, #items - 1 do - local is_selected = (idx == n) - if ImGui.Selectable(items[n + 1], is_selected) then - idx = n - changed = true - end - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndListBox() - elseif not ImGui.BeginListBox then - DemoNotPorted("ListBox") - end - return idx, changed -end - ---- Closable header: CollapsingHeader(label, &p_open). Returns visible, open. -function DemoCollapsingHeaderClosable(label, open) - return ImGui.CollapsingHeader(label, open) -end - ---- ImColor::HSV() as ImVec4 -function DemoHSV(h, s, v, a) - local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v) - return ImVec4(r, g, b, a or 1.0) -end - ---- Minimal ImGuiTextFilter when the library one isn't available (Draw/DrawWithHint/PassFilter/Clear/IsActive) -function DemoTextFilter() - if ImGuiTextFilter then return ImGuiTextFilter() end - local f = { InputBuf = DemoBuf("", 256) } - local function parse(self) - local inc, exc = {}, {} - for tok in string.gmatch(string.lower(DemoBufStr(self.InputBuf)), "[^,%s]+") do - if string.sub(tok, 1, 1) == "-" then - if #tok > 1 then exc[#exc + 1] = string.sub(tok, 2) end - else - inc[#inc + 1] = tok - end - end - return inc, exc - end - function f:Draw(label, width) - if width and width ~= 0 then ImGui.SetNextItemWidth(width) end - return ImGui.InputText(label or "Filter (inc,-exc)", self.InputBuf, 256) - end - function f:DrawWithHint(label, hint, width) - if width and width ~= 0 then ImGui.SetNextItemWidth(width) end - return ImGui.InputTextWithHint(label, hint, self.InputBuf, 256) - end - function f:Clear() self.InputBuf[1] = 0 end - function f:IsActive() return self.InputBuf[1] ~= 0 and self.InputBuf[1] ~= nil end - function f:PassFilter(text) - local inc, exc = parse(self) - text = string.lower(text) - for _, e in ipairs(exc) do if string.find(text, e, 1, true) then return false end end - if #inc == 0 then return true end - for _, i in ipairs(inc) do if string.find(text, i, 1, true) then return true end end - return false - end - return f -end +-- Sneakily forward declare functions which aren't worth putting in public API yet +-- [Port] ImGui.ShowFontAtlas(atlas) and ImGui.TreeNodeSetOpen(storage_id, is_open) are already public here. ------------------------------------------------------------------------------- --- [SECTION] Demo Window data +-- [SECTION] Demo Window / ShowDemoWindow() ------------------------------------------------------------------------------- ---- Data to be shared across different functions of the demo. +-- Data to be shared across different functions of the demo. function ImGuiDemoWindowData() return { -- Examples Apps (accessible from the "Examples" menu) @@ -21835,11 +21785,466 @@ function ImGuiDemoWindowData() -- Other data DisableSections = false, LiveEditOverride = false, - LiveEditFlags = 128 --[[ImGuiItemFlags.LiveEditOnInputText]] or 0, + LiveEditFlags = 128 --[[ImGuiItemFlags.LiveEditOnInputText]], DemoTree = nil, + + -- [Port] no destructor: DemoTree is garbage collected (upstream calls ExampleTree_DestroyNode(DemoTree)). } end +S.ShowDemoWindow = { + -- Stored data + demo_data = ImGuiDemoWindowData(), + + -- Demonstrate the various window flags. Typically you would just use the default! + no_titlebar = false, + no_scrollbar = false, + no_menu = false, + no_move = false, + no_resize = false, + no_collapse = false, + no_close = false, + no_nav = false, + no_background = false, + no_bring_to_front = false, + no_docking = false, + unsaved_document = false, +} + +-- Demonstrate most Dear ImGui features (this is big function!) +-- You may execute this function to experiment with the UI and understand what it does. +-- You may then search for keywords in the code when you are interested by a specific feature. +-- [Port] p_open: true/false/nil (nil = no close button). Returns the new p_open value. +function ImGui.ShowDemoWindow(p_open) + local s = S.ShowDemoWindow + + -- Exceptionally add an extra assert here for people confused about initial Dear ImGui setup + -- Most functions would normally just assert/crash if the context is missing. + assert(ImGui.GetCurrentContext() ~= nil, "Missing Dear ImGui context. Refer to examples app!") + + -- Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues. + -- [Port] IMGUI_CHECKVERSION() dropped: no ABI to verify. + + -- Stored data + local demo_data = s.demo_data + + -- Examples Apps (accessible from the "Examples" menu) + if demo_data.ShowMainMenuBar then ShowExampleAppMainMenuBar() end + if demo_data.ShowAppDockSpace then demo_data.ShowAppDockSpace = ShowExampleAppDockSpace(demo_data.ShowAppDockSpace) end -- Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) + if demo_data.ShowAppDocuments then demo_data.ShowAppDocuments = ShowExampleAppDocuments(demo_data.ShowAppDocuments) end -- ...process the Document app next, as it may also use a DockSpace() + if demo_data.ShowAppAssetsBrowser then demo_data.ShowAppAssetsBrowser = ShowExampleAppAssetsBrowser(demo_data.ShowAppAssetsBrowser) end + if demo_data.ShowAppConsole then demo_data.ShowAppConsole = ShowExampleAppConsole(demo_data.ShowAppConsole) end + if demo_data.ShowAppCustomRendering then demo_data.ShowAppCustomRendering = ShowExampleAppCustomRendering(demo_data.ShowAppCustomRendering) end + if demo_data.ShowAppImageViewer then demo_data.ShowAppImageViewer = ShowExampleAppImageViewer(demo_data.ShowAppImageViewer) end + if demo_data.ShowAppLog then demo_data.ShowAppLog = ShowExampleAppLog(demo_data.ShowAppLog) end + if demo_data.ShowAppLayout then demo_data.ShowAppLayout = ShowExampleAppLayout(demo_data.ShowAppLayout) end + if demo_data.ShowAppPropertyEditor then demo_data.ShowAppPropertyEditor = ShowExampleAppPropertyEditor(demo_data.ShowAppPropertyEditor, demo_data) end + if demo_data.ShowAppSimpleOverlay then demo_data.ShowAppSimpleOverlay = ShowExampleAppSimpleOverlay(demo_data.ShowAppSimpleOverlay) end + if demo_data.ShowAppAutoResize then demo_data.ShowAppAutoResize = ShowExampleAppAutoResize(demo_data.ShowAppAutoResize) end + if demo_data.ShowAppConstrainedResize then demo_data.ShowAppConstrainedResize = ShowExampleAppConstrainedResize(demo_data.ShowAppConstrainedResize) end + if demo_data.ShowAppFullscreen then demo_data.ShowAppFullscreen = ShowExampleAppFullscreen(demo_data.ShowAppFullscreen) end + if demo_data.ShowAppLongText then demo_data.ShowAppLongText = ShowExampleAppLongText(demo_data.ShowAppLongText) end + if demo_data.ShowAppWindowTitles then demo_data.ShowAppWindowTitles = ShowExampleAppWindowTitles(demo_data.ShowAppWindowTitles) end + + -- Dear ImGui Tools (accessible from the "Tools" menu) + if demo_data.ShowMetrics then demo_data.ShowMetrics = ImGui.ShowMetricsWindow(demo_data.ShowMetrics) end + if demo_data.ShowDebugLog then demo_data.ShowDebugLog = ImGui.ShowDebugLogWindow(demo_data.ShowDebugLog) end + if demo_data.ShowIDStackTool then demo_data.ShowIDStackTool = ImGui.ShowIDStackToolWindow(demo_data.ShowIDStackTool) end + if demo_data.ShowAbout then demo_data.ShowAbout = ImGui.ShowAboutWindow(demo_data.ShowAbout) end + if demo_data.ShowStyleEditor then + demo_data.ShowStyleEditor = ImGui.Begin("Dear ImGui Style Editor", demo_data.ShowStyleEditor) + ImGui.ShowStyleEditor() + ImGui.End() + end + + -- Demonstrate the various window flags. Typically you would just use the default! + local window_flags = 0 + if s.no_titlebar then window_flags = bit32.bor(window_flags, 1 --[[ImGuiWindowFlags.NoTitleBar]]) end + if s.no_scrollbar then window_flags = bit32.bor(window_flags, 8 --[[ImGuiWindowFlags.NoScrollbar]]) end + if not s.no_menu then window_flags = bit32.bor(window_flags, 1024 --[[ImGuiWindowFlags.MenuBar]]) end + if s.no_move then window_flags = bit32.bor(window_flags, 4 --[[ImGuiWindowFlags.NoMove]]) end + if s.no_resize then window_flags = bit32.bor(window_flags, 2 --[[ImGuiWindowFlags.NoResize]]) end + if s.no_collapse then window_flags = bit32.bor(window_flags, 32 --[[ImGuiWindowFlags.NoCollapse]]) end + if s.no_nav then window_flags = bit32.bor(window_flags, 196608 --[[ImGuiWindowFlags.NoNav]]) end + if s.no_background then window_flags = bit32.bor(window_flags, 128 --[[ImGuiWindowFlags.NoBackground]]) end + if s.no_bring_to_front then window_flags = bit32.bor(window_flags, 8192 --[[ImGuiWindowFlags.NoBringToFrontOnFocus]]) end + if s.no_docking then window_flags = bit32.bor(window_flags, 524288 --[[ImGuiWindowFlags.NoDocking]]) end + if s.unsaved_document then window_flags = bit32.bor(window_flags, 262144 --[[ImGuiWindowFlags.UnsavedDocument]]) end + local begin_p_open = p_open -- [Port] keep the caller's value intact when not passed to Begin() + if s.no_close then begin_p_open = nil end -- Don't pass our bool* to Begin + + -- We specify a default position/size in case there's no data in the .ini file. + -- We only do it to make the demo applications a little more welcoming, but typically this isn't required. + local main_viewport = ImGui.GetMainViewport() + ImGui.SetNextWindowPos(ImVec2(main_viewport.WorkPos.x + 650, main_viewport.WorkPos.y + 20), 4 --[[ImGuiCond.FirstUseEver]]) + ImGui.SetNextWindowSize(ImVec2(550, 680), 4 --[[ImGuiCond.FirstUseEver]]) + + -- Main body of the Demo window starts here. + local open, visible = ImGui.Begin("Dear ImGui Demo", begin_p_open, window_flags) + if begin_p_open ~= nil then p_open = open end -- [Port] write back the bool* output + if not visible then + -- Early out if the window is collapsed, as an optimization. + ImGui.End() + return p_open + end + + -- Most framed widgets share a common width settings. Remaining width is used for the label. + -- The width of the frame may be changed with PushItemWidth() or SetNextItemWidth(). + -- - Positive value for absolute size, negative value for right-alignment. + -- - The default value is about GetWindowWidth() * 0.65f. + -- - See 'Demo->Layout->Widgets Width' for details. + -- Here we change the frame width based on how much width we want to give to the label. + local label_width_base = ImGui.GetFontSize() * 12 -- Some amount of width for label, based on font size. + local label_width_max = ImGui.GetContentRegionAvail().x * 0.40 -- ...but always leave some room for framed widgets. + local label_width = ImMin(label_width_base, label_width_max) + ImGui.PushItemWidth(-label_width) -- Right-align: framed items will leave 'label_width' available for the label. + --ImGui.PushItemWidth(ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for framed widgets, leaving 60% width for labels. + --ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for labels, leaving 60% width for framed widgets. + --ImGui.PushItemWidth(ImGui.GetFontSize() * -12) -- e.g. Use XXX width for labels, leaving the rest for framed widgets. + + -- Menu Bar + DemoWindowMenuBar(demo_data) + + ImGui.Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, 19298 --[[IMGUI_VERSION_NUM]]) + ImGui.Spacing() + + if ImGui.CollapsingHeader("Help") then + IMGUI_DEMO_MARKER("Help") + ImGui.SeparatorText("ABOUT THIS DEMO:") + ImGui.BulletText("Sections below are demonstrating many aspects of the library.") + ImGui.BulletText("The \"Examples\" menu above leads to more demo contents.") + ImGui.BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" .. + "and Metrics/Debugger (general purpose Dear ImGui debugging tool).") + ImGui.BulletText("Web demo (w/ source code browser): ") + ImGui.SameLine(0, 0) + ImGui.TextLinkOpenURL("https://pthom.github.io/imgui_explorer") + + ImGui.SeparatorText("PROGRAMMER GUIDE:") + ImGui.BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!") + ImGui.BulletText("See comments in imgui.cpp.") + ImGui.BulletText("See example applications in the examples/ folder.") + ImGui.BulletText("Read the FAQ at ") + ImGui.SameLine(0, 0) + ImGui.TextLinkOpenURL("https://www.dearimgui.com/faq/") + ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.") + ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.") + + ImGui.SeparatorText("USER GUIDE:") + ImGui.ShowUserGuide() + end + + if ImGui.CollapsingHeader("Configuration") then + local io = ImGui.GetIO() + + if ImGui.TreeNode("Configuration##2") then + IMGUI_DEMO_MARKER("Configuration") + ImGui.SeparatorText("General") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", io.ConfigFlags, 1 --[[ImGuiConfigFlags.NavEnableKeyboard]]) + ImGui.SameLine(); HelpMarker("Enable keyboard controls.") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NavEnableGamepad", io.ConfigFlags, 2 --[[ImGuiConfigFlags.NavEnableGamepad]]) + ImGui.SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NoMouse", io.ConfigFlags, 16 --[[ImGuiConfigFlags.NoMouse]]) + ImGui.SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.") + + -- The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: + if bit32.band(io.ConfigFlags, 16 --[[ImGuiConfigFlags.NoMouse]]) ~= 0 then + if math.fmod(ImGui.GetTime(), 0.40) < 0.20 then + ImGui.SameLine() + ImGui.Text("<>") + end + -- Prevent both being checked + if ImGui.IsKeyPressed(524 --[[ImGuiKey.Space]]) or bit32.band(io.ConfigFlags, 64 --[[ImGuiConfigFlags.NoKeyboard]]) ~= 0 then + io.ConfigFlags = bit32.band(io.ConfigFlags, bit32.bnot(16 --[[ImGuiConfigFlags.NoMouse]])) + end + end + + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", io.ConfigFlags, 32 --[[ImGuiConfigFlags.NoMouseCursorChange]]) + ImGui.SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NoKeyboard", io.ConfigFlags, 64 --[[ImGuiConfigFlags.NoKeyboard]]) + ImGui.SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.") + + _, io.ConfigInputTrickleEventQueue = ImGui.Checkbox("io.ConfigInputTrickleEventQueue", io.ConfigInputTrickleEventQueue) + ImGui.SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.") + _, io.MouseDrawCursor = ImGui.Checkbox("io.MouseDrawCursor", io.MouseDrawCursor) + ImGui.SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).") + + ImGui.SeparatorText("Keyboard/Gamepad Navigation") + _, io.ConfigNavSwapGamepadButtons = ImGui.Checkbox("io.ConfigNavSwapGamepadButtons", io.ConfigNavSwapGamepadButtons) + _, io.ConfigNavMoveSetMousePos = ImGui.Checkbox("io.ConfigNavMoveSetMousePos", io.ConfigNavMoveSetMousePos) + ImGui.SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult") + _, io.ConfigNavCaptureKeyboard = ImGui.Checkbox("io.ConfigNavCaptureKeyboard", io.ConfigNavCaptureKeyboard) + _, io.ConfigNavEscapeClearFocusItem = ImGui.Checkbox("io.ConfigNavEscapeClearFocusItem", io.ConfigNavEscapeClearFocusItem) + ImGui.SameLine(); HelpMarker("Pressing Escape clears focused item.") + _, io.ConfigNavEscapeClearFocusWindow = ImGui.Checkbox("io.ConfigNavEscapeClearFocusWindow", io.ConfigNavEscapeClearFocusWindow) + ImGui.SameLine(); HelpMarker("Pressing Escape clears focused window.") + _, io.ConfigNavCursorVisibleAuto = ImGui.Checkbox("io.ConfigNavCursorVisibleAuto", io.ConfigNavCursorVisibleAuto) + ImGui.SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.") + _, io.ConfigNavCursorVisibleAlways = ImGui.Checkbox("io.ConfigNavCursorVisibleAlways", io.ConfigNavCursorVisibleAlways) + ImGui.SameLine(); HelpMarker("Navigation cursor is always visible.") + + ImGui.SeparatorText("Docking") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: DockingEnable", io.ConfigFlags, 128 --[[ImGuiConfigFlags.DockingEnable]]) + ImGui.SameLine() + if io.ConfigDockingWithShift then + HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") + else + HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") + end + if bit32.band(io.ConfigFlags, 128 --[[ImGuiConfigFlags.DockingEnable]]) ~= 0 then + ImGui.Indent() + _, io.ConfigDockingNoSplit = ImGui.Checkbox("io.ConfigDockingNoSplit", io.ConfigDockingNoSplit) + ImGui.SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.") + _, io.ConfigDockingNoDockingOver = ImGui.Checkbox("io.ConfigDockingNoDockingOver", io.ConfigDockingNoDockingOver) + ImGui.SameLine(); HelpMarker("Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows.") + _, io.ConfigDockingWithShift = ImGui.Checkbox("io.ConfigDockingWithShift", io.ConfigDockingWithShift) + ImGui.SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)") + _, io.ConfigDockingAlwaysTabBar = ImGui.Checkbox("io.ConfigDockingAlwaysTabBar", io.ConfigDockingAlwaysTabBar) + ImGui.SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.") + _, io.ConfigDockingTransparentPayload = ImGui.Checkbox("io.ConfigDockingTransparentPayload", io.ConfigDockingTransparentPayload) + ImGui.SameLine(); HelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.") + ImGui.Unindent() + end + + ImGui.SeparatorText("Multi-viewports") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: ViewportsEnable", io.ConfigFlags, 1024 --[[ImGuiConfigFlags.ViewportsEnable]]) + ImGui.SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.") + if bit32.band(io.ConfigFlags, 1024 --[[ImGuiConfigFlags.ViewportsEnable]]) ~= 0 then + ImGui.Indent() + _, io.ConfigViewportsNoAutoMerge = ImGui.Checkbox("io.ConfigViewportsNoAutoMerge", io.ConfigViewportsNoAutoMerge) + ImGui.SameLine(); HelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.") + _, io.ConfigViewportsNoTaskBarIcon = ImGui.Checkbox("io.ConfigViewportsNoTaskBarIcon", io.ConfigViewportsNoTaskBarIcon) + ImGui.SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)") + _, io.ConfigViewportsNoDecoration = ImGui.Checkbox("io.ConfigViewportsNoDecoration", io.ConfigViewportsNoDecoration) + ImGui.SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)") + _, io.ConfigViewportsNoDefaultParent = ImGui.Checkbox("io.ConfigViewportsNoDefaultParent", io.ConfigViewportsNoDefaultParent) + ImGui.SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)") + _, io.ConfigViewportsPlatformFocusSetsImGuiFocus = ImGui.Checkbox("io.ConfigViewportsPlatformFocusSetsImGuiFocus", io.ConfigViewportsPlatformFocusSetsImGuiFocus) + ImGui.SameLine(); HelpMarker("When a platform window is focused (e.g. using Alt+Tab, clicking Platform Title Bar), apply corresponding focus on imgui windows (may clear focus/active id from imgui windows location in other platform windows). In principle this is better enabled but we provide an opt-out, because some Linux window managers tend to eagerly focus windows (e.g. on mouse hover, or even a simple window pos/size change).") + ImGui.Unindent() + end + + --ImGui.SeparatorText("DPI/Scaling") + --_, io.ConfigDpiScaleFonts = ImGui.Checkbox("io.ConfigDpiScaleFonts", io.ConfigDpiScaleFonts) + --ImGui.SameLine(); HelpMarker("Experimental: Automatically update style.FontScaleDpi when Monitor DPI changes. This will scale fonts but NOT style sizes/padding for now.") + --_, io.ConfigDpiScaleViewports = ImGui.Checkbox("io.ConfigDpiScaleViewports", io.ConfigDpiScaleViewports) + --ImGui.SameLine(); HelpMarker("Experimental: Scale Dear ImGui and Platform Windows when Monitor DPI changes.") + + ImGui.SeparatorText("Windows") + _, io.ConfigWindowsResizeFromEdges = ImGui.Checkbox("io.ConfigWindowsResizeFromEdges", io.ConfigWindowsResizeFromEdges) + ImGui.SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.") + _, io.ConfigWindowsMoveFromTitleBarOnly = ImGui.Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", io.ConfigWindowsMoveFromTitleBarOnly) + _, io.ConfigWindowsCopyContentsWithCtrlC = ImGui.Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", io.ConfigWindowsCopyContentsWithCtrlC) -- [EXPERIMENTAL] + ImGui.SameLine(); HelpMarker("*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.") + _, io.ConfigScrollbarScrollByPage = ImGui.Checkbox("io.ConfigScrollbarScrollByPage", io.ConfigScrollbarScrollByPage) + ImGui.SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.") + + ImGui.SeparatorText("Widgets") + _, io.ConfigInputTextCursorBlink = ImGui.Checkbox("io.ConfigInputTextCursorBlink", io.ConfigInputTextCursorBlink) + ImGui.SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).") + _, io.ConfigInputTextEnterKeepActive = ImGui.Checkbox("io.ConfigInputTextEnterKeepActive", io.ConfigInputTextEnterKeepActive) + ImGui.SameLine(); HelpMarker("Pressing Enter will reactivate item and select all text (single-line only).") + _, io.ConfigDragClickToInputText = ImGui.Checkbox("io.ConfigDragClickToInputText", io.ConfigDragClickToInputText) + ImGui.SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).") + _, io.ConfigMacOSXBehaviors = ImGui.Checkbox("io.ConfigMacOSXBehaviors", io.ConfigMacOSXBehaviors) + ImGui.SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.") + ImGui.Text("Also see Style->Rendering for rendering options.") + + ImGui.SeparatorText("Settings") + _, io.ConfigIniSettingsSaveLastUsedDate = ImGui.Checkbox("io.ConfigIniSettingsSaveLastUsedDate", io.ConfigIniSettingsSaveLastUsedDate) + + -- Also read: https://github.com/ocornut/imgui/wiki/Error-Handling + ImGui.SeparatorText("Error Handling") + + _, io.ConfigErrorRecovery = ImGui.Checkbox("io.ConfigErrorRecovery", io.ConfigErrorRecovery) + ImGui.SameLine(); HelpMarker( + "Options to configure how we handle recoverable errors.\n" .. + "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n" .. + "- You not are not supposed to rely on it in the course of a normal application run.\n" .. + "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n" .. + "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call! " .. + "Otherwise it would severely hinder your ability to catch and correct mistakes!") + _, io.ConfigErrorRecoveryEnableAssert = ImGui.Checkbox("io.ConfigErrorRecoveryEnableAssert", io.ConfigErrorRecoveryEnableAssert) + _, io.ConfigErrorRecoveryEnableDebugLog = ImGui.Checkbox("io.ConfigErrorRecoveryEnableDebugLog", io.ConfigErrorRecoveryEnableDebugLog) + _, io.ConfigErrorRecoveryEnableTooltip = ImGui.Checkbox("io.ConfigErrorRecoveryEnableTooltip", io.ConfigErrorRecoveryEnableTooltip) + if not io.ConfigErrorRecoveryEnableAssert and not io.ConfigErrorRecoveryEnableDebugLog and not io.ConfigErrorRecoveryEnableTooltip then + io.ConfigErrorRecoveryEnableAssert = true; io.ConfigErrorRecoveryEnableDebugLog = true; io.ConfigErrorRecoveryEnableTooltip = true + end + + -- Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools + ImGui.SeparatorText("Debug") + _, io.ConfigDebugIsDebuggerPresent = ImGui.Checkbox("io.ConfigDebugIsDebuggerPresent", io.ConfigDebugIsDebuggerPresent) + ImGui.SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.") + _, io.ConfigDebugHighlightIdConflicts = ImGui.Checkbox("io.ConfigDebugHighlightIdConflicts", io.ConfigDebugHighlightIdConflicts) + ImGui.SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.") + ImGui.BeginDisabled() + _, io.ConfigDebugBeginReturnValueOnce = ImGui.Checkbox("io.ConfigDebugBeginReturnValueOnce", io.ConfigDebugBeginReturnValueOnce) + ImGui.EndDisabled() + ImGui.SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.") + _, io.ConfigDebugBeginReturnValueLoop = ImGui.Checkbox("io.ConfigDebugBeginReturnValueLoop", io.ConfigDebugBeginReturnValueLoop) + ImGui.SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.") + _, io.ConfigDebugIgnoreFocusLoss = ImGui.Checkbox("io.ConfigDebugIgnoreFocusLoss", io.ConfigDebugIgnoreFocusLoss) + ImGui.SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.") + _, io.ConfigDebugDrawListDefaultsToStrokeLegacy = ImGui.Checkbox("io.ConfigDebugDrawListDefaultsToStrokeLegacy", io.ConfigDebugDrawListDefaultsToStrokeLegacy) + ImGui.SameLine(); HelpMarker("Option to default all ImDrawList to ImDrawFlags_StrokeLegacy mode, mimicking pre-1.93.0 rendering.") + _, io.ConfigDebugIniSettings = ImGui.Checkbox("io.ConfigDebugIniSettings", io.ConfigDebugIniSettings) + ImGui.SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).") + + ImGui.TreePop() + ImGui.Spacing() + end + + if ImGui.TreeNode("Backend Flags") then + IMGUI_DEMO_MARKER("Configuration/Backend Flags") + HelpMarker( + "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" .. + "Here we expose them as read-only fields to avoid breaking interactions with your backend.") + + -- Make a local copy to avoid modifying actual backend flags. + -- FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright? + ImGui.BeginDisabled() + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasGamepad", io.BackendFlags, 1 --[[ImGuiBackendFlags.HasGamepad]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseCursors", io.BackendFlags, 2 --[[ImGuiBackendFlags.HasMouseCursors]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasSetMousePos", io.BackendFlags, 4 --[[ImGuiBackendFlags.HasSetMousePos]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: PlatformHasViewports", io.BackendFlags, 2048 --[[ImGuiBackendFlags.PlatformHasViewports]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",io.BackendFlags, 4096 --[[ImGuiBackendFlags.HasMouseHoveredViewport]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasParentViewport", io.BackendFlags, 8192 --[[ImGuiBackendFlags.HasParentViewport]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", io.BackendFlags, 8 --[[ImGuiBackendFlags.RendererHasVtxOffset]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasTextures", io.BackendFlags, 16 --[[ImGuiBackendFlags.RendererHasTextures]]) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasViewports", io.BackendFlags, 1024 --[[ImGuiBackendFlags.RendererHasViewports]]) + ImGui.EndDisabled() + + ImGui.TreePop() + ImGui.Spacing() + end + + if ImGui.TreeNode("Style, Fonts") then + IMGUI_DEMO_MARKER("Configuration/Style, Fonts") + _, demo_data.ShowStyleEditor = ImGui.Checkbox("Style Editor", demo_data.ShowStyleEditor) + ImGui.SameLine() + HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.") + ImGui.TreePop() + ImGui.Spacing() + end + + if ImGui.TreeNode("Capture/Logging") then + IMGUI_DEMO_MARKER("Configuration/Capture, Logging") + HelpMarker( + "The logging API redirects all text output so you can easily capture the content of " .. + "a window or a block. Tree nodes can be automatically expanded.\n" .. + "Try opening any of the contents below in this window and then click one of the \"Log To\" button.") + ImGui.LogButtons() + + HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.") + if ImGui.Button("Copy \"Hello, world!\" to clipboard") then + ImGui.LogToClipboard() + ImGui.LogText("Hello, world!") + ImGui.LogFinish() + end + ImGui.TreePop() + end + end + + if ImGui.CollapsingHeader("Window options") then + IMGUI_DEMO_MARKER("Window options") + if ImGui.BeginTable("split", 3) then + ImGui.TableNextColumn(); _, s.no_titlebar = ImGui.Checkbox("No titlebar", s.no_titlebar) + ImGui.TableNextColumn(); _, s.no_scrollbar = ImGui.Checkbox("No scrollbar", s.no_scrollbar) + ImGui.TableNextColumn(); _, s.no_menu = ImGui.Checkbox("No menu", s.no_menu) + ImGui.TableNextColumn(); _, s.no_move = ImGui.Checkbox("No move", s.no_move) + ImGui.TableNextColumn(); _, s.no_resize = ImGui.Checkbox("No resize", s.no_resize) + ImGui.TableNextColumn(); _, s.no_collapse = ImGui.Checkbox("No collapse", s.no_collapse) + ImGui.TableNextColumn(); _, s.no_close = ImGui.Checkbox("No close", s.no_close) + ImGui.TableNextColumn(); _, s.no_nav = ImGui.Checkbox("No nav", s.no_nav) + ImGui.TableNextColumn(); _, s.no_background = ImGui.Checkbox("No background", s.no_background) + ImGui.TableNextColumn(); _, s.no_bring_to_front = ImGui.Checkbox("No bring to front", s.no_bring_to_front) + ImGui.TableNextColumn(); _, s.no_docking = ImGui.Checkbox("No docking", s.no_docking) + ImGui.TableNextColumn(); _, s.unsaved_document = ImGui.Checkbox("Unsaved document", s.unsaved_document) + ImGui.EndTable() + end + end + + -- All demo contents + DemoWindowWidgets(demo_data) + DemoWindowLayout() + DemoWindowPopups() + DemoWindowTables() + DemoWindowInputs() + + -- End of ShowDemoWindow() + ImGui.PopItemWidth() + ImGui.End() + return p_open +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowMenuBar() +------------------------------------------------------------------------------- + +function DemoWindowMenuBar(demo_data) + if ImGui.BeginMenuBar() then + if ImGui.BeginMenu("Menu") then + IMGUI_DEMO_MARKER("Menu/File") + ShowExampleMenuFile() + ImGui.EndMenu() + end + if ImGui.BeginMenu("Examples") then + IMGUI_DEMO_MARKER("Menu/Examples") + _, demo_data.ShowMainMenuBar = ImGui.MenuItem("Main menu bar", nil, demo_data.ShowMainMenuBar) + + ImGui.SeparatorText("Mini apps") + _, demo_data.ShowAppAssetsBrowser = ImGui.MenuItem("Assets Browser", nil, demo_data.ShowAppAssetsBrowser) + _, demo_data.ShowAppConsole = ImGui.MenuItem("Console", nil, demo_data.ShowAppConsole) + _, demo_data.ShowAppCustomRendering = ImGui.MenuItem("Custom rendering", nil, demo_data.ShowAppCustomRendering) + _, demo_data.ShowAppDocuments = ImGui.MenuItem("Documents", nil, demo_data.ShowAppDocuments) + _, demo_data.ShowAppDockSpace = ImGui.MenuItem("Dockspace", nil, demo_data.ShowAppDockSpace) + _, demo_data.ShowAppImageViewer = ImGui.MenuItem("Image Viewer", nil, demo_data.ShowAppImageViewer) + _, demo_data.ShowAppLog = ImGui.MenuItem("Log", nil, demo_data.ShowAppLog) + _, demo_data.ShowAppPropertyEditor = ImGui.MenuItem("Property editor", nil, demo_data.ShowAppPropertyEditor) + _, demo_data.ShowAppLayout = ImGui.MenuItem("Simple layout", nil, demo_data.ShowAppLayout) + _, demo_data.ShowAppSimpleOverlay = ImGui.MenuItem("Simple overlay", nil, demo_data.ShowAppSimpleOverlay) + + ImGui.SeparatorText("Concepts") + _, demo_data.ShowAppAutoResize = ImGui.MenuItem("Auto-resizing window", nil, demo_data.ShowAppAutoResize) + _, demo_data.ShowAppConstrainedResize = ImGui.MenuItem("Constrained-resizing window", nil, demo_data.ShowAppConstrainedResize) + _, demo_data.ShowAppFullscreen = ImGui.MenuItem("Fullscreen window", nil, demo_data.ShowAppFullscreen) + _, demo_data.ShowAppLongText = ImGui.MenuItem("Long text display", nil, demo_data.ShowAppLongText) + _, demo_data.ShowAppWindowTitles = ImGui.MenuItem("Manipulating window titles", nil, demo_data.ShowAppWindowTitles) + + ImGui.EndMenu() + end + --if ImGui.MenuItem("MenuItem") then end -- You can also use MenuItem() inside a menu bar! + if ImGui.BeginMenu("Tools") then + IMGUI_DEMO_MARKER("Menu/Tools") + local io = ImGui.GetIO() + local has_debug_tools = true -- [Port] IMGUI_DISABLE_DEBUG_TOOLS is never defined here + _, demo_data.ShowMetrics = ImGui.MenuItem("Metrics/Debugger", nil, demo_data.ShowMetrics, has_debug_tools) + if ImGui.BeginMenu("Debug Options") then + ImGui.BeginDisabled(not has_debug_tools) + _, io.ConfigDebugHighlightIdConflicts = ImGui.Checkbox("Highlight ID Conflicts", io.ConfigDebugHighlightIdConflicts) + ImGui.EndDisabled() + _, io.ConfigErrorRecoveryEnableAssert = ImGui.Checkbox("Assert on error recovery", io.ConfigErrorRecoveryEnableAssert) + ImGui.TextDisabled("(see Demo->Configuration for more)") + ImGui.EndMenu() + end + _, demo_data.ShowDebugLog = ImGui.MenuItem("Debug Log", nil, demo_data.ShowDebugLog, has_debug_tools) + _, demo_data.ShowIDStackTool = ImGui.MenuItem("ID Stack Tool", nil, demo_data.ShowIDStackTool, has_debug_tools) + local is_debugger_present = io.ConfigDebugIsDebuggerPresent + local has_item_picker = ImGui.DebugStartItemPicker ~= nil -- [Port] ImGui.DebugStartItemPicker() is not ported yet: menu item disabled until it is + if ImGui.MenuItem("Item Picker", nil, false, has_debug_tools and has_item_picker) then -- and is_debugger_present + ImGui.DebugStartItemPicker() + end + if not is_debugger_present then + ImGui.SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application.") + end + _, demo_data.ShowStyleEditor = ImGui.MenuItem("Style Editor", nil, demo_data.ShowStyleEditor) + _, demo_data.ShowAbout = ImGui.MenuItem("About Dear ImGui", nil, demo_data.ShowAbout) + + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end +end + ------------------------------------------------------------------------------- -- [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) ------------------------------------------------------------------------------- @@ -21849,23 +22254,43 @@ end function ExampleTreeNode() return { -- Tree structure - Name = "", + Name = "", -- [Port] Lua string (upstream char Name[28]), max 27 bytes UID = 0, Parent = nil, - Childs = {}, -- 1-based - IndexInParent = 0, -- 0-based. Maintaining this allows us to implement linear traversal more easily + Childs = {}, -- [Port] plain 1-based Lua array (upstream ImVector): #Childs, Childs[n + 1] + IndexInParent = 0, -- Maintaining this allows us to implement linear traversal more easily (0-based) -- Leaf Data - HasData = false, -- All leaves have data + HasData = false, -- All leaves have data DataMyBool = true, DataMyInt = 128, DataMyVec2 = ImVec2(0.0, 3.141592), } end +-- Simple representation of struct metadata/serialization data. +-- (this is a minimal version of what a typical advanced application may provide) +function ExampleMemberInfo(name, data_type, data_count, offset) + return { + Name = name, -- Member name + DataType = data_type, -- Member type + DataCount = data_count, -- Member count (1 when scalar) + Offset = offset, -- Offset inside parent structure -- [Port] field key in the node table (no offsetof) + } +end + +-- Metadata description of ExampleTreeNode struct. +ExampleTreeNodeMemberInfos = +{ + ExampleMemberInfo("MyName", ImGuiDataType.String, 1, "Name"), + ExampleMemberInfo("MyBool", ImGuiDataType.Bool, 1, "DataMyBool"), + ExampleMemberInfo("MyInt", ImGuiDataType.S32, 1, "DataMyInt"), + ExampleMemberInfo("MyVec2", ImGuiDataType.Float, 2, "DataMyVec2"), +} + function ExampleTree_CreateNode(name, uid, parent) local node = ExampleTreeNode() - node.Name = string.sub(name, 1, 27) + node.Name = string.sub(name, 1, 27) -- [Port] snprintf() into char[28] node.UID = uid node.Parent = parent node.IndexInParent = parent and #parent.Childs or 0 @@ -21875,34 +22300,49 @@ function ExampleTree_CreateNode(name, uid, parent) return node end -function ExampleTree_DestroyNode(node) end -- GC +function ExampleTree_DestroyNode(node) + for _, child_node in ipairs(node.Childs) do + ExampleTree_DestroyNode(child_node) + end + -- [Port] IM_DELETE(node): nothing to do, garbage collected +end + +S.ExampleTree_CreateDemoTree = { + category_names = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" }, +} -- Create example tree data -- (warning: this can allocates MANY MANY more times than other code in all of Dear ImGui + demo combined) -- (a real application managing one million nodes would likely store its tree data differently) function ExampleTree_CreateDemoTree() + local s = S.ExampleTree_CreateDemoTree + -- 20 root nodes -> 211 total nodes, ~261 allocs. -- 1000 root nodes -> ~11K total nodes, ~14K allocs. -- 10000 root nodes -> ~123K total nodes, ~154K allocs. -- 100000 root nodes -> ~1338K total nodes, ~1666K allocs. local ROOT_ITEMS_COUNT = 20 - local category_names = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" } + + local category_names = s.category_names local category_count = #category_names + local name_buf -- [Port] Lua string, truncated to sizeof(ExampleTreeNode::Name) by ExampleTree_CreateNode() local uid = 0 uid = uid + 1 local node_L0 = ExampleTree_CreateNode("", uid, nil) for idx_L0 = 0, ROOT_ITEMS_COUNT - 1 do - local name_buf = string.format("%s %d", category_names[math.floor(idx_L0 / math.floor(ROOT_ITEMS_COUNT / category_count)) + 1], idx_L0 % math.floor(ROOT_ITEMS_COUNT / category_count)) + name_buf = string.format("%s %d", category_names[math.floor(idx_L0 / math.floor(ROOT_ITEMS_COUNT / category_count)) + 1], idx_L0 % math.floor(ROOT_ITEMS_COUNT / category_count)) uid = uid + 1 local node_L1 = ExampleTree_CreateNode(name_buf, uid, node_L0) local number_of_childs = #node_L1.Name for idx_L1 = 0, number_of_childs - 1 do + name_buf = string.format("Child %d", idx_L1) uid = uid + 1 - local node_L2 = ExampleTree_CreateNode(string.format("Child %d", idx_L1), uid, node_L1) + local node_L2 = ExampleTree_CreateNode(name_buf, uid, node_L1) node_L2.HasData = true if idx_L1 == 0 then + name_buf = string.format("Sub-child %d", 0) uid = uid + 1 - local node_L3 = ExampleTree_CreateNode(string.format("Sub-child %d", 0), uid, node_L2) + local node_L3 = ExampleTree_CreateNode(name_buf, uid, node_L2) node_L3.HasData = true end end @@ -21917,13 +22357,13 @@ end function ExampleImageViewerData() return { ImageBgColor = IM_COL32(100, 100, 100, 255), - GridColor = IM_COL32(255, 255, 255, 100), - GridEnabled = true, - ViewReset = true, - ViewOffset = ImVec2(0, 0), -- in image space - Zoom = 10.0, - ZoomMin = 1.0, - ZoomMax = 10000.0, + GridColor = IM_COL32(255, 255, 255, 100), + GridEnabled = true, + ViewReset = true, + ViewOffset = ImVec2(0.0, 0.0), -- in image space + Zoom = 10.0, + ZoomMin = 1.0, + ZoomMax = 10000.0, } end @@ -21959,7 +22399,7 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w -- Handle inputs if ImGui.SetItemKeyOwner(662 --[[ImGuiKey.MouseWheelY]]) then if io.MouseWheel ~= 0.0 then - data.Zoom = DemoClamp(data.Zoom * (1.0 + io.MouseWheel * 0.10), data.ZoomMin, data.ZoomMax) + data.Zoom = ImClamp(data.Zoom * (1.0 + io.MouseWheel * 0.10), data.ZoomMin, data.ZoomMax) end end local zoom = data.Zoom -- (float)(int)ViewZoom; @@ -21969,11 +22409,11 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w end -- Display image - local image_min = ImVec2(); local image_max = ImVec2() - image_min.x = math.floor((canvas_min.x - (data.ViewOffset.x * zoom)) + (canvas_size.x * 0.5)) - image_min.y = math.floor((canvas_min.y - (data.ViewOffset.y * zoom)) + (canvas_size.y * 0.5)) - image_max.x = math.floor(image_min.x + image_w * zoom) - image_max.y = math.floor(image_min.y + image_h * zoom) + local image_min, image_max = ImVec2(), ImVec2() + image_min.x = ImTrunc((canvas_min.x - (data.ViewOffset.x * zoom)) + (canvas_size.x * 0.5)) + image_min.y = ImTrunc((canvas_min.y - (data.ViewOffset.y * zoom)) + (canvas_size.y * 0.5)) + image_max.x = ImTrunc(image_min.x + image_w * zoom) + image_max.y = ImTrunc(image_min.y + image_h * zoom) draw_list:AddRect(ImVec2(canvas_min.x - 1.0, canvas_min.y - 1.0), ImVec2(canvas_max.x + 1.0, canvas_max.y + 1.0), IM_COL32(255, 255, 255, 255)) draw_list:PushClipRect(canvas_min, canvas_max, true) draw_list:AddRectFilled(image_min, image_max, data.ImageBgColor) @@ -21988,10 +22428,10 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w -- Display grid lines for visible pixels if data.GridEnabled and zoom > 6.0 then local step = zoom - for px = math.floor((canvas_min.x - image_min.x) / step), math.floor((canvas_max.x - image_min.x) / step) do + for px = ImTrunc((canvas_min.x - image_min.x) / step), ImTrunc((canvas_max.x - image_min.x) / step) do draw_list:AddLineV(image_min.x + px * step, canvas_min.y, canvas_max.y, data.GridColor, 1.0) end - for py = math.floor((canvas_min.y - image_min.y) / step), math.floor((canvas_max.y - image_min.y) / step) do + for py = ImTrunc((canvas_min.y - image_min.y) / step), ImTrunc((canvas_max.y - image_min.y) / step) do draw_list:AddLineH(canvas_min.x, canvas_max.x, image_min.y + py * step, data.GridColor, 1.0) end end @@ -21999,547 +22439,2834 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w end ------------------------------------------------------------------------------- --- [SECTION] Demo Window / ShowDemoWindow() +-- [SECTION] DemoWindowWidgetsBasic() ------------------------------------------------------------------------------- --- Stored data -local demo_data = ImGuiDemoWindowData() +S.DemoWindowWidgetsBasic = { + clicked = 0, + check = true, + e = 0, + counter = 0, + inputs = { + str0 = ImGui.NewTextBuffer("Hello, world!", 128), + str1 = ImGui.NewTextBuffer("", 128), + i0 = 123, + f0 = 0.001, + d0 = 999999.00000001, + f1 = 1.e10, + vec4a = { 0.10, 0.20, 0.30, 0.44 }, + }, + drags = { i1 = 50, i2 = 42, i3 = 128, f1 = 1.00, f2 = 0.0067 }, + sliders = { i1 = 0, f1 = 0.123, f2 = 0.0, angle = 0.0, elem = 0 }, + pickers = { col1 = { 1.0, 0.0, 0.2 }, col2 = { 0.4, 0.7, 0.0, 0.5 } }, + combo = { item_current = 0 }, + listbox = { item_current = 1 }, +} -local no_titlebar = false -local no_scrollbar = false -local no_menu = false -local no_move = false -local no_resize = false -local no_collapse = false -local no_close = false -local no_nav = false -local no_background = false -local no_bring_to_front = false -local no_docking = false -local unsaved_document = false - ---- Shows an example app: `if X then X.open = X(open) end`. Example apps return the new p_open. -local function RunApp(fn, key, ...) - if fn then - demo_data[key] = fn(demo_data[key], ...) - if demo_data[key] == nil then demo_data[key] = false end - else - demo_data[key] = false - end -end - -local function DemoWindowMenuBar(data) - if ImGui.BeginMenuBar() then - if ImGui.BeginMenu("Menu") then - IMGUI_DEMO_MARKER("Menu/File") - ShowExampleMenuFile() - ImGui.EndMenu() - end - if ImGui.BeginMenu("Examples") then - IMGUI_DEMO_MARKER("Menu/Examples") - _, data.ShowMainMenuBar = ImGui.MenuItem("Main menu bar", nil, data.ShowMainMenuBar) - - ImGui.SeparatorText("Mini apps") - _, data.ShowAppAssetsBrowser = ImGui.MenuItem("Assets Browser", nil, data.ShowAppAssetsBrowser) - _, data.ShowAppConsole = ImGui.MenuItem("Console", nil, data.ShowAppConsole) - _, data.ShowAppCustomRendering = ImGui.MenuItem("Custom rendering", nil, data.ShowAppCustomRendering) - _, data.ShowAppDocuments = ImGui.MenuItem("Documents", nil, data.ShowAppDocuments) - _, data.ShowAppDockSpace = ImGui.MenuItem("Dockspace", nil, data.ShowAppDockSpace) - _, data.ShowAppImageViewer = ImGui.MenuItem("Image Viewer", nil, data.ShowAppImageViewer) - _, data.ShowAppLog = ImGui.MenuItem("Log", nil, data.ShowAppLog) - _, data.ShowAppPropertyEditor = ImGui.MenuItem("Property editor", nil, data.ShowAppPropertyEditor) - _, data.ShowAppLayout = ImGui.MenuItem("Simple layout", nil, data.ShowAppLayout) - _, data.ShowAppSimpleOverlay = ImGui.MenuItem("Simple overlay", nil, data.ShowAppSimpleOverlay) - - ImGui.SeparatorText("Concepts") - _, data.ShowAppAutoResize = ImGui.MenuItem("Auto-resizing window", nil, data.ShowAppAutoResize) - _, data.ShowAppConstrainedResize = ImGui.MenuItem("Constrained-resizing window", nil, data.ShowAppConstrainedResize) - _, data.ShowAppFullscreen = ImGui.MenuItem("Fullscreen window", nil, data.ShowAppFullscreen) - _, data.ShowAppLongText = ImGui.MenuItem("Long text display", nil, data.ShowAppLongText) - _, data.ShowAppWindowTitles = ImGui.MenuItem("Manipulating window titles", nil, data.ShowAppWindowTitles) - - ImGui.EndMenu() - end - -- if ImGui.MenuItem("MenuItem") then end -- You can also use MenuItem() inside a menu bar! - if ImGui.BeginMenu("Tools") then - IMGUI_DEMO_MARKER("Menu/Tools") - local io = ImGui.GetIO() - local has_debug_tools = not IMGUI_DISABLE_DEBUG_TOOLS - _, data.ShowMetrics = ImGui.MenuItem("Metrics/Debugger", nil, data.ShowMetrics, has_debug_tools and ImGui.ShowMetricsWindow ~= nil) - if ImGui.BeginMenu("Debug Options") then - ImGui.BeginDisabled(not has_debug_tools) - _, io.ConfigDebugHighlightIdConflicts = ImGui.Checkbox("Highlight ID Conflicts", io.ConfigDebugHighlightIdConflicts) - ImGui.EndDisabled() - _, io.ConfigErrorRecoveryEnableAssert = ImGui.Checkbox("Assert on error recovery", io.ConfigErrorRecoveryEnableAssert) - ImGui.TextDisabled("(see Demo->Configuration for more)") - ImGui.EndMenu() - end - _, data.ShowDebugLog = ImGui.MenuItem("Debug Log", nil, data.ShowDebugLog, has_debug_tools and ImGui.ShowDebugLogWindow ~= nil) - _, data.ShowIDStackTool = ImGui.MenuItem("ID Stack Tool", nil, data.ShowIDStackTool, has_debug_tools and ImGui.ShowIDStackToolWindow ~= nil) - local is_debugger_present = io.ConfigDebugIsDebuggerPresent - if ImGui.MenuItem("Item Picker", nil, false, has_debug_tools and ImGui.DebugStartItemPicker ~= nil) then -- and is_debugger_present - ImGui.DebugStartItemPicker() - end - if not is_debugger_present then - ImGui.SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application.") - end - _, data.ShowStyleEditor = ImGui.MenuItem("Style Editor", nil, data.ShowStyleEditor) - _, data.ShowAbout = ImGui.MenuItem("About Dear ImGui", nil, data.ShowAbout) - - ImGui.EndMenu() - end - ImGui.EndMenuBar() - end -end - ---- Configuration header contents (split from ShowDemoWindow to keep the function small) -local function DemoWindowConfiguration(io) - local F = ImGuiConfigFlags - local function CF(label, flag) - local pressed - pressed, io.ConfigFlags = ImGui.CheckboxFlags(label, io.ConfigFlags, flag) - return pressed - end - local function CB(label, field) - local pressed - pressed, io[field] = ImGui.Checkbox(label, io[field]) - return pressed - end - local function HM(desc) ImGui.SameLine(); HelpMarker(desc) end - - if ImGui.TreeNode("Configuration##2") then - IMGUI_DEMO_MARKER("Configuration") +function DemoWindowWidgetsBasic() + local _ + if ImGui.TreeNode("Basic") then + local s = S.DemoWindowWidgetsBasic + IMGUI_DEMO_MARKER("Widgets/Basic") ImGui.SeparatorText("General") - CF("io.ConfigFlags: NavEnableKeyboard", F.NavEnableKeyboard) - HM("Enable keyboard controls.") - CF("io.ConfigFlags: NavEnableGamepad", F.NavEnableGamepad) - HM("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.") - CF("io.ConfigFlags: NoMouse", F.NoMouse) - HM("Instruct dear imgui to disable mouse inputs and interactions.") - -- The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: - if DemoHas(io.ConfigFlags, F.NoMouse) then - if (ImGui.GetTime() % 0.40) < 0.20 then + IMGUI_DEMO_MARKER("Widgets/Basic/Button") + if ImGui.Button("Button") then + s.clicked = s.clicked + 1 + end + if bit32.band(s.clicked, 1) ~= 0 then + ImGui.SameLine() + ImGui.Text("Thanks for clicking me!") + end + + IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox") + _, s.check = ImGui.Checkbox("checkbox", s.check) + + IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton") + _, s.e = ImGui.RadioButton("radio a", s.e, 0); ImGui.SameLine() + _, s.e = ImGui.RadioButton("radio b", s.e, 1); ImGui.SameLine() + _, s.e = ImGui.RadioButton("radio c", s.e, 2) + + ImGui.AlignTextToFramePadding() + ImGui.TextLinkOpenURL("Hyperlink", "https://github.com/ocornut/imgui/wiki/Error-Handling") + + -- Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)") + for i = 0, 6 do + if i > 0 then ImGui.SameLine() - ImGui.Text("<>") - end - -- Prevent both being checked - if ImGui.IsKeyPressed(524 --[[ImGuiKey.Space]]) or DemoHas(io.ConfigFlags, F.NoKeyboard) then - io.ConfigFlags = bit32.band(io.ConfigFlags, bit32.bnot(F.NoMouse)) end + ImGui.PushID(i) + ImGui.PushStyleColor(22 --[[ImGuiCol.Button]], ImColor.HSV(i / 7.0, 0.6, 0.6).Value) + ImGui.PushStyleColor(23 --[[ImGuiCol.ButtonHovered]], ImColor.HSV(i / 7.0, 0.7, 0.7).Value) + ImGui.PushStyleColor(24 --[[ImGuiCol.ButtonActive]], ImColor.HSV(i / 7.0, 0.8, 0.8).Value) + ImGui.Button("Click") + ImGui.PopStyleColor(3) + ImGui.PopID() end - CF("io.ConfigFlags: NoMouseCursorChange", F.NoMouseCursorChange) - HM("Instruct backend to not alter mouse cursor shape and visibility.") - CF("io.ConfigFlags: NoKeyboard", F.NoKeyboard) - HM("Instruct dear imgui to disable keyboard inputs and interactions.") - - CB("io.ConfigInputTrickleEventQueue", "ConfigInputTrickleEventQueue") - HM("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.") - CB("io.MouseDrawCursor", "MouseDrawCursor") - HM("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).") - - ImGui.SeparatorText("Keyboard/Gamepad Navigation") - CB("io.ConfigNavSwapGamepadButtons", "ConfigNavSwapGamepadButtons") - CB("io.ConfigNavMoveSetMousePos", "ConfigNavMoveSetMousePos") - HM("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult") - CB("io.ConfigNavCaptureKeyboard", "ConfigNavCaptureKeyboard") - CB("io.ConfigNavEscapeClearFocusItem", "ConfigNavEscapeClearFocusItem") - HM("Pressing Escape clears focused item.") - CB("io.ConfigNavEscapeClearFocusWindow", "ConfigNavEscapeClearFocusWindow") - HM("Pressing Escape clears focused window.") - CB("io.ConfigNavCursorVisibleAuto", "ConfigNavCursorVisibleAuto") - HM("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.") - CB("io.ConfigNavCursorVisibleAlways", "ConfigNavCursorVisibleAlways") - HM("Navigation cursor is always visible.") - - ImGui.SeparatorText("Docking") - CF("io.ConfigFlags: DockingEnable", F.DockingEnable) + -- Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements + -- (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) + -- See 'Demo->Layout->Text Baseline Alignment' for details. + ImGui.AlignTextToFramePadding() + ImGui.Text("Hold to repeat:") ImGui.SameLine() - if io.ConfigDockingWithShift then - HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") - else - HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") - end - if DemoHas(io.ConfigFlags, F.DockingEnable) then - ImGui.Indent() - CB("io.ConfigDockingNoSplit", "ConfigDockingNoSplit") - HM("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.") - CB("io.ConfigDockingNoDockingOver", "ConfigDockingNoDockingOver") - HM("Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows.") - CB("io.ConfigDockingWithShift", "ConfigDockingWithShift") - HM("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)") - CB("io.ConfigDockingAlwaysTabBar", "ConfigDockingAlwaysTabBar") - HM("Create a docking node and tab-bar on single floating windows.") - CB("io.ConfigDockingTransparentPayload", "ConfigDockingTransparentPayload") - HM("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.") - ImGui.Unindent() + + -- Arrow buttons with Repeater + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)") + local spacing = ImGui.GetStyle().ItemInnerSpacing.x + ImGui.PushItemFlag(8 --[[ImGuiItemFlags.ButtonRepeat]], true) + if ImGui.ArrowButton("##left", 0 --[[ImGuiDir.Left]]) then s.counter = s.counter - 1 end + ImGui.SameLine(0.0, spacing) + if ImGui.ArrowButton("##right", 1 --[[ImGuiDir.Right]]) then s.counter = s.counter + 1 end + ImGui.PopItemFlag() + ImGui.SameLine() + ImGui.Text("%d", s.counter) + + ImGui.Button("Tooltip") + ImGui.SetItemTooltip("I am a tooltip") + + ImGui.LabelText("label", "Value") + + ImGui.SeparatorText("Inputs") + + do + local s = S.DemoWindowWidgetsBasic.inputs + -- If you want to use InputText() with std::string or any custom dynamic string type: + -- - For std::string: use the wrapper in misc/cpp/imgui_stdlib.h/.cpp + -- - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize. + IMGUI_DEMO_MARKER("Widgets/Basic/InputText") + ImGui.InputText("input text", s.str0, 128) + ImGui.SameLine(); HelpMarker( + "USER:\n" .. + "Hold Shift or use mouse to select text.\n" .. + "Ctrl+Left/Right to word jump.\n" .. + "Ctrl+A or Double-Click to select all.\n" .. + "Ctrl+X,Ctrl+C,Ctrl+V for clipboard.\n" .. + "Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.\n" .. + "Escape to revert.\n\n" .. + "PROGRAMMER:\n" .. + "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " .. + "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " .. + "in imgui_demo.cpp).") + + ImGui.InputTextWithHint("input text (w/ hint)", "enter text here", s.str1, 128) + + IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat") + s.i0 = ImGui.InputInt("input int", s.i0) + + s.f0 = ImGui.InputFloat("input float", s.f0, 0.01, 1.0, "%.3f") + + s.d0 = ImGui.InputDouble("input double", s.d0, 0.01, 1.0, "%.8f") + + s.f1 = ImGui.InputFloat("input scientific", s.f1, 0.0, 0.0, "%e") + ImGui.SameLine(); HelpMarker( + "You can input value using the scientific notation,\n" .. + " e.g. \"1e+8\" becomes \"100000000\".") + + ImGui.InputFloat3("input float3", s.vec4a) end - ImGui.SeparatorText("Multi-viewports") - CF("io.ConfigFlags: ViewportsEnable", F.ViewportsEnable) - HM("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.") - if DemoHas(io.ConfigFlags, F.ViewportsEnable) then - ImGui.Indent() - DemoNotSupported() - ImGui.Unindent() + ImGui.SeparatorText("Drags") + + do + local s = S.DemoWindowWidgetsBasic.drags + IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat") + s.i1 = ImGui.DragInt("drag int", s.i1, 1) + ImGui.SameLine(); HelpMarker( + "Click and drag to edit value.\n" .. + "Hold Shift/Alt for faster/slower edit.\n" .. + "Double-Click or Ctrl+Click to input value.") + s.i2 = ImGui.DragInt("drag int 0..100", s.i2, 1, 0, 100, "%d%%", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + s.i3 = ImGui.DragInt("drag int wrap 100..200", s.i3, 1, 100, 200, "%d", 256 --[[ImGuiSliderFlags.WrapAround]]) + + s.f1 = ImGui.DragFloat("drag float", s.f1, 0.005) + s.f2 = ImGui.DragFloat("drag small float", s.f2, 0.0001, 0.0, 0.0, "%.06f ns") + --ImGui.DragFloat("drag wrap -1..1", f3, 0.005, -1.0, 1.0, nil, ImGuiSliderFlags.WrapAround) end - -- ImGui.SeparatorText("DPI/Scaling") - -- CB("io.ConfigDpiScaleFonts", "ConfigDpiScaleFonts") - -- HM("Experimental: Automatically update style.FontScaleDpi when Monitor DPI changes. This will scale fonts but NOT style sizes/padding for now.") - -- CB("io.ConfigDpiScaleViewports", "ConfigDpiScaleViewports") - -- HM("Experimental: Scale Dear ImGui and Platform Windows when Monitor DPI changes.") + ImGui.SeparatorText("Sliders") - ImGui.SeparatorText("Windows") - CB("io.ConfigWindowsResizeFromEdges", "ConfigWindowsResizeFromEdges") - HM("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.") - CB("io.ConfigWindowsMoveFromTitleBarOnly", "ConfigWindowsMoveFromTitleBarOnly") - CB("io.ConfigWindowsCopyContentsWithCtrlC", "ConfigWindowsCopyContentsWithCtrlC") -- [EXPERIMENTAL] - HM("*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.") - CB("io.ConfigScrollbarScrollByPage", "ConfigScrollbarScrollByPage") - HM("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.") + do + local s = S.DemoWindowWidgetsBasic.sliders + IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat") + s.i1 = ImGui.SliderInt("slider int", s.i1, -1, 3) + ImGui.SameLine(); HelpMarker("Ctrl+Click to input value.") - ImGui.SeparatorText("Widgets") - CB("io.ConfigInputTextCursorBlink", "ConfigInputTextCursorBlink") - HM("Enable blinking cursor (optional as some users consider it to be distracting).") - CB("io.ConfigInputTextEnterKeepActive", "ConfigInputTextEnterKeepActive") - HM("Pressing Enter will reactivate item and select all text (single-line only).") - CB("io.ConfigDragClickToInputText", "ConfigDragClickToInputText") - HM("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).") - CB("io.ConfigMacOSXBehaviors", "ConfigMacOSXBehaviors") - HM("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.") - ImGui.Text("Also see Style->Rendering for rendering options.") + s.f1 = ImGui.SliderFloat("slider float", s.f1, 0.0, 1.0, "ratio = %.3f") + s.f2 = ImGui.SliderFloat("slider float (log)", s.f2, -10.0, 10.0, "%.4f", 32 --[[ImGuiSliderFlags.Logarithmic]]) - ImGui.SeparatorText("Settings") - CB("io.ConfigIniSettingsSaveLastUsedDate", "ConfigIniSettingsSaveLastUsedDate") + IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle") + s.angle = ImGui.SliderAngle("slider angle", s.angle) - -- Also read: https://github.com/ocornut/imgui/wiki/Error-Handling - ImGui.SeparatorText("Error Handling") - - CB("io.ConfigErrorRecovery", "ConfigErrorRecovery") - HM( - "Options to configure how we handle recoverable errors.\n" .. - "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n" .. - "- You not are not supposed to rely on it in the course of a normal application run.\n" .. - "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n" .. - "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call! " .. - "Otherwise it would severely hinder your ability to catch and correct mistakes!") - CB("io.ConfigErrorRecoveryEnableAssert", "ConfigErrorRecoveryEnableAssert") - CB("io.ConfigErrorRecoveryEnableDebugLog", "ConfigErrorRecoveryEnableDebugLog") - CB("io.ConfigErrorRecoveryEnableTooltip", "ConfigErrorRecoveryEnableTooltip") - if not io.ConfigErrorRecoveryEnableAssert and not io.ConfigErrorRecoveryEnableDebugLog and not io.ConfigErrorRecoveryEnableTooltip then - io.ConfigErrorRecoveryEnableAssert = true - io.ConfigErrorRecoveryEnableDebugLog = true - io.ConfigErrorRecoveryEnableTooltip = true + -- Using the format string to display a name instead of an integer. + -- Here we completely omit '%d' from the format string, so it'll only display a name. + -- This technique can also be used with DragInt(). + IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)") + local Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT = 0, 1, 2, 3, 4 + local elems_names = { "Fire", "Earth", "Air", "Water" } + local elem_name = (s.elem >= 0 and s.elem < Element_COUNT) and elems_names[s.elem + 1] or "Unknown" + s.elem = ImGui.SliderInt("slider enum", s.elem, 0, Element_COUNT - 1, elem_name) -- Use ImGuiSliderFlags_NoInput flag to disable Ctrl+Click here. + ImGui.SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.") end - -- Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools - ImGui.SeparatorText("Debug") - CB("io.ConfigDebugIsDebuggerPresent", "ConfigDebugIsDebuggerPresent") - HM("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.") - CB("io.ConfigDebugHighlightIdConflicts", "ConfigDebugHighlightIdConflicts") - HM("Highlight and show an error message when multiple items have conflicting identifiers.") - ImGui.BeginDisabled() - CB("io.ConfigDebugBeginReturnValueOnce", "ConfigDebugBeginReturnValueOnce") - ImGui.EndDisabled() - HM("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.") - CB("io.ConfigDebugBeginReturnValueLoop", "ConfigDebugBeginReturnValueLoop") - HM("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.") - CB("io.ConfigDebugIgnoreFocusLoss", "ConfigDebugIgnoreFocusLoss") - HM("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.") - CB("io.ConfigDebugDrawListDefaultsToStrokeLegacy", "ConfigDebugDrawListDefaultsToStrokeLegacy") - HM("Option to default all ImDrawList to ImDrawFlags_StrokeLegacy mode, mimicking pre-1.93.0 rendering.") - CB("io.ConfigDebugIniSettings", "ConfigDebugIniSettings") - HM("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).") + ImGui.SeparatorText("Selectors/Pickers") + + do + local s = S.DemoWindowWidgetsBasic.pickers + IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4") + ImGui.ColorEdit3("color 1", s.col1) + ImGui.SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" .. + "Click and hold to use drag and drop.\n" .. + "Right-Click on the color square to show options.\n" .. + "Ctrl+Click on individual component to input value.\n") + + ImGui.ColorEdit4("color 2", s.col2) + end + + do + local s = S.DemoWindowWidgetsBasic.combo + -- Using the _simplified_ one-liner Combo() api here + -- See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. + IMGUI_DEMO_MARKER("Widgets/Basic/Combo") + local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" } + s.item_current = ImGui.Combo("combo", s.item_current, items, #items) + ImGui.SameLine(); HelpMarker( + "Using the simplified one-liner Combo API here.\n" .. + "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.") + end + + do + local s = S.DemoWindowWidgetsBasic.listbox + -- Using the _simplified_ one-liner ListBox() api here + -- See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. + IMGUI_DEMO_MARKER("Widgets/Basic/ListBox") + local items = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" } + s.item_current = ImGui.ListBox("listbox", s.item_current, items, #items, 4) + ImGui.SameLine(); HelpMarker( + "Using the simplified one-liner ListBox API here.\n" .. + "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.") + end + + -- Testing ImGuiOnceUponAFrame helper. + --static ImGuiOnceUponAFrame once; + --for (int i = 0; i < 5; i++) + -- if (once) + -- ImGui.Text("This will be displayed only once."); ImGui.TreePop() - ImGui.Spacing() end +end - if ImGui.TreeNode("Backend Flags") then - IMGUI_DEMO_MARKER("Configuration/Backend Flags") - HelpMarker( - "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" .. - "Here we expose them as read-only fields to avoid breaking interactions with your backend.") +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsBullets() +------------------------------------------------------------------------------- - -- Make a local copy to avoid modifying actual backend flags. - -- FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright? - local B = ImGuiBackendFlags - local backend_flags = io.BackendFlags - ImGui.BeginDisabled() - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasGamepad", backend_flags, B.HasGamepad) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseCursors", backend_flags, B.HasMouseCursors) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasSetMousePos", backend_flags, B.HasSetMousePos) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: PlatformHasViewports", backend_flags, B.PlatformHasViewports) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport", backend_flags, B.HasMouseHoveredViewport) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasParentViewport", backend_flags, B.HasParentViewport) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", backend_flags, B.RendererHasVtxOffset) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasTextures", backend_flags, B.RendererHasTextures) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasViewports", backend_flags, B.RendererHasViewports) +function DemoWindowWidgetsBullets() + if ImGui.TreeNode("Bullets") then + IMGUI_DEMO_MARKER("Widgets/Bullets") + ImGui.BulletText("Bullet point 1") + ImGui.BulletText("Bullet point 2\nOn multiple lines") + if ImGui.TreeNode("Tree node") then + ImGui.BulletText("Another bullet point") + ImGui.TreePop() + end + ImGui.Bullet(); ImGui.Text("Bullet point 3 (two calls)") + ImGui.Bullet(); ImGui.SmallButton("Button") + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsCollapsingHeaders() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsCollapsingHeaders = { + closable_group = true, +} + +function DemoWindowWidgetsCollapsingHeaders() + local _ + if ImGui.TreeNode("Collapsing Headers") then + local s = S.DemoWindowWidgetsCollapsingHeaders + IMGUI_DEMO_MARKER("Widgets/Collapsing Headers") + _, s.closable_group = ImGui.Checkbox("Show 2nd header", s.closable_group) + if ImGui.CollapsingHeader("Header", 0 --[[ImGuiTreeNodeFlags.None]]) then + ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) + for i = 0, 4 do + ImGui.Text("Some content %d", i) + end + end + local open + open, s.closable_group = ImGui.CollapsingHeader("Header with a close button", s.closable_group) + if open then + ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) + for i = 0, 4 do + ImGui.Text("More content %d", i) + end + end + --[[ + if ImGui.CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags.Bullet) then + ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered()) + end + ]] + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsColorAndPickers() +------------------------------------------------------------------------------- + +-- [Port] the library does not define the standard color payload types (ColorButton drag source is not ported yet) +IMGUI_PAYLOAD_TYPE_COLOR_3F = IMGUI_PAYLOAD_TYPE_COLOR_3F or "_COL3F" +IMGUI_PAYLOAD_TYPE_COLOR_4F = IMGUI_PAYLOAD_TYPE_COLOR_4F or "_COL4F" + +S.DemoWindowWidgetsColorAndPickers = { + color = ImVec4(114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 200.0 / 255.0), + base_flags = ImGuiColorEditFlags.None, + saved_palette_init = true, + saved_palette = {}, -- 32 x ImVec4, 1-based + backup_color = ImVec4(), + no_border = false, + ref_color = false, + ref_color_v = ImVec4(1.0, 0.0, 1.0, 0.5), + picker_mode = 0, + display_mode = 0, + color_picker_flags = ImGuiColorEditFlags.AlphaBar, + color_hsv = ImVec4(0.23, 1.0, 1.0, 1.0), -- Stored as HSV! +} + +function DemoWindowWidgetsColorAndPickers() + local _ + if ImGui.TreeNode("Color/Picker Widgets") then + local s = S.DemoWindowWidgetsColorAndPickers + IMGUI_DEMO_MARKER("Widgets/Color") + local color = s.color + + ImGui.SeparatorText("Options") + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.base_flags, 2 --[[ImGuiColorEditFlags.NoAlpha]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", s.base_flags, 4096 --[[ImGuiColorEditFlags.AlphaOpaque]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", s.base_flags, 8192 --[[ImGuiColorEditFlags.AlphaNoBg]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", s.base_flags, 16384 --[[ImGuiColorEditFlags.AlphaPreviewHalf]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoOptions", s.base_flags, 8 --[[ImGuiColorEditFlags.NoOptions]]); ImGui.SameLine(); HelpMarker("Right-click on the individual color widget to show options.") + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", s.base_flags, 512 --[[ImGuiColorEditFlags.NoDragDrop]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoColorMarkers", s.base_flags, 2048 --[[ImGuiColorEditFlags.NoColorMarkers]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_HDR", s.base_flags, 524288 --[[ImGuiColorEditFlags.HDR]]); ImGui.SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.") + local base_flags = s.base_flags + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit") + ImGui.SeparatorText("Inline color editor") + ImGui.Text("Color widget:") + ImGui.SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" .. + "Ctrl+Click on individual component to input value.\n") + ImGui.ColorEdit3("MyColor##1", color, base_flags) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)") + ImGui.Text("Color widget HSV with Alpha:") + ImGui.ColorEdit4("MyColor##2", color, bit32.bor(2097152 --[[ImGuiColorEditFlags.DisplayHSV]], base_flags)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)") + ImGui.Text("Color widget with Float Display:") + ImGui.ColorEdit4("MyColor##2f", color, bit32.bor(16777216 --[[ImGuiColorEditFlags.Float]], base_flags)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)") + ImGui.Text("Color button with Picker:") + ImGui.SameLine(); HelpMarker( + "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" .. + "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " .. + "be used for the tooltip and picker popup.") + ImGui.ColorEdit4("MyColor##3", color, bit32.bor(32 --[[ImGuiColorEditFlags.NoInputs]], 128 --[[ImGuiColorEditFlags.NoLabel]], base_flags)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)") + ImGui.Text("Color button with Custom Picker Popup:") + + -- Generate a default palette. The palette will persist and can be edited. + local saved_palette = s.saved_palette + if s.saved_palette_init then + for n = 0, 32 - 1 do + saved_palette[n + 1] = ImVec4() + saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z = ImGui.ColorConvertHSVtoRGB(n / 31.0, 0.8, 0.8) + saved_palette[n + 1].w = 1.0 -- Alpha + end + s.saved_palette_init = false + end + + local open_popup = ImGui.ColorButton("MyColor##3b", color, base_flags) + ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.x) + open_popup = ImGui.Button("Palette") or open_popup + if open_popup then + ImGui.OpenPopup("mypicker") + ImVec4_Copy(s.backup_color, color) + end + if ImGui.BeginPopup("mypicker") then + ImGui.Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!") + ImGui.Separator() + ImGui.ColorPicker4("##picker", color, bit32.bor(base_flags, 256 --[[ImGuiColorEditFlags.NoSidePreview]], 16 --[[ImGuiColorEditFlags.NoSmallPreview]])) + ImGui.SameLine() + + ImGui.BeginGroup() -- Lock X position + ImGui.Text("Current") + ImGui.ColorButton("##current", color, bit32.bor(4 --[[ImGuiColorEditFlags.NoPicker]], 16384 --[[ImGuiColorEditFlags.AlphaPreviewHalf]]), ImVec2(60, 40)) + ImGui.Text("Previous") + if ImGui.ColorButton("##previous", s.backup_color, bit32.bor(4 --[[ImGuiColorEditFlags.NoPicker]], 16384 --[[ImGuiColorEditFlags.AlphaPreviewHalf]]), ImVec2(60, 40)) then + ImVec4_Copy(color, s.backup_color) + end + ImGui.Separator() + ImGui.Text("Palette") + for n = 0, #saved_palette - 1 do + ImGui.PushID(n) + if (n % 8) ~= 0 then + ImGui.SameLine(0.0, ImGui.GetStyle().ItemSpacing.y) + end + + local palette_button_flags = bit32.bor(2 --[[ImGuiColorEditFlags.NoAlpha]], 4 --[[ImGuiColorEditFlags.NoPicker]], 64 --[[ImGuiColorEditFlags.NoTooltip]]) + if ImGui.ColorButton("##palette", saved_palette[n + 1], palette_button_flags, ImVec2(20, 20)) then + color.x, color.y, color.z = saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z -- Preserve alpha! + end + + -- Allow user to drop colors into each palette entry. Note that ColorButton() is already a + -- drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. + if ImGui.BeginDragDropTarget() then + local payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F) + if payload then + local d = payload.Data -- [Port] memcpy -> copy components (Data is a 1-based float array or ImVec4) + saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z = d[1], d[2], d[3] + end + payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F) + if payload then + local d = payload.Data -- [Port] memcpy -> copy components + saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z, saved_palette[n + 1].w = d[1], d[2], d[3], d[4] + end + ImGui.EndDragDropTarget() + end + + ImGui.PopID() + end + ImGui.EndGroup() + ImGui.EndPopup() + end + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)") + ImGui.Text("Color button only:") + _, s.no_border = ImGui.Checkbox("ImGuiColorEditFlags_NoBorder", s.no_border) + ImGui.ColorButton("MyColor##3c", color, bit32.bor(base_flags, s.no_border and 1024 --[[ImGuiColorEditFlags.NoBorder]] or 0), ImVec2(80, 80)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker") + ImGui.SeparatorText("Color picker") + + ImGui.PushID("Color picker") + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.color_picker_flags, 2 --[[ImGuiColorEditFlags.NoAlpha]]) + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaBar", s.color_picker_flags, 262144 --[[ImGuiColorEditFlags.AlphaBar]]) + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", s.color_picker_flags, 256 --[[ImGuiColorEditFlags.NoSidePreview]]) + if bit32.band(s.color_picker_flags, 256 --[[ImGuiColorEditFlags.NoSidePreview]]) ~= 0 then + ImGui.SameLine() + _, s.ref_color = ImGui.Checkbox("With Ref Color", s.ref_color) + if s.ref_color then + ImGui.SameLine() + ImGui.ColorEdit4("##RefColor", s.ref_color_v, bit32.bor(32 --[[ImGuiColorEditFlags.NoInputs]], base_flags)) + end + end + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_PickerNoRotate", s.color_picker_flags, 134217728 --[[ImGuiColorEditFlags.PickerNoRotate]]) + + s.picker_mode = ImGui.Combo("Picker Mode", s.picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0") + ImGui.SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode.") + + s.display_mode = ImGui.Combo("Display Mode", s.display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0") + ImGui.SameLine(); HelpMarker( + "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " .. + "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex " .. + "if you don't specify a display mode.\n\nYou can change the defaults using io.ConfigColorEditFlags.") + + local flags = bit32.bor(base_flags, s.color_picker_flags) + if s.picker_mode == 1 then flags = bit32.bor(flags, 33554432 --[[ImGuiColorEditFlags.PickerHueBar]]) end + if s.picker_mode == 2 then flags = bit32.bor(flags, 67108864 --[[ImGuiColorEditFlags.PickerHueWheel]]) end + if s.display_mode == 1 then flags = bit32.bor(flags, 32 --[[ImGuiColorEditFlags.NoInputs]]) end -- Disable all RGB/HSV/Hex displays + if s.display_mode == 2 then flags = bit32.bor(flags, 1048576 --[[ImGuiColorEditFlags.DisplayRGB]]) end -- Override display mode + if s.display_mode == 3 then flags = bit32.bor(flags, 2097152 --[[ImGuiColorEditFlags.DisplayHSV]]) end + if s.display_mode == 4 then flags = bit32.bor(flags, 4194304 --[[ImGuiColorEditFlags.DisplayHex]]) end + ImGui.ColorPicker4("MyColor##4", color, flags, s.ref_color and s.ref_color_v or nil) + + ImGui.Text("Set defaults in code:") + ImGui.SameLine(); HelpMarker( + "io.ConfigColorEditFlags is designed to allow you to set boot-time default.\n" .. + "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " .. + "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " .. + "encouraging you to persistently save values that aren't forward-compatible.") + if ImGui.Button("Overwrite default: Uint8 + HSV + Hue Bar") then + ImGui.GetIO().ConfigColorEditFlags = bit32.bor(8388608 --[[ImGuiColorEditFlags.Uint8]], 2097152 --[[ImGuiColorEditFlags.DisplayHSV]], 33554432 --[[ImGuiColorEditFlags.PickerHueBar]], 268435456 --[[ImGuiColorEditFlags.InputRGB]]) -- [Port] + InputRGB: without it ColorEdit4's InputMask_ power-of-two assert trips + end + if ImGui.Button("Overwrite default: Float + HDR + Hue Wheel") then + ImGui.GetIO().ConfigColorEditFlags = bit32.bor(16777216 --[[ImGuiColorEditFlags.Float]], 524288 --[[ImGuiColorEditFlags.HDR]], 67108864 --[[ImGuiColorEditFlags.PickerHueWheel]], 1048576 --[[ImGuiColorEditFlags.DisplayRGB]], 268435456 --[[ImGuiColorEditFlags.InputRGB]]) -- [Port] + DisplayRGB + InputRGB: same asserts (DisplayMask_/InputMask_) + end + + -- Always display a small version of both types of pickers + -- (that's in order to make it more visible in the demo to people who are skimming quickly through it) + ImGui.Text("Both types:") + local w = (ImGui.GetContentRegionAvail().x - ImGui.GetStyle().ItemSpacing.y) * 0.40 + ImGui.SetNextItemWidth(w) + ImGui.ColorPicker3("##MyColor##5", color, bit32.bor(33554432 --[[ImGuiColorEditFlags.PickerHueBar]], 256 --[[ImGuiColorEditFlags.NoSidePreview]], 32 --[[ImGuiColorEditFlags.NoInputs]], 2 --[[ImGuiColorEditFlags.NoAlpha]])) + ImGui.SameLine() + ImGui.SetNextItemWidth(w) + ImGui.ColorPicker3("##MyColor##6", color, bit32.bor(67108864 --[[ImGuiColorEditFlags.PickerHueWheel]], 256 --[[ImGuiColorEditFlags.NoSidePreview]], 32 --[[ImGuiColorEditFlags.NoInputs]], 2 --[[ImGuiColorEditFlags.NoAlpha]])) + ImGui.PopID() + + -- HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) + local color_hsv = s.color_hsv -- Stored as HSV! + ImGui.Spacing() + ImGui.Text("HSV encoded colors") + ImGui.SameLine(); HelpMarker( + "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV " .. + "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the " .. + "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.") + ImGui.Text("Color widget with InputHSV:") + ImGui.ColorEdit4("HSV shown as RGB##1", color_hsv, bit32.bor(1048576 --[[ImGuiColorEditFlags.DisplayRGB]], 536870912 --[[ImGuiColorEditFlags.InputHSV]], 16777216 --[[ImGuiColorEditFlags.Float]])) + ImGui.ColorEdit4("HSV shown as HSV##1", color_hsv, bit32.bor(2097152 --[[ImGuiColorEditFlags.DisplayHSV]], 536870912 --[[ImGuiColorEditFlags.InputHSV]], 16777216 --[[ImGuiColorEditFlags.Float]])) + ImGui.DragFloat4("Raw HSV values", color_hsv, 0.01, 0.0, 1.0) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsComboBoxes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsComboBoxes = { + flags = 0, + item_selected_idx = 0, -- Here we store our selection data as an index. + filter = nil, -- ImGuiTextFilter, created lazily + item_current_2 = 0, + item_current_3 = -1, -- If the selection isn't within 0..count, Combo won't display a preview + item_current_4 = 0, +} + +function DemoWindowWidgetsComboBoxes() + local _, pressed + if ImGui.TreeNode("Combo") then + local s = S.DemoWindowWidgetsComboBoxes + IMGUI_DEMO_MARKER("Widgets/Combo") + -- Combo Boxes are also called "Dropdown" in other systems + -- Expose flags as checkbox for the demo + _, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", s.flags, 1 --[[ImGuiComboFlags.PopupAlignLeft]]) + ImGui.SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo") + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoArrowButton", s.flags, 32 --[[ImGuiComboFlags.NoArrowButton]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(64 --[[ImGuiComboFlags.NoPreview]])) -- Clear incompatible flags + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoPreview", s.flags, 64 --[[ImGuiComboFlags.NoPreview]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.bor(32 --[[ImGuiComboFlags.NoArrowButton]], 128 --[[ImGuiComboFlags.WidthFitPreview]]))) -- Clear incompatible flags + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_WidthFitPreview", s.flags, 128 --[[ImGuiComboFlags.WidthFitPreview]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(64 --[[ImGuiComboFlags.NoPreview]])) + end + + -- Override default popup height + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_HeightSmall", s.flags, 2 --[[ImGuiComboFlags.HeightSmall]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(30 --[[ImGuiComboFlags.HeightMask_]], bit32.bnot(2 --[[ImGuiComboFlags.HeightSmall]])))) + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_HeightRegular", s.flags, 4 --[[ImGuiComboFlags.HeightRegular]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(30 --[[ImGuiComboFlags.HeightMask_]], bit32.bnot(4 --[[ImGuiComboFlags.HeightRegular]])))) + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_HeightLargest", s.flags, 16 --[[ImGuiComboFlags.HeightLargest]]) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(30 --[[ImGuiComboFlags.HeightMask_]], bit32.bnot(16 --[[ImGuiComboFlags.HeightLargest]])))) + end + + -- Using the generic BeginCombo() API, you have full control over how to display the combo contents. + -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + -- stored in the object itself, etc.) + local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } + + -- Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) + local combo_preview_value = items[s.item_selected_idx + 1] + if ImGui.BeginCombo("combo 1", combo_preview_value, s.flags) then + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + if ImGui.Selectable(items[n + 1], is_selected) then + s.item_selected_idx = n + end + + -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if is_selected then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndCombo() + end + + -- Show case embedding a filter using a simple trick: displaying the filter inside combo contents. + -- See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives. + if ImGui.BeginCombo("combo 2 (w/ filter)", combo_preview_value, s.flags) then + if s.filter == nil then s.filter = ImGuiTextFilter() end + local filter = s.filter + if ImGui.IsWindowAppearing() then + ImGui.SetKeyboardFocusHere() + filter:Clear() + end + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 551 --[[ImGuiKey.F]])) + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + filter:DrawWithHint("##Filter", "Filter (incl -excl)") + + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + if filter:PassFilter(items[n + 1]) then + if ImGui.Selectable(items[n + 1], is_selected) then + s.item_selected_idx = n + end + end + end + ImGui.EndCombo() + end + + ImGui.Spacing() + ImGui.SeparatorText("One-liner variants") + HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section.") + + -- Simplified one-liner Combo() API, using values packed in a single constant string + -- This is a convenience for when the selection set is small and known at compile-time. + s.item_current_2 = ImGui.Combo("combo 3 (one-liner)", s.item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0") + + -- Simplified one-liner Combo() using an array of const char* + -- This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. + s.item_current_3 = ImGui.Combo("combo 4 (array)", s.item_current_3, items, #items) + + -- Simplified one-liner Combo() using an accessor function + s.item_current_4 = ImGui.Combo("combo 5 (function)", s.item_current_4, function(data, n) return data[n + 1] end, items, #items) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDataTypes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsDataTypes = { + -- State + s8_v = 127, + u8_v = 255, + s16_v = 32767, + u16_v = 65535, + s32_v = -1, + u32_v = 4294967295, -- (ImU32)-1 + -- [Port] s64_v / u64_v: 64-bit integer types are not supported (Lua numbers are doubles) + f32_v = 0.123, + f64_v = 90000.01234567890123456789, + drag_clamp = false, + inputs_step = true, + flags = ImGuiInputTextFlags.None, +} + +function DemoWindowWidgetsDataTypes() + local _ + if ImGui.TreeNode("Data Types") then + local s = S.DemoWindowWidgetsDataTypes + IMGUI_DEMO_MARKER("Widgets/Data Types") + -- DragScalar/InputScalar/SliderScalar functions allow various data types + -- - signed/unsigned + -- - 8/16/32/64-bits + -- - integer/float/double + -- To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum + -- to pass the type, and passing all arguments by pointer. + -- This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type. + -- In practice, if you frequently use a given type that is not covered by the normal API entry points, + -- you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, + -- and then pass their address to the generic function. For example: + -- bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") + -- { + -- return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); + -- } + -- [Port] in this port the value is passed and returned by value: `v = ImGui.SliderScalar(label, data_type, v, min, max, format)` + + -- Setup limits (as helper variables so we can take their address, as explained above) + -- Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. + -- [Port] LLONG_MIN/LLONG_MAX/ULLONG_MAX fallback block dropped: no 64-bit integer types + local s8_zero, s8_one, s8_fifty, s8_min, s8_max = 0, 1, 50, -128, 127 + local u8_zero, u8_one, u8_fifty, u8_min, u8_max = 0, 1, 50, 0, 255 + local s16_zero, s16_one, s16_fifty, s16_min, s16_max = 0, 1, 50, -32768, 32767 + local u16_zero, u16_one, u16_fifty, u16_min, u16_max = 0, 1, 50, 0, 65535 + local s32_zero, s32_one, s32_fifty, s32_min, s32_max, s32_hi_a, s32_hi_b = 0, 1, 50, -1073741824, 1073741823, 1073741823 - 100, 1073741823 -- INT_MIN/2, INT_MAX/2 + local u32_zero, u32_one, u32_fifty, u32_min, u32_max, u32_hi_a, u32_hi_b = 0, 1, 50, 0, 2147483647, 2147483647 - 100, 2147483647 -- UINT_MAX/2 + -- [Port] s64_* / u64_* limits: ImGuiDataType.S64/U64 are not supported + local f32_zero, f32_one, f32_lo_a, f32_hi_a = 0.0, 1.0, -10000000000.0, 10000000000.0 + local f64_zero, f64_one, f64_lo_a, f64_hi_a = 0.0, 1.0, -1000000000000000.0, 1000000000000000.0 + + -- State + -- (see S.DemoWindowWidgetsDataTypes) + + local drag_speed = 0.2 + IMGUI_DEMO_MARKER("Widgets/Data Types/Drags") + ImGui.SeparatorText("Drags") + _, s.drag_clamp = ImGui.Checkbox("Clamp integers to 0..50", s.drag_clamp) + ImGui.SameLine(); HelpMarker( + "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" .. + "You can override the clamping limits by using Ctrl+Click to input a value.") + local drag_clamp = s.drag_clamp + s.s8_v = ImGui.DragScalar("drag s8", 0 --[[ImGuiDataType.S8]], s.s8_v, drag_speed, drag_clamp and s8_zero or nil, drag_clamp and s8_fifty or nil) + s.u8_v = ImGui.DragScalar("drag u8", 1 --[[ImGuiDataType.U8]], s.u8_v, drag_speed, drag_clamp and u8_zero or nil, drag_clamp and u8_fifty or nil, "%u ms") + s.s16_v = ImGui.DragScalar("drag s16", 2 --[[ImGuiDataType.S16]], s.s16_v, drag_speed, drag_clamp and s16_zero or nil, drag_clamp and s16_fifty or nil) + s.u16_v = ImGui.DragScalar("drag u16", 3 --[[ImGuiDataType.U16]], s.u16_v, drag_speed, drag_clamp and u16_zero or nil, drag_clamp and u16_fifty or nil, "%u ms") + s.s32_v = ImGui.DragScalar("drag s32", 4 --[[ImGuiDataType.S32]], s.s32_v, drag_speed, drag_clamp and s32_zero or nil, drag_clamp and s32_fifty or nil) + s.s32_v = ImGui.DragScalar("drag s32 hex", 4 --[[ImGuiDataType.S32]], s.s32_v, drag_speed, drag_clamp and s32_zero or nil, drag_clamp and s32_fifty or nil, "0x%08X") + s.u32_v = ImGui.DragScalar("drag u32", 5 --[[ImGuiDataType.U32]], s.u32_v, drag_speed, drag_clamp and u32_zero or nil, drag_clamp and u32_fifty or nil, "%u ms") + -- [Port] ImGui.DragScalar("drag s64", ImGuiDataType.S64, s64_v, ...) -- 64-bit types not supported + -- [Port] ImGui.DragScalar("drag u64", ImGuiDataType.U64, u64_v, ...) -- 64-bit types not supported + s.f32_v = ImGui.DragScalar("drag float", 6 --[[ImGuiDataType.Float]], s.f32_v, 0.005, f32_zero, f32_one, "%f") + s.f32_v = ImGui.DragScalar("drag float log", 6 --[[ImGuiDataType.Float]], s.f32_v, 0.005, f32_zero, f32_one, "%f", 32 --[[ImGuiSliderFlags.Logarithmic]]) + s.f64_v = ImGui.DragScalar("drag double", 7 --[[ImGuiDataType.Double]], s.f64_v, 0.0005, f64_zero, nil, "%.10f grams") + s.f64_v = ImGui.DragScalar("drag double log",7 --[[ImGuiDataType.Double]], s.f64_v, 0.0005, f64_zero, f64_one, "0 < %.10f < 1", 32 --[[ImGuiSliderFlags.Logarithmic]]) + + IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders") + ImGui.SeparatorText("Sliders") + s.s8_v = ImGui.SliderScalar("slider s8 full", 0 --[[ImGuiDataType.S8]], s.s8_v, s8_min, s8_max, "%d") + s.u8_v = ImGui.SliderScalar("slider u8 full", 1 --[[ImGuiDataType.U8]], s.u8_v, u8_min, u8_max, "%u") + s.s16_v = ImGui.SliderScalar("slider s16 full", 2 --[[ImGuiDataType.S16]], s.s16_v, s16_min, s16_max, "%d") + s.u16_v = ImGui.SliderScalar("slider u16 full", 3 --[[ImGuiDataType.U16]], s.u16_v, u16_min, u16_max, "%u") + s.s32_v = ImGui.SliderScalar("slider s32 low", 4 --[[ImGuiDataType.S32]], s.s32_v, s32_zero, s32_fifty,"%d") + s.s32_v = ImGui.SliderScalar("slider s32 high", 4 --[[ImGuiDataType.S32]], s.s32_v, s32_hi_a, s32_hi_b, "%d") + s.s32_v = ImGui.SliderScalar("slider s32 full", 4 --[[ImGuiDataType.S32]], s.s32_v, s32_min, s32_max, "%d") + s.s32_v = ImGui.SliderScalar("slider s32 hex", 4 --[[ImGuiDataType.S32]], s.s32_v, s32_zero, s32_fifty, "0x%04X") + s.u32_v = ImGui.SliderScalar("slider u32 low", 5 --[[ImGuiDataType.U32]], s.u32_v, u32_zero, u32_fifty,"%u") + s.u32_v = ImGui.SliderScalar("slider u32 high", 5 --[[ImGuiDataType.U32]], s.u32_v, u32_hi_a, u32_hi_b, "%u") + s.u32_v = ImGui.SliderScalar("slider u32 full", 5 --[[ImGuiDataType.U32]], s.u32_v, u32_min, u32_max, "%u") + -- [Port] "slider s64 low" / "slider s64 high" / "slider s64 full" (ImGuiDataType.S64): 64-bit types not supported + -- [Port] "slider u64 low" / "slider u64 high" / "slider u64 full" (ImGuiDataType.U64): 64-bit types not supported + s.f32_v = ImGui.SliderScalar("slider float low", 6 --[[ImGuiDataType.Float]], s.f32_v, f32_zero, f32_one) + s.f32_v = ImGui.SliderScalar("slider float low log", 6 --[[ImGuiDataType.Float]], s.f32_v, f32_zero, f32_one, "%.10f", 32 --[[ImGuiSliderFlags.Logarithmic]]) + s.f32_v = ImGui.SliderScalar("slider float high", 6 --[[ImGuiDataType.Float]], s.f32_v, f32_lo_a, f32_hi_a, "%e") + s.f64_v = ImGui.SliderScalar("slider double low", 7 --[[ImGuiDataType.Double]], s.f64_v, f64_zero, f64_one, "%.10f grams") + s.f64_v = ImGui.SliderScalar("slider double low log",7 --[[ImGuiDataType.Double]], s.f64_v, f64_zero, f64_one, "%.10f", 32 --[[ImGuiSliderFlags.Logarithmic]]) + s.f64_v = ImGui.SliderScalar("slider double high", 7 --[[ImGuiDataType.Double]], s.f64_v, f64_lo_a, f64_hi_a, "%e grams") + + ImGui.SeparatorText("Sliders (reverse)") + s.s8_v = ImGui.SliderScalar("slider s8 reverse", 0 --[[ImGuiDataType.S8]], s.s8_v, s8_max, s8_min, "%d") + s.u8_v = ImGui.SliderScalar("slider u8 reverse", 1 --[[ImGuiDataType.U8]], s.u8_v, u8_max, u8_min, "%u") + s.s32_v = ImGui.SliderScalar("slider s32 reverse", 4 --[[ImGuiDataType.S32]], s.s32_v, s32_fifty, s32_zero, "%d") + s.u32_v = ImGui.SliderScalar("slider u32 reverse", 5 --[[ImGuiDataType.U32]], s.u32_v, u32_fifty, u32_zero, "%u") + -- [Port] "slider s64 reverse" / "slider u64 reverse": 64-bit types not supported + + IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs") + ImGui.SeparatorText("Inputs") + _, s.inputs_step = ImGui.Checkbox("Show step buttons", s.inputs_step) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, 512 --[[ImGuiInputTextFlags.ReadOnly]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", s.flags, 8192 --[[ImGuiInputTextFlags.ParseEmptyRefVal]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", s.flags, 16384 --[[ImGuiInputTextFlags.DisplayEmptyRefVal]]) + local inputs_step, flags = s.inputs_step, s.flags + s.s8_v = ImGui.InputScalar("input s8", 0 --[[ImGuiDataType.S8]], s.s8_v, inputs_step and s8_one or nil, nil, "%d", flags) + s.u8_v = ImGui.InputScalar("input u8", 1 --[[ImGuiDataType.U8]], s.u8_v, inputs_step and u8_one or nil, nil, "%u", flags) + s.s16_v = ImGui.InputScalar("input s16", 2 --[[ImGuiDataType.S16]], s.s16_v, inputs_step and s16_one or nil, nil, "%d", flags) + s.u16_v = ImGui.InputScalar("input u16", 3 --[[ImGuiDataType.U16]], s.u16_v, inputs_step and u16_one or nil, nil, "%u", flags) + s.s32_v = ImGui.InputScalar("input s32", 4 --[[ImGuiDataType.S32]], s.s32_v, inputs_step and s32_one or nil, nil, "%d", flags) + s.s32_v = ImGui.InputScalar("input s32 hex", 4 --[[ImGuiDataType.S32]], s.s32_v, inputs_step and s32_one or nil, nil, "%04X", flags) + s.u32_v = ImGui.InputScalar("input u32", 5 --[[ImGuiDataType.U32]], s.u32_v, inputs_step and u32_one or nil, nil, "%u", flags) + s.u32_v = ImGui.InputScalar("input u32 hex", 5 --[[ImGuiDataType.U32]], s.u32_v, inputs_step and u32_one or nil, nil, "%08X", flags) + -- [Port] ImGui.InputScalar("input s64", ImGuiDataType.S64, ...) -- 64-bit types not supported + -- [Port] ImGui.InputScalar("input u64", ImGuiDataType.U64, ...) -- 64-bit types not supported + s.f32_v = ImGui.InputScalar("input float", 6 --[[ImGuiDataType.Float]], s.f32_v, inputs_step and f32_one or nil, nil, nil, flags) + s.f64_v = ImGui.InputScalar("input double", 7 --[[ImGuiDataType.Double]], s.f64_v, inputs_step and f64_one or nil, nil, nil, flags) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDisableBlocks() +------------------------------------------------------------------------------- + +function DemoWindowWidgetsDisableBlocks(demo_data) + local _ + if ImGui.TreeNode("Disable Blocks") then + IMGUI_DEMO_MARKER("Widgets/Disable Blocks") + _, demo_data.DisableSections = ImGui.Checkbox("Disable entire section above", demo_data.DisableSections) + ImGui.SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections.") + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDragAndDrop() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsDragAndDrop = { + col1 = { 1.0, 0.0, 0.2 }, + col2 = { 0.4, 0.7, 0.0, 0.5 }, + mode = 0, + names = { -- 1-based + "Bobby", "Beatrice", "Betty", + "Brianna", "Barry", "Bernard", + "Bibi", "Blaine", "Bryn" + }, + item_names = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }, -- 1-based + col4 = ImVec4(1.0, 0.0, 0.2, 1.0), +} + +function DemoWindowWidgetsDragAndDrop() + if ImGui.TreeNode("Drag and Drop") then + local s = S.DemoWindowWidgetsDragAndDrop + IMGUI_DEMO_MARKER("Widgets/Drag and drop") + if ImGui.TreeNode("Drag and drop in standard widgets") then + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets") + -- ColorEdit widgets automatically act as drag source and drag target. + -- They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F + -- to allow your own widgets to use colors in their drag and drop interaction. + -- Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. + HelpMarker("You can drag from the color squares.") + ImGui.ColorEdit3("color 1", s.col1) + ImGui.ColorEdit4("color 2", s.col2) + ImGui.TreePop() + end + + if ImGui.TreeNode("Drag and drop to copy/swap items") then + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items") + local Mode_Copy, Mode_Move, Mode_Swap = 0, 1, 2 + if ImGui.RadioButtonEx("Copy", s.mode == Mode_Copy) then s.mode = Mode_Copy end ImGui.SameLine() + if ImGui.RadioButtonEx("Move", s.mode == Mode_Move) then s.mode = Mode_Move end ImGui.SameLine() + if ImGui.RadioButtonEx("Swap", s.mode == Mode_Swap) then s.mode = Mode_Swap end + local names = s.names + for n = 0, #names - 1 do + ImGui.PushID(n) + if (n % 3) ~= 0 then + ImGui.SameLine() + end + ImGui.Button(names[n + 1], ImVec2(60, 60)) + + -- Our buttons are both drag sources and drag targets here! + if ImGui.BeginDragDropSource(0 --[[ImGuiDragDropFlags.None]]) then + -- Set payload to carry the index of our item (could be anything) + ImGui.SetDragDropPayload("DND_DEMO_CELL", n, 4) -- [Port] sizeof(int) -> 4, payload carries the Lua value + + -- Display preview (could be anything, e.g. when dragging an image we could decide to display + -- the filename and a small preview of the image, etc.) + if s.mode == Mode_Copy then ImGui.Text("Copy %s", names[n + 1]) end + if s.mode == Mode_Move then ImGui.Text("Move %s", names[n + 1]) end + if s.mode == Mode_Swap then ImGui.Text("Swap %s", names[n + 1]) end + ImGui.EndDragDropSource() + end + if ImGui.BeginDragDropTarget() then + local payload = ImGui.AcceptDragDropPayload("DND_DEMO_CELL") + if payload then + assert(payload.DataSize == 4) + local payload_n = payload.Data + if s.mode == Mode_Copy then + names[n + 1] = names[payload_n + 1] + end + if s.mode == Mode_Move then + names[n + 1] = names[payload_n + 1] + names[payload_n + 1] = "" + end + if s.mode == Mode_Swap then + local tmp = names[n + 1] + names[n + 1] = names[payload_n + 1] + names[payload_n + 1] = tmp + end + end + ImGui.EndDragDropTarget() + end + ImGui.PopID() + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Drag to reorder items (simple)") then + IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)") + -- FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. + -- This code was always slightly faulty but in a way which was not easily noticeable. + -- Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue. + ImGui.PushItemFlag(32 --[[ImGuiItemFlags.AllowDuplicateId]], true) + + -- Simple reordering + HelpMarker( + "We don't use the drag and drop api at all here! " .. + "Instead we query when the item is held but not hovered, and order items accordingly.") + local item_names = s.item_names + for n = 0, #item_names - 1 do + local item = item_names[n + 1] + ImGui.Selectable(item) + + if ImGui.IsItemActive() and not ImGui.IsItemHovered() then + local n_next = n + ((ImGui.GetMouseDragDelta(0).y < 0.0) and -1 or 1) + if n_next >= 0 and n_next < #item_names then + item_names[n + 1] = item_names[n_next + 1] + item_names[n_next + 1] = item + ImGui.ResetMouseDragDelta() + end + end + end + + ImGui.PopItemFlag() + ImGui.TreePop() + end + + if ImGui.TreeNode("Tooltip at target location") then + IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location") + for n = 0, 1 do + -- Drop targets + ImGui.Button((n ~= 0) and "drop here##1" or "drop here##0") + if ImGui.BeginDragDropTarget() then + local drop_target_flags = bit32.bor(1024 --[[ImGuiDragDropFlags.AcceptBeforeDelivery]], 4096 --[[ImGuiDragDropFlags.AcceptNoPreviewTooltip]]) + local payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags) + if payload then + -- IM_UNUSED(payload) + ImGui.SetMouseCursor(10 --[[ImGuiMouseCursor.NotAllowed]]) + ImGui.SetTooltip("Cannot drop here!") + end + ImGui.EndDragDropTarget() + end + + -- Drop source + if n == 0 then + ImGui.ColorButton("drag me", s.col4) + end + + end + ImGui.TreePop() + end + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDragsAndSliders() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsDragsAndSliders = { + flags = ImGuiSliderFlags.None, + -- Drags + drag_f = 0.5, + drag_f4 = { 0.0, 0.0, 0.0, 0.0 }, + drag_i = 50, + -- Sliders + slider_f = 0.5, + slider_f4 = { 0.0, 0.0, 0.0, 0.0 }, + slider_i = 50, +} + +function DemoWindowWidgetsDragsAndSliders() + local _ + if ImGui.TreeNode("Drag/Slider Flags") then + local s = S.DemoWindowWidgetsDragsAndSliders + IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags") + -- Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", s.flags, 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ClampOnInput", s.flags, 512 --[[ImGuiSliderFlags.ClampOnInput]]) + ImGui.SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with Ctrl+Click. By default Ctrl+Click allows going out of bounds.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", s.flags, 1024 --[[ImGuiSliderFlags.ClampZeroRange]]) + ImGui.SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_Logarithmic", s.flags, 32 --[[ImGuiSliderFlags.Logarithmic]]) + ImGui.SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", s.flags, 64 --[[ImGuiSliderFlags.NoRoundToFormat]]) + ImGui.SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_NoInput", s.flags, 128 --[[ImGuiSliderFlags.NoInput]]) + ImGui.SameLine(); HelpMarker("Disable Ctrl+Click or Enter key allowing to input text directly into the widget.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_NoSpeedTweaks", s.flags, 2048 --[[ImGuiSliderFlags.NoSpeedTweaks]]) + ImGui.SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_WrapAround", s.flags, 256 --[[ImGuiSliderFlags.WrapAround]]) + ImGui.SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ColorMarkers", s.flags, 4096 --[[ImGuiSliderFlags.ColorMarkers]]) + local flags = s.flags + + -- Drags + ImGui.Text("Underlying float value: %f", s.drag_f) + s.drag_f = ImGui.DragFloat("DragFloat (0 -> 1)", s.drag_f, 0.005, 0.0, 1.0, "%.3f", flags) + s.drag_f = ImGui.DragFloat("DragFloat (0 -> +inf)", s.drag_f, 0.005, 0.0, 3.4028234663853e+38 --[[FLT_MAX]], "%.3f", flags) + s.drag_f = ImGui.DragFloat("DragFloat (-inf -> 1)", s.drag_f, 0.005, -3.4028234663853e+38 --[[FLT_MAX]], 1.0, "%.3f", flags) + s.drag_f = ImGui.DragFloat("DragFloat (-inf -> +inf)", s.drag_f, 0.005, -3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]], "%.3f", flags) + --ImGui.DragFloat("DragFloat (0 -> 0)", drag_f, 0.005, 0.0, 0.0, "%.3f", flags) -- To test ClampZeroRange + --ImGui.DragFloat("DragFloat (100 -> 100)", drag_f, 0.005, 100.0, 100.0, "%.3f", flags) + s.drag_i = ImGui.DragInt("DragInt (0 -> 100)", s.drag_i, 0.5, 0, 100, "%d", flags) + ImGui.DragFloat4("DragFloat4 (0 -> 1)", s.drag_f4, 0.005, 0.0, 1.0, "%.3f", flags) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers. + + -- Sliders + local flags_for_sliders = bit32.band(flags, bit32.bnot(256 --[[ImGuiSliderFlags.WrapAround]])) + ImGui.Text("Underlying float value: %f", s.slider_f) + s.slider_f = ImGui.SliderFloat("SliderFloat (0 -> 1)", s.slider_f, 0.0, 1.0, "%.3f", flags_for_sliders) + s.slider_i = ImGui.SliderInt("SliderInt (0 -> 100)", s.slider_i, 0, 100, "%d", flags_for_sliders) + ImGui.SliderFloat4("SliderFloat4 (0 -> 1)", s.slider_f4, 0.0, 1.0, "%.3f", flags_for_sliders) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers. -- [Port] flags_for_sliders: upstream passes `flags`, which trips SliderScalar's WrapAround assert + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsFonts() +------------------------------------------------------------------------------- + +function DemoWindowWidgetsFonts() + if ImGui.TreeNode("Fonts") then + IMGUI_DEMO_MARKER("Widgets/Fonts") + local atlas = ImGui.GetIO().Fonts + ImGui.ShowFontAtlas(atlas) + -- FIXME-NEWATLAS: Provide a demo to add/create a procedural font? + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsImages() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsImages = { + image_viewer = ExampleImageViewerData(), + pressed_count = 0, +} +function DemoWindowWidgetsImages() + local s = S.DemoWindowWidgetsImages + if ImGui.TreeNode("Images") then + IMGUI_DEMO_MARKER("Widgets/Images") + local io = ImGui.GetIO() + ImGui.TextWrapped( + "Below we are displaying the font texture (which is the only texture we have access to in this demo). " .. + "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " .. + "Hover the texture for a zoomed view!") + + -- Below we are displaying the font texture because it is the only texture we have access to inside the demo! + -- Read description about ImTextureID/ImTextureRef and FAQ for details about texture identifiers. + -- If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top + -- of their respective source file to specify what they are using as texture identifier, for example: + -- - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. + -- - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. + -- So with the DirectX11 backend, you call ImGui.Image() with a 'ID3D11ShaderResourceView*' cast to ImTextureID. + -- - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers + -- to ImGui.Image(), and gather width/height through your own functions, etc. + -- - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, + -- it will help you debug issues if you are confused about it. + -- - Consider using the lower-level ImDrawList::AddImage() API, via ImGui.GetWindowDrawList():AddImage(). + -- - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md + -- - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + + -- Grab the current texture identifier used by the font atlas. + local atlas = io.Fonts + local my_tex_id = atlas.TexRef + local my_tex_w = atlas.TexData.Width -- Regular user code should never have to care about TexData-> fields, but since we want to display the entire texture here, we pull Width/Height from it. + local my_tex_h = atlas.TexData.Height + ImGui.Text("%.0fx%.0f", my_tex_w, my_tex_h) + + -- Basic drawing + ImGui.SeparatorText("Image()/ImageWithBg() function") + local uv_min = ImVec2(0.0, 0.0) -- Top-left + local uv_max = ImVec2(1.0, 1.0) -- Lower-right + ImGui.PushStyleVar(24 --[[ImGuiStyleVar.ImageBorderSize]], ImMax(1.0, ImGui.GetStyle().ImageBorderSize)) + ImGui.ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0, 0.0, 0.0, 1.0)) + ImGui.PopStyleVar() + + -- Fancy widget + ImGui.SeparatorText("Interactive Image Viewer") + local canvas_size = ImVec2(ImGui.GetContentRegionAvail().x, my_tex_h * 2.0) + ExampleImageViewer_DrawOptions(s.image_viewer) + ExampleImageViewer_DrawCanvas(s.image_viewer, canvas_size, my_tex_id, math.floor(my_tex_w), math.floor(my_tex_h)) + + IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons") + ImGui.SeparatorText("Textured Buttons") + ImGui.TextWrapped("And now some textured buttons..") + for i = 0, 7 do + -- UV coordinates are often (0.0, 0.0) and (1.0, 1.0) to display an entire textures. + -- Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation. + -- Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + ImGui.PushID(i) + if i > 0 then + ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(i - 1.0, i - 1.0)) + end + local size = ImVec2(32.0, 32.0) -- Size of the image we want to make visible + local uv0 = ImVec2(0.0, 0.0) -- UV coordinates for lower-left + local uv1 = ImVec2(32.0 / my_tex_w, 32.0 / my_tex_h) -- UV coordinates for (32,32) in our texture + local bg_col = ImVec4(0.0, 0.0, 0.0, 1.0) -- Black background + local tint_col = ImVec4(1.0, 1.0, 1.0, 1.0) -- No tint + if ImGui.ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col) then + s.pressed_count = s.pressed_count + 1 + end + if i > 0 then + ImGui.PopStyleVar() + end + ImGui.PopID() + ImGui.SameLine() + end + ImGui.NewLine() + ImGui.Text("Pressed %d times.", s.pressed_count) + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsListBoxes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsListBoxes = { + item_selected_idx = 0, -- Here we store our selected data as an index. + item_highlight = false, +} +function DemoWindowWidgetsListBoxes() + local s = S.DemoWindowWidgetsListBoxes + if ImGui.TreeNode("List Boxes") then + IMGUI_DEMO_MARKER("Widgets/List Boxes") + -- BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() + -- using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. + -- You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild() + -- to always be called (inconsistent with BeginListBox()/EndListBox()). + + -- Using the generic BeginListBox() API, you have full control over how to display the combo contents. + -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + -- stored in the object itself, etc.) + local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } + -- static int item_selected_idx = 0; // Here we store our selected data as an index. + + local item_highlighted_idx = -1 -- Here we store our highlighted data as an index. + _, s.item_highlight = ImGui.Checkbox("Highlight hovered item in second listbox", s.item_highlight) + + if ImGui.BeginListBox("listbox 1") then + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + if ImGui.Selectable(items[n + 1], is_selected) then + s.item_selected_idx = n + end + + if s.item_highlight and ImGui.IsItemHovered() then + item_highlighted_idx = n + end + + -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if is_selected then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndListBox() + end + ImGui.SameLine(); HelpMarker("Here we are sharing selection state between both boxes.") + + -- Custom size: use all width, 5 items tall + ImGui.Text("Full-width:") + if ImGui.BeginListBox("##listbox 2", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 5 * ImGui.GetTextLineHeightWithSpacing())) then + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + local flags = 0 + if item_highlighted_idx == n then flags = 32 --[[ImGuiSelectableFlags.Highlight]] end + if ImGui.Selectable(items[n + 1], is_selected, flags) then + s.item_selected_idx = n + end + + -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if is_selected then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndListBox() + end + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsLiveEdit() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsLiveEdit = { + str = ImGui.NewTextBuffer("", 32), + i = 0, + f = 0.0, +} +function DemoWindowWidgetsLiveEdit(demo_data) + local s = S.DemoWindowWidgetsLiveEdit + if ImGui.TreeNode("Live Edit Flags") then + IMGUI_DEMO_MARKER("Widgets/Live Edit Flags") + + ImGui.TextWrapped("Select whether to apply keyboard edits to backing variables _while_ typing.") + + _, demo_data.LiveEditOverride = ImGui.Checkbox("Override Live Edit Flags in Demo Window", demo_data.LiveEditOverride) + if not demo_data.LiveEditOverride then + demo_data.LiveEditFlags = ImGui.GetItemFlags() + end + + ImGui.BeginDisabled(demo_data.LiveEditOverride == false) + ImGui.Indent() + _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputText", demo_data.LiveEditFlags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) + _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputScalar", demo_data.LiveEditFlags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) + ImGui.Unindent() ImGui.EndDisabled() - ImGui.TreePop() - ImGui.Spacing() - end + ImGui.Text("Try typing '123' and seeing effect on backing value:") + ImGui.InputText("str", s.str, 32) + ImGui.Text("Backing value: \"%s\"", ImGui.TextBufferToString(s.str)) + s.i = ImGui.InputInt("int", s.i, 0, 0) + ImGui.Text("Backing value: %d", s.i) + s.f = ImGui.SliderFloat("float", s.f, 0.0, 100.0) + ImGui.Text("Backing value: %f", s.f) - if ImGui.TreeNode("Style, Fonts") then - IMGUI_DEMO_MARKER("Configuration/Style, Fonts") - _, demo_data.ShowStyleEditor = ImGui.Checkbox("Style Editor", demo_data.ShowStyleEditor) + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsMixedValues() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsMixedValues = { + use_liveedit = false, + items = { 12.0, 0.0, 0.0 }, +} +function DemoWindowWidgetsMixedValues() + local s = S.DemoWindowWidgetsMixedValues + if ImGui.TreeNode("Mixed Values") then + -- This is designed for advanced property editors which are generally reusable and data-driven. + HelpMarker("Using ImGuiItemFlags_MixedValue.") + + local items = s.items + local item_ref = 1 -- [Port] index of the reference item (C++: float* item_ref = &items[0]) + _, s.use_liveedit = ImGui.Checkbox("ImGuiItemFlags_LiveEditOnInput", s.use_liveedit) + + ImGui.SeparatorText("Scalar/Text Widgets") + local is_mixed = items[1] ~= items[2] or items[1] ~= items[3] + + -- Demonstrate Drags, Sliders, Inputs + ImGui.PushItemFlag(384 --[[ImGuiItemFlags.LiveEditOnInput]], s.use_liveedit) + ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], is_mixed) + local edited = false + local changed + items[item_ref], changed = ImGui.DragFloat("DragFloat", items[item_ref]); edited = edited or changed + items[item_ref], changed = ImGui.SliderFloat("SliderFloat", items[item_ref], 0.0, 100.0); edited = edited or changed + items[item_ref], changed = ImGui.InputFloat("InputFloat", items[item_ref], 1.0); edited = edited or changed + if edited then + for n = 1, #items do + if n ~= item_ref then + items[n] = items[item_ref] + end + end + end + ImGui.PopItemFlag() + + ImGui.Text("Underlying data:") + items[1] = ImGui.InputFloat("item 0 (ref)", items[1]) + items[2] = ImGui.InputFloat("item 1", items[2]) + items[3] = ImGui.InputFloat("item 2", items[3]) + ImGui.PopItemFlag() + + -- Demonstrate Checkbox(), RadioButton(), Combo(), ColorEdit4() + ImGui.SeparatorText("Others Widgets") + ImGui.Text("(note: edits are not applied in this demo)") -- <-- Would need more state tracking. + local b_on, b_off = true, false + _, b_on = ImGui.Checkbox("Checkbox On", b_on) + _, b_off = ImGui.Checkbox("Checkbox Off", b_off) + ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], true) + _, b_off = ImGui.Checkbox("Checkbox Mixed", b_off) + ImGui.RadioButtonEx("RadioButton Mixed", true) -- [Port] RadioButton(label, bool active) overload is RadioButtonEx ImGui.SameLine() - HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.") - ImGui.TreePop() - ImGui.Spacing() - end + ImGui.RadioButtonEx("RadioButton Mixed##2", true) -- Showing 2 radio buttons makes the example more clear + local combo_idx = 0 + combo_idx = ImGui.Combo("Combo", combo_idx, "One\0Two\0Three\0") + local color = ImVec4(0.5, 0.5, 0.5, 0.5) + ImGui.ColorEdit4("ColorEdit4", color) + ImGui.PopItemFlag() - if ImGui.TreeNode("Capture/Logging") then - IMGUI_DEMO_MARKER("Configuration/Capture, Logging") - HelpMarker( - "The logging API redirects all text output so you can easily capture the content of " .. - "a window or a block. Tree nodes can be automatically expanded.\n" .. - "Try opening any of the contents below in this window and then click one of the \"Log To\" button.") - if ImGui.LogButtons then - ImGui.LogButtons() - else - DemoNotPorted("LogButtons") + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsMultiComponents() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsMultiComponents = { + vec4f = { 0.10, 0.20, 0.30, 0.44 }, + vec4i = { 1, 5, 100, 255 }, + flags = 0, + begin = 10, ["end"] = 90, + begin_i = 100, end_i = 1000, +} +function DemoWindowWidgetsMultiComponents() + local s = S.DemoWindowWidgetsMultiComponents + if ImGui.TreeNode("Multi-component Widgets") then + IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets") + local vec4f = s.vec4f + local vec4i = s.vec4i + + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ColorMarkers", s.flags, 4096 --[[ImGuiSliderFlags.ColorMarkers]]) -- Only passing this to Drag/Sliders + local flags = s.flags + + ImGui.SeparatorText("2-wide") + ImGui.InputFloat2("input float2", vec4f) + ImGui.InputInt2("input int2", vec4i) + ImGui.DragFloat2("drag float2", vec4f, 0.01, 0.0, 1.0, nil, flags) + ImGui.DragInt2("drag int2", vec4i, 1, 0, 255, nil, flags) + ImGui.SliderFloat2("slider float2", vec4f, 0.0, 1.0, nil, flags) + ImGui.SliderInt2("slider int2", vec4i, 0, 255, nil, flags) + + ImGui.SeparatorText("3-wide") + ImGui.InputFloat3("input float3", vec4f) + ImGui.InputInt3("input int3", vec4i) + ImGui.DragFloat3("drag float3", vec4f, 0.01, 0.0, 1.0, nil, flags) + ImGui.DragInt3("drag int3", vec4i, 1, 0, 255, nil, flags) + ImGui.SliderFloat3("slider float3", vec4f, 0.0, 1.0, nil, flags) + ImGui.SliderInt3("slider int3", vec4i, 0, 255, nil, flags) + + ImGui.SeparatorText("4-wide") + ImGui.InputFloat4("input float4", vec4f) + ImGui.InputInt4("input int4", vec4i) + ImGui.DragFloat4("drag float4", vec4f, 0.01, 0.0, 1.0, nil, flags) + ImGui.DragInt4("drag int4", vec4i, 1, 0, 255, nil, flags) + ImGui.SliderFloat4("slider float4", vec4f, 0.0, 1.0, nil, flags) + ImGui.SliderInt4("slider int4", vec4i, 0, 255, nil, flags) + + ImGui.SeparatorText("Ranges") + s.begin, s["end"] = ImGui.DragFloatRange2("range float", s.begin, s["end"], 0.25, 0.0, 100.0, "Min: %.1f %%", "Max: %.1f %%", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + s.begin_i, s.end_i = ImGui.DragIntRange2("range int", s.begin_i, s.end_i, 5, 0, 1000, "Min: %d units", "Max: %d units") + s.begin_i, s.end_i = ImGui.DragIntRange2("range int (no bounds)", s.begin_i, s.end_i, 5, 0, 0, "Min: %d units", "Max: %d units") + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsPlotting() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsPlotting = { + animate = true, + arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, + values = {}, -- 90 zeros, filled below + values_offset = 0, + refresh_time = 0.0, + phase = 0.0, + func_type = 0, display_count = 70, +} +for n = 1, 90 do S.DemoWindowWidgetsPlotting.values[n] = 0.0 end + +-- Use functions to generate output +-- [Port] struct Funcs hoisted out of the function to avoid per-frame closures. +-- Plot getters receive a 1-based index in this port: convert back to upstream's 0-based i. +local DemoPlottingFuncs = { + Sin = function(_, idx) local i = idx - 1; return math.sin(i * 0.1) end, + Saw = function(_, idx) local i = idx - 1; if bit32.band(i, 1) ~= 0 then return 1.0 end return -1.0 end, +} + +function DemoWindowWidgetsPlotting() + local s = S.DemoWindowWidgetsPlotting + -- Plot/Graph widgets are not very good. + -- Consider using a third-party library such as ImPlot: https://github.com/epezent/implot + -- (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) + if ImGui.TreeNode("Plotting") then + IMGUI_DEMO_MARKER("Widgets/Plotting") + ImGui.Text("Need better plotting and graphing? Consider using ImPlot:") + ImGui.TextLinkOpenURL("https://github.com/epezent/implot") + ImGui.Separator() + + _, s.animate = ImGui.Checkbox("Animate", s.animate) + + -- Plot as lines and plot as histogram + local arr = s.arr + ImGui.PlotLines("Frame Times", arr, nil, #arr) + ImGui.PlotHistogram("Histogram", arr, nil, #arr, 0, nil, 0.0, 1.0, ImVec2(0, 80.0)) + -- ImGui.SameLine(); HelpMarker("Consider using ImPlot instead!") + + -- Fill an array of contiguous float values to plot + -- Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float + -- and the sizeof() of your structure in the "stride" parameter. + local values = s.values + if not s.animate or s.refresh_time == 0.0 then + s.refresh_time = ImGui.GetTime() + end + while s.refresh_time < ImGui.GetTime() do -- Create data at fixed 60 Hz rate for the demo + values[s.values_offset + 1] = math.cos(s.phase) + s.values_offset = (s.values_offset + 1) % #values + s.phase = s.phase + 0.10 * s.values_offset + s.refresh_time = s.refresh_time + 1.0 / 60.0 end - HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.") - if ImGui.Button("Copy \"Hello, world!\" to clipboard") then - if ImGui.LogToClipboard then - ImGui.LogToClipboard() - ImGui.LogText("Hello, world!") - ImGui.LogFinish() - else - ImGui.SetClipboardText("Hello, world!") -- internal clipboard only on Roblox + -- Plots can display overlay texts + -- (in this example, we will display an average value) + do + local average = 0.0 + for n = 0, #values - 1 do + average = average + values[n + 1] end + average = average / #values + local overlay = string.format("avg %f", average) + ImGui.PlotLines("Lines", values, nil, #values, s.values_offset, overlay, -1.0, 1.0, ImVec2(0, 80.0)) + end + + -- Use functions to generate output + -- FIXME: This is actually VERY awkward because current plot API only pass in indices. + -- We probably want an API passing floats and user provide sample rate/count. + local Funcs = DemoPlottingFuncs + ImGui.SeparatorText("Functions") + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.func_type = ImGui.Combo("func", s.func_type, "Sin\0Saw\0") + ImGui.SameLine() + s.display_count = ImGui.SliderInt("Sample count", s.display_count, 1, 400) + local func = Funcs.Saw + if s.func_type == 0 then func = Funcs.Sin end + ImGui.PlotLines("Lines##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) + ImGui.PlotHistogram("Histogram##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsProgressBars() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsProgressBars = { + progress_accum = 0.0, progress_dir = 1.0, +} +function DemoWindowWidgetsProgressBars() + local s = S.DemoWindowWidgetsProgressBars + if ImGui.TreeNode("Progress Bars") then + IMGUI_DEMO_MARKER("Widgets/Progress Bars") + -- Animate a simple progress bar + s.progress_accum = s.progress_accum + s.progress_dir * 0.4 * ImGui.GetIO().DeltaTime + if s.progress_accum >= 1.1 then s.progress_accum = 1.1; s.progress_dir = s.progress_dir * -1.0 end + if s.progress_accum <= -0.1 then s.progress_accum = -0.1; s.progress_dir = s.progress_dir * -1.0 end + + local progress = ImClamp(s.progress_accum, 0.0, 1.0) + + -- Typically we would use ImVec2(-1.0,0.0) or ImVec2(-FLT_MIN,0.0) to use all available width, + -- or ImVec2(width,0.0) for a specified width. ImVec2(0.0,0.0) uses ItemWidth. + ImGui.ProgressBar(progress, ImVec2(0.0, 0.0)) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + ImGui.Text("Progress Bar") + + local buf = string.format("%d/%d", math.floor(progress * 1753), 1753) + ImGui.ProgressBar(progress, ImVec2(0.0, 0.0), buf) + + -- Pass an animated negative value, e.g. -1.0 * ImGui.GetTime() is the recommended value. + -- Adjust the factor if you want to adjust the animation speed. + ImGui.ProgressBar(-1.0 * ImGui.GetTime(), ImVec2(0.0, 0.0), "Searching..") + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + ImGui.Text("Indeterminate") + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsQueryingStatuses() +------------------------------------------------------------------------------- + +-- [Port] C++ passes bools to "%d"; string.format needs numbers. +local function DemoBoolToInt(b) if b then return 1 end return 0 end + +S.DemoWindowWidgetsQueryingStatuses = { + item_type = 4, + item_disabled = false, + item_mixedvalue = false, + liveedit_flags_override = false, + liveedit_flags = 0, + b = false, + col4f = { 1.0, 0.5, 0.0, 1.0 }, + str = ImGui.NewTextBuffer("", 16), + current = 1, -- item_type == 14 + current_2 = 1, -- item_type == 15 + embed_all_inside_a_child_window = false, + test_window = false, +} +function DemoWindowWidgetsQueryingStatuses() + local s = S.DemoWindowWidgetsQueryingStatuses + local B = DemoBoolToInt + if ImGui.TreeNode("Querying Item Status (Edited/Active/Hovered etc.)") then + IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)") + -- Select an item type + local item_names = + { + "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", + "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" + } + s.item_type = ImGui.Combo("Item Type", s.item_type, item_names, #item_names, #item_names) + ImGui.SameLine() + HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().") + _, s.item_disabled = ImGui.Checkbox("Item Disabled", s.item_disabled) + _, s.item_mixedvalue = ImGui.Checkbox("Item MixedValue", s.item_mixedvalue) + _, s.liveedit_flags_override = ImGui.Checkbox("Override LiveEdit:", s.liveedit_flags_override) + ImGui.SameLine() + if not s.liveedit_flags_override then + s.liveedit_flags = ImGui.GetItemFlags() + end + ImGui.BeginDisabled(s.liveedit_flags_override == false) + _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInput", s.liveedit_flags, 384 --[[ImGuiItemFlags.LiveEditOnInput]]) + ImGui.SameLine() + _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputText", s.liveedit_flags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) + ImGui.SameLine() + _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputScalar", s.liveedit_flags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) + ImGui.EndDisabled() + if s.liveedit_flags_override then + ImGui.PushItemFlag(128 --[[ImGuiItemFlags.LiveEditOnInputText]], bit32.band(s.liveedit_flags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) ~= 0) + ImGui.PushItemFlag(256 --[[ImGuiItemFlags.LiveEditOnInputScalar]], bit32.band(s.liveedit_flags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) ~= 0) + end + + -- Submit selected items so we can query their status in the code following it. + local ret = false + local item_type = s.item_type + local col4f = s.col4f + if s.item_disabled then + ImGui.BeginDisabled(true) + end + if s.item_mixedvalue then + ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], true) + end + if item_type == 0 then ImGui.Text("ITEM: Text") end -- Testing text items with no identifier/interaction + if item_type == 1 then ret = ImGui.Button("ITEM: Button") end -- Testing button + if item_type == 2 then ImGui.PushItemFlag(8 --[[ImGuiItemFlags.ButtonRepeat]], true); ret = ImGui.Button("ITEM: Button"); ImGui.PopItemFlag() end -- Testing button (with repeater) + if item_type == 3 then ret, s.b = ImGui.Checkbox("ITEM: Checkbox", s.b) end -- Testing checkbox + if item_type == 4 then col4f[1], ret = ImGui.SliderFloat("ITEM: SliderFloat", col4f[1], 0.0, 1.0) end -- Testing basic item + if item_type == 5 then ret = ImGui.InputText("ITEM: InputText", s.str, 16) end -- Testing input text (which handles tabbing) + if item_type == 6 then ret = ImGui.InputTextMultiline("ITEM: InputTextMultiline", s.str, 16) end -- Testing input text (which uses a child window) + if item_type == 7 then col4f[1], ret = ImGui.InputFloat("ITEM: InputFloat", col4f[1], 1.0) end -- Testing +/- buttons on scalar input + if item_type == 8 then ret = ImGui.InputFloat3("ITEM: InputFloat3", col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) + if item_type == 9 then ret = ImGui.ColorEdit4("ITEM: ColorEdit4", col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) + if item_type == 10 then ret = ImGui.Selectable("ITEM: Selectable") end -- Testing selectable item + if item_type == 11 then ret = ImGui.MenuItem("ITEM: MenuItem") end -- Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) + if item_type == 12 then ret = ImGui.TreeNode("ITEM: TreeNode"); if ret then ImGui.TreePop() end end -- Testing tree node + if item_type == 13 then ret = ImGui.TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", bit32.bor(64 --[[ImGuiTreeNodeFlags.OpenOnDoubleClick]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]])) end -- Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if item_type == 14 then local items = { "Apple", "Banana", "Cherry", "Kiwi" }; s.current, ret = ImGui.Combo("ITEM: Combo", s.current, items, #items) end + if item_type == 15 then local items = { "Apple", "Banana", "Cherry", "Kiwi" }; s.current_2, ret = ImGui.ListBox("ITEM: ListBox", s.current_2, items, #items, #items) end + + local hovered_delay_none = ImGui.IsItemHovered() + local hovered_delay_stationary = ImGui.IsItemHovered(8192 --[[ImGuiHoveredFlags.Stationary]]) + local hovered_delay_short = ImGui.IsItemHovered(32768 --[[ImGuiHoveredFlags.DelayShort]]) + local hovered_delay_normal = ImGui.IsItemHovered(65536 --[[ImGuiHoveredFlags.DelayNormal]]) + local hovered_delay_tooltip = ImGui.IsItemHovered(4096 --[[ImGuiHoveredFlags.ForTooltip]]) -- = Normal + Stationary + + -- Display the values of IsItemHovered() and other common item state functions. + -- Note that the ImGuiHoveredFlags_XXX flags can be combined. + -- Because BulletText is an item itself and that would affect the output of IsItemXXX functions, + -- we query every state in a single call to avoid storing them and to simplify the code. + ImGui.BulletText( + "Return value = %d\n" .. + "IsItemFocused() = %d\n" .. + "IsItemHovered() = %d\n" .. + "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" .. + "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" .. + "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n" .. + "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n" .. + "IsItemHovered(_AllowWhenDisabled) = %d\n" .. + "IsItemHovered(_RectOnly) = %d\n" .. + "IsItemActive() = %d\n" .. + "IsItemEdited() = %d\n" .. + "IsItemActivated() = %d\n" .. + "IsItemDeactivated() = %d\n" .. + "IsItemDeactivatedAfterEdit() = %d\n" .. + "IsItemVisible() = %d\n" .. + "IsItemClicked() = %d\n" .. + "IsItemToggledOpen() = %d\n" .. + "GetItemRectMin() = (%.1f, %.1f)\n" .. + "GetItemRectMax() = (%.1f, %.1f)\n" .. + "GetItemRectSize() = (%.1f, %.1f)", + B(ret), + B(ImGui.IsItemFocused()), + B(ImGui.IsItemHovered()), + B(ImGui.IsItemHovered(32 --[[ImGuiHoveredFlags.AllowWhenBlockedByPopup]])), + B(ImGui.IsItemHovered(128 --[[ImGuiHoveredFlags.AllowWhenBlockedByActiveItem]])), + B(ImGui.IsItemHovered(256 --[[ImGuiHoveredFlags.AllowWhenOverlappedByItem]])), + B(ImGui.IsItemHovered(512 --[[ImGuiHoveredFlags.AllowWhenOverlappedByWindow]])), + B(ImGui.IsItemHovered(1024 --[[ImGuiHoveredFlags.AllowWhenDisabled]])), + B(ImGui.IsItemHovered(928 --[[ImGuiHoveredFlags.RectOnly]])), + B(ImGui.IsItemActive()), + B(ImGui.IsItemEdited()), + B(ImGui.IsItemActivated()), + B(ImGui.IsItemDeactivated()), + B(ImGui.IsItemDeactivatedAfterEdit()), + B(ImGui.IsItemVisible()), + B(ImGui.IsItemClicked()), + B(ImGui.IsItemToggledOpen()), + ImGui.GetItemRectMin().x, ImGui.GetItemRectMin().y, + ImGui.GetItemRectMax().x, ImGui.GetItemRectMax().y, + ImGui.GetItemRectSize().x, ImGui.GetItemRectSize().y + ) + ImGui.BulletText( + "with Hovering Delay or Stationary test:\n" .. + "IsItemHovered() = %d\n" .. + "IsItemHovered(_Stationary) = %d\n" .. + "IsItemHovered(_DelayShort) = %d\n" .. + "IsItemHovered(_DelayNormal) = %d\n" .. + "IsItemHovered(_Tooltip) = %d", + B(hovered_delay_none), B(hovered_delay_stationary), B(hovered_delay_short), B(hovered_delay_normal), B(hovered_delay_tooltip)) + + if s.liveedit_flags_override then + ImGui.PopItemFlag() + ImGui.PopItemFlag() + end + if s.item_mixedvalue then + ImGui.PopItemFlag() + end + if s.item_disabled then + ImGui.EndDisabled() + end + + local buf = ImGui.NewTextBuffer("", 1) + ImGui.InputText("unused", buf, 1, 512 --[[ImGuiInputTextFlags.ReadOnly]]) + ImGui.SameLine() + HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.") + + ImGui.TreePop() + end + + if ImGui.TreeNode("Querying Window Status (Focused/Hovered etc.)") then + IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)") + _, s.embed_all_inside_a_child_window = ImGui.Checkbox("Embed everything inside a child window for testing _RootWindow flag.", s.embed_all_inside_a_child_window) + if s.embed_all_inside_a_child_window then + ImGui.BeginChild("outer_child", ImVec2(0, ImGui.GetFontSize() * 20.0), 1 --[[ImGuiChildFlags.Borders]]) + end + + -- Testing IsWindowFocused() function with its various flags. + ImGui.BulletText( + "IsWindowFocused() = %d\n" .. + "IsWindowFocused(_ChildWindows) = %d\n" .. + "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" .. + "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n" .. + "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" .. + "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowFocused(_RootWindow) = %d\n" .. + "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowFocused(_AnyWindow) = %d\n", + B(ImGui.IsWindowFocused()), + B(ImGui.IsWindowFocused(1 --[[ImGuiFocusedFlags.ChildWindows]])), + B(ImGui.IsWindowFocused(bit32.bor(1 --[[ImGuiFocusedFlags.ChildWindows]], 8 --[[ImGuiFocusedFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowFocused(bit32.bor(1 --[[ImGuiFocusedFlags.ChildWindows]], 16 --[[ImGuiFocusedFlags.DockHierarchy]]))), + B(ImGui.IsWindowFocused(bit32.bor(1 --[[ImGuiFocusedFlags.ChildWindows]], 2 --[[ImGuiFocusedFlags.RootWindow]]))), + B(ImGui.IsWindowFocused(bit32.bor(1 --[[ImGuiFocusedFlags.ChildWindows]], 2 --[[ImGuiFocusedFlags.RootWindow]], 8 --[[ImGuiFocusedFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowFocused(bit32.bor(1 --[[ImGuiFocusedFlags.ChildWindows]], 2 --[[ImGuiFocusedFlags.RootWindow]], 16 --[[ImGuiFocusedFlags.DockHierarchy]]))), + B(ImGui.IsWindowFocused(2 --[[ImGuiFocusedFlags.RootWindow]])), + B(ImGui.IsWindowFocused(bit32.bor(2 --[[ImGuiFocusedFlags.RootWindow]], 8 --[[ImGuiFocusedFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowFocused(bit32.bor(2 --[[ImGuiFocusedFlags.RootWindow]], 16 --[[ImGuiFocusedFlags.DockHierarchy]]))), + B(ImGui.IsWindowFocused(4 --[[ImGuiFocusedFlags.AnyWindow]]))) + + -- Testing IsWindowHovered() function with its various flags. + ImGui.BulletText( + "IsWindowHovered() = %d\n" .. + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" .. + "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" .. + "IsWindowHovered(_ChildWindows) = %d\n" .. + "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" .. + "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowHovered(_RootWindow) = %d\n" .. + "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" .. + "IsWindowHovered(_AnyWindow) = %d\n" .. + "IsWindowHovered(_Stationary) = %d\n", + B(ImGui.IsWindowHovered()), + B(ImGui.IsWindowHovered(32 --[[ImGuiHoveredFlags.AllowWhenBlockedByPopup]])), + B(ImGui.IsWindowHovered(128 --[[ImGuiHoveredFlags.AllowWhenBlockedByActiveItem]])), + B(ImGui.IsWindowHovered(1 --[[ImGuiHoveredFlags.ChildWindows]])), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 8 --[[ImGuiHoveredFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 16 --[[ImGuiHoveredFlags.DockHierarchy]]))), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 2 --[[ImGuiHoveredFlags.RootWindow]]))), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 2 --[[ImGuiHoveredFlags.RootWindow]], 8 --[[ImGuiHoveredFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 2 --[[ImGuiHoveredFlags.RootWindow]], 16 --[[ImGuiHoveredFlags.DockHierarchy]]))), + B(ImGui.IsWindowHovered(2 --[[ImGuiHoveredFlags.RootWindow]])), + B(ImGui.IsWindowHovered(bit32.bor(2 --[[ImGuiHoveredFlags.RootWindow]], 8 --[[ImGuiHoveredFlags.NoPopupHierarchy]]))), + B(ImGui.IsWindowHovered(bit32.bor(2 --[[ImGuiHoveredFlags.RootWindow]], 16 --[[ImGuiHoveredFlags.DockHierarchy]]))), + B(ImGui.IsWindowHovered(bit32.bor(1 --[[ImGuiHoveredFlags.ChildWindows]], 32 --[[ImGuiHoveredFlags.AllowWhenBlockedByPopup]]))), + B(ImGui.IsWindowHovered(4 --[[ImGuiHoveredFlags.AnyWindow]])), + B(ImGui.IsWindowHovered(8192 --[[ImGuiHoveredFlags.Stationary]]))) + + ImGui.BeginChild("child", ImVec2(0, 50), 1 --[[ImGuiChildFlags.Borders]]) + ImGui.Text("This is another child window for testing the _ChildWindows flag.") + ImGui.EndChild() + if s.embed_all_inside_a_child_window then + ImGui.EndChild() + end + + -- Calling IsItemHovered() after begin returns the hovered status of the title bar. + -- This is useful in particular if you want to create a context menu associated to the title bar of a window. + -- This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties). + _, s.test_window = ImGui.Checkbox("Hovered/Active tests after Begin() for title bar testing", s.test_window) + if s.test_window then + -- FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. + -- Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? + s.test_window = ImGui.Begin("Title bar Hovered/Active tests", s.test_window) + if ImGui.BeginPopupContextItem() then -- <-- This is using IsItemHovered() + if ImGui.MenuItem("Close") then s.test_window = false end + ImGui.EndPopup() + end + ImGui.Text( + "IsItemHovered() after begin = %d (== is title bar hovered)\n" .. + "IsItemActive() after begin = %d (== is window being clicked/moved)\n", + B(ImGui.IsItemHovered()), B(ImGui.IsItemActive())) + ImGui.End() + end + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsSelectables() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsSelectables = { + selection = { false, true, false, false, false }, -- Basic + selected_multi = { false, false, false }, -- Multiple items on the same line (1) + checked = { false, false, false, false, false }, -- Multiple items on the same line (2) + selected_n = 0, + selected_tables = { false, false, false, false, false, false, false, false, false, false }, -- In Tables + selected_grid = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }, -- Grid + selected_align = { true, false, true, false, true, false, true, false, true }, -- Alignment +} +-- [Port] The Selectable(label, bool* p_selected) overload doesn't exist in this port (Selectable returns pressed, selected +-- without toggling): written as `if ImGui.Selectable(label, sel) then sel = not sel end`. +function DemoWindowWidgetsSelectables() + local s = S.DemoWindowWidgetsSelectables + -- ImGui.SetNextItemOpen(true, ImGuiCond.Once) + if ImGui.TreeNode("Selectables") then + IMGUI_DEMO_MARKER("Widgets/Selectables") + -- Selectable() has 2 overloads: + -- - The one taking "bool selected" as a read-only selection information. + -- When Selectable() has been clicked it returns true and you can alter selection state accordingly. + -- - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) + -- The earlier is more flexible, as in real application your selection may be stored in many different ways + -- and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). + IMGUI_DEMO_MARKER("Widgets/Selectables/Basic") + if ImGui.TreeNode("Basic") then + local selection = s.selection + if ImGui.Selectable("1. I am selectable", selection[1]) then selection[1] = not selection[1] end + if ImGui.Selectable("2. I am selectable", selection[2]) then selection[2] = not selection[2] end + if ImGui.Selectable("3. I am selectable", selection[3]) then selection[3] = not selection[3] end + if ImGui.Selectable("4. I am double clickable", selection[4], 4 --[[ImGuiSelectableFlags.AllowDoubleClick]]) then + if ImGui.IsMouseDoubleClicked(0) then + selection[4] = not selection[4] + end + end + ImGui.TreePop() + end + + IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line") + if ImGui.TreeNode("Multiple items on the same line") then + IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple items on the same line") + -- - Using SetNextItemAllowOverlap() + -- - Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. + do + local selected = s.selected_multi + ImGui.SetNextItemAllowOverlap(); if ImGui.Selectable("main.c", selected[1]) then selected[1] = not selected[1] end; ImGui.SameLine(); ImGui.SmallButton("Link 1") + ImGui.SetNextItemAllowOverlap(); if ImGui.Selectable("hello.cpp", selected[2]) then selected[2] = not selected[2] end; ImGui.SameLine(); ImGui.SmallButton("Link 2") + ImGui.SetNextItemAllowOverlap(); if ImGui.Selectable("hello.h", selected[3]) then selected[3] = not selected[3] end; ImGui.SameLine(); ImGui.SmallButton("Link 3") + end + + -- (2) + -- - Using ImGuiSelectableFlags_AllowOverlap is a shortcut for calling SetNextItemAllowOverlap() + -- - No visible label, display contents inside the selectable bounds. + -- - We don't maintain actual selection in this example to keep things simple. + ImGui.Spacing() + do + local checked = s.checked + local color_marker_w = ImGui.CalcTextSize("x").x + for n = 0, 4 do + ImGui.PushID(n) + ImGui.AlignTextToFramePadding() + if ImGui.Selectable("##selectable", s.selected_n == n, 16 --[[ImGuiSelectableFlags.AllowOverlap]]) then + s.selected_n = n + end + ImGui.SameLine(0, 0) + _, checked[n + 1] = ImGui.Checkbox("##check", checked[n + 1]) + ImGui.SameLine() + local color = ImVec4(bit32.band(n, 1) ~= 0 and 1.0 or 0.2, bit32.band(n, 2) ~= 0 and 1.0 or 0.2, 0.2, 1.0) + ImGui.ColorButton("##color", color, 64 --[[ImGuiColorEditFlags.NoTooltip]], ImVec2(color_marker_w, 0)) + ImGui.SameLine() + ImGui.Text("Some label") + ImGui.PopID() + end + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("In Tables") then + IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables") + local selected = s.selected_tables + + if ImGui.BeginTable("split1", 3, bit32.bor(1 --[[ImGuiTableFlags.Resizable]], 16 --[[ImGuiTableFlags.NoSavedSettings]], 1920 --[[ImGuiTableFlags.Borders]])) then + for i = 0, 9 do + local label = string.format("Item %d", i) + ImGui.TableNextColumn() + if ImGui.Selectable(label, selected[i + 1]) then selected[i + 1] = not selected[i + 1] end -- FIXME-TABLE: Selection overlap + end + ImGui.EndTable() + end + ImGui.Spacing() + if ImGui.BeginTable("split2", 3, bit32.bor(1 --[[ImGuiTableFlags.Resizable]], 16 --[[ImGuiTableFlags.NoSavedSettings]], 1920 --[[ImGuiTableFlags.Borders]])) then + for i = 0, 9 do + local label = string.format("Item %d", i) + ImGui.TableNextRow() + ImGui.TableNextColumn() + if ImGui.Selectable(label, selected[i + 1], 2 --[[ImGuiSelectableFlags.SpanAllColumns]]) then selected[i + 1] = not selected[i + 1] end + ImGui.TableNextColumn() + ImGui.Text("Some other contents") + ImGui.TableNextColumn() + ImGui.Text("123456") + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Grid") then + IMGUI_DEMO_MARKER("Widgets/Selectables/Grid") + local selected = s.selected_grid + + -- Add in a bit of silly fun... + local time = ImGui.GetTime() + local winning_state = true -- If all cells are selected... + for y = 1, 4 do for x = 1, 4 do if selected[y][x] == 0 then winning_state = false end end end -- [Port] memchr(selected, 0, sizeof(selected)) == NULL + if winning_state then + ImGui.PushStyleVar(39 --[[ImGuiStyleVar.SelectableTextAlign]], ImVec2(0.5 + 0.5 * math.cos(time * 2.0), 0.5 + 0.5 * math.sin(time * 3.0))) + end + + local size = ImGui.CalcTextSize("Sailor").x + for y = 0, 3 do + for x = 0, 3 do + if x > 0 then + ImGui.SameLine() + end + ImGui.PushID(y * 4 + x) + if ImGui.Selectable("Sailor", selected[y + 1][x + 1] ~= 0, 0, ImVec2(size, size)) then + -- Toggle clicked cell + toggle neighbors + selected[y + 1][x + 1] = bit32.bxor(selected[y + 1][x + 1], 1) + if x > 0 then selected[y + 1][x] = bit32.bxor(selected[y + 1][x], 1) end + if x < 3 then selected[y + 1][x + 2] = bit32.bxor(selected[y + 1][x + 2], 1) end + if y > 0 then selected[y][x + 1] = bit32.bxor(selected[y][x + 1], 1) end + if y < 3 then selected[y + 2][x + 1] = bit32.bxor(selected[y + 2][x + 1], 1) end + end + ImGui.PopID() + end + end + + if winning_state then + ImGui.PopStyleVar() + end + ImGui.TreePop() + end + if ImGui.TreeNode("Alignment") then + IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment") + HelpMarker( + "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " .. + "basis using PushStyleVar(). You'll probably want to always keep your default situation to " .. + "left-align otherwise it becomes difficult to layout multiple items on a same line") + + local selected = s.selected_align + local size = ImGui.CalcTextSize("(1.0,1.0)").x + for y = 0, 2 do + for x = 0, 2 do + local alignment = ImVec2(x / 2.0, y / 2.0) + local name = string.format("(%.1f,%.1f)", alignment.x, alignment.y) + if x > 0 then ImGui.SameLine() end + ImGui.PushStyleVar(39 --[[ImGuiStyleVar.SelectableTextAlign]], alignment) + local idx = 3 * y + x + 1 + if ImGui.Selectable(name, selected[idx], 0 --[[ImGuiSelectableFlags.None]], ImVec2(size, size)) then selected[idx] = not selected[idx] end + ImGui.PopStyleVar() + end + end + ImGui.TreePop() end ImGui.TreePop() end end --- Demonstrate most Dear ImGui features (this is big function!) --- You may execute this function to experiment with the UI and understand what it does. --- You may then search for keywords in the code when you are interested by a specific feature. ---- @param p_open? bool ---- @return bool? p_open -function ImGui.ShowDemoWindow(p_open) - -- Exceptionally add an extra assert here for people confused about initial Dear ImGui setup - -- Most functions would normally just assert/crash if the context is missing. - assert(ImGui.GetCurrentContext() ~= nil, "Missing Dear ImGui context. Refer to examples app!") +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsSelectionAndMultiSelect() +------------------------------------------------------------------------------- +-- Multi-selection demos +-- Also read: https://github.com/ocornut/imgui/wiki/Multi-Select +------------------------------------------------------------------------------- - local data = demo_data +ExampleNames = +{ + "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper", + "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava", + "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber" +} - -- Examples Apps (accessible from the "Examples" menu) - if data.ShowMainMenuBar then - if ShowExampleAppMainMenuBar then ShowExampleAppMainMenuBar() end +function DemoWindowWidgetsSelectionAndMultiSelect(demo_data) + if ImGui.TreeNode("Selection State & Multi-Select") then + IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select") + HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.") + ImGui.TextDisabled("(multi-select API not ported yet)") -- [Port] TODO: BeginMultiSelect()/EndMultiSelect() + ImGui.TreePop() end - if data.ShowAppDockSpace then RunApp(ShowExampleAppDockSpace, "ShowAppDockSpace") end -- Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) - if data.ShowAppDocuments then RunApp(ShowExampleAppDocuments, "ShowAppDocuments") end -- ...process the Document app next, as it may also use a DockSpace() - if data.ShowAppAssetsBrowser then RunApp(ShowExampleAppAssetsBrowser, "ShowAppAssetsBrowser") end - if data.ShowAppConsole then RunApp(ShowExampleAppConsole, "ShowAppConsole") end - if data.ShowAppCustomRendering then RunApp(ShowExampleAppCustomRendering, "ShowAppCustomRendering") end - if data.ShowAppImageViewer then RunApp(ShowExampleAppImageViewer, "ShowAppImageViewer") end - if data.ShowAppLog then RunApp(ShowExampleAppLog, "ShowAppLog") end - if data.ShowAppLayout then RunApp(ShowExampleAppLayout, "ShowAppLayout") end - if data.ShowAppPropertyEditor then RunApp(ShowExampleAppPropertyEditor, "ShowAppPropertyEditor", data) end - if data.ShowAppSimpleOverlay then RunApp(ShowExampleAppSimpleOverlay, "ShowAppSimpleOverlay") end - if data.ShowAppAutoResize then RunApp(ShowExampleAppAutoResize, "ShowAppAutoResize") end - if data.ShowAppConstrainedResize then RunApp(ShowExampleAppConstrainedResize, "ShowAppConstrainedResize") end - if data.ShowAppFullscreen then RunApp(ShowExampleAppFullscreen, "ShowAppFullscreen") end - if data.ShowAppLongText then RunApp(ShowExampleAppLongText, "ShowAppLongText") end - if data.ShowAppWindowTitles then RunApp(ShowExampleAppWindowTitles, "ShowAppWindowTitles") end +end - -- Dear ImGui Tools (accessible from the "Tools" menu) - if data.ShowMetrics then RunApp(ImGui.ShowMetricsWindow, "ShowMetrics") end - if data.ShowDebugLog then RunApp(ImGui.ShowDebugLogWindow, "ShowDebugLog") end - if data.ShowIDStackTool then RunApp(ImGui.ShowIDStackToolWindow, "ShowIDStackTool") end - if data.ShowAbout then RunApp(ImGui.ShowAboutWindow, "ShowAbout") end - if data.ShowStyleEditor then - local visible - data.ShowStyleEditor, visible = ImGui.Begin("Dear ImGui Style Editor", data.ShowStyleEditor) - if visible then - ImGui.ShowStyleEditor() +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTabs() +------------------------------------------------------------------------------- + +-- [Port] ImGuiTabBarFlags* p_flags -> takes flags, returns the new flags +function EditTabBarFittingPolicyFlags(p_flags) + if bit32.band(p_flags, 896 --[[ImGuiTabBarFlags.FittingPolicyMask_]]) == 0 then + p_flags = bit32.bor(p_flags, 128 --[[ImGuiTabBarFlags.FittingPolicyDefault_]]) + end + local pressed + pressed, p_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyMixed", p_flags, 128 --[[ImGuiTabBarFlags.FittingPolicyMixed]]) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(896 --[[ImGuiTabBarFlags.FittingPolicyMask_]], 128 --[[ImGuiTabBarFlags.FittingPolicyMixed]]))) + end + pressed, p_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyShrink", p_flags, 256 --[[ImGuiTabBarFlags.FittingPolicyShrink]]) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(896 --[[ImGuiTabBarFlags.FittingPolicyMask_]], 256 --[[ImGuiTabBarFlags.FittingPolicyShrink]]))) + end + pressed, p_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", p_flags, 512 --[[ImGuiTabBarFlags.FittingPolicyScroll]]) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(896 --[[ImGuiTabBarFlags.FittingPolicyMask_]], 512 --[[ImGuiTabBarFlags.FittingPolicyScroll]]))) + end + return p_flags +end + +S.DemoWindowWidgetsTabs = { + tab_bar_flags = ImGuiTabBarFlags.Reorderable, + opened = { true, true, true, true }, -- Persistent user state + active_tabs = ImVector(), + next_tab_id = 0, + show_leading_button = true, + show_trailing_button = true, + show_leading_trailing_tabs = false, + tab_bar_flags_2 = bit32.bor(ImGuiTabBarFlags.AutoSelectNewTabs, ImGuiTabBarFlags.Reorderable, ImGuiTabBarFlags.FittingPolicyMixed), +} +function DemoWindowWidgetsTabs() + local s = S.DemoWindowWidgetsTabs + if ImGui.TreeNode("Tabs") then + IMGUI_DEMO_MARKER("Widgets/Tabs") + if ImGui.TreeNode("Basic") then + IMGUI_DEMO_MARKER("Widgets/Tabs/Basic") + local tab_bar_flags = 0 --[[ImGuiTabBarFlags.None]] + if ImGui.BeginTabBar("MyTabBar", tab_bar_flags) then + if ImGui.BeginTabItem("Avocado") then + ImGui.Text("This is the Avocado tab!\nblah blah blah blah blah") + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Broccoli") then + ImGui.Text("This is the Broccoli tab!\nblah blah blah blah blah") + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Cucumber") then + ImGui.Text("This is the Cucumber tab!\nblah blah blah blah blah") + ImGui.EndTabItem() + end + ImGui.EndTabBar() + end + ImGui.Separator() + ImGui.TreePop() end - ImGui.End() - end - -- Demonstrate the various window flags. Typically you would just use the default! - local W = ImGuiWindowFlags - local window_flags = 0 - if no_titlebar then window_flags = bit32.bor(window_flags, W.NoTitleBar) end - if no_scrollbar then window_flags = bit32.bor(window_flags, W.NoScrollbar) end - if not no_menu then window_flags = bit32.bor(window_flags, W.MenuBar) end - if no_move then window_flags = bit32.bor(window_flags, W.NoMove) end - if no_resize then window_flags = bit32.bor(window_flags, W.NoResize) end - if no_collapse then window_flags = bit32.bor(window_flags, W.NoCollapse) end - if no_nav then window_flags = bit32.bor(window_flags, W.NoNav) end - if no_background then window_flags = bit32.bor(window_flags, W.NoBackground) end - if no_bring_to_front then window_flags = bit32.bor(window_flags, W.NoBringToFrontOnFocus) end - if no_docking then window_flags = bit32.bor(window_flags, W.NoDocking) end - if unsaved_document then window_flags = bit32.bor(window_flags, W.UnsavedDocument) end - if no_close then p_open = nil end -- Don't pass our bool* to Begin + if ImGui.TreeNode("Advanced & Close Button") then + IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button") + -- Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_Reorderable", s.tab_bar_flags, 1 --[[ImGuiTabBarFlags.Reorderable]]) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", s.tab_bar_flags, 2 --[[ImGuiTabBarFlags.AutoSelectNewTabs]]) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", s.tab_bar_flags, 4 --[[ImGuiTabBarFlags.TabListPopupButton]]) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", s.tab_bar_flags, 8 --[[ImGuiTabBarFlags.NoCloseWithMiddleMouseButton]]) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", s.tab_bar_flags, 64 --[[ImGuiTabBarFlags.DrawSelectedOverline]]) + s.tab_bar_flags = EditTabBarFittingPolicyFlags(s.tab_bar_flags) - -- We specify a default position/size in case there's no data in the .ini file. - -- We only do it to make the demo applications a little more welcoming, but typically this isn't required. - local main_viewport = ImGui.GetMainViewport() - ImGui.SetNextWindowPos(ImVec2(main_viewport.WorkPos.x + 650, main_viewport.WorkPos.y + 20), 4 --[[ImGuiCond.FirstUseEver]]) - ImGui.SetNextWindowSize(ImVec2(550, 680), 4 --[[ImGuiCond.FirstUseEver]]) + -- Tab Bar + ImGui.AlignTextToFramePadding() + ImGui.Text("Opened:") + local names = { "Artichoke", "Beetroot", "Celery", "Daikon" } + local opened = s.opened -- Persistent user state + for n = 0, #opened - 1 do + ImGui.SameLine() + _, opened[n + 1] = ImGui.Checkbox(names[n + 1], opened[n + 1]) + end - -- Main body of the Demo window starts here. - local visible - p_open, visible = ImGui.Begin("Dear ImGui Demo", p_open, window_flags) - if no_close then p_open = nil end - if not visible then - -- Early out if the window is collapsed, as an optimization. - ImGui.End() - return p_open - end - - -- Most framed widgets share a common width settings. Remaining width is used for the label. - -- The width of the frame may be changed with PushItemWidth() or SetNextItemWidth(). - -- - Positive value for absolute size, negative value for right-alignment. - -- - The default value is about GetWindowWidth() * 0.65f. - -- - See 'Demo->Layout->Widgets Width' for details. - -- Here we change the frame width based on how much width we want to give to the label. - local label_width_base = ImGui.GetFontSize() * 12 -- Some amount of width for label, based on font size. - local label_width_max = ImGui.GetContentRegionAvail().x * 0.40 -- ...but always leave some room for framed widgets. - local label_width = math.min(label_width_base, label_width_max) - ImGui.PushItemWidth(-label_width) -- Right-align: framed items will leave 'label_width' available for the label. - -- ImGui.PushItemWidth(ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for framed widgets, leaving 60% width for labels. - -- ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for labels, leaving 60% width for framed widgets. - -- ImGui.PushItemWidth(ImGui.GetFontSize() * -12) -- e.g. Use XXX width for labels, leaving the rest for framed widgets. - - -- Menu Bar - DemoWindowMenuBar(data) - - ImGui.Text("Dear ImGui says hello! (%s) (%d)", IMGUI_VERSION or "WIP", 19298 --[[IMGUI_VERSION_NUM]] or 0) - ImGui.Spacing() - - if ImGui.CollapsingHeader("Help") then - IMGUI_DEMO_MARKER("Help") - ImGui.SeparatorText("ABOUT THIS DEMO:") - ImGui.BulletText("Sections below are demonstrating many aspects of the library.") - ImGui.BulletText("The \"Examples\" menu above leads to more demo contents.") - ImGui.BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" .. - "and Metrics/Debugger (general purpose Dear ImGui debugging tool).") - ImGui.BulletText("Web demo (w/ source code browser): ") - ImGui.SameLine(0, 0) - ImGui.TextLinkOpenURL("https://pthom.github.io/imgui_explorer") - - ImGui.SeparatorText("PROGRAMMER GUIDE:") - ImGui.BulletText("See the ShowDemoWindow() code in imgui_demo.lua. <- you are here!") - ImGui.BulletText("See comments in imgui.lua.") - ImGui.BulletText("See example applications in the examples/ folder.") - ImGui.BulletText("Read the FAQ at ") - ImGui.SameLine(0, 0) - ImGui.TextLinkOpenURL("https://www.dearimgui.com/faq/") - ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.") - ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.") - - ImGui.SeparatorText("USER GUIDE:") - ImGui.ShowUserGuide() - end - - if ImGui.CollapsingHeader("Configuration") then - DemoWindowConfiguration(ImGui.GetIO()) - end - - if ImGui.CollapsingHeader("Window options") then - IMGUI_DEMO_MARKER("Window options") - if ImGui.BeginTable("split", 3) then - ImGui.TableNextColumn(); _, no_titlebar = ImGui.Checkbox("No titlebar", no_titlebar) - ImGui.TableNextColumn(); _, no_scrollbar = ImGui.Checkbox("No scrollbar", no_scrollbar) - ImGui.TableNextColumn(); _, no_menu = ImGui.Checkbox("No menu", no_menu) - ImGui.TableNextColumn(); _, no_move = ImGui.Checkbox("No move", no_move) - ImGui.TableNextColumn(); _, no_resize = ImGui.Checkbox("No resize", no_resize) - ImGui.TableNextColumn(); _, no_collapse = ImGui.Checkbox("No collapse", no_collapse) - ImGui.TableNextColumn(); _, no_close = ImGui.Checkbox("No close", no_close) - ImGui.TableNextColumn(); _, no_nav = ImGui.Checkbox("No nav", no_nav) - ImGui.TableNextColumn(); _, no_background = ImGui.Checkbox("No background", no_background) - ImGui.TableNextColumn(); _, no_bring_to_front = ImGui.Checkbox("No bring to front", no_bring_to_front) - ImGui.TableNextColumn(); _, no_docking = ImGui.Checkbox("No docking", no_docking) - ImGui.TableNextColumn(); _, unsaved_document = ImGui.Checkbox("Unsaved document", unsaved_document) - ImGui.EndTable() + -- Passing a bool* to BeginTabItem() is similar to passing one to Begin(): + -- the underlying bool will be set to false when the tab is closed. + if ImGui.BeginTabBar("MyTabBar", s.tab_bar_flags) then + for n = 0, #opened - 1 do + if opened[n + 1] then + local visible + visible, opened[n + 1] = ImGui.BeginTabItem(names[n + 1], opened[n + 1], 0 --[[ImGuiTabItemFlags.None]]) + if visible then + ImGui.Text("This is the %s tab!", names[n + 1]) + if bit32.band(n, 1) ~= 0 then + ImGui.Text("I am an odd tab.") + end + ImGui.EndTabItem() + end + end + end + ImGui.EndTabBar() + end + ImGui.Separator() + ImGui.TreePop() end + + if ImGui.TreeNode("TabItemButton & Leading/Trailing flags") then + IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags") + local active_tabs = s.active_tabs + if s.next_tab_id == 0 then -- Initialize with some default tabs + for i = 0, 2 do + active_tabs:push_back(s.next_tab_id); s.next_tab_id = s.next_tab_id + 1 + end + end + + -- TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. + -- (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... + -- but they tend to make more sense together) + _, s.show_leading_button = ImGui.Checkbox("Show Leading TabItemButton()", s.show_leading_button) + _, s.show_trailing_button = ImGui.Checkbox("Show Trailing TabItemButton()", s.show_trailing_button) + _, s.show_leading_trailing_tabs = ImGui.Checkbox("Show Leading+Trailing TabItem()", s.show_leading_trailing_tabs) + + -- Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs + s.tab_bar_flags_2 = EditTabBarFittingPolicyFlags(s.tab_bar_flags_2) + + if ImGui.BeginTabBar("MyTabBar", s.tab_bar_flags_2) then + -- Demo a Leading TabItemButton(): click the "?" button to open a menu + if s.show_leading_button then + if ImGui.TabItemButton("?", bit32.bor(64 --[[ImGuiTabItemFlags.Leading]], 16 --[[ImGuiTabItemFlags.NoTooltip]])) then + ImGui.OpenPopup("MyHelpMenu") + end + end + if ImGui.BeginPopup("MyHelpMenu") then + ImGui.Selectable("Hello!") + ImGui.EndPopup() + end + + -- Demo Leading/Trailing Tabs + if s.show_leading_trailing_tabs then + if ImGui.BeginTabItem("Leading", nil, 64 --[[ImGuiTabItemFlags.Leading]]) then + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Trailing", nil, 128 --[[ImGuiTabItemFlags.Trailing]]) then + ImGui.EndTabItem() + end + end + + -- Demo Trailing Tabs: click the "+" button to add a new tab. + -- (In your app you may want to use a font icon instead of the "+") + -- We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end. + if s.show_trailing_button then + if ImGui.TabItemButton("+", bit32.bor(128 --[[ImGuiTabItemFlags.Trailing]], 16 --[[ImGuiTabItemFlags.NoTooltip]])) then + active_tabs:push_back(s.next_tab_id); s.next_tab_id = s.next_tab_id + 1 -- Add new tab + end + end + + -- Submit our regular tabs + local n = 0 + while n < active_tabs.Size do + local open = true + local name = string.format("%04d", active_tabs.Data[n + 1]) + local visible + visible, open = ImGui.BeginTabItem(name, open, 0 --[[ImGuiTabItemFlags.None]]) + if visible then + ImGui.Text("This is the %s tab!", name) + ImGui.EndTabItem() + end + + if not open then + active_tabs:erase(n + 1) + else + n = n + 1 + end + end + + ImGui.EndTabBar() + end + ImGui.Separator() + ImGui.TreePop() + end + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsText() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsText = { + custom_size = 16.0, + custom_scale = 1.0, + wrap_width = 200.0, + buf = ImGui.NewTextBuffer("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e", 32), +} +function DemoWindowWidgetsText() + local s = S.DemoWindowWidgetsText + if ImGui.TreeNode("Text") then + IMGUI_DEMO_MARKER("Widgets/Text") + if ImGui.TreeNode("Colorful Text") then + IMGUI_DEMO_MARKER("Widgets/Text/Colored Text") + -- Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. + ImGui.TextColored(ImVec4(1.0, 0.0, 1.0, 1.0), "Pink") + ImGui.TextColored(ImVec4(1.0, 1.0, 0.0, 1.0), "Yellow") + ImGui.TextDisabled("Disabled") + ImGui.SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.") + ImGui.TreePop() + end + + if ImGui.TreeNode("Font Size") then + IMGUI_DEMO_MARKER("Widgets/Text/Font Size") + local style = ImGui.GetStyle() + local global_scale = style.FontScaleMain * style.FontScaleDpi + ImGui.Text("style.FontScaleMain = %0.2f", style.FontScaleMain) + ImGui.Text("style.FontScaleDpi = %0.2f", style.FontScaleDpi) + ImGui.Text("global_scale = ~%0.2f", global_scale) -- This is not technically accurate as internal scales may apply, but conceptually let's pretend it is. + ImGui.Text("FontSize = %0.2f", ImGui.GetFontSize()) + + ImGui.SeparatorText("") + s.custom_size = ImGui.SliderFloat("custom_size", s.custom_size, 10.0, 100.0, "%.0f") + ImGui.Text("ImGui::PushFont(nullptr, custom_size);") + ImGui.PushFont(nil, s.custom_size) + ImGui.Text("FontSize = %.2f (== %.2f * global_scale)", ImGui.GetFontSize(), s.custom_size) + ImGui.PopFont() + + ImGui.SeparatorText("") + s.custom_scale = ImGui.SliderFloat("custom_scale", s.custom_scale, 0.5, 4.0, "%.2f") + ImGui.Text("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scale);") + ImGui.PushFont(nil, style.FontSizeBase * s.custom_scale) + ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), s.custom_scale) + ImGui.PopFont() + + ImGui.SeparatorText("") + local scaling = 0.5 + while scaling <= 4.0 do + ImGui.PushFont(nil, style.FontSizeBase * scaling) + ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), scaling) + ImGui.PopFont() + scaling = scaling + 0.5 + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Word Wrapping") then + IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping") + -- Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. + ImGui.TextWrapped( + "This text should automatically wrap on the edge of the window. The current implementation " .. + "for text wrapping follows simple rules suitable for English and possibly other languages.") + ImGui.Spacing() + + s.wrap_width = ImGui.SliderFloat("Wrap width", s.wrap_width, -20, 600, "%.0f") + + local draw_list = ImGui.GetWindowDrawList() + for n = 0, 1 do + ImGui.Text("Test paragraph %d:", n) + local pos = ImGui.GetCursorScreenPos() + local marker_min = ImVec2(pos.x + s.wrap_width, pos.y) + local marker_max = ImVec2(pos.x + s.wrap_width + 10, pos.y + ImGui.GetTextLineHeight()) + ImGui.PushTextWrapPos(ImGui.GetCursorPos().x + s.wrap_width) + if n == 0 then + ImGui.Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", s.wrap_width) + else + ImGui.Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh") + end + + -- Draw actual text bounding box, following by marker of our expected limit (should not overlap!) + draw_list:AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), IM_COL32(255, 255, 0, 255)) + draw_list:AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)) + ImGui.PopTextWrapPos() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("UTF-8 Text") then + IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text") + -- UTF-8 test with Japanese characters + -- (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) + -- - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 + -- - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you + -- can save your source files as 'UTF-8 without signature'). + -- - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 + -- CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. + -- Don't do this in your application! Please use u8"text in any language" in your application! + -- Note that characters values are preserved even by InputText() if the font cannot be displayed, + -- so you can safely copy & paste garbled characters into another application. + ImGui.TextWrapped( + "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. " .. + "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. " .. + "Read docs/FONTS.md for details.") + ImGui.Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)") + ImGui.Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)") + --static char buf[32] = u8"NIHONGO"; -- <- this is how you would write it with C++11, using real kanjis + ImGui.InputText("UTF-8 input", s.buf, 32) + ImGui.TreePop() + end + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTextFilter() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTextFilter = { + filter = ImGuiTextFilter(), +} +function DemoWindowWidgetsTextFilter() + local s = S.DemoWindowWidgetsTextFilter + if ImGui.TreeNode("Text Filter") then + IMGUI_DEMO_MARKER("Widgets/Text Filter") + -- Helper class to easy setup a text filter. + -- You may want to implement a more feature-full filtering scheme in your own application. + HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.") + local filter = s.filter + ImGui.Text("Filter usage:\n" .. + " \"\" display all lines\n" .. + " xxx display lines containing \"xxx\"\n" .. + " xxx yyy display lines containing \"xxx\" and \"yyy\"\n" .. + " \"xxx yyy\" display lines containing \"xxx yyy\"\n" .. + " xxx,yyy display lines containing \"xxx\" or \"yyy\"\n" .. + " -xxx hide lines containing \"xxx\"") + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + filter:DrawWithHint("##Filter", "Filter (incl -excl)") + if ImGui.BeginChild("##items", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeightWithSpacing() * 15), 128 --[[ImGuiChildFlags.FrameStyle]]) then + local lines = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" } + for _, item in ipairs(lines) do + if filter:PassFilter(item) then + ImGui.TextUnformatted(item) + end + end + for _, item in ipairs(ExampleNames) do + if filter:PassFilter(item) then + ImGui.TextUnformatted(item) + end + end + end + ImGui.EndChild() + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTextInput() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTextInput = { + -- "Multi-line Text Input" + ml = { + text = ImGui.NewTextBuffer( + "/*\n" .. + " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" .. + " the hexadecimal encoding of one offending instruction,\n" .. + " more formally, the invalid operand with locked CMPXCHG8B\n" .. + " instruction bug, is a design flaw in the majority of\n" .. + " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" .. + " processors (all in the P5 microarchitecture).\n" .. + "*/\n\n" .. + "label:\n" .. + "\tlock cmpxchg8b eax\n", 1024 * 16), + flags = ImGuiInputTextFlags.AllowTabInput, + }, + -- "Filtered Text Input" + filtered = { + buf1 = ImGui.NewTextBuffer("", 32), buf2 = ImGui.NewTextBuffer("", 32), buf3 = ImGui.NewTextBuffer("", 32), + buf4 = ImGui.NewTextBuffer("", 32), buf5 = ImGui.NewTextBuffer("", 32), buf6 = ImGui.NewTextBuffer("", 32), + buf7 = ImGui.NewTextBuffer("", 32), + }, + -- "Password Input" + password = { password = ImGui.NewTextBuffer("password123", 64) }, + -- "Completion, History, Edit Callbacks" + callbacks = { + buf1 = ImGui.NewTextBuffer("", 64), buf2 = ImGui.NewTextBuffer("", 64), buf3 = ImGui.NewTextBuffer("", 64), + edit_count = 0, + }, + -- "Resize Callback" + resize = { flags = ImGuiInputTextFlags.None, my_str = ImVector() }, + -- "Eliding, Alignment" + eliding = { buf1 = ImGui.NewTextBuffer("/path/to/some/folder/with/long/filename.cpp", 128), flags = ImGuiInputTextFlags.ElideLeft }, + -- "Miscellaneous" + misc = { buf1 = ImGui.NewTextBuffer("", 16), flags = ImGuiInputTextFlags.EscapeClearsAll }, +} +function DemoWindowWidgetsTextInput() + local S_ti = S.DemoWindowWidgetsTextInput + -- To wire InputText() with std::string or any other custom string type, + -- see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + if ImGui.TreeNode("Text Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input") + if ImGui.TreeNode("Multi-line Text Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input") + local s = S_ti.ml + -- WE ARE USING A FIXED-SIZE BUFFER FOR SIMPLICITY HERE. + -- If you want to use InputText() with std::string or any custom dynamic string type: + -- - For std::string: use the wrapper in misc/cpp/imgui_stdlib.h/.cpp + -- - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize. + HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include in here)") + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, 512 --[[ImGuiInputTextFlags.ReadOnly]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_WordWrap", s.flags, 16777216 --[[ImGuiInputTextFlags.WordWrap]]) + ImGui.SameLine(); HelpMarker("Feature is currently in Beta. Please read comments in imgui.h") + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", s.flags, 32 --[[ImGuiInputTextFlags.AllowTabInput]]) + ImGui.SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets.") + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", s.flags, 256 --[[ImGuiInputTextFlags.CtrlEnterForNewLine]]) + ImGui.InputTextMultiline("##source", s.text, 1024 * 16, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeight() * 16), s.flags) + ImGui.TreePop() + end + + if ImGui.TreeNode("Filtered Text Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input") + local s = S_ti.filtered + local TextFilters = {} + -- Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback) + function TextFilters.FilterCasingSwap(data) + if data.EventChar >= string.byte('a') and data.EventChar <= string.byte('z') then data.EventChar = data.EventChar - (string.byte('a') - string.byte('A')) -- Lowercase becomes uppercase + elseif data.EventChar >= string.byte('A') and data.EventChar <= string.byte('Z') then data.EventChar = data.EventChar + (string.byte('a') - string.byte('A')) end -- Uppercase becomes lowercase + return 0 + end + + -- Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) + function TextFilters.FilterImGuiLetters(data) + if data.EventChar < 256 and string.find("imgui", string.char(data.EventChar), 1, true) then + return 0 + end + return 1 + end + + ImGui.InputText("default", s.buf1, 32) + ImGui.InputText("decimal", s.buf2, 32, 1 --[[ImGuiInputTextFlags.CharsDecimal]]) + ImGui.InputText("hexadecimal", s.buf3, 32, bit32.bor(2 --[[ImGuiInputTextFlags.CharsHexadecimal]], 8 --[[ImGuiInputTextFlags.CharsUppercase]])) + ImGui.InputText("uppercase", s.buf4, 32, 8 --[[ImGuiInputTextFlags.CharsUppercase]]) + ImGui.InputText("no blank", s.buf5, 32, 16 --[[ImGuiInputTextFlags.CharsNoBlank]]) + ImGui.InputText("casing swap", s.buf6, 32, 2097152 --[[ImGuiInputTextFlags.CallbackCharFilter]], TextFilters.FilterCasingSwap) -- Use CharFilter callback to replace characters. + ImGui.InputText("\"imgui\"", s.buf7, 32, 2097152 --[[ImGuiInputTextFlags.CallbackCharFilter]], TextFilters.FilterImGuiLetters) -- Use CharFilter callback to disable some characters. + ImGui.TreePop() + end + + if ImGui.TreeNode("Password Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Password input") + local s = S_ti.password + ImGui.InputText("password", s.password, 64, 1024 --[[ImGuiInputTextFlags.Password]]) + ImGui.SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n") + ImGui.InputTextWithHint("password (w/ hint)", "", s.password, 64, 1024 --[[ImGuiInputTextFlags.Password]]) + ImGui.InputText("password (clear)", s.password, 64) + ImGui.TreePop() + end + + if ImGui.TreeNode("Completion, History, Edit Callbacks") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks") + local s = S_ti.callbacks + local Funcs = {} + function Funcs.MyCallback(data) + if data.EventFlag == 262144 --[[ImGuiInputTextFlags.CallbackCompletion]] then + data:InsertChars(data.CursorPos, "..") + elseif data.EventFlag == 524288 --[[ImGuiInputTextFlags.CallbackHistory]] then + if data.EventKey == 515 --[[ImGuiKey.UpArrow]] then + data:DeleteChars(0, data.BufTextLen) + data:InsertChars(0, "Pressed Up!") + data:SelectAll() + elseif data.EventKey == 516 --[[ImGuiKey.DownArrow]] then + data:DeleteChars(0, data.BufTextLen) + data:InsertChars(0, "Pressed Down!") + data:SelectAll() + end + elseif data.EventFlag == 8388608 --[[ImGuiInputTextFlags.CallbackEdit]] then + -- Toggle casing of first character + local c = data.Buf[1] + if (c >= string.byte('a') and c <= string.byte('z')) or (c >= string.byte('A') and c <= string.byte('Z')) then data.Buf[1] = bit32.bxor(data.Buf[1], 32) end + data.BufDirty = true + + -- Increment a counter + local p_int = data.UserData -- [Port] int* -> the statics table, counter in .edit_count + p_int.edit_count = p_int.edit_count + 1 + end + return 0 + end + ImGui.InputText("Completion", s.buf1, 64, 262144 --[[ImGuiInputTextFlags.CallbackCompletion]], Funcs.MyCallback) + ImGui.SameLine(); HelpMarker( + "Here we append \"..\" each time Tab is pressed. " .. + "See 'Examples>Console' for a more meaningful demonstration of using this callback.") + + ImGui.InputText("History", s.buf2, 64, 524288 --[[ImGuiInputTextFlags.CallbackHistory]], Funcs.MyCallback) + ImGui.SameLine(); HelpMarker( + "Here we replace and select text each time Up/Down are pressed. " .. + "See 'Examples>Console' for a more meaningful demonstration of using this callback.") + + ImGui.InputText("Edit", s.buf3, 64, 8388608 --[[ImGuiInputTextFlags.CallbackEdit]], Funcs.MyCallback, s) -- [Port] (void*)&edit_count -> s + ImGui.SameLine(); HelpMarker( + "Here we toggle the casing of the first character on every edit + count edits.") + ImGui.SameLine(); ImGui.Text("(%d)", s.edit_count) + + ImGui.TreePop() + end + + if ImGui.TreeNode("Resize Callback") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback") + local s = S_ti.resize + -- To wire InputText() with std::string or any other custom string type, + -- you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper + -- using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. + HelpMarker( + "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" .. + "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.") + local Funcs = {} + function Funcs.MyResizeCallback(data) + if data.EventFlag == 4194304 --[[ImGuiInputTextFlags.CallbackResize]] then + local my_str = data.UserData + assert(my_str.Data == data.Buf) + my_str:resize(data.BufSize, 0) -- NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 -- [Port] new bytes filled with 0 + data.Buf = my_str.Data + end + return 0 + end + + -- Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. + -- For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' + function Funcs.MyInputTextMultiline(label, my_str, size, flags) + if size == nil then size = ImVec2(0, 0) end + if flags == nil then flags = 0 end + assert(bit32.band(flags, 4194304 --[[ImGuiInputTextFlags.CallbackResize]]) == 0) + return ImGui.InputTextMultiline(label, my_str.Data, my_str.Size, size, bit32.bor(flags, 4194304 --[[ImGuiInputTextFlags.CallbackResize]]), Funcs.MyResizeCallback, my_str) + end + + -- For this demo we are using ImVector as a string container. + -- Note that because we need to store a terminating zero character, our size/capacity are 1 more + -- than usually reported by a typical string class. + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_WordWrap", s.flags, 16777216 --[[ImGuiInputTextFlags.WordWrap]]) + + local my_str = s.my_str + if my_str:empty() then + my_str:push_back(0) + end + Funcs.MyInputTextMultiline("##MyStr", my_str, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeight() * 16), s.flags) + ImGui.Text("Data: %s\nSize: %d\nCapacity: %d", tostring(my_str.Data), my_str.Size, my_str.Capacity) -- [Port] %p -> %s + tostring + ImGui.TreePop() + end + + if ImGui.TreeNode("Eliding, Alignment") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment") + local s = S_ti.eliding + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ElideLeft", s.flags, 131072 --[[ImGuiInputTextFlags.ElideLeft]]) + ImGui.InputText("Path", s.buf1, 128, s.flags) + ImGui.TreePop() + end + + if ImGui.TreeNode("Miscellaneous") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous") + local s = S_ti.misc + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", s.flags, 128 --[[ImGuiInputTextFlags.EscapeClearsAll]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, 512 --[[ImGuiInputTextFlags.ReadOnly]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", s.flags, 65536 --[[ImGuiInputTextFlags.NoUndoRedo]]) + ImGui.InputText("Hello", s.buf1, 16, s.flags) + ImGui.TreePop() + end + + ImGui.TreePop() end - -- All demo contents - DemoWindowWidgets(data) - if DemoWindowLayout then DemoWindowLayout() end - if DemoWindowPopups then DemoWindowPopups() end - if DemoWindowTables then DemoWindowTables() end - if DemoWindowInputs then DemoWindowInputs() end +end - -- End of ShowDemoWindow() - ImGui.PopItemWidth() - ImGui.End() - return p_open +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTooltips() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTooltips = { + arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, + always_on = 0, +} +function DemoWindowWidgetsTooltips() + local s = S.DemoWindowWidgetsTooltips + if ImGui.TreeNode("Tooltips") then + IMGUI_DEMO_MARKER("Widgets/Tooltips") + -- Tooltips are windows following the mouse. They do not take focus away. + ImGui.SeparatorText("General") + + -- Typical use cases: + -- - Short-form (text only): SetItemTooltip("Hello"); + -- - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); } + + -- - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); } + -- - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); } + + HelpMarker( + "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n" .. + "We provide a helper SetItemTooltip() function to perform the two with standards flags.") + + local sz = ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0) + + ImGui.Button("Basic", sz) + ImGui.SetItemTooltip("I am a tooltip") + + ImGui.Button("Fancy", sz) + if ImGui.BeginItemTooltip() then + ImGui.Text("I am a fancy tooltip") + ImGui.PlotLines("Curve", s.arr, nil, #s.arr) + ImGui.Text("Sin(time) = %f", math.sin(ImGui.GetTime())) + ImGui.EndTooltip() + end + + ImGui.SeparatorText("Always On") + + -- Showcase NOT relying on a IsItemHovered() to emit a tooltip. + -- Here the tooltip is always emitted when 'always_on == true'. + _, s.always_on = ImGui.RadioButton("Off", s.always_on, 0) + ImGui.SameLine() + _, s.always_on = ImGui.RadioButton("Always On (Simple)", s.always_on, 1) + ImGui.SameLine() + _, s.always_on = ImGui.RadioButton("Always On (Advanced)", s.always_on, 2) + if s.always_on == 1 then + ImGui.SetTooltip("I am following you around.") + elseif s.always_on == 2 and ImGui.BeginTooltip() then + ImGui.ProgressBar(math.sin(ImGui.GetTime()) * 0.5 + 0.5, ImVec2(ImGui.GetFontSize() * 25, 0.0)) + ImGui.EndTooltip() + end + + ImGui.SeparatorText("Custom") + + HelpMarker( + "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize " .. + "tooltip activation details across your application. You may however decide to use custom " .. + "flags for a specific tooltip instance.") + + -- The following examples are passed for documentation purpose but may not be useful to most users. + -- Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from + -- 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. + -- With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. + ImGui.Button("Manual", sz) + if ImGui.IsItemHovered(4096 --[[ImGuiHoveredFlags.ForTooltip]]) then + ImGui.SetTooltip("I am a manually emitted tooltip.") + end + + ImGui.Button("DelayNone", sz) + if ImGui.IsItemHovered(16384 --[[ImGuiHoveredFlags.DelayNone]]) then + ImGui.SetTooltip("I am a tooltip with no delay.") + end + + ImGui.Button("DelayShort", sz) + if ImGui.IsItemHovered(bit32.bor(32768 --[[ImGuiHoveredFlags.DelayShort]], 131072 --[[ImGuiHoveredFlags.NoSharedDelay]])) then + ImGui.SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui.GetStyle().HoverDelayShort) + end + + ImGui.Button("DelayLong", sz) + if ImGui.IsItemHovered(bit32.bor(65536 --[[ImGuiHoveredFlags.DelayNormal]], 131072 --[[ImGuiHoveredFlags.NoSharedDelay]])) then + ImGui.SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui.GetStyle().HoverDelayNormal) + end + + ImGui.Button("Stationary", sz) + if ImGui.IsItemHovered(8192 --[[ImGuiHoveredFlags.Stationary]]) then + ImGui.SetTooltip("I am a tooltip requiring mouse to be stationary before activating.") + end + + -- Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav', + -- which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag. + ImGui.BeginDisabled() + ImGui.Button("Disabled item", sz) + if ImGui.IsItemHovered(4096 --[[ImGuiHoveredFlags.ForTooltip]]) then + ImGui.SetTooltip("I am a tooltip for a disabled item.") + end + ImGui.EndDisabled() + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTreeNodes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTreeNodes = { + base_flags = bit32.bor(ImGuiTreeNodeFlags.DrawLinesFull, ImGuiTreeNodeFlags.DefaultOpen), -- "Hierarchy Lines" + selection_mask = 0x00, + base_flags_2 = bit32.bor(ImGuiTreeNodeFlags.OpenOnArrow, ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.SpanAvailWidth), -- "Advanced" + align_label_with_current_x_position = false, + use_drag_and_drop = false, +} +function DemoWindowWidgetsTreeNodes() + local s = S.DemoWindowWidgetsTreeNodes + if ImGui.TreeNode("Tree Nodes") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes") + -- See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree. + if ImGui.TreeNode("Basic Trees") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic Trees") + for i = 0, 4 do + -- Use SetNextItemOpen() so set the default state of a node to be open. We could + -- also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! + if i == 0 then + ImGui.SetNextItemOpen(true, 2 --[[ImGuiCond.Once]]) + end + + -- Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict. + -- An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)', + -- aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine. + ImGui.PushID(i) + if ImGui.TreeNode("", "Child %d", i) then + ImGui.Text("blah blah") + ImGui.SameLine() + if ImGui.SmallButton("button") then end + ImGui.TreePop() + end + ImGui.PopID() + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Hierarchy Lines") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy Lines") + HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") + _, s.base_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", s.base_flags, 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", s.base_flags, 524288 --[[ImGuiTreeNodeFlags.DrawLinesFull]]) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", s.base_flags, 1048576 --[[ImGuiTreeNodeFlags.DrawLinesToNodes]]) + + if ImGui.TreeNodeEx("Parent", s.base_flags) then + if ImGui.TreeNodeEx("Child 1", s.base_flags) then + ImGui.Button("Button for Child 1") + ImGui.TreePop() + end + if ImGui.TreeNodeEx("Child 2", s.base_flags) then + ImGui.Button("Button for Child 2") + ImGui.TreePop() + end + ImGui.Text("Remaining contents") + ImGui.Text("Remaining contents") + ImGui.TreePop() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Clipping Large Trees") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Clipping Large Trees") + ImGui.TextWrapped( + "- Using ImGuiListClipper with trees is a less easy than on arrays or grids.\n" .. + "- Refer to 'Demo->Examples->Property Editor' for an example of how to do that.\n" .. + "- Discuss in #3823") + ImGui.TreePop() + end + + if ImGui.TreeNode("Selectable Nodes") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Selectable Nodes") + HelpMarker( + "Manually implemented selectable nodes.\n" .. + "Click to select, Ctrl+Click to toggle, click on arrows or double-click to open.\n\n" .. + "You may also use the multi-select API (see 'Demo->Widgets->Selection State & Multi-Select') for more advanced multi-selection features.") + + -- Hold in 'selection_mask' a simple representation of what may be user-side selection state. + -- - You may retain selection state inside or outside your objects in whatever format you see fit. + -- You may use ImGuiSelectionBasicStorage which is conceptually close to a set<> of identifiers. + -- - We record which node was clicked and then apply selection at the end of the loop. + -- - This is a manual and simplified reimplementation of multi-selection, which the full + -- BeginMultiSelect() API implements better, but which is not trivial to wire for trees. + local node_clicked_idx = -1 + for node_n = 0, 5 do + -- Disable the default "open on single-click behavior" + set Selected flag according to our selection. + -- To alter selection we use if 'IsItemClicked() && !IsItemToggledOpen()', so clicking on an arrow doesn't alter selection. + -- In a BeginMultiSelect()/EndMultiSelect() we could use IsItemToggledSelection() but here we reimplement and use our own logic. + local flags = bit32.bor(128 --[[ImGuiTreeNodeFlags.OpenOnArrow]], 64 --[[ImGuiTreeNodeFlags.OpenOnDoubleClick]], 2048 --[[ImGuiTreeNodeFlags.SpanAvailWidth]]) + if bit32.band(s.selection_mask, bit32.lshift(1, node_n)) ~= 0 then + flags = bit32.bor(flags, 1 --[[ImGuiTreeNodeFlags.Selected]]) + end + + local is_open = ImGui.TreeNodeEx(node_n, flags, "Selectable Node %d", node_n) -- [Port] (void*)(intptr_t)node_n -> node_n + if ImGui.IsItemClicked() and not ImGui.IsItemToggledOpen() then + node_clicked_idx = node_n + end + if is_open then + ImGui.BulletText("") + ImGui.TreePop() + end + end + if node_clicked_idx ~= -1 then + -- Update selection state (process outside of tree loop to avoid visual inconsistencies during the clicking frame) + if ImGui.GetIO().KeyCtrl then + s.selection_mask = bit32.bxor(s.selection_mask, bit32.lshift(1, node_clicked_idx)) -- Ctrl+Click to toggle + else --if (!(selection_mask & (1 << node_clicked_idx))) -- Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection + s.selection_mask = bit32.lshift(1, node_clicked_idx) -- Click to single-select + end + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Advanced") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", s.base_flags_2, 128 --[[ImGuiTreeNodeFlags.OpenOnArrow]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", s.base_flags_2, 64 --[[ImGuiTreeNodeFlags.OpenOnDoubleClick]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", s.base_flags_2, 2048 --[[ImGuiTreeNodeFlags.SpanAvailWidth]]); ImGui.SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", s.base_flags_2, 4096 --[[ImGuiTreeNodeFlags.SpanFullWidth]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", s.base_flags_2, 8192 --[[ImGuiTreeNodeFlags.SpanLabelWidth]]); ImGui.SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin.") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", s.base_flags_2, 16384 --[[ImGuiTreeNodeFlags.SpanAllColumns]]); ImGui.SameLine(); HelpMarker("For use in Tables only.") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", s.base_flags_2, 4 --[[ImGuiTreeNodeFlags.AllowOverlap]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_Framed", s.base_flags_2, 2 --[[ImGuiTreeNodeFlags.Framed]]); ImGui.SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_FramePadding", s.base_flags_2, 1024 --[[ImGuiTreeNodeFlags.FramePadding]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsToParent", s.base_flags_2, 131072 --[[ImGuiTreeNodeFlags.NavLeftJumpsToParent]]) + + HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", s.base_flags_2, 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", s.base_flags_2, 524288 --[[ImGuiTreeNodeFlags.DrawLinesFull]]) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", s.base_flags_2, 1048576 --[[ImGuiTreeNodeFlags.DrawLinesToNodes]]) + + _, s.align_label_with_current_x_position = ImGui.Checkbox("Align label with current X position", s.align_label_with_current_x_position) + _, s.use_drag_and_drop = ImGui.Checkbox("Make Tree Nodes as drag & drop sources", s.use_drag_and_drop) + if s.align_label_with_current_x_position then + ImGui.Unindent(ImGui.GetTreeNodeToLabelSpacing()) + end + + for node_n = 0, 5 do + local node_flags = s.base_flags_2 + if node_n < 3 then + -- Items 0..2 are Tree Node + local is_open = ImGui.TreeNodeEx(node_n, node_flags, "Selectable Node %d", node_n) + if s.use_drag_and_drop and ImGui.BeginDragDropSource() then + ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) + ImGui.Text("This is a drag and drop source") + ImGui.EndDragDropSource() + end + if node_n == 2 and bit32.band(s.base_flags_2, 8192 --[[ImGuiTreeNodeFlags.SpanLabelWidth]]) ~= 0 then + -- Item 2 has an additional inline button to help demonstrate SpanLabelWidth. + ImGui.SameLine() + if ImGui.SmallButton("button") then end + end + if is_open then + ImGui.BulletText("Blah blah\nBlah Blah") + ImGui.SameLine() + ImGui.SmallButton("Button") + ImGui.TreePop() + end + else + -- Items 3..5 are Tree Leaves + -- The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can + -- use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). + node_flags = bit32.bor(node_flags, 256 --[[ImGuiTreeNodeFlags.Leaf]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]]) -- ImGuiTreeNodeFlags_Bullet + ImGui.TreeNodeEx(node_n, node_flags, "Selectable Leaf %d", node_n) + if s.use_drag_and_drop and ImGui.BeginDragDropSource() then + ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) + ImGui.Text("This is a drag and drop source") + ImGui.EndDragDropSource() + end + end + end + if s.align_label_with_current_x_position then + ImGui.Indent(ImGui.GetTreeNodeToLabelSpacing()) + end + ImGui.TreePop() + end + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsVerticalSliders() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsVerticalSliders = { + int_value = 0, + values = { 0.0, 0.60, 0.35, 0.9, 0.70, 0.20, 0.0 }, + values2 = { 0.20, 0.80, 0.40, 0.25 }, +} +function DemoWindowWidgetsVerticalSliders() + local s = S.DemoWindowWidgetsVerticalSliders + if ImGui.TreeNode("Vertical Sliders") then + IMGUI_DEMO_MARKER("Widgets/Vertical Sliders") + local spacing = 4 + ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(spacing, spacing)) + + s.int_value = ImGui.VSliderInt("##int", ImVec2(18, 160), s.int_value, 0, 5) + ImGui.SameLine() + + local values = s.values + ImGui.PushID("set1") + for i = 0, 6 do + if i > 0 then ImGui.SameLine() end + ImGui.PushID(i) + ImGui.PushStyleColor(7 --[[ImGuiCol.FrameBg]], ImColor.HSV(i / 7.0, 0.5, 0.5).Value) + ImGui.PushStyleColor(8 --[[ImGuiCol.FrameBgHovered]], ImColor.HSV(i / 7.0, 0.6, 0.5).Value) + ImGui.PushStyleColor(9 --[[ImGuiCol.FrameBgActive]], ImColor.HSV(i / 7.0, 0.7, 0.5).Value) + ImGui.PushStyleColor(20 --[[ImGuiCol.SliderGrab]], ImColor.HSV(i / 7.0, 0.9, 0.9).Value) + values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(18, 160), values[i + 1], 0.0, 1.0, "") + if ImGui.IsItemActive() or ImGui.IsItemHovered() then + ImGui.SetTooltip("%.3f", values[i + 1]) + end + ImGui.PopStyleColor(4) + ImGui.PopID() + end + ImGui.PopID() + + ImGui.SameLine() + ImGui.PushID("set2") + local values2 = s.values2 + local rows = 3 + local small_slider_size = ImVec2(18, math.floor((160.0 - (rows - 1) * spacing) / rows)) + for nx = 0, 3 do + if nx > 0 then ImGui.SameLine() end + ImGui.BeginGroup() + for ny = 0, rows - 1 do + ImGui.PushID(nx * rows + ny) + values2[nx + 1] = ImGui.VSliderFloat("##v", small_slider_size, values2[nx + 1], 0.0, 1.0, "") + if ImGui.IsItemActive() or ImGui.IsItemHovered() then + ImGui.SetTooltip("%.3f", values2[nx + 1]) + end + ImGui.PopID() + end + ImGui.EndGroup() + end + ImGui.PopID() + + ImGui.SameLine() + ImGui.PushID("set3") + for i = 0, 3 do + if i > 0 then ImGui.SameLine() end + ImGui.PushID(i) + ImGui.PushStyleVar(21 --[[ImGuiStyleVar.GrabMinSize]], 40) + values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(40, 160), values[i + 1], 0.0, 1.0, "%.2f\nsec") + ImGui.PopStyleVar() + ImGui.PopID() + end + ImGui.PopID() + ImGui.PopStyleVar() + ImGui.TreePop() + end end ------------------------------------------------------------------------------- -- [SECTION] DemoWindowWidgets() ------------------------------------------------------------------------------- ---- Calls a (global) demo section if it exists, otherwise shows a placeholder -local function Sub(fn, title, ...) - if fn then fn(...) else - if ImGui.TreeNode(title) then DemoNotPorted(title) ImGui.TreePop() end - end -end - -function DemoWindowWidgets(data) - -- ImGui.SetNextItemOpen(true, ImGuiCond.Once) +function DemoWindowWidgets(demo_data) + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) if not ImGui.CollapsingHeader("Widgets") then return end - -- IMGUI_DEMO_MARKER("Widgets") + -- IMGUI_DEMO_MARKER("Widgets"); - local disable_all = data.DisableSections -- The Checkbox for that is inside the "Disabled" section at the bottom - local override_liveedit = data.LiveEditOverride + local disable_all = demo_data.DisableSections -- The Checkbox for that is inside the "Disabled" section at the bottom + local override_liveedit = demo_data.LiveEditOverride if disable_all then ImGui.BeginDisabled() end if override_liveedit then - ImGui.PushItemFlag(128 --[[ImGuiItemFlags.LiveEditOnInputText]], DemoHas(data.LiveEditFlags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]])) - ImGui.PushItemFlag(256 --[[ImGuiItemFlags.LiveEditOnInputScalar]], DemoHas(data.LiveEditFlags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]])) + ImGui.PushItemFlag(128 --[[ImGuiItemFlags.LiveEditOnInputText]], bit32.band(demo_data.LiveEditFlags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) ~= 0) + ImGui.PushItemFlag(256 --[[ImGuiItemFlags.LiveEditOnInputScalar]], bit32.band(demo_data.LiveEditFlags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) ~= 0) end - Sub(DemoWindowWidgetsBasic, "Basic") - Sub(DemoWindowWidgetsBullets, "Bullets") - Sub(DemoWindowWidgetsCollapsingHeaders, "Collapsing Headers") - Sub(DemoWindowWidgetsComboBoxes, "Combo") - Sub(DemoWindowWidgetsColorAndPickers, "Color/Picker Widgets") - Sub(DemoWindowWidgetsDataTypes, "Data Types") + DemoWindowWidgetsBasic() + DemoWindowWidgetsBullets() + DemoWindowWidgetsCollapsingHeaders() + DemoWindowWidgetsComboBoxes() + DemoWindowWidgetsColorAndPickers() + DemoWindowWidgetsDataTypes() if disable_all then ImGui.EndDisabled() end - Sub(DemoWindowWidgetsDisableBlocks, "Disable Blocks", data) + DemoWindowWidgetsDisableBlocks(demo_data) if disable_all then ImGui.BeginDisabled() end - Sub(DemoWindowWidgetsDragAndDrop, "Drag and Drop") - Sub(DemoWindowWidgetsDragsAndSliders, "Drag/Slider Flags") - Sub(DemoWindowWidgetsFonts, "Fonts") - Sub(DemoWindowWidgetsImages, "Images") - Sub(DemoWindowWidgetsListBoxes, "List Boxes") - Sub(DemoWindowWidgetsLiveEdit, "Live Edit Flags", data) - Sub(DemoWindowWidgetsMixedValues, "Mixed Values") - Sub(DemoWindowWidgetsMultiComponents, "Multi-component Widgets") - Sub(DemoWindowWidgetsPlotting, "Plotting") - Sub(DemoWindowWidgetsProgressBars, "Progress Bars") - Sub(DemoWindowWidgetsQueryingStatuses, "Querying Item Status (Edited/Active/Hovered etc.)") - Sub(DemoWindowWidgetsSelectables, "Selectables") - Sub(DemoWindowWidgetsSelectionAndMultiSelect, "Selection State & Multi-Select", data) - Sub(DemoWindowWidgetsTabs, "Tabs") - Sub(DemoWindowWidgetsText, "Text") - Sub(DemoWindowWidgetsTextFilter, "Text Filter") - Sub(DemoWindowWidgetsTextInput, "Text Input") - Sub(DemoWindowWidgetsTooltips, "Tooltips") - Sub(DemoWindowWidgetsTreeNodes, "Tree Nodes") - Sub(DemoWindowWidgetsVerticalSliders, "Vertical Sliders") + DemoWindowWidgetsDragAndDrop() + DemoWindowWidgetsDragsAndSliders() + DemoWindowWidgetsFonts() + DemoWindowWidgetsImages() + DemoWindowWidgetsListBoxes() + DemoWindowWidgetsLiveEdit(demo_data) + DemoWindowWidgetsMixedValues() + DemoWindowWidgetsMultiComponents() + DemoWindowWidgetsPlotting() + DemoWindowWidgetsProgressBars() + DemoWindowWidgetsQueryingStatuses() + DemoWindowWidgetsSelectables() + DemoWindowWidgetsSelectionAndMultiSelect(demo_data) + DemoWindowWidgetsTabs() + DemoWindowWidgetsText() + DemoWindowWidgetsTextFilter() + DemoWindowWidgetsTextInput() + DemoWindowWidgetsTooltips() + DemoWindowWidgetsTreeNodes() + DemoWindowWidgetsVerticalSliders() if override_liveedit then ImGui.PopItemFlag() @@ -22550,1237 +25277,897 @@ function DemoWindowWidgets(data) end end -------------------------------------------------------------------------------- --- [SECTION] User Guide / ShowUserGuide() -------------------------------------------------------------------------------- - -function ImGui.ShowUserGuide() - local io = ImGui.GetIO() - ImGui.BulletText("Double-click on title bar to collapse window.") - ImGui.BulletText( - "Click and drag on lower corner or border to resize window.\n" .. - "(double-click to auto fit window to its contents)") - ImGui.BulletText("Ctrl+Click on a slider or drag box to input value as text.") - ImGui.BulletText("Tab/Shift+Tab to cycle through keyboard editable fields.") - ImGui.BulletText("Ctrl+Tab/Ctrl+Shift+Tab to focus windows.") - if io.FontAllowUserScaling then - ImGui.BulletText("Ctrl+Mouse Wheel to zoom window contents.") - end - ImGui.BulletText("While inputting text:\n") - ImGui.Indent() - ImGui.BulletText("Ctrl+Left/Right to word jump.") - ImGui.BulletText("Ctrl+A or double-click to select all.") - ImGui.BulletText("Ctrl+X/C/V to use clipboard cut/copy/paste.") - ImGui.BulletText("Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.") - ImGui.BulletText("Escape to revert.") - ImGui.Unindent() - ImGui.BulletText("With Keyboard controls enabled:") - ImGui.Indent() - ImGui.BulletText("Arrow keys or Home/End/PageUp/PageDown to navigate.") - ImGui.BulletText("Space to activate a widget.") - ImGui.BulletText("Return to input text into a widget.") - ImGui.BulletText("Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus.") - ImGui.BulletText("Alt to jump to the menu layer of a window.") - ImGui.BulletText("Menu or Shift+F10 to open a context menu.") - ImGui.Unindent() - ImGui.BulletText("With Gamepad controls enabled:") - ImGui.Indent() - ImGui.BulletText("D-Pad: Navigate / Tweak / Resize (in Windowing mode).") - ImGui.BulletText("%s Face button: Activate / Open / Toggle. Hold: activate with text input.", io.ConfigNavSwapGamepadButtons and "East" or "South") - ImGui.BulletText("%s Face button: Cancel / Close / Exit.", io.ConfigNavSwapGamepadButtons and "South" or "East") - ImGui.BulletText("West Face button: Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows).") - ImGui.BulletText("North Face button: Open Context Menu.") - ImGui.BulletText("L1/R1: Tweak Slower/Faster, Focus Previous/Next (in Windowing Mode).") - ImGui.Unindent() -end -end --[[ imgui_demo.lua ]] - -do --[[ imgui_demo_2.lua ]] ---- Dear ImGui WIP --- (Demo Code, part 2): DemoWindowLayout(), DemoWindowPopups(), DemoWindowTables(), DemoWindowColumns(), --- DemoWindowInputs() and all ShowExampleAppXXX() example apps. --- Port of imgui_demo.cpp (docking branch). Globals are shared with imgui_demo.lua (HelpMarker, ShowExampleMenuFile, ...) - --- Helpers macros --- We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, --- but making an exception here as those are largely simplifying code... --- In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. -local IM_MIN = math.min -local IM_MAX = math.max -local function IM_CLAMP(V, MN, MX) return (V < MN) and MN or (V > MX) and MX or V end -local _ -local function IMGUI_DEMO_MARKER(_) end -- upstream hook, no-op here - ---- `char buf[size] = "str"` -> zero-terminated byte table -local function Buf(str, size) - local t = {} - for i = 1, #str do t[i] = string.byte(str, i) end - t[#str + 1] = 0 - if size then for i = #str + 2, size do t[i] = 0 end end - return t -end ---- byte table -> Lua string (up to the zero terminator) -local function BufStr(buf) - local n = 0 - while buf[n + 1] ~= nil and buf[n + 1] ~= 0 do n = n + 1 end - return ImGui._ByteArrayToString(buf, 1, n + 1) -end -local function BufSet(buf, str) - for i = 1, #str do buf[i] = string.byte(str, i) end - buf[#str + 1] = 0 -end - ---- ImColor::HSV() as ImVec4 -local function HSV(h, s, v, a) - local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v) - return ImVec4(r, g, b, a or 1.0) -end -local function B2I(b) return b and 1 or 0 end - -local function Has(flags, f) return bit32.band(flags, f) ~= 0 end -local function NotSupported() ImGui.TextDisabled("(not supported on Roblox)") end -local function NotPorted(what) ImGui.TextDisabled("(not ported yet%s)", what and (": " .. what) or "") end - -local function DemoHelpMarker(desc) - if HelpMarker then HelpMarker(desc) return end - ImGui.TextDisabled("(?)") - if ImGui.BeginItemTooltip() then - ImGui.PushTextWrapPos(ImGui.GetFontSize() * 35.0) - ImGui.TextUnformatted(desc) - ImGui.PopTextWrapPos() - ImGui.EndTooltip() - end -end -local function DemoMenuFile() if ShowExampleMenuFile then ShowExampleMenuFile() end end - ---- Minimal ImGuiTextFilter stand-in when the library one isn't available -local function MakeTextFilter() - if ImGuiTextFilter then return ImGuiTextFilter() end - local f = { InputBuf = Buf("", 256) } - function f:Draw(label, width) - if width and width ~= 0 then ImGui.SetNextItemWidth(width) end - return ImGui.InputText(label or "Filter (inc,-exc)", self.InputBuf, 256) - end - function f:IsActive() return self.InputBuf[1] ~= 0 end - function f:Clear() self.InputBuf[1] = 0 end - function f:Build() end - function f:PassFilter(text, text_end) - if text_end then text = string.sub(text, 1, text_end - 1) end - local s = BufStr(self.InputBuf) - if s == "" then return true end - local any_inc, pass_inc = false, false - for tok in string.gmatch(s, "[^,]+") do - tok = string.match(tok, "^%s*(.-)%s*$") - if tok ~= "" then - if string.sub(tok, 1, 1) == "-" then - if #tok > 1 and string.find(string.lower(text), string.lower(string.sub(tok, 2)), 1, true) then return false end - else - any_inc = true - if string.find(string.lower(text), string.lower(tok), 1, true) then pass_inc = true end - end - end - end - return (not any_inc) or pass_inc - end - return f -end - --- ImGuiInputTextCallbackData helpers (the port's callback data has no methods). Buf is a 1-based zero-terminated --- byte table, positions are 0-based like C++. -local function CB_DeleteChars(data, pos, bytes_count) - local buf = data.Buf - local len = data.BufTextLen - for i = pos + 1, len - bytes_count + 1 do buf[i] = buf[i + bytes_count] end - for i = len - bytes_count + 2, len + 1 do buf[i] = 0 end - if data.CursorPos >= pos + bytes_count then data.CursorPos = data.CursorPos - bytes_count - elseif data.CursorPos >= pos then data.CursorPos = pos end - data.SelectionStart = data.CursorPos; data.SelectionEnd = data.CursorPos - data.BufDirty = true - data.BufTextLen = len - bytes_count -end -local function CB_InsertChars(data, pos, text) - local n = #text - if n == 0 then return end - if data.BufTextLen + n >= data.BufSize then return end - local buf = data.Buf - for i = data.BufTextLen + 1, pos + 1, -1 do buf[i + n] = buf[i] end - for i = 1, n do buf[pos + i] = string.byte(text, i) end - if data.CursorPos >= pos then data.CursorPos = data.CursorPos + n end - data.SelectionStart = data.CursorPos; data.SelectionEnd = data.CursorPos - data.BufDirty = true - data.BufTextLen = data.BufTextLen + n -end -local function CB_SelectAll(data) data.SelectionStart = 0; data.SelectionEnd = data.BufTextLen end - ---- ImGui::BeginChild() wrapper accepting upstream args -local function BeginChild(id, size, child_flags, window_flags) - return ImGui.BeginChild(id, size or ImVec2(0, 0), child_flags or 0, window_flags or 0) -end - ------------------------------------------------------------------------------- -- [SECTION] DemoWindowLayout() ------------------------------------------------------------------------------- -local SL = { - disable_mouse_wheel = false, disable_menu = false, - draw_lines = 3, max_height_in_lines = 10, - offset_x = 0, override_bg_color = true, child_flags = nil, - f = 0.0, show_indented_items = true, +S.DemoWindowLayout = { + -- Child windows + disable_mouse_wheel = false, + disable_menu = false, + draw_lines = 3, + max_height_in_lines = 10, + offset_x = 0, + override_bg_color = true, + child_flags = bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.ResizeX, ImGuiChildFlags.ResizeY), + -- Widgets Width + f = 0.0, + show_indented_items = true, + -- Basic Horizontal Layout c1 = false, c2 = false, c3 = false, c4 = false, - f0 = 1.0, f1 = 2.0, f2 = 3.0, item = -1, selection = { 0, 1, 2, 3 }, - track_item = 50, enable_track = true, enable_extra_decorations = false, scroll_to_off_px = 0.0, scroll_to_pos_px = 200.0, - lines = 7, show_horizontal_contents_size_demo_window = false, - show_h_scrollbar = true, show_button = true, show_tree_nodes = true, show_text_wrapped = false, show_columns = true, - show_tab_bar = true, show_child = false, explicit_content_size = false, contents_size_x = 300.0, - clip_size = nil, clip_offset = nil, + f0 = 1.0, f1 = 2.0, f2 = 3.0, + item = -1, + selection = { 0, 1, 2, 3 }, + -- Scrolling + track_item = 50, + enable_track = true, + enable_extra_decorations = false, + scroll_to_off_px = 0.0, + scroll_to_pos_px = 200.0, + lines = 7, + show_horizontal_contents_size_demo_window = false, + show_h_scrollbar = true, + show_button = true, + show_tree_nodes = true, + show_text_wrapped = false, + show_columns = true, + show_tab_bar = true, + show_child = false, + explicit_content_size = false, + contents_size_x = 300.0, + -- Text Clipping + size = ImVec2(100.0, 100.0), + offset = ImVec2(30.0, 30.0), + -- Overlap Mode enable_allow_overlap = true, } -local function DemoWindowLayout_ChildWindows() - IMGUI_DEMO_MARKER("Layout/Child windows") - ImGui.SeparatorText("Child windows") - - DemoHelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.") - _, SL.disable_mouse_wheel = ImGui.Checkbox("Disable Mouse Wheel", SL.disable_mouse_wheel) - _, SL.disable_menu = ImGui.Checkbox("Disable Menu", SL.disable_menu) - - -- Child 1: no border, enable horizontal scrollbar - do - local window_flags = 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]] - if SL.disable_mouse_wheel then - window_flags = bit32.bor(window_flags, 16 --[[ImGuiWindowFlags.NoScrollWithMouse]]) - end - BeginChild("ChildL", ImVec2(ImGui.GetContentRegionAvail().x * 0.5, 260), 0 --[[ImGuiChildFlags.None]], window_flags) - for i = 0, 99 do - ImGui.Text("%04d: scrollable region", i) - end - ImGui.EndChild() +function DemoWindowLayout() + local s = S.DemoWindowLayout + if not ImGui.CollapsingHeader("Layout & Scrolling") then + return end - ImGui.SameLine() + if ImGui.TreeNode("Child windows") then + IMGUI_DEMO_MARKER("Layout/Child windows") + ImGui.SeparatorText("Child windows") - -- Child 2: rounded border - do - local window_flags = 0 --[[ImGuiWindowFlags.None]] - if SL.disable_mouse_wheel then - window_flags = bit32.bor(window_flags, 16 --[[ImGuiWindowFlags.NoScrollWithMouse]]) - end - if not SL.disable_menu then - window_flags = bit32.bor(window_flags, 1024 --[[ImGuiWindowFlags.MenuBar]]) - end - ImGui.PushStyleVar(7 --[[ImGuiStyleVar.ChildRounding]], 5.0) - BeginChild("ChildR", ImVec2(0, 260), 1 --[[ImGuiChildFlags.Borders]], window_flags) - if not SL.disable_menu and ImGui.BeginMenuBar() then - if ImGui.BeginMenu("Menu") then - DemoMenuFile() - ImGui.EndMenu() + HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.") + _, s.disable_mouse_wheel = ImGui.Checkbox("Disable Mouse Wheel", s.disable_mouse_wheel) + _, s.disable_menu = ImGui.Checkbox("Disable Menu", s.disable_menu) + + -- Child 1: no border, enable horizontal scrollbar + do + local window_flags = 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]] + if s.disable_mouse_wheel then + window_flags = bit32.bor(window_flags, 16 --[[ImGuiWindowFlags.NoScrollWithMouse]]) end - ImGui.EndMenuBar() - end - if ImGui.BeginTable("split", 2, bit32.bor(1 --[[ImGuiTableFlags.Resizable]], 16 --[[ImGuiTableFlags.NoSavedSettings]])) then + ImGui.BeginChild("ChildL", ImVec2(ImGui.GetContentRegionAvail().x * 0.5, 260), 0 --[[ImGuiChildFlags.None]], window_flags) for i = 0, 99 do - local buf = string.format("%03d", i) - ImGui.TableNextColumn() - ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + ImGui.Text("%04d: scrollable region", i) end - ImGui.EndTable() + ImGui.EndChild() end - ImGui.EndChild() - ImGui.PopStyleVar() - end - -- Child 3: manual-resize - ImGui.SeparatorText("Manual-resize") - do - DemoHelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.") - -- if ImGui.Button("Set Height to 200") then - -- ImGui.SetNextWindowSize(ImVec2(-FLT_MIN, 200.0)) - -- end + ImGui.SameLine() - ImGui.PushStyleColor(3 --[[ImGuiCol.ChildBg]], ImGui.GetStyleColorVec4(7 --[[ImGuiCol.FrameBg]])) - if BeginChild("ResizableChild", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeightWithSpacing() * 8), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 8 --[[ImGuiChildFlags.ResizeY]])) then - for n = 0, 9 do - ImGui.Text("Line %04d", n) + -- Child 2: rounded border + do + local window_flags = 0 --[[ImGuiWindowFlags.None]] + if s.disable_mouse_wheel then + window_flags = bit32.bor(window_flags, 16 --[[ImGuiWindowFlags.NoScrollWithMouse]]) end - end - ImGui.PopStyleColor() - ImGui.EndChild() - end - - -- Child 4: auto-resizing height with a limit - ImGui.SeparatorText("Auto-resize with constraints") - do - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - SL.draw_lines = ImGui.DragInt("Lines Count", SL.draw_lines, 0.2) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - SL.max_height_in_lines = ImGui.DragInt("Max Height (in Lines)", SL.max_height_in_lines, 0.2) - - ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 1), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], ImGui.GetTextLineHeightWithSpacing() * SL.max_height_in_lines)) - if BeginChild("ConstrainedChild", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 32 --[[ImGuiChildFlags.AutoResizeY]])) then - for n = 0, SL.draw_lines - 1 do - ImGui.Text("Line %04d", n) + if not s.disable_menu then + window_flags = bit32.bor(window_flags, 1024 --[[ImGuiWindowFlags.MenuBar]]) end - end - ImGui.EndChild() - end - - ImGui.SeparatorText("Misc/Advanced") - - -- Demonstrate a few extra things - -- - Changing ImGuiCol.ChildBg (which is transparent black in default styles) - -- - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) - -- You can also call SetNextWindowPos() to position the child window. The parent window will effectively - -- layout from this position. - -- - Using ImGui.GetItemRectMin/Max() to query the "item" state (because the child window is an item from - -- the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details. - do - if SL.child_flags == nil then SL.child_flags = bit32.bor(1 --[[ImGuiChildFlags.Borders]], 4 --[[ImGuiChildFlags.ResizeX]], 8 --[[ImGuiChildFlags.ResizeY]]) end - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - SL.offset_x = ImGui.DragInt("Offset X", SL.offset_x, 1.0, -1000, 1000) - _, SL.override_bg_color = ImGui.Checkbox("Override ChildBg color", SL.override_bg_color) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_Borders", SL.child_flags, 1 --[[ImGuiChildFlags.Borders]]) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", SL.child_flags, 2 --[[ImGuiChildFlags.AlwaysUseWindowPadding]]) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeX", SL.child_flags, 4 --[[ImGuiChildFlags.ResizeX]]) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeY", SL.child_flags, 8 --[[ImGuiChildFlags.ResizeY]]) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_FrameStyle", SL.child_flags, 128 --[[ImGuiChildFlags.FrameStyle]]) - ImGui.SameLine(); DemoHelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.") - if Has(SL.child_flags, 128 --[[ImGuiChildFlags.FrameStyle]]) then - SL.override_bg_color = false + ImGui.PushStyleVar(7 --[[ImGuiStyleVar.ChildRounding]], 5.0) + ImGui.BeginChild("ChildR", ImVec2(0, 260), 1 --[[ImGuiChildFlags.Borders]], window_flags) + if not s.disable_menu and ImGui.BeginMenuBar() then + if ImGui.BeginMenu("Menu") then + ShowExampleMenuFile() + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end + if ImGui.BeginTable("split", 2, bit32.bor(1 --[[ImGuiTableFlags.Resizable]], 16 --[[ImGuiTableFlags.NoSavedSettings]])) then + for i = 0, 99 do + local buf = string.format("%03d", i) + ImGui.TableNextColumn() + ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + end + ImGui.EndTable() + end + ImGui.EndChild() + ImGui.PopStyleVar() end - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + SL.offset_x) - if SL.override_bg_color then - ImGui.PushStyleColor(3 --[[ImGuiCol.ChildBg]], IM_COL32(255, 0, 0, 100)) - end - BeginChild("Red", ImVec2(200, 100), SL.child_flags, 0 --[[ImGuiWindowFlags.None]]) - if SL.override_bg_color then + -- Child 3: manual-resize + ImGui.SeparatorText("Manual-resize") + do + HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.") + --if (ImGui.Button("Set Height to 200")) + -- ImGui.SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f)); + + ImGui.PushStyleColor(3 --[[ImGuiCol.ChildBg]], ImGui.GetStyleColorVec4(7 --[[ImGuiCol.FrameBg]])) + if ImGui.BeginChild("ResizableChild", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeightWithSpacing() * 8), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 8 --[[ImGuiChildFlags.ResizeY]])) then + for n = 0, 9 do + ImGui.Text("Line %04d", n) + end + end ImGui.PopStyleColor() + ImGui.EndChild() end - for n = 0, 49 do - ImGui.Text("Some test %d", n) + -- Child 4: auto-resizing height with a limit + ImGui.SeparatorText("Auto-resize with constraints") + do + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.draw_lines = ImGui.DragInt("Lines Count", s.draw_lines, 0.2) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.max_height_in_lines = ImGui.DragInt("Max Height (in Lines)", s.max_height_in_lines, 0.2) + + ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 1), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], ImGui.GetTextLineHeightWithSpacing() * s.max_height_in_lines)) + if ImGui.BeginChild("ConstrainedChild", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 32 --[[ImGuiChildFlags.AutoResizeY]])) then + for n = 0, s.draw_lines - 1 do + ImGui.Text("Line %04d", n) + end + end + ImGui.EndChild() end - ImGui.EndChild() - local child_is_hovered = ImGui.IsItemHovered() - local child_rect_min = ImGui.GetItemRectMin() - local child_rect_max = ImGui.GetItemRectMax() - ImGui.Text("Hovered: %d", B2I(child_is_hovered)) - ImGui.Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y) + + ImGui.SeparatorText("Misc/Advanced") + + -- Demonstrate a few extra things + -- - Changing ImGuiCol.ChildBg (which is transparent black in default styles) + -- - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) + -- You can also call SetNextWindowPos() to position the child window. The parent window will effectively + -- layout from this position. + -- - Using ImGui.GetItemRectMin/Max() to query the "item" state (because the child window is an item from + -- the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details. + do + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.offset_x = ImGui.DragInt("Offset X", s.offset_x, 1.0, -1000, 1000) + _, s.override_bg_color = ImGui.Checkbox("Override ChildBg color", s.override_bg_color) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_Borders", s.child_flags, 1 --[[ImGuiChildFlags.Borders]]) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", s.child_flags, 2 --[[ImGuiChildFlags.AlwaysUseWindowPadding]]) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeX", s.child_flags, 4 --[[ImGuiChildFlags.ResizeX]]) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeY", s.child_flags, 8 --[[ImGuiChildFlags.ResizeY]]) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_FrameStyle", s.child_flags, 128 --[[ImGuiChildFlags.FrameStyle]]) + ImGui.SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.") + if bit32.band(s.child_flags, 128 --[[ImGuiChildFlags.FrameStyle]]) ~= 0 then + s.override_bg_color = false + end + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + s.offset_x) + if s.override_bg_color then + ImGui.PushStyleColor(3 --[[ImGuiCol.ChildBg]], IM_COL32(255, 0, 0, 100)) + end + ImGui.BeginChild("Red", ImVec2(200, 100), s.child_flags, 0 --[[ImGuiWindowFlags.None]]) + if s.override_bg_color then + ImGui.PopStyleColor() + end + + for n = 0, 49 do + ImGui.Text("Some test %d", n) + end + ImGui.EndChild() + local child_is_hovered = ImGui.IsItemHovered() + local child_rect_min = ImGui.GetItemRectMin() + local child_rect_max = ImGui.GetItemRectMax() + ImGui.Text("Hovered: %d", child_is_hovered and 1 or 0) + ImGui.Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y) + end + + ImGui.TreePop() end -end -local function DemoWindowLayout_WidgetsWidth() - IMGUI_DEMO_MARKER("Layout/Widgets Width") - _, SL.show_indented_items = ImGui.Checkbox("Show indented items", SL.show_indented_items) + if ImGui.TreeNode("Widgets Width") then + IMGUI_DEMO_MARKER("Layout/Widgets Width") + _, s.show_indented_items = ImGui.Checkbox("Show indented items", s.show_indented_items) - -- Use SetNextItemWidth() to set the width of a single upcoming item. - -- Use PushItemWidth()/PopItemWidth() to set the width of a group of items. - -- In real code use you'll probably want to choose width values that are proportional to your font size - -- e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. + -- Use SetNextItemWidth() to set the width of a single upcoming item. + -- Use PushItemWidth()/PopItemWidth() to set the width of a group of items. + -- In real code use you'll probably want to choose width values that are proportional to your font size + -- e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. - local function block(text, help, width, l1, l2) - ImGui.Text(text) - if help then ImGui.SameLine(); DemoHelpMarker(help) end - ImGui.PushItemWidth(width) - SL.f = ImGui.DragFloat(l1, SL.f) - if SL.show_indented_items then + ImGui.Text("SetNextItemWidth/PushItemWidth(100)") + ImGui.SameLine(); HelpMarker("Fixed width.") + ImGui.PushItemWidth(100) + s.f = ImGui.DragFloat("float##1b", s.f) + if s.show_indented_items then ImGui.Indent() - SL.f = ImGui.DragFloat(l2, SL.f) + s.f = ImGui.DragFloat("float (indented)##1b", s.f) ImGui.Unindent() end ImGui.PopItemWidth() - end - block("SetNextItemWidth/PushItemWidth(100)", "Fixed width.", 100, "float##1b", "float (indented)##1b") - block("SetNextItemWidth/PushItemWidth(-100)", "Align to right edge minus 100", -100, "float##2a", "float (indented)##2b") - block("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)", "Half of available width.\n(~ right-cursor_pos)\n(works within a column set)", ImGui.GetContentRegionAvail().x * 0.5, "float##3a", "float (indented)##3b") - block("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)", "Align to right edge minus half", -ImGui.GetContentRegionAvail().x * 0.5, "float##4a", "float (indented)##4b") - block("SetNextItemWidth/PushItemWidth(-Min(GetContentRegionAvail().x * 0.40f, GetFontSize() * 12))", nil, -IM_MIN(ImGui.GetFontSize() * 12, ImGui.GetContentRegionAvail().x * 0.40), "float##5a", "float (indented)##5b") - -- Demonstrate using PushItemWidth to surround three items. - -- Calling SetNextItemWidth() before each of them would have the same effect. - block("SetNextItemWidth/PushItemWidth(-FLT_MIN)", "Align to right edge", -1.1754943508223e-38 --[[FLT_MIN]], "##float6a", "float (indented)##6b") -end -local function DemoWindowLayout_BasicHorizontal() - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout") - ImGui.TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)") - - -- Text - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine") - ImGui.Text("Two items: Hello"); ImGui.SameLine() - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") - - -- Adjust spacing - ImGui.Text("More spacing: Hello"); ImGui.SameLine(0, 20) - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") - - -- Button - ImGui.AlignTextToFramePadding() - ImGui.Text("Normal buttons"); ImGui.SameLine() - ImGui.Button("Banana"); ImGui.SameLine() - ImGui.Button("Apple"); ImGui.SameLine() - ImGui.Button("Corniflower") - - -- Button - ImGui.Text("Small buttons"); ImGui.SameLine() - ImGui.SmallButton("Like this one"); ImGui.SameLine() - ImGui.Text("can fit within a text block.") - - -- Aligned to arbitrary position. Easy/cheap column. - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)") - ImGui.Text("Aligned") - ImGui.SameLine(150); ImGui.Text("x=150") - ImGui.SameLine(300); ImGui.Text("x=300") - ImGui.Text("Aligned") - ImGui.SameLine(150); ImGui.SmallButton("x=150") - ImGui.SameLine(300); ImGui.SmallButton("x=300") - - -- Checkbox - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)") - _, SL.c1 = ImGui.Checkbox("My", SL.c1); ImGui.SameLine() - _, SL.c2 = ImGui.Checkbox("Tailor", SL.c2); ImGui.SameLine() - _, SL.c3 = ImGui.Checkbox("Is", SL.c3); ImGui.SameLine() - _, SL.c4 = ImGui.Checkbox("Rich", SL.c4) - - -- Various - ImGui.PushItemWidth(ImGui.CalcTextSize("AAAAAAA").x) - local items = { "AAAA", "BBBB", "CCCC", "DDDD" } - if ImGui.Combo then - SL.item = ImGui.Combo("Combo", SL.item, items, #items) - else - NotPorted("Combo") - end - ImGui.SameLine() - SL.f0 = ImGui.SliderFloat("X", SL.f0, 0.0, 5.0); ImGui.SameLine() - SL.f1 = ImGui.SliderFloat("Y", SL.f1, 0.0, 5.0); ImGui.SameLine() - SL.f2 = ImGui.SliderFloat("Z", SL.f2, 0.0, 5.0) - - ImGui.Text("Lists:") - for i = 1, 4 do - if i > 1 then ImGui.SameLine() end - ImGui.PushID(i - 1) - if ImGui.ListBox then - SL.selection[i] = ImGui.ListBox("", SL.selection[i], items, #items) - else - NotPorted("ListBox") + ImGui.Text("SetNextItemWidth/PushItemWidth(-100)") + ImGui.SameLine(); HelpMarker("Align to right edge minus 100") + ImGui.PushItemWidth(-100) + s.f = ImGui.DragFloat("float##2a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##2b", s.f) + ImGui.Unindent() end - ImGui.PopID() - -- ImGui.SetItemTooltip("ListBox %d hovered", i) + ImGui.PopItemWidth() + + ImGui.Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)") + ImGui.SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)") + ImGui.PushItemWidth(ImGui.GetContentRegionAvail().x * 0.5) + s.f = ImGui.DragFloat("float##3a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##3b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + ImGui.Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)") + ImGui.SameLine(); HelpMarker("Align to right edge minus half") + ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.5) + s.f = ImGui.DragFloat("float##4a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##4b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + ImGui.Text("SetNextItemWidth/PushItemWidth(-Min(GetContentRegionAvail().x * 0.40f, GetFontSize() * 12))") + ImGui.PushItemWidth(-ImMin(ImGui.GetFontSize() * 12, ImGui.GetContentRegionAvail().x * 0.40)) + s.f = ImGui.DragFloat("float##5a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##5b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + -- Demonstrate using PushItemWidth to surround three items. + -- Calling SetNextItemWidth() before each of them would have the same effect. + ImGui.Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)") + ImGui.SameLine(); HelpMarker("Align to right edge") + ImGui.PushItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + s.f = ImGui.DragFloat("##float6a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##6b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + ImGui.TreePop() end - ImGui.PopItemWidth() - -- Dummy - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy") - local button_sz = ImVec2(40, 40) - ImGui.Button("A", button_sz); ImGui.SameLine() - ImGui.Dummy(button_sz); ImGui.SameLine() - ImGui.Button("B", button_sz) + if ImGui.TreeNode("Basic Horizontal Layout") then + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout") + ImGui.TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)") - -- Manually wrapping - -- (we should eventually provide this as an automatic layout feature, but for now you can do it manually) - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping") - ImGui.Text("Manual wrapping:") - local style = ImGui.GetStyle() - local buttons_count = 20 - local window_visible_x2 = ImGui.GetCursorScreenPos().x + ImGui.GetContentRegionAvail().x - for n = 0, buttons_count - 1 do - ImGui.PushID(n) - ImGui.Button("Box", button_sz) - local last_button_x2 = ImGui.GetItemRectMax().x - local next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x -- Expected position if next button was on same line - if n + 1 < buttons_count and next_button_x2 < window_visible_x2 then + -- Text + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine") + ImGui.Text("Two items: Hello"); ImGui.SameLine() + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") + + -- Adjust spacing + ImGui.Text("More spacing: Hello"); ImGui.SameLine(0, 20) + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") + + -- Button + ImGui.AlignTextToFramePadding() + ImGui.Text("Normal buttons"); ImGui.SameLine() + ImGui.Button("Banana"); ImGui.SameLine() + ImGui.Button("Apple"); ImGui.SameLine() + ImGui.Button("Corniflower") + + -- Button + ImGui.Text("Small buttons"); ImGui.SameLine() + ImGui.SmallButton("Like this one"); ImGui.SameLine() + ImGui.Text("can fit within a text block.") + + -- Aligned to arbitrary position. Easy/cheap column. + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)") + ImGui.Text("Aligned") + ImGui.SameLine(150); ImGui.Text("x=150") + ImGui.SameLine(300); ImGui.Text("x=300") + ImGui.Text("Aligned") + ImGui.SameLine(150); ImGui.SmallButton("x=150") + ImGui.SameLine(300); ImGui.SmallButton("x=300") + + -- Checkbox + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)") + _, s.c1 = ImGui.Checkbox("My", s.c1); ImGui.SameLine() + _, s.c2 = ImGui.Checkbox("Tailor", s.c2); ImGui.SameLine() + _, s.c3 = ImGui.Checkbox("Is", s.c3); ImGui.SameLine() + _, s.c4 = ImGui.Checkbox("Rich", s.c4) + + -- Various + ImGui.PushItemWidth(ImGui.CalcTextSize("AAAAAAA").x) + local items = { "AAAA", "BBBB", "CCCC", "DDDD" } + s.item = ImGui.Combo("Combo", s.item, items, #items); ImGui.SameLine() + s.f0 = ImGui.SliderFloat("X", s.f0, 0.0, 5.0); ImGui.SameLine() + s.f1 = ImGui.SliderFloat("Y", s.f1, 0.0, 5.0); ImGui.SameLine() + s.f2 = ImGui.SliderFloat("Z", s.f2, 0.0, 5.0) + + ImGui.Text("Lists:") + for i = 0, 3 do + if i > 0 then ImGui.SameLine() end + ImGui.PushID(i) + s.selection[i + 1] = ImGui.ListBox("", s.selection[i + 1], items, #items) + ImGui.PopID() + --ImGui.SetItemTooltip("ListBox %d hovered", i); + end + ImGui.PopItemWidth() + + -- Dummy + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy") + local button_sz = ImVec2(40, 40) + ImGui.Button("A", button_sz); ImGui.SameLine() + ImGui.Dummy(button_sz); ImGui.SameLine() + ImGui.Button("B", button_sz) + + -- Manually wrapping + -- (we should eventually provide this as an automatic layout feature, but for now you can do it manually) + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping") + ImGui.Text("Manual wrapping:") + local style = ImGui.GetStyle() + local buttons_count = 20 + local window_visible_x2 = ImGui.GetCursorScreenPos().x + ImGui.GetContentRegionAvail().x + for n = 0, buttons_count - 1 do + ImGui.PushID(n) + ImGui.Button("Box", button_sz) + local last_button_x2 = ImGui.GetItemRectMax().x + local next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x -- Expected position if next button was on same line + if n + 1 < buttons_count and next_button_x2 < window_visible_x2 then + ImGui.SameLine() + end + ImGui.PopID() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Groups") then + IMGUI_DEMO_MARKER("Layout/Groups") + HelpMarker( + "BeginGroup() basically locks the horizontal position for new line. " .. + "EndGroup() bundles the whole group so that you can use \"item\" functions such as " .. + "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.") + ImGui.BeginGroup() + do + ImGui.BeginGroup() + ImGui.Button("AAA") ImGui.SameLine() + ImGui.Button("BBB") + ImGui.SameLine() + ImGui.BeginGroup() + ImGui.Button("CCC") + ImGui.Button("DDD") + ImGui.EndGroup() + ImGui.SameLine() + ImGui.Button("EEE") + ImGui.EndGroup() + ImGui.SetItemTooltip("First group hovered") end - ImGui.PopID() - end -end + -- Capture the group size and create widgets using the same size + local size = ImGui.GetItemRectSize() + local values = { 0.5, 0.20, 0.80, 0.60, 0.25 } + ImGui.PlotHistogram("##values", values, nil, #values, 0, nil, 0.0, 1.0, size) -local function DemoWindowLayout_Groups() - IMGUI_DEMO_MARKER("Layout/Groups") - DemoHelpMarker( - "BeginGroup() basically locks the horizontal position for new line. " .. - "EndGroup() bundles the whole group so that you can use \"item\" functions such as " .. - "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.") - ImGui.BeginGroup() - do - ImGui.BeginGroup() - ImGui.Button("AAA") + ImGui.Button("ACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) ImGui.SameLine() - ImGui.Button("BBB") - ImGui.SameLine() - ImGui.BeginGroup() - ImGui.Button("CCC") - ImGui.Button("DDD") + ImGui.Button("REACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) ImGui.EndGroup() ImGui.SameLine() - ImGui.Button("EEE") - ImGui.EndGroup() - ImGui.SetItemTooltip("First group hovered") - end - -- Capture the group size and create widgets using the same size - local size = ImGui.GetItemRectSize() - local values = { 0.5, 0.20, 0.80, 0.60, 0.25 } - ImGui.PlotHistogram("##values", values, nil, #values, 0, nil, 0.0, 1.0, size) - ImGui.Button("ACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) - ImGui.SameLine() - ImGui.Button("REACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) - ImGui.EndGroup() - ImGui.SameLine() - - ImGui.Button("LEVERAGE\nBUZZWORD", size) - ImGui.SameLine() - - if ImGui.BeginListBox and ImGui.BeginListBox("List", size) then - ImGui.Selectable("Selected", true) - ImGui.Selectable("Not Selected", false) - ImGui.EndListBox() - end -end - -local function DemoWindowLayout_TextBaseline() - IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment") - do - ImGui.BulletText("Text baseline:") - ImGui.SameLine(); DemoHelpMarker( - "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " .. - "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.") - ImGui.Indent() - - ImGui.Text("KO Blahblah"); ImGui.SameLine() - ImGui.Button("Some framed item"); ImGui.SameLine() - DemoHelpMarker("Baseline of button will look misaligned with text..") - - -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. - -- (because we don't know what's coming after the Text() statement, we need to move the text baseline - -- down by FramePadding.y ahead of time) - ImGui.AlignTextToFramePadding() - ImGui.Text("OK Blahblah"); ImGui.SameLine() - ImGui.Button("Some framed item##2"); ImGui.SameLine() - DemoHelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y") - - -- SmallButton() uses the same vertical padding as Text - ImGui.Button("TEST##1"); ImGui.SameLine() - ImGui.Text("TEST"); ImGui.SameLine() - ImGui.SmallButton("TEST##2") - - -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. - ImGui.AlignTextToFramePadding() - ImGui.Text("Text aligned to framed item"); ImGui.SameLine() - ImGui.Button("Item##1"); ImGui.SameLine() - ImGui.Text("Item"); ImGui.SameLine() - ImGui.SmallButton("Item##2"); ImGui.SameLine() - ImGui.Button("Item##3") - - ImGui.Unindent() - end - - ImGui.Spacing() - - do - ImGui.BulletText("Multi-line text:") - ImGui.Indent() - ImGui.Text("One\nTwo\nThree"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("Banana") - - ImGui.Text("Banana"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("One\nTwo\nThree") - - ImGui.Button("HOP##1"); ImGui.SameLine() - ImGui.Text("Banana"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("Banana") - - ImGui.Button("HOP##2"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("Banana") - ImGui.Unindent() - end - - ImGui.Spacing() - - do - ImGui.BulletText("Misc items:") - ImGui.Indent() - - -- SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. - ImGui.Button("80x80", ImVec2(80, 80)) + ImGui.Button("LEVERAGE\nBUZZWORD", size) ImGui.SameLine() - ImGui.Button("50x50", ImVec2(50, 50)) - ImGui.SameLine() - ImGui.Button("Button()") - ImGui.SameLine() - ImGui.SmallButton("SmallButton()") - -- Tree - -- (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags.DrawLinesNone to disable hierarchy outline) - local spacing = ImGui.GetStyle().ItemInnerSpacing.x - ImGui.Button("Button##1") -- Will make line higher - ImGui.SameLine(0.0, spacing) - if ImGui.TreeNodeEx("Node##1", 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) then - -- Placeholder tree data - for i = 0, 5 do - ImGui.BulletText("Item %d..", i) - end - ImGui.TreePop() + if ImGui.BeginListBox("List", size) then + ImGui.Selectable("Selected", true) + ImGui.Selectable("Not Selected", false) + ImGui.EndListBox() end - local padding = math.floor(ImGui.GetFontSize() * 1.20) -- Large padding - ImGui.PushStyleVarY(11 --[[ImGuiStyleVar.FramePadding]], padding) - ImGui.Button("Button##2") - ImGui.PopStyleVar() - ImGui.SameLine(0.0, spacing) - if ImGui.TreeNodeEx("Node##2", 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) then - ImGui.TreePop() + ImGui.TreePop() + end + + if ImGui.TreeNode("Text Baseline Alignment") then + IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment") + do + ImGui.BulletText("Text baseline:") + ImGui.SameLine(); HelpMarker( + "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " .. + "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.") + ImGui.Indent() + + ImGui.Text("KO Blahblah"); ImGui.SameLine() + ImGui.Button("Some framed item"); ImGui.SameLine() + HelpMarker("Baseline of button will look misaligned with text..") + + -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. + -- (because we don't know what's coming after the Text() statement, we need to move the text baseline + -- down by FramePadding.y ahead of time) + ImGui.AlignTextToFramePadding() + ImGui.Text("OK Blahblah"); ImGui.SameLine() + ImGui.Button("Some framed item##2"); ImGui.SameLine() + HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y") + + -- SmallButton() uses the same vertical padding as Text + ImGui.Button("TEST##1"); ImGui.SameLine() + ImGui.Text("TEST"); ImGui.SameLine() + ImGui.SmallButton("TEST##2") + + -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. + ImGui.AlignTextToFramePadding() + ImGui.Text("Text aligned to framed item"); ImGui.SameLine() + ImGui.Button("Item##1"); ImGui.SameLine() + ImGui.Text("Item"); ImGui.SameLine() + ImGui.SmallButton("Item##2"); ImGui.SameLine() + ImGui.Button("Item##3") + + ImGui.Unindent() end - -- Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. - -- Otherwise you can use SmallButton() (smaller fit). - ImGui.AlignTextToFramePadding() + ImGui.Spacing() - -- Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add - -- other contents "inside" the node. - local node_open = ImGui.TreeNode("Node##3") - ImGui.SameLine(0.0, spacing); ImGui.Button("Button##3") - if node_open then - -- Placeholder tree data - for i = 0, 5 do - ImGui.BulletText("Item %d..", i) - end - ImGui.TreePop() + do + ImGui.BulletText("Multi-line text:") + ImGui.Indent() + ImGui.Text("One\nTwo\nThree"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("Banana") + + ImGui.Text("Banana"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("One\nTwo\nThree") + + ImGui.Button("HOP##1"); ImGui.SameLine() + ImGui.Text("Banana"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("Banana") + + ImGui.Button("HOP##2"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("Banana") + ImGui.Unindent() end - -- Bullet - ImGui.Button("Button##4") - ImGui.SameLine(0.0, spacing) - ImGui.BulletText("Bullet text") + ImGui.Spacing() - ImGui.AlignTextToFramePadding() - ImGui.BulletText("Node") - ImGui.SameLine(0.0, spacing); ImGui.Button("Button##5") - ImGui.Unindent() - end -end + do + ImGui.BulletText("Misc items:") + ImGui.Indent() -local function DemoWindowLayout_HorizontalContentsSizeWindow() - if SL.explicit_content_size then - ImGui.SetNextWindowContentSize(ImVec2(SL.contents_size_x, 0.0)) - end - SL.show_horizontal_contents_size_demo_window = ImGui.Begin("Horizontal contents size demo window", SL.show_horizontal_contents_size_demo_window, SL.show_h_scrollbar and 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]] or 0) - IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window") - ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(2, 0)) - ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(2, 0)) - DemoHelpMarker( - "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n" .. - "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.") - _, SL.show_h_scrollbar = ImGui.Checkbox("H-scrollbar", SL.show_h_scrollbar) - _, SL.show_button = ImGui.Checkbox("Button", SL.show_button) -- Will grow contents size (unless explicitly overwritten) - _, SL.show_tree_nodes = ImGui.Checkbox("Tree nodes", SL.show_tree_nodes) -- Will grow contents size and display highlight over full width - _, SL.show_text_wrapped = ImGui.Checkbox("Text wrapped", SL.show_text_wrapped) -- Will grow and use contents size - _, SL.show_columns = ImGui.Checkbox("Columns", SL.show_columns) -- Will use contents size - _, SL.show_tab_bar = ImGui.Checkbox("Tab bar", SL.show_tab_bar) -- Will use contents size - _, SL.show_child = ImGui.Checkbox("Child", SL.show_child) -- Will grow and use contents size - _, SL.explicit_content_size = ImGui.Checkbox("Explicit content size", SL.explicit_content_size) - ImGui.Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui.GetScrollX(), ImGui.GetScrollMaxX(), ImGui.GetScrollY(), ImGui.GetScrollMaxY()) - if SL.explicit_content_size then - ImGui.SameLine() - ImGui.SetNextItemWidth(ImGui.CalcTextSize("123456").x) - SL.contents_size_x = ImGui.DragFloat("##csx", SL.contents_size_x) - local p = ImGui.GetCursorScreenPos() - ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), 4294967295 --[[IM_COL32_WHITE]]) - ImGui.GetWindowDrawList():AddRectFilled(ImVec2(p.x + SL.contents_size_x - 10, p.y), ImVec2(p.x + SL.contents_size_x, p.y + 10), 4294967295 --[[IM_COL32_WHITE]]) - ImGui.Dummy(ImVec2(0, 10)) - end - ImGui.PopStyleVar(2) - ImGui.Separator() - if SL.show_button then - ImGui.Button("this is a 300-wide button", ImVec2(300, 0)) - end - if SL.show_tree_nodes then - local open = true - if ImGui.TreeNode("this is a tree node") then - if ImGui.TreeNode("another one of those tree node...") then - ImGui.Text("Some tree contents") + -- SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. + ImGui.Button("80x80", ImVec2(80, 80)) + ImGui.SameLine() + ImGui.Button("50x50", ImVec2(50, 50)) + ImGui.SameLine() + ImGui.Button("Button()") + ImGui.SameLine() + ImGui.SmallButton("SmallButton()") + + -- Tree + -- (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags.DrawLinesNone to disable hierarchy outline) + local spacing = ImGui.GetStyle().ItemInnerSpacing.x + ImGui.Button("Button##1") -- Will make line higher + ImGui.SameLine(0.0, spacing) + if ImGui.TreeNodeEx("Node##1", 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) then + -- Placeholder tree data + for i = 0, 5 do + ImGui.BulletText("Item %d..", i) + end ImGui.TreePop() end - ImGui.TreePop() - end - ImGui.CollapsingHeader("CollapsingHeader", open) - end - if SL.show_text_wrapped then - ImGui.TextWrapped("This text should automatically wrap on the edge of the work rectangle.") - end - if SL.show_columns then - ImGui.Text("Tables:") - if ImGui.BeginTable("table", 4, 1920 --[[ImGuiTableFlags.Borders]]) then - for n = 0, 3 do - ImGui.TableNextColumn() - ImGui.Text("Width %.2f", ImGui.GetContentRegionAvail().x) + + local padding = math.floor(ImGui.GetFontSize() * 1.20) -- Large padding + ImGui.PushStyleVarY(11 --[[ImGuiStyleVar.FramePadding]], padding) + ImGui.Button("Button##2") + ImGui.PopStyleVar() + ImGui.SameLine(0.0, spacing) + if ImGui.TreeNodeEx("Node##2", 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]]) then + ImGui.TreePop() end - ImGui.EndTable() - end - ImGui.Text("Columns:") - if ImGui.Columns then - ImGui.Columns(4) - for n = 0, 3 do - ImGui.Text("Width %.2f", ImGui.GetColumnWidth()) - ImGui.NextColumn() + + -- Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. + -- Otherwise you can use SmallButton() (smaller fit). + ImGui.AlignTextToFramePadding() + + -- Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add + -- other contents "inside" the node. + local node_open = ImGui.TreeNode("Node##3") + ImGui.SameLine(0.0, spacing); ImGui.Button("Button##3") + if node_open then + -- Placeholder tree data + for i = 0, 5 do + ImGui.BulletText("Item %d..", i) + end + ImGui.TreePop() end - ImGui.Columns(1) - else - NotPorted("Columns") + + -- Bullet + ImGui.Button("Button##4") + ImGui.SameLine(0.0, spacing) + ImGui.BulletText("Bullet text") + + ImGui.AlignTextToFramePadding() + ImGui.BulletText("Node") + ImGui.SameLine(0.0, spacing); ImGui.Button("Button##5") + ImGui.Unindent() end - end - if SL.show_tab_bar and ImGui.BeginTabBar and ImGui.BeginTabBar("Hello") then - if ImGui.BeginTabItem("OneOneOne") then ImGui.EndTabItem() end - if ImGui.BeginTabItem("TwoTwoTwo") then ImGui.EndTabItem() end - if ImGui.BeginTabItem("ThreeThreeThree") then ImGui.EndTabItem() end - if ImGui.BeginTabItem("FourFourFour") then ImGui.EndTabItem() end - ImGui.EndTabBar() - end - if SL.show_child then - BeginChild("child", ImVec2(0, 0), 1 --[[ImGuiChildFlags.Borders]]) - ImGui.EndChild() - end - ImGui.End() -end -local function DemoWindowLayout_Scrolling() - IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical") - -- Vertical scroll functions - DemoHelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.") - - _, SL.enable_extra_decorations = ImGui.Checkbox("Decoration", SL.enable_extra_decorations) - - ImGui.PushItemWidth(ImGui.GetFontSize() * 10) - local changed - SL.track_item, changed = ImGui.DragInt("##item", SL.track_item, 0.25, 0, 99, "Item = %d") - SL.enable_track = SL.enable_track or changed - ImGui.SameLine() - _, SL.enable_track = ImGui.Checkbox("Track", SL.enable_track) - - local scroll_to_off - SL.scroll_to_off_px, scroll_to_off = ImGui.DragFloat("##off", SL.scroll_to_off_px, 1.00, 0, 3.4028234663853e+38 --[[FLT_MAX]], "+%.0f px") - ImGui.SameLine() - scroll_to_off = ImGui.Button("Scroll Offset") or scroll_to_off - - local scroll_to_pos - SL.scroll_to_pos_px, scroll_to_pos = ImGui.DragFloat("##pos", SL.scroll_to_pos_px, 1.00, -10, 3.4028234663853e+38 --[[FLT_MAX]], "X/Y = %.0f px") - ImGui.SameLine() - scroll_to_pos = ImGui.Button("Scroll To Pos") or scroll_to_pos - ImGui.PopItemWidth() - - if scroll_to_off or scroll_to_pos then - SL.enable_track = false + ImGui.TreePop() end - local style = ImGui.GetStyle() - local child_w = (ImGui.GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5 - if child_w < 1.0 then - child_w = 1.0 - end - ImGui.PushID("##VerticalScrolling") - local vnames = { "Top", "25%", "Center", "75%", "Bottom" } - for i = 0, 4 do - if i > 0 then ImGui.SameLine() end - ImGui.BeginGroup() - ImGui.TextUnformatted(vnames[i + 1]) + if ImGui.TreeNode("Scrolling") then + IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical") + -- Vertical scroll functions + HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.") - local child_flags = SL.enable_extra_decorations and 1024 --[[ImGuiWindowFlags.MenuBar]] or 0 - local child_id = ImGui.GetID(i) - local child_is_visible = BeginChild(child_id, ImVec2(child_w, 200.0), 1 --[[ImGuiChildFlags.Borders]], child_flags) - if ImGui.BeginMenuBar() then - ImGui.TextUnformatted("abc") - ImGui.EndMenuBar() + _, s.enable_extra_decorations = ImGui.Checkbox("Decoration", s.enable_extra_decorations) + + ImGui.PushItemWidth(ImGui.GetFontSize() * 10) + local track_changed + s.track_item, track_changed = ImGui.DragInt("##item", s.track_item, 0.25, 0, 99, "Item = %d") + s.enable_track = s.enable_track or track_changed + ImGui.SameLine() + _, s.enable_track = ImGui.Checkbox("Track", s.enable_track) + + local scroll_to_off + s.scroll_to_off_px, scroll_to_off = ImGui.DragFloat("##off", s.scroll_to_off_px, 1.00, 0, 3.4028234663853e+38 --[[FLT_MAX]], "+%.0f px") + ImGui.SameLine() + scroll_to_off = ImGui.Button("Scroll Offset") or scroll_to_off + + local scroll_to_pos + s.scroll_to_pos_px, scroll_to_pos = ImGui.DragFloat("##pos", s.scroll_to_pos_px, 1.00, -10, 3.4028234663853e+38 --[[FLT_MAX]], "X/Y = %.0f px") + ImGui.SameLine() + scroll_to_pos = ImGui.Button("Scroll To Pos") or scroll_to_pos + ImGui.PopItemWidth() + + if scroll_to_off or scroll_to_pos then + s.enable_track = false end - if scroll_to_off then - ImGui.SetScrollY(SL.scroll_to_off_px) + + local style = ImGui.GetStyle() + local child_w = (ImGui.GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5 + if child_w < 1.0 then + child_w = 1.0 end - if scroll_to_pos then - ImGui.SetScrollFromPosY(ImGui.GetCursorStartPos().y + SL.scroll_to_pos_px, i * 0.25) - end - if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items - for item = 0, 99 do - if SL.enable_track and item == SL.track_item then - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) - ImGui.SetScrollHereY(i * 0.25) -- 0.0f:top, 0.5f:center, 1.0f:bottom - else - ImGui.Text("Item %d", item) + ImGui.PushID("##VerticalScrolling") + for i = 0, 4 do + if i > 0 then ImGui.SameLine() end + ImGui.BeginGroup() + local names = { "Top", "25%", "Center", "75%", "Bottom" } + ImGui.TextUnformatted(names[i + 1]) + + local child_flags = 0 + if s.enable_extra_decorations then child_flags = 1024 --[[ImGuiWindowFlags.MenuBar]] end + local child_id = ImGui.GetID(i) + local child_is_visible = ImGui.BeginChild(child_id, ImVec2(child_w, 200.0), 1 --[[ImGuiChildFlags.Borders]], child_flags) + if ImGui.BeginMenuBar() then + ImGui.TextUnformatted("abc") + ImGui.EndMenuBar() + end + if scroll_to_off then + ImGui.SetScrollY(s.scroll_to_off_px) + end + if scroll_to_pos then + ImGui.SetScrollFromPosY(ImGui.GetCursorStartPos().y + s.scroll_to_pos_px, i * 0.25) + end + if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items + for item = 0, 99 do + if s.enable_track and item == s.track_item then + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) + ImGui.SetScrollHereY(i * 0.25) -- 0.0f:top, 0.5f:center, 1.0f:bottom + else + ImGui.Text("Item %d", item) + end end end + local scroll_y = ImGui.GetScrollY() + local scroll_max_y = ImGui.GetScrollMaxY() + ImGui.EndChild() + ImGui.Text("%.0f/%.0f", scroll_y, scroll_max_y) + ImGui.EndGroup() end - local scroll_y = ImGui.GetScrollY() - local scroll_max_y = ImGui.GetScrollMaxY() - ImGui.EndChild() - ImGui.Text("%.0f/%.0f", scroll_y, scroll_max_y) - ImGui.EndGroup() - end - ImGui.PopID() + ImGui.PopID() - -- Horizontal scroll functions - IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal") - ImGui.Spacing() - DemoHelpMarker( - "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" .. - "Because the clipping rectangle of most window hides half worth of WindowPadding on the " .. - "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " .. - "equivalent SetScrollFromPosY(+1) wouldn't.") - ImGui.PushID("##HorizontalScrolling") - local hnames = { "Left", "25%", "Center", "75%", "Right" } - for i = 0, 4 do - local child_height = ImGui.GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0 - local child_flags = bit32.bor(2048 --[[ImGuiWindowFlags.HorizontalScrollbar]], SL.enable_extra_decorations and 16384 --[[ImGuiWindowFlags.AlwaysVerticalScrollbar]] or 0) - local child_id = ImGui.GetID(i) - local child_is_visible = BeginChild(child_id, ImVec2(-100, child_height), 1 --[[ImGuiChildFlags.Borders]], child_flags) - if scroll_to_off then - ImGui.SetScrollX(SL.scroll_to_off_px) - end - if scroll_to_pos then - ImGui.SetScrollFromPosX(ImGui.GetCursorStartPos().x + SL.scroll_to_pos_px, i * 0.25) - end - if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items - for item = 0, 99 do - if item > 0 then - ImGui.SameLine() - end - if SL.enable_track and item == SL.track_item then - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) - ImGui.SetScrollHereX(i * 0.25) -- 0.0f:left, 0.5f:center, 1.0f:right - else - ImGui.Text("Item %d", item) + -- Horizontal scroll functions + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal") + ImGui.Spacing() + HelpMarker( + "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" .. + "Because the clipping rectangle of most window hides half worth of WindowPadding on the " .. + "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " .. + "equivalent SetScrollFromPosY(+1) wouldn't.") + ImGui.PushID("##HorizontalScrolling") + for i = 0, 4 do + local child_height = ImGui.GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0 + local child_flags = 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]] + if s.enable_extra_decorations then child_flags = bit32.bor(child_flags, 16384 --[[ImGuiWindowFlags.AlwaysVerticalScrollbar]]) end + local child_id = ImGui.GetID(i) + local child_is_visible = ImGui.BeginChild(child_id, ImVec2(-100, child_height), 1 --[[ImGuiChildFlags.Borders]], child_flags) + if scroll_to_off then + ImGui.SetScrollX(s.scroll_to_off_px) + end + if scroll_to_pos then + ImGui.SetScrollFromPosX(ImGui.GetCursorStartPos().x + s.scroll_to_pos_px, i * 0.25) + end + if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items + for item = 0, 99 do + if item > 0 then + ImGui.SameLine() + end + if s.enable_track and item == s.track_item then + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) + ImGui.SetScrollHereX(i * 0.25) -- 0.0f:left, 0.5f:center, 1.0f:right + else + ImGui.Text("Item %d", item) + end end end + local scroll_x = ImGui.GetScrollX() + local scroll_max_x = ImGui.GetScrollMaxX() + ImGui.EndChild() + ImGui.SameLine() + local names = { "Left", "25%", "Center", "75%", "Right" } + ImGui.Text("%s\n%.0f/%.0f", names[i + 1], scroll_x, scroll_max_x) + ImGui.Spacing() + end + ImGui.PopID() + + -- Miscellaneous Horizontal Scrolling Demo + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)") + HelpMarker( + "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" .. + "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().") + s.lines = ImGui.SliderInt("Lines", s.lines, 1, 15) + ImGui.PushStyleVar(12 --[[ImGuiStyleVar.FrameRounding]], 3.0) + ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(2.0, 1.0)) + local scrolling_child_size = ImVec2(0, ImGui.GetFrameHeightWithSpacing() * 7 + 30) + ImGui.BeginChild("scrolling", scrolling_child_size, 1 --[[ImGuiChildFlags.Borders]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) + for line = 0, s.lines - 1 do + -- Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() + -- If you want to create your own time line for a real application you may be better off manipulating + -- the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets + -- yourself. You may also want to use the lower-level ImDrawList API. + local num_buttons = 10 + ((line % 2 == 1) and line * 9 or line * 3) + local base_w = ImGui.GetFontSize() * 3 + for n = 0, num_buttons - 1 do + if n > 0 then ImGui.SameLine() end + ImGui.PushID(n + line * 1000) + local num_buf = string.format("%d", n) + local label = num_buf + if n % 15 == 0 then label = "FizzBuzz" elseif n % 3 == 0 then label = "Fizz" elseif n % 5 == 0 then label = "Buzz" end + local hue = n * 0.05 + ImGui.PushStyleColor(22 --[[ImGuiCol.Button]], ImColor.HSV(hue, 0.6, 0.6).Value) + ImGui.PushStyleColor(23 --[[ImGuiCol.ButtonHovered]], ImColor.HSV(hue, 0.7, 0.7).Value) + ImGui.PushStyleColor(24 --[[ImGuiCol.ButtonActive]], ImColor.HSV(hue, 0.8, 0.8).Value) + ImGui.Button(label, ImVec2(base_w + math.sin(line + n) * base_w * 0.5, 0.0)) + ImGui.PopStyleColor(3) + ImGui.PopID() + end end local scroll_x = ImGui.GetScrollX() local scroll_max_x = ImGui.GetScrollMaxX() ImGui.EndChild() + ImGui.PopStyleVar(2) + local scroll_x_delta = 0.0 + ImGui.SmallButton("<<") + if ImGui.IsItemActive() then + scroll_x_delta = -ImGui.GetIO().DeltaTime * 1000.0 + end ImGui.SameLine() - ImGui.Text("%s\n%.0f/%.0f", hnames[i + 1], scroll_x, scroll_max_x) + ImGui.Text("Scroll from code"); ImGui.SameLine() + ImGui.SmallButton(">>") + if ImGui.IsItemActive() then + scroll_x_delta = ImGui.GetIO().DeltaTime * 1000.0 + end + ImGui.SameLine() + ImGui.Text("%.0f/%.0f", scroll_x, scroll_max_x) + if scroll_x_delta ~= 0.0 then + -- Demonstrate a trick: you can use Begin to set yourself in the context of another window + -- (here we are already out of your child window) + ImGui.BeginChild("scrolling") + ImGui.SetScrollX(ImGui.GetScrollX() + scroll_x_delta) + ImGui.EndChild() + end ImGui.Spacing() - end - ImGui.PopID() - -- Miscellaneous Horizontal Scrolling Demo - IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)") - DemoHelpMarker( - "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" .. - "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().") - SL.lines = ImGui.SliderInt("Lines", SL.lines, 1, 15) - ImGui.PushStyleVar(12 --[[ImGuiStyleVar.FrameRounding]], 3.0) - ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(2.0, 1.0)) - local scrolling_child_size = ImVec2(0, ImGui.GetFrameHeightWithSpacing() * 7 + 30) - BeginChild("scrolling", scrolling_child_size, 1 --[[ImGuiChildFlags.Borders]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) - for line = 0, SL.lines - 1 do - -- Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() - -- If you want to create your own time line for a real application you may be better off manipulating - -- the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets - -- yourself. You may also want to use the lower-level ImDrawList API. - local num_buttons = 10 + ((line % 2 == 1) and line * 9 or line * 3) - local base_w = ImGui.GetFontSize() * 3 - for n = 0, num_buttons - 1 do - if n > 0 then ImGui.SameLine() end - ImGui.PushID(n + line * 1000) - local label = (n % 15 == 0) and "FizzBuzz" or (n % 3 == 0) and "Fizz" or (n % 5 == 0) and "Buzz" or tostring(n) - local hue = n * 0.05 - ImGui.PushStyleColor(22 --[[ImGuiCol.Button]], HSV(hue, 0.6, 0.6)) - ImGui.PushStyleColor(23 --[[ImGuiCol.ButtonHovered]], HSV(hue, 0.7, 0.7)) - ImGui.PushStyleColor(24 --[[ImGuiCol.ButtonActive]], HSV(hue, 0.8, 0.8)) - ImGui.Button(label, ImVec2(base_w + math.sin(line + n) * base_w * 0.5, 0.0)) - ImGui.PopStyleColor(3) + _, s.show_horizontal_contents_size_demo_window = ImGui.Checkbox("Show Horizontal contents size demo window", s.show_horizontal_contents_size_demo_window) + + if s.show_horizontal_contents_size_demo_window then + if s.explicit_content_size then + ImGui.SetNextWindowContentSize(ImVec2(s.contents_size_x, 0.0)) + end + local window_flags = 0 + if s.show_h_scrollbar then window_flags = 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]] end + s.show_horizontal_contents_size_demo_window = ImGui.Begin("Horizontal contents size demo window", s.show_horizontal_contents_size_demo_window, window_flags) + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window") + ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(2, 0)) + ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(2, 0)) + HelpMarker( + "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n" .. + "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.") + _, s.show_h_scrollbar = ImGui.Checkbox("H-scrollbar", s.show_h_scrollbar) + _, s.show_button = ImGui.Checkbox("Button", s.show_button) -- Will grow contents size (unless explicitly overwritten) + _, s.show_tree_nodes = ImGui.Checkbox("Tree nodes", s.show_tree_nodes) -- Will grow contents size and display highlight over full width + _, s.show_text_wrapped = ImGui.Checkbox("Text wrapped", s.show_text_wrapped)-- Will grow and use contents size + _, s.show_columns = ImGui.Checkbox("Columns", s.show_columns) -- Will use contents size + _, s.show_tab_bar = ImGui.Checkbox("Tab bar", s.show_tab_bar) -- Will use contents size + _, s.show_child = ImGui.Checkbox("Child", s.show_child) -- Will grow and use contents size + _, s.explicit_content_size = ImGui.Checkbox("Explicit content size", s.explicit_content_size) + ImGui.Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui.GetScrollX(), ImGui.GetScrollMaxX(), ImGui.GetScrollY(), ImGui.GetScrollMaxY()) + if s.explicit_content_size then + ImGui.SameLine() + ImGui.SetNextItemWidth(ImGui.CalcTextSize("123456").x) + s.contents_size_x = ImGui.DragFloat("##csx", s.contents_size_x) + local p = ImGui.GetCursorScreenPos() + ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), 4294967295 --[[IM_COL32_WHITE]]) + ImGui.GetWindowDrawList():AddRectFilled(ImVec2(p.x + s.contents_size_x - 10, p.y), ImVec2(p.x + s.contents_size_x, p.y + 10), 4294967295 --[[IM_COL32_WHITE]]) + ImGui.Dummy(ImVec2(0, 10)) + end + ImGui.PopStyleVar(2) + ImGui.Separator() + if s.show_button then + ImGui.Button("this is a 300-wide button", ImVec2(300, 0)) + end + if s.show_tree_nodes then + local open = true + if ImGui.TreeNode("this is a tree node") then + if ImGui.TreeNode("another one of those tree node...") then + ImGui.Text("Some tree contents") + ImGui.TreePop() + end + ImGui.TreePop() + end + _, open = ImGui.CollapsingHeader("CollapsingHeader", open) + end + if s.show_text_wrapped then + ImGui.TextWrapped("This text should automatically wrap on the edge of the work rectangle.") + end + if s.show_columns then + ImGui.Text("Tables:") + if ImGui.BeginTable("table", 4, 1920 --[[ImGuiTableFlags.Borders]]) then + for n = 0, 3 do + ImGui.TableNextColumn() + ImGui.Text("Width %.2f", ImGui.GetContentRegionAvail().x) + end + ImGui.EndTable() + end + ImGui.Text("Columns:") + ImGui.Columns(4) + for n = 0, 3 do + ImGui.Text("Width %.2f", ImGui.GetColumnWidth()) + ImGui.NextColumn() + end + ImGui.Columns(1) + end + if s.show_tab_bar and ImGui.BeginTabBar("Hello") then + if ImGui.BeginTabItem("OneOneOne") then ImGui.EndTabItem() end + if ImGui.BeginTabItem("TwoTwoTwo") then ImGui.EndTabItem() end + if ImGui.BeginTabItem("ThreeThreeThree") then ImGui.EndTabItem() end + if ImGui.BeginTabItem("FourFourFour") then ImGui.EndTabItem() end + ImGui.EndTabBar() + end + if s.show_child then + ImGui.BeginChild("child", ImVec2(0, 0), 1 --[[ImGuiChildFlags.Borders]]) + ImGui.EndChild() + end + ImGui.End() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Text Clipping") then + IMGUI_DEMO_MARKER("Layout/Text Clipping") + local size = s.size + local offset = s.offset + ImGui.DragFloat2("size", size, 0.5, 1.0, 200.0, "%.0f") + ImGui.TextWrapped("(Click and drag to scroll)") + + HelpMarker( + "(Left) Using ImGui::PushClipRect():\n" .. + "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" .. + "(use this if you want your clipping rectangle to affect interactions)\n\n" .. + "(Center) Using ImDrawList::PushClipRect():\n" .. + "Will alter ImDrawList rendering only.\n" .. + "(use this as a shortcut if you are only using ImDrawList calls)\n\n" .. + "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n" .. + "Will alter only this specific ImDrawList::AddText() rendering.\n" .. + "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.") + + for n = 0, 2 do repeat + if n > 0 then + ImGui.SameLine() + end + + ImGui.PushID(n) + ImGui.InvisibleButton("##canvas", size) + if ImGui.IsItemActive() and ImGui.IsMouseDragging(0 --[[ImGuiMouseButton.Left]]) then + offset.x = offset.x + ImGui.GetIO().MouseDelta.x + offset.y = offset.y + ImGui.GetIO().MouseDelta.y + end ImGui.PopID() + if not ImGui.IsItemVisible() then -- Skip rendering as ImDrawList elements are not clipped. + break -- continue + end + + local p0 = ImGui.GetItemRectMin() + local p1 = ImGui.GetItemRectMax() + local text_str = "Line 1 hello\nLine 2 clip me!" + local text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y) + local draw_list = ImGui.GetWindowDrawList() + if n == 0 then + ImGui.PushClipRect(p0, p1, true) + draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) + draw_list:AddText(text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str) + ImGui.PopClipRect() + elseif n == 1 then + draw_list:PushClipRect(p0, p1, true) + draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) + draw_list:AddText(text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str) + draw_list:PopClipRect() + elseif n == 2 then + local clip_rect = ImVec4(p0.x, p0.y, p1.x, p1.y) -- AddText() takes a ImVec4* here so let's convert. + draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) + draw_list:AddText(ImGui.GetFont(), ImGui.GetFontSize(), text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str, 1, #text_str + 1, 0.0, clip_rect) -- [Port] explicit text_begin/text_end (port's AddText needs text_end) + end + until true end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Overlap Mode") then + IMGUI_DEMO_MARKER("Layout/Overlap Mode") + + HelpMarker( + "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n" .. + "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. " .. + "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.") + _, s.enable_allow_overlap = ImGui.Checkbox("Enable AllowOverlap", s.enable_allow_overlap) + + local button1_pos = ImGui.GetCursorScreenPos() + local button2_pos = ImVec2(button1_pos.x + 50.0, button1_pos.y + 50.0) + if s.enable_allow_overlap then + ImGui.SetNextItemAllowOverlap() end - end - local scroll_x = ImGui.GetScrollX() - local scroll_max_x = ImGui.GetScrollMaxX() - ImGui.EndChild() - ImGui.PopStyleVar(2) - local scroll_x_delta = 0.0 - ImGui.SmallButton("<<") - if ImGui.IsItemActive() then - scroll_x_delta = -ImGui.GetIO().DeltaTime * 1000.0 - end - ImGui.SameLine() - ImGui.Text("Scroll from code"); ImGui.SameLine() - ImGui.SmallButton(">>") - if ImGui.IsItemActive() then - scroll_x_delta = ImGui.GetIO().DeltaTime * 1000.0 - end - ImGui.SameLine() - ImGui.Text("%.0f/%.0f", scroll_x, scroll_max_x) - if scroll_x_delta ~= 0.0 then - -- Demonstrate a trick: you can use Begin to set yourself in the context of another window - -- (here we are already out of your child window) - BeginChild("scrolling") - ImGui.SetScrollX(ImGui.GetScrollX() + scroll_x_delta) - ImGui.EndChild() - end - ImGui.Spacing() + ImGui.Button("Button 1", ImVec2(80, 80)) + ImGui.SetCursorScreenPos(button2_pos) + ImGui.Button("Button 2", ImVec2(80, 80)) - _, SL.show_horizontal_contents_size_demo_window = ImGui.Checkbox("Show Horizontal contents size demo window", SL.show_horizontal_contents_size_demo_window) - - if SL.show_horizontal_contents_size_demo_window then - DemoWindowLayout_HorizontalContentsSizeWindow() - end -end - -local function DemoWindowLayout_TextClipping() - IMGUI_DEMO_MARKER("Layout/Text Clipping") - if SL.clip_size == nil then SL.clip_size = { 100.0, 100.0 }; SL.clip_offset = ImVec2(30.0, 30.0) end - ImGui.DragFloat2("size", SL.clip_size, 0.5, 1.0, 200.0, "%.0f") - ImGui.TextWrapped("(Click and drag to scroll)") - - DemoHelpMarker( - "(Left) Using ImGui::PushClipRect():\n" .. - "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" .. - "(use this if you want your clipping rectangle to affect interactions)\n\n" .. - "(Center) Using ImDrawList::PushClipRect():\n" .. - "Will alter ImDrawList rendering only.\n" .. - "(use this as a shortcut if you are only using ImDrawList calls)\n\n" .. - "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n" .. - "Will alter only this specific ImDrawList::AddText() rendering.\n" .. - "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.") - - local size = ImVec2(SL.clip_size[1], SL.clip_size[2]) - local offset = SL.clip_offset - for n = 0, 2 do repeat - if n > 0 then - ImGui.SameLine() + -- This is typically used with width-spanning items. + -- (note that Selectable() has a dedicated flag ImGuiSelectableFlags.AllowOverlap, which is a shortcut + -- for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.) + if s.enable_allow_overlap then + ImGui.SetNextItemAllowOverlap() end + ImGui.Selectable("Some Selectable", false) + ImGui.SameLine() + ImGui.SmallButton("++") - ImGui.PushID(n) - ImGui.InvisibleButton("##canvas", size) - if ImGui.IsItemActive() and ImGui.IsMouseDragging(0 --[[ImGuiMouseButton.Left]]) then - offset.x = offset.x + ImGui.GetIO().MouseDelta.x - offset.y = offset.y + ImGui.GetIO().MouseDelta.y - end - ImGui.PopID() - if not ImGui.IsItemVisible() then -- Skip rendering as ImDrawList elements are not clipped. - break - end - - local p0 = ImGui.GetItemRectMin() - local p1 = ImGui.GetItemRectMax() - local text_str = "Line 1 hello\nLine 2 clip me!" - local text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y) - local draw_list = ImGui.GetWindowDrawList() - if n == 0 then - ImGui.PushClipRect(p0, p1, true) - draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) - draw_list:AddText(text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str) - ImGui.PopClipRect() - elseif n == 1 then - draw_list:PushClipRect(p0, p1, true) - draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) - draw_list:AddText(text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str) - draw_list:PopClipRect() - else - local clip_rect = ImVec4(p0.x, p0.y, p1.x, p1.y) -- AddText() takes a ImVec4 here so let's convert. - draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) - draw_list:AddText(ImGui.GetFont(), ImGui.GetFontSize(), text_pos, 4294967295 --[[IM_COL32_WHITE]], text_str, 1, #text_str + 1, 0.0, clip_rect) - end - until true end -end - -local function DemoWindowLayout_OverlapMode() - IMGUI_DEMO_MARKER("Layout/Overlap Mode") - DemoHelpMarker( - "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n" .. - "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. " .. - "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.") - _, SL.enable_allow_overlap = ImGui.Checkbox("Enable AllowOverlap", SL.enable_allow_overlap) - - local button1_pos = ImGui.GetCursorScreenPos() - local button2_pos = ImVec2(button1_pos.x + 50.0, button1_pos.y + 50.0) - if SL.enable_allow_overlap then - ImGui.SetNextItemAllowOverlap() + ImGui.TreePop() end - ImGui.Button("Button 1", ImVec2(80, 80)) - ImGui.SetCursorScreenPos(button2_pos) - ImGui.Button("Button 2", ImVec2(80, 80)) - - -- This is typically used with width-spanning items. - -- (note that Selectable() has a dedicated flag ImGuiSelectableFlags.AllowOverlap, which is a shortcut - -- for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.) - if SL.enable_allow_overlap then - ImGui.SetNextItemAllowOverlap() - end - ImGui.Selectable("Some Selectable", false) - ImGui.SameLine() - ImGui.SmallButton("++") -end - -function DemoWindowLayout() - if not ImGui.CollapsingHeader("Layout & Scrolling") then - return - end - if ImGui.TreeNode("Child windows") then DemoWindowLayout_ChildWindows(); ImGui.TreePop() end - if ImGui.TreeNode("Widgets Width") then DemoWindowLayout_WidgetsWidth(); ImGui.TreePop() end - if ImGui.TreeNode("Basic Horizontal Layout") then DemoWindowLayout_BasicHorizontal(); ImGui.TreePop() end - if ImGui.TreeNode("Groups") then DemoWindowLayout_Groups(); ImGui.TreePop() end - if ImGui.TreeNode("Text Baseline Alignment") then DemoWindowLayout_TextBaseline(); ImGui.TreePop() end - if ImGui.TreeNode("Scrolling") then DemoWindowLayout_Scrolling(); ImGui.TreePop() end - if ImGui.TreeNode("Text Clipping") then DemoWindowLayout_TextClipping(); ImGui.TreePop() end - if ImGui.TreeNode("Overlap Mode") then DemoWindowLayout_OverlapMode(); ImGui.TreePop() end end ------------------------------------------------------------------------------- -- [SECTION] DemoWindowPopups() ------------------------------------------------------------------------------- -local SP = { - selected_fish = -1, toggles = { true, false, false, false, false }, - ctx_selected = -1, value = 0.5, name = nil, - dont_ask_me_next_time = false, item = 1, color = { 0.4, 0.7, 0.0, 0.5 }, +S.DemoWindowPopups = { + selected_fish = -1, -- static int selected_fish = -1; + toggles = { true, false, false, false, false }, -- static bool toggles[] = { true, false, false, false, false }; + selected = -1, -- static int selected = -1; + value = 0.5, -- static float value = 0.5f; + name = ImGui.NewTextBuffer("Label1", 32), -- static char name[32] = "Label1"; + dont_ask_me_next_time = false, -- static bool dont_ask_me_next_time = false; + item = 1, -- static int item = 1; + color = { 0.4, 0.7, 0.0, 0.5 }, -- static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; } - -local function DemoWindowPopups_Popups() - IMGUI_DEMO_MARKER("Popups/Popups") - ImGui.TextWrapped( - "When a popup is active, it inhibits interacting with windows that are behind the popup. " .. - "Clicking outside the popup closes it.") - - local names = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" } - local toggles = SP.toggles - - -- Simple selection popup (if you want to show the current selection inside the Button itself, - -- you may want to build a string using the "###" operator to preserve a constant ID with a variable label) - if ImGui.Button("Select..") then - ImGui.OpenPopup("my_select_popup") - end - ImGui.SameLine() - ImGui.TextUnformatted(SP.selected_fish == -1 and "" or names[SP.selected_fish + 1]) - if ImGui.BeginPopup("my_select_popup") then - ImGui.SeparatorText("Aquarium") - for i = 1, #names do - if ImGui.Selectable(names[i]) then - SP.selected_fish = i - 1 - end - end - ImGui.EndPopup() - end - - -- Showing a menu with toggles - if ImGui.Button("Toggle..") then - ImGui.OpenPopup("my_toggle_popup") - end - if ImGui.BeginPopup("my_toggle_popup") then - for i = 1, #names do - _, toggles[i] = ImGui.MenuItem(names[i], "", toggles[i]) - end - if ImGui.BeginMenu("Sub-menu") then - ImGui.MenuItem("Click me") - ImGui.EndMenu() - end - - ImGui.Separator() - ImGui.Text("Tooltip here") - ImGui.SetItemTooltip("I am a tooltip over a popup") - - if ImGui.Button("Stacked Popup") then - ImGui.OpenPopup("another popup") - end - if ImGui.BeginPopup("another popup") then - for i = 1, #names do - _, toggles[i] = ImGui.MenuItem(names[i], "", toggles[i]) - end - if ImGui.BeginMenu("Sub-menu") then - ImGui.MenuItem("Click me") - if ImGui.Button("Stacked Popup") then - ImGui.OpenPopup("another popup") - end - if ImGui.BeginPopup("another popup") then - ImGui.Text("I am the last one here.") - ImGui.EndPopup() - end - ImGui.EndMenu() - end - ImGui.EndPopup() - end - ImGui.EndPopup() - end - - -- Call the more complete ShowExampleMenuFile which we use in various places of this demo - if ImGui.Button("With a menu..") then - ImGui.OpenPopup("my_file_popup") - end - if ImGui.BeginPopup("my_file_popup", 1024 --[[ImGuiWindowFlags.MenuBar]]) then - if ImGui.BeginMenuBar() then - if ImGui.BeginMenu("File") then - DemoMenuFile() - ImGui.EndMenu() - end - if ImGui.BeginMenu("Edit") then - ImGui.MenuItem("Dummy") - ImGui.EndMenu() - end - ImGui.EndMenuBar() - end - ImGui.Text("Hello from popup!") - ImGui.Button("This is a dummy button..") - ImGui.EndPopup() - end -end - -local function DemoWindowPopups_ContextMenus() - IMGUI_DEMO_MARKER("Popups/Context menus") - DemoHelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.") - - -- BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: - -- if id == 0 then - -- id = GetItemID() -- Use last item id - -- end - -- if IsItemHovered() and IsMouseReleased(ImGuiMouseButton.Right) then - -- OpenPopup(id) - -- end - -- return BeginPopup(id) - -- For advanced uses you may want to replicate and customize this code. - -- See more details in BeginPopupContextItem(). - - -- Example 1 - -- When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(), - -- and BeginPopupContextItem() will use the last item ID as the popup ID. - do - local names = { "Label1", "Label2", "Label3", "Label4", "Label5" } - for n = 0, 4 do - if ImGui.Selectable(names[n + 1], SP.ctx_selected == n) then - SP.ctx_selected = n - end - if ImGui.BeginPopupContextItem() then -- <-- use last item id as popup id - SP.ctx_selected = n - ImGui.Text("This is a popup for \"%s\"!", names[n + 1]) - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - ImGui.SetItemTooltip("Right-click to open popup") - end - end - - -- Example 2 - -- Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem(). - -- Using an explicit identifier is also convenient if you want to activate the popups from different locations. - do - DemoHelpMarker("Text() elements don't have stable identifiers so we need to provide one.") - ImGui.Text("Value = %.3f <-- (1) right-click this text", SP.value) - if ImGui.BeginPopupContextItem("my popup") then - if ImGui.Selectable("Set to zero") then SP.value = 0.0 end - if ImGui.Selectable("Set to PI") then SP.value = 3.1415 end - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - SP.value = ImGui.DragFloat("##Value", SP.value, 0.1, 0.0, 0.0) - ImGui.EndPopup() - end - - -- We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup. - -- Here we make it that right-clicking this other text element opens the same popup as above. - -- The popup itself will be submitted by the code above. - ImGui.Text("(2) Or right-click this text") - ImGui.OpenPopupOnItemClick("my popup", 8 --[[ImGuiPopupFlags.MouseButtonRight]]) - - -- Back to square one: manually open the same popup. - if ImGui.Button("(3) Or click this button") then - ImGui.OpenPopup("my popup") - end - end - - -- Example 3 - -- When using BeginPopupContextItem() with an implicit identifier (nil == use last item ID), - -- we need to make sure your item identifier is stable. - -- In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ). - do - DemoHelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.") - if SP.name == nil then SP.name = Buf("Label1", 32) end - local buf = string.format("Button: %s###Button", BufStr(SP.name)) -- ### operator override ID ignoring the preceding label - ImGui.Button(buf) - if ImGui.BeginPopupContextItem() then - ImGui.Text("Edit name:") - ImGui.InputText("##edit", SP.name, 32) - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - ImGui.SameLine(); ImGui.Text("(<-- right-click here)") - end -end - -local function DemoWindowPopups_Modals() - IMGUI_DEMO_MARKER("Popups/Modals") - ImGui.TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.") - - if ImGui.Button("Delete..") then - ImGui.OpenPopup("Delete?") - end - - -- Always center this window when appearing - local center = ImGui.GetMainViewport():GetCenter() - ImGui.SetNextWindowPos(center, 8 --[[ImGuiCond.Appearing]], ImVec2(0.5, 0.5)) - - if ImGui.BeginPopupModal("Delete?", nil, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) then - ImGui.Text("All those beautiful files will be deleted.\nThis operation cannot be undone!") - ImGui.Separator() - - -- local unused_i = 0 - -- unused_i = ImGui.Combo("Combo", unused_i, "Delete\0Delete harder\0") - - ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(0, 0)) - _, SP.dont_ask_me_next_time = ImGui.Checkbox("Don't ask me next time", SP.dont_ask_me_next_time) - ImGui.PopStyleVar() - - if ImGui.Button("OK", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end - ImGui.SetItemDefaultFocus() - ImGui.SameLine() - if ImGui.Button("Cancel", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end - ImGui.EndPopup() - end - - if ImGui.Button("Stacked modals..") then - ImGui.OpenPopup("Stacked 1") - end - if ImGui.BeginPopupModal("Stacked 1", nil, 1024 --[[ImGuiWindowFlags.MenuBar]]) then - if ImGui.BeginMenuBar() then - if ImGui.BeginMenu("File") then - if ImGui.MenuItem("Some menu item") then end - ImGui.EndMenu() - end - ImGui.EndMenuBar() - end - ImGui.Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.") - - -- Testing behavior of widgets stacking their own regular popups over the modal. - if ImGui.Combo then - SP.item = ImGui.Combo("Combo", SP.item, { "aaaa", "bbbb", "cccc", "dddd", "eeee" }, 5) - else - NotPorted("Combo") - end - ImGui.ColorEdit4("Color", SP.color) - - if ImGui.Button("Add another modal..") then - ImGui.OpenPopup("Stacked 2") - end - - -- Also demonstrate passing a p_open bool to BeginPopupModal(), this will create a regular close button which - -- will close the popup. Note that the visibility state of popups is owned by imgui, so the input value - -- of the bool actually doesn't matter here. - local unused_open = true - if ImGui.BeginPopupModal("Stacked 2", unused_open) then - ImGui.Text("Hello from Stacked The Second!") - ImGui.ColorEdit4("Color", SP.color) -- Allow opening another nested popup - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end -end - function DemoWindowPopups() + local s = S.DemoWindowPopups if not ImGui.CollapsingHeader("Popups & Modal windows") then return end @@ -23796,17 +26183,259 @@ function DemoWindowPopups() -- popups at any time. -- Typical use for regular windows: - -- local my_tool_is_active = false; if ImGui.Button("Open") then my_tool_is_active = true end; [...] if my_tool_is_active then my_tool_is_active, visible = ImGui.Begin("My Tool", my_tool_is_active); [...] ImGui.End() end + -- bool my_tool_is_active = false; if (ImGui.Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", my_tool_is_active) { [...] } End(); -- Typical use for popups: - -- if ImGui.Button("Open") then ImGui.OpenPopup("MyPopup") end; if ImGui.BeginPopup("MyPopup") then [...] ImGui.EndPopup() end + -- if (ImGui.Button("Open")) ImGui.OpenPopup("MyPopup"); if (ImGui.BeginPopup("MyPopup")) { [...] EndPopup(); } -- With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. -- This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. - if ImGui.TreeNode("Popups") then DemoWindowPopups_Popups(); ImGui.TreePop() end - if ImGui.TreeNode("Context menus") then DemoWindowPopups_ContextMenus(); ImGui.TreePop() end + if ImGui.TreeNode("Popups") then + IMGUI_DEMO_MARKER("Popups/Popups") + ImGui.TextWrapped( + "When a popup is active, it inhibits interacting with windows that are behind the popup. " .. + "Clicking outside the popup closes it.") + + local names = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" } + local toggles = s.toggles + + -- Simple selection popup (if you want to show the current selection inside the Button itself, + -- you may want to build a string using the "###" operator to preserve a constant ID with a variable label) + if ImGui.Button("Select..") then + ImGui.OpenPopup("my_select_popup") + end + ImGui.SameLine() + local fish_name = "" + if s.selected_fish ~= -1 then fish_name = names[s.selected_fish + 1] end + ImGui.TextUnformatted(fish_name) + if ImGui.BeginPopup("my_select_popup") then + ImGui.SeparatorText("Aquarium") + for i = 0, #names - 1 do + if ImGui.Selectable(names[i + 1]) then + s.selected_fish = i + end + end + ImGui.EndPopup() + end + + -- Showing a menu with toggles + if ImGui.Button("Toggle..") then + ImGui.OpenPopup("my_toggle_popup") + end + if ImGui.BeginPopup("my_toggle_popup") then + for i = 0, #names - 1 do + _, toggles[i + 1] = ImGui.MenuItem(names[i + 1], "", toggles[i + 1]) + end + if ImGui.BeginMenu("Sub-menu") then + ImGui.MenuItem("Click me") + ImGui.EndMenu() + end + + ImGui.Separator() + ImGui.Text("Tooltip here") + ImGui.SetItemTooltip("I am a tooltip over a popup") + + if ImGui.Button("Stacked Popup") then + ImGui.OpenPopup("another popup") + end + if ImGui.BeginPopup("another popup") then + for i = 0, #names - 1 do + _, toggles[i + 1] = ImGui.MenuItem(names[i + 1], "", toggles[i + 1]) + end + if ImGui.BeginMenu("Sub-menu") then + ImGui.MenuItem("Click me") + if ImGui.Button("Stacked Popup") then + ImGui.OpenPopup("another popup") + end + if ImGui.BeginPopup("another popup") then + ImGui.Text("I am the last one here.") + ImGui.EndPopup() + end + ImGui.EndMenu() + end + ImGui.EndPopup() + end + ImGui.EndPopup() + end + + -- Call the more complete ShowExampleMenuFile which we use in various places of this demo + if ImGui.Button("With a menu..") then + ImGui.OpenPopup("my_file_popup") + end + if ImGui.BeginPopup("my_file_popup", 1024 --[[ImGuiWindowFlags.MenuBar]]) then + if ImGui.BeginMenuBar() then + if ImGui.BeginMenu("File") then + ShowExampleMenuFile() + ImGui.EndMenu() + end + if ImGui.BeginMenu("Edit") then + ImGui.MenuItem("Dummy") + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end + ImGui.Text("Hello from popup!") + ImGui.Button("This is a dummy button..") + ImGui.EndPopup() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Context menus") then + IMGUI_DEMO_MARKER("Popups/Context menus") + HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.") + + -- BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: + -- if (id == 0) + -- id = GetItemID(); -- Use last item id + -- if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton.Right)) + -- OpenPopup(id); + -- return BeginPopup(id); + -- For advanced uses you may want to replicate and customize this code. + -- See more details in BeginPopupContextItem(). + + -- Example 1 + -- When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(), + -- and BeginPopupContextItem() will use the last item ID as the popup ID. + do + local names = { "Label1", "Label2", "Label3", "Label4", "Label5" } + for n = 0, 4 do + if ImGui.Selectable(names[n + 1], s.selected == n) then + s.selected = n + end + if ImGui.BeginPopupContextItem() then -- <-- use last item id as popup id + s.selected = n + ImGui.Text("This is a popup for \"%s\"!", names[n + 1]) + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.SetItemTooltip("Right-click to open popup") + end + end + + -- Example 2 + -- Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem(). + -- Using an explicit identifier is also convenient if you want to activate the popups from different locations. + do + HelpMarker("Text() elements don't have stable identifiers so we need to provide one.") + ImGui.Text("Value = %.3f <-- (1) right-click this text", s.value) + if ImGui.BeginPopupContextItem("my popup") then + if ImGui.Selectable("Set to zero") then s.value = 0.0 end + if ImGui.Selectable("Set to PI") then s.value = 3.1415 end + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + s.value = ImGui.DragFloat("##Value", s.value, 0.1, 0.0, 0.0) + ImGui.EndPopup() + end + + -- We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup. + -- Here we make it that right-clicking this other text element opens the same popup as above. + -- The popup itself will be submitted by the code above. + ImGui.Text("(2) Or right-click this text") + ImGui.OpenPopupOnItemClick("my popup", 8 --[[ImGuiPopupFlags.MouseButtonRight]]) + + -- Back to square one: manually open the same popup. + if ImGui.Button("(3) Or click this button") then + ImGui.OpenPopup("my popup") + end + end + + -- Example 3 + -- When using BeginPopupContextItem() with an implicit identifier (nil == use last item ID), + -- we need to make sure your item identifier is stable. + -- In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ). + do + HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.") + local buf = string.format("Button: %s###Button", ImGui.TextBufferToString(s.name)) -- ### operator override ID ignoring the preceding label + ImGui.Button(buf) + if ImGui.BeginPopupContextItem() then + ImGui.Text("Edit name:") + ImGui.InputText("##edit", s.name, 32) + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.SameLine(); ImGui.Text("(<-- right-click here)") + end + + ImGui.TreePop() + end + if ImGui.TreeNode("Modals") then - if ImGui.BeginPopupModal then DemoWindowPopups_Modals() else NotPorted("BeginPopupModal") end + IMGUI_DEMO_MARKER("Popups/Modals") + ImGui.TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.") + + if ImGui.Button("Delete..") then + ImGui.OpenPopup("Delete?") + end + + -- Always center this window when appearing + local center = ImGui.GetMainViewport():GetCenter() + ImGui.SetNextWindowPos(center, 8 --[[ImGuiCond.Appearing]], ImVec2(0.5, 0.5)) + + if ImGui.BeginPopupModal("Delete?", nil, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) then + ImGui.Text("All those beautiful files will be deleted.\nThis operation cannot be undone!") + ImGui.Separator() + + --static int unused_i = 0; + --ImGui.Combo("Combo", unused_i, "Delete\0Delete harder\0"); + + ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(0, 0)) + _, s.dont_ask_me_next_time = ImGui.Checkbox("Don't ask me next time", s.dont_ask_me_next_time) + ImGui.PopStyleVar() + + if ImGui.Button("OK", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end + ImGui.SetItemDefaultFocus() + ImGui.SameLine() + if ImGui.Button("Cancel", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end + ImGui.EndPopup() + end + + if ImGui.Button("Stacked modals..") then + ImGui.OpenPopup("Stacked 1") + end + if ImGui.BeginPopupModal("Stacked 1", nil, 1024 --[[ImGuiWindowFlags.MenuBar]]) then + if ImGui.BeginMenuBar() then + if ImGui.BeginMenu("File") then + if ImGui.MenuItem("Some menu item") then end + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end + ImGui.Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.") + + -- Testing behavior of widgets stacking their own regular popups over the modal. + s.item = ImGui.Combo("Combo", s.item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0") + ImGui.ColorEdit4("Color", s.color) + + if ImGui.Button("Add another modal..") then + ImGui.OpenPopup("Stacked 2") + end + + -- Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which + -- will close the popup. Note that the visibility state of popups is owned by imgui, so the input value + -- of the bool actually doesn't matter here. + local unused_open = true + local visible + visible, unused_open = ImGui.BeginPopupModal("Stacked 2", unused_open) + if visible then + ImGui.Text("Hello from Stacked The Second!") + ImGui.ColorEdit4("Color", s.color) -- Allow opening another nested popup + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.TreePop() end @@ -23817,7 +26446,7 @@ function DemoWindowPopups() ImGui.MenuItem("Menu item", "Ctrl+M") if ImGui.BeginMenu("Menu inside a regular window") then - DemoMenuFile() + ShowExampleMenuFile() ImGui.EndMenu() end ImGui.Separator() @@ -23825,99 +26454,123 @@ function DemoWindowPopups() end end -------------------------------------------------------------------------------- --- [SECTION] DemoWindowTables() -------------------------------------------------------------------------------- - -- Dummy data structure that we use for the Table demo. +-- (pre-C++11 doesn't allow us to instantiate ImVector template if this structure is defined inside the demo function) +-- [Port] namespace { ... } -> globals with a MyItem prefix (part 08_tables uses them). -- We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code. -- This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID. -- But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex) -- If you don't use sorting, you will generally never care about giving column an ID! --- MyItemColumnID -local MyItemColumnID_ID, MyItemColumnID_Name, MyItemColumnID_Action, MyItemColumnID_Quantity, MyItemColumnID_Description = 0, 1, 2, 3, 4 +-- enum MyItemColumnID +MyItemColumnID_ID = 0 +MyItemColumnID_Name = 1 +MyItemColumnID_Action = 2 +MyItemColumnID_Quantity = 3 +MyItemColumnID_Description = 4 -local function MyItem(id, name, quantity) return { ID = id, Name = name, Quantity = quantity } end +-- struct MyItem: [Port] constructor; fields ID (int), Name (string), Quantity (int) +function MyItem(ID, Name, Quantity) + return { ID = ID, Name = Name, Quantity = Quantity } +end ---- Sort a Lua array (1-based) of MyItem with ImGuiTableSortSpecs (Specs is 1-based array or ImVector) -local function MyItem_SortWithSortSpecs(sort_specs, items, items_count) - if items_count <= 1 then return end - local specs = sort_specs.Specs - local function get_spec(n) -- n: 0-based - if specs.Data then return specs.Data[n + 1] end - return specs[n + 1] - end - local function cmp(a, b) -- returns <0, 0, >0 - for n = 0, sort_specs.SpecsCount - 1 do - -- Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn() - -- We could also choose to identify columns based on their index (sort_spec.ColumnIndex), which is simpler! - local sort_spec = get_spec(n) - local delta = 0 - local uid = sort_spec.ColumnUserID - if uid == MyItemColumnID_ID then delta = a.ID - b.ID - elseif uid == MyItemColumnID_Name then delta = (a.Name < b.Name) and -1 or (a.Name > b.Name) and 1 or 0 - elseif uid == MyItemColumnID_Quantity then delta = a.Quantity - b.Quantity - elseif uid == MyItemColumnID_Description then delta = (a.Name < b.Name) and -1 or (a.Name > b.Name) and 1 or 0 - else assert(false) end - if delta > 0 then - return (sort_spec.SortDirection == 1 --[[ImGuiSortDirection.Ascending]]) and 1 or -1 - end - if delta < 0 then - return (sort_spec.SortDirection == 1 --[[ImGuiSortDirection.Ascending]]) and -1 or 1 - end +-- We have a problem which is affecting _only this demo_ and should not affect your code: +-- As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(), +-- however qsort doesn't allow passing user data to comparing function. +-- As a workaround, we are storing the sort specs in a static/global for the comparing function to access. +-- In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global. +-- We could technically call ImGui.TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called +-- very often by the sorting algorithm it would be a little wasteful. +MyItem_s_current_sort_specs = nil + +-- [Port] items: 1-based Lua array of MyItem (e.g. ImVector .Data), sorted in place over [1, items_count]. +local function MyItem_Less(a, b) return MyItem_CompareWithSortSpecs(a, b) < 0 end -- [Port] table.sort wants a "less than" predicate +function MyItem_SortWithSortSpecs(sort_specs, items, items_count) + MyItem_s_current_sort_specs = sort_specs -- Store in variable accessible by the sort function. + if items_count > 1 then + if items_count == #items then + table.sort(items, MyItem_Less) + else -- [Port] sort only the used range + local tmp = {} + for i = 1, items_count do tmp[i] = items[i] end + table.sort(tmp, MyItem_Less) + for i = 1, items_count do items[i] = tmp[i] end end + end + MyItem_s_current_sort_specs = nil +end - -- table.sort() is instable so always return a way to differentiate items. - -- Your own compare function may want to avoid fallback on implicit sort specs. - -- e.g. a Name compare if it wasn't already part of the sort specs. - return a.ID - b.ID - end - local arr = items.Data or items - if items.Data then - -- ImVector: sort only the used range - local tmp = {} - for i = 1, items_count do tmp[i] = arr[i] end - table.sort(tmp, function(a, b) return cmp(a, b) < 0 end) - for i = 1, items_count do arr[i] = tmp[i] end - else - table.sort(arr, function(a, b) return cmp(a, b) < 0 end) +-- Compare function to be used by qsort() +-- [Port] strcmp -> Lua string comparison; returns <0, 0, >0 like upstream (strict weak order via the ID fallback). +function MyItem_CompareWithSortSpecs(a, b) + for n = 0, MyItem_s_current_sort_specs.SpecsCount - 1 do + -- Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn() + -- We could also choose to identify columns based on their index (sort_spec.ColumnIndex), which is simpler! + local sort_spec = MyItem_s_current_sort_specs.Specs[n + 1] -- [Port] Specs is a 1-based array + local delta = 0 + local id = sort_spec.ColumnUserID + if id == MyItemColumnID_ID then delta = (a.ID - b.ID) + elseif id == MyItemColumnID_Name then delta = (a.Name < b.Name and -1 or (a.Name > b.Name and 1 or 0)) + elseif id == MyItemColumnID_Quantity then delta = (a.Quantity - b.Quantity) + elseif id == MyItemColumnID_Description then delta = (a.Name < b.Name and -1 or (a.Name > b.Name and 1 or 0)) + else assert(false) end + if delta > 0 then + return (sort_spec.SortDirection == 1 --[[ImGuiSortDirection.Ascending]]) and 1 or -1 + end + if delta < 0 then + return (sort_spec.SortDirection == 1 --[[ImGuiSortDirection.Ascending]]) and -1 or 1 + end end + + -- qsort() is instable so always return a way to differentiate items. + -- Your own compare function may want to avoid fallback on implicit sort specs. + -- e.g. a Name compare if it wasn't already part of the sort specs. + return a.ID - b.ID end -- Make the UI compact because there are so many fields -local function PushStyleCompact() +function PushStyleCompact() local style = ImGui.GetStyle() ImGui.PushStyleVarY(11 --[[ImGuiStyleVar.FramePadding]], math.floor(style.FramePadding.y * 0.60)) ImGui.PushStyleVarY(14 --[[ImGuiStyleVar.ItemSpacing]], math.floor(style.ItemSpacing.y * 0.60)) end -local function PopStyleCompact() +function PopStyleCompact() ImGui.PopStyleVar(2) end -local table_sizing_policies = nil +S.EditTableSizingFlags = { policies = nil } -- Show a combo box with a choice of sizing policies -local function EditTableSizingFlags(flags) - if table_sizing_policies == nil then - table_sizing_policies = { - { Value = 0 --[[ImGuiTableFlags.None]], Name = "Default", Tooltip = "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." }, - { Value = 8192 --[[ImGuiTableFlags.SizingFixedFit]], Name = "ImGuiTableFlags_SizingFixedFit", Tooltip = "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." }, - { Value = 16384 --[[ImGuiTableFlags.SizingFixedSame]], Name = "ImGuiTableFlags_SizingFixedSame", Tooltip = "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." }, - { Value = 24576 --[[ImGuiTableFlags.SizingStretchProp]], Name = "ImGuiTableFlags_SizingStretchProp", Tooltip = "Columns default to _WidthStretch with weights proportional to their widths." }, - { Value = 32768 --[[ImGuiTableFlags.SizingStretchSame]], Name = "ImGuiTableFlags_SizingStretchSame", Tooltip = "Columns default to _WidthStretch with same weights." }, +-- [Port] p_flags -> takes flags, returns the new flags. +function EditTableSizingFlags(p_flags) + local s = S.EditTableSizingFlags + -- struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; }; + if s.policies == nil then + s.policies = + { + { Value = 0 --[[ImGuiTableFlags.None]], Name = "Default", Tooltip = "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." }, + { Value = 8192 --[[ImGuiTableFlags.SizingFixedFit]], Name = "ImGuiTableFlags_SizingFixedFit", Tooltip = "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." }, + { Value = 16384 --[[ImGuiTableFlags.SizingFixedSame]], Name = "ImGuiTableFlags_SizingFixedSame", Tooltip = "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." }, + { Value = 24576 --[[ImGuiTableFlags.SizingStretchProp]], Name = "ImGuiTableFlags_SizingStretchProp", Tooltip = "Columns default to _WidthStretch with weights proportional to their widths." }, + { Value = 32768 --[[ImGuiTableFlags.SizingStretchSame]], Name = "ImGuiTableFlags_SizingStretchSame", Tooltip = "Columns default to _WidthStretch with same weights." }, } end - local policies = table_sizing_policies - local idx = 1 - while idx <= #policies do - if policies[idx].Value == bit32.band(flags, 57344 --[[ImGuiTableFlags.SizingMask_]]) then break end + local policies = s.policies + local idx = 0 + while idx < #policies do + if policies[idx + 1].Value == bit32.band(p_flags, 57344 --[[ImGuiTableFlags.SizingMask_]]) then + break + end idx = idx + 1 end - local preview_text = (idx <= #policies) and (idx > 1 and string.sub(policies[idx].Name, #"ImGuiTableFlags" + 1) or policies[idx].Name) or "" + local preview_text = "" + if idx < #policies then + preview_text = policies[idx + 1].Name + if idx > 0 then preview_text = string.sub(preview_text, #"ImGuiTableFlags" + 1) end + end if ImGui.BeginCombo("Sizing Policy", preview_text) then - for n = 1, #policies do - if ImGui.Selectable(policies[n].Name, idx == n) then - flags = bit32.bor(bit32.band(flags, bit32.bnot(57344 --[[ImGuiTableFlags.SizingMask_]])), policies[n].Value) + for n = 0, #policies - 1 do + if ImGui.Selectable(policies[n + 1].Name, idx == n) then + p_flags = bit32.bor(bit32.band(p_flags, bit32.bnot(57344 --[[ImGuiTableFlags.SizingMask_]])), policies[n + 1].Value) end end ImGui.EndCombo() @@ -23926,1256 +26579,1507 @@ local function EditTableSizingFlags(flags) ImGui.TextDisabled("(?)") if ImGui.BeginItemTooltip() then ImGui.PushTextWrapPos(ImGui.GetFontSize() * 50.0) - for m = 1, #policies do + for m = 0, #policies - 1 do ImGui.Separator() - ImGui.Text("%s:", policies[m].Name) + ImGui.Text("%s:", policies[m + 1].Name) ImGui.Separator() ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().IndentSpacing * 0.5) - ImGui.TextUnformatted(policies[m].Tooltip) + ImGui.TextUnformatted(policies[m + 1].Tooltip) end ImGui.PopTextWrapPos() ImGui.EndTooltip() end - return flags + return p_flags end -local function EditTableColumnsFlags(f) - local p - local F = ImGuiTableColumnFlags - _, f = ImGui.CheckboxFlags("_Disabled", f, F.Disabled); ImGui.SameLine(); DemoHelpMarker("Master disable flag (also hide from context menu)") - _, f = ImGui.CheckboxFlags("_DefaultHide", f, F.DefaultHide) - _, f = ImGui.CheckboxFlags("_DefaultSort", f, F.DefaultSort) - p, f = ImGui.CheckboxFlags("_WidthStretch", f, F.WidthStretch) - if p then f = bit32.band(f, bit32.bnot(bit32.bxor(F.WidthMask_, F.WidthStretch))) end - p, f = ImGui.CheckboxFlags("_WidthFixed", f, F.WidthFixed) - if p then f = bit32.band(f, bit32.bnot(bit32.bxor(F.WidthMask_, F.WidthFixed))) end - _, f = ImGui.CheckboxFlags("_NoResize", f, F.NoResize) - _, f = ImGui.CheckboxFlags("_NoReorder", f, F.NoReorder) - _, f = ImGui.CheckboxFlags("_NoHide", f, F.NoHide) - _, f = ImGui.CheckboxFlags("_NoClip", f, F.NoClip) - _, f = ImGui.CheckboxFlags("_NoSort", f, F.NoSort) - _, f = ImGui.CheckboxFlags("_NoSortAscending", f, F.NoSortAscending) - _, f = ImGui.CheckboxFlags("_NoSortDescending", f, F.NoSortDescending) - _, f = ImGui.CheckboxFlags("_NoHeaderLabel", f, F.NoHeaderLabel) - _, f = ImGui.CheckboxFlags("_NoHeaderWidth", f, F.NoHeaderWidth) - _, f = ImGui.CheckboxFlags("_PreferSortAscending", f, F.PreferSortAscending) - _, f = ImGui.CheckboxFlags("_PreferSortDescending", f, F.PreferSortDescending) - _, f = ImGui.CheckboxFlags("_IndentEnable", f, F.IndentEnable); ImGui.SameLine(); DemoHelpMarker("Default for column 0") - _, f = ImGui.CheckboxFlags("_IndentDisable", f, F.IndentDisable); ImGui.SameLine(); DemoHelpMarker("Default for column >0") - _, f = ImGui.CheckboxFlags("_AngledHeader", f, F.AngledHeader) - return f +-- [Port] p_flags -> takes flags, returns the new flags. +function EditTableColumnsFlags(p_flags) + local pressed + _, p_flags = ImGui.CheckboxFlags("_Disabled", p_flags, 1 --[[ImGuiTableColumnFlags.Disabled]]); ImGui.SameLine(); HelpMarker("Master disable flag (also hide from context menu)") + _, p_flags = ImGui.CheckboxFlags("_DefaultHide", p_flags, 2 --[[ImGuiTableColumnFlags.DefaultHide]]) + _, p_flags = ImGui.CheckboxFlags("_DefaultSort", p_flags, 4 --[[ImGuiTableColumnFlags.DefaultSort]]) + pressed, p_flags = ImGui.CheckboxFlags("_WidthStretch", p_flags, 8 --[[ImGuiTableColumnFlags.WidthStretch]]) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(24 --[[ImGuiTableColumnFlags.WidthMask_]], 8 --[[ImGuiTableColumnFlags.WidthStretch]]))) + end + pressed, p_flags = ImGui.CheckboxFlags("_WidthFixed", p_flags, 16 --[[ImGuiTableColumnFlags.WidthFixed]]) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(24 --[[ImGuiTableColumnFlags.WidthMask_]], 16 --[[ImGuiTableColumnFlags.WidthFixed]]))) + end + _, p_flags = ImGui.CheckboxFlags("_NoResize", p_flags, 32 --[[ImGuiTableColumnFlags.NoResize]]) + _, p_flags = ImGui.CheckboxFlags("_NoReorder", p_flags, 64 --[[ImGuiTableColumnFlags.NoReorder]]) + _, p_flags = ImGui.CheckboxFlags("_NoHide", p_flags, 128 --[[ImGuiTableColumnFlags.NoHide]]) + _, p_flags = ImGui.CheckboxFlags("_NoClip", p_flags, 256 --[[ImGuiTableColumnFlags.NoClip]]) + _, p_flags = ImGui.CheckboxFlags("_NoSort", p_flags, 512 --[[ImGuiTableColumnFlags.NoSort]]) + _, p_flags = ImGui.CheckboxFlags("_NoSortAscending", p_flags, 1024 --[[ImGuiTableColumnFlags.NoSortAscending]]) + _, p_flags = ImGui.CheckboxFlags("_NoSortDescending", p_flags, 2048 --[[ImGuiTableColumnFlags.NoSortDescending]]) + _, p_flags = ImGui.CheckboxFlags("_NoHeaderLabel", p_flags, 4096 --[[ImGuiTableColumnFlags.NoHeaderLabel]]) + _, p_flags = ImGui.CheckboxFlags("_NoHeaderWidth", p_flags, 8192 --[[ImGuiTableColumnFlags.NoHeaderWidth]]) + _, p_flags = ImGui.CheckboxFlags("_PreferSortAscending", p_flags, 16384 --[[ImGuiTableColumnFlags.PreferSortAscending]]) + _, p_flags = ImGui.CheckboxFlags("_PreferSortDescending", p_flags, 32768 --[[ImGuiTableColumnFlags.PreferSortDescending]]) + _, p_flags = ImGui.CheckboxFlags("_IndentEnable", p_flags, 65536 --[[ImGuiTableColumnFlags.IndentEnable]]); ImGui.SameLine(); HelpMarker("Default for column 0") + _, p_flags = ImGui.CheckboxFlags("_IndentDisable", p_flags, 131072 --[[ImGuiTableColumnFlags.IndentDisable]]); ImGui.SameLine(); HelpMarker("Default for column >0") + _, p_flags = ImGui.CheckboxFlags("_AngledHeader", p_flags, 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) + return p_flags end -local function ShowTableColumnsStatusFlags(flags) +function ShowTableColumnsStatusFlags(flags) ImGui.CheckboxFlags("_IsEnabled", flags, 16777216 --[[ImGuiTableColumnFlags.IsEnabled]]) ImGui.CheckboxFlags("_IsVisible", flags, 33554432 --[[ImGuiTableColumnFlags.IsVisible]]) ImGui.CheckboxFlags("_IsSorted", flags, 67108864 --[[ImGuiTableColumnFlags.IsSorted]]) ImGui.CheckboxFlags("_IsHovered", flags, 134217728 --[[ImGuiTableColumnFlags.IsHovered]]) end -local function bor(...) return bit32.bor(...) end -local TF = setmetatable({}, { __index = function(_, k) return ImGuiTableFlags[k] end }) +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowTables() +------------------------------------------------------------------------------- -local ST = {} -- statics for DemoWindowTables (one sub-table per section) --- Using those as a base value to create width/height that are factor of the size of our font -local TEXT_BASE_WIDTH, TEXT_BASE_HEIGHT = 0, 0 +S.DemoWindowTables = { -- statics of DemoWindowTables(), one sub-table per TreeNode + disable_indent = false, + BordersBackground = { + flags = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg), + display_headers = false, + contents_type = 0, -- CT_Text + }, + ResizableStretch = { + flags = bit32.bor(ImGuiTableFlags.SizingStretchSame, ImGuiTableFlags.Resizable, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.ContextMenuInBody), + }, + ResizableFixed = { + flags = bit32.bor(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.Resizable, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.ContextMenuInBody), + }, + ResizableMixed = { + flags = bit32.bor(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.RowBg, ImGuiTableFlags.Borders, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable), + }, + Reorderable = { + flags = bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV), + }, + Padding = { + flags1 = ImGuiTableFlags.BordersV, + show_headers = false, + flags2 = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg), + cell_padding = ImVec2(0.0, 0.0), + show_widget_frame_bg = true, + text_bufs = {}, -- 1-based, cell + 1 + init = true, + }, + SizingPolicies = { + flags1 = bit32.bor(ImGuiTableFlags.BordersV, ImGuiTableFlags.BordersOuterH, ImGuiTableFlags.RowBg, ImGuiTableFlags.ContextMenuInBody), + sizing_policy_flags = { ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.SizingFixedSame, ImGuiTableFlags.SizingStretchProp, ImGuiTableFlags.SizingStretchSame }, + flags = bit32.bor(ImGuiTableFlags.ScrollY, ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg, ImGuiTableFlags.Resizable), + contents_type = 0, -- CT_ShowWidth + column_count = 3, + text_buf = ImGui.NewTextBuffer("", 32), + }, + VerticalScrolling = { + flags = bit32.bor(ImGuiTableFlags.ScrollY, ImGuiTableFlags.RowBg, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable), + }, + HorizontalScrolling = { + flags = bit32.bor(ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, ImGuiTableFlags.RowBg, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable), + freeze_cols = 1, + freeze_rows = 1, + flags2 = bit32.bor(ImGuiTableFlags.SizingStretchSame, ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.RowBg, ImGuiTableFlags.ContextMenuInBody), + inner_width = 1000.0, + }, + ColumnsFlags = { + column_flags = { ImGuiTableColumnFlags.DefaultSort, ImGuiTableColumnFlags.None, ImGuiTableColumnFlags.DefaultHide }, + column_flags_out = { 0, 0, 0 }, -- Output from TableGetColumnFlags() + }, + ColumnsWidths = { + flags1 = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.NoBordersInBodyUntilResize), + flags2 = ImGuiTableFlags.None, + }, + OuterSize = { + flags = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.Resizable, ImGuiTableFlags.ContextMenuInBody, ImGuiTableFlags.RowBg, ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.NoHostExtendX), + }, + BackgroundColor = { + flags = ImGuiTableFlags.RowBg, + row_bg_type = 1, + row_bg_target = 1, + cell_bg_type = 1, + }, + TreeView = { + table_flags = bit32.bor(ImGuiTableFlags.BordersV, ImGuiTableFlags.BordersOuterH, ImGuiTableFlags.Resizable, ImGuiTableFlags.RowBg, ImGuiTableFlags.NoBordersInBody), + tree_node_flags_base = bit32.bor(ImGuiTreeNodeFlags.SpanAllColumns, ImGuiTreeNodeFlags.DefaultOpen, ImGuiTreeNodeFlags.DrawLinesFull), + MyTreeNode = nil, -- [Port] local struct, created once on first use + nodes = { -- 1-based; ChildIdx stays 0-based like upstream + { Name = "Root with Long Name", Type = "Folder", Size = -1, ChildIdx = 1, ChildCount = 3 }, -- 0 + { Name = "Music", Type = "Folder", Size = -1, ChildIdx = 4, ChildCount = 2 }, -- 1 + { Name = "Textures", Type = "Folder", Size = -1, ChildIdx = 6, ChildCount = 3 }, -- 2 + { Name = "desktop.ini", Type = "System file", Size = 1024, ChildIdx = -1, ChildCount = -1 }, -- 3 + { Name = "File1_a.wav", Type = "Audio file", Size = 123000, ChildIdx = -1, ChildCount = -1 }, -- 4 + { Name = "File1_b.wav", Type = "Audio file", Size = 456000, ChildIdx = -1, ChildCount = -1 }, -- 5 + { Name = "Image001.png", Type = "Image file", Size = 203128, ChildIdx = -1, ChildCount = -1 }, -- 6 + { Name = "Copy of Image001.png", Type = "Image file", Size = 203256, ChildIdx = -1, ChildCount = -1 }, -- 7 + { Name = "Copy of Image001 (Final2).png", Type = "Image file", Size = 203512, ChildIdx = -1, ChildCount = -1 }, -- 8 + }, + }, + ItemWidth = { + dummy_f = 0.0, + }, + CustomHeaders = { + column_selected = { false, false, false }, + }, + AngledHeaders = { + table_flags = bit32.bor(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersInnerH, ImGuiTableFlags.Hideable, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.HighlightHoveredColumn), + column_flags = bit32.bor(ImGuiTableColumnFlags.AngledHeader, ImGuiTableColumnFlags.WidthFixed), + bools = {}, -- 1-based, filled with false on first use + frozen_cols = 1, + frozen_rows = 2, + }, + ContextMenus = { + flags1 = bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Borders, ImGuiTableFlags.ContextMenuInBody), + }, + SyncedInstances = { + flags = bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Borders, ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.NoSavedSettings), + }, + template_items_names = { + "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango", + "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot" + }, + Sorting = { + items = ImVector(), + flags = bit32.bor( + ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Sortable, ImGuiTableFlags.SortMulti, + ImGuiTableFlags.RowBg, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.NoBordersInBody, + ImGuiTableFlags.ScrollY), + }, + Advanced = { + flags = bit32.bor( + ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, + ImGuiTableFlags.Sortable, ImGuiTableFlags.SortMulti, + ImGuiTableFlags.RowBg, ImGuiTableFlags.Borders, ImGuiTableFlags.NoBordersInBody, + ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, + ImGuiTableFlags.SizingFixedFit), + columns_base_flags = ImGuiTableColumnFlags.None, + contents_type = 5, -- CT_SelectableSpanRow + freeze_cols = 1, + freeze_rows = 1, + items_count = 0, -- IM_COUNTOF(template_items_names) * 2, set below + outer_size_value = nil, -- ImVec2(0.0f, TEXT_BASE_HEIGHT * 12), set lazily (needs font) + row_min_height = 0.0, -- Auto + inner_width_with_scroll = 0.0, -- Auto-extend + outer_size_enabled = true, + show_headers = true, + show_wrapped_text = false, + items = ImVector(), + selection = ImVector(), + items_need_sort = false, + show_debug_details = false, + }, +} +S.DemoWindowTables.Advanced.items_count = #S.DemoWindowTables.template_items_names * 2 -local function Tables_Basic() - IMGUI_DEMO_MARKER("Tables/Basic") - -- Here we will showcase three different ways to output a table. - -- They are very simple variations of a same thing! - - -- [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. - -- In many situations, this is the most flexible and easy to use pattern. - DemoHelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.") - if ImGui.BeginTable("table1", 3) then - for row = 0, 3 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Row %d Column %d", row, column) - end - end - ImGui.EndTable() +function DemoWindowTables() + local _ + local s = S.DemoWindowTables + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) + if not ImGui.CollapsingHeader("Tables & Columns") then + return end - -- [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). - -- This is generally more convenient when you have code manually submitting the contents of each column. - DemoHelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.") - if ImGui.BeginTable("table2", 3) then - for row = 0, 3 do - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.Text("Row %d", row) - ImGui.TableNextColumn() - ImGui.Text("Some contents") - ImGui.TableNextColumn() - ImGui.Text("123.456") - end - ImGui.EndTable() + -- Using those as a base value to create width/height that are factor of the size of our font + local TEXT_BASE_WIDTH = ImGui.CalcTextSize("A").x + local TEXT_BASE_HEIGHT = ImGui.GetTextLineHeightWithSpacing() + + ImGui.PushID("Tables") + + local open_action = -1 + if ImGui.Button("Expand all") then + open_action = 1 end - - -- [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), - -- as TableNextColumn() will automatically wrap around and create new rows as needed. - -- This is generally more convenient when your cells all contains the same type of data. - DemoHelpMarker( - "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains " .. - "the same type of contents.\n This is also more similar to the old NextColumn() function of the " .. - "Columns API, and provided to facilitate the Columns->Tables API transition.") - if ImGui.BeginTable("table3", 3) then - for item = 0, 13 do - ImGui.TableNextColumn() - ImGui.Text("Item %d", item) - end - ImGui.EndTable() - end -end - -local function Tables_BordersBackground() - IMGUI_DEMO_MARKER("Tables/Borders, background") - -- Expose a few Borders related flags interactively - local CT_Text, CT_FillButton = 0, 1 - local s = ST.borders - if s == nil then s = { flags = bor(TF.Borders, TF.RowBg), display_headers = false, contents_type = CT_Text }; ST.borders = s end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, TF.RowBg) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, TF.Borders) - ImGui.SameLine(); DemoHelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH") - ImGui.Indent() - - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, TF.BordersH) - ImGui.Indent() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, TF.BordersOuterH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, TF.BordersInnerH) - ImGui.Unindent() - - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, TF.BordersV) - ImGui.Indent() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, TF.BordersOuterV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, TF.BordersInnerV) - ImGui.Unindent() - - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags, TF.BordersOuter) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags, TF.BordersInner) - ImGui.Unindent() - - ImGui.AlignTextToFramePadding(); ImGui.Text("Cell contents:") - ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("Text", s.contents_type, CT_Text) - ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("FillButton", s.contents_type, CT_FillButton) - _, s.display_headers = ImGui.Checkbox("Display headers", s.display_headers) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, TF.NoBordersInBody); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") - PopStyleCompact() - - if ImGui.BeginTable("table1", 3, s.flags) then - -- Display headers so we can inspect their interaction with borders - -- (Headers are not the main purpose of this section of the demo, so we are not elaborating on them now. See other sections for details) - if s.display_headers then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - end - - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - local buf = string.format("Hello %d,%d", column, row) - if s.contents_type == CT_Text then - ImGui.TextUnformatted(buf) - elseif s.contents_type == CT_FillButton then - ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) - end - end - end - ImGui.EndTable() - end -end - -local function Tables_HelloGrid(id, flags, rows, cols, fmt) - if ImGui.BeginTable(id, cols, flags) then - for row = 0, rows - 1 do - ImGui.TableNextRow() - for column = 0, cols - 1 do - ImGui.TableSetColumnIndex(column) - ImGui.Text(fmt or "Hello %d,%d", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_ResizableStretch() - IMGUI_DEMO_MARKER("Tables/Resizable, stretch") - -- By default, if we don't enable ScrollX the sizing policy for each column is "Stretch" - -- All columns maintain a sizing weight, and they will occupy all available width. - local s = ST.rstretch - if s == nil then s = { flags = bor(TF.SizingStretchSame, TF.Resizable, TF.BordersOuter, TF.BordersV, TF.ContextMenuInBody) }; ST.rstretch = s end - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, TF.BordersV) - ImGui.SameLine(); DemoHelpMarker( - "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, " .. - "this is why the resize borders are still showing when unchecking this.") - PopStyleCompact() - - Tables_HelloGrid("table1", s.flags, 5, 3) -end - -local function Tables_ResizableFixed() - IMGUI_DEMO_MARKER("Tables/Resizable, fixed") - -- Here we use ImGuiTableFlags.SizingFixedFit (even though _ScrollX is not set) - -- So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) - -- If there is not enough available width to fit all columns, they will however be resized down. - -- FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings - DemoHelpMarker( - "Using _Resizable + _SizingFixedFit flags.\n" .. - "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" .. - "Double-click a column border to auto-fit the column to its contents.") - PushStyleCompact() - local s = ST.rfixed - if s == nil then s = { flags = bor(TF.SizingFixedFit, TF.Resizable, TF.BordersOuter, TF.BordersV, TF.ContextMenuInBody) }; ST.rfixed = s end - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, TF.NoHostExtendX) - PopStyleCompact() - - Tables_HelloGrid("table1", s.flags, 5, 3) -end - -local function Tables_ResizableMixed() - IMGUI_DEMO_MARKER("Tables/Resizable, mixed") - DemoHelpMarker( - "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" .. - "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.") - local flags = bor(TF.SizingFixedFit, TF.RowBg, TF.Borders, TF.Resizable, TF.Reorderable, TF.Hideable) - local CF = ImGuiTableColumnFlags - - if ImGui.BeginTable("table1", 3, flags) then - ImGui.TableSetupColumn("AAA", CF.WidthFixed) - ImGui.TableSetupColumn("BBB", CF.WidthFixed) - ImGui.TableSetupColumn("CCC", CF.WidthStretch) - ImGui.TableHeadersRow() - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s %d,%d", (column == 2) and "Stretch" or "Fixed", column, row) - end - end - ImGui.EndTable() - end - if ImGui.BeginTable("table2", 6, flags) then - ImGui.TableSetupColumn("AAA", CF.WidthFixed) - ImGui.TableSetupColumn("BBB", CF.WidthFixed) - ImGui.TableSetupColumn("CCC", bor(CF.WidthFixed, CF.DefaultHide)) - ImGui.TableSetupColumn("DDD", CF.WidthStretch) - ImGui.TableSetupColumn("EEE", CF.WidthStretch) - ImGui.TableSetupColumn("FFF", bor(CF.WidthStretch, CF.DefaultHide)) - ImGui.TableHeadersRow() - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 5 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s %d,%d", (column >= 3) and "Stretch" or "Fixed", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_Reorderable() - IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers") - DemoHelpMarker( - "Click and drag column headers to reorder columns.\n\n" .. - "Right-click on a header to open a context menu.") - local s = ST.reorder - if s == nil then s = { flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.BordersOuter, TF.BordersV) }; ST.reorder = s end - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, TF.Reorderable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, TF.Hideable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, TF.NoBordersInBody) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, TF.NoBordersInBodyUntilResize); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, TF.HighlightHoveredColumn) - PopStyleCompact() - - if ImGui.BeginTable("table1", 3, s.flags) then - -- Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column. - -- (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.) - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - for row = 0, 5 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Hello %d,%d", column, row) - end - end - ImGui.EndTable() - end - - -- Use outer_size.x == 0.0f instead of default to make the table as tight as possible - -- (only valid when no scrolling and no stretch column) - if ImGui.BeginTable("table2", 3, bor(s.flags, TF.SizingFixedFit), ImVec2(0.0, 0.0)) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - for row = 0, 5 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Fixed %d,%d", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_Padding() - IMGUI_DEMO_MARKER("Tables/Padding") - -- First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding. - -- We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding. - DemoHelpMarker( - "We often want outer padding activated when any using features which makes the edges of a column visible:\n" .. - "e.g.:\n" .. - "- BorderOuterV\n" .. - "- any form of row selection\n" .. - "Because of this, activating BorderOuterV sets the default to PadOuterX. " .. - "Using PadOuterX or NoPadOuterX you can override the default.\n\n" .. - "Actual padding values are using style.CellPadding.\n\n" .. - "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.") - - local s = ST.padding - if s == nil then - s = { flags1 = TF.BordersV, show_headers = false, flags2 = bor(TF.Borders, TF.RowBg), cell_padding = ImVec2(0.0, 0.0), - show_widget_frame_bg = true, text_bufs = {}, init = true } -- text_bufs: Mini text storage for 3x5 cells - ST.padding = s - end - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags1, TF.PadOuterX) - ImGui.SameLine(); DemoHelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)") - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags1, TF.NoPadOuterX) - ImGui.SameLine(); DemoHelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)") - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags1, TF.NoPadInnerX) - ImGui.SameLine(); DemoHelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)") - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags1, TF.BordersOuterV) - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags1, TF.BordersInnerV) - _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) - PopStyleCompact() - - if ImGui.BeginTable("table_padding", 3, s.flags1) then - if s.show_headers then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - end - - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - if row == 0 then - ImGui.Text("Avail %.2f", ImGui.GetContentRegionAvail().x) - else - local buf = string.format("Hello %d,%d", column, row) - ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) - end - -- if bit32.band(ImGui.TableGetColumnFlags(), ImGuiTableColumnFlags.IsHovered) ~= 0 then - -- ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, IM_COL32(0, 100, 0, 255)) - -- end - end - end - ImGui.EndTable() - end - - -- Second example: set style.CellPadding to (0.0) or a custom value. - -- FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one... - DemoHelpMarker("Setting style.CellPadding to (0,0) or a custom value.") - - PushStyleCompact() - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags2, TF.Borders) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags2, TF.BordersH) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags2, TF.BordersV) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags2, TF.BordersInner) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags2, TF.BordersOuter) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags2, TF.RowBg) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags2, TF.Resizable) - _, s.show_widget_frame_bg = ImGui.Checkbox("show_widget_frame_bg", s.show_widget_frame_bg) - ImGui.SliderFloat2("CellPadding", s.cell_padding, 0.0, 10.0, "%.0f") - PopStyleCompact() - - ImGui.PushStyleVar(17 --[[ImGuiStyleVar.CellPadding]], s.cell_padding) - if ImGui.BeginTable("table_padding_2", 3, s.flags2) then - if not s.show_widget_frame_bg then - ImGui.PushStyleColor(7 --[[ImGuiCol.FrameBg]], 0) - end - for cell = 0, 3 * 5 - 1 do - ImGui.TableNextColumn() - if s.init then - s.text_bufs[cell + 1] = Buf("edit me", 16) - end - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - ImGui.PushID(cell) - ImGui.InputText("##cell", s.text_bufs[cell + 1], 16) - ImGui.PopID() - end - if not s.show_widget_frame_bg then - ImGui.PopStyleColor() - end - s.init = false - ImGui.EndTable() - end - ImGui.PopStyleVar() -end - -local function Tables_SizingPolicies() - IMGUI_DEMO_MARKER("Tables/Explicit widths") - local s = ST.sizing - if s == nil then - s = { flags1 = bor(TF.BordersV, TF.BordersOuterH, TF.RowBg, TF.ContextMenuInBody), - sizing_policy_flags = { TF.SizingFixedFit, TF.SizingFixedSame, TF.SizingStretchProp, TF.SizingStretchSame }, - flags = bor(TF.ScrollY, TF.Borders, TF.RowBg, TF.Resizable), contents_type = 0, column_count = 3, text_buf = Buf("", 32) } - ST.sizing = s - end - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, TF.Resizable) - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags1, TF.NoHostExtendX) - PopStyleCompact() - - for table_n = 0, 3 do - ImGui.PushID(table_n) - ImGui.SetNextItemWidth(TEXT_BASE_WIDTH * 30) - s.sizing_policy_flags[table_n + 1] = EditTableSizingFlags(s.sizing_policy_flags[table_n + 1]) - - -- To make it easier to understand the different sizing policy, - -- For each policy: we display one table where the columns have equal contents width, - -- and one where the columns have different contents width. - if ImGui.BeginTable("table1", 3, bor(s.sizing_policy_flags[table_n + 1], s.flags1)) then - for row = 0, 2 do - ImGui.TableNextRow() - ImGui.TableNextColumn(); ImGui.Text("Oh dear") - ImGui.TableNextColumn(); ImGui.Text("Oh dear") - ImGui.TableNextColumn(); ImGui.Text("Oh dear") - end - ImGui.EndTable() - end - if ImGui.BeginTable("table2", 3, bor(s.sizing_policy_flags[table_n + 1], s.flags1)) then - for row = 0, 2 do - ImGui.TableNextRow() - ImGui.TableNextColumn(); ImGui.Text("AAAA") - ImGui.TableNextColumn(); ImGui.Text("BBBBBBBB") - ImGui.TableNextColumn(); ImGui.Text("CCCCCCCCCCCC") - end - ImGui.EndTable() - end - ImGui.PopID() - end - - ImGui.Spacing() - ImGui.TextUnformatted("Advanced") ImGui.SameLine() - DemoHelpMarker( - "This section allows you to interact and see the effect of various sizing policies " .. - "depending on whether Scroll is enabled and the contents of your columns.") - - local CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText = 0, 1, 2, 3, 4, 5 - - PushStyleCompact() - ImGui.PushID("Advanced") - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) - s.flags = EditTableSizingFlags(s.flags) - if ImGui.Combo then - s.contents_type = ImGui.Combo("Contents", s.contents_type, { "Show width", "Short Text", "Long Text", "Button", "Fill Button", "InputText" }, 6) - else - NotPorted("Combo") + if ImGui.Button("Collapse all") then + open_action = 0 end - if s.contents_type == CT_FillButton then - ImGui.SameLine() - DemoHelpMarker( - "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop " .. - "where contents width can feed into auto-column width can feed into contents width.") + ImGui.SameLine() + + -- Options + _, s.disable_indent = ImGui.Checkbox("Disable tree indentation", s.disable_indent) + ImGui.SameLine() + HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.") + ImGui.Separator() + if s.disable_indent then + ImGui.PushStyleVar(16 --[[ImGuiStyleVar.IndentSpacing]], 0.0) end - s.column_count = ImGui.DragInt("Columns", s.column_count, 0.1, 1, 64, "%d", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, TF.PreciseWidths) - ImGui.SameLine(); DemoHelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, TF.ScrollX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, TF.NoClip) - ImGui.PopItemWidth() - ImGui.PopID() - PopStyleCompact() - if ImGui.BeginTable("table2", s.column_count, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 7)) then - for cell = 0, 10 * s.column_count - 1 do - ImGui.TableNextColumn() - local column = ImGui.TableGetColumnIndex() - local row = ImGui.TableGetRowIndex() + -- About Styling of tables + -- Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs. + -- There are however a few settings that a shared and part of the ImGuiStyle structure: + -- style.CellPadding -- Padding within each cell + -- style.Colors[ImGuiCol.TableHeaderBg] -- Table header background + -- style.Colors[ImGuiCol.TableBorderStrong] -- Table outer and header borders + -- style.Colors[ImGuiCol.TableBorderLight] -- Table inner borders + -- style.Colors[ImGuiCol.TableRowBg] -- Table row background when ImGuiTableFlags_RowBg is enabled (even rows) + -- style.Colors[ImGuiCol.TableRowBgAlt] -- Table row background when ImGuiTableFlags_RowBg is enabled (odds rows) - ImGui.PushID(cell) - local label = string.format("Hello %d,%d", column, row) - local ct = s.contents_type - if ct == CT_ShortText then ImGui.TextUnformatted(label) - elseif ct == CT_LongText then ImGui.Text("Some %s text %d,%d\nOver two lines..", column == 0 and "long" or "longeeer", column, row) - elseif ct == CT_ShowWidth then ImGui.Text("W: %.1f", ImGui.GetContentRegionAvail().x) - elseif ct == CT_Button then ImGui.Button(label) - elseif ct == CT_FillButton then ImGui.Button(label, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) - elseif ct == CT_InputText then ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]); ImGui.InputText("##", s.text_buf, 32) - end - ImGui.PopID() - end - ImGui.EndTable() + -- Demos + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) end -end + if ImGui.TreeNode("Basic") then + IMGUI_DEMO_MARKER("Tables/Basic") + -- Here we will showcase three different ways to output a table. + -- They are very simple variations of a same thing! -local function Tables_VerticalScrolling() - IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping") - DemoHelpMarker( - "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n" .. - "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.") - local s = ST.vscroll - if s == nil then s = { flags = bor(TF.ScrollY, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.Resizable, TF.Reorderable, TF.Hideable) }; ST.vscroll = s end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - PopStyleCompact() - - -- When using ScrollX or ScrollY we need to specify a size for our table container! - -- Otherwise by default the table will fit all available space, like a BeginChild() call. - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) - if ImGui.BeginTable("table_scrolly", 3, s.flags, outer_size) then - ImGui.TableSetupScrollFreeze(0, 1) -- Make top row always visible - ImGui.TableSetupColumn("One", 0 --[[ImGuiTableColumnFlags.None]]) - ImGui.TableSetupColumn("Two", 0 --[[ImGuiTableColumnFlags.None]]) - ImGui.TableSetupColumn("Three", 0 --[[ImGuiTableColumnFlags.None]]) - ImGui.TableHeadersRow() - - -- Demonstrate using clipper for large vertical lists - local clipper = ImGuiListClipper() - clipper:Begin(1000) - while clipper:Step() do - for row = clipper.DisplayStart, clipper.DisplayEnd - 1 do + -- [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. + -- In many situations, this is the most flexible and easy to use pattern. + HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.") + if ImGui.BeginTable("table1", 3) then + for row = 0, 4 - 1 do ImGui.TableNextRow() - for column = 0, 2 do + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Row %d Column %d", row, column) + end + end + ImGui.EndTable() + end + + -- [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). + -- This is generally more convenient when you have code manually submitting the contents of each column. + HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.") + if ImGui.BeginTable("table2", 3) then + for row = 0, 4 - 1 do + ImGui.TableNextRow() + ImGui.TableNextColumn() + ImGui.Text("Row %d", row) + ImGui.TableNextColumn() + ImGui.Text("Some contents") + ImGui.TableNextColumn() + ImGui.Text("123.456") + end + ImGui.EndTable() + end + + -- [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), + -- as TableNextColumn() will automatically wrap around and create new rows as needed. + -- This is generally more convenient when your cells all contains the same type of data. + HelpMarker( + "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains " .. + "the same type of contents.\n This is also more similar to the old NextColumn() function of the " .. + "Columns API, and provided to facilitate the Columns->Tables API transition.") + if ImGui.BeginTable("table3", 3) then + for item = 0, 14 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Item %d", item) + end + ImGui.EndTable() + end + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Borders, background") then + IMGUI_DEMO_MARKER("Tables/Borders, background") + -- Expose a few Borders related flags interactively + local CT_Text, CT_FillButton = 0, 1 -- enum ContentsType + local s = s.BordersBackground + + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, 64 --[[ImGuiTableFlags.RowBg]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, 1920 --[[ImGuiTableFlags.Borders]]) + ImGui.SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH") + ImGui.Indent() + + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, 384 --[[ImGuiTableFlags.BordersH]]) + ImGui.Indent() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, 256 --[[ImGuiTableFlags.BordersOuterH]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, 128 --[[ImGuiTableFlags.BordersInnerH]]) + ImGui.Unindent() + + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, 1536 --[[ImGuiTableFlags.BordersV]]) + ImGui.Indent() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, 1024 --[[ImGuiTableFlags.BordersOuterV]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, 512 --[[ImGuiTableFlags.BordersInnerV]]) + ImGui.Unindent() + + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags, 1280 --[[ImGuiTableFlags.BordersOuter]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags, 640 --[[ImGuiTableFlags.BordersInner]]) + ImGui.Unindent() + + ImGui.AlignTextToFramePadding(); ImGui.Text("Cell contents:") + ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("Text", s.contents_type, CT_Text) + ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("FillButton", s.contents_type, CT_FillButton) + _, s.display_headers = ImGui.Checkbox("Display headers", s.display_headers) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, 2048 --[[ImGuiTableFlags.NoBordersInBody]]); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") + PopStyleCompact() + + if ImGui.BeginTable("table1", 3, s.flags) then + -- Display headers so we can inspect their interaction with borders + -- (Headers are not the main purpose of this section of the demo, so we are not elaborating on them now. See other sections for details) + if s.display_headers then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + end + + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + local buf = string.format("Hello %d,%d", column, row) + if s.contents_type == CT_Text then + ImGui.TextUnformatted(buf) + elseif s.contents_type == CT_FillButton then + ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Resizable, stretch") then + IMGUI_DEMO_MARKER("Tables/Resizable, stretch") + -- By default, if we don't enable ScrollX the sizing policy for each column is "Stretch" + -- All columns maintain a sizing weight, and they will occupy all available width. + local s = s.ResizableStretch + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, 1536 --[[ImGuiTableFlags.BordersV]]) + ImGui.SameLine(); HelpMarker( + "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, " .. + "this is why the resize borders are still showing when unchecking this.") + PopStyleCompact() + + if ImGui.BeginTable("table1", 3, s.flags) then + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do ImGui.TableSetColumnIndex(column) ImGui.Text("Hello %d,%d", column, row) end end + ImGui.EndTable() end - ImGui.EndTable() - end -end - -local function Tables_HorizontalScrolling() - IMGUI_DEMO_MARKER("Tables/Horizontal scrolling") - DemoHelpMarker( - "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " .. - "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" .. - "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, " .. - "because the container window won't automatically extend vertically to fix contents " .. - "(this may be improved in future versions).") - local s = ST.hscroll - if s == nil then - s = { flags = bor(TF.ScrollX, TF.ScrollY, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.Resizable, TF.Reorderable, TF.Hideable), - freeze_cols = 1, freeze_rows = 1, - flags2 = bor(TF.SizingStretchSame, TF.ScrollX, TF.ScrollY, TF.BordersOuter, TF.RowBg, TF.ContextMenuInBody), inner_width = 1000.0 } - ST.hscroll = s - end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, TF.ScrollX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) - PopStyleCompact() - - -- When using ScrollX or ScrollY we need to specify a size for our table container! - -- Otherwise by default the table will fit all available space, like a BeginChild() call. - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) - if ImGui.BeginTable("table_scrollx", 7, s.flags, outer_size) then - ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) - ImGui.TableSetupColumn("Line #", 128 --[[ImGuiTableColumnFlags.NoHide]]) -- Make the first column not hideable to match our use of TableSetupScrollFreeze() - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableSetupColumn("Four") - ImGui.TableSetupColumn("Five") - ImGui.TableSetupColumn("Six") - ImGui.TableHeadersRow() - for row = 0, 19 do - ImGui.TableNextRow() - for column = 0, 6 do repeat - -- Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement. - -- Because here we know that: - -- - A) all our columns are contributing the same to row height - -- - B) column 0 is always visible, - -- We only always submit this one column and can skip others. - -- More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags(). - if not ImGui.TableSetColumnIndex(column) and column > 0 then - break -- continue - end - if column == 0 then - ImGui.Text("Line %d", row) - else - ImGui.Text("Hello world %d,%d", column, row) - end - until true end - end - ImGui.EndTable() - end - - ImGui.Spacing() - ImGui.TextUnformatted("Stretch + ScrollX") - ImGui.SameLine() - DemoHelpMarker( - "Showcase using Stretch columns + ScrollX together: " .. - "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" .. - "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns " .. - "along with ScrollX doesn't make sense.") - PushStyleCompact() - ImGui.PushID("flags3") - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags2, TF.ScrollX) - s.inner_width = ImGui.DragFloat("inner_width", s.inner_width, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]], "%.1f") - ImGui.PopItemWidth() - ImGui.PopID() - PopStyleCompact() - if ImGui.BeginTable("table2", 7, s.flags2, outer_size, s.inner_width) then - for cell = 0, 20 * 7 - 1 do - ImGui.TableNextColumn() - ImGui.Text("Hello world %d,%d", ImGui.TableGetColumnIndex(), ImGui.TableGetRowIndex()) - end - ImGui.EndTable() - end -end - -local function Tables_ColumnsFlags() - IMGUI_DEMO_MARKER("Tables/Columns flags") - -- Create a first table just to show all the options/flags we want to make visible in our example! - local column_count = 3 - local column_names = { "One", "Two", "Three" } - local s = ST.colflags - if s == nil then - s = { column_flags = { 4 --[[ImGuiTableColumnFlags.DefaultSort]], 0 --[[ImGuiTableColumnFlags.None]], 2 --[[ImGuiTableColumnFlags.DefaultHide]] }, column_flags_out = { 0, 0, 0 } } -- column_flags_out: Output from TableGetColumnFlags() - ST.colflags = s - end - - if ImGui.BeginTable("table_columns_flags_checkboxes", column_count, 0 --[[ImGuiTableFlags.None]]) then - PushStyleCompact() - for column = 1, column_count do - ImGui.TableNextColumn() - ImGui.PushID(column - 1) - ImGui.AlignTextToFramePadding() -- FIXME-TABLE: Workaround for wrong text baseline propagation across columns - ImGui.Text("'%s'", column_names[column]) - ImGui.Spacing() - ImGui.Text("Input flags:") - s.column_flags[column] = EditTableColumnsFlags(s.column_flags[column]) - ImGui.Spacing() - ImGui.Text("Output flags:") - ImGui.BeginDisabled() - ShowTableColumnsStatusFlags(s.column_flags_out[column]) - ImGui.EndDisabled() - ImGui.PopID() - end - PopStyleCompact() - ImGui.EndTable() - end - - -- Create the real table we care about for the example! - -- We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, - -- otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible - -- + resizing the parent window down). - local flags = bor(TF.SizingFixedFit, TF.ScrollX, TF.ScrollY, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.Resizable, TF.Reorderable, TF.Hideable, TF.Sortable) - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 9) - if ImGui.BeginTable("table_columns_flags", column_count, flags, outer_size) then - local has_angled_header = false - for column = 1, column_count do - has_angled_header = has_angled_header or Has(s.column_flags[column], 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) - ImGui.TableSetupColumn(column_names[column], s.column_flags[column]) - end - if has_angled_header then - ImGui.TableAngledHeadersRow() - end - ImGui.TableHeadersRow() - for column = 1, column_count do - s.column_flags_out[column] = ImGui.TableGetColumnFlags(column - 1) - end - local indent_step = math.floor(math.floor(TEXT_BASE_WIDTH) / 2) - for row = 0, 7 do - -- Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags. - ImGui.Indent(indent_step) - ImGui.TableNextRow() - for column = 0, column_count - 1 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s %s", (column == 0) and "Indented" or "Hello", ImGui.TableGetColumnName(column)) - end - end - ImGui.Unindent(indent_step * 8.0) - - ImGui.EndTable() - end -end - -local function Tables_ColumnsWidths() - IMGUI_DEMO_MARKER("Tables/Columns widths") - DemoHelpMarker("Using TableSetupColumn() to setup default width.") - local s = ST.colwidths - if s == nil then s = { flags1 = bor(TF.Borders, TF.NoBordersInBodyUntilResize), flags2 = TF.None }; ST.colwidths = s end - local CF = ImGuiTableColumnFlags - - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, TF.Resizable) - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags1, TF.NoBordersInBodyUntilResize) - PopStyleCompact() - if ImGui.BeginTable("table1", 3, s.flags1) then - -- We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. - ImGui.TableSetupColumn("one", CF.WidthFixed, 100.0) -- Default to 100.0f - ImGui.TableSetupColumn("two", CF.WidthFixed, 200.0) -- Default to 200.0f - ImGui.TableSetupColumn("three", CF.WidthFixed) -- Default to auto - ImGui.TableHeadersRow() - for row = 0, 3 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - if row == 0 then - ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) - else - ImGui.Text("Hello %d,%d", column, row) - end - end - end - ImGui.EndTable() - end - - DemoHelpMarker( - "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, " .. - "fixed columns with set width may still be shrunk down if there's not enough space in the host.") - - PushStyleCompact() - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags2, TF.NoKeepColumnsVisible) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags2, TF.BordersInnerV) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags2, TF.BordersOuterV) - PopStyleCompact() - if ImGui.BeginTable("table2", 4, s.flags2) then - -- We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns - -- will default to ImGuiTableColumnFlags_WidthFixed. - ImGui.TableSetupColumn("", CF.WidthFixed, 100.0) - ImGui.TableSetupColumn("", CF.WidthFixed, TEXT_BASE_WIDTH * 15.0) - ImGui.TableSetupColumn("", CF.WidthFixed, TEXT_BASE_WIDTH * 30.0) - ImGui.TableSetupColumn("", CF.WidthFixed, TEXT_BASE_WIDTH * 15.0) - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 3 do - ImGui.TableSetColumnIndex(column) - if row == 0 then - ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) - else - ImGui.Text("Hello %d,%d", column, row) - end - end - end - ImGui.EndTable() - end -end - -local function Tables_Nested() - IMGUI_DEMO_MARKER("Tables/Nested tables") - DemoHelpMarker("This demonstrates embedding a table into another table cell.") - - if ImGui.BeginTable("table_nested1", 2, bor(TF.Borders, TF.Resizable, TF.Reorderable, TF.Hideable)) then - ImGui.TableSetupColumn("A0") - ImGui.TableSetupColumn("A1") - ImGui.TableHeadersRow() - - ImGui.TableNextColumn() - ImGui.Text("A0 Row 0") - do - local rows_height = (TEXT_BASE_HEIGHT * 2.0) + (ImGui.GetStyle().CellPadding.y * 2.0) - if ImGui.BeginTable("table_nested2", 2, bor(TF.Borders, TF.Resizable, TF.Reorderable, TF.Hideable)) then - ImGui.TableSetupColumn("B0") - ImGui.TableSetupColumn("B1") - ImGui.TableHeadersRow() - - ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], rows_height) - ImGui.TableNextColumn() - ImGui.Text("B0 Row 0") - ImGui.TableNextColumn() - ImGui.Text("B1 Row 0") - ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], rows_height) - ImGui.TableNextColumn() - ImGui.Text("B0 Row 1") - ImGui.TableNextColumn() - ImGui.Text("B1 Row 1") - - ImGui.EndTable() - end - end - ImGui.TableNextColumn(); ImGui.Text("A1 Row 0") - ImGui.TableNextColumn(); ImGui.Text("A0 Row 1") - ImGui.TableNextColumn(); ImGui.Text("A1 Row 1") - ImGui.EndTable() - end -end - -local function Tables_RowHeight() - IMGUI_DEMO_MARKER("Tables/Row height") - DemoHelpMarker( - "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, " .. - "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n" .. - "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.") - if ImGui.BeginTable("table_row_height", 1, TF.Borders) then - for row = 0, 7 do - local min_row_height = math.floor(TEXT_BASE_HEIGHT * 0.30 * row + ImGui.GetStyle().CellPadding.y * 2.0) - ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], min_row_height) - ImGui.TableNextColumn() - ImGui.Text("min_row_height = %.2f", min_row_height) - end - ImGui.EndTable() - end - - DemoHelpMarker( - "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n" .. - "Please note that Tables Row Height is not the same thing as Current Line Height, " .. - "as a table cell may contains multiple lines.") - if ImGui.BeginTable("table_share_lineheight", 2, TF.Borders) then - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.ColorButton("##1", ImVec4(0.13, 0.26, 0.40, 1.0), 0 --[[ImGuiColorEditFlags.None]], ImVec2(40, 40)) - ImGui.TableNextColumn() - ImGui.Text("Line 1") - ImGui.Text("Line 2") - - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.ColorButton("##2", ImVec4(0.13, 0.26, 0.40, 1.0), 0 --[[ImGuiColorEditFlags.None]], ImVec2(40, 40)) - ImGui.TableNextColumn() - ImGui.SameLine(0.0, 0.0) -- Reuse line height from previous column - ImGui.Text("Line 1, with SameLine(0,0)") - ImGui.Text("Line 2") - - ImGui.EndTable() - end - - DemoHelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.") - if ImGui.BeginTable("table_changing_cellpadding_y", 1, TF.Borders) then - local style = ImGui.GetStyle() - for row = 0, 7 do - if (row % 3) == 2 then - ImGui.PushStyleVarY(17 --[[ImGuiStyleVar.CellPadding]], 20.0) - end - ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]]) - ImGui.TableNextColumn() - ImGui.Text("CellPadding.y = %.2f", style.CellPadding.y) - if (row % 3) == 2 then - ImGui.PopStyleVar() - end - end - ImGui.EndTable() - end -end - -local function Tables_OuterSize() - IMGUI_DEMO_MARKER("Tables/Outer size") - -- Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY - -- Important to that note how the two flags have slightly different behaviors! - ImGui.Text("Using NoHostExtendX and NoHostExtendY:") - PushStyleCompact() - local s = ST.outer - if s == nil then s = { flags = bor(TF.Borders, TF.Resizable, TF.ContextMenuInBody, TF.RowBg, TF.SizingFixedFit, TF.NoHostExtendX) }; ST.outer = s end - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, TF.NoHostExtendX) - ImGui.SameLine(); DemoHelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, TF.NoHostExtendY) - ImGui.SameLine(); DemoHelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") - PopStyleCompact() - - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 5.5) - if ImGui.BeginTable("table1", 3, s.flags, outer_size) then - for row = 0, 9 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableNextColumn() - ImGui.Text("Cell %d,%d", column, row) - end - end - ImGui.EndTable() - end - ImGui.SameLine() - ImGui.Text("Hello!") - - ImGui.Spacing() - - ImGui.Text("Using explicit size:") - if ImGui.BeginTable("table2", 3, bor(TF.Borders, TF.RowBg), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableNextColumn() - ImGui.Text("Cell %d,%d", column, row) - end - end - ImGui.EndTable() - end - ImGui.SameLine() - if ImGui.BeginTable("table3", 3, bor(TF.Borders, TF.RowBg), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then - local rows_height = TEXT_BASE_HEIGHT * 1.5 + ImGui.GetStyle().CellPadding.y * 2.0 - for row = 0, 2 do - ImGui.TableNextRow(0, rows_height) - for column = 0, 2 do - ImGui.TableNextColumn() - ImGui.Text("Cell %d,%d", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_BackgroundColor() - IMGUI_DEMO_MARKER("Tables/Background color") - local s = ST.bgcolor - if s == nil then s = { flags = TF.RowBg, row_bg_type = 1, row_bg_target = 1, cell_bg_type = 1 }; ST.bgcolor = s end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, TF.Borders) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, TF.RowBg) - ImGui.SameLine(); DemoHelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.") - if ImGui.Combo then - s.row_bg_type = ImGui.Combo("row bg type", s.row_bg_type, { "None", "Red", "Gradient" }, 3) - s.row_bg_target = ImGui.Combo("row bg target", s.row_bg_target, { "RowBg0", "RowBg1" }, 2); ImGui.SameLine(); DemoHelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.") - s.cell_bg_type = ImGui.Combo("cell bg type", s.cell_bg_type, { "None", "Blue" }, 2); ImGui.SameLine(); DemoHelpMarker("We are colorizing cells to B1->C2 here.") - else - NotPorted("Combo") - end - assert(s.row_bg_type >= 0 and s.row_bg_type <= 2) - assert(s.row_bg_target >= 0 and s.row_bg_target <= 1) - assert(s.cell_bg_type >= 0 and s.cell_bg_type <= 1) - PopStyleCompact() - - if ImGui.BeginTable("table1", 5, s.flags) then - for row = 0, 5 do - ImGui.TableNextRow() - - -- Demonstrate setting a row background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBgX, ...)' - -- We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag. - if s.row_bg_type ~= 0 then - local row_bg_color = ImGui.GetColorU32(s.row_bg_type == 1 and ImVec4(0.7, 0.3, 0.3, 0.65) or ImVec4(0.2 + row * 0.1, 0.2, 0.2, 0.65)) -- Flat or Gradient? - ImGui.TableSetBgColor(1 --[[ImGuiTableBgTarget.RowBg0]] + s.row_bg_target, row_bg_color) - end - - -- Fill cells - for column = 0, 4 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s%s", string.char(65 + row), string.char(48 + column)) - - -- Change background of Cells B1->C2 - -- Demonstrate setting a cell background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ...)' - -- (the CellBg color will be blended over the RowBg and ColumnBg colors) - -- We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop. - if row >= 1 and row <= 2 and column >= 1 and column <= 2 and s.cell_bg_type == 1 then - local cell_bg_color = ImGui.GetColorU32(ImVec4(0.3, 0.3, 0.7, 0.65)) - ImGui.TableSetBgColor(3 --[[ImGuiTableBgTarget.CellBg]], cell_bg_color) - end - end - end - ImGui.EndTable() - end -end - --- Simple storage to output a dummy file-system. -local tree_view_nodes = { - { Name = "Root with Long Name", Type = "Folder", Size = -1, ChildIdx = 1, ChildCount = 3 }, -- 0 - { Name = "Music", Type = "Folder", Size = -1, ChildIdx = 4, ChildCount = 2 }, -- 1 - { Name = "Textures", Type = "Folder", Size = -1, ChildIdx = 6, ChildCount = 3 }, -- 2 - { Name = "desktop.ini", Type = "System file", Size = 1024, ChildIdx = -1, ChildCount = -1 }, -- 3 - { Name = "File1_a.wav", Type = "Audio file", Size = 123000, ChildIdx = -1, ChildCount = -1 }, -- 4 - { Name = "File1_b.wav", Type = "Audio file", Size = 456000, ChildIdx = -1, ChildCount = -1 }, -- 5 - { Name = "Image001.png", Type = "Image file", Size = 203128, ChildIdx = -1, ChildCount = -1 }, -- 6 - { Name = "Copy of Image001.png", Type = "Image file", Size = 203256, ChildIdx = -1, ChildCount = -1 }, -- 7 - { Name = "Copy of Image001 (Final2).png", Type = "Image file", Size = 203512, ChildIdx = -1, ChildCount = -1 }, -- 8 -} - -local function MyTreeNode_DisplayNode(node, all_nodes, tree_node_flags_base) - ImGui.TableNextRow() - ImGui.TableNextColumn() - local is_folder = (node.ChildCount > 0) - - local node_flags = tree_node_flags_base - if node ~= all_nodes[1] then - node_flags = bit32.band(node_flags, bit32.bnot(32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]])) -- Only demonstrate this on the root node. - end - - if is_folder then - local open = ImGui.TreeNodeEx(node.Name, node_flags) - if bit32.band(node_flags, 32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]]) == 0 then - ImGui.TableNextColumn() - ImGui.TextDisabled("--") - ImGui.TableNextColumn() - ImGui.TextUnformatted(node.Type) - end - if open then - for child_n = 0, node.ChildCount - 1 do - MyTreeNode_DisplayNode(all_nodes[node.ChildIdx + child_n + 1], all_nodes, tree_node_flags_base) - end - ImGui.TreePop() - end - else - ImGui.TreeNodeEx(node.Name, bor(node_flags, 256 --[[ImGuiTreeNodeFlags.Leaf]], 512 --[[ImGuiTreeNodeFlags.Bullet]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]])) - ImGui.TableNextColumn() - ImGui.Text("%d", node.Size) - ImGui.TableNextColumn() - ImGui.TextUnformatted(node.Type) - end -end - -local function Tables_TreeView() - IMGUI_DEMO_MARKER("Tables/Tree view") - local s = ST.treeview - if s == nil then - s = { table_flags = bor(TF.BordersV, TF.BordersOuterH, TF.Resizable, TF.RowBg, TF.NoBordersInBody), - tree_node_flags_base = bor(16384 --[[ImGuiTreeNodeFlags.SpanAllColumns]], 32 --[[ImGuiTreeNodeFlags.DefaultOpen]], 524288 --[[ImGuiTreeNodeFlags.DrawLinesFull]]) } - ST.treeview = s - end - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", s.tree_node_flags_base, 4096 --[[ImGuiTreeNodeFlags.SpanFullWidth]]) - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", s.tree_node_flags_base, 8192 --[[ImGuiTreeNodeFlags.SpanLabelWidth]]) - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", s.tree_node_flags_base, 16384 --[[ImGuiTreeNodeFlags.SpanAllColumns]]) - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", s.tree_node_flags_base, 32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]]) - ImGui.SameLine(); DemoHelpMarker("Useful if you know that you aren't displaying contents in other columns") - - DemoHelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.") - if ImGui.BeginTable("3ways", 3, s.table_flags) then - -- The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On - ImGui.TableSetupColumn("Name", 128 --[[ImGuiTableColumnFlags.NoHide]]) - ImGui.TableSetupColumn("Size", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 12.0) - ImGui.TableSetupColumn("Type", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 18.0) - ImGui.TableHeadersRow() - - MyTreeNode_DisplayNode(tree_view_nodes[1], tree_view_nodes, s.tree_node_flags_base) - - ImGui.EndTable() - end -end - -local function Tables_ItemWidth() - IMGUI_DEMO_MARKER("Tables/Item width") - DemoHelpMarker( - "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" .. - "Note that on auto-resizing non-resizable fixed columns, querying the content width for " .. - "e.g. right-alignment doesn't make sense.") - if ImGui.BeginTable("table_item_width", 3, TF.Borders) then - ImGui.TableSetupColumn("small") - ImGui.TableSetupColumn("half") - ImGui.TableSetupColumn("right-align") - ImGui.TableHeadersRow() - - for row = 0, 2 do - ImGui.TableNextRow() - if row == 0 then - -- Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient) - ImGui.TableSetColumnIndex(0) - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 3.0) -- Small - ImGui.TableSetColumnIndex(1) - ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.5) - ImGui.TableSetColumnIndex(2) - ImGui.PushItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) -- Right-aligned - end - - -- Draw our contents - ImGui.PushID(row) - ImGui.TableSetColumnIndex(0) - ST.dummy_f = ImGui.SliderFloat("float0", ST.dummy_f or 0.0, 0.0, 1.0) - ImGui.TableSetColumnIndex(1) - ST.dummy_f = ImGui.SliderFloat("float1", ST.dummy_f, 0.0, 1.0) - ImGui.TableSetColumnIndex(2) - ST.dummy_f = ImGui.SliderFloat("##float2", ST.dummy_f, 0.0, 1.0) -- No visible label since right-aligned - ImGui.PopID() - end - ImGui.EndTable() - end -end - --- Demonstrate using TableHeader() calls instead of TableHeadersRow() -local function Tables_CustomHeaders() - IMGUI_DEMO_MARKER("Tables/Custom headers") - local COLUMNS_COUNT = 3 - if ImGui.BeginTable("table_custom_headers", COLUMNS_COUNT, bor(TF.Borders, TF.Reorderable, TF.Hideable)) then - ImGui.TableSetupColumn("Apricot") - ImGui.TableSetupColumn("Banana") - ImGui.TableSetupColumn("Cherry") - - -- Dummy entire-column selection storage - -- FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. - if ST.column_selected == nil then ST.column_selected = { false, false, false } end - local column_selected = ST.column_selected - - -- Instead of calling TableHeadersRow() we'll submit custom headers ourselves. - -- (A different approach is also possible: - -- - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call. - -- - Call TableHeadersRow() normally. This will submit TableHeader() with no name. - -- - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().) - ImGui.TableNextRow(1 --[[ImGuiTableRowFlags.Headers]]) - for column = 0, COLUMNS_COUNT - 1 do - ImGui.TableSetColumnIndex(column) - local column_name = ImGui.TableGetColumnName(column) -- Retrieve name passed to TableSetupColumn() - ImGui.PushID(column) - ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(0, 0)) - _, column_selected[column + 1] = ImGui.Checkbox("##checkall", column_selected[column + 1]) - ImGui.PopStyleVar() - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - ImGui.TableHeader(column_name) - ImGui.PopID() - end - - -- Submit table contents - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - local buf = string.format("Cell %d,%d", column, row) - ImGui.TableSetColumnIndex(column) - ImGui.Selectable(buf, column_selected[column + 1]) - end - end - ImGui.EndTable() - end -end - --- Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers -local function Tables_AngledHeaders() - IMGUI_DEMO_MARKER("Tables/Angled headers") - local column_names = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" } - local columns_count = #column_names - local rows_count = 12 - - local s = ST.angled - if s == nil then - s = { table_flags = bor(TF.SizingFixedFit, TF.ScrollX, TF.ScrollY, TF.BordersOuter, TF.BordersInnerH, TF.Hideable, TF.Resizable, TF.Reorderable, TF.HighlightHoveredColumn), - column_flags = bor(262144 --[[ImGuiTableColumnFlags.AngledHeader]], 16 --[[ImGuiTableColumnFlags.WidthFixed]]), - bools = {}, frozen_cols = 1, frozen_rows = 2 } -- bools: Dummy storage selection storage - for i = 1, columns_count * rows_count do s.bools[i] = false end - ST.angled = s - end - _, s.table_flags = ImGui.CheckboxFlags("_ScrollX", s.table_flags, TF.ScrollX) - _, s.table_flags = ImGui.CheckboxFlags("_ScrollY", s.table_flags, TF.ScrollY) - _, s.table_flags = ImGui.CheckboxFlags("_Resizable", s.table_flags, TF.Resizable) - _, s.table_flags = ImGui.CheckboxFlags("_Sortable", s.table_flags, TF.Sortable) - _, s.table_flags = ImGui.CheckboxFlags("_NoBordersInBody", s.table_flags, TF.NoBordersInBody) - _, s.table_flags = ImGui.CheckboxFlags("_HighlightHoveredColumn", s.table_flags, TF.HighlightHoveredColumn) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - s.frozen_cols = ImGui.SliderInt("Frozen columns", s.frozen_cols, 0, 2) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - s.frozen_rows = ImGui.SliderInt("Frozen rows", s.frozen_rows, 0, 2) - _, s.column_flags = ImGui.CheckboxFlags("Disable header contributing to column width", s.column_flags, 8192 --[[ImGuiTableColumnFlags.NoHeaderWidth]]) - - if ImGui.TreeNode("Style settings") then - ImGui.SameLine() - DemoHelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.") - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - local style = ImGui.GetStyle() - style.TableAngledHeadersAngle = ImGui.SliderAngle("style.TableAngledHeadersAngle", style.TableAngledHeadersAngle, -50.0, 50.0) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - ImGui.SliderFloat2("style.TableAngledHeadersTextAlign", style.TableAngledHeadersTextAlign, 0.0, 1.0, "%.2f") ImGui.TreePop() end - if ImGui.BeginTable("table_angled_headers", columns_count, s.table_flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 12)) then - ImGui.TableSetupColumn(column_names[1], bor(128 --[[ImGuiTableColumnFlags.NoHide]], 64 --[[ImGuiTableColumnFlags.NoReorder]])) - for n = 2, columns_count do - ImGui.TableSetupColumn(column_names[n], s.column_flags) - end - ImGui.TableSetupScrollFreeze(s.frozen_cols, s.frozen_rows) + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Resizable, fixed") then + IMGUI_DEMO_MARKER("Tables/Resizable, fixed") + -- Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set) + -- So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) + -- If there is not enough available width to fit all columns, they will however be resized down. + -- FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings + HelpMarker( + "Using _Resizable + _SizingFixedFit flags.\n" .. + "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" .. + "Double-click a column border to auto-fit the column to its contents.") + PushStyleCompact() + local s = s.ResizableFixed + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, 65536 --[[ImGuiTableFlags.NoHostExtendX]]) + PopStyleCompact() - ImGui.TableAngledHeadersRow() -- Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag. - ImGui.TableHeadersRow() -- Draw remaining headers and allow access to context-menu and other functions. - for row = 0, rows_count - 1 do - ImGui.PushID(row) - ImGui.TableNextRow() - ImGui.TableSetColumnIndex(0) - ImGui.AlignTextToFramePadding() - ImGui.Text("Track %d", row) - for column = 1, columns_count - 1 do - if ImGui.TableSetColumnIndex(column) then - ImGui.PushID(column) - local idx = row * columns_count + column + 1 - _, s.bools[idx] = ImGui.Checkbox("", s.bools[idx]) - ImGui.PopID() + if ImGui.BeginTable("table1", 3, s.flags) then + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Hello %d,%d", column, row) end end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Resizable, mixed") then + IMGUI_DEMO_MARKER("Tables/Resizable, mixed") + HelpMarker( + "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" .. + "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.") + local s = s.ResizableMixed + + if ImGui.BeginTable("table1", 3, s.flags) then + ImGui.TableSetupColumn("AAA", 16 --[[ImGuiTableColumnFlags.WidthFixed]]) + ImGui.TableSetupColumn("BBB", 16 --[[ImGuiTableColumnFlags.WidthFixed]]) + ImGui.TableSetupColumn("CCC", 8 --[[ImGuiTableColumnFlags.WidthStretch]]) + ImGui.TableHeadersRow() + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%s %d,%d", (column == 2) and "Stretch" or "Fixed", column, row) + end + end + ImGui.EndTable() + end + if ImGui.BeginTable("table2", 6, s.flags) then + ImGui.TableSetupColumn("AAA", 16 --[[ImGuiTableColumnFlags.WidthFixed]]) + ImGui.TableSetupColumn("BBB", 16 --[[ImGuiTableColumnFlags.WidthFixed]]) + ImGui.TableSetupColumn("CCC", bit32.bor(16 --[[ImGuiTableColumnFlags.WidthFixed]], 2 --[[ImGuiTableColumnFlags.DefaultHide]])) + ImGui.TableSetupColumn("DDD", 8 --[[ImGuiTableColumnFlags.WidthStretch]]) + ImGui.TableSetupColumn("EEE", 8 --[[ImGuiTableColumnFlags.WidthStretch]]) + ImGui.TableSetupColumn("FFF", bit32.bor(8 --[[ImGuiTableColumnFlags.WidthStretch]], 2 --[[ImGuiTableColumnFlags.DefaultHide]])) + ImGui.TableHeadersRow() + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 6 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%s %d,%d", (column >= 3) and "Stretch" or "Fixed", column, row) + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Reorderable, hideable, with headers") then + IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers") + HelpMarker( + "Click and drag column headers to reorder columns.\n\n" .. + "Right-click on a header to open a context menu.") + local s = s.Reorderable + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, 2 --[[ImGuiTableFlags.Reorderable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, 4 --[[ImGuiTableFlags.Hideable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, 2048 --[[ImGuiTableFlags.NoBordersInBody]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, 4096 --[[ImGuiTableFlags.NoBordersInBodyUntilResize]]); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, 268435456 --[[ImGuiTableFlags.HighlightHoveredColumn]]) + PopStyleCompact() + + if ImGui.BeginTable("table1", 3, s.flags) then + -- Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column. + -- (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.) + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + for row = 0, 6 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Hello %d,%d", column, row) + end + end + ImGui.EndTable() + end + + -- Use outer_size.x == 0.0f instead of default to make the table as tight as possible + -- (only valid when no scrolling and no stretch column) + if ImGui.BeginTable("table2", 3, bit32.bor(s.flags, 8192 --[[ImGuiTableFlags.SizingFixedFit]]), ImVec2(0.0, 0.0)) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + for row = 0, 6 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Fixed %d,%d", column, row) + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Padding") then + IMGUI_DEMO_MARKER("Tables/Padding") + -- First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding. + -- We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding. + HelpMarker( + "We often want outer padding activated when any using features which makes the edges of a column visible:\n" .. + "e.g.:\n" .. + "- BorderOuterV\n" .. + "- any form of row selection\n" .. + "Because of this, activating BorderOuterV sets the default to PadOuterX. " .. + "Using PadOuterX or NoPadOuterX you can override the default.\n\n" .. + "Actual padding values are using style.CellPadding.\n\n" .. + "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.") + + local s = s.Padding + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags1, 2097152 --[[ImGuiTableFlags.PadOuterX]]) + ImGui.SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)") + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags1, 4194304 --[[ImGuiTableFlags.NoPadOuterX]]) + ImGui.SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)") + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags1, 8388608 --[[ImGuiTableFlags.NoPadInnerX]]) + ImGui.SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)") + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags1, 1024 --[[ImGuiTableFlags.BordersOuterV]]) + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags1, 512 --[[ImGuiTableFlags.BordersInnerV]]) + _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) + PopStyleCompact() + + if ImGui.BeginTable("table_padding", 3, s.flags1) then + if s.show_headers then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + end + + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + if row == 0 then + ImGui.Text("Avail %.2f", ImGui.GetContentRegionAvail().x) + else + local buf = string.format("Hello %d,%d", column, row) + ImGui.Button(buf, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + end + --if bit32.band(ImGui.TableGetColumnFlags(), ImGuiTableColumnFlags.IsHovered) ~= 0 then + -- ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, IM_COL32(0, 100, 0, 255)) end + end + end + ImGui.EndTable() + end + + -- Second example: set style.CellPadding to (0.0) or a custom value. + -- FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one... + HelpMarker("Setting style.CellPadding to (0,0) or a custom value.") + + PushStyleCompact() + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags2, 1920 --[[ImGuiTableFlags.Borders]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags2, 384 --[[ImGuiTableFlags.BordersH]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags2, 1536 --[[ImGuiTableFlags.BordersV]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags2, 640 --[[ImGuiTableFlags.BordersInner]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags2, 1280 --[[ImGuiTableFlags.BordersOuter]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags2, 64 --[[ImGuiTableFlags.RowBg]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags2, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.show_widget_frame_bg = ImGui.Checkbox("show_widget_frame_bg", s.show_widget_frame_bg) + ImGui.SliderFloat2("CellPadding", s.cell_padding, 0.0, 10.0, "%.0f") + PopStyleCompact() + + ImGui.PushStyleVar(17 --[[ImGuiStyleVar.CellPadding]], s.cell_padding) + if ImGui.BeginTable("table_padding_2", 3, s.flags2) then + -- static char text_bufs[3 * 5][16] -- Mini text storage for 3x5 cells + if not s.show_widget_frame_bg then + ImGui.PushStyleColor(7 --[[ImGuiCol.FrameBg]], 0) + end + for cell = 0, 3 * 5 - 1 do + ImGui.TableNextColumn() + if s.init then + s.text_bufs[cell + 1] = ImGui.NewTextBuffer("edit me", 16) -- [Port] strcpy() -> new buffer + end + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + ImGui.PushID(cell) + ImGui.InputText("##cell", s.text_bufs[cell + 1], 16) + ImGui.PopID() + end + if not s.show_widget_frame_bg then + ImGui.PopStyleColor() + end + s.init = false + ImGui.EndTable() + end + ImGui.PopStyleVar() + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Sizing policies") then + IMGUI_DEMO_MARKER("Tables/Explicit widths") + local s = s.SizingPolicies + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags1, 65536 --[[ImGuiTableFlags.NoHostExtendX]]) + PopStyleCompact() + + local sizing_policy_flags = s.sizing_policy_flags -- 1-based + for table_n = 0, 4 - 1 do + ImGui.PushID(table_n) + ImGui.SetNextItemWidth(TEXT_BASE_WIDTH * 30) + sizing_policy_flags[table_n + 1] = EditTableSizingFlags(sizing_policy_flags[table_n + 1]) + + -- To make it easier to understand the different sizing policy, + -- For each policy: we display one table where the columns have equal contents width, + -- and one where the columns have different contents width. + if ImGui.BeginTable("table1", 3, bit32.bor(sizing_policy_flags[table_n + 1], s.flags1)) then + for row = 0, 3 - 1 do + ImGui.TableNextRow() + ImGui.TableNextColumn(); ImGui.Text("Oh dear") + ImGui.TableNextColumn(); ImGui.Text("Oh dear") + ImGui.TableNextColumn(); ImGui.Text("Oh dear") + end + ImGui.EndTable() + end + if ImGui.BeginTable("table2", 3, bit32.bor(sizing_policy_flags[table_n + 1], s.flags1)) then + for row = 0, 3 - 1 do + ImGui.TableNextRow() + ImGui.TableNextColumn(); ImGui.Text("AAAA") + ImGui.TableNextColumn(); ImGui.Text("BBBBBBBB") + ImGui.TableNextColumn(); ImGui.Text("CCCCCCCCCCCC") + end + ImGui.EndTable() + end ImGui.PopID() end - ImGui.EndTable() - end -end --- Demonstrate creating custom context menus inside columns, --- while playing it nice with context menus provided by TableHeadersRow()/TableHeader() -local function Tables_ContextMenus() - IMGUI_DEMO_MARKER("Tables/Context menus") - DemoHelpMarker( - "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n" .. - "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.") - local s = ST.ctxmenu - if s == nil then s = { flags1 = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Borders, TF.ContextMenuInBody) }; ST.ctxmenu = s end + ImGui.Spacing() + ImGui.TextUnformatted("Advanced") + ImGui.SameLine() + HelpMarker( + "This section allows you to interact and see the effect of various sizing policies " .. + "depending on whether Scroll is enabled and the contents of your columns.") - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags1, TF.ContextMenuInBody) - PopStyleCompact() + local CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText = 0, 1, 2, 3, 4, 5 -- enum ContentsType - -- Context Menus: first example - -- [1.1] Right-click on the TableHeadersRow() line to open the default table context menu. - -- [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set) - local COLUMNS_COUNT = 3 - if ImGui.BeginTable("table_context_menu", COLUMNS_COUNT, s.flags1) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - - -- [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu. - ImGui.TableHeadersRow() - - -- Submit dummy contents - for row = 0, 3 do - ImGui.TableNextRow() - for column = 0, COLUMNS_COUNT - 1 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Cell %d,%d", column, row) - end + PushStyleCompact() + ImGui.PushID("Advanced") + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) + s.flags = EditTableSizingFlags(s.flags) + s.contents_type = ImGui.Combo("Contents", s.contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0") + if s.contents_type == CT_FillButton then + ImGui.SameLine() + HelpMarker( + "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop " .. + "where contents width can feed into auto-column width can feed into contents width.") end - ImGui.EndTable() + s.column_count = ImGui.DragInt("Columns", s.column_count, 0.1, 1, 64, "%d", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, 524288 --[[ImGuiTableFlags.PreciseWidths]]) + ImGui.SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, 16777216 --[[ImGuiTableFlags.ScrollX]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, 1048576 --[[ImGuiTableFlags.NoClip]]) + ImGui.PopItemWidth() + ImGui.PopID() + PopStyleCompact() + + if ImGui.BeginTable("table2", s.column_count, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 7)) then + for cell = 0, 10 * s.column_count - 1 do + ImGui.TableNextColumn() + local column = ImGui.TableGetColumnIndex() + local row = ImGui.TableGetRowIndex() + + ImGui.PushID(cell) + local label = string.format("Hello %d,%d", column, row) + local contents_type = s.contents_type + if contents_type == CT_ShortText then ImGui.TextUnformatted(label) + elseif contents_type == CT_LongText then ImGui.Text("Some %s text %d,%d\nOver two lines..", (column == 0) and "long" or "longeeer", column, row) + elseif contents_type == CT_ShowWidth then ImGui.Text("W: %.1f", ImGui.GetContentRegionAvail().x) + elseif contents_type == CT_Button then ImGui.Button(label) + elseif contents_type == CT_FillButton then ImGui.Button(label, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + elseif contents_type == CT_InputText then ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]); ImGui.InputText("##", s.text_buf, 32) + end + ImGui.PopID() + end + ImGui.EndTable() + end + ImGui.TreePop() end - -- Context Menus: second example - -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. - -- [2.2] Right-click on the ".." to open a custom popup - -- [2.3] Right-click in columns to open another custom popup - DemoHelpMarker( - "Demonstrate mixing table context menu (over header), item context button (over button) " .. - "and custom per-column context menu (over column body).") - local flags2 = bor(TF.Resizable, TF.SizingFixedFit, TF.Reorderable, TF.Hideable, TF.Borders) - if ImGui.BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Vertical scrolling, with clipping") then + IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping") + HelpMarker( + "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n" .. + "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.") + local s = s.VerticalScrolling - -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. - ImGui.TableHeadersRow() - for row = 0, 3 do + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + PopStyleCompact() + + -- When using ScrollX or ScrollY we need to specify a size for our table container! + -- Otherwise by default the table will fit all available space, like a BeginChild() call. + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) + if ImGui.BeginTable("table_scrolly", 3, s.flags, outer_size) then + ImGui.TableSetupScrollFreeze(0, 1) -- Make top row always visible + ImGui.TableSetupColumn("One", 0 --[[ImGuiTableColumnFlags.None]]) + ImGui.TableSetupColumn("Two", 0 --[[ImGuiTableColumnFlags.None]]) + ImGui.TableSetupColumn("Three", 0 --[[ImGuiTableColumnFlags.None]]) + ImGui.TableHeadersRow() + + -- Demonstrate using clipper for large vertical lists + local clipper = ImGuiListClipper() + clipper:Begin(1000) + while clipper:Step() do + for row = clipper.DisplayStart, clipper.DisplayEnd - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Hello %d,%d", column, row) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Horizontal scrolling") then + IMGUI_DEMO_MARKER("Tables/Horizontal scrolling") + HelpMarker( + "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " .. + "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" .. + "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, " .. + "because the container window won't automatically extend vertically to fix contents " .. + "(this may be improved in future versions).") + local s = s.HorizontalScrolling + + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, 16777216 --[[ImGuiTableFlags.ScrollX]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) + PopStyleCompact() + + -- When using ScrollX or ScrollY we need to specify a size for our table container! + -- Otherwise by default the table will fit all available space, like a BeginChild() call. + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) + if ImGui.BeginTable("table_scrollx", 7, s.flags, outer_size) then + ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) + ImGui.TableSetupColumn("Line #", 128 --[[ImGuiTableColumnFlags.NoHide]]) -- Make the first column not hideable to match our use of TableSetupScrollFreeze() + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableSetupColumn("Four") + ImGui.TableSetupColumn("Five") + ImGui.TableSetupColumn("Six") + ImGui.TableHeadersRow() + for row = 0, 20 - 1 do + ImGui.TableNextRow() + for column = 0, 7 - 1 do repeat + -- Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement. + -- Because here we know that: + -- - A) all our columns are contributing the same to row height + -- - B) column 0 is always visible, + -- We only always submit this one column and can skip others. + -- More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags(). + if not ImGui.TableSetColumnIndex(column) and column > 0 then + break -- continue + end + if column == 0 then + ImGui.Text("Line %d", row) + else + ImGui.Text("Hello world %d,%d", column, row) + end + until true end + end + ImGui.EndTable() + end + + ImGui.Spacing() + ImGui.TextUnformatted("Stretch + ScrollX") + ImGui.SameLine() + HelpMarker( + "Showcase using Stretch columns + ScrollX together: " .. + "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" .. + "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns " .. + "along with ScrollX doesn't make sense.") + PushStyleCompact() + ImGui.PushID("flags3") + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags2, 16777216 --[[ImGuiTableFlags.ScrollX]]) + s.inner_width = ImGui.DragFloat("inner_width", s.inner_width, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]], "%.1f") + ImGui.PopItemWidth() + ImGui.PopID() + PopStyleCompact() + if ImGui.BeginTable("table2", 7, s.flags2, outer_size, s.inner_width) then + for cell = 0, 20 * 7 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Hello world %d,%d", ImGui.TableGetColumnIndex(), ImGui.TableGetRowIndex()) + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Columns flags") then + IMGUI_DEMO_MARKER("Tables/Columns flags") + -- Create a first table just to show all the options/flags we want to make visible in our example! + local column_count = 3 + local column_names = { "One", "Two", "Three" } -- 1-based + local column_flags = s.ColumnsFlags.column_flags -- 1-based + local column_flags_out = s.ColumnsFlags.column_flags_out -- Output from TableGetColumnFlags() + + if ImGui.BeginTable("table_columns_flags_checkboxes", column_count, 0 --[[ImGuiTableFlags.None]]) then + PushStyleCompact() + for column = 0, column_count - 1 do + ImGui.TableNextColumn() + ImGui.PushID(column) + ImGui.AlignTextToFramePadding() -- FIXME-TABLE: Workaround for wrong text baseline propagation across columns + ImGui.Text("'%s'", column_names[column + 1]) + ImGui.Spacing() + ImGui.Text("Input flags:") + column_flags[column + 1] = EditTableColumnsFlags(column_flags[column + 1]) + ImGui.Spacing() + ImGui.Text("Output flags:") + ImGui.BeginDisabled() + ShowTableColumnsStatusFlags(column_flags_out[column + 1]) + ImGui.EndDisabled() + ImGui.PopID() + end + PopStyleCompact() + ImGui.EndTable() + end + + -- Create the real table we care about for the example! + -- We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, + -- otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + -- + resizing the parent window down). + local flags + = bit32.bor(8192 --[[ImGuiTableFlags.SizingFixedFit]], 16777216 --[[ImGuiTableFlags.ScrollX]], 33554432 --[[ImGuiTableFlags.ScrollY]] + , 64 --[[ImGuiTableFlags.RowBg]], 1280 --[[ImGuiTableFlags.BordersOuter]], 1536 --[[ImGuiTableFlags.BordersV]] + , 1 --[[ImGuiTableFlags.Resizable]], 2 --[[ImGuiTableFlags.Reorderable]], 4 --[[ImGuiTableFlags.Hideable]], 8 --[[ImGuiTableFlags.Sortable]]) + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 9) + if ImGui.BeginTable("table_columns_flags", column_count, flags, outer_size) then + local has_angled_header = false + for column = 0, column_count - 1 do + has_angled_header = has_angled_header or (bit32.band(column_flags[column + 1], 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) ~= 0) + ImGui.TableSetupColumn(column_names[column + 1], column_flags[column + 1]) + end + if has_angled_header then + ImGui.TableAngledHeadersRow() + end + ImGui.TableHeadersRow() + for column = 0, column_count - 1 do + column_flags_out[column + 1] = ImGui.TableGetColumnFlags(column) + end + local indent_step = math.floor(math.floor(TEXT_BASE_WIDTH) / 2) + for row = 0, 8 - 1 do + -- Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags. + ImGui.Indent(indent_step) + ImGui.TableNextRow() + for column = 0, column_count - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%s %s", (column == 0) and "Indented" or "Hello", ImGui.TableGetColumnName(column)) + end + end + ImGui.Unindent(indent_step * 8.0) + + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Columns widths") then + IMGUI_DEMO_MARKER("Tables/Columns widths") + HelpMarker("Using TableSetupColumn() to setup default width.") + + local s = s.ColumnsWidths + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags1, 4096 --[[ImGuiTableFlags.NoBordersInBodyUntilResize]]) + PopStyleCompact() + if ImGui.BeginTable("table1", 3, s.flags1) then + -- We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. + ImGui.TableSetupColumn("one", 16 --[[ImGuiTableColumnFlags.WidthFixed]], 100.0) -- Default to 100.0f + ImGui.TableSetupColumn("two", 16 --[[ImGuiTableColumnFlags.WidthFixed]], 200.0) -- Default to 200.0f + ImGui.TableSetupColumn("three", 16 --[[ImGuiTableColumnFlags.WidthFixed]]) -- Default to auto + ImGui.TableHeadersRow() + for row = 0, 4 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + if row == 0 then + ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) + else + ImGui.Text("Hello %d,%d", column, row) + end + end + end + ImGui.EndTable() + end + + HelpMarker( + "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, " .. + "fixed columns with set width may still be shrunk down if there's not enough space in the host.") + + PushStyleCompact() + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags2, 262144 --[[ImGuiTableFlags.NoKeepColumnsVisible]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags2, 512 --[[ImGuiTableFlags.BordersInnerV]]) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags2, 1024 --[[ImGuiTableFlags.BordersOuterV]]) + PopStyleCompact() + if ImGui.BeginTable("table2", 4, s.flags2) then + -- We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns + -- will default to ImGuiTableColumnFlags_WidthFixed. + ImGui.TableSetupColumn("", 16 --[[ImGuiTableColumnFlags.WidthFixed]], 100.0) + ImGui.TableSetupColumn("", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 15.0) + ImGui.TableSetupColumn("", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 30.0) + ImGui.TableSetupColumn("", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 15.0) + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 4 - 1 do + ImGui.TableSetColumnIndex(column) + if row == 0 then + ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) + else + ImGui.Text("Hello %d,%d", column, row) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Nested tables") then + IMGUI_DEMO_MARKER("Tables/Nested tables") + HelpMarker("This demonstrates embedding a table into another table cell.") + + if ImGui.BeginTable("table_nested1", 2, bit32.bor(1920 --[[ImGuiTableFlags.Borders]], 1 --[[ImGuiTableFlags.Resizable]], 2 --[[ImGuiTableFlags.Reorderable]], 4 --[[ImGuiTableFlags.Hideable]])) then + ImGui.TableSetupColumn("A0") + ImGui.TableSetupColumn("A1") + ImGui.TableHeadersRow() + + ImGui.TableNextColumn() + ImGui.Text("A0 Row 0") + do + local rows_height = (TEXT_BASE_HEIGHT * 2.0) + (ImGui.GetStyle().CellPadding.y * 2.0) + if ImGui.BeginTable("table_nested2", 2, bit32.bor(1920 --[[ImGuiTableFlags.Borders]], 1 --[[ImGuiTableFlags.Resizable]], 2 --[[ImGuiTableFlags.Reorderable]], 4 --[[ImGuiTableFlags.Hideable]])) then + ImGui.TableSetupColumn("B0") + ImGui.TableSetupColumn("B1") + ImGui.TableHeadersRow() + + ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], rows_height) + ImGui.TableNextColumn() + ImGui.Text("B0 Row 0") + ImGui.TableNextColumn() + ImGui.Text("B1 Row 0") + ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], rows_height) + ImGui.TableNextColumn() + ImGui.Text("B0 Row 1") + ImGui.TableNextColumn() + ImGui.Text("B1 Row 1") + + ImGui.EndTable() + end + end + ImGui.TableNextColumn(); ImGui.Text("A1 Row 0") + ImGui.TableNextColumn(); ImGui.Text("A0 Row 1") + ImGui.TableNextColumn(); ImGui.Text("A1 Row 1") + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Row height") then + IMGUI_DEMO_MARKER("Tables/Row height") + HelpMarker( + "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, " .. + "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n" .. + "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.") + if ImGui.BeginTable("table_row_height", 1, 1920 --[[ImGuiTableFlags.Borders]]) then + for row = 0, 8 - 1 do + local min_row_height = math.floor(TEXT_BASE_HEIGHT * 0.30 * row + ImGui.GetStyle().CellPadding.y * 2.0) + ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], min_row_height) + ImGui.TableNextColumn() + ImGui.Text("min_row_height = %.2f", min_row_height) + end + ImGui.EndTable() + end + + HelpMarker( + "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n" .. + "Please note that Tables Row Height is not the same thing as Current Line Height, " .. + "as a table cell may contains multiple lines.") + if ImGui.BeginTable("table_share_lineheight", 2, 1920 --[[ImGuiTableFlags.Borders]]) then ImGui.TableNextRow() - for column = 0, COLUMNS_COUNT - 1 do - -- Submit dummy contents - ImGui.TableSetColumnIndex(column) - ImGui.Text("Cell %d,%d", column, row) - ImGui.SameLine() + ImGui.TableNextColumn() + ImGui.ColorButton("##1", ImVec4(0.13, 0.26, 0.40, 1.0), 0 --[[ImGuiColorEditFlags.None]], ImVec2(40, 40)) + ImGui.TableNextColumn() + ImGui.Text("Line 1") + ImGui.Text("Line 2") - -- [2.2] Right-click on the ".." to open a custom popup - ImGui.PushID(row * COLUMNS_COUNT + column) - ImGui.SmallButton("..") - if ImGui.BeginPopupContextItem() then - ImGui.Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row) + ImGui.TableNextRow() + ImGui.TableNextColumn() + ImGui.ColorButton("##2", ImVec4(0.13, 0.26, 0.40, 1.0), 0 --[[ImGuiColorEditFlags.None]], ImVec2(40, 40)) + ImGui.TableNextColumn() + ImGui.SameLine(0.0, 0.0) -- Reuse line height from previous column + ImGui.Text("Line 1, with SameLine(0,0)") + ImGui.Text("Line 2") + + ImGui.EndTable() + end + + HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.") + if ImGui.BeginTable("table_changing_cellpadding_y", 1, 1920 --[[ImGuiTableFlags.Borders]]) then + local style = ImGui.GetStyle() + for row = 0, 8 - 1 do + if (row % 3) == 2 then + ImGui.PushStyleVarY(17 --[[ImGuiStyleVar.CellPadding]], 20.0) + end + ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]]) + ImGui.TableNextColumn() + ImGui.Text("CellPadding.y = %.2f", style.CellPadding.y) + if (row % 3) == 2 then + ImGui.PopStyleVar() + end + end + ImGui.EndTable() + end + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Outer size") then + IMGUI_DEMO_MARKER("Tables/Outer size") + -- Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY + -- Important to that note how the two flags have slightly different behaviors! + ImGui.Text("Using NoHostExtendX and NoHostExtendY:") + PushStyleCompact() + local s = s.OuterSize + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, 65536 --[[ImGuiTableFlags.NoHostExtendX]]) + ImGui.SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, 131072 --[[ImGuiTableFlags.NoHostExtendY]]) + ImGui.SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") + PopStyleCompact() + + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 5.5) + if ImGui.BeginTable("table1", 3, s.flags, outer_size) then + for row = 0, 10 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + ImGui.SameLine() + ImGui.Text("Hello!") + + ImGui.Spacing() + + ImGui.Text("Using explicit size:") + if ImGui.BeginTable("table2", 3, bit32.bor(1920 --[[ImGuiTableFlags.Borders]], 64 --[[ImGuiTableFlags.RowBg]]), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + ImGui.SameLine() + if ImGui.BeginTable("table3", 3, bit32.bor(1920 --[[ImGuiTableFlags.Borders]], 64 --[[ImGuiTableFlags.RowBg]]), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then + local rows_height = TEXT_BASE_HEIGHT * 1.5 + ImGui.GetStyle().CellPadding.y * 2.0 + for row = 0, 3 - 1 do + ImGui.TableNextRow(0, rows_height) + for column = 0, 3 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Background color") then + IMGUI_DEMO_MARKER("Tables/Background color") + local s = s.BackgroundColor + + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, 1920 --[[ImGuiTableFlags.Borders]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, 64 --[[ImGuiTableFlags.RowBg]]) + ImGui.SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.") + s.row_bg_type = ImGui.Combo("row bg type", s.row_bg_type, "None\0Red\0Gradient\0") + s.row_bg_target = ImGui.Combo("row bg target", s.row_bg_target, "RowBg0\0RowBg1\0"); ImGui.SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.") + s.cell_bg_type = ImGui.Combo("cell bg type", s.cell_bg_type, "None\0Blue\0"); ImGui.SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.") + assert(s.row_bg_type >= 0 and s.row_bg_type <= 2) + assert(s.row_bg_target >= 0 and s.row_bg_target <= 1) + assert(s.cell_bg_type >= 0 and s.cell_bg_type <= 1) + PopStyleCompact() + + if ImGui.BeginTable("table1", 5, s.flags) then + for row = 0, 6 - 1 do + ImGui.TableNextRow() + + -- Demonstrate setting a row background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBgX, ...)' + -- We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag. + if s.row_bg_type ~= 0 then + local row_bg_color = ImGui.GetColorU32((s.row_bg_type == 1) and ImVec4(0.7, 0.3, 0.3, 0.65) or ImVec4(0.2 + row * 0.1, 0.2, 0.2, 0.65)) -- Flat or Gradient? + ImGui.TableSetBgColor(1 --[[ImGuiTableBgTarget.RowBg0]] + s.row_bg_target, row_bg_color) + end + + -- Fill cells + for column = 0, 5 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%c%c", string.byte("A") + row, string.byte("0") + column) + + -- Change background of Cells B1->C2 + -- Demonstrate setting a cell background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ...)' + -- (the CellBg color will be blended over the RowBg and ColumnBg colors) + -- We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop. + if row >= 1 and row <= 2 and column >= 1 and column <= 2 and s.cell_bg_type == 1 then + local cell_bg_color = ImGui.GetColorU32(ImVec4(0.3, 0.3, 0.7, 0.65)) + ImGui.TableSetBgColor(3 --[[ImGuiTableBgTarget.CellBg]], cell_bg_color) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Tree view") then + IMGUI_DEMO_MARKER("Tables/Tree view") + local s = s.TreeView + + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", s.tree_node_flags_base, 4096 --[[ImGuiTreeNodeFlags.SpanFullWidth]]) + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", s.tree_node_flags_base, 8192 --[[ImGuiTreeNodeFlags.SpanLabelWidth]]) + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", s.tree_node_flags_base, 16384 --[[ImGuiTreeNodeFlags.SpanAllColumns]]) + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", s.tree_node_flags_base, 32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]]) + ImGui.SameLine(); HelpMarker("Useful if you know that you aren't displaying contents in other columns") + + HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.") + if ImGui.BeginTable("3ways", 3, s.table_flags) then + -- The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On + ImGui.TableSetupColumn("Name", 128 --[[ImGuiTableColumnFlags.NoHide]]) + ImGui.TableSetupColumn("Size", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 12.0) + ImGui.TableSetupColumn("Type", 16 --[[ImGuiTableColumnFlags.WidthFixed]], TEXT_BASE_WIDTH * 18.0) + ImGui.TableHeadersRow() + + -- Simple storage to output a dummy file-system. + -- struct MyTreeNode { Name, Type, Size, ChildIdx, ChildCount } (see s.nodes) + local MyTreeNode = s.MyTreeNode + if MyTreeNode == nil then -- [Port] local struct with a static method, created once and kept in statics + MyTreeNode = {} + function MyTreeNode.DisplayNode(node, all_nodes) + ImGui.TableNextRow() + ImGui.TableNextColumn() + local is_folder = (node.ChildCount > 0) + + local node_flags = s.tree_node_flags_base + if node ~= all_nodes[1] then + node_flags = bit32.band(node_flags, bit32.bnot(32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]])) -- Only demonstrate this on the root node. + end + + if is_folder then + local open = ImGui.TreeNodeEx(node.Name, node_flags) + if bit32.band(node_flags, 32768 --[[ImGuiTreeNodeFlags.LabelSpanAllColumns]]) == 0 then + ImGui.TableNextColumn() + ImGui.TextDisabled("--") + ImGui.TableNextColumn() + ImGui.TextUnformatted(node.Type) + end + if open then + for child_n = 0, node.ChildCount - 1 do + MyTreeNode.DisplayNode(all_nodes[node.ChildIdx + child_n + 1], all_nodes) + end + ImGui.TreePop() + end + else + ImGui.TreeNodeEx(node.Name, bit32.bor(node_flags, 256 --[[ImGuiTreeNodeFlags.Leaf]], 512 --[[ImGuiTreeNodeFlags.Bullet]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]])) + ImGui.TableNextColumn() + ImGui.Text("%d", node.Size) + ImGui.TableNextColumn() + ImGui.TextUnformatted(node.Type) + end + end + s.MyTreeNode = MyTreeNode + end + local nodes = s.nodes + + MyTreeNode.DisplayNode(nodes[1], nodes) + + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Item width") then + IMGUI_DEMO_MARKER("Tables/Item width") + HelpMarker( + "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" .. + "Note that on auto-resizing non-resizable fixed columns, querying the content width for " .. + "e.g. right-alignment doesn't make sense.") + if ImGui.BeginTable("table_item_width", 3, 1920 --[[ImGuiTableFlags.Borders]]) then + ImGui.TableSetupColumn("small") + ImGui.TableSetupColumn("half") + ImGui.TableSetupColumn("right-align") + ImGui.TableHeadersRow() + + for row = 0, 3 - 1 do + ImGui.TableNextRow() + if row == 0 then + -- Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient) + ImGui.TableSetColumnIndex(0) + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 3.0) -- Small + ImGui.TableSetColumnIndex(1) + ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.5) + ImGui.TableSetColumnIndex(2) + ImGui.PushItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) -- Right-aligned + end + + -- Draw our contents + local s = s.ItemWidth + ImGui.PushID(row) + ImGui.TableSetColumnIndex(0) + s.dummy_f = ImGui.SliderFloat("float0", s.dummy_f, 0.0, 1.0) + ImGui.TableSetColumnIndex(1) + s.dummy_f = ImGui.SliderFloat("float1", s.dummy_f, 0.0, 1.0) + ImGui.TableSetColumnIndex(2) + s.dummy_f = ImGui.SliderFloat("##float2", s.dummy_f, 0.0, 1.0) -- No visible label since right-aligned + ImGui.PopID() + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + -- Demonstrate using TableHeader() calls instead of TableHeadersRow() + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Custom headers") then + IMGUI_DEMO_MARKER("Tables/Custom headers") + local COLUMNS_COUNT = 3 + if ImGui.BeginTable("table_custom_headers", COLUMNS_COUNT, bit32.bor(1920 --[[ImGuiTableFlags.Borders]], 2 --[[ImGuiTableFlags.Reorderable]], 4 --[[ImGuiTableFlags.Hideable]])) then + ImGui.TableSetupColumn("Apricot") + ImGui.TableSetupColumn("Banana") + ImGui.TableSetupColumn("Cherry") + + -- Dummy entire-column selection storage + -- FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. + local column_selected = s.CustomHeaders.column_selected -- 1-based + + -- Instead of calling TableHeadersRow() we'll submit custom headers ourselves. + -- (A different approach is also possible: + -- - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call. + -- - Call TableHeadersRow() normally. This will submit TableHeader() with no name. + -- - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().) + ImGui.TableNextRow(1 --[[ImGuiTableRowFlags.Headers]]) + for column = 0, COLUMNS_COUNT - 1 do + ImGui.TableSetColumnIndex(column) + local column_name = ImGui.TableGetColumnName(column) -- Retrieve name passed to TableSetupColumn() + ImGui.PushID(column) + ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(0, 0)) + _, column_selected[column + 1] = ImGui.Checkbox("##checkall", column_selected[column + 1]) + ImGui.PopStyleVar() + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + ImGui.TableHeader(column_name) + ImGui.PopID() + end + + -- Submit table contents + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + local buf = string.format("Cell %d,%d", column, row) + ImGui.TableSetColumnIndex(column) + ImGui.Selectable(buf, column_selected[column + 1]) + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + -- Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Angled headers") then + IMGUI_DEMO_MARKER("Tables/Angled headers") + local column_names = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" } -- 1-based + local columns_count = #column_names + local rows_count = 12 + + local s = s.AngledHeaders + -- static bool bools[columns_count * rows_count] = {} -- Dummy storage selection storage + local bools = s.bools -- 1-based + if #bools == 0 then + for n = 1, columns_count * rows_count do bools[n] = false end + end + _, s.table_flags = ImGui.CheckboxFlags("_ScrollX", s.table_flags, 16777216 --[[ImGuiTableFlags.ScrollX]]) + _, s.table_flags = ImGui.CheckboxFlags("_ScrollY", s.table_flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + _, s.table_flags = ImGui.CheckboxFlags("_Resizable", s.table_flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.table_flags = ImGui.CheckboxFlags("_Sortable", s.table_flags, 8 --[[ImGuiTableFlags.Sortable]]) + _, s.table_flags = ImGui.CheckboxFlags("_NoBordersInBody", s.table_flags, 2048 --[[ImGuiTableFlags.NoBordersInBody]]) + _, s.table_flags = ImGui.CheckboxFlags("_HighlightHoveredColumn", s.table_flags, 268435456 --[[ImGuiTableFlags.HighlightHoveredColumn]]) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.frozen_cols = ImGui.SliderInt("Frozen columns", s.frozen_cols, 0, 2) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.frozen_rows = ImGui.SliderInt("Frozen rows", s.frozen_rows, 0, 2) + _, s.column_flags = ImGui.CheckboxFlags("Disable header contributing to column width", s.column_flags, 8192 --[[ImGuiTableColumnFlags.NoHeaderWidth]]) + + if ImGui.TreeNode("Style settings") then + ImGui.SameLine() + HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.") + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + ImGui.GetStyle().TableAngledHeadersAngle = ImGui.SliderAngle("style.TableAngledHeadersAngle", ImGui.GetStyle().TableAngledHeadersAngle, -50.0, 50.0) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + ImGui.SliderFloat2("style.TableAngledHeadersTextAlign", ImGui.GetStyle().TableAngledHeadersTextAlign, 0.0, 1.0, "%.2f") + ImGui.TreePop() + end + + if ImGui.BeginTable("table_angled_headers", columns_count, s.table_flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 12)) then + ImGui.TableSetupColumn(column_names[1], bit32.bor(128 --[[ImGuiTableColumnFlags.NoHide]], 64 --[[ImGuiTableColumnFlags.NoReorder]])) + for n = 1, columns_count - 1 do + ImGui.TableSetupColumn(column_names[n + 1], s.column_flags) + end + ImGui.TableSetupScrollFreeze(s.frozen_cols, s.frozen_rows) + + ImGui.TableAngledHeadersRow() -- Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag. + ImGui.TableHeadersRow() -- Draw remaining headers and allow access to context-menu and other functions. + for row = 0, rows_count - 1 do + ImGui.PushID(row) + ImGui.TableNextRow() + ImGui.TableSetColumnIndex(0) + ImGui.AlignTextToFramePadding() + ImGui.Text("Track %d", row) + for column = 1, columns_count - 1 do + if ImGui.TableSetColumnIndex(column) then + ImGui.PushID(column) + _, bools[row * columns_count + column + 1] = ImGui.Checkbox("", bools[row * columns_count + column + 1]) + ImGui.PopID() + end + end + ImGui.PopID() + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + -- Demonstrate creating custom context menus inside columns, + -- while playing it nice with context menus provided by TableHeadersRow()/TableHeader() + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Context menus") then + IMGUI_DEMO_MARKER("Tables/Context menus") + HelpMarker( + "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n" .. + "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.") + local s = s.ContextMenus + + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags1, 32 --[[ImGuiTableFlags.ContextMenuInBody]]) + PopStyleCompact() + + -- Context Menus: first example + -- [1.1] Right-click on the TableHeadersRow() line to open the default table context menu. + -- [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set) + local COLUMNS_COUNT = 3 + if ImGui.BeginTable("table_context_menu", COLUMNS_COUNT, s.flags1) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + + -- [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu. + ImGui.TableHeadersRow() + + -- Submit dummy contents + for row = 0, 4 - 1 do + ImGui.TableNextRow() + for column = 0, COLUMNS_COUNT - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + + -- Context Menus: second example + -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. + -- [2.2] Right-click on the ".." to open a custom popup + -- [2.3] Right-click in columns to open another custom popup + HelpMarker( + "Demonstrate mixing table context menu (over header), item context button (over button) " .. + "and custom per-column context menu (over column body).") + local flags2 = bit32.bor(1 --[[ImGuiTableFlags.Resizable]], 8192 --[[ImGuiTableFlags.SizingFixedFit]], 2 --[[ImGuiTableFlags.Reorderable]], 4 --[[ImGuiTableFlags.Hideable]], 1920 --[[ImGuiTableFlags.Borders]]) + if ImGui.BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + + -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. + ImGui.TableHeadersRow() + for row = 0, 4 - 1 do + ImGui.TableNextRow() + for column = 0, COLUMNS_COUNT - 1 do + -- Submit dummy contents + ImGui.TableSetColumnIndex(column) + ImGui.Text("Cell %d,%d", column, row) + ImGui.SameLine() + + -- [2.2] Right-click on the ".." to open a custom popup + ImGui.PushID(row * COLUMNS_COUNT + column) + ImGui.SmallButton("..") + if ImGui.BeginPopupContextItem() then + ImGui.Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row) + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.PopID() + end + end + + -- [2.3] Right-click anywhere in columns to open another custom popup + -- (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup + -- to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping) + local hovered_column = -1 + for column = 0, COLUMNS_COUNT + 1 - 1 do + ImGui.PushID(column) + if bit32.band(ImGui.TableGetColumnFlags(column), 134217728 --[[ImGuiTableColumnFlags.IsHovered]]) ~= 0 then + hovered_column = column + end + if hovered_column == column and not ImGui.IsAnyItemHovered() and ImGui.IsMouseReleased(1) then + ImGui.OpenPopup("MyPopup") + end + if ImGui.BeginPopup("MyPopup") then + if column == COLUMNS_COUNT then + ImGui.Text("This is a custom popup for unused space after the last column.") + else + ImGui.Text("This is a custom popup for Column %d", column) + end if ImGui.Button("Close") then ImGui.CloseCurrentPopup() end @@ -25183,442 +28087,434 @@ local function Tables_ContextMenus() end ImGui.PopID() end - end - -- [2.3] Right-click anywhere in columns to open another custom popup - -- (instead of testing for not IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup - -- to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping) - local hovered_column = -1 - for column = 0, COLUMNS_COUNT do - ImGui.PushID(column) - if Has(ImGui.TableGetColumnFlags(column), 134217728 --[[ImGuiTableColumnFlags.IsHovered]]) then - hovered_column = column - end - if hovered_column == column and not ImGui.IsAnyItemHovered() and ImGui.IsMouseReleased(1) then - ImGui.OpenPopup("MyPopup") - end - if ImGui.BeginPopup("MyPopup") then - if column == COLUMNS_COUNT then - ImGui.Text("This is a custom popup for unused space after the last column.") - else - ImGui.Text("This is a custom popup for Column %d", column) - end - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - ImGui.PopID() + ImGui.EndTable() + ImGui.Text("Hovered column: %d", hovered_column) end - - ImGui.EndTable() - ImGui.Text("Hovered column: %d", hovered_column) + ImGui.TreePop() end -end --- Demonstrate creating multiple tables with the same ID -local function Tables_SyncedInstances() - IMGUI_DEMO_MARKER("Tables/Synced instances") - DemoHelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.") + -- Demonstrate creating multiple tables with the same ID + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Synced instances") then + IMGUI_DEMO_MARKER("Tables/Synced instances") + HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.") - local s = ST.synced - if s == nil then s = { flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Borders, TF.SizingFixedFit, TF.NoSavedSettings) }; ST.synced = s end - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SizingFixedFit", s.flags, TF.SizingFixedFit) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, TF.HighlightHoveredColumn) - for n = 0, 2 do - local buf = string.format("Synced Table %d", n) - local open = ImGui.CollapsingHeader(buf, 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) - if open and ImGui.BeginTable("Table", 3, s.flags, ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 5)) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") + local s = s.SyncedInstances + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SizingFixedFit", s.flags, 8192 --[[ImGuiTableFlags.SizingFixedFit]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, 268435456 --[[ImGuiTableFlags.HighlightHoveredColumn]]) + for n = 0, 3 - 1 do + local buf = string.format("Synced Table %d", n) + local open = ImGui.CollapsingHeader(buf, 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) + if open and ImGui.BeginTable("Table", 3, s.flags, ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 5)) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + local cell_count = (n == 1) and 27 or 9 -- Make second table have a scrollbar to verify that additional decoration is not affecting column positions. + for cell = 0, cell_count - 1 do + ImGui.TableNextColumn() + ImGui.Text("this cell %d", cell) + end + ImGui.EndTable() + end + end + ImGui.TreePop() + end + + -- Demonstrate using Sorting facilities + -- This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting. + -- Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified) + local template_items_names = s.template_items_names -- 1-based + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Sorting") then + IMGUI_DEMO_MARKER("Tables/Sorting") + local s = s.Sorting + -- Create item list + local items = s.items + if items.Size == 0 then + items:resize(50) + for n = 0, items.Size - 1 do + local template_n = n % #template_items_names + local item = MyItem(); items.Data[n + 1] = item -- [Port] resize(50, MyItem()) would share one table + item.ID = n + item.Name = template_items_names[template_n + 1] + item.Quantity = (n * n - n) % 20 -- Assign default quantities + end + end + + -- Options + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, 67108864 --[[ImGuiTableFlags.SortMulti]]) + ImGui.SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, 134217728 --[[ImGuiTableFlags.SortTristate]]) + ImGui.SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") + PopStyleCompact() + + if ImGui.BeginTable("table_sorting", 4, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 15), 0.0) then + -- Declare columns + -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. + -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! + -- Demonstrate using a mixture of flags among available sort-related flags: + -- - ImGuiTableColumnFlags_DefaultSort + -- - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending + -- - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending + ImGui.TableSetupColumn("ID", bit32.bor(4 --[[ImGuiTableColumnFlags.DefaultSort]], 16 --[[ImGuiTableColumnFlags.WidthFixed]]), 0.0, MyItemColumnID_ID) + ImGui.TableSetupColumn("Name", 16 --[[ImGuiTableColumnFlags.WidthFixed]], 0.0, MyItemColumnID_Name) + ImGui.TableSetupColumn("Action", bit32.bor(512 --[[ImGuiTableColumnFlags.NoSort]], 16 --[[ImGuiTableColumnFlags.WidthFixed]]), 0.0, MyItemColumnID_Action) + ImGui.TableSetupColumn("Quantity", bit32.bor(32768 --[[ImGuiTableColumnFlags.PreferSortDescending]], 8 --[[ImGuiTableColumnFlags.WidthStretch]]), 0.0, MyItemColumnID_Quantity) + ImGui.TableSetupScrollFreeze(0, 1) -- Make row always visible ImGui.TableHeadersRow() - local cell_count = (n == 1) and 27 or 9 -- Make second table have a scrollbar to verify that additional decoration is not affecting column positions. - for cell = 0, cell_count - 1 do - ImGui.TableNextColumn() - ImGui.Text("this cell %d", cell) + + -- Sort our data if sort specs have been changed! + local sort_specs = ImGui.TableGetSortSpecs() + if sort_specs then + if sort_specs.SpecsDirty then + MyItem_SortWithSortSpecs(sort_specs, items.Data, items.Size) + sort_specs.SpecsDirty = false + end + end + + -- Demonstrate using clipper for large vertical lists + local clipper = ImGuiListClipper() + clipper:Begin(items.Size) + while clipper:Step() do + for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do + -- Display a data item + local item = items.Data[row_n + 1] + ImGui.PushID(item.ID) + ImGui.TableNextRow() + ImGui.TableNextColumn() + ImGui.Text("%04d", item.ID) + ImGui.TableNextColumn() + ImGui.TextUnformatted(item.Name) + ImGui.TableNextColumn() + ImGui.SmallButton("None") + ImGui.TableNextColumn() + ImGui.Text("%d", item.Quantity) + ImGui.PopID() + end end ImGui.EndTable() end + ImGui.TreePop() end -end --- Demonstrate using Sorting facilities --- This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting. --- Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified) -local template_items_names = { - "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango", - "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot" -} - -local function Tables_Sorting() - IMGUI_DEMO_MARKER("Tables/Sorting") - -- Create item list - local s = ST.sorting - if s == nil then - s = { items = {}, - flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Sortable, TF.SortMulti, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.NoBordersInBody, TF.ScrollY) } - for n = 0, 49 do - local template_n = n % #template_items_names - s.items[n + 1] = MyItem(n, template_items_names[template_n + 1], (n * n - n) % 20) -- Assign default quantities - end - ST.sorting = s + -- In this example we'll expose most table flags and settings. + -- For specific flags and settings refer to the corresponding section for more detailed explanation. + -- This section is mostly useful to experiment with combining certain flags or settings with each others. + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) -- [DEBUG] + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) end - local items = s.items + if ImGui.TreeNode("Advanced") then + IMGUI_DEMO_MARKER("Tables/Advanced") + local s = s.Advanced - -- Options - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, TF.SortMulti) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, TF.SortTristate) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") - PopStyleCompact() + local CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow = 0, 1, 2, 3, 4, 5 -- enum ContentsType + local contents_type_names = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" } + if s.outer_size_value == nil then s.outer_size_value = ImVec2(0.0, TEXT_BASE_HEIGHT * 12) end + -- static float row_min_height = 0.0f -- Auto + -- static float inner_width_with_scroll = 0.0f -- Auto-extend + --static ImGuiTextFilter filter + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) -- FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing + if ImGui.TreeNode("Options") then + -- Make the UI compact because there are so many fields + PushStyleCompact() + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 28.0) - if ImGui.BeginTable("table_sorting", 4, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 15), 0.0) then - local CF = ImGuiTableColumnFlags - -- Declare columns - -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. - -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! - -- Demonstrate using a mixture of flags among available sort-related flags: - -- - ImGuiTableColumnFlags_DefaultSort - -- - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending - -- - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending - ImGui.TableSetupColumn("ID", bor(CF.DefaultSort, CF.WidthFixed), 0.0, MyItemColumnID_ID) - ImGui.TableSetupColumn("Name", CF.WidthFixed, 0.0, MyItemColumnID_Name) - ImGui.TableSetupColumn("Action", bor(CF.NoSort, CF.WidthFixed), 0.0, MyItemColumnID_Action) - ImGui.TableSetupColumn("Quantity", bor(CF.PreferSortDescending, CF.WidthStretch), 0.0, MyItemColumnID_Quantity) - ImGui.TableSetupScrollFreeze(0, 1) -- Make row always visible - ImGui.TableHeadersRow() + if ImGui.TreeNodeEx("Features:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, 1 --[[ImGuiTableFlags.Resizable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, 2 --[[ImGuiTableFlags.Reorderable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, 4 --[[ImGuiTableFlags.Hideable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Sortable", s.flags, 8 --[[ImGuiTableFlags.Sortable]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoSavedSettings", s.flags, 16 --[[ImGuiTableFlags.NoSavedSettings]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags, 32 --[[ImGuiTableFlags.ContextMenuInBody]]) + ImGui.TreePop() + end - -- Sort our data if sort specs have been changed! - local sort_specs = ImGui.TableGetSortSpecs() - if sort_specs and sort_specs.SpecsDirty then - MyItem_SortWithSortSpecs(sort_specs, items, #items) - sort_specs.SpecsDirty = false + if ImGui.TreeNodeEx("Decorations:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, 64 --[[ImGuiTableFlags.RowBg]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, 1536 --[[ImGuiTableFlags.BordersV]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, 1024 --[[ImGuiTableFlags.BordersOuterV]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, 512 --[[ImGuiTableFlags.BordersInnerV]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, 384 --[[ImGuiTableFlags.BordersH]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, 256 --[[ImGuiTableFlags.BordersOuterH]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, 128 --[[ImGuiTableFlags.BordersInnerH]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, 2048 --[[ImGuiTableFlags.NoBordersInBody]]); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, 4096 --[[ImGuiTableFlags.NoBordersInBodyUntilResize]]); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Sizing:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + s.flags = EditTableSizingFlags(s.flags) + ImGui.SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, 65536 --[[ImGuiTableFlags.NoHostExtendX]]) + ImGui.SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, 131072 --[[ImGuiTableFlags.NoHostExtendY]]) + ImGui.SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags, 262144 --[[ImGuiTableFlags.NoKeepColumnsVisible]]) + ImGui.SameLine(); HelpMarker("Only available if ScrollX is disabled.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, 524288 --[[ImGuiTableFlags.PreciseWidths]]) + ImGui.SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, 1048576 --[[ImGuiTableFlags.NoClip]]) + ImGui.SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Padding:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags, 2097152 --[[ImGuiTableFlags.PadOuterX]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags, 4194304 --[[ImGuiTableFlags.NoPadOuterX]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags, 8388608 --[[ImGuiTableFlags.NoPadInnerX]]) + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Scrolling:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, 16777216 --[[ImGuiTableFlags.ScrollX]]) + ImGui.SameLine() + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, 33554432 --[[ImGuiTableFlags.ScrollY]]) + ImGui.SameLine() + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Sorting:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, 67108864 --[[ImGuiTableFlags.SortMulti]]) + ImGui.SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, 134217728 --[[ImGuiTableFlags.SortTristate]]) + ImGui.SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Headers:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, 268435456 --[[ImGuiTableFlags.HighlightHoveredColumn]]) + _, s.columns_base_flags = ImGui.CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", s.columns_base_flags, 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) + ImGui.SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Other:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then + _, s.show_wrapped_text = ImGui.Checkbox("show_wrapped_text", s.show_wrapped_text) + + ImGui.DragFloat2("##OuterSize", s.outer_size_value) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + _, s.outer_size_enabled = ImGui.Checkbox("outer_size", s.outer_size_enabled) + ImGui.SameLine() + HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n" .. + "- The table is output directly in the parent window.\n" .. + "- OuterSize.x < 0.0f will right-align the table.\n" .. + "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n" .. + "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).") + + -- From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling. + -- To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled. + s.inner_width_with_scroll = ImGui.DragFloat("inner_width (when ScrollX active)", s.inner_width_with_scroll, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]]) + + s.row_min_height = ImGui.DragFloat("row_min_height", s.row_min_height, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]]) + ImGui.SameLine(); HelpMarker("Specify height of the Selectable item.") + + s.items_count = ImGui.DragInt("items_count", s.items_count, 0.1, 0, 9999) + s.contents_type = ImGui.Combo("items_type (first column)", s.contents_type, contents_type_names, #contents_type_names) + --filter.Draw("filter") + ImGui.TreePop() + end + + ImGui.PopItemWidth() + PopStyleCompact() + ImGui.Spacing() + ImGui.TreePop() end - -- Demonstrate using clipper for large vertical lists - local clipper = ImGuiListClipper() - clipper:Begin(#items) - while clipper:Step() do - for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do - -- Display a data item - local item = items[row_n + 1] - ImGui.PushID(item.ID) - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.Text("%04d", item.ID) - ImGui.TableNextColumn() - ImGui.TextUnformatted(item.Name) - ImGui.TableNextColumn() - ImGui.SmallButton("None") - ImGui.TableNextColumn() - ImGui.Text("%d", item.Quantity) - ImGui.PopID() + -- Update item list if we changed the number of items + local items = s.items + local selection = s.selection + if items.Size ~= s.items_count then + items:resize(s.items_count) + for n = 0, s.items_count - 1 do + local template_n = n % #template_items_names + local item = items.Data[n + 1] + if item == nil then item = MyItem(); items.Data[n + 1] = item end -- [Port] resize(n, MyItem()) would share one table + item.ID = n + item.Name = template_items_names[template_n + 1] + item.Quantity = (template_n == 3) and 10 or (template_n == 4) and 20 or 0 -- Assign default quantities end end - ImGui.EndTable() - end -end -local function Tables_AdvancedOptions(s) - -- Make the UI compact because there are so many fields - PushStyleCompact() - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 28.0) + local parent_draw_list = ImGui.GetWindowDrawList() + local parent_draw_list_draw_cmd_count = parent_draw_list.CmdBuffer.Size + local table_scroll_cur, table_scroll_max -- For debug display + local table_draw_list = nil -- " - if ImGui.TreeNodeEx("Features:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, TF.Reorderable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, TF.Hideable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Sortable", s.flags, TF.Sortable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoSavedSettings", s.flags, TF.NoSavedSettings) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags, TF.ContextMenuInBody) - ImGui.TreePop() - end + -- Submit table + local flags = s.flags + local columns_base_flags = s.columns_base_flags + local inner_width_to_use = (bit32.band(flags, 16777216 --[[ImGuiTableFlags.ScrollX]]) ~= 0) and s.inner_width_with_scroll or 0.0 + if ImGui.BeginTable("table_advanced", 6, flags, s.outer_size_enabled and s.outer_size_value or ImVec2(0, 0), inner_width_to_use) then + -- Declare columns + -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. + -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! + ImGui.TableSetupColumn("ID", bit32.bor(columns_base_flags, 4 --[[ImGuiTableColumnFlags.DefaultSort]], 16 --[[ImGuiTableColumnFlags.WidthFixed]], 128 --[[ImGuiTableColumnFlags.NoHide]]), 0.0, MyItemColumnID_ID) + ImGui.TableSetupColumn("Name", bit32.bor(columns_base_flags, 16 --[[ImGuiTableColumnFlags.WidthFixed]]), 0.0, MyItemColumnID_Name) + ImGui.TableSetupColumn("Action", bit32.bor(columns_base_flags, 512 --[[ImGuiTableColumnFlags.NoSort]], 16 --[[ImGuiTableColumnFlags.WidthFixed]]), 0.0, MyItemColumnID_Action) + ImGui.TableSetupColumn("Quantity", bit32.bor(columns_base_flags, 32768 --[[ImGuiTableColumnFlags.PreferSortDescending]]), 0.0, MyItemColumnID_Quantity) + ImGui.TableSetupColumn("Description", bit32.bor(columns_base_flags, (bit32.band(flags, 65536 --[[ImGuiTableFlags.NoHostExtendX]]) ~= 0) and 0 or 8 --[[ImGuiTableColumnFlags.WidthStretch]]), 0.0, MyItemColumnID_Description) + ImGui.TableSetupColumn("Hidden", bit32.bor(columns_base_flags, 2 --[[ImGuiTableColumnFlags.DefaultHide]], 512 --[[ImGuiTableColumnFlags.NoSort]])) + ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) - if ImGui.TreeNodeEx("Decorations:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, TF.RowBg) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, TF.BordersV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, TF.BordersOuterV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, TF.BordersInnerV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, TF.BordersH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, TF.BordersOuterH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, TF.BordersInnerH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, TF.NoBordersInBody); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, TF.NoBordersInBodyUntilResize); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") - ImGui.TreePop() - end + -- Sort our data if sort specs have been changed! + local sort_specs = ImGui.TableGetSortSpecs() + if sort_specs and sort_specs.SpecsDirty then + s.items_need_sort = true + end + if sort_specs and s.items_need_sort and items.Size > 1 then + MyItem_SortWithSortSpecs(sort_specs, items.Data, items.Size) + sort_specs.SpecsDirty = false + end + s.items_need_sort = false - if ImGui.TreeNodeEx("Sizing:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - s.flags = EditTableSizingFlags(s.flags) - ImGui.SameLine(); DemoHelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, TF.NoHostExtendX) - ImGui.SameLine(); DemoHelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, TF.NoHostExtendY) - ImGui.SameLine(); DemoHelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags, TF.NoKeepColumnsVisible) - ImGui.SameLine(); DemoHelpMarker("Only available if ScrollX is disabled.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, TF.PreciseWidths) - ImGui.SameLine(); DemoHelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, TF.NoClip) - ImGui.SameLine(); DemoHelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.") - ImGui.TreePop() - end + -- Take note of whether we are currently sorting based on the Quantity field, + -- we will use this to trigger sorting when we know the data of this column has been modified. + local sorts_specs_using_quantity = bit32.band(ImGui.TableGetColumnFlags(3), 67108864 --[[ImGuiTableColumnFlags.IsSorted]]) ~= 0 - if ImGui.TreeNodeEx("Padding:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags, TF.PadOuterX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags, TF.NoPadOuterX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags, TF.NoPadInnerX) - ImGui.TreePop() - end + -- Show headers + if s.show_headers and bit32.band(columns_base_flags, 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) ~= 0 then + ImGui.TableAngledHeadersRow() + end + if s.show_headers then + ImGui.TableHeadersRow() + end - if ImGui.TreeNodeEx("Scrolling:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, TF.ScrollX) - ImGui.SameLine() - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - ImGui.SameLine() - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, 128 --[[ImGuiSliderFlags.NoInput]]) - ImGui.TreePop() - end + -- Show data + -- FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here? + -- Demonstrate using clipper for large vertical lists + local clipper = ImGuiListClipper() + clipper:Begin(items.Size) + while clipper:Step() do + for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do + local item = items.Data[row_n + 1] + --if not filter:PassFilter(item.Name) then + -- continue - if ImGui.TreeNodeEx("Sorting:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, TF.SortMulti) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, TF.SortTristate) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") - ImGui.TreePop() - end + local item_is_selected = selection:contains(item.ID) + ImGui.PushID(item.ID) + ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], s.row_min_height) - if ImGui.TreeNodeEx("Headers:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, TF.HighlightHoveredColumn) - _, s.columns_base_flags = ImGui.CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", s.columns_base_flags, 262144 --[[ImGuiTableColumnFlags.AngledHeader]]) - ImGui.SameLine(); DemoHelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).") - ImGui.TreePop() - end - - if ImGui.TreeNodeEx("Other:", 32 --[[ImGuiTreeNodeFlags.DefaultOpen]]) then - _, s.show_wrapped_text = ImGui.Checkbox("show_wrapped_text", s.show_wrapped_text) - - ImGui.DragFloat2("##OuterSize", s.outer_size_value) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - _, s.outer_size_enabled = ImGui.Checkbox("outer_size", s.outer_size_enabled) - ImGui.SameLine() - DemoHelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n" .. - "- The table is output directly in the parent window.\n" .. - "- OuterSize.x < 0.0f will right-align the table.\n" .. - "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n" .. - "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).") - - -- From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling. - -- To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled. - s.inner_width_with_scroll = ImGui.DragFloat("inner_width (when ScrollX active)", s.inner_width_with_scroll, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]]) - - s.row_min_height = ImGui.DragFloat("row_min_height", s.row_min_height, 1.0, 0.0, 3.4028234663853e+38 --[[FLT_MAX]]) - ImGui.SameLine(); DemoHelpMarker("Specify height of the Selectable item.") - - s.items_count = ImGui.DragInt("items_count", s.items_count, 0.1, 0, 9999) - local contents_type_names = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" } - if ImGui.Combo then - s.contents_type = ImGui.Combo("items_type (first column)", s.contents_type, contents_type_names, #contents_type_names) - else - NotPorted("Combo") - end - ImGui.TreePop() - end - - ImGui.PopItemWidth() - PopStyleCompact() - ImGui.Spacing() -end - --- In this example we'll expose most table flags and settings. --- For specific flags and settings refer to the corresponding section for more detailed explanation. --- This section is mostly useful to experiment with combining certain flags or settings with each others. -local function Tables_Advanced() - IMGUI_DEMO_MARKER("Tables/Advanced") - local CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow = 0, 1, 2, 3, 4, 5 - local s = ST.advanced - if s == nil then - s = { flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Sortable, TF.SortMulti, TF.RowBg, TF.Borders, TF.NoBordersInBody, TF.ScrollX, TF.ScrollY, TF.SizingFixedFit), - columns_base_flags = 0 --[[ImGuiTableColumnFlags.None]], contents_type = CT_SelectableSpanRow, - freeze_cols = 1, freeze_rows = 1, items_count = #template_items_names * 2, - outer_size_value = ImVec2(0.0, TEXT_BASE_HEIGHT * 12), row_min_height = 0.0, inner_width_with_scroll = 0.0, - outer_size_enabled = true, show_headers = true, show_wrapped_text = false, - items = {}, selection = {}, items_need_sort = false, show_debug_details = false } - ST.advanced = s - end - --ImGui.SetNextItemOpen(true, ImGuiCond.Once) -- FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing - if ImGui.TreeNode("Options") then - Tables_AdvancedOptions(s) - ImGui.TreePop() - end - - -- Update item list if we changed the number of items - local items = s.items - local selection = s.selection - if #items ~= s.items_count then - for n = #items, s.items_count + 1, -1 do items[n] = nil end - for n = 0, s.items_count - 1 do - local template_n = n % #template_items_names - items[n + 1] = MyItem(n, template_items_names[template_n + 1], (template_n == 3) and 10 or (template_n == 4) and 20 or 0) -- Assign default quantities - end - end - - local parent_draw_list = ImGui.GetWindowDrawList() - local parent_draw_list_draw_cmd_count = parent_draw_list.CmdBuffer.Size - local table_scroll_cur, table_scroll_max -- For debug display - local table_draw_list = nil -- " - - -- Submit table - local flags = s.flags - local columns_base_flags = s.columns_base_flags - local inner_width_to_use = Has(flags, TF.ScrollX) and s.inner_width_with_scroll or 0.0 - local CF = ImGuiTableColumnFlags - if ImGui.BeginTable("table_advanced", 6, flags, s.outer_size_enabled and s.outer_size_value or ImVec2(0, 0), inner_width_to_use) then - -- Declare columns - -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. - -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! - ImGui.TableSetupColumn("ID", bor(columns_base_flags, CF.DefaultSort, CF.WidthFixed, CF.NoHide), 0.0, MyItemColumnID_ID) - ImGui.TableSetupColumn("Name", bor(columns_base_flags, CF.WidthFixed), 0.0, MyItemColumnID_Name) - ImGui.TableSetupColumn("Action", bor(columns_base_flags, CF.NoSort, CF.WidthFixed), 0.0, MyItemColumnID_Action) - ImGui.TableSetupColumn("Quantity", bor(columns_base_flags, CF.PreferSortDescending), 0.0, MyItemColumnID_Quantity) - ImGui.TableSetupColumn("Description", bor(columns_base_flags, Has(flags, TF.NoHostExtendX) and 0 or CF.WidthStretch), 0.0, MyItemColumnID_Description) - ImGui.TableSetupColumn("Hidden", bor(columns_base_flags, CF.DefaultHide, CF.NoSort)) - ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) - - -- Sort our data if sort specs have been changed! - local sort_specs = ImGui.TableGetSortSpecs() - if sort_specs and sort_specs.SpecsDirty then - s.items_need_sort = true - end - if sort_specs and s.items_need_sort and #items > 1 then - MyItem_SortWithSortSpecs(sort_specs, items, #items) - sort_specs.SpecsDirty = false - end - s.items_need_sort = false - - -- Take note of whether we are currently sorting based on the Quantity field, - -- we will use this to trigger sorting when we know the data of this column has been modified. - local sorts_specs_using_quantity = Has(ImGui.TableGetColumnFlags(3), CF.IsSorted) - - -- Show headers - if s.show_headers and Has(columns_base_flags, CF.AngledHeader) then - ImGui.TableAngledHeadersRow() - end - if s.show_headers then - ImGui.TableHeadersRow() - end - - -- Show data - -- FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here? - -- Demonstrate using clipper for large vertical lists - local clipper = ImGuiListClipper() - clipper:Begin(#items) - while clipper:Step() do - for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do - local item = items[row_n + 1] - - local item_is_selected = table.find(selection, item.ID) ~= nil - ImGui.PushID(item.ID) - ImGui.TableNextRow(0 --[[ImGuiTableRowFlags.None]], s.row_min_height) - - -- For the demo purpose we can select among different type of items submitted in the first column - ImGui.TableSetColumnIndex(0) - local label = string.format("%04d", item.ID) - local ct = s.contents_type - if ct == CT_Text then - ImGui.TextUnformatted(label) - elseif ct == CT_Button then - ImGui.Button(label) - elseif ct == CT_SmallButton then - ImGui.SmallButton(label) - elseif ct == CT_FillButton then - ImGui.Button(label, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) - elseif ct == CT_Selectable or ct == CT_SelectableSpanRow then - local selectable_flags = (ct == CT_SelectableSpanRow) and bor(2 --[[ImGuiSelectableFlags.SpanAllColumns]], 16 --[[ImGuiSelectableFlags.AllowOverlap]]) or 0 --[[ImGuiSelectableFlags.None]] - if ImGui.Selectable(label, item_is_selected, selectable_flags, ImVec2(0, s.row_min_height)) then - if ImGui.GetIO().KeyCtrl then - if item_is_selected then - table.remove(selection, table.find(selection, item.ID)) + -- For the demo purpose we can select among different type of items submitted in the first column + ImGui.TableSetColumnIndex(0) + local label = string.format("%04d", item.ID) + local contents_type = s.contents_type + if contents_type == CT_Text then + ImGui.TextUnformatted(label) + elseif contents_type == CT_Button then + ImGui.Button(label) + elseif contents_type == CT_SmallButton then + ImGui.SmallButton(label) + elseif contents_type == CT_FillButton then + ImGui.Button(label, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0)) + elseif contents_type == CT_Selectable or contents_type == CT_SelectableSpanRow then + local selectable_flags = (contents_type == CT_SelectableSpanRow) and bit32.bor(2 --[[ImGuiSelectableFlags.SpanAllColumns]], 16 --[[ImGuiSelectableFlags.AllowOverlap]]) or 0 --[[ImGuiSelectableFlags.None]] + if ImGui.Selectable(label, item_is_selected, selectable_flags, ImVec2(0, s.row_min_height)) then + if ImGui.GetIO().KeyCtrl then + if item_is_selected then + selection:find_erase_unsorted(item.ID) + else + selection:push_back(item.ID) + end else - table.insert(selection, item.ID) + selection:clear() + selection:push_back(item.ID) end - else - table.clear(selection) - table.insert(selection, item.ID) end end - end - if ImGui.TableSetColumnIndex(1) then - ImGui.TextUnformatted(item.Name) - end + if ImGui.TableSetColumnIndex(1) then + ImGui.TextUnformatted(item.Name) + end - -- Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity, - -- and we are currently sorting on the column showing the Quantity. - -- To avoid triggering a sort while holding the button, we only trigger it when the button has been released. - -- You will probably need some extra logic if you want to automatically sort when a specific entry changes. - if ImGui.TableSetColumnIndex(2) then - if ImGui.SmallButton("Chop") then item.Quantity = item.Quantity + 1 end - if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end - ImGui.SameLine() - if ImGui.SmallButton("Eat") then item.Quantity = item.Quantity - 1 end - if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end - end + -- Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity, + -- and we are currently sorting on the column showing the Quantity. + -- To avoid triggering a sort while holding the button, we only trigger it when the button has been released. + -- You will probably need some extra logic if you want to automatically sort when a specific entry changes. + if ImGui.TableSetColumnIndex(2) then + if ImGui.SmallButton("Chop") then item.Quantity = item.Quantity + 1 end + if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end + ImGui.SameLine() + if ImGui.SmallButton("Eat") then item.Quantity = item.Quantity - 1 end + if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end + end - if ImGui.TableSetColumnIndex(3) then - ImGui.Text("%d", item.Quantity) - end + if ImGui.TableSetColumnIndex(3) then + ImGui.Text("%d", item.Quantity) + end - ImGui.TableSetColumnIndex(4) - if s.show_wrapped_text then - ImGui.TextWrapped("Lorem ipsum dolor sit amet") - else - ImGui.Text("Lorem ipsum dolor sit amet") - end + ImGui.TableSetColumnIndex(4) + if s.show_wrapped_text then + ImGui.TextWrapped("Lorem ipsum dolor sit amet") + else + ImGui.Text("Lorem ipsum dolor sit amet") + end - if ImGui.TableSetColumnIndex(5) then - ImGui.Text("1234") - end + if ImGui.TableSetColumnIndex(5) then + ImGui.Text("1234") + end - ImGui.PopID() + ImGui.PopID() + end + end + + -- Store some info to display debug details below + table_scroll_cur = ImVec2(ImGui.GetScrollX(), ImGui.GetScrollY()) + table_scroll_max = ImVec2(ImGui.GetScrollMaxX(), ImGui.GetScrollMaxY()) + table_draw_list = ImGui.GetWindowDrawList() + ImGui.EndTable() + end + _, s.show_debug_details = ImGui.Checkbox("Debug details", s.show_debug_details) + if s.show_debug_details and table_draw_list then + ImGui.SameLine(0.0, 0.0) + local table_draw_list_draw_cmd_count = table_draw_list.CmdBuffer.Size + if table_draw_list == parent_draw_list then + ImGui.Text(": DrawCmd: +%d (in same window)", + table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count) + else + ImGui.Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", + table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y) end end - - -- Store some info to display debug details below - table_scroll_cur = ImVec2(ImGui.GetScrollX(), ImGui.GetScrollY()) - table_scroll_max = ImVec2(ImGui.GetScrollMaxX(), ImGui.GetScrollMaxY()) - table_draw_list = ImGui.GetWindowDrawList() - ImGui.EndTable() + ImGui.TreePop() end - _, s.show_debug_details = ImGui.Checkbox("Debug details", s.show_debug_details) - if s.show_debug_details and table_draw_list then - ImGui.SameLine(0.0, 0.0) - local table_draw_list_draw_cmd_count = table_draw_list.CmdBuffer.Size - if table_draw_list == parent_draw_list then - ImGui.Text(": DrawCmd: +%d (in same window)", - table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count) - else - ImGui.Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", - table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y) - end + + ImGui.PopID() + + DemoWindowColumns() + + if s.disable_indent then + ImGui.PopStyleVar() end end -local DCS = { selected = -1, h_borders = true, v_borders = true, columns_count = 4, foo = 1.0, bar = 1.0 } - --- Demonstrate old/legacy Columns API! --- [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!] -local function DemoWindowColumns() +S.DemoWindowColumns = { + selected = -1, + h_borders = true, + v_borders = true, + columns_count = 4, + foo = 1.0, + bar = 1.0, +} +function DemoWindowColumns() + local s = S.DemoWindowColumns local open = ImGui.TreeNode("Legacy Columns API") ImGui.SameLine() - DemoHelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!") + HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!") if not open then return end @@ -25627,12 +28523,12 @@ local function DemoWindowColumns() if ImGui.TreeNode("Basic") then IMGUI_DEMO_MARKER("Columns (legacy API)/Basic") ImGui.Text("Without border:") - ImGui.Columns(3, "mycolumns3", false) -- 3-ways, no border + ImGui.Columns(3, "mycolumns3", false) -- 3-ways, no border ImGui.Separator() for n = 0, 13 do local label = string.format("Item %d", n) if ImGui.Selectable(label) then end - --if ImGui.Button(label, ImVec2(-FLT_MIN,0.0)) then end + --if (ImGui.Button(label, ImVec2(-FLT_MIN,0.0))) {} ImGui.NextColumn() end ImGui.Columns(1) @@ -25650,8 +28546,8 @@ local function DemoWindowColumns() local paths = { "/path/one", "/path/two", "/path/three" } for i = 0, 2 do local label = string.format("%04d", i) - if ImGui.Selectable(label, DCS.selected == i, 2 --[[ImGuiSelectableFlags.SpanAllColumns]]) then - DCS.selected = i + if ImGui.Selectable(label, s.selected == i, 2 --[[ImGuiSelectableFlags.SpanAllColumns]]) then + s.selected = i end local hovered = ImGui.IsItemHovered() ImGui.NextColumn() @@ -25669,17 +28565,17 @@ local function DemoWindowColumns() -- NB: Future columns API should allow automatic horizontal borders. local lines_count = 3 ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - DCS.columns_count = ImGui.DragInt("##columns_count", DCS.columns_count, 0.1, 2, 10, "%d columns") - if DCS.columns_count < 2 then - DCS.columns_count = 2 + s.columns_count = ImGui.DragInt("##columns_count", s.columns_count, 0.1, 2, 10, "%d columns") + if s.columns_count < 2 then + s.columns_count = 2 end ImGui.SameLine() - _, DCS.h_borders = ImGui.Checkbox("horizontal", DCS.h_borders) + _, s.h_borders = ImGui.Checkbox("horizontal", s.h_borders) ImGui.SameLine() - _, DCS.v_borders = ImGui.Checkbox("vertical", DCS.v_borders) - ImGui.Columns(DCS.columns_count, nil, DCS.v_borders) - for i = 0, DCS.columns_count * lines_count - 1 do - if DCS.h_borders and ImGui.GetColumnIndex() == 0 then + _, s.v_borders = ImGui.Checkbox("vertical", s.v_borders) + ImGui.Columns(s.columns_count, nil, s.v_borders) + for i = 0, s.columns_count * lines_count - 1 do + if s.h_borders and ImGui.GetColumnIndex() == 0 then ImGui.Separator() end ImGui.PushID(i) @@ -25694,7 +28590,7 @@ local function DemoWindowColumns() ImGui.NextColumn() end ImGui.Columns(1) - if DCS.h_borders then + if s.h_borders then ImGui.Separator() end ImGui.TreePop() @@ -25712,13 +28608,13 @@ local function DemoWindowColumns() ImGui.Text("ImGui") ImGui.Button("Apple") - DCS.foo = ImGui.InputFloat("red", DCS.foo, 0.05, 0, "%.3f") + s.foo = ImGui.InputFloat("red", s.foo, 0.05, 0, "%.3f") ImGui.Text("An extra line here.") ImGui.NextColumn() ImGui.Text("Sailor") ImGui.Button("Corniflower") - DCS.bar = ImGui.InputFloat("blue", DCS.bar, 0.05, 0, "%.3f") + s.bar = ImGui.InputFloat("blue", s.bar, 0.05, 0, "%.3f") ImGui.NextColumn() if ImGui.CollapsingHeader("Category A") then ImGui.Text("Blah blah blah") end ImGui.NextColumn() @@ -25803,104 +28699,1045 @@ local function DemoWindowColumns() ImGui.TreePop() end -local tables_sections = { - { "Basic", Tables_Basic }, - { "Borders, background", Tables_BordersBackground }, - { "Resizable, stretch", Tables_ResizableStretch }, - { "Resizable, fixed", Tables_ResizableFixed }, - { "Resizable, mixed", Tables_ResizableMixed }, - { "Reorderable, hideable, with headers", Tables_Reorderable }, - { "Padding", Tables_Padding }, - { "Sizing policies", Tables_SizingPolicies }, - { "Vertical scrolling, with clipping", Tables_VerticalScrolling }, - { "Horizontal scrolling", Tables_HorizontalScrolling }, - { "Columns flags", Tables_ColumnsFlags }, - { "Columns widths", Tables_ColumnsWidths }, - { "Nested tables", Tables_Nested }, - { "Row height", Tables_RowHeight }, - { "Outer size", Tables_OuterSize }, - { "Background color", Tables_BackgroundColor }, - { "Tree view", Tables_TreeView }, - { "Item width", Tables_ItemWidth }, - { "Custom headers", Tables_CustomHeaders }, - { "Angled headers", Tables_AngledHeaders }, - { "Context menus", Tables_ContextMenus }, - { "Synced instances", Tables_SyncedInstances }, - { "Sorting", Tables_Sorting }, - { "Advanced", Tables_Advanced }, +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowInputs() +------------------------------------------------------------------------------- + +S.DemoWindowInputs = { + funcs = { IsLegacyNativeDupe = function(key) return false end }, -- struct funcs (hoisted to avoid a per-frame closure) -- [Port] + capture_override_mouse = -1, + capture_override_keyboard = -1, + route_options = ImGuiInputFlags.Repeat, + route_type = ImGuiInputFlags.RouteFocused, + f = 0.5, + tabbing_buf = ImGui.NewTextBuffer("hello", 32), + focus_buf = ImGui.NewTextBuffer("click on a button to set focus", 128), + f3 = { 0.0, 0.0, 0.0 }, } +S.DemoWindowInputs.mouse_cursors_names = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "Wait", "Progress", "NotAllowed" } +function DemoWindowInputs() + local s = S.DemoWindowInputs + if ImGui.CollapsingHeader("Inputs & Focus") then + local io = ImGui.GetIO() -function DemoWindowTables() - --ImGui.SetNextItemOpen(true, ImGuiCond.Once) - if not ImGui.CollapsingHeader("Tables & Columns") then - return - end + -- Display inputs submitted to ImGuiIO + ImGui.SetNextItemOpen(true, 2 --[[ImGuiCond.Once]]) + local inputs_opened = ImGui.TreeNode("Inputs") + ImGui.SameLine() + HelpMarker( + "This is a simplified view. See more detailed input state:\n" .. + "- in 'Tools->Metrics/Debugger->Inputs'.\n" .. + "- in 'Tools->Debug Log->IO'.") + if inputs_opened then + IMGUI_DEMO_MARKER("Inputs & Focus/Inputs") + if ImGui.IsMousePosValid() then + ImGui.Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y) + else + ImGui.Text("Mouse pos: ") + end + ImGui.Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y) + ImGui.Text("Mouse down:") + for i = 0, 2 do if ImGui.IsMouseDown(i) then ImGui.SameLine(); ImGui.Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]) end end -- IM_COUNTOF(io.MouseDown) == 3, 0-based + ImGui.Text("Mouse wheel: %.1f", io.MouseWheel) + ImGui.Text("Mouse clicked count:") + for i = 0, 2 do if io.MouseClickedCount[i] > 0 then ImGui.SameLine(); ImGui.Text("b%d: %d", i, io.MouseClickedCount[i]) end end - -- Using those as a base value to create width/height that are factor of the size of our font - TEXT_BASE_WIDTH = ImGui.CalcTextSize("A").x - TEXT_BASE_HEIGHT = ImGui.GetTextLineHeightWithSpacing() + -- We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows + -- displaying the data for old/new backends. + -- User code should never have to go through such hoops! + -- You can generally iterate between ImGuiKey.NamedKey_BEGIN and ImGuiKey.NamedKey_END. + local funcs = s.funcs + local start_key = 512 --[[ImGuiKey.NamedKey_BEGIN]] + ImGui.Text("Keys down:") for key = start_key, 667 --[[ImGuiKey.NamedKey_END]] - 1 do repeat if funcs.IsLegacyNativeDupe(key) or not ImGui.IsKeyDown(key) then break end ImGui.SameLine(); if key < 512 --[[ImGuiKey.NamedKey_BEGIN]] then ImGui.Text("\"%s\"", ImGui.GetKeyName(key)) else ImGui.Text("\"%s\" %d", ImGui.GetKeyName(key), key) end until true end + ImGui.Text("Keys mods: %s%s%s%s", io.KeyCtrl and "CTRL " or "", io.KeyShift and "SHIFT " or "", io.KeyAlt and "ALT " or "", io.KeySuper and "SUPER " or "") + ImGui.Text("Chars queue:") for i = 0, io.InputQueueCharacters.Size - 1 do local c = io.InputQueueCharacters.Data[i + 1]; ImGui.SameLine(); ImGui.Text("\'%s\' (0x%04X)", (c > 32 and c <= 255) and string.char(c) or '?', c) end -- FIXME: We should convert 'c' to UTF-8 here but the functions are not public. - ImGui.PushID("Tables") - - local open_action = -1 - if ImGui.Button("Expand all") then - open_action = 1 - end - ImGui.SameLine() - if ImGui.Button("Collapse all") then - open_action = 0 - end - ImGui.SameLine() - - -- Options - _, ST.disable_indent = ImGui.Checkbox("Disable tree indentation", ST.disable_indent or false) - ImGui.SameLine() - DemoHelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.") - ImGui.Separator() - local disable_indent = ST.disable_indent - if disable_indent then - ImGui.PushStyleVar(16 --[[ImGuiStyleVar.IndentSpacing]], 0.0) - end - - -- About Styling of tables - -- Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs. - -- There are however a few settings that a shared and part of the ImGuiStyle structure: - -- style.CellPadding -- Padding within each cell - -- style.Colors[ImGuiCol.TableHeaderBg] -- Table header background - -- style.Colors[ImGuiCol.TableBorderStrong] -- Table outer and header borders - -- style.Colors[ImGuiCol.TableBorderLight] -- Table inner borders - -- style.Colors[ImGuiCol.TableRowBg] -- Table row background when ImGuiTableFlags_RowBg is enabled (even rows) - -- style.Colors[ImGuiCol.TableRowBgAlt] -- Table row background when ImGuiTableFlags_RowBg is enabled (odds rows) - - -- Demos - for _, sec in ipairs(tables_sections) do - if open_action ~= -1 then - ImGui.SetNextItemOpen(open_action ~= 0) + ImGui.TreePop() end - if ImGui.TreeNode(sec[1]) then - sec[2]() + + -- Display ImGuiIO output flags + ImGui.SetNextItemOpen(true, 2 --[[ImGuiCond.Once]]) + local outputs_opened = ImGui.TreeNode("Outputs") + ImGui.SameLine() + HelpMarker( + "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui " .. + "to instruct your application of how to route inputs. Typically, when a value is true, it means " .. + "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n" .. + "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, " .. + "and underlying application should ignore mouse inputs (in practice there are many and more subtle " .. + "rules leading to how those flags are set).") + if outputs_opened then + IMGUI_DEMO_MARKER("Inputs & Focus/Outputs") + ImGui.Text("io.WantCaptureMouse: %d", io.WantCaptureMouse and 1 or 0) + ImGui.Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose and 1 or 0) + ImGui.Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard and 1 or 0) + ImGui.Text("io.WantTextInput: %d", io.WantTextInput and 1 or 0) + ImGui.Text("io.WantSetMousePos: %d", io.WantSetMousePos and 1 or 0) + ImGui.Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive and 1 or 0, io.NavVisible and 1 or 0) + + IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override") + if ImGui.TreeNode("WantCapture override") then + HelpMarker( + "Hovering the colored canvas will override io.WantCaptureXXX fields.\n" .. + "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering " .. + "and true when clicking.") + local capture_override_desc = { "None", "Set to false", "Set to true" } + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 15) + s.capture_override_mouse = ImGui.SliderInt("SetNextFrameWantCaptureMouse() on hover", s.capture_override_mouse, -1, 1, capture_override_desc[s.capture_override_mouse + 2], 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 15) + s.capture_override_keyboard = ImGui.SliderInt("SetNextFrameWantCaptureKeyboard() on hover", s.capture_override_keyboard, -1, 1, capture_override_desc[s.capture_override_keyboard + 2], 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + + ImGui.ColorButton("##panel", ImVec4(0.7, 0.1, 0.7, 1.0), bit32.bor(64 --[[ImGuiColorEditFlags.NoTooltip]], 512 --[[ImGuiColorEditFlags.NoDragDrop]]), ImVec2(128.0, 96.0)) -- Dummy item + if ImGui.IsItemHovered() and s.capture_override_mouse ~= -1 then + ImGui.SetNextFrameWantCaptureMouse(s.capture_override_mouse == 1) + end + if ImGui.IsItemHovered() and s.capture_override_keyboard ~= -1 then + ImGui.SetNextFrameWantCaptureKeyboard(s.capture_override_keyboard == 1) + end + + ImGui.TreePop() + end + ImGui.TreePop() + end + + -- Demonstrate using Shortcut() and Routing Policies. + -- The general flow is: + -- - Code interested in a chord (e.g. "Ctrl+A") declares their intent. + -- - Multiple locations may be interested in same chord! Routing helps find a winner. + -- - Every frame, we resolve all claims and assign one owner if the modifiers are matching. + -- - The lower-level function is 'bool SetShortcutRouting()', returns true when caller got the route. + -- - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing flags. + -- - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags.RouteFocused. + -- TL;DR: Most uses will simply be: + -- - Shortcut(ImGuiMod_Ctrl | ImGuiKey.A); -- Use ImGuiInputFlags.RouteFocused policy. + if ImGui.TreeNode("Shortcuts") then + IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts") + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_Repeat", s.route_options, 1 --[[ImGuiInputFlags.Repeat]]) + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteActive", s.route_type, 1024 --[[ImGuiInputFlags.RouteActive]]) + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteFocused (default)", s.route_type, 2048 --[[ImGuiInputFlags.RouteFocused]]) + ImGui.Indent() + ImGui.BeginDisabled(s.route_type ~= 2048 --[[ImGuiInputFlags.RouteFocused]]) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteOverActive##0", s.route_options, 32768 --[[ImGuiInputFlags.RouteOverActive]]) + ImGui.EndDisabled() + ImGui.Unindent() + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteGlobal", s.route_type, 4096 --[[ImGuiInputFlags.RouteGlobal]]) + ImGui.Indent() + ImGui.BeginDisabled(s.route_type ~= 4096 --[[ImGuiInputFlags.RouteGlobal]]) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteOverFocused", s.route_options, 16384 --[[ImGuiInputFlags.RouteOverFocused]]) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteOverActive", s.route_options, 32768 --[[ImGuiInputFlags.RouteOverActive]]) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", s.route_options, 65536 --[[ImGuiInputFlags.RouteUnlessBgFocused]]) + ImGui.EndDisabled() + ImGui.Unindent() + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteAlways", s.route_type, 8192 --[[ImGuiInputFlags.RouteAlways]]) + local flags = bit32.bor(s.route_type, s.route_options) -- Merged flags + if s.route_type ~= 4096 --[[ImGuiInputFlags.RouteGlobal]] then + flags = bit32.band(flags, bit32.bnot(bit32.bor(16384 --[[ImGuiInputFlags.RouteOverFocused]], 32768 --[[ImGuiInputFlags.RouteOverActive]], 65536 --[[ImGuiInputFlags.RouteUnlessBgFocused]]))) + end + + ImGui.SeparatorText("Using SetNextItemShortcut()") + ImGui.Text("Ctrl+S") + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 564 --[[ImGuiKey.S]]), bit32.bor(flags, 262144 --[[ImGuiInputFlags.Tooltip]])) + ImGui.Button("Save") + ImGui.Text("Alt+F") + ImGui.SetNextItemShortcut(bit32.bor(16384 --[[ImGuiMod_Alt]], 551 --[[ImGuiKey.F]]), bit32.bor(flags, 262144 --[[ImGuiInputFlags.Tooltip]])) + s.f = ImGui.SliderFloat("Factor", s.f, 0.0, 1.0) + + ImGui.SeparatorText("Using Shortcut()") + local line_height = ImGui.GetTextLineHeightWithSpacing() + local key_chord = bit32.bor(4096 --[[ImGuiMod_Ctrl]], 546 --[[ImGuiKey.A]]) + + -- [Port] ImGui.Shortcut() has no owner_id default (upstream public overload passes ImGuiKeyOwner_Any): pass it explicitly. + ImGui.Text("Ctrl+A") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, 0 --[[ImGuiKeyOwner_Any]]) and "PRESSED" or "...") + + ImGui.PushStyleColor(3 --[[ImGuiCol.ChildBg]], ImVec4(1.0, 0.0, 1.0, 0.1)) + + ImGui.BeginChild("WindowA", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], line_height * 14), true) + ImGui.Text("Press Ctrl+A and see who receives it!") + ImGui.Separator() + + -- 1: Window polling for Ctrl+A + ImGui.Text("(in WindowA)") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, 0 --[[ImGuiKeyOwner_Any]]) and "PRESSED" or "...") + + -- 2: InputText also polling for Ctrl+A: it always uses _RouteFocused internally (gets priority when active) + -- (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h) + --char str[16] = "Press Ctrl+A"; + --ImGui.Spacing(); + --ImGui.InputText("InputTextB", str, IM_COUNTOF(str), ImGuiInputTextFlags.ReadOnly); + --ImGuiID item_id = ImGui.GetItemID(); + --ImGui.SameLine(); HelpMarker("Internal widgets always use _RouteFocused"); + --ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused(), ImGui.Shortcut(key_chord, flags, item_id) ? "PRESSED" : "..."); + + -- 3: Dummy child is not claiming the route: focusing them shouldn't steal route away from WindowA + ImGui.BeginChild("ChildD", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], line_height * 4), true) + ImGui.Text("(in ChildD: not using same Shortcut)") + ImGui.Text("IsWindowFocused: %d", ImGui.IsWindowFocused() and 1 or 0) + ImGui.EndChild() + + -- 4: Child window polling for Ctrl+A. It is deeper than WindowA and gets priority when focused. + ImGui.BeginChild("ChildE", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], line_height * 4), true) + ImGui.Text("(in ChildE: using same Shortcut)") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, 0 --[[ImGuiKeyOwner_Any]]) and "PRESSED" or "...") + ImGui.EndChild() + + -- 5: In a popup + if ImGui.Button("Open Popup") then + ImGui.OpenPopup("PopupF") + end + if ImGui.BeginPopup("PopupF") then + ImGui.Text("(in PopupF)") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, 0 --[[ImGuiKeyOwner_Any]]) and "PRESSED" or "...") + -- (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h) + --ImGui.InputText("InputTextG", str, IM_COUNTOF(str), ImGuiInputTextFlags.ReadOnly); + --ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused(), ImGui.Shortcut(key_chord, flags, ImGui.GetItemID()) ? "PRESSED" : "..."); + ImGui.EndPopup() + end + ImGui.EndChild() + ImGui.PopStyleColor() + + ImGui.TreePop() + end + + -- Display mouse cursors + if ImGui.TreeNode("Mouse Cursors") then + IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors") + local mouse_cursors_names = s.mouse_cursors_names -- 1-based + assert(#mouse_cursors_names == 11 --[[ImGuiMouseCursor.COUNT]]) + + local current = ImGui.GetMouseCursor() + local cursor_name = "N/A" + if (current >= 0 --[[ImGuiMouseCursor.Arrow]]) and (current < 11 --[[ImGuiMouseCursor.COUNT]]) then cursor_name = mouse_cursors_names[current + 1] end + ImGui.Text("Current mouse cursor = %d: %s", current, cursor_name) + ImGui.BeginDisabled(true) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseCursors", io.BackendFlags, 2 --[[ImGuiBackendFlags.HasMouseCursors]]) + ImGui.EndDisabled() + + ImGui.Text("Hover to see mouse cursors:") + ImGui.SameLine(); HelpMarker( + "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " .. + "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " .. + "otherwise your backend needs to handle it.") + for i = 0, 11 --[[ImGuiMouseCursor.COUNT]] - 1 do + local label = string.format("Mouse cursor %d: %s", i, mouse_cursors_names[i + 1]) + ImGui.Bullet(); ImGui.Selectable(label, false) + if ImGui.IsItemHovered() then + ImGui.SetMouseCursor(i) + end + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Tabbing") then + IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing") + ImGui.Text("Use Tab/Shift+Tab to cycle through keyboard editable fields.") + local buf = s.tabbing_buf + ImGui.InputText("1", buf, 32) + ImGui.InputText("2", buf, 32) + ImGui.InputText("3", buf, 32) + ImGui.PushItemFlag(1 --[[ImGuiItemFlags.NoTabStop]], true) + ImGui.InputText("4 (tab skip)", buf, 32) + ImGui.SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.") + ImGui.PopItemFlag() + ImGui.InputText("5", buf, 32) + ImGui.TreePop() + end + + if ImGui.TreeNode("Focus from code") then + IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code") + local focus_1 = ImGui.Button("Focus on 1"); ImGui.SameLine() + local focus_2 = ImGui.Button("Focus on 2"); ImGui.SameLine() + local focus_3 = ImGui.Button("Focus on 3") + local has_focus = 0 + local buf = s.focus_buf + + if focus_1 then ImGui.SetKeyboardFocusHere() end + ImGui.InputText("1", buf, 128) + if ImGui.IsItemActive() then has_focus = 1 end + + if focus_2 then ImGui.SetKeyboardFocusHere() end + ImGui.InputText("2", buf, 128) + if ImGui.IsItemActive() then has_focus = 2 end + + ImGui.PushItemFlag(1 --[[ImGuiItemFlags.NoTabStop]], true) + if focus_3 then ImGui.SetKeyboardFocusHere() end + ImGui.InputText("3 (tab skip)", buf, 128) + if ImGui.IsItemActive() then has_focus = 3 end + ImGui.SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.") + ImGui.PopItemFlag() + + if has_focus ~= 0 then + ImGui.Text("Item with focus: %d", has_focus) + else + ImGui.Text("Item with focus: ") + end + + -- Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item + local f3 = s.f3 + local focus_ahead = -1 + if ImGui.Button("Focus on X") then focus_ahead = 0 end ImGui.SameLine() + if ImGui.Button("Focus on Y") then focus_ahead = 1 end ImGui.SameLine() + if ImGui.Button("Focus on Z") then focus_ahead = 2 end + if focus_ahead ~= -1 then ImGui.SetKeyboardFocusHere(focus_ahead) end + ImGui.SliderFloat3("Float3", f3, 0.0, 1.0) + + ImGui.TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.") + ImGui.TreePop() + end + + if ImGui.TreeNode("Dragging") then + IMGUI_DEMO_MARKER("Inputs & Focus/Dragging") + ImGui.TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.") + for button = 0, 2 do + ImGui.Text("IsMouseDragging(%d):", button) + ImGui.Text(" w/ default threshold: %d,", ImGui.IsMouseDragging(button) and 1 or 0) + ImGui.Text(" w/ zero threshold: %d,", ImGui.IsMouseDragging(button, 0.0) and 1 or 0) + ImGui.Text(" w/ large threshold: %d,", ImGui.IsMouseDragging(button, 20.0) and 1 or 0) + end + + ImGui.Button("Drag Me") + if ImGui.IsItemActive() then + ImGui.GetForegroundDrawList():AddLine(io.MouseClickedPos[0], io.MousePos, ImGui.GetColorU32(22 --[[ImGuiCol.Button]]), 4.0) -- Draw a line between the button and the mouse cursor + end + + -- Drag operations gets "unlocked" when the mouse has moved past a certain threshold + -- (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher + -- threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta(). + local value_raw = ImGui.GetMouseDragDelta(0, 0.0) + local value_with_lock_threshold = ImGui.GetMouseDragDelta(0) + local mouse_delta = io.MouseDelta + ImGui.Text("GetMouseDragDelta(0):") + ImGui.Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y) + ImGui.Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y) + ImGui.Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y) ImGui.TreePop() end end +end - ImGui.PopID() +------------------------------------------------------------------------------- +-- [SECTION] About Window / ShowAboutWindow() +-- Access from Dear ImGui Demo -> Tools -> About +------------------------------------------------------------------------------- - DemoWindowColumns() +S.ShowAboutWindow = { + show_config_info = false, +} +function ImGui.ShowAboutWindow(p_open) + local s = S.ShowAboutWindow + local _, visible + p_open, visible = ImGui.Begin("About Dear ImGui", p_open, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Tools/About Dear ImGui") + ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, 19298 --[[IMGUI_VERSION_NUM]]) - if disable_indent then - ImGui.PopStyleVar() + ImGui.TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui") + ImGui.SameLine() + ImGui.TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Extensions", "https://github.com/ocornut/imgui/wiki/Useful-Extensions") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding") + + ImGui.Separator() + ImGui.Text("(c) 2014-2026 Omar Cornut") + ImGui.Text("Developed by Omar Cornut and all Dear ImGui contributors.") + ImGui.Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.") + ImGui.Text("If your company uses this, please consider funding the project.") + + _, s.show_config_info = ImGui.Checkbox("Config/Build Information", s.show_config_info) + if s.show_config_info then + local io = ImGui.GetIO() + local style = ImGui.GetStyle() + + local copy_to_clipboard = ImGui.Button("Copy to clipboard") + local child_size = ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 18) + ImGui.BeginChild(ImGui.GetID("cfg_infos"), child_size, 128 --[[ImGuiChildFlags.FrameStyle]]) + if copy_to_clipboard then + ImGui.LogToClipboard() + ImGui.LogText("// (Copy from the next line. Keep the ``` markers for formatting.)\n") + ImGui.LogText("```cpp\n") -- Back quotes will make text appears without formatting when pasting on GitHub + end + + ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, 19298 --[[IMGUI_VERSION_NUM]]) + ImGui.Separator() + -- [Port] no sizeof()/__cplusplus/compiler/OS #defines in Lua: report the Lua runtime instead + ImGui.Text("runtime: %s", tostring(_VERSION)) + ImGui.Text("define: IMGUI_HAS_VIEWPORT") + ImGui.Text("define: IMGUI_HAS_DOCK") + + -- Heuristic to detect no-op IM_ASSERT() macros + -- - This is designed so people opening bug reports would convey and notice that they have disabled asserts for Dear ImGui code. + -- - 16 is > strlen("((void)(_EXPR))") which we suggested in our imconfig.h template as a possible way to disable. + local assert_runs_expression = 0 + assert((function() assert_runs_expression = assert_runs_expression + 1; return assert_runs_expression end)()) -- [Port] no ++ in expressions + local assert_expand_len = 17 -- [Port] IM_ASSERT is a function, not a macro: nothing to stringify, it cannot be expanded to a no-op + local assert_maybe_disabled = (assert_runs_expression == 0 or assert_expand_len <= 16) + ImGui.Text("IM_ASSERT: runs expression: %s. expand size: %s%s", + (assert_runs_expression ~= 0) and "OK" or "KO", (assert_expand_len > 16) and "OK" or "KO", assert_maybe_disabled and " (MAYBE DISABLED?!)" or "") + if assert_maybe_disabled then + ImGui.SameLine() + HelpMarker("IM_ASSERT() calls assert() by default. Compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes!") + end + + ImGui.Separator() + ImGui.Text("io.BackendPlatformName: %s", io.BackendPlatformName or "NULL") + ImGui.Text("io.BackendRendererName: %s", io.BackendRendererName or "NULL") + ImGui.Text("io.ConfigFlags: 0x%08X", io.ConfigFlags) + if bit32.band(io.ConfigFlags, 1 --[[ImGuiConfigFlags.NavEnableKeyboard]]) ~= 0 then ImGui.Text(" NavEnableKeyboard") end + if bit32.band(io.ConfigFlags, 2 --[[ImGuiConfigFlags.NavEnableGamepad]]) ~= 0 then ImGui.Text(" NavEnableGamepad") end + if bit32.band(io.ConfigFlags, 16 --[[ImGuiConfigFlags.NoMouse]]) ~= 0 then ImGui.Text(" NoMouse") end + if bit32.band(io.ConfigFlags, 32 --[[ImGuiConfigFlags.NoMouseCursorChange]]) ~= 0 then ImGui.Text(" NoMouseCursorChange") end + if bit32.band(io.ConfigFlags, 64 --[[ImGuiConfigFlags.NoKeyboard]]) ~= 0 then ImGui.Text(" NoKeyboard") end + if bit32.band(io.ConfigFlags, 128 --[[ImGuiConfigFlags.DockingEnable]]) ~= 0 then ImGui.Text(" DockingEnable") end + if bit32.band(io.ConfigFlags, 1024 --[[ImGuiConfigFlags.ViewportsEnable]]) ~= 0 then ImGui.Text(" ViewportsEnable") end + if io.MouseDrawCursor then ImGui.Text("io.MouseDrawCursor") end + if io.ConfigDpiScaleFonts then ImGui.Text("io.ConfigDpiScaleFonts") end + if io.ConfigDpiScaleViewports then ImGui.Text("io.ConfigDpiScaleViewports") end + if io.ConfigViewportsNoAutoMerge then ImGui.Text("io.ConfigViewportsNoAutoMerge") end + if io.ConfigViewportsNoTaskBarIcon then ImGui.Text("io.ConfigViewportsNoTaskBarIcon") end + if io.ConfigViewportsNoDecoration then ImGui.Text("io.ConfigViewportsNoDecoration") end + if io.ConfigViewportsNoDefaultParent then ImGui.Text("io.ConfigViewportsNoDefaultParent") end + if io.ConfigDockingNoSplit then ImGui.Text("io.ConfigDockingNoSplit") end + if io.ConfigDockingNoDockingOver then ImGui.Text("io.ConfigDockingNoDockingOver") end + if io.ConfigDockingWithShift then ImGui.Text("io.ConfigDockingWithShift") end + if io.ConfigDockingAlwaysTabBar then ImGui.Text("io.ConfigDockingAlwaysTabBar") end + if io.ConfigDockingTransparentPayload then ImGui.Text("io.ConfigDockingTransparentPayload") end + if io.ConfigMacOSXBehaviors then ImGui.Text("io.ConfigMacOSXBehaviors") end + if io.ConfigNavMoveSetMousePos then ImGui.Text("io.ConfigNavMoveSetMousePos") end + if io.ConfigNavCaptureKeyboard then ImGui.Text("io.ConfigNavCaptureKeyboard") end + if io.ConfigInputTextCursorBlink then ImGui.Text("io.ConfigInputTextCursorBlink") end + if io.ConfigWindowsResizeFromEdges then ImGui.Text("io.ConfigWindowsResizeFromEdges") end + if io.ConfigWindowsMoveFromTitleBarOnly then ImGui.Text("io.ConfigWindowsMoveFromTitleBarOnly") end + if io.ConfigMemoryCompactTimer >= 0.0 then ImGui.Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer) end + ImGui.Text("io.BackendFlags: 0x%08X", io.BackendFlags) + if bit32.band(io.BackendFlags, 1 --[[ImGuiBackendFlags.HasGamepad]]) ~= 0 then ImGui.Text(" HasGamepad") end + if bit32.band(io.BackendFlags, 2 --[[ImGuiBackendFlags.HasMouseCursors]]) ~= 0 then ImGui.Text(" HasMouseCursors") end + if bit32.band(io.BackendFlags, 4 --[[ImGuiBackendFlags.HasSetMousePos]]) ~= 0 then ImGui.Text(" HasSetMousePos") end + if bit32.band(io.BackendFlags, 2048 --[[ImGuiBackendFlags.PlatformHasViewports]]) ~= 0 then ImGui.Text(" PlatformHasViewports") end + if bit32.band(io.BackendFlags, 4096 --[[ImGuiBackendFlags.HasMouseHoveredViewport]]) ~= 0 then ImGui.Text(" HasMouseHoveredViewport") end + if bit32.band(io.BackendFlags, 8192 --[[ImGuiBackendFlags.HasParentViewport]]) ~= 0 then ImGui.Text(" HasParentViewport") end + if bit32.band(io.BackendFlags, 8 --[[ImGuiBackendFlags.RendererHasVtxOffset]]) ~= 0 then ImGui.Text(" RendererHasVtxOffset") end + if bit32.band(io.BackendFlags, 16 --[[ImGuiBackendFlags.RendererHasTextures]]) ~= 0 then ImGui.Text(" RendererHasTextures") end + if bit32.band(io.BackendFlags, 1024 --[[ImGuiBackendFlags.RendererHasViewports]]) ~= 0 then ImGui.Text(" RendererHasViewports") end + ImGui.Separator() + ImGui.Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts.Fonts.Size, io.Fonts.Flags, io.Fonts.TexData.Width, io.Fonts.TexData.Height) + ImGui.Text("io.Fonts->FontLoaderName: %s", io.Fonts.FontLoaderName or "NULL") + ImGui.Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y) + ImGui.Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y) + ImGui.Separator() + ImGui.Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y) + ImGui.Text("style.WindowBorderSize: %.2f", style.WindowBorderSize) + ImGui.Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y) + ImGui.Text("style.FrameRounding: %.2f", style.FrameRounding) + ImGui.Text("style.FrameBorderSize: %.2f", style.FrameBorderSize) + ImGui.Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y) + ImGui.Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y) + + if copy_to_clipboard then + ImGui.LogText("\n```\n") + ImGui.LogFinish() + end + ImGui.EndChild() + end + ImGui.End() + return p_open +end + +------------------------------------------------------------------------------- +-- [SECTION] Style Editor / ShowStyleEditor() +------------------------------------------------------------------------------- +-- - ShowStyleSelector() +-- - ShowStyleEditor() +------------------------------------------------------------------------------- + +-- [Port] C++ copies ImGuiStyle by value (`dst = src`). Copy fields in place so ImVec2/ImVec4 objects of `dst` keep +-- their identity (the live style's vectors may be referenced elsewhere) and are never aliased with `src`. +function ImGuiStyle_Copy(dst, src) + for k, v in pairs(src) do + if k == "Colors" then + local dst_colors = dst.Colors + for i, col in pairs(v) do + if dst_colors[i] then ImVec4_Copy(dst_colors[i], col) else dst_colors[i] = ImVec4(col.x, col.y, col.z, col.w) end + end + elseif type(v) == "table" then -- ImVec2 + if dst[k] then ImVec2_Copy(dst[k], v) else dst[k] = ImVec2(v.x, v.y) end + else + dst[k] = v + end + end + return dst +end + +S.ShowStyleSelector = { + style_idx = -1, +} +-- Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. +function ImGui.ShowStyleSelector(label) + -- FIXME: This is a bit tricky to get right as style are functions, they don't register a name nor the fact that one is active. + -- So we keep track of last active one among our limited selection. + local s = S.ShowStyleSelector + local style_names = { "Dark", "Light", "Classic" } + local ret = false + if ImGui.BeginCombo(label, (s.style_idx >= 0 and s.style_idx < #style_names) and style_names[s.style_idx + 1] or "") then + for n = 0, #style_names - 1 do + if ImGui.Selectable(style_names[n + 1], s.style_idx == n, 64 --[[ImGuiSelectableFlags.SelectOnNav]]) then + s.style_idx = n + ret = true + if s.style_idx == 0 then ImGui.StyleColorsDark() + elseif s.style_idx == 1 then ImGui.StyleColorsLight() + elseif s.style_idx == 2 then ImGui.StyleColorsClassic() + end + elseif s.style_idx == n then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndCombo() + end + return ret +end + +function GetTreeLinesFlagsName(flags) + if flags == 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]] then return "DrawLinesNone" end + if flags == 524288 --[[ImGuiTreeNodeFlags.DrawLinesFull]] then return "DrawLinesFull" end + if flags == 1048576 --[[ImGuiTreeNodeFlags.DrawLinesToNodes]] then return "DrawLinesToNodes" end + return "" +end + +S.ShowStyleEditor = { + ref_saved_style = nil, -- static ImGuiStyle ref_saved_style; (created lazily) + init = true, + output_dest = 0, + output_only_modified = true, + alpha_flags = 0, + filter = nil, -- static ImGuiTextFilter filter; (created lazily) +} +-- We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code. +-- [Port] Lua has no `using namespace`: calls keep the ImGui. prefix +function ImGui.ShowStyleEditor(ref) + local s = S.ShowStyleEditor + local _, changed + IMGUI_DEMO_MARKER("Tools/Style Editor") + -- You can pass in a reference ImGuiStyle structure to compare to, revert to and save to + -- (without a reference style pointer, we will use one compared locally as a reference) + local style = ImGui.GetStyle() + if s.ref_saved_style == nil then s.ref_saved_style = ImGuiStyle() end + + -- Default to using internal storage as reference + if s.init and ref == nil then + ImGuiStyle_Copy(s.ref_saved_style, style) + end + s.init = false + if ref == nil then + ref = s.ref_saved_style + end + + -- The logic behind dynamically changing 'max_border_size' is to not encourage people to increase border size too much: it'll likely reveal lots of subtle rendering artifacts and this isn't a priority right now. + -- Note that _MainScale is currently internal PLEASE DO NOT USE IN YOUR CODE. + local default_border_size = math.floor(style._MainScale) + local max_border_size = ImMax(default_border_size, 2.0) + + ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50) + + do + -- General + ImGui.SeparatorText("General") + if bit32.band(ImGui.GetIO().BackendFlags, 16 --[[ImGuiBackendFlags.RendererHasTextures]]) == 0 then + ImGui.BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!") + ImGui.BulletText("For instructions, see:") + ImGui.SameLine() + ImGui.TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md") + end + + if ImGui.ShowStyleSelector("Colors##Selector") then + ImGuiStyle_Copy(s.ref_saved_style, style) + end + ImGui.ShowFontSelector("Fonts##Selector") + style.FontSizeBase, changed = ImGui.DragFloat("FontSizeBase", style.FontSizeBase, 0.20, 5.0, 100.0, "%.0f") + if changed then + style._NextFrameFontSizeBase = style.FontSizeBase -- FIXME: Temporary hack until we finish remaining work. + end + ImGui.SameLine(0.0, 0.0); ImGui.Text(" (out %.2f)", ImGui.GetFontSize()) + style.FontScaleMain = ImGui.DragFloat("FontScaleMain", style.FontScaleMain, 0.02, 0.5, 4.0) + ImGui.BeginDisabled(ImGui.GetIO().ConfigDpiScaleFonts == true) -- [Port] field is nil in the port's ImGuiIO (nil would mean "disabled") + style.FontScaleDpi = ImGui.DragFloat("FontScaleDpi", style.FontScaleDpi, 0.02, 0.5, 4.0) + ImGui.SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.") + ImGui.EndDisabled() + + -- Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) + style.FrameRounding, changed = ImGui.SliderFloat("FrameRounding", style.FrameRounding, 0.0, 12.0, "%.0f") + if changed then + style.GrabRounding = style.FrameRounding -- Make GrabRounding always the same value as FrameRounding + end + do local pressed, border = ImGui.Checkbox("WindowBorder", style.WindowBorderSize > 0.0); if pressed then if border then style.WindowBorderSize = default_border_size else style.WindowBorderSize = 0.0 end end end + ImGui.SameLine() + do local pressed, border = ImGui.Checkbox("FrameBorder", style.FrameBorderSize > 0.0); if pressed then if border then style.FrameBorderSize = default_border_size else style.FrameBorderSize = 0.0 end end end + ImGui.SameLine() + do local pressed, border = ImGui.Checkbox("PopupBorder", style.PopupBorderSize > 0.0); if pressed then if border then style.PopupBorderSize = default_border_size else style.PopupBorderSize = 0.0 end end end + end + + -- Save/Revert button + if ImGui.Button("Save Ref") then + ImGuiStyle_Copy(ref, ImGuiStyle_Copy(s.ref_saved_style, style)) + end + ImGui.SameLine() + if ImGui.Button("Revert Ref") then + ImGuiStyle_Copy(style, ref) + end + ImGui.SameLine() + HelpMarker( + "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " .. + "Use \"Export\" below to save them somewhere.") + + ImGui.SeparatorText("Details") + if ImGui.BeginTabBar("##tabs", 0 --[[ImGuiTabBarFlags.None]]) then + if ImGui.BeginTabItem("Sizes") then + ImGui.SeparatorText("Main") + ImGui.SliderFloat2("WindowPadding", style.WindowPadding, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("FramePadding", style.FramePadding, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("ItemSpacing", style.ItemSpacing, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("ItemInnerSpacing", style.ItemInnerSpacing, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("TouchExtraPadding", style.TouchExtraPadding, 0.0, 10.0, "%.0f") + style.IndentSpacing = ImGui.SliderFloat("IndentSpacing", style.IndentSpacing, 0.0, 30.0, "%.0f") + style.GrabMinSize = ImGui.SliderFloat("GrabMinSize", style.GrabMinSize, 1.0, 20.0, "%.0f") + + ImGui.SeparatorText("Borders") + style.WindowBorderSize = ImGui.SliderFloat("WindowBorderSize", style.WindowBorderSize, 0.0, max_border_size, "%.0f") + style.ChildBorderSize = ImGui.SliderFloat("ChildBorderSize", style.ChildBorderSize, 0.0, max_border_size, "%.0f") + style.PopupBorderSize = ImGui.SliderFloat("PopupBorderSize", style.PopupBorderSize, 0.0, max_border_size, "%.0f") + style.FrameBorderSize = ImGui.SliderFloat("FrameBorderSize", style.FrameBorderSize, 0.0, max_border_size, "%.0f") + + ImGui.SeparatorText("Rounding") + style.WindowRounding = ImGui.SliderFloat("WindowRounding", style.WindowRounding, 0.0, 12.0, "%.0f") + style.ChildRounding = ImGui.SliderFloat("ChildRounding", style.ChildRounding, 0.0, 12.0, "%.0f") + style.FrameRounding = ImGui.SliderFloat("FrameRounding", style.FrameRounding, 0.0, 12.0, "%.0f") + style.PopupRounding = ImGui.SliderFloat("PopupRounding", style.PopupRounding, 0.0, 12.0, "%.0f") + style.GrabRounding = ImGui.SliderFloat("GrabRounding", style.GrabRounding, 0.0, 12.0, "%.0f") + style.MenuItemRounding = ImGui.SliderFloat("MenuItemRounding", style.MenuItemRounding, 0.0, 12.0, "%.0f") + -- NB: SelectableRounding is intentionally NOT made visible here. We don't want to encourage people using that. + + ImGui.SeparatorText("Scrollbar") + style.ScrollbarSize = ImGui.SliderFloat("ScrollbarSize", style.ScrollbarSize, 1.0, 20.0, "%.0f") + style.ScrollbarRounding = ImGui.SliderFloat("ScrollbarRounding", style.ScrollbarRounding, 0.0, 12.0, "%.0f") + style.ScrollbarPadding = ImGui.SliderFloat("ScrollbarPadding", style.ScrollbarPadding, 0.0, 10.0, "%.0f") + + ImGui.SeparatorText("Tabs") + style.TabBorderSize = ImGui.SliderFloat("TabBorderSize", style.TabBorderSize, 0.0, max_border_size, "%.0f") + style.TabBarBorderSize = ImGui.SliderFloat("TabBarBorderSize", style.TabBarBorderSize, 0.0, max_border_size, "%.0f") + style.TabBarOverlineSize = ImGui.SliderFloat("TabBarOverlineSize", style.TabBarOverlineSize, 0.0, ImMax(3.0, max_border_size), "%.0f") + ImGui.SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.") + style.TabMinWidthBase = ImGui.DragFloat("TabMinWidthBase", style.TabMinWidthBase, 0.5, 1.0, 500.0, "%.0f") + style.TabMinWidthShrink = ImGui.DragFloat("TabMinWidthShrink", style.TabMinWidthShrink, 0.5, 1.0, 500.0, "%0.f") + style.TabCloseButtonMinWidthSelected = ImGui.DragFloat("TabCloseButtonMinWidthSelected", style.TabCloseButtonMinWidthSelected, 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthSelected < 0.0) and "%.0f (Always)" or "%.0f") + style.TabCloseButtonMinWidthUnselected = ImGui.DragFloat("TabCloseButtonMinWidthUnselected", style.TabCloseButtonMinWidthUnselected, 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthUnselected < 0.0) and "%.0f (Always)" or "%.0f") + style.TabRounding = ImGui.SliderFloat("TabRounding", style.TabRounding, 0.0, 12.0, "%.0f") + + ImGui.SeparatorText("Tables") + ImGui.SliderFloat2("CellPadding", style.CellPadding, 0.0, 20.0, "%.0f") + style.TableAngledHeadersAngle = ImGui.SliderAngle("TableAngledHeadersAngle", style.TableAngledHeadersAngle, -50.0, 50.0) + ImGui.SliderFloat2("TableAngledHeadersTextAlign", style.TableAngledHeadersTextAlign, 0.0, 1.0, "%.2f") + + ImGui.SeparatorText("Trees") + local combo_open = ImGui.BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)) + ImGui.SameLine() + HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode.") + if combo_open then + local options = { 262144 --[[ImGuiTreeNodeFlags.DrawLinesNone]], 524288 --[[ImGuiTreeNodeFlags.DrawLinesFull]], 1048576 --[[ImGuiTreeNodeFlags.DrawLinesToNodes]] } + for _, option in ipairs(options) do + if ImGui.Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option) then + style.TreeLinesFlags = option + end + end + ImGui.EndCombo() + end + style.TreeLinesSize = ImGui.SliderFloat("TreeLinesSize", style.TreeLinesSize, 0.0, max_border_size, "%.0f") + style.TreeLinesRounding = ImGui.SliderFloat("TreeLinesRounding", style.TreeLinesRounding, 0.0, 12.0, "%.0f") + + ImGui.SeparatorText("Windows") + ImGui.SliderFloat2("WindowTitleAlign", style.WindowTitleAlign, 0.0, 1.0, "%.2f") + style.WindowBorderHoverPadding = ImGui.SliderFloat("WindowBorderHoverPadding", style.WindowBorderHoverPadding, 1.0, 20.0, "%.0f") + local window_menu_button_position = style.WindowMenuButtonPosition + 1 + window_menu_button_position, changed = ImGui.Combo("WindowMenuButtonPosition", window_menu_button_position, "None\0Left\0Right\0") + if changed then + style.WindowMenuButtonPosition = window_menu_button_position - 1 + end + + ImGui.SeparatorText("Widgets") + style.ColorMarkerSize = ImGui.SliderFloat("ColorMarkerSize", style.ColorMarkerSize, 0.0, 8.0, "%.0f") + style.ColorButtonPosition = ImGui.Combo("ColorButtonPosition", style.ColorButtonPosition, "Left\0Right\0") + ImGui.SliderFloat2("ButtonTextAlign", style.ButtonTextAlign, 0.0, 1.0, "%.2f") + ImGui.SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.") + ImGui.SliderFloat2("SelectableTextAlign", style.SelectableTextAlign, 0.0, 1.0, "%.2f") + ImGui.SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.") + style.SeparatorSize = ImGui.SliderFloat("SeparatorSize", style.SeparatorSize, 0.0, 10.0, "%.0f") + style.SeparatorTextBorderSize = ImGui.SliderFloat("SeparatorTextBorderSize", style.SeparatorTextBorderSize, 0.0, 10.0, "%.0f") + ImGui.SliderFloat2("SeparatorTextAlign", style.SeparatorTextAlign, 0.0, 1.0, "%.2f") + ImGui.SliderFloat2("SeparatorTextPadding", style.SeparatorTextPadding, 0.0, 40.0, "%.0f") + style.LogSliderDeadzone = ImGui.SliderFloat("LogSliderDeadzone", style.LogSliderDeadzone, 0.0, 12.0, "%.0f") + style.ImageRounding = ImGui.SliderFloat("ImageRounding", style.ImageRounding, 0.0, 12.0, "%.0f") + style.ImageBorderSize = ImGui.SliderFloat("ImageBorderSize", style.ImageBorderSize, 0.0, max_border_size, "%.0f") + + ImGui.SeparatorText("Docking") + --SetCursorPosX(GetCursorPosX() + CalcItemWidth() - GetFrameHeight()); + _, style.DockingNodeHasCloseButton = ImGui.Checkbox("DockingNodeHasCloseButton", style.DockingNodeHasCloseButton) + style.DockingSeparatorSize = ImGui.SliderFloat("DockingSeparatorSize", style.DockingSeparatorSize, 0.0, 12.0, "%.0f") + + ImGui.SeparatorText("Tooltips") + for n = 0, 1 do + if ImGui.TreeNodeEx(n == 0 and "HoverFlagsForTooltipMouse" or "HoverFlagsForTooltipNav") then + local p = (n == 0) and "HoverFlagsForTooltipMouse" or "HoverFlagsForTooltipNav" -- [Port] pointer -> field name + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_DelayNone", style[p], 16384 --[[ImGuiHoveredFlags.DelayNone]]) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_DelayShort", style[p], 32768 --[[ImGuiHoveredFlags.DelayShort]]) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_DelayNormal", style[p], 65536 --[[ImGuiHoveredFlags.DelayNormal]]) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_Stationary", style[p], 8192 --[[ImGuiHoveredFlags.Stationary]]) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", style[p], 131072 --[[ImGuiHoveredFlags.NoSharedDelay]]) + ImGui.TreePop() + end + end + + ImGui.SeparatorText("Misc") + ImGui.SliderFloat2("DisplayWindowPadding", style.DisplayWindowPadding, 0.0, 30.0, "%.0f"); ImGui.SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.") + ImGui.SliderFloat2("DisplaySafeAreaPadding", style.DisplaySafeAreaPadding, 0.0, 30.0, "%.0f"); ImGui.SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).") + + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Colors") then + if ImGui.Button("Export") then + if s.output_dest == 0 then + ImGui.LogToClipboard() + else + ImGui.LogToTTY() + end + ImGui.LogText("ImVec4* colors = GetStyle().Colors;" .. "\n") -- [Port] IM_NEWLINE == "\n" + for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do + local col = style.Colors[i] + local name = ImGui.GetStyleColorName(i) + if not s.output_only_modified or col ~= ref.Colors[i] then -- [Port] memcmp -> ImVec4 __eq + ImGui.LogText("colors[ImGuiCol_%s]%s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" .. "\n", + name, string.rep(" ", 23 - #name), col.x, col.y, col.z, col.w) -- [Port] "%*s" -> string.rep + end + end + ImGui.LogFinish() + end + ImGui.SameLine(); ImGui.SetNextItemWidth(ImGui.GetFontSize() * 10); s.output_dest = ImGui.Combo("##output_type", s.output_dest, "To Clipboard\0To TTY\0") + ImGui.SameLine(); _, s.output_only_modified = ImGui.Checkbox("Only Modified Colors", s.output_only_modified) + + -- [Port] RadioButton(label, bool active) overload is RadioButtonEx() in the port + if ImGui.RadioButtonEx("Opaque", s.alpha_flags == 4096 --[[ImGuiColorEditFlags.AlphaOpaque]]) then s.alpha_flags = 4096 --[[ImGuiColorEditFlags.AlphaOpaque]] end ImGui.SameLine() + if ImGui.RadioButtonEx("Alpha", s.alpha_flags == 0 --[[ImGuiColorEditFlags.None]]) then s.alpha_flags = 0 --[[ImGuiColorEditFlags.None]] end ImGui.SameLine() + if ImGui.RadioButtonEx("Both", s.alpha_flags == 16384 --[[ImGuiColorEditFlags.AlphaPreviewHalf]]) then s.alpha_flags = 16384 --[[ImGuiColorEditFlags.AlphaPreviewHalf]] end ImGui.SameLine() + HelpMarker( + "In the color list:\n" .. + "Left-click on color square to open color picker,\n" .. + "Right-click to open edit options menu.") + + if s.filter == nil then s.filter = ImGuiTextFilter() end + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + s.filter:DrawWithHint("##FilterColors", "Filter Colors (incl -excl)") + + ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 10), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]])) + ImGui.BeginChild("##colors", ImVec2(0, 0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 256 --[[ImGuiChildFlags.NavFlattened]]), bit32.bor(16384 --[[ImGuiWindowFlags.AlwaysVerticalScrollbar]], 32768 --[[ImGuiWindowFlags.AlwaysHorizontalScrollbar]])) + ImGui.PushItemWidth(ImGui.GetFontSize() * -12) + for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do repeat + local name = ImGui.GetStyleColorName(i) + if not s.filter:PassFilter(name) then + break -- continue + end + ImGui.PushID(i) + if ImGui.Button("?") then + if ImGui.DebugFlashStyleColor then ImGui.DebugFlashStyleColor(i) end -- [Port] DebugFlashStyleColor() is not in the library yet + end + ImGui.SetItemTooltip("Flash given color to identify places where it is used.") + ImGui.SameLine() + ImGui.ColorEdit4("##color", style.Colors[i], bit32.bor(262144 --[[ImGuiColorEditFlags.AlphaBar]], s.alpha_flags)) + if style.Colors[i] ~= ref.Colors[i] then -- [Port] memcmp -> ImVec4 __eq + -- Tips: in a real user application, you may want to merge and use an icon font into the main font, + -- so instead of "Save"/"Revert" you'd use icons! + -- Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! + ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Save") then ImVec4_Copy(ref.Colors[i], style.Colors[i]) end + ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Revert") then ImVec4_Copy(style.Colors[i], ref.Colors[i]) end + end + ImGui.SameLine(0.0, style.ItemInnerSpacing.x) + ImGui.TextUnformatted(name) + ImGui.PopID() + until true end + ImGui.PopItemWidth() + ImGui.EndChild() + + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Fonts") then + local io = ImGui.GetIO() + local atlas = io.Fonts + ImGui.ShowFontAtlas(atlas) + + -- Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. + -- (we enforce hard clamping manually as by default DragFloat/SliderFloat allows Ctrl+Click text to get out of bounds). + --[[ + SeparatorText("Legacy Scaling"); + const float MIN_SCALE = 0.3f; + const float MAX_SCALE = 2.0f; + HelpMarker( + "Those are old settings provided for convenience.\n" + "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, " + "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" + "Using those settings here will give you poor quality results."); + PushItemWidth(GetFontSize() * 8); + DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything + //static float window_scale = 1.0f; + //if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window + // SetWindowFontScale(window_scale); + PopItemWidth(); + ]] + + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Rendering") then + _, style.AntiAliasedLines = ImGui.Checkbox("Anti-aliased lines", style.AntiAliasedLines) + ImGui.SameLine() + HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.") + ImGui.BeginDisabled(style.AntiAliasedLines == false) + _, style.AntiAliasedLineEnds = ImGui.Checkbox("Anti-aliased line ends", style.AntiAliasedLineEnds) + ImGui.EndDisabled() + + ImGui.BeginDisabled() + _, style.AntiAliasedLinesUseTex = ImGui.Checkbox("Anti-aliased lines use texture", style.AntiAliasedLinesUseTex) + ImGui.SameLine() + HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).") + ImGui.EndDisabled() + + _, style.AntiAliasedFill = ImGui.Checkbox("Anti-aliased fill", style.AntiAliasedFill) + local io = ImGui.GetIO() + _, io.ConfigDebugDrawListDefaultsToStrokeLegacy = ImGui.Checkbox("Debug: DrawList Defaults to _StrokeLegacy", io.ConfigDebugDrawListDefaultsToStrokeLegacy == true) -- [Port] field not declared in the port's ImGuiIO + + ImGui.PushItemWidth(ImGui.GetFontSize() * 8) + -- [Port] the library still stores the older style.CurveTessellationTol (== MaxError * MaxError) instead of style.CurveTessellationMaxError + local curve_tessellation_max_error + curve_tessellation_max_error, changed = ImGui.DragFloat("Curve Tessellation Max Error", math.sqrt(style.CurveTessellationTol), 0.02, 0.10, 10.0, "%.2f") + if curve_tessellation_max_error < 0.10 then + curve_tessellation_max_error = 0.10 + changed = true + end + if changed then style.CurveTessellationTol = curve_tessellation_max_error * curve_tessellation_max_error end -- [Port] only write back on change (sqrt/square round-trip is not exact) + + -- When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. + style.CircleTessellationMaxError = ImGui.DragFloat("Circle Tessellation Max Error", style.CircleTessellationMaxError, 0.005, 0.10, 5.0, "%.2f", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) + local show_samples = ImGui.IsItemActive() + if show_samples then + ImGui.SetNextWindowPos(ImGui.GetCursorScreenPos()) + end + if show_samples and ImGui.BeginTooltip() then + ImGui.TextUnformatted("(R = radius, N = approx number of segments)") + ImGui.Spacing() + local draw_list = ImGui.GetWindowDrawList() + local min_widget_width = ImGui.CalcTextSize("R: MMM\nN: MMM").x + for n = 0, 7 do + local RAD_MIN = 5.0 + local RAD_MAX = 70.0 + local rad = RAD_MIN + (RAD_MAX - RAD_MIN) * n / (8.0 - 1.0) + + ImGui.BeginGroup() + + -- N is not always exact here due to how PathArcTo() function work internally + ImGui.Text("R: %.f\nN: %d", rad, draw_list:_CalcCircleAutoSegmentCount(rad)) + + local canvas_width = ImMax(min_widget_width, rad * 2.0) + local offset_x = math.floor(canvas_width * 0.5) + local offset_y = math.floor(RAD_MAX) + + local p1 = ImGui.GetCursorScreenPos() + draw_list:AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui.GetColorU32(0 --[[ImGuiCol.Text]])) + ImGui.Dummy(ImVec2(canvas_width, RAD_MAX * 2)) + + --[[ + const ImVec2 p2 = GetCursorScreenPos(); + draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, GetColorU32(ImGuiCol_Text)); + Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + ]] + + ImGui.EndGroup() + ImGui.SameLine() + end + ImGui.EndTooltip() + end + ImGui.SameLine() + HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically.") + + style.Alpha = ImGui.DragFloat("Global Alpha", style.Alpha, 0.005, 0.20, 1.0, "%.2f") -- Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. + style.DisabledAlpha = ImGui.DragFloat("Disabled Alpha", style.DisabledAlpha, 0.005, 0.0, 1.0, "%.2f"); ImGui.SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).") + ImGui.PopItemWidth() + + ImGui.EndTabItem() + end + + ImGui.EndTabBar() + end + ImGui.PopItemWidth() +end + +------------------------------------------------------------------------------- +-- [SECTION] User Guide / ShowUserGuide() +------------------------------------------------------------------------------- + +-- We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code. +function ImGui.ShowUserGuide() + local io = ImGui.GetIO() + ImGui.BulletText("Double-click on title bar to collapse window.") + ImGui.BulletText( + "Click and drag on lower corner or border to resize window.\n" .. + "(double-click to auto fit window to its contents)") + ImGui.BulletText("Ctrl+Click on a slider or drag box to input value as text.") + ImGui.BulletText("Tab/Shift+Tab to cycle through keyboard editable fields.") + ImGui.BulletText("Ctrl+Tab/Ctrl+Shift+Tab to focus windows.") + if io.FontAllowUserScaling then + ImGui.BulletText("Ctrl+Mouse Wheel to zoom window contents.") + end + ImGui.BulletText("While inputting text:\n") + ImGui.Indent() + ImGui.BulletText("Ctrl+Left/Right to word jump.") + ImGui.BulletText("Ctrl+A or double-click to select all.") + ImGui.BulletText("Ctrl+X/C/V to use clipboard cut/copy/paste.") + ImGui.BulletText("Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.") + ImGui.BulletText("Escape to revert.") + ImGui.Unindent() + ImGui.BulletText("With Keyboard controls enabled:") + ImGui.Indent() + ImGui.BulletText("Arrow keys or Home/End/PageUp/PageDown to navigate.") + ImGui.BulletText("Space to activate a widget.") + ImGui.BulletText("Return to input text into a widget.") + ImGui.BulletText("Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus.") + ImGui.BulletText("Alt to jump to the menu layer of a window.") + ImGui.BulletText("Menu or Shift+F10 to open a context menu.") + ImGui.Unindent() + ImGui.BulletText("With Gamepad controls enabled:") + ImGui.Indent() + ImGui.BulletText("D-Pad: Navigate / Tweak / Resize (in Windowing mode).") + ImGui.BulletText("%s Face button: Activate / Open / Toggle. Hold: activate with text input.", io.ConfigNavSwapGamepadButtons and "East" or "South") + ImGui.BulletText("%s Face button: Cancel / Close / Exit.", io.ConfigNavSwapGamepadButtons and "South" or "East") + ImGui.BulletText("West Face button: Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows).") + ImGui.BulletText("North Face button: Open Context Menu.") + ImGui.BulletText("L1/R1: Tweak Slower/Faster, Focus Previous/Next (in Windowing Mode).") + ImGui.Unindent() +end + +------------------------------------------------------------------------------- +-- [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +------------------------------------------------------------------------------- +-- - ShowExampleAppMainMenuBar() +-- - ShowExampleMenuFile() +------------------------------------------------------------------------------- + +-- Demonstrate creating a "main" fullscreen menu bar and populating it. +-- Note the difference between BeginMainMenuBar() and BeginMenuBar(): +-- - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags.MenuBar flag!) +-- - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. +function ShowExampleAppMainMenuBar() + if ImGui.BeginMainMenuBar() then + if ImGui.BeginMenu("File") then + IMGUI_DEMO_MARKER("Menu/File") + ShowExampleMenuFile() + ImGui.EndMenu() + end + if ImGui.BeginMenu("Edit") then + IMGUI_DEMO_MARKER("Menu/Edit") + if ImGui.MenuItem("Undo", "Ctrl+Z") then end + if ImGui.MenuItem("Redo", "Ctrl+Y", false, false) then end -- Disabled item + ImGui.Separator() + if ImGui.MenuItem("Cut", "Ctrl+X") then end + if ImGui.MenuItem("Copy", "Ctrl+C") then end + if ImGui.MenuItem("Paste", "Ctrl+V") then end + ImGui.EndMenu() + end + ImGui.EndMainMenuBar() end end -end --[[ imgui_demo_2.lua ]] -do --[[ imgui_demo_apps.lua ]] --- Demo: Example apps (port of imgui_demo.cpp "Example App" sections). Each ShowExampleAppXXX(p_open) returns the new p_open. -local _ -local Buf, BufStr = DemoBuf, DemoBufStr +-- Note that shortcuts are currently provided for display only +-- (future version will add explicit flags to BeginMenu() to request processing shortcuts) +S.ShowExampleMenuFile = { + enabled = true, + f = 0.5, + n = 0, + b = true, +} +function ShowExampleMenuFile() + local s = S.ShowExampleMenuFile + IMGUI_DEMO_MARKER("Examples/Menu") + ImGui.MenuItem("(demo menu)", nil, false, false) + if ImGui.MenuItem("New") then end + if ImGui.MenuItem("Open", "Ctrl+O") then end + if ImGui.BeginMenu("Open Recent") then + ImGui.MenuItem("fish_hat.c") + ImGui.MenuItem("fish_hat.inl") + ImGui.MenuItem("fish_hat.h") + if ImGui.BeginMenu("More..") then + ImGui.MenuItem("Hello") + ImGui.MenuItem("Sailor") + if ImGui.BeginMenu("Recurse..") then + ShowExampleMenuFile() + ImGui.EndMenu() + end + ImGui.EndMenu() + end + ImGui.EndMenu() + end + if ImGui.MenuItem("Save", "Ctrl+S") then end + if ImGui.MenuItem("Save As..") then end -local function BufSet(buf, str) - for i = 1, #str do buf[i] = string.byte(str, i) end - buf[#str + 1] = 0 + ImGui.Separator() + if ImGui.BeginMenu("Options") then + IMGUI_DEMO_MARKER("Examples/Menu/Options") + _, s.enabled = ImGui.MenuItem("Enabled", "", s.enabled) + ImGui.BeginChild("child", ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 5.0), 1 --[[ImGuiChildFlags.Borders]]) + for i = 0, 10 - 1 do + ImGui.Text("Scrolling Text %d", i) + end + ImGui.EndChild() + s.f = ImGui.SliderFloat("Value", s.f, 0.0, 1.0) + s.f = ImGui.InputFloat("Input", s.f, 0.1) + s.n = ImGui.Combo("Combo", s.n, "Yes\0No\0Maybe\0\0") + ImGui.EndMenu() + end + + if ImGui.BeginMenu("Colors") then + IMGUI_DEMO_MARKER("Examples/Menu/Colors") + local sz = ImGui.GetTextLineHeight() + for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do + local name = ImGui.GetStyleColorName(i) + local p = ImGui.GetCursorScreenPos() + ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui.GetColorU32(i)) + ImGui.Dummy(ImVec2(sz, sz)) + ImGui.SameLine() + ImGui.MenuItem(name) + end + ImGui.EndMenu() + end + + -- Here we demonstrate appending again to the "Options" menu (which we already created above) + -- Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. + -- In a real code-base using it would make senses to use this feature from very different code locations. + if ImGui.BeginMenu("Options") then -- <-- Append! + IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu") + _, s.b = ImGui.Checkbox("SomeOption", s.b) + ImGui.EndMenu() + end + + if ImGui.BeginMenu("Disabled", false) then -- Disabled + assert(false) + end + if ImGui.MenuItem("Checked", nil, true) then end + ImGui.Separator() + if ImGui.MenuItem("Quit", "Alt+F4") then end end ------------------------------------------------------------------------------- @@ -25909,245 +29746,383 @@ end -- Demonstrate creating a simple console window, with scrolling, filtering, completion and history. -- For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. -local Console = nil -local function ConsoleNew() - -- HistoryPos: -1: new line, 0..#History-1 browsing history. +ExampleAppConsoleMT = {} +ExampleAppConsoleMT.__index = ExampleAppConsoleMT +function ExampleAppConsole() + local self = setmetatable({}, ExampleAppConsoleMT) + self.InputBuf = nil -- char InputBuf[256] + self.Items = ImVector() -- ImVector + self.Commands = ImVector() -- ImVector + self.History = ImVector() -- ImVector + self.HistoryPos = 0 -- -1: new line, 0..History.Size-1 browsing history. + self.Filter = ImGuiTextFilter() + self.AutoScroll = false + self.ScrollToBottom = false + + self:ClearLog() + self.InputBuf = ImGui.NewTextBuffer("", 256) -- memset(InputBuf, 0, sizeof(InputBuf)) + self.HistoryPos = -1 + -- "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches. - local c = { InputBuf = Buf("", 256), Items = {}, Commands = { "HELP", "HISTORY", "CLEAR", "CLASSIFY" }, History = {}, - HistoryPos = -1, Filter = ImGuiTextFilter(), AutoScroll = true, ScrollToBottom = false } - function c:ClearLog() self.Items = {} end - function c:AddLog(fmt, ...) - -- FIXME-OPT - local s = (select("#", ...) > 0) and string.format(fmt, ...) or fmt - self.Items[#self.Items + 1] = s - end - function c:ExecCommand(command_line) - self:AddLog("# %s\n", command_line) + self.Commands:push_back("HELP") + self.Commands:push_back("HISTORY") + self.Commands:push_back("CLEAR") + self.Commands:push_back("CLASSIFY") + self.AutoScroll = true + self.ScrollToBottom = false + self:AddLog("Welcome to Dear ImGui!") + return self +end +-- [Port] ~ExampleAppConsole(): nothing to free (GC) - -- Insert into history. First find match and delete it so it can be pushed to the back. - -- This isn't trying to be smart or optimal. - self.HistoryPos = -1 - for i = #self.History, 1, -1 do - if string.upper(self.History[i]) == string.upper(command_line) then table.remove(self.History, i); break end - end - self.History[#self.History + 1] = command_line +-- Portable helpers +do + local function toupper(c) if c >= 97 and c <= 122 then return c - 32 end return c end -- [Port] C toupper() on bytes + function ExampleAppConsoleMT.Stricmp(s1, s2) local i = 1; local d; while true do local c1 = string.byte(s1, i) or 0; d = toupper(string.byte(s2, i) or 0) - toupper(c1); if d ~= 0 or c1 == 0 then break end; i = i + 1 end; return d end + function ExampleAppConsoleMT.Strnicmp(s1, s2, n) local i = 1; local d = 0; while n > 0 do local c1 = string.byte(s1, i) or 0; d = toupper(string.byte(s2, i) or 0) - toupper(c1); if d ~= 0 or c1 == 0 then break end; i = i + 1; n = n - 1 end; return d end + function ExampleAppConsoleMT.Strdup(s) assert(s); return s end -- [Port] Lua strings are immutable values + function ExampleAppConsoleMT.Strtrimblanks(s) local str_end = 0; while s[str_end + 1] ~= nil and s[str_end + 1] ~= 0 do str_end = str_end + 1 end; while str_end > 0 and s[str_end] == 32 do str_end = str_end - 1 end; s[str_end + 1] = 0 end + ExampleAppConsoleMT.toupper = toupper -- [Port] used by TextEditCallback() +end - -- Process command - local cmd = string.upper(command_line) - if cmd == "CLEAR" then - self:ClearLog() - elseif cmd == "HELP" then - self:AddLog("Commands:") - for i = 1, #self.Commands do self:AddLog("- %s", self.Commands[i]) end - elseif cmd == "HISTORY" then - local first = #self.History - 10 - for i = math.max(first, 0), #self.History - 1 do self:AddLog("%3d: %s\n", i, self.History[i + 1]) end - else - self:AddLog("Unknown command: '%s'\n", command_line) - end +function ExampleAppConsoleMT:ClearLog() + -- [Port] ImGui::MemFree(Items[i]) not needed (GC) + self.Items:clear() +end - -- On command input, we scroll to bottom even if AutoScroll==false - self.ScrollToBottom = true - end - function c:TextEditCallback(data) - --self:AddLog("cursor: %d, selection: %d-%d", data.CursorPos, data.SelectionStart, data.SelectionEnd) - if data.EventFlag == 262144 --[[ImGuiInputTextFlags.CallbackCompletion]] then - -- Example of TEXT COMPLETION +function ExampleAppConsoleMT:AddLog(fmt, ...) + -- FIXME-OPT + local buf = string.format(fmt, ...) + buf = string.sub(buf, 1, 1024 - 1) -- [Port] vsnprintf() into char buf[1024] + self.Items:push_back(ExampleAppConsoleMT.Strdup(buf)) +end - -- Locate beginning of current word (positions are 0-based offsets into data.Buf) - local word_end = data.CursorPos - local word_start = word_end - while word_start > 0 do - local ch = data.Buf[word_start] - if ch == 32 or ch == 9 or ch == 44 or ch == 59 then break end - word_start = word_start - 1 - end - local word = "" - for i = word_start + 1, word_end do word = word .. string.char(data.Buf[i]) end - - -- Build a list of candidates - local candidates = {} - for i = 1, #self.Commands do - if string.upper(string.sub(self.Commands[i], 1, #word)) == string.upper(word) then candidates[#candidates + 1] = self.Commands[i] end - end - if #candidates == 0 then - -- No match - self:AddLog("No match for \"%s\"!\n", word) - elseif #candidates == 1 then - -- Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. - data:DeleteChars(word_start, word_end - word_start) - data:InsertChars(data.CursorPos, candidates[1]) - data:InsertChars(data.CursorPos, " ") - else - -- Multiple matches. Complete as much as we can.. - -- So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. - local match_len = word_end - word_start - while true do - local ch, all_match = nil, true - for i = 1, #candidates do - local cc = string.upper(string.sub(candidates[i], match_len + 1, match_len + 1)) - if i == 1 then ch = cc elseif ch == "" or ch ~= cc then all_match = false; break end - end - if not all_match or ch == "" then break end - match_len = match_len + 1 - end - if match_len > 0 then - data:DeleteChars(word_start, word_end - word_start) - data:InsertChars(data.CursorPos, string.sub(candidates[1], 1, match_len)) - end - - -- List matches - self:AddLog("Possible matches:\n") - for i = 1, #candidates do self:AddLog("- %s\n", candidates[i]) end - end - elseif data.EventFlag == 524288 --[[ImGuiInputTextFlags.CallbackHistory]] then - -- Example of HISTORY - local prev_history_pos = self.HistoryPos - if data.EventKey == 515 --[[ImGuiKey.UpArrow]] then - if self.HistoryPos == -1 then self.HistoryPos = #self.History - 1 - elseif self.HistoryPos > 0 then self.HistoryPos = self.HistoryPos - 1 end - elseif data.EventKey == 516 --[[ImGuiKey.DownArrow]] then - if self.HistoryPos ~= -1 then - self.HistoryPos = self.HistoryPos + 1 - if self.HistoryPos >= #self.History then self.HistoryPos = -1 end - end - end - - -- A better implementation would preserve the data on the current input line along with cursor position. - if prev_history_pos ~= self.HistoryPos then - local history_str = (self.HistoryPos >= 0) and self.History[self.HistoryPos + 1] or "" - data:DeleteChars(0, data.BufTextLen) - data:InsertChars(0, history_str) - end - end - return 0 - end - function c:Draw(title, p_open) - ImGui.SetNextWindowSize(ImVec2(520, 600), 4 --[[ImGuiCond.FirstUseEver]]) - local visible - p_open, visible = ImGui.Begin(title, p_open) - if not visible then ImGui.End(); return p_open end - - -- As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. - -- So e.g. IsItemHovered() will return true when hovering the title bar. - -- Here we create a context menu only available from the title bar. - if ImGui.BeginPopupContextItem() then - if ImGui.MenuItem("Close Console") then p_open = false end - ImGui.EndPopup() - end - ImGui.TextWrapped("This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc.") - ImGui.TextWrapped("Enter 'HELP' for help.") - - -- TODO: display items starting from the bottom - - if ImGui.SmallButton("Add Debug Text") then self:AddLog("%d some text", #self.Items); self:AddLog("some more text"); self:AddLog("display very important message here!") end - ImGui.SameLine() - if ImGui.SmallButton("Add Debug Error") then self:AddLog("[error] something went wrong") end - ImGui.SameLine() - if ImGui.SmallButton("Clear") then self:ClearLog() end - ImGui.SameLine() - local copy_to_clipboard = ImGui.SmallButton("Copy") - --local t = 0.0; if ImGui.GetTime() - t > 0.02 then t = ImGui.GetTime(); self:AddLog("Spam %f", t) end - - ImGui.Separator() - - -- Options menu - if ImGui.BeginPopup("Options") then - _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) - ImGui.EndPopup() - end - - -- Options, Filter - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 560 --[[ImGuiKey.O]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - if ImGui.Button("Options") then ImGui.OpenPopup("Options") end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 551 --[[ImGuiKey.F]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") - ImGui.Separator() - - -- Reserve enough left-over height for 1 separator + 1 input text - local style = ImGui.GetStyle() - local footer_height_to_reserve = (style.SeparatorSize or 1.0) + style.ItemSpacing.y + ImGui.GetFrameHeightWithSpacing() - if ImGui.BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), 256 --[[ImGuiChildFlags.NavFlattened]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) then - if ImGui.BeginPopupContextWindow() then - if ImGui.Selectable("Clear") then self:ClearLog() end - ImGui.EndPopup() - end - - -- Display every line as a separate entry so we can change their color or add custom widgets. - -- If you only want raw text you can use ImGui.TextUnformatted(log.begin(), log.end()) - -- NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping - -- to only process visible items. The clipper will automatically measure the height of your first item and then - -- "seek" to display only items in the visible area. - -- To use the clipper we can replace your standard loop: - -- for i = 1, #Items do - -- With: - -- local clipper = ImGuiListClipper() - -- clipper:Begin(#Items) - -- while clipper:Step() do - -- for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do - -- - That your items are evenly spaced (same height) - -- - That you have cheap random access to your elements (you can access them given their index, - -- without processing all the ones before) - -- You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. - -- We would need random-access on the post-filtered list. - -- A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices - -- or offsets of items that passed the filtering test, recomputing this array when user changes the filter, - -- and appending newly elements as they are inserted. This is left as a task to the user until we can manage - -- to improve this example code! - -- If your items are of variable height: - -- - Split them into same height items would be simpler and facilitate random-seeking into your list. - -- - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. - ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(4, 1)) -- Tighten spacing - if copy_to_clipboard then ImGui.LogToClipboard() end - for _, item in ipairs(self.Items) do - if self.Filter:PassFilter(item) then - -- Normally you would store more information in your item than just a string. - -- (e.g. make Items[] an array of structure, store color/type etc.) - local color - if string.find(item, "[error]", 1, true) then color = ImVec4(1.0, 0.4, 0.4, 1.0) - elseif string.sub(item, 1, 2) == "# " then color = ImVec4(1.0, 0.8, 0.6, 1.0) end - if color then ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], color) end - ImGui.TextUnformatted(item) - if color then ImGui.PopStyleColor() end - end - end - if copy_to_clipboard then ImGui.LogFinish() end - - -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. - -- Using a scrollbar or mouse-wheel will take away from the bottom edge. - if self.ScrollToBottom or (self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY()) then ImGui.SetScrollHereY(1.0) end - self.ScrollToBottom = false - ImGui.PopStyleVar() - end - ImGui.EndChild() - ImGui.Separator() - - -- Command-line - local reclaim_focus = false - local IT = ImGuiInputTextFlags - local input_text_flags = bit32.bor(IT.EnterReturnsTrue, IT.EscapeClearsAll, IT.CallbackCompletion, IT.CallbackHistory) - if ImGui.InputText("Input", self.InputBuf, 256, input_text_flags, function(data) return self:TextEditCallback(data) end) then - local s = string.gsub(BufStr(self.InputBuf), " +$", "") - if s ~= "" then self:ExecCommand(s) end - self.InputBuf[1] = 0 - reclaim_focus = true - end - - -- Auto-focus on window apparition - ImGui.SetItemDefaultFocus() - if reclaim_focus then ImGui.SetKeyboardFocusHere(-1) end -- Auto focus previous widget +function ExampleAppConsoleMT:Draw(title, p_open) + ImGui.SetNextWindowSize(ImVec2(520, 600), 4 --[[ImGuiCond.FirstUseEver]]) + local visible + p_open, visible = ImGui.Begin(title, p_open) + if not visible then ImGui.End() return p_open end - c:AddLog("Welcome to Dear ImGui!") - return c + IMGUI_DEMO_MARKER("Examples/Console") + + -- As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. + -- So e.g. IsItemHovered() will return true when hovering the title bar. + -- Here we create a context menu only available from the title bar. + if ImGui.BeginPopupContextItem() then + if ImGui.MenuItem("Close Console") then + p_open = false + end + ImGui.EndPopup() + end + + ImGui.TextWrapped( + "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " .. + "implementation may want to store entries along with extra data such as timestamp, emitter, etc.") + ImGui.TextWrapped("Enter 'HELP' for help.") + + -- TODO: display items starting from the bottom + + if ImGui.SmallButton("Add Debug Text") then self:AddLog("%d some text", self.Items.Size); self:AddLog("some more text"); self:AddLog("display very important message here!") end + ImGui.SameLine() + if ImGui.SmallButton("Add Debug Error") then self:AddLog("[error] something went wrong") end + ImGui.SameLine() + if ImGui.SmallButton("Clear") then self:ClearLog() end + ImGui.SameLine() + local copy_to_clipboard = ImGui.SmallButton("Copy") + --static float t = 0.0f; if (ImGui.GetTime() - t > 0.02f) { t = ImGui.GetTime(); AddLog("Spam %f", t); } + + ImGui.Separator() + + -- Options menu + if ImGui.BeginPopup("Options") then + _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) + ImGui.EndPopup() + end + + -- Options, Filter + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 560 --[[ImGuiKey.O]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + if ImGui.Button("Options") then + ImGui.OpenPopup("Options") + end + ImGui.SameLine() + + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 551 --[[ImGuiKey.F]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") + ImGui.Separator() + + -- Reserve enough left-over height for 1 separator + 1 input text + local style = ImGui.GetStyle() + local footer_height_to_reserve = style.SeparatorSize + style.ItemSpacing.y + ImGui.GetFrameHeightWithSpacing() + if ImGui.BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), 256 --[[ImGuiChildFlags.NavFlattened]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) then + if ImGui.BeginPopupContextWindow() then + if ImGui.Selectable("Clear") then self:ClearLog() end + ImGui.EndPopup() + end + + -- Display every line as a separate entry so we can change their color or add custom widgets. + -- If you only want raw text you can use ImGui.TextUnformatted(log.begin(), log.end()); + -- NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping + -- to only process visible items. The clipper will automatically measure the height of your first item and then + -- "seek" to display only items in the visible area. + -- To use the clipper we can replace your standard loop: + -- for (int i = 0; i < Items.Size; i++) + -- With: + -- ImGuiListClipper clipper; + -- clipper.Begin(Items.Size); + -- while (clipper.Step()) + -- for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + -- - That your items are evenly spaced (same height) + -- - That you have cheap random access to your elements (you can access them given their index, + -- without processing all the ones before) + -- You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. + -- We would need random-access on the post-filtered list. + -- A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices + -- or offsets of items that passed the filtering test, recomputing this array when user changes the filter, + -- and appending newly elements as they are inserted. This is left as a task to the user until we can manage + -- to improve this example code! + -- If your items are of variable height: + -- - Split them into same height items would be simpler and facilitate random-seeking into your list. + -- - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. + ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(4, 1)) -- Tighten spacing + if copy_to_clipboard then + ImGui.LogToClipboard() + end + for _, item in self.Items:iter() do repeat + if not self.Filter:PassFilter(item) then + break -- continue + end + + -- Normally you would store more information in your item than just a string. + -- (e.g. make Items[] an array of structure, store color/type etc.) + local color + local has_color = false + if string.find(item, "[error]", 1, true) then color = ImVec4(1.0, 0.4, 0.4, 1.0); has_color = true + elseif string.sub(item, 1, 2) == "# " then color = ImVec4(1.0, 0.8, 0.6, 1.0); has_color = true end + if has_color then + ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], color) + end + ImGui.TextUnformatted(item) + if has_color then + ImGui.PopStyleColor() + end + until true end + if copy_to_clipboard then + ImGui.LogFinish() + end + + -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. + -- Using a scrollbar or mouse-wheel will take away from the bottom edge. + if self.ScrollToBottom or (self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY()) then + ImGui.SetScrollHereY(1.0) + end + self.ScrollToBottom = false + + ImGui.PopStyleVar() + end + ImGui.EndChild() + ImGui.Separator() + + -- Command-line + local reclaim_focus = false + local input_text_flags = bit32.bor(64 --[[ImGuiInputTextFlags.EnterReturnsTrue]], 128 --[[ImGuiInputTextFlags.EscapeClearsAll]], 262144 --[[ImGuiInputTextFlags.CallbackCompletion]], 524288 --[[ImGuiInputTextFlags.CallbackHistory]]) + if ImGui.InputText("Input", self.InputBuf, 256, input_text_flags, ExampleAppConsoleMT.TextEditCallbackStub, self) then + local s = self.InputBuf + ExampleAppConsoleMT.Strtrimblanks(s) + if s[1] ~= 0 then + self:ExecCommand(ImGui.TextBufferToString(s)) + end + s[1] = 0 + reclaim_focus = true + end + + -- Auto-focus on window apparition + ImGui.SetItemDefaultFocus() + if reclaim_focus then + ImGui.SetKeyboardFocusHere(-1) -- Auto focus previous widget + end + + ImGui.End() + return p_open end +function ExampleAppConsoleMT:ExecCommand(command_line) + local Stricmp = ExampleAppConsoleMT.Stricmp + self:AddLog("# %s\n", command_line) + + -- Insert into history. First find match and delete it so it can be pushed to the back. + -- This isn't trying to be smart or optimal. + self.HistoryPos = -1 + for i = self.History.Size - 1, 0, -1 do + if Stricmp(self.History.Data[i + 1], command_line) == 0 then + self.History:erase(i + 1) + break + end + end + self.History:push_back(ExampleAppConsoleMT.Strdup(command_line)) + + -- Process command + if Stricmp(command_line, "CLEAR") == 0 then + self:ClearLog() + elseif Stricmp(command_line, "HELP") == 0 then + self:AddLog("Commands:") + for i = 0, self.Commands.Size - 1 do + self:AddLog("- %s", self.Commands.Data[i + 1]) + end + elseif Stricmp(command_line, "HISTORY") == 0 then + local first = self.History.Size - 10 + for i = (first > 0) and first or 0, self.History.Size - 1 do + self:AddLog("%3d: %s\n", i, self.History.Data[i + 1]) + end + else + self:AddLog("Unknown command: '%s'\n", command_line) + end + + -- On command input, we scroll to bottom even if AutoScroll==false + self.ScrollToBottom = true +end + +-- In C++11 you'd be better off using lambdas for this sort of forwarding callbacks +function ExampleAppConsoleMT.TextEditCallbackStub(data) + local console = data.UserData + return console:TextEditCallback(data) +end + +-- [Port] data.Buf is a 1-based byte table; positions (CursorPos, word_start, word_end) are 0-based offsets like upstream. +function ExampleAppConsoleMT:TextEditCallback(data) + local toupper = ExampleAppConsoleMT.toupper + --AddLog("cursor: %d, selection: %d-%d", data.CursorPos, data.SelectionStart, data.SelectionEnd) + if data.EventFlag == 262144 --[[ImGuiInputTextFlags.CallbackCompletion]] then + -- Example of TEXT COMPLETION + + -- Locate beginning of current word + local word_end = data.CursorPos + local word_start = word_end + while word_start > 0 do + local c = data.Buf[word_start] -- word_start[-1] + if c == 32 or c == 9 or c == 44 or c == 59 then -- ' ', '\t', ',', ';' + break + end + word_start = word_start - 1 + end + local word = string.char(table.unpack(data.Buf, word_start + 1, word_end)) -- [Port] word_start..word_end as a string + + -- Build a list of candidates + local candidates = ImVector() + for i = 0, self.Commands.Size - 1 do + if ExampleAppConsoleMT.Strnicmp(self.Commands.Data[i + 1], word, word_end - word_start) == 0 then + candidates:push_back(self.Commands.Data[i + 1]) + end + end + + if candidates.Size == 0 then + -- No match + self:AddLog("No match for \"%s\"!\n", word) -- [Port] "%.*s" -> "%s" + elseif candidates.Size == 1 then + -- Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. + data:DeleteChars(word_start, word_end - word_start) + data:InsertChars(data.CursorPos, candidates.Data[1]) + data:InsertChars(data.CursorPos, " ") + else + -- Multiple matches. Complete as much as we can.. + -- So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. + local match_len = word_end - word_start + while true do + local c = 0 + local all_candidates_matches = true + local i = 0 + while i < candidates.Size and all_candidates_matches do + if i == 0 then + c = toupper(string.byte(candidates.Data[i + 1], match_len + 1) or 0) + elseif c == 0 or c ~= toupper(string.byte(candidates.Data[i + 1], match_len + 1) or 0) then + all_candidates_matches = false + end + i = i + 1 + end + if not all_candidates_matches then + break + end + match_len = match_len + 1 + end + + if match_len > 0 then + data:DeleteChars(word_start, word_end - word_start) + data:InsertChars(data.CursorPos, string.sub(candidates.Data[1], 1, match_len)) -- [Port] InsertChars() has no text_end parameter + end + + -- List matches + self:AddLog("Possible matches:\n") + for i = 0, candidates.Size - 1 do + self:AddLog("- %s\n", candidates.Data[i + 1]) + end + end + + elseif data.EventFlag == 524288 --[[ImGuiInputTextFlags.CallbackHistory]] then + -- Example of HISTORY + local prev_history_pos = self.HistoryPos + if data.EventKey == 515 --[[ImGuiKey.UpArrow]] then + if self.HistoryPos == -1 then + self.HistoryPos = self.History.Size - 1 + elseif self.HistoryPos > 0 then + self.HistoryPos = self.HistoryPos - 1 + end + elseif data.EventKey == 516 --[[ImGuiKey.DownArrow]] then + if self.HistoryPos ~= -1 then + self.HistoryPos = self.HistoryPos + 1 + if self.HistoryPos >= self.History.Size then + self.HistoryPos = -1 + end + end + end + + -- A better implementation would preserve the data on the current input line along with cursor position. + if prev_history_pos ~= self.HistoryPos then + local history_str = "" + if self.HistoryPos >= 0 then history_str = self.History.Data[self.HistoryPos + 1] end + data:DeleteChars(0, data.BufTextLen) + data:InsertChars(0, history_str) + end + end + return 0 +end + +S.ShowExampleAppConsole = { + console = nil, -- ExampleAppConsole, created on first use +} function ShowExampleAppConsole(p_open) - Console = Console or ConsoleNew() - return Console:Draw("Example: Console", p_open) + local s = S.ShowExampleAppConsole + if s.console == nil then s.console = ExampleAppConsole() end + return s.console:Draw("Example: Console", p_open) +end + +------------------------------------------------------------------------------- +-- [SECTION] Example App: Image Viewer / ShowExampleAppImageViewer() +------------------------------------------------------------------------------- + +S.ShowExampleAppImageViewer = { + image_viewer = nil, -- ExampleImageViewerData, created on first use +} +function ShowExampleAppImageViewer(p_open) + local s = S.ShowExampleAppImageViewer + local atlas = ImGui.GetIO().Fonts + local tex_ref = atlas.TexRef -- We don't have access to other textures in this demo! + local tex_w = atlas.TexData.Width + local tex_h = atlas.TexData.Height + local visible + p_open, visible = ImGui.Begin("Example: Image Viewer", p_open) + if visible then + if s.image_viewer == nil then s.image_viewer = ExampleImageViewerData() end + ExampleImageViewer_DrawOptions(s.image_viewer) + local canvas_size = ImGui.GetContentRegionAvail() + local canvas_min_size + if ImGui.IsWindowAppearing() then canvas_min_size = ImVec2(3.0 * tex_w, 4.0 * tex_h) else canvas_min_size = ImVec2(1.0, 1.0) end + canvas_size = ImVec2(ImMax(canvas_size.x, canvas_min_size.x), ImMax(canvas_size.y, canvas_min_size.y)) + ExampleImageViewer_DrawCanvas(s.image_viewer, canvas_size, tex_ref, tex_w, tex_h) + end + ImGui.End() + return p_open end ------------------------------------------------------------------------------- @@ -26155,115 +30130,166 @@ end ------------------------------------------------------------------------------- -- Usage: --- local my_log = ExampleAppLog() --- my_log:AddLog("Hello %d world\n", 123) --- my_log:Draw("title") --- Lines are stored as a Lua array (equivalent of Buf + LineOffsets) -local function ExampleAppLog() - local l = { Lines = { "" }, Filter = ImGuiTextFilter(), AutoScroll = true } -- AutoScroll: Keep scrolling if already at the bottom. - function l:Clear() self.Lines = { "" } end - function l:AddLog(fmt, ...) - local s = (select("#", ...) > 0) and string.format(fmt, ...) or fmt - local lines = self.Lines - for part, nl in string.gmatch(s, "([^\n]*)(\n?)") do - lines[#lines] = lines[#lines] .. part - if nl ~= "" then lines[#lines + 1] = "" end - if part == "" and nl == "" then break end +-- static ExampleAppLog my_log; +-- my_log.AddLog("Hello %d world\n", 123); +-- my_log.Draw("title"); +ExampleAppLogMT = {} +ExampleAppLogMT.__index = ExampleAppLogMT +function ExampleAppLog() + local self = setmetatable({}, ExampleAppLogMT) + self.Buf = ImGuiTextBuffer() + self.Filter = ImGuiTextFilter() + self.LineOffsets = ImVector() -- Index to lines offset. We maintain this with AddLog() calls. + self.AutoScroll = false -- Keep scrolling if already at the bottom. + + self.AutoScroll = true + self:Clear() + return self +end + +function ExampleAppLogMT:Clear() + self.Buf:clear() + self.LineOffsets:clear() + self.LineOffsets:push_back(0) +end + +function ExampleAppLogMT:AddLog(fmt, ...) + local old_size = self.Buf:size() + self.Buf:appendf(fmt, ...) + local buf = self.Buf:c_str() -- [Port] Buf[] byte access + local new_size = #buf + while old_size < new_size do + if string.byte(buf, old_size + 1) == 10 then -- '\n' + self.LineOffsets:push_back(old_size + 1) end + old_size = old_size + 1 end - function l:Draw(title, p_open) - local visible - p_open, visible = ImGui.Begin(title, p_open) - if not visible then ImGui.End(); return p_open end +end - -- Options menu - if ImGui.BeginPopup("Options") then - _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) - ImGui.EndPopup() - end - - -- Main window - if ImGui.Button("Options") then ImGui.OpenPopup("Options") end - ImGui.SameLine() - local clear = ImGui.Button("Clear") - ImGui.SameLine() - local copy = ImGui.Button("Copy") - ImGui.SameLine() - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") - ImGui.Separator() - if ImGui.BeginChild("scrolling", ImVec2(0, 0), 0 --[[ImGuiChildFlags.None]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) then - if clear then self:Clear() end - if copy then ImGui.LogToClipboard() end - ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(0, 0)) - local lines = self.Lines - if self.Filter:IsActive() then - -- In this example we don't use the clipper when Filter is enabled. - -- This is because we don't have random access to the result of our filter. - -- A real application processing logs with ten of thousands of entries may want to store the result of - -- search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). - for line_no = 1, #lines do - if self.Filter:PassFilter(lines[line_no]) then ImGui.TextUnformatted(lines[line_no]) end - end - else - -- The simplest and easy way to display the entire buffer: - -- ImGui.TextUnformatted(buf_begin, buf_end) - -- And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward - -- to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are - -- within the visible area. - -- If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them - -- on your side is recommended. Using ImGuiListClipper requires - -- - A) random access into your data - -- - B) items all being the same height, - -- both of which we can handle since we have an array pointing to the beginning of each line of text. - -- When using the filter (in the block of code above) we don't have random access into the data to display - -- anymore, which is why we don't use the clipper. Storing or skimming through the search result would make - -- it possible (and would be recommended if you want to search through tens of thousands of entries). - local clipper = ImGuiListClipper() - clipper:Begin(#lines) - while clipper:Step() do - for line_no = clipper.DisplayStart, clipper.DisplayEnd - 1 do ImGui.TextUnformatted(lines[line_no + 1]) end - end - clipper:End() - end - ImGui.PopStyleVar() - if copy then ImGui.LogFinish() end - - -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. - -- Using a scrollbar or mouse-wheel will take away from the bottom edge. - if self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY() then ImGui.SetScrollHereY(1.0) end - end - ImGui.EndChild() +-- [Port] line offsets are 0-based like upstream; a line is string.sub(buf, line_start + 1, line_end) (TextUnformatted()/PassFilter() have no text_begin) +function ExampleAppLogMT:Draw(title, p_open) + local visible + p_open, visible = ImGui.Begin(title, p_open) + if not visible then ImGui.End() return p_open end - return l + + -- Options menu + if ImGui.BeginPopup("Options") then + _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) + ImGui.EndPopup() + end + + -- Main window + if ImGui.Button("Options") then + ImGui.OpenPopup("Options") + end + ImGui.SameLine() + local clear = ImGui.Button("Clear") + ImGui.SameLine() + local copy = ImGui.Button("Copy") + ImGui.SameLine() + ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) + self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") + + ImGui.Separator() + + if ImGui.BeginChild("scrolling", ImVec2(0, 0), 0 --[[ImGuiChildFlags.None]], 2048 --[[ImGuiWindowFlags.HorizontalScrollbar]]) then + if clear then + self:Clear() + end + if copy then + ImGui.LogToClipboard() + end + + ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(0, 0)) + local buf = self.Buf:c_str() + local buf_end = #buf + local LineOffsets = self.LineOffsets + if self.Filter:IsActive() then + -- In this example we don't use the clipper when Filter is enabled. + -- This is because we don't have random access to the result of our filter. + -- A real application processing logs with ten of thousands of entries may want to store the result of + -- search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). + for line_no = 0, LineOffsets.Size - 1 do + local line_start = LineOffsets.Data[line_no + 1] + local line_end + if line_no + 1 < LineOffsets.Size then line_end = LineOffsets.Data[line_no + 2] - 1 else line_end = buf_end end + local line = string.sub(buf, line_start + 1, line_end) + if self.Filter:PassFilter(line) then + ImGui.TextUnformatted(line) + end + end + else + -- The simplest and easy way to display the entire buffer: + -- ImGui.TextUnformatted(buf_begin, buf_end); + -- And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward + -- to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are + -- within the visible area. + -- If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them + -- on your side is recommended. Using ImGuiListClipper requires + -- - A) random access into your data + -- - B) items all being the same height, + -- both of which we can handle since we have an array pointing to the beginning of each line of text. + -- When using the filter (in the block of code above) we don't have random access into the data to display + -- anymore, which is why we don't use the clipper. Storing or skimming through the search result would make + -- it possible (and would be recommended if you want to search through tens of thousands of entries). + local clipper = ImGuiListClipper() + clipper:Begin(LineOffsets.Size) + while clipper:Step() do + for line_no = clipper.DisplayStart, clipper.DisplayEnd - 1 do + local line_start = LineOffsets.Data[line_no + 1] + local line_end + if line_no + 1 < LineOffsets.Size then line_end = LineOffsets.Data[line_no + 2] - 1 else line_end = buf_end end + ImGui.TextUnformatted(string.sub(buf, line_start + 1, line_end)) + end + end + clipper:End() + end + ImGui.PopStyleVar() + + -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. + -- Using a scrollbar or mouse-wheel will take away from the bottom edge. + if self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY() then + ImGui.SetScrollHereY(1.0) + end + end + ImGui.EndChild() + ImGui.End() + return p_open end -- Demonstrate creating a simple log window with basic filtering. -local AppLog, AppLogCounter = nil, 0 +S.ShowExampleAppLog = { + log = nil, -- ExampleAppLog, created on first use + counter = 0, +} function ShowExampleAppLog(p_open) - AppLog = AppLog or ExampleAppLog() + local s = S.ShowExampleAppLog + if s.log == nil then s.log = ExampleAppLog() end -- For the demo: add a debug button _BEFORE_ the normal log window contents -- We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. - -- Most of the contents of the window will be added by the log:Draw() call. + -- Most of the contents of the window will be added by the log.Draw() call. ImGui.SetNextWindowSize(ImVec2(500, 400), 4 --[[ImGuiCond.FirstUseEver]]) p_open = ImGui.Begin("Example: Log", p_open) + IMGUI_DEMO_MARKER("Examples/Log") if ImGui.SmallButton("[Debug] Add 5 entries") then local categories = { "info", "warn", "error" } local words = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" } - for _ = 1, 5 do - local category = categories[AppLogCounter % #categories + 1] - local word = words[AppLogCounter % #words + 1] - AppLog:AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", ImGui.GetFrameCount(), category, ImGui.GetTime(), word) - AppLogCounter = AppLogCounter + 1 + for n = 0, 5 - 1 do + local category = categories[s.counter % #categories + 1] + local word = words[s.counter % #words + 1] + s.log:AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", + ImGui.GetFrameCount(), category, ImGui.GetTime(), word) + s.counter = s.counter + 1 end end ImGui.End() -- Actually call in the regular Log helper (which will Begin() into the same window as we just did) - return AppLog:Draw("Example: Log", p_open) + return s.log:Draw("Example: Log", p_open) end ------------------------------------------------------------------------------- @@ -26271,12 +30297,16 @@ end ------------------------------------------------------------------------------- -- Demonstrate create a window with multiple child windows. -local LayoutSelected = 0 +S.ShowExampleAppLayout = { + selected = 0, +} function ShowExampleAppLayout(p_open) + local s = S.ShowExampleAppLayout ImGui.SetNextWindowSize(ImVec2(500, 440), 4 --[[ImGuiCond.FirstUseEver]]) local visible p_open, visible = ImGui.Begin("Example: Simple layout", p_open, 1024 --[[ImGuiWindowFlags.MenuBar]]) if visible then + IMGUI_DEMO_MARKER("Examples/Simple layout") if ImGui.BeginMenuBar() then if ImGui.BeginMenu("File") then if ImGui.MenuItem("Close", "Ctrl+W") then p_open = false end @@ -26286,34 +30316,41 @@ function ShowExampleAppLayout(p_open) end -- Left - ImGui.BeginChild("left pane", ImVec2(150, 0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 4 --[[ImGuiChildFlags.ResizeX]])) - for i = 0, 99 do - if ImGui.Selectable(string.format("MyObject %d", i), LayoutSelected == i, 64 --[[ImGuiSelectableFlags.SelectOnNav]]) then LayoutSelected = i end + do + ImGui.BeginChild("left pane", ImVec2(150, 0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 4 --[[ImGuiChildFlags.ResizeX]])) + for i = 0, 100 - 1 do + local label = string.format("MyObject %d", i) + if ImGui.Selectable(label, s.selected == i, 64 --[[ImGuiSelectableFlags.SelectOnNav]]) then + s.selected = i + end + end + ImGui.EndChild() end - ImGui.EndChild() ImGui.SameLine() -- Right - ImGui.BeginGroup() - ImGui.BeginChild("item view", ImVec2(0, -ImGui.GetFrameHeightWithSpacing())) -- Leave room for 1 line below us - ImGui.Text("MyObject: %d", LayoutSelected) - ImGui.Separator() - if ImGui.BeginTabBar("##Tabs", 0 --[[ImGuiTabBarFlags.None]]) then - if ImGui.BeginTabItem("Description") then - ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ") - ImGui.EndTabItem() + do + ImGui.BeginGroup() + ImGui.BeginChild("item view", ImVec2(0, -ImGui.GetFrameHeightWithSpacing())) -- Leave room for 1 line below us + ImGui.Text("MyObject: %d", s.selected) + ImGui.Separator() + if ImGui.BeginTabBar("##Tabs", 0 --[[ImGuiTabBarFlags.None]]) then + if ImGui.BeginTabItem("Description") then + ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ") + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Details") then + ImGui.Text("ID: 0123456789") + ImGui.EndTabItem() + end + ImGui.EndTabBar() end - if ImGui.BeginTabItem("Details") then - ImGui.Text("ID: 0123456789") - ImGui.EndTabItem() - end - ImGui.EndTabBar() + ImGui.EndChild() + if ImGui.Button("Revert") then end + ImGui.SameLine() + if ImGui.Button("Save") then end + ImGui.EndGroup() end - ImGui.EndChild() - if ImGui.Button("Revert") then end - ImGui.SameLine() - if ImGui.Button("Save") then end - ImGui.EndGroup() end ImGui.End() return p_open @@ -26328,121 +30365,20 @@ end -- - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties. ------------------------------------------------------------------------------- --- ExampleMemberInfo equivalent: field name, data type, component count -local ExampleTreeNodeMemberInfos = { - { Name = "MyName", DataType = ImGuiDataType.String, DataCount = 1, Field = "Name" }, - { Name = "MyBool", DataType = ImGuiDataType.Bool, DataCount = 1, Field = "DataMyBool" }, - { Name = "MyInt", DataType = ImGuiDataType.S32, DataCount = 1, Field = "DataMyInt" }, - { Name = "MyVec2", DataType = ImGuiDataType.Float, DataCount = 2, Field = "DataMyVec2" }, -} - -local PropEd = { Filter = nil, SelectedNode = nil, UseClipper = false, NameBufs = setmetatable({}, { __mode = "k" }) } - --- Custom search filter --- - Here we apply on root node only. --- - This does a case insensitive stristr which is pretty heavy. In a real large-scale app you would likely store a filtered list which in turns would be trivial to linearize. -function PropEd:IsNodePassingFilter(node) - return node.Parent.Parent ~= nil or self.Filter:PassFilter(node.Name) +ExampleAppPropertyEditorMT = {} +ExampleAppPropertyEditorMT.__index = ExampleAppPropertyEditorMT +function ExampleAppPropertyEditor() + local self = setmetatable({}, ExampleAppPropertyEditorMT) + self.Filter = ImGuiTextFilter() + self.SelectedNode = nil + self.UseClipper = false + self.StringBufs = setmetatable({}, { __mode = "k" }) -- [Port] node -> 28-byte edit buffer for ImGuiDataType.String fields (node.Name is a Lua string) + return self end --- To support node with same name we incorporate node.UID into the item ID. --- (this would more naturally be done using PushID(node.UID) + TreeNodeEx(node.Name, tree_flags), --- but it would require in DrawClippedTreeNodeAndAdvanceToNext() to add PushID() before TreePush(), and PopID() after TreePop(), --- so instead we use TreeNodeEx(node.UID, tree_flags, "%s", node.Name) here) -function PropEd:DrawTreeNode(node) - local TN = ImGuiTreeNodeFlags - ImGui.TableNextRow() - ImGui.TableNextColumn() - -- OpenOnArrow | OpenOnDoubleClick: Standard opening mode as we are likely to want to add selection afterwards - -- NavLeftJumpsToParent: Left arrow support - -- SpanFullWidth: Span full width for easier mouse reach - -- DrawLinesToNodes: Always draw hierarchy outlines - local tree_flags = bit32.bor(TN.OpenOnArrow, TN.OpenOnDoubleClick, TN.NavLeftJumpsToParent, TN.SpanFullWidth, TN.DrawLinesToNodes) - if node == self.SelectedNode then tree_flags = bit32.bor(tree_flags, TN.Selected) end -- Draw selection highlight - if #node.Childs == 0 then tree_flags = bit32.bor(tree_flags, TN.Leaf, TN.Bullet, TN.NoTreePushOnOpen) end -- Use _NoTreePushOnOpen + set is_open=false to avoid unnecessarily push/pop on leaves. - if node.DataMyBool == false then ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], ImGui.GetStyle().Colors[1 --[[ImGuiCol.TextDisabled]]]) end - ImGui.SetNextItemStorageID(node.UID) -- Use node.UID as storage id - local is_open = ImGui.TreeNodeEx(node.UID, tree_flags, "%s", node.Name) - if #node.Childs == 0 then is_open = false end - if node.DataMyBool == false then ImGui.PopStyleColor() end - if ImGui.IsItemFocused() then self.SelectedNode = node end - return is_open -end +function ExampleAppPropertyEditorMT:Draw(root_node) + IMGUI_DEMO_MARKER("Examples/Property editor") --- Basic version, recursive. This is how you would generally draw a tree. --- - Simple but going to be noticeably costly if you have a large amount of nodes as DrawTreeNode() is called for all of them. --- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~1.2 ms --- - Unlike arrays or grids which are very easy to clip, trees are currently more difficult to clip. -function PropEd:DrawTree(node) - for _, child in ipairs(node.Childs) do - if self:IsNodePassingFilter(child) and self:DrawTreeNode(child) then - self:DrawTree(child) - ImGui.TreePop() - end - end -end - -function PropEd:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) - if self:IsNodePassingFilter(node) then - -- Draw node if within visible range - local is_open - if clipper.UserIndex >= clipper.DisplayStart and clipper.UserIndex < clipper.DisplayEnd then - is_open = self:DrawTreeNode(node) - else - is_open = (#node.Childs > 0 and ImGui.TreeNodeGetOpen(node.UID)) - if is_open then ImGui.TreePush(node.Name) end - end - clipper.UserIndex = clipper.UserIndex + 1 - - -- Next node: recurse into childs - if is_open then return node.Childs[1] end - end - - -- Next node: next sibling, otherwise move back to parent - while node ~= nil do - if node.IndexInParent + 1 < #node.Parent.Childs then - return node.Parent.Childs[node.IndexInParent + 2] - end - node = node.Parent - if node.Parent == nil then break end - ImGui.TreePop() - end - return nil -end - --- More advanced version. Use a alternative clipping technique: fast-forwarding through non-visible chunks. --- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~0.1 ms --- (in ExampleTree_CreateDemoTree(), change 'ROOT_ITEMS_COUNT = 10000' to try with this amount of root nodes). --- - 1. Use clipper with indeterminate count (items_count = INT_MAX): we need to call SeekCursorForItem() at the end once we know the count. --- - 2. Use SetNextItemStorageID() to specify ID used for open/close storage, making it easy to call TreeNodeGetOpen() on any arbitrary node. --- - 3. Linearize tree during traversal: our tree data structure makes it easy to access sibling and parents. --- - Unlike clipping for a regular array or grid which may be done using random access limited to visible areas, --- this technique requires traversing most accessible nodes. This could be made more optimal with extra work, --- but this is a decent simplicity<>speed trade-off. --- See https://github.com/ocornut/imgui/issues/3823 for discussions about this. -function PropEd:DrawClippedTree(root_node) - local node = root_node.Childs[1] -- First node - local clipper = ImGuiListClipper() - clipper:Begin(2147483647 --[[INT_MAX]]) - while clipper:Step() do - while clipper.UserIndex < clipper.DisplayEnd and node ~= nil do - node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) - end - end - - -- Keep going to count nodes and submit final count so we have a reliable scrollbar. - -- - One could consider caching this value and only refreshing it occasionally e.g. window is focused and an action occurs. - -- - Incorrect but cheap approximation would be to use 'clipper_current_idx = IM_MAX(clipper_current_idx, #root_node.Childs)' instead. - -- - If either of those is implemented, the general cost will approach zero when scrolling is at the top of the tree. - while node ~= nil do - node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) - end - --clipper.UserIndex = math.max(clipper.UserIndex, #root_node.Childs) -- <-- Cheap approximation instead of while() loop above. - clipper:SeekCursorForItem(clipper.UserIndex) -end - -function PropEd:Draw(root_node) - self.Filter = self.Filter or ImGuiTextFilter() -- Left side: draw tree -- - Currently using a table to benefit from RowBg feature -- - Our tree node are all of equal height, facilitating the use of a clipper. @@ -26457,8 +30393,13 @@ function PropEd:Draw(root_node) self.Filter:Build() end ImGui.PopItemFlag() + if ImGui.BeginTable("##list", 1, 64 --[[ImGuiTableFlags.RowBg]]) then - if self.UseClipper then self:DrawClippedTree(root_node) else self:DrawTree(root_node) end + if self.UseClipper then + self:DrawClippedTree(root_node) + else + self:DrawTree(root_node) + end ImGui.EndTable() end end @@ -26489,19 +30430,26 @@ function PropEd:Draw(root_node) ImGui.AlignTextToFramePadding() ImGui.TextUnformatted(field_desc.Name) ImGui.TableNextColumn() - local DT = ImGuiDataType - if field_desc.DataType == DT.Bool then - _, node[field_desc.Field] = ImGui.Checkbox("##Editor", node[field_desc.Field]) - elseif field_desc.DataType == DT.S32 then + local field_ptr = field_desc.Offset -- [Port] Offset is the field name inside ExampleTreeNode + if field_desc.DataType == 8 --[[ImGuiDataType.Bool]] then + assert(field_desc.DataCount == 1) + _, node[field_ptr] = ImGui.Checkbox("##Editor", node[field_ptr]) + elseif field_desc.DataType == 4 --[[ImGuiDataType.S32]] then + local v_min, v_max = (-2147483648) --[[INT_MIN]], 2147483647 --[[INT_MAX]] ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - node[field_desc.Field] = ImGui.DragScalar("##Editor", DT.S32, node[field_desc.Field], 1.0, (-2147483648) --[[INT_MIN]] or -2147483648, 2147483647 --[[INT_MAX]]) - elseif field_desc.DataType == DT.Float then + if field_desc.DataCount == 1 then -- [Port] scalar fields are plain Lua values: DragScalar() returns the new value + node[field_ptr] = ImGui.DragScalar("##Editor", field_desc.DataType, node[field_ptr], 1.0, v_min, v_max) + else + ImGui.DragScalarN("##Editor", field_desc.DataType, node[field_ptr], field_desc.DataCount, 1.0, v_min, v_max) + end + elseif field_desc.DataType == 6 --[[ImGuiDataType.Float]] then + local v_min, v_max = 0.0, 1.0 ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - ImGui.SliderScalarN("##Editor", DT.Float, node[field_desc.Field], field_desc.DataCount, 0.0, 1.0) - elseif field_desc.DataType == DT.String then - local b = self.NameBufs[node] - if b == nil then b = Buf(node.Name, 28); self.NameBufs[node] = b end - if ImGui.InputText("##Editor", b, 28) then node.Name = BufStr(b) end + ImGui.SliderScalarN("##Editor", field_desc.DataType, node[field_ptr], field_desc.DataCount, v_min, v_max) + elseif field_desc.DataType == 9 --[[ImGuiDataType.String]] then + local buf = self.StringBufs[node] -- [Port] edit the Lua string through a 28-byte buffer + if buf == nil then buf = ImGui.NewTextBuffer(node[field_ptr], 28); self.StringBufs[node] = buf end + if ImGui.InputText("##Editor", buf, 28) then node[field_ptr] = ImGui.TextBufferToString(buf) end end ImGui.PopID() end @@ -26513,16 +30461,152 @@ function PropEd:Draw(root_node) ImGui.EndGroup() end +-- Custom search filter +-- - Here we apply on root node only. +-- - This does a case insensitive stristr which is pretty heavy. In a real large-scale app you would likely store a filtered list which in turns would be trivial to linearize. +function ExampleAppPropertyEditorMT:IsNodePassingFilter(node) + return node.Parent.Parent ~= nil or self.Filter:PassFilter(node.Name) +end + +-- Basic version, recursive. This is how you would generally draw a tree. +-- - Simple but going to be noticeably costly if you have a large amount of nodes as DrawTreeNode() is called for all of them. +-- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~1.2 ms +-- - Unlike arrays or grids which are very easy to clip, trees are currently more difficult to clip. +function ExampleAppPropertyEditorMT:DrawTree(node) + for _, child in ipairs(node.Childs) do + if self:IsNodePassingFilter(child) and self:DrawTreeNode(child) then + self:DrawTree(child) + ImGui.TreePop() + end + end +end + +-- More advanced version. Use a alternative clipping technique: fast-forwarding through non-visible chunks. +-- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~0.1 ms +-- (in ExampleTree_CreateDemoTree(), change 'int ROOT_ITEMS_COUNT = 10000' to try with this amount of root nodes). +-- - 1. Use clipper with indeterminate count (items_count = INT_MAX): we need to call SeekCursorForItem() at the end once we know the count. +-- - 2. Use SetNextItemStorageID() to specify ID used for open/close storage, making it easy to call TreeNodeGetOpen() on any arbitrary node. +-- - 3. Linearize tree during traversal: our tree data structure makes it easy to access sibling and parents. +-- - Unlike clipping for a regular array or grid which may be done using random access limited to visible areas, +-- this technique requires traversing most accessible nodes. This could be made more optimal with extra work, +-- but this is a decent simplicity<>speed trade-off. +-- See https://github.com/ocornut/imgui/issues/3823 for discussions about this. +function ExampleAppPropertyEditorMT:DrawClippedTree(root_node) + local node = root_node.Childs[1] -- First node + local clipper = ImGuiListClipper() + clipper:Begin(2147483647 --[[INT_MAX]]) + while clipper:Step() do + while clipper.UserIndex < clipper.DisplayEnd and node ~= nil do + node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) + end + end + + -- Keep going to count nodes and submit final count so we have a reliable scrollbar. + -- - One could consider caching this value and only refreshing it occasionally e.g. window is focused and an action occurs. + -- - Incorrect but cheap approximation would be to use 'clipper_current_idx = IM_MAX(clipper_current_idx, root_node.Childs.Size)' instead. + -- - If either of those is implemented, the general cost will approach zero when scrolling is at the top of the tree. + while node ~= nil do + node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) + end + --clipper.UserIndex = IM_MAX(clipper.UserIndex, root_node.Childs.Size); // <-- Cheap approximation instead of while() loop above. + clipper:SeekCursorForItem(clipper.UserIndex) +end + +function ExampleAppPropertyEditorMT:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) + if self:IsNodePassingFilter(node) then + -- Draw node if within visible range + local is_open = false + if clipper.UserIndex >= clipper.DisplayStart and clipper.UserIndex < clipper.DisplayEnd then + is_open = self:DrawTreeNode(node) + else + is_open = (#node.Childs > 0 and ImGui.TreeNodeGetOpen(node.UID)) + if is_open then + ImGui.TreePush(node.Name) + end + end + clipper.UserIndex = clipper.UserIndex + 1 + + -- Next node: recurse into childs + if is_open then + return node.Childs[1] + end + end + + -- Next node: next sibling, otherwise move back to parent + while node ~= nil do + if node.IndexInParent + 1 < #node.Parent.Childs then + return node.Parent.Childs[node.IndexInParent + 1 + 1] -- [Port] Childs is 1-based, IndexInParent 0-based + end + node = node.Parent + if node.Parent == nil then + break + end + ImGui.TreePop() + end + return nil +end + +-- To support node with same name we incorporate node.UID into the item ID. +-- (this would more naturally be done using PushID(node.UID) + TreeNodeEx(node.Name, tree_flags), +-- but it would require in DrawClippedTreeNodeAndAdvanceToNext() to add PushID() before TreePush(), and PopID() after TreePop(), +-- so instead we use TreeNodeEx(node.UID, tree_flags, "%s", node.Name) here) +function ExampleAppPropertyEditorMT:DrawTreeNode(node) + ImGui.TableNextRow() + ImGui.TableNextColumn() + local tree_flags = 0 --[[ImGuiTreeNodeFlags.None]] + tree_flags = bit32.bor(tree_flags, 128 --[[ImGuiTreeNodeFlags.OpenOnArrow]], 64 --[[ImGuiTreeNodeFlags.OpenOnDoubleClick]]) -- Standard opening mode as we are likely to want to add selection afterwards + tree_flags = bit32.bor(tree_flags, 131072 --[[ImGuiTreeNodeFlags.NavLeftJumpsToParent]]) -- Left arrow support + tree_flags = bit32.bor(tree_flags, 4096 --[[ImGuiTreeNodeFlags.SpanFullWidth]]) -- Span full width for easier mouse reach + tree_flags = bit32.bor(tree_flags, 1048576 --[[ImGuiTreeNodeFlags.DrawLinesToNodes]]) -- Always draw hierarchy outlines + if node == self.SelectedNode then + tree_flags = bit32.bor(tree_flags, 1 --[[ImGuiTreeNodeFlags.Selected]]) -- Draw selection highlight + end + if #node.Childs == 0 then + tree_flags = bit32.bor(tree_flags, 256 --[[ImGuiTreeNodeFlags.Leaf]], 512 --[[ImGuiTreeNodeFlags.Bullet]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]]) -- Use _NoTreePushOnOpen + set is_open=false to avoid unnecessarily push/pop on leaves. + end + if node.DataMyBool == false then + ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], ImGui.GetStyle().Colors[1 --[[ImGuiCol.TextDisabled]]]) + end + ImGui.SetNextItemStorageID(node.UID) -- Use node.UID as storage id + local is_open = ImGui.TreeNodeEx(node.UID, tree_flags, "%s", node.Name) + if #node.Childs == 0 then + is_open = false + end + if node.DataMyBool == false then + ImGui.PopStyleColor() + end + if ImGui.IsItemFocused() then + self.SelectedNode = node + end + return is_open +end + -- Demonstrate creating a simple property editor. -local DemoTree = nil +S.ShowExampleAppPropertyEditor = { + property_editor = nil, -- ExampleAppPropertyEditor, created on first use + demo_data = nil, -- [Port] fallback when called without demo_data +} function ShowExampleAppPropertyEditor(p_open, demo_data) + local s = S.ShowExampleAppPropertyEditor ImGui.SetNextWindowSize(ImVec2(430, 450), 4 --[[ImGuiCond.FirstUseEver]]) local visible p_open, visible = ImGui.Begin("Example: Property editor", p_open) - if not visible then ImGui.End(); return p_open end - if demo_data and demo_data.DemoTree == nil then demo_data.DemoTree = ExampleTree_CreateDemoTree() end - DemoTree = (demo_data and demo_data.DemoTree) or DemoTree or ExampleTree_CreateDemoTree() - PropEd:Draw(DemoTree) + if not visible then + ImGui.End() + return p_open + end + + IMGUI_DEMO_MARKER("Examples/Property Editor") + if s.property_editor == nil then s.property_editor = ExampleAppPropertyEditor() end + if demo_data == nil then -- [Port] tolerate callers without demo_data (test harness) + if s.demo_data == nil then s.demo_data = {} end + demo_data = s.demo_data + end + if demo_data.DemoTree == nil then + demo_data.DemoTree = ExampleTree_CreateDemoTree() + end + s.property_editor:Draw(demo_data.DemoTree) + ImGui.End() return p_open end @@ -26532,44 +30616,57 @@ end ------------------------------------------------------------------------------- -- Demonstrate/test rendering huge amount of text, and the incidence of clipping. -local LT = { test_type = 0, log = {}, lines = 0, bytes = 0 } +S.ShowExampleAppLongText = { + test_type = 0, + log = ImGuiTextBuffer(), + lines = 0, +} function ShowExampleAppLongText(p_open) + local s = S.ShowExampleAppLongText ImGui.SetNextWindowSize(ImVec2(520, 600), 4 --[[ImGuiCond.FirstUseEver]]) local visible p_open, visible = ImGui.Begin("Example: Long text display", p_open) - if not visible then ImGui.End(); return p_open end + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Examples/Long text display") + ImGui.Text("Printing unusually long amount of text.") - LT.test_type = ImGui.Combo("Test type", LT.test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped\0Multiple calls to Text(), not clipped (slow)\0") - ImGui.Text("Buffer contents: %d lines, %d bytes", LT.lines, LT.bytes) - if ImGui.Button("Clear") then LT.log = {}; LT.lines = 0; LT.bytes = 0; LT.text = nil end + s.test_type = ImGui.Combo("Test type", s.test_type, + "Single call to TextUnformatted()\0" .. + "Multiple calls to Text(), clipped\0" .. + "Multiple calls to Text(), not clipped (slow)\0") + ImGui.Text("Buffer contents: %d lines, %d bytes", s.lines, s.log:size()) + if ImGui.Button("Clear") then s.log:clear(); s.lines = 0 end ImGui.SameLine() if ImGui.Button("Add 1000 lines") then - for i = 0, 999 do - local line = string.format("%i The quick brown fox jumps over the lazy dog\n", LT.lines + i) - LT.log[#LT.log + 1] = line - LT.bytes = LT.bytes + #line + for i = 0, 1000 - 1 do + s.log:appendf("%i The quick brown fox jumps over the lazy dog\n", s.lines + i) end - LT.lines = LT.lines + 1000 - LT.text = nil + s.lines = s.lines + 1000 end ImGui.BeginChild("Log") - if LT.test_type == 0 then + if s.test_type == 0 then -- Single call to TextUnformatted() with a big buffer - LT.text = LT.text or table.concat(LT.log) - ImGui.TextUnformatted(LT.text) - elseif LT.test_type == 1 then + ImGui.TextUnformatted(s.log:c_str()) -- [Port] ImGuiTextBuffer is a chunk list: c_str() instead of begin()/end() + elseif s.test_type == 1 then -- Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(0, 0)) local clipper = ImGuiListClipper() - clipper:Begin(LT.lines) + clipper:Begin(s.lines) while clipper:Step() do - for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) end + for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do + ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) + end end ImGui.PopStyleVar() - else + elseif s.test_type == 2 then -- Multiple calls to Text(), not clipped (slow) ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(0, 0)) - for i = 0, LT.lines - 1 do ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) end + for i = 0, s.lines - 1 do + ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) + end ImGui.PopStyleVar() end ImGui.EndChild() @@ -26582,14 +30679,27 @@ end ------------------------------------------------------------------------------- -- Demonstrate creating a window which gets auto-resized according to its content. -local AutoResizeLines = 10 +S.ShowExampleAppAutoResize = { + lines = 10, +} function ShowExampleAppAutoResize(p_open) + local s = S.ShowExampleAppAutoResize local visible p_open, visible = ImGui.Begin("Example: Auto-resizing window", p_open, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) - if not visible then ImGui.End(); return p_open end - ImGui.TextUnformatted("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop.") - AutoResizeLines = ImGui.SliderInt("Number of lines", AutoResizeLines, 1, 20) - for i = 0, AutoResizeLines - 1 do ImGui.Text("%sThis is line %d", string.rep(" ", i * 4), i) end -- Pad with space to extend size horizontally + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Examples/Auto-resizing window") + + ImGui.TextUnformatted( + "Window will resize every-frame to the size of its content.\n" .. + "Note that you probably don't want to query the window size to\n" .. + "output your content because that would create a feedback loop.") + s.lines = ImGui.SliderInt("Number of lines", s.lines, 1, 20) + for i = 0, s.lines - 1 do + ImGui.Text("%sThis is line %d", string.rep(" ", i * 4), i) -- Pad with space to extend size horizontally -- [Port] "%*s" -> string.rep + end ImGui.End() return p_open end @@ -26600,38 +30710,69 @@ end -- Demonstrate creating a window with custom resize constraints. -- Note that size constraints currently don't work on a docked window (when in 'docking' branch) --- Options -local CR = { auto_resize = false, window_padding = true, type = 6, display_lines = 10 } -- type 6: Aspect Ratio +CustomConstraints = {} +-- Helper functions to demonstrate programmatic constraints +-- FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier. +-- FIXME: None of the three demos works consistently when resizing from borders. +function CustomConstraints.AspectRatio(data) + local aspect_ratio = data.UserData -- [Port] UserData is the number itself (no float*) + data.DesiredSize.y = math.floor(data.DesiredSize.x / aspect_ratio) +end +function CustomConstraints.Square(data) + local m = ImMax(data.DesiredSize.x, data.DesiredSize.y) -- [Port] IM_MAX -> ImMax + data.DesiredSize.x = m; data.DesiredSize.y = m +end +function CustomConstraints.Step(data) + local step = data.UserData + data.DesiredSize = ImVec2(math.floor(data.DesiredSize.x / step + 0.5) * step, math.floor(data.DesiredSize.y / step + 0.5) * step) +end + +S.ShowExampleAppConstrainedResize = { + -- Options + auto_resize = false, + window_padding = true, + type = 6, -- Aspect Ratio + display_lines = 10, +} function ShowExampleAppConstrainedResize(p_open) - -- Helper functions to demonstrate programmatic constraints - -- FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier. - -- FIXME: None of the three demos works consistently when resizing from borders. - local function AspectRatio(data) data.DesiredSize.y = math.floor(data.DesiredSize.x / data.UserData) end - local function Square(data) local m = math.max(data.DesiredSize.x, data.DesiredSize.y); data.DesiredSize.x = m; data.DesiredSize.y = m end - local function Step(data) - local step = data.UserData - data.DesiredSize = ImVec2(math.floor(data.DesiredSize.x / step + 0.5) * step, math.floor(data.DesiredSize.y / step + 0.5) * step) - end - local test_desc = { "Between 100x100 and 500x500", "At least 100x100", "Resize vertical + lock current width", "Resize horizontal + lock current height", - "Width Between 400 and 500", "Height at least 400", "Custom: Aspect Ratio 16:9", "Custom: Always Square", "Custom: Fixed Steps (100)" } + local s = S.ShowExampleAppConstrainedResize + local test_desc = + { + "Between 100x100 and 500x500", + "At least 100x100", + "Resize vertical + lock current width", + "Resize horizontal + lock current height", + "Width Between 400 and 500", + "Height at least 400", + "Custom: Aspect Ratio 16:9", + "Custom: Always Square", + "Custom: Fixed Steps (100)", + } + -- Submit constraint - local t = CR.type - if t == 0 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)) end -- Between 100x100 and 500x500 - if t == 1 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]])) end -- Width > 100, Height > 100 - if t == 2 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, 3.4028234663853e+38 --[[FLT_MAX]])) end -- Resize vertical + lock current width - if t == 3 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], -1)) end -- Resize horizontal + lock current height - if t == 4 then ImGui.SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)) end -- Width Between and 400 and 500 - if t == 5 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 3.4028234663853e+38 --[[FLT_MAX]])) end -- Height at least 400 - if t == 6 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), AspectRatio, 16.0 / 9.0) end -- Aspect ratio - if t == 7 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), Square) end -- Always Square - if t == 8 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), Step, 100.0) end -- Fixed Step + local aspect_ratio = 16.0 / 9.0 + local fixed_step = 100.0 + if s.type == 0 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)) end -- Between 100x100 and 500x500 + if s.type == 1 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]])) end -- Width > 100, Height > 100 + if s.type == 2 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, 3.4028234663853e+38 --[[FLT_MAX]])) end -- Resize vertical + lock current width + if s.type == 3 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], -1)) end -- Resize horizontal + lock current height + if s.type == 4 then ImGui.SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)) end -- Width Between and 400 and 500 + if s.type == 5 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 3.4028234663853e+38 --[[FLT_MAX]])) end -- Height at least 400 + if s.type == 6 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), CustomConstraints.AspectRatio, aspect_ratio) end -- Aspect ratio + if s.type == 7 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), CustomConstraints.Square) end -- Always Square + if s.type == 8 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]]), CustomConstraints.Step, fixed_step) end -- Fixed Step -- Submit window - if not CR.window_padding then ImGui.PushStyleVar(2 --[[ImGuiStyleVar.WindowPadding]], ImVec2(0.0, 0.0)) end - local window_flags = CR.auto_resize and 64 --[[ImGuiWindowFlags.AlwaysAutoResize]] or 0 + if not s.window_padding then + ImGui.PushStyleVar(2 --[[ImGuiStyleVar.WindowPadding]], ImVec2(0.0, 0.0)) + end + local window_flags = s.auto_resize and 64 --[[ImGuiWindowFlags.AlwaysAutoResize]] or 0 local window_open p_open, window_open = ImGui.Begin("Example: Constrained Resize", p_open, window_flags) - if not CR.window_padding then ImGui.PopStyleVar() end + if not s.window_padding then + ImGui.PopStyleVar() + end + IMGUI_DEMO_MARKER("Examples/Constrained Resizing window") if window_open then if ImGui.GetIO().KeyShift then -- Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture) @@ -26642,17 +30783,21 @@ function ShowExampleAppConstrainedResize(p_open) ImGui.Text("%.2f x %.2f", avail_size.x, avail_size.y) else ImGui.Text("(Hold Shift to display a dummy viewport)") - if ImGui.IsWindowDocked() then ImGui.Text("Warning: Sizing Constraints won't work if the window is docked!") end + if ImGui.IsWindowDocked() then + ImGui.Text("Warning: Sizing Constraints won't work if the window is docked!") + end if ImGui.Button("Set 200x200") then ImGui.SetWindowSize(ImVec2(200, 200)) end ImGui.SameLine() if ImGui.Button("Set 500x500") then ImGui.SetWindowSize(ImVec2(500, 500)) end ImGui.SameLine() if ImGui.Button("Set 800x200") then ImGui.SetWindowSize(ImVec2(800, 200)) end ImGui.SetNextItemWidth(ImGui.GetFontSize() * 20) - CR.type = ImGui.Combo("Constraint", CR.type, test_desc, #test_desc) + s.type = ImGui.Combo("Constraint", s.type, test_desc, #test_desc) ImGui.SetNextItemWidth(ImGui.GetFontSize() * 20) - CR.display_lines = ImGui.DragInt("Lines", CR.display_lines, 0.2, 1, 100) - _, CR.auto_resize = ImGui.Checkbox("Auto-resize", CR.auto_resize) - _, CR.window_padding = ImGui.Checkbox("Window padding", CR.window_padding) - for i = 0, CR.display_lines - 1 do ImGui.Text("%sHello, sailor! Making this line long enough for the example.", string.rep(" ", i * 4)) end + s.display_lines = ImGui.DragInt("Lines", s.display_lines, 0.2, 1, 100) + _, s.auto_resize = ImGui.Checkbox("Auto-resize", s.auto_resize) + _, s.window_padding = ImGui.Checkbox("Window padding", s.window_padding) + for i = 0, s.display_lines - 1 do + ImGui.Text("%sHello, sailor! Making this line long enough for the example.", string.rep(" ", i * 4)) -- [Port] "%*s" -> string.rep + end end end ImGui.End() @@ -26665,40 +30810,50 @@ end -- Demonstrate creating a simple static window with no decoration -- + a context-menu to choose which corner of the screen to use. -local OverlayLocation = 0 +S.ShowExampleAppSimpleOverlay = { + location = 0, +} function ShowExampleAppSimpleOverlay(p_open) + local s = S.ShowExampleAppSimpleOverlay local io = ImGui.GetIO() - local W = ImGuiWindowFlags - local window_flags = bit32.bor(W.NoDecoration, W.NoDocking, W.AlwaysAutoResize, W.NoSavedSettings, W.NoFocusOnAppearing, W.NoNav) - if OverlayLocation >= 0 then + local window_flags = bit32.bor(43 --[[ImGuiWindowFlags.NoDecoration]], 524288 --[[ImGuiWindowFlags.NoDocking]], 64 --[[ImGuiWindowFlags.AlwaysAutoResize]], 256 --[[ImGuiWindowFlags.NoSavedSettings]], 4096 --[[ImGuiWindowFlags.NoFocusOnAppearing]], 196608 --[[ImGuiWindowFlags.NoNav]]) + if s.location >= 0 then local PAD = 10.0 local viewport = ImGui.GetMainViewport() - local work_pos, work_size = viewport.WorkPos, viewport.WorkSize -- Use work area to avoid menu-bar/task-bar, if any! - local right, bottom = OverlayLocation % 2 == 1, OverlayLocation >= 2 - local window_pos = ImVec2(right and (work_pos.x + work_size.x - PAD) or (work_pos.x + PAD), bottom and (work_pos.y + work_size.y - PAD) or (work_pos.y + PAD)) - local window_pos_pivot = ImVec2(right and 1.0 or 0.0, bottom and 1.0 or 0.0) + local work_pos = viewport.WorkPos -- Use work area to avoid menu-bar/task-bar, if any! + local work_size = viewport.WorkSize + local window_pos, window_pos_pivot = ImVec2(), ImVec2() + window_pos.x = (bit32.band(s.location, 1) ~= 0) and (work_pos.x + work_size.x - PAD) or (work_pos.x + PAD) + window_pos.y = (bit32.band(s.location, 2) ~= 0) and (work_pos.y + work_size.y - PAD) or (work_pos.y + PAD) + window_pos_pivot.x = (bit32.band(s.location, 1) ~= 0) and 1.0 or 0.0 + window_pos_pivot.y = (bit32.band(s.location, 2) ~= 0) and 1.0 or 0.0 ImGui.SetNextWindowPos(window_pos, 1 --[[ImGuiCond.Always]], window_pos_pivot) ImGui.SetNextWindowViewport(viewport.ID) - window_flags = bit32.bor(window_flags, W.NoMove) - elseif OverlayLocation == -2 then + window_flags = bit32.bor(window_flags, 4 --[[ImGuiWindowFlags.NoMove]]) + elseif s.location == -2 then -- Center window ImGui.SetNextWindowPos(ImGui.GetMainViewport():GetCenter(), 1 --[[ImGuiCond.Always]], ImVec2(0.5, 0.5)) - window_flags = bit32.bor(window_flags, W.NoMove) + window_flags = bit32.bor(window_flags, 4 --[[ImGuiWindowFlags.NoMove]]) end ImGui.SetNextWindowBgAlpha(0.35) -- Transparent background local visible p_open, visible = ImGui.Begin("Example: Simple overlay", p_open, window_flags) if visible then - ImGui.Text("Simple overlay\n(right-click to change position)") + IMGUI_DEMO_MARKER("Examples/Simple overlay") -- Scroll up to the beginning of this function to see overlay flags + ImGui.Text("Simple overlay\n" .. "(right-click to change position)") ImGui.Separator() - if ImGui.IsMousePosValid() then ImGui.Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y) else ImGui.Text("Mouse Position: ") end + if ImGui.IsMousePosValid() then + ImGui.Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y) + else + ImGui.Text("Mouse Position: ") + end if ImGui.BeginPopupContextWindow() then - if ImGui.MenuItem("Custom", nil, OverlayLocation == -1) then OverlayLocation = -1 end - if ImGui.MenuItem("Center", nil, OverlayLocation == -2) then OverlayLocation = -2 end - if ImGui.MenuItem("Top-left", nil, OverlayLocation == 0) then OverlayLocation = 0 end - if ImGui.MenuItem("Top-right", nil, OverlayLocation == 1) then OverlayLocation = 1 end - if ImGui.MenuItem("Bottom-left", nil, OverlayLocation == 2) then OverlayLocation = 2 end - if ImGui.MenuItem("Bottom-right", nil, OverlayLocation == 3) then OverlayLocation = 3 end + if ImGui.MenuItem("Custom", nil, s.location == -1) then s.location = -1 end + if ImGui.MenuItem("Center", nil, s.location == -2) then s.location = -2 end + if ImGui.MenuItem("Top-left", nil, s.location == 0) then s.location = 0 end + if ImGui.MenuItem("Top-right", nil, s.location == 1) then s.location = 1 end + if ImGui.MenuItem("Bottom-left", nil, s.location == 2) then s.location = 2 end + if ImGui.MenuItem("Bottom-right", nil, s.location == 3) then s.location = 3 end if p_open ~= nil and ImGui.MenuItem("Close") then p_open = false end ImGui.EndPopup() end @@ -26712,28 +30867,38 @@ end ------------------------------------------------------------------------------- -- Demonstrate creating a window covering the entire screen/viewport -local FS = { use_work_area = true, flags = bit32.bor(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings) } +S.ShowExampleAppFullscreen = { + use_work_area = true, + flags = bit32.bor(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings), +} function ShowExampleAppFullscreen(p_open) + local s = S.ShowExampleAppFullscreen + -- We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.) -- Based on your use case you may want one or the other. local viewport = ImGui.GetMainViewport() - ImGui.SetNextWindowPos(FS.use_work_area and viewport.WorkPos or viewport.Pos) - ImGui.SetNextWindowSize(FS.use_work_area and viewport.WorkSize or viewport.Size) + ImGui.SetNextWindowPos(s.use_work_area and viewport.WorkPos or viewport.Pos) + ImGui.SetNextWindowSize(s.use_work_area and viewport.WorkSize or viewport.Size) + local visible - p_open, visible = ImGui.Begin("Example: Fullscreen window", p_open, FS.flags) + p_open, visible = ImGui.Begin("Example: Fullscreen window", p_open, s.flags) if visible then - _, FS.use_work_area = ImGui.Checkbox("Use work area instead of main area", FS.use_work_area) + IMGUI_DEMO_MARKER("Examples/Fullscreen window") + _, s.use_work_area = ImGui.Checkbox("Use work area instead of main area", s.use_work_area) ImGui.SameLine() HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference.") - local W = ImGuiWindowFlags - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoBackground", FS.flags, W.NoBackground) - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoDecoration", FS.flags, W.NoDecoration) + + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoBackground", s.flags, 128 --[[ImGuiWindowFlags.NoBackground]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoDecoration", s.flags, 43 --[[ImGuiWindowFlags.NoDecoration]]) ImGui.Indent() - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoTitleBar", FS.flags, W.NoTitleBar) - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoCollapse", FS.flags, W.NoCollapse) - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoScrollbar", FS.flags, W.NoScrollbar) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoTitleBar", s.flags, 1 --[[ImGuiWindowFlags.NoTitleBar]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoCollapse", s.flags, 32 --[[ImGuiWindowFlags.NoCollapse]]) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoScrollbar", s.flags, 8 --[[ImGuiWindowFlags.NoScrollbar]]) ImGui.Unindent() - if p_open ~= nil and ImGui.Button("Close this window") then p_open = false end + + if p_open ~= nil and ImGui.Button("Close this window") then + p_open = false + end end ImGui.End() return p_open @@ -26756,19 +30921,22 @@ function ShowExampleAppWindowTitles(p_open) -- Using "##" to display same title but have unique identifier. ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), 4 --[[ImGuiCond.FirstUseEver]]) ImGui.Begin("Same title as another window##1") + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##1") ImGui.Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.") ImGui.End() + ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), 4 --[[ImGuiCond.FirstUseEver]]) ImGui.Begin("Same title as another window##2") + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##2") ImGui.Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.") ImGui.End() -- Using "###" to display a changing title but keep a static identifier "AnimatedTitle" - local spin = "|/-\\" - local k = math.floor(ImGui.GetTime() / 0.25) % 4 + 1 - local buf = string.format("Animated title %s %d###AnimatedTitle", string.sub(spin, k, k), ImGui.GetFrameCount()) + local spin_i = bit32.band(math.floor(ImGui.GetTime() / 0.25), 3) + 1 + local buf = string.format("Animated title %s %d###AnimatedTitle", string.sub("|/-\\", spin_i, spin_i), ImGui.GetFrameCount()) ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), 4 --[[ImGuiCond.FirstUseEver]]) ImGui.Begin(buf) + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##3") ImGui.Text("This window has a changing title.") ImGui.End() return p_open @@ -26783,297 +30951,406 @@ end -- - Pixel Perfect Anti-aliased Rendering: https://github.com/ocornut/imgui/wiki/Pixel-Perfect-Rendering -- - How Anti-aliased Polyline Rendering is Implemented: https://github.com/ocornut/imgui/wiki/Polyline-Rendering -local CRS = { sz = 42.0, base_rounding = 8.0, base_thickness = 3.0, animate_rounding = false, animate_thickness = false, ngon_segments = 6, - circle_override = false, circle_override_v = 12, curve_override = false, curve_override_v = 8, - colf_stroke = ImVec4(1.000, 0.384, 0.169, 1.000), colf_fill = ImVec4(0.416, 0.378, 0.420, 1.000), - points = {}, scrolling = ImVec2(0.0, 0.0), opt_enable_grid = true, opt_enable_context_menu = true, adding_line = false, - draw_bg = true, draw_fg = true } - -local function CustomRenderingPrimitives() - local s = CRS - ImGui.PushItemWidth(-ImGui.GetFontSize() * 15) - ImGui.PushItemFlag(384 --[[ImGuiItemFlags.LiveEditOnInput]], true) - local draw_list = ImGui.GetWindowDrawList() - - -- Draw gradients - -- (note that those are currently exacerbating our sRGB/Linear issues) - -- Calling ImGui.GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. - ImGui.Text("Gradients") - local gradient_size = ImVec2(ImGui.CalcItemWidth(), ImGui.GetFrameHeight()) - ImGui.InvisibleButton("##gradient1", gradient_size) - local col_a, col_b = ImGui.GetColorU32(IM_COL32(0, 0, 0, 255), nil, true), ImGui.GetColorU32(IM_COL32(255, 255, 255, 255), nil, true) - draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) - ImGui.InvisibleButton("##gradient2", gradient_size) - col_a, col_b = ImGui.GetColorU32(IM_COL32(0, 255, 0, 255), nil, true), ImGui.GetColorU32(IM_COL32(255, 0, 0, 255), nil, true) - draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) - - -- Draw a bunch of primitives - ImGui.Text("All primitives") - s.sz = ImGui.DragFloat("Size", s.sz, 0.2, 0.2, 100.0, "%.0f") - local t = ImGui.GetTime() - local rounding_wave = 1.0 - math.abs((t % 3.0) * (2.0 / 3.0) - 1.0) - local rounding = s.animate_rounding and (math.floor(rounding_wave * s.base_rounding * 10.0) / 10.0) or s.base_rounding -- Sub-integer rounding works but has discontinuities in small values, so best disable we - s.base_rounding = ImGui.DragFloat("Rounding", s.base_rounding, 0.02, 0.0, 32.0, "%.1f"); ImGui.SameLine() - _, s.animate_rounding = ImGui.Checkbox("Animate##rounding", s.animate_rounding); ImGui.SameLine() - ImGui.Text("%.2f", rounding) - local thickness_wave = 1.0 - math.abs((t % 5.0) * (2.0 / 5.0) - 1.0) - local thickness = s.animate_thickness and (thickness_wave * s.base_thickness) or s.base_thickness - s.base_thickness = ImGui.DragFloat("Thickness", s.base_thickness, 0.02, 0.0, 32.0, "%.02f"); ImGui.SameLine() - _, s.animate_thickness = ImGui.Checkbox("Animate##thickness", s.animate_thickness); ImGui.SameLine() - ImGui.Text("%.2f", thickness) - s.ngon_segments = ImGui.SliderInt("N-gon sides", s.ngon_segments, 3, 12) - local changed - _, s.circle_override = ImGui.Checkbox("##CircleSegmentOverride", s.circle_override) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - s.circle_override_v, changed = ImGui.SliderInt("Circle segments override", s.circle_override_v, 3, 30) - s.circle_override = s.circle_override or changed - _, s.curve_override = ImGui.Checkbox("##CurvesSegmentOverride", s.curve_override) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - s.curve_override_v, changed = ImGui.SliderInt("Curves segments override", s.curve_override_v, 3, 30) - s.curve_override = s.curve_override or changed - ImGui.ColorEdit4("Stroke Color", s.colf_stroke) - ImGui.ColorEdit4("Fill Color", s.colf_fill) - ImGui.SeparatorText("Per primitive flags (AddXXX functions)") - ImGui.TextDisabled("(stroke placement/AA flags: not ported, this port uses the 1.92 stroker)") - ImGui.Spacing() - - local sz = s.sz - local start_pos = ImGui.GetCursorScreenPos() - local pi = 3.141592 - local step = sz + 10.0 - local corners_tl_br = bit32.bor(16 --[[ImDrawFlags.RoundCornersTopLeft]], 128 --[[ImDrawFlags.RoundCornersBottomRight]]) - local half_sz = sz * 0.5 - local circle_segments = s.circle_override and s.circle_override_v or 0 - local curve_segments = s.curve_override and s.curve_override_v or 0 - local cp3 = { ImVec2(0.0, sz * 0.6), ImVec2(sz * 0.5, -sz * 0.4), ImVec2(sz, sz) } -- Control points for curves - local cp4 = { ImVec2(0.0, 0.0), ImVec2(sz * 1.3, sz * 0.3), ImVec2(sz - sz * 1.3, sz - sz * 0.3), ImVec2(sz, sz) } - local concave_shape = { { 0.0, 0.0 }, { 0.3, 0.0 }, { 0.3, 0.7 }, { 0.7, 0.7 }, { 0.7, 0.0 }, { 1.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 1.0 } } -- |_| looking shape. Normalized. - local zigzag_shape = { { 0.0, 0.0 }, { 0.9, 0.0 }, { 1.0, 0.1 }, { 1.0, 0.9 }, { 0.9, 1.0 }, { 0.3, 1.0 }, { 0.3, 0.4 }, { 0.9, 0.4 } } - local rotating_square = {} - for side = 0, 3 do - local a = t * 0.1 + side * pi * 0.5 - rotating_square[side + 1] = ImVec2(math.cos(a) * half_sz, math.sin(a) * half_sz) - end - local function Shape(shape, x, y) - for _, p in ipairs(shape) do draw_list:PathLineTo(ImVec2(x + math.floor(sz * p[1]), y + math.floor(sz * p[2]))) end - end - - local y = start_pos.y - for row = 0, 3 do - local x = start_pos.x - local draw_fill = (row == 2 or row == 3) - local draw_strokes = (row == 0 or row == 1 or row == 3) - if draw_fill then - -- FILLED SHAPES - local col = ImGui.ColorConvertFloat4ToU32(s.colf_fill) - draw_list:AddNgonFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments); x = x + step -- N-gon - draw_list:AddCircleFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments); x = x + step -- Circle - draw_list:AddEllipseFilled(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments); x = x + step -- Ellipse - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x = x + step -- Square - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding); x = x + step -- Square with all rounded corners - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br); x = x + step -- Square with two rounded corners - draw_list:AddTriangleFilled(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col); x = x + step -- Triangle - draw_list:AddTriangleFilled(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col); x = x + step - math.floor(sz * 0.6) -- Thin triangle - - -- Concave shape: U - Shape(concave_shape, x, y); draw_list:PathFillConcave(col); x = x + step - - -- Concave shape: Zig-Zag with sharp angles - Shape(zigzag_shape, x, y); draw_list:PathFillConcave(col); x = x + step - - -- Horizontal/Vertical lines - -- (here for consistency with the strokes section. AddRectFilled() is roughly close to AddLineH(), AddLineV() - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x = x + step - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x = x + step - math.floor(half_sz) - if not (draw_fill and draw_strokes) then - local block_sz, off = 1, 0 - while block_sz < 16 and off + block_sz <= sz do - draw_list:AddRectFilled(ImVec2(x, y + off), ImVec2(x + block_sz, y + off + block_sz), col) - off = off + block_sz + 1 - block_sz = block_sz + 1 - end - end - x = x + step - math.floor(half_sz) - - -- Rotating square - for n = 1, 4 do draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y)) end - draw_list:PathFillConvex(col); x = x + step - - -- Path - draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) - draw_list:PathFillConvex(col); x = x + step - - -- Quadratic Bezier Curve (3 control points) - draw_list:PathLineTo(ImVec2(x + cp3[1].x, y + cp3[1].y)) - draw_list:PathBezierQuadraticCurveTo(ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), curve_segments) - draw_list:PathFillConvex(col); x = x + step - if not (draw_fill and draw_strokes) then - draw_list:AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)) - x = x + step - end - end - if draw_fill and draw_strokes then x = start_pos.x end - if draw_strokes then - -- STROKES - -- First row uses a thickness of 1.0f, second row uses the configurable thickness - local col = ImGui.ColorConvertFloat4ToU32(s.colf_stroke) - local th = (row == 0) and 1.0 or thickness - draw_list:AddNgon(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments, th); x = x + step -- N-gon - draw_list:AddCircle(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments, th); x = x + step -- Circle - draw_list:AddEllipse(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments, th); x = x + step -- Ellipse - draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, th); x = x + step -- Square - draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th); x = x + step -- Square with all rounded corners - draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, corners_tl_br); x = x + step -- Square with two rounded corners - draw_list:AddTriangle(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col, th); x = x + step -- Triangle - draw_list:AddTriangle(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col, th); x = x + step - math.floor(sz * 0.6) -- Thin triangle - - -- Concave shape: U - Shape(concave_shape, x, y); draw_list:PathStroke(col, th, 512 --[[ImDrawFlags.Closed]]); x = x + step - - -- Concave shape: Zig-Zag with sharp angles - Shape(zigzag_shape, x, y); draw_list:PathStroke(col, th, 512 --[[ImDrawFlags.Closed]]); x = x + step - - -- Horizontal/Vertical/Diagonal lines - local off = math.floor(sz * 0.4) - draw_list:AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th) - draw_list:AddLine(ImVec2(x, y + off), ImVec2(x + sz, y + off), col, th); x = x + step - draw_list:AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th) - draw_list:AddLine(ImVec2(x + off, y + sz), ImVec2(x + off, y), col, th); x = x + step - math.floor(half_sz) - if not (draw_fill and draw_strokes) then - draw_list:AddLine(ImVec2(x, y), ImVec2(x + half_sz, y + sz), col, th) - draw_list:AddLine(ImVec2(x, y + sz), ImVec2(x + half_sz, y), col, th) - end - x = x + step - math.floor(half_sz) - - -- Rotating square - for n = 1, 4 do draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y)) end - draw_list:PathStroke(col, th, 512 --[[ImDrawFlags.Closed]]); x = x + step - - -- Path - draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) - draw_list:PathStroke(col, th); x = x + step - - -- Quadratic Bezier Curve (3 control points) - draw_list:AddBezierQuadratic(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), col, th, curve_segments); x = x + step - - -- Cubic Bezier Curve (4 control points) - if not (draw_fill and draw_strokes) then - draw_list:AddBezierCubic(ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), ImVec2(x + cp4[4].x, y + cp4[4].y), col, th, curve_segments) - x = x + step - end - end - y = y + step - end - ImGui.Dummy(ImVec2(step * 15.5, step * 4.0)) - ImGui.Text("ImDrawList Vector Rendering Reference:") - ImGui.TextLinkOpenURL("https://github.com/ocornut/imgui/wiki/Draw-List") - ImGui.PopItemFlag() - ImGui.PopItemWidth() -end - -local function CustomRenderingCanvas() - local s = CRS - _, s.opt_enable_grid = ImGui.Checkbox("Enable grid", s.opt_enable_grid) - _, s.opt_enable_context_menu = ImGui.Checkbox("Enable context menu", s.opt_enable_context_menu) - ImGui.Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.") - - -- Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. - -- Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. - -- To use a child window instead we could use, e.g: - -- ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0, 0)) -- Disable padding - -- ImGui.PushStyleColor(ImGuiCol.ChildBg, IM_COL32(50, 50, 50, 255)) -- Set a background color - -- ImGui.BeginChild("canvas", ImVec2(0.0, 0.0), ImGuiChildFlags.Borders, ImGuiWindowFlags.NoMove) - -- ImGui.PopStyleColor() - -- ImGui.PopStyleVar() - -- [...] - -- ImGui.EndChild() - - -- Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() - local canvas_p0 = ImGui.GetCursorScreenPos() -- ImDrawList API uses screen coordinates! - local canvas_sz = ImGui.GetContentRegionAvail() -- Resize canvas to what's available - if canvas_sz.x < 50.0 then canvas_sz.x = 50.0 end - if canvas_sz.y < 50.0 then canvas_sz.y = 50.0 end - local canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y) - - -- Draw border and background color - local io = ImGui.GetIO() - local draw_list = ImGui.GetWindowDrawList() - draw_list:AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)) - draw_list:AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)) - - -- This will catch our interactions - ImGui.InvisibleButton("canvas", canvas_sz, bit32.bor(1 --[[ImGuiButtonFlags.MouseButtonLeft]], 2 --[[ImGuiButtonFlags.MouseButtonRight]])) - local is_hovered = ImGui.IsItemHovered() -- Hovered - local is_active = ImGui.IsItemActive() -- Held - local origin = ImVec2(canvas_p0.x + s.scrolling.x, canvas_p0.y + s.scrolling.y) -- Lock scrolled origin - local mouse_pos_in_canvas = ImVec2(io.MousePos.x - origin.x, io.MousePos.y - origin.y) - local points = s.points - - -- Add first and second point - if is_hovered and not s.adding_line and ImGui.IsMouseClicked(0 --[[ImGuiMouseButton.Left]]) then - points[#points + 1] = ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y) - points[#points + 1] = ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y) - s.adding_line = true - end - if s.adding_line then - points[#points] = ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y) - if not ImGui.IsMouseDown(0 --[[ImGuiMouseButton.Left]]) then s.adding_line = false end - end - - -- Pan (we use a zero mouse threshold when there's no context menu) - -- You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. - local mouse_threshold_for_pan = s.opt_enable_context_menu and -1.0 or 0.0 - if is_active and ImGui.IsMouseDragging(1 --[[ImGuiMouseButton.Right]], mouse_threshold_for_pan) then - s.scrolling.x = s.scrolling.x + io.MouseDelta.x - s.scrolling.y = s.scrolling.y + io.MouseDelta.y - end - - -- Context menu (under default mouse threshold) - local drag_delta = ImGui.GetMouseDragDelta(1 --[[ImGuiMouseButton.Right]]) - if s.opt_enable_context_menu and drag_delta.x == 0.0 and drag_delta.y == 0.0 then - ImGui.OpenPopupOnItemClick("context", 8 --[[ImGuiPopupFlags.MouseButtonRight]]) - end - if ImGui.BeginPopup("context") then - if s.adding_line then points[#points] = nil; points[#points] = nil end - s.adding_line = false - if ImGui.MenuItem("Remove one", nil, false, #points > 0) then points[#points] = nil; points[#points] = nil end - if ImGui.MenuItem("Remove all", nil, false, #points > 0) then table.clear(points) end - ImGui.EndPopup() - end - - -- Draw grid + all lines in the canvas - draw_list:PushClipRect(canvas_p0, canvas_p1, true) - if s.opt_enable_grid then - local GRID_STEP = 64.0 - local x = math.fmod(s.scrolling.x, GRID_STEP) - while x < canvas_sz.x do draw_list:AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40)); x = x + GRID_STEP end - local y = math.fmod(s.scrolling.y, GRID_STEP) - while y < canvas_sz.y do draw_list:AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40)); y = y + GRID_STEP end - end - for n = 1, #points - 1, 2 do - draw_list:AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0) - end - draw_list:PopClipRect() -end - -- Demonstrate using the low-level ImDrawList to draw custom shapes. +S.ShowExampleAppCustomRendering = { + -- Primitives + sz = 42.0, + base_rounding = 8.0, + base_thickness = 3.0, + animate_rounding = false, + animate_thickness = false, + ngon_segments = 6, + circle_segments_override = false, + circle_segments_override_v = 12, + curve_segments_override = false, + curve_segments_override_v = 8, + colf_stroke = ImVec4(1.000, 0.384, 0.169, 1.000), + colf_fill = ImVec4(0.416, 0.378, 0.420, 1.000), + -- Canvas + points = ImVector(), + scrolling = ImVec2(0.0, 0.0), + opt_enable_grid = true, + opt_enable_context_menu = true, + adding_line = false, + -- BG/FG draw lists + draw_bg = true, + draw_fg = true, +} function ShowExampleAppCustomRendering(p_open) + local s = S.ShowExampleAppCustomRendering local visible p_open, visible = ImGui.Begin("Example: Custom rendering", p_open) - if not visible then ImGui.End(); return p_open end - local s = CRS + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Examples/Custom rendering") + + -- Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of + -- overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your + -- types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not + -- exposed outside (to avoid messing with your types) In this example we are not using the maths operators! + if ImGui.BeginTabBar("##TabBar") then - if ImGui.BeginTabItem("Primitives") then CustomRenderingPrimitives(); ImGui.EndTabItem() end - if ImGui.BeginTabItem("Canvas") then CustomRenderingCanvas(); ImGui.EndTabItem() end + if ImGui.BeginTabItem("Primitives") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/Primitives") + ImGui.PushItemWidth(-ImGui.GetFontSize() * 15) + ImGui.PushItemFlag(384 --[[ImGuiItemFlags.LiveEditOnInput]], true) + local draw_list = ImGui.GetWindowDrawList() + + -- Draw gradients + -- (note that those are currently exacerbating our sRGB/Linear issues) + -- Calling ImGui.GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. + -- [Port] GetColorU32(u32, nil, true): the ImU32 overload is selected explicitly + ImGui.Text("Gradients") + local gradient_size = ImVec2(ImGui.CalcItemWidth(), ImGui.GetFrameHeight()) + do + ImGui.InvisibleButton("##gradient1", gradient_size) + local col_a = ImGui.GetColorU32(IM_COL32(0, 0, 0, 255), nil, true) + local col_b = ImGui.GetColorU32(IM_COL32(255, 255, 255, 255), nil, true) + draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) + end + do + ImGui.InvisibleButton("##gradient2", gradient_size) + local col_a = ImGui.GetColorU32(IM_COL32(0, 255, 0, 255), nil, true) + local col_b = ImGui.GetColorU32(IM_COL32(255, 0, 0, 255), nil, true) + draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) + end + + -- Draw a bunch of primitives + ImGui.Text("All primitives") + + s.sz = ImGui.DragFloat("Size", s.sz, 0.2, 0.2, 100.0, "%.0f") + + local rounding_anim_period = 3.0 + local rounding_wave = 1.0 - math.abs(math.fmod(ImGui.GetTime(), rounding_anim_period) * (2.0 / rounding_anim_period) - 1.0) + local rounding = s.animate_rounding and math.floor(rounding_wave * s.base_rounding * 10.0) / 10.0 or s.base_rounding -- Sub-integer rounding works but has discontinuities in small values, so best disable we + s.base_rounding = ImGui.DragFloat("Rounding", s.base_rounding, 0.02, 0.0, 32.0, "%.1f"); ImGui.SameLine() + _, s.animate_rounding = ImGui.Checkbox("Animate##rounding", s.animate_rounding); ImGui.SameLine() + ImGui.Text("%.2f", rounding) + + local thickness_anim_period = 5.0 + local thickness_wave = 1.0 - math.abs(math.fmod(ImGui.GetTime(), thickness_anim_period) * (2.0 / thickness_anim_period) - 1.0) + local thickness = s.animate_thickness and thickness_wave * s.base_thickness or s.base_thickness + s.base_thickness = ImGui.DragFloat("Thickness", s.base_thickness, 0.02, 0.0, 32.0, "%.02f"); ImGui.SameLine() + _, s.animate_thickness = ImGui.Checkbox("Animate##thickness", s.animate_thickness); ImGui.SameLine() + ImGui.Text("%.2f", thickness) + + local changed + s.ngon_segments = ImGui.SliderInt("N-gon sides", s.ngon_segments, 3, 12) + _, s.circle_segments_override = ImGui.Checkbox("##CircleSegmentOverride", s.circle_segments_override) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + s.circle_segments_override_v, changed = ImGui.SliderInt("Circle segments override", s.circle_segments_override_v, 3, 30) + s.circle_segments_override = s.circle_segments_override or changed + _, s.curve_segments_override = ImGui.Checkbox("##CurvesSegmentOverride", s.curve_segments_override) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + s.curve_segments_override_v, changed = ImGui.SliderInt("Curves segments override", s.curve_segments_override_v, 3, 30) + s.curve_segments_override = s.curve_segments_override or changed + ImGui.ColorEdit4("Stroke Color", s.colf_stroke) + ImGui.ColorEdit4("Fill Color", s.colf_fill) + + -- [Port] ImDrawFlags_StrokeInside/StrokeCenter/StrokeCenterBiased/StrokeOutside/StrokeLegacy, AAFill/AALines/AALineEnds, + -- [Port] JoinMiter/CapSquare, AllowInPushScope_ and ImDrawList::PushDrawFlag()/PopDrawFlag() don't exist in this port + -- [Port] (1.92 stroker): prim_stroke_flags/prim_other_flags/scope_flags and their widgets are not ported, flags = None. + ImGui.SeparatorText("Per primitive flags (AddXXX functions)") + ImGui.TextDisabled("(not supported by this port)") -- [Port] + --ImGui.CheckboxFlags("UseTexForRoundCorners", &prim_other_flags, ImDrawFlags_UseTexForRoundCorners); + + ImGui.SeparatorText("Current ImDrawList flags (e.g. PushDrawFlag function)") + ImGui.PushID("ScopeFlags") + ImGui.TextDisabled("(not supported by this port)") -- [Port] + --ImGui.CheckboxFlags("UseTexForRoundCorners", &scope_flags, ImDrawFlags_UseTexForRoundCorners); + ImGui.PopID() + ImGui.Spacing() + + -- [Port] draw_list->PushDrawFlag(ImDrawFlags_AllowInPushScope_, false); // Reset all existing (very unusual: done for this demo) + -- [Port] draw_list->PushDrawFlag(scope_flags, true); + local flags = 0 --[[ImDrawFlags.None]] -- [Port] prim_stroke_flags | prim_other_flags + + -- [Port] In this port AddNgon/AddCircle/AddEllipse/AddTriangle/AddLine*/AddBezier*/PathFillConvex take no flags argument (dropped below). + local sz = s.sz + local start_pos = ImGui.GetCursorScreenPos() + local pi = 3.141592 + local step = sz + 10.0 + local corners_tl_br = bit32.bor(16 --[[ImDrawFlags.RoundCornersTopLeft]], 128 --[[ImDrawFlags.RoundCornersBottomRight]]) -- [Port] 1.92 names (upstream ImDrawFlags_RoundTopLeft/RoundBottomRight) + local half_sz = sz * 0.5 + local circle_segments = s.circle_segments_override and s.circle_segments_override_v or 0 + local curve_segments = s.curve_segments_override and s.curve_segments_override_v or 0 + local cp3 = { ImVec2(0.0, sz * 0.6), ImVec2(sz * 0.5, -sz * 0.4), ImVec2(sz, sz) } -- Control points for curves + local cp4 = { ImVec2(0.0, 0.0), ImVec2(sz * 1.3, sz * 0.3), ImVec2(sz - sz * 1.3, sz - sz * 0.3), ImVec2(sz, sz) } + local concave_shape = { ImVec2(0.0, 0.0), ImVec2(0.3, 0.0), ImVec2(0.3, 0.7), ImVec2(0.7, 0.7), ImVec2(0.7, 0.0), ImVec2(1.0, 0.0), ImVec2(1.0, 1.0), ImVec2(0.0, 1.0) } -- |_| looking shape. Normalized. + local zigzag_shape = { ImVec2(0.0, 0.0), ImVec2(0.9, 0.0), ImVec2(1.0, 0.1), ImVec2(1.0, 0.9), ImVec2(0.9, 1.0), ImVec2(0.3, 1.0), ImVec2(0.3, 0.4), ImVec2(0.9, 0.4) } + local rotating_square = {} -- 1-based + for side = 0, 4 - 1 do + local t = ImGui.GetTime() * 0.1 + side * pi * 0.5 + rotating_square[side + 1] = ImVec2(math.cos(t) * half_sz, math.sin(t) * half_sz) + end + + local x = start_pos.x + local y = start_pos.y + for row = 0, 4 - 1 do + x = start_pos.x + local draw_fill = (row == 2 or row == 3) + local draw_strokes = (row == 0 or row == 1 or row == 3) + if draw_fill then + -- FILLED SHAPES + local col = ImColor(s.colf_fill):U32() + draw_list:AddNgonFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments); x = x + step -- N-gon + draw_list:AddCircleFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments); x = x + step -- Circle + draw_list:AddEllipseFilled(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments); x = x + step -- Ellipse + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, flags); x = x + step -- Square + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, flags); x = x + step -- Square with all rounded corners + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, bit32.bor(flags, corners_tl_br)); x = x + step -- Square with two rounded corners + draw_list:AddTriangleFilled(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col); x = x + step -- Triangle + draw_list:AddTriangleFilled(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col); x = x + step - math.floor(sz * 0.6) -- Thin triangle + + -- Concave shape: U + for _, p in ipairs(concave_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathFillConcave(col) + x = x + step + + -- Concave shape: Zig-Zag with sharp angles (see difference with/without JoinMiter) + for _, p in ipairs(zigzag_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathFillConcave(col) + x = x + step + + -- Horizontal/Vertical lines + -- (here for consistency with the strokes section. AddRectFilled() is roughly close to AddLineH(), AddLineV() + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x = x + step + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x = x + step - math.floor(half_sz) + if not (draw_fill and draw_strokes) then -- -V560 + local block_sz, off = 1, 0 + while block_sz < 16 and off + block_sz <= sz do + draw_list:AddRectFilled(ImVec2(x, y + off), ImVec2(x + block_sz, y + off + block_sz), col) + off = off + block_sz + 1; block_sz = block_sz + 1 + end + end + x = x + step - math.floor(half_sz) + + -- Rotating square + for n = 0, 4 - 1 do + draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n + 1].x, y + half_sz + rotating_square[n + 1].y)) + end + draw_list:PathFillConvex(col) -- [Port] no flags argument + x = x + step + + -- Path + draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) + draw_list:PathFillConvex(col) + x = x + step + + -- Quadratic Bezier Curve (3 control points) + draw_list:PathLineTo(ImVec2(x + cp3[1].x, y + cp3[1].y)) + draw_list:PathBezierQuadraticCurveTo(ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), curve_segments) + draw_list:PathFillConvex(col) + x = x + step + + if not (draw_fill and draw_strokes) then -- -V560 + draw_list:AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)) + x = x + step + end + end + if draw_fill and draw_strokes then + x = start_pos.x + end + if draw_strokes then + -- STROKES + -- First row uses a thickness of 1.0f, second row uses the configurable thickness + local col = ImColor(s.colf_stroke):U32() + local th = (row == 0) and 1.0 or thickness + draw_list:AddNgon(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments, th); x = x + step -- N-gon + draw_list:AddCircle(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments, th); x = x + step -- Circle + draw_list:AddEllipse(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments, th); x = x + step -- Ellipse + draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, th, flags); x = x + step -- Square + draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, flags); x = x + step -- Square with all rounded corners + draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, bit32.bor(flags, corners_tl_br)); x = x + step -- Square with two rounded corners + draw_list:AddTriangle(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col, th); x = x + step -- Triangle + draw_list:AddTriangle(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col, th); x = x + step - math.floor(sz * 0.6) -- Thin triangle + + -- Concave shape: U + for _, p in ipairs(concave_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathStroke(col, th, bit32.bor(flags, 512 --[[ImDrawFlags.Closed]])) + x = x + step + + -- Concave shape: Zig-Zag with sharp angles (see difference with/without JoinMiter) + for _, p in ipairs(zigzag_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathStroke(col, th, bit32.bor(flags, 512 --[[ImDrawFlags.Closed]])) + x = x + step + + -- Horizontal/Vertical/Diagonal lines + local off = math.floor(sz * 0.4) + draw_list:AddLineH(x, x + sz, y, col, th) + draw_list:AddLine(ImVec2(x, y + off), ImVec2(x + sz, y + off), col, th) + x = x + step + draw_list:AddLineV(x, y, y + sz, col, th) + draw_list:AddLine(ImVec2(x + off, y + sz), ImVec2(x + off, y), col, th) + x = x + step - math.floor(half_sz) + if not (draw_fill and draw_strokes) then -- -V560 + draw_list:AddLine(ImVec2(x, y), ImVec2(x + half_sz, y + sz), col, th) + draw_list:AddLine(ImVec2(x, y + sz), ImVec2(x + half_sz, y), col, th) + end + x = x + step - math.floor(half_sz) + + -- Rotating square + for n = 0, 4 - 1 do + draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n + 1].x, y + half_sz + rotating_square[n + 1].y)) + end + draw_list:PathStroke(col, th, bit32.bor(flags, 512 --[[ImDrawFlags.Closed]])) + --for (int n = 0; n < 4; n++) // ...made of individual line + -- draw_list->AddLine({ x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y }, { x + half_sz + rotating_square[(n + 1) & 3].x, y + half_sz + rotating_square[(n + 1) & 3].y }, col, th, flags); + x = x + step + + -- Path + draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) + draw_list:PathStroke(col, th, flags) + x = x + step + + -- Quadratic Bezier Curve (3 control points) + draw_list:AddBezierQuadratic(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), col, th, curve_segments) + x = x + step + + -- Cubic Bezier Curve (4 control points) + if not (draw_fill and draw_strokes) then -- -V560 + draw_list:AddBezierCubic(ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), ImVec2(x + cp4[4].x, y + cp4[4].y), col, th, curve_segments) + x = x + step + end + end + y = y + step + end + + ImGui.Dummy(ImVec2(step * 15.5, step * 4.0)) + -- [Port] draw_list->PopDrawFlag(); x2 + + ImGui.Text("ImDrawList Vector Rendering Reference:") + ImGui.TextLinkOpenURL("https://github.com/ocornut/imgui/wiki/Draw-List") + + ImGui.PopItemFlag() + ImGui.PopItemWidth() + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Canvas") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/Canvas") + local points = s.points + local scrolling = s.scrolling + + _, s.opt_enable_grid = ImGui.Checkbox("Enable grid", s.opt_enable_grid) + _, s.opt_enable_context_menu = ImGui.Checkbox("Enable context menu", s.opt_enable_context_menu) + ImGui.Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.") + + -- Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. + -- Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. + -- To use a child window instead we could use, e.g: + -- ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0, 0)) -- Disable padding + -- ImGui.PushStyleColor(ImGuiCol.ChildBg, IM_COL32(50, 50, 50, 255)) -- Set a background color + -- ImGui.BeginChild("canvas", ImVec2(0.0, 0.0), ImGuiChildFlags.Borders, ImGuiWindowFlags.NoMove) + -- ImGui.PopStyleColor() + -- ImGui.PopStyleVar() + -- [...] + -- ImGui.EndChild() + + -- Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() + local canvas_p0 = ImGui.GetCursorScreenPos() -- ImDrawList API uses screen coordinates! + local canvas_sz = ImGui.GetContentRegionAvail() -- Resize canvas to what's available + if canvas_sz.x < 50.0 then canvas_sz.x = 50.0 end + if canvas_sz.y < 50.0 then canvas_sz.y = 50.0 end + local canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y) + + -- Draw border and background color + local io = ImGui.GetIO() + local draw_list = ImGui.GetWindowDrawList() + draw_list:AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)) + draw_list:AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)) + + -- This will catch our interactions + ImGui.InvisibleButton("canvas", canvas_sz, bit32.bor(1 --[[ImGuiButtonFlags.MouseButtonLeft]], 2 --[[ImGuiButtonFlags.MouseButtonRight]])) + local is_hovered = ImGui.IsItemHovered() -- Hovered + local is_active = ImGui.IsItemActive() -- Held + local origin = ImVec2(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y) -- Lock scrolled origin + local mouse_pos_in_canvas = ImVec2(io.MousePos.x - origin.x, io.MousePos.y - origin.y) + + -- Add first and second point + if is_hovered and not s.adding_line and ImGui.IsMouseClicked(0 --[[ImGuiMouseButton.Left]]) then + points:push_back(ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y)) -- [Port] copies: ImVector stores references + points:push_back(ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y)) + s.adding_line = true + end + if s.adding_line then + ImVec2_Copy(points:back(), mouse_pos_in_canvas) + if not ImGui.IsMouseDown(0 --[[ImGuiMouseButton.Left]]) then + s.adding_line = false + end + end + + -- Pan (we use a zero mouse threshold when there's no context menu) + -- You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. + local mouse_threshold_for_pan = s.opt_enable_context_menu and -1.0 or 0.0 + if is_active and ImGui.IsMouseDragging(1 --[[ImGuiMouseButton.Right]], mouse_threshold_for_pan) then + scrolling.x = scrolling.x + io.MouseDelta.x + scrolling.y = scrolling.y + io.MouseDelta.y + end + + -- Context menu (under default mouse threshold) + local drag_delta = ImGui.GetMouseDragDelta(1 --[[ImGuiMouseButton.Right]]) + if s.opt_enable_context_menu and drag_delta.x == 0.0 and drag_delta.y == 0.0 then + ImGui.OpenPopupOnItemClick("context", 8 --[[ImGuiPopupFlags.MouseButtonRight]]) + end + if ImGui.BeginPopup("context") then + if s.adding_line then + points:resize(points.Size - 2) + end + s.adding_line = false + if ImGui.MenuItem("Remove one", nil, false, points.Size > 0) then points:resize(points.Size - 2) end + if ImGui.MenuItem("Remove all", nil, false, points.Size > 0) then points:clear() end + ImGui.EndPopup() + end + + -- Draw grid + all lines in the canvas + draw_list:PushClipRect(canvas_p0, canvas_p1, true) + if s.opt_enable_grid then + local GRID_STEP = 64.0 + local x = math.fmod(scrolling.x, GRID_STEP) + while x < canvas_sz.x do + draw_list:AddLineV(canvas_p0.x + x, canvas_p0.y, canvas_p1.y, IM_COL32(200, 200, 200, 40)) + x = x + GRID_STEP + end + local y = math.fmod(scrolling.y, GRID_STEP) + while y < canvas_sz.y do + draw_list:AddLineH(canvas_p0.x, canvas_p1.x, canvas_p0.y + y, IM_COL32(200, 200, 200, 40)) + y = y + GRID_STEP + end + end + for n = 0, points.Size - 1, 2 do + draw_list:AddLine(ImVec2(origin.x + points.Data[n + 1].x, origin.y + points.Data[n + 1].y), ImVec2(origin.x + points.Data[n + 2].x, origin.y + points.Data[n + 2].y), IM_COL32(255, 255, 0, 255), 2.0) + end + draw_list:PopClipRect() + + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("BG/FG draw lists") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/BG & FG draw lists") _, s.draw_bg = ImGui.Checkbox("Draw in Background draw list", s.draw_bg) ImGui.SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.") _, s.draw_fg = ImGui.Checkbox("Draw in Foreground draw list", s.draw_fg) ImGui.SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.") - local window_pos, window_size = ImGui.GetWindowPos(), ImGui.GetWindowSize() + local window_pos = ImGui.GetWindowPos() + local window_size = ImGui.GetWindowSize() local window_center = ImVec2(window_pos.x + window_size.x * 0.5, window_pos.y + window_size.y * 0.5) - if s.draw_bg then ImGui.GetBackgroundDrawList():AddCircle(window_center, window_size.x * 0.6, IM_COL32(255, 0, 0, 200), 0, 10 + 4) end - if s.draw_fg then ImGui.GetForegroundDrawList():AddCircle(window_center, window_size.y * 0.6, IM_COL32(0, 255, 0, 200), 0, 10) end + if s.draw_bg then + ImGui.GetBackgroundDrawList():AddCircle(window_center, window_size.x * 0.6, IM_COL32(255, 0, 0, 200), 0, 10 + 4) + end + if s.draw_fg then + ImGui.GetForegroundDrawList():AddCircle(window_center, window_size.y * 0.6, IM_COL32(0, 255, 0, 200), 0, 10) + end ImGui.EndTabItem() end @@ -27081,35 +31358,42 @@ function ShowExampleAppCustomRendering(p_open) -- We use functions in ImDrawList as each draw list contains a convenience splitter, -- but you can also instantiate your own ImDrawListSplitter if you need to nest them. if ImGui.BeginTabItem("Draw Channels") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/Draw Channels") local draw_list = ImGui.GetWindowDrawList() - ImGui.Text("Blue shape is drawn first: appears in back") - ImGui.Text("Red shape is drawn after: appears in front") - local p0 = ImGui.GetCursorScreenPos() - draw_list:AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue - draw_list:AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)) -- Red - ImGui.Dummy(ImVec2(75, 75)) + do + ImGui.Text("Blue shape is drawn first: appears in back") + ImGui.Text("Red shape is drawn after: appears in front") + local p0 = ImGui.GetCursorScreenPos() + draw_list:AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue + draw_list:AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)) -- Red + ImGui.Dummy(ImVec2(75, 75)) + end ImGui.Separator() - ImGui.Text("Blue shape is drawn first, into channel 1: appears in front") - ImGui.Text("Red shape is drawn after, into channel 0: appears in back") - local p1 = ImGui.GetCursorScreenPos() + do + ImGui.Text("Blue shape is drawn first, into channel 1: appears in front") + ImGui.Text("Red shape is drawn after, into channel 0: appears in back") + local p1 = ImGui.GetCursorScreenPos() - -- Create 2 channels and draw a Blue shape THEN a Red shape. - -- You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls. - draw_list:ChannelsSplit(2) - draw_list:ChannelsSetCurrent(1) - draw_list:AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue - draw_list:ChannelsSetCurrent(0) - draw_list:AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)) -- Red + -- Create 2 channels and draw a Blue shape THEN a Red shape. + -- You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls. + draw_list:ChannelsSplit(2) + draw_list:ChannelsSetCurrent(1) + draw_list:AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue + draw_list:ChannelsSetCurrent(0) + draw_list:AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)) -- Red - -- Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1. - -- This works by copying draw indices only (vertices are not copied). - draw_list:ChannelsMerge() - ImGui.Dummy(ImVec2(75, 75)) - ImGui.Text("After reordering, contents of channel 0 appears below channel 1.") + -- Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1. + -- This works by copying draw indices only (vertices are not copied). + draw_list:ChannelsMerge() + ImGui.Dummy(ImVec2(75, 75)) + ImGui.Text("After reordering, contents of channel 0 appears below channel 1.") + end ImGui.EndTabItem() end + ImGui.EndTabBar() end + ImGui.End() return p_open end @@ -27118,14 +31402,19 @@ end -- [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() ------------------------------------------------------------------------------- --- KeepWindowPadding: Keep WindowPadding to help understand that DockSpace() is a widget inside the window. -local DSA = { IsFullscreen = true, KeepWindowPadding = false, DockSpaceFlags = 0, opt_demo_mode = 0, opt_demo_mode_changed = false } +function ImGuiDemoDockspaceArgs() + return { + IsFullscreen = true, + KeepWindowPadding = false, -- Keep WindowPadding to help understand that DockSpace() is a widget inside the window. + DockSpaceFlags = 0 --[[ImGuiDockNodeFlags.None]], + } +end -- THIS IS A DEMO FOR ADVANCED USAGE OF DockSpace(). -- MOST REGULAR APPLICATIONS WANTING TO ALLOW DOCKING WINDOWS ON THE EDGE OF YOUR SCREEN CAN SIMPLY USE: --- ImGui.NewFrame() + ImGui.DockSpaceOverViewport() -- Create a dockspace in main viewport +-- ImGui.NewFrame(); + ImGui.DockSpaceOverViewport(); -- Create a dockspace in main viewport -- OR: --- ImGui.NewFrame() + ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode) -- Create a dockspace in main viewport, where central node is transparent. +-- ImGui.NewFrame(); + ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode); -- Create a dockspace in main viewport, where central node is transparent. -- Demonstrate using DockSpace() to create an explicit docking node within an existing window, with various options. -- Read https://github.com/ocornut/imgui/wiki/Docking for details. -- The reasons we do not use DockSpaceOverViewport() in this demo is because: @@ -27134,22 +31423,23 @@ local DSA = { IsFullscreen = true, KeepWindowPadding = false, DockSpaceFlags = 0 -- Also see 'Demo->Examples->Documents' for a less abstract version of this. -- - (2) we allow the host window to have padding (when args.UsePadding == true) -- - (3) we expose variety of other flags. -local function ShowExampleAppDockSpaceAdvanced(args, p_open) +function ShowExampleAppDockSpaceAdvanced(args, p_open) local dockspace_flags = args.DockSpaceFlags - -- We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, + -- We are using the ImGuiWindowFlags.NoDocking flag to make the parent window not dockable into, -- because it would be confusing to have two docking targets within each others. - local W = ImGuiWindowFlags - local window_flags = W.NoDocking + local window_flags = 524288 --[[ImGuiWindowFlags.NoDocking]] if args.IsFullscreen then - -- Fullscreen dockspace: practically the same as calling DockSpaceOverViewport() + -- Fullscreen dockspace: practically the same as calling DockSpaceOverViewport(); local viewport = ImGui.GetMainViewport() ImGui.SetNextWindowPos(viewport.WorkPos) ImGui.SetNextWindowSize(viewport.WorkSize) ImGui.SetNextWindowViewport(viewport.ID) ImGui.PushStyleVar(3 --[[ImGuiStyleVar.WindowRounding]], 0.0) ImGui.PushStyleVar(4 --[[ImGuiStyleVar.WindowBorderSize]], 0.0) - window_flags = bit32.bor(window_flags, W.NoTitleBar, W.NoCollapse, W.NoResize, W.NoMove, W.NoBringToFrontOnFocus, W.NoNavFocus, W.NoBackground) + window_flags = bit32.bor(window_flags, 1 --[[ImGuiWindowFlags.NoTitleBar]], 32 --[[ImGuiWindowFlags.NoCollapse]], 2 --[[ImGuiWindowFlags.NoResize]], 4 --[[ImGuiWindowFlags.NoMove]]) + window_flags = bit32.bor(window_flags, 8192 --[[ImGuiWindowFlags.NoBringToFrontOnFocus]], 131072 --[[ImGuiWindowFlags.NoNavFocus]]) + window_flags = bit32.bor(window_flags, 128 --[[ImGuiWindowFlags.NoBackground]]) else -- Floating dockspace dockspace_flags = bit32.band(dockspace_flags, bit32.bnot(8 --[[ImGuiDockNodeFlags.PassthruCentralNode]])) @@ -27160,70 +31450,102 @@ local function ShowExampleAppDockSpaceAdvanced(args, p_open) -- all active windows docked into it will lose their parent and become undocked. -- We cannot preserve the docking relationship between an active window and an inactive docking, otherwise -- any change of dockspace/settings would lead to windows being stuck in limbo and never being visible. - if not args.KeepWindowPadding then ImGui.PushStyleVar(2 --[[ImGuiStyleVar.WindowPadding]], ImVec2(0.0, 0.0)) end + if not args.KeepWindowPadding then + ImGui.PushStyleVar(2 --[[ImGuiStyleVar.WindowPadding]], ImVec2(0.0, 0.0)) + end p_open = ImGui.Begin("Window with a DockSpace", p_open, window_flags) - if not args.KeepWindowPadding then ImGui.PopStyleVar() end + if not args.KeepWindowPadding then + ImGui.PopStyleVar() + end - if args.IsFullscreen then ImGui.PopStyleVar(2) end + if args.IsFullscreen then + ImGui.PopStyleVar(2) + end -- Submit the DockSpace widget inside our window -- - Note that the id here is different from the one used by DockSpaceOverViewport(), so docking state won't get transfered between "Basic" and "Advanced" demos. -- - If we made the ShowExampleAppDockSpaceBasic() calculate its own ID and pass it to DockSpaceOverViewport() the ID could easily match. local dockspace_id = ImGui.GetID("MyDockSpace") ImGui.DockSpace(dockspace_id, ImVec2(0.0, 0.0), dockspace_flags) + ImGui.End() return p_open end +function ShowExampleAppDockSpaceBasic(flags) + -- Basic version which you can use in many apps: + -- e.g: + -- ImGui.DockSpaceOverViewport(); + -- or: + -- ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode); -- Central node will be transparent + -- or: + -- local viewport = ImGui.GetMainViewport(); + -- ImGui.DockSpaceOverViewport(0, viewport, ImGuiDockNodeFlags.None); + + ImGui.DockSpaceOverViewport(0, nil, flags) +end + +S.ShowExampleAppDockSpace = { + opt_demo_mode = 0, + opt_demo_mode_changed = false, + args = ImGuiDemoDockspaceArgs(), +} function ShowExampleAppDockSpace(p_open) - local args = DSA - if args.opt_demo_mode == 0 then - -- Basic version which you can use in many apps: - -- e.g: - -- ImGui.DockSpaceOverViewport() - -- or: - -- ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode) -- Central node will be transparent - -- or: - -- local viewport = ImGui.GetMainViewport() - -- ImGui.DockSpaceOverViewport(0, viewport, ImGuiDockNodeFlags.None) - ImGui.DockSpaceOverViewport(0, nil, args.DockSpaceFlags) + local s = S.ShowExampleAppDockSpace + local args = s.args + + if s.opt_demo_mode == 0 then + ShowExampleAppDockSpaceBasic(args.DockSpaceFlags) else p_open = ShowExampleAppDockSpaceAdvanced(args, p_open) end -- Refocus our window to minimize perceived loss of focus when changing mode (caused by the fact that each use a different window, which would not happen in a real app) - if args.opt_demo_mode_changed then ImGui.SetNextWindowFocus() end + if s.opt_demo_mode_changed then + ImGui.SetNextWindowFocus() + end p_open = ImGui.Begin("Examples: Dockspace", p_open, 1024 --[[ImGuiWindowFlags.MenuBar]]) - local c1, c2 - c1, args.opt_demo_mode = ImGui.RadioButton("Basic demo mode", args.opt_demo_mode, 0) - c2, args.opt_demo_mode = ImGui.RadioButton("Advanced demo mode", args.opt_demo_mode, 1) - args.opt_demo_mode_changed = c1 or c2 + s.opt_demo_mode_changed = false + local pressed + pressed, s.opt_demo_mode = ImGui.RadioButton("Basic demo mode", s.opt_demo_mode, 0) + s.opt_demo_mode_changed = s.opt_demo_mode_changed or pressed + pressed, s.opt_demo_mode = ImGui.RadioButton("Advanced demo mode", s.opt_demo_mode, 1) + s.opt_demo_mode_changed = s.opt_demo_mode_changed or pressed + ImGui.SeparatorText("Options") - local D = ImGuiDockNodeFlags + if bit32.band(ImGui.GetIO().ConfigFlags, 128 --[[ImGuiConfigFlags.DockingEnable]]) == 0 then ShowDockingDisabledMessage() - elseif args.opt_demo_mode == 0 then - args.DockSpaceFlags = bit32.band(args.DockSpaceFlags, D.PassthruCentralNode) -- Allowed flags - _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, D.PassthruCentralNode) - else + elseif s.opt_demo_mode == 0 then + args.DockSpaceFlags = bit32.band(args.DockSpaceFlags, 8 --[[ImGuiDockNodeFlags.PassthruCentralNode]]) -- Allowed flags + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, 8 --[[ImGuiDockNodeFlags.PassthruCentralNode]]) + elseif s.opt_demo_mode == 1 then _, args.IsFullscreen = ImGui.Checkbox("Fullscreen", args.IsFullscreen) _, args.KeepWindowPadding = ImGui.Checkbox("Keep Window Padding", args.KeepWindowPadding) ImGui.SameLine() HelpMarker("This is mostly exposed to facilitate understanding that a DockSpace() is _inside_ a window.") ImGui.BeginDisabled(args.IsFullscreen == false) - _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, D.PassthruCentralNode) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, 8 --[[ImGuiDockNodeFlags.PassthruCentralNode]]) ImGui.EndDisabled() - for _, n in ipairs({ "NoDockingOverCentralNode", "NoDockingSplit", "NoUndocking", "NoResize", "AutoHideTabBar" }) do - if D[n] then _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: " .. n, args.DockSpaceFlags, D[n]) end - end + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoDockingOverCentralNode", args.DockSpaceFlags, 4 --[[ImGuiDockNodeFlags.NoDockingOverCentralNode]]) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoDockingSplit", args.DockSpaceFlags, 16 --[[ImGuiDockNodeFlags.NoDockingSplit]]) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoUndocking", args.DockSpaceFlags, 128 --[[ImGuiDockNodeFlags.NoUndocking]]) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoResize", args.DockSpaceFlags, 32 --[[ImGuiDockNodeFlags.NoResize]]) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: AutoHideTabBar", args.DockSpaceFlags, 64 --[[ImGuiDockNodeFlags.AutoHideTabBar]]) end -- Show demo options and help if ImGui.BeginMenuBar() then if ImGui.BeginMenu("Help") then - ImGui.TextUnformatted("This demonstrates the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window.\nThe \"Basic\" version uses the ImGui::DockSpaceOverViewport() helper. Most applications can probably use this.") + ImGui.TextUnformatted( + "This demonstrates the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window." .. "\n" .. + "The \"Basic\" version uses the ImGui::DockSpaceOverViewport() helper. Most applications can probably use this.") ImGui.Separator() - ImGui.TextUnformatted("When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!\n- Drag from window title bar or their tab to dock/undock.\n- Drag from window menu button (upper-left button) to undock an entire node (all windows).\n- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)\n- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)") + ImGui.TextUnformatted("When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" .. "\n" .. + "- Drag from window title bar or their tab to dock/undock." .. "\n" .. + "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." .. "\n" .. + "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" .. "\n" .. + "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)") ImGui.Separator() ImGui.TextUnformatted("More details:"); ImGui.Bullet(); ImGui.SameLine(); ImGui.TextLinkOpenURL("Docking Wiki page", "https://github.com/ocornut/imgui/wiki/Docking") ImGui.BulletText("Read comments in ShowExampleAppDockSpace()") @@ -27231,6 +31553,7 @@ function ShowExampleAppDockSpace(p_open) end ImGui.EndMenuBar() end + ImGui.End() return p_open end @@ -27240,93 +31563,139 @@ end ------------------------------------------------------------------------------- -- Simplified structure to mimic a Document model --- NameBuf: Document title --- UID: Unique ID (necessary as we can change title) --- Open: Set when open (we keep an array of all available documents to simplify demo code!) --- OpenPrev: Copy of Open from last update. --- Dirty: Set when the document has been modified --- Color: An arbitrary variable associated to the document -local function MyDocument(uid, name, open, color) +-- Name Document title -- [Port] char[32] text buffer, read with ImGui.TextBufferToString() +-- UID Unique ID (necessary as we can change title) +-- Open Set when open (we keep an array of all available documents to simplify demo code!) +-- OpenPrev Copy of Open from last update. +-- Dirty Set when the document has been modified +-- Color An arbitrary variable associated to the document +local MyDocumentMT = {} +MyDocumentMT.__index = MyDocumentMT +function MyDocument(uid, name, open, color) if open == nil then open = true end - local d = { UID = uid, NameBuf = Buf(name, 32), Open = open, OpenPrev = open, Dirty = false, Color = color or ImVec4(1.0, 1.0, 1.0, 1.0) } - function d:Name() return BufStr(self.NameBuf) end - function d:DoOpen() self.Open = true end - function d:DoForceClose() self.Open = false; self.Dirty = false end - function d:DoSave() self.Dirty = false end - return d + if color == nil then color = ImVec4(1.0, 1.0, 1.0, 1.0) end + local self = setmetatable({}, MyDocumentMT) + self.UID = uid + self.Name = ImGui.NewTextBuffer(name, 32) + self.Open = open; self.OpenPrev = open + self.Dirty = false + self.Color = color + return self +end +function MyDocumentMT:DoOpen() self.Open = true end +function MyDocumentMT:DoForceClose() self.Open = false; self.Dirty = false end +function MyDocumentMT:DoSave() self.Dirty = false end + +local ExampleAppDocumentsMT = {} +ExampleAppDocumentsMT.__index = ExampleAppDocumentsMT +function ExampleAppDocuments() + local self = setmetatable({}, ExampleAppDocumentsMT) + self.Documents = ImVector() + self.CloseQueue = ImVector() + self.RenamingDoc = nil + self.RenamingStarted = false + + self.Documents:push_back(MyDocument(0, "Lettuce", true, ImVec4(0.4, 0.8, 0.4, 1.0))) + self.Documents:push_back(MyDocument(1, "Eggplant", true, ImVec4(0.8, 0.5, 1.0, 1.0))) + self.Documents:push_back(MyDocument(2, "Carrot", true, ImVec4(1.0, 0.8, 0.5, 1.0))) + self.Documents:push_back(MyDocument(3, "Tomato", false, ImVec4(1.0, 0.3, 0.4, 1.0))) + self.Documents:push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4, 0.8, 0.8, 1.0))) + self.Documents:push_back(MyDocument(5, "Some Document", false, ImVec4(0.8, 0.8, 1.0, 1.0))) + return self end -local Docs = nil -local function DocsInit() - local app = { Documents = { - MyDocument(0, "Lettuce", true, ImVec4(0.4, 0.8, 0.4, 1.0)), - MyDocument(1, "Eggplant", true, ImVec4(0.8, 0.5, 1.0, 1.0)), - MyDocument(2, "Carrot", true, ImVec4(1.0, 0.8, 0.5, 1.0)), - MyDocument(3, "Tomato", false, ImVec4(1.0, 0.3, 0.4, 1.0)), - MyDocument(4, "A Rather Long Title", false, ImVec4(0.4, 0.8, 0.8, 1.0)), - MyDocument(5, "Some Document", false, ImVec4(0.8, 0.8, 1.0, 1.0)), - }, CloseQueue = {}, RenamingDoc = nil, RenamingStarted = false, - opt_target = 1, opt_reorderable = true, opt_fitting_flags = 128 --[[ImGuiTabBarFlags.FittingPolicyDefault_]] } - function app:QueueClose(doc) - for _, d in ipairs(self.CloseQueue) do if d == doc then return end end - self.CloseQueue[#self.CloseQueue + 1] = doc - end - -- As we allow to change document name, we append a never-changing document ID so tabs are stable - function app:GetTabName(doc) return string.format("%s###doc%d", doc:Name(), doc.UID) end - -- Display placeholder contents for the Document - function app:DisplayDocContents(doc) - ImGui.PushID("doc" .. doc.UID) - ImGui.Text("Document \"%s\"", doc:Name()) - ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], doc.Color) - ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") - ImGui.PopStyleColor() +-- As we allow to change document name, we append a never-changing document ID so tabs are stable +function ExampleAppDocumentsMT:GetTabName(doc) -- [Port] returns the string instead of filling out_buf + return string.format("%s###doc%d", ImGui.TextBufferToString(doc.Name), doc.UID) +end - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 563 --[[ImGuiKey.R]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - if ImGui.Button("Rename..") then self.RenamingDoc = doc; self.RenamingStarted = true end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 558 --[[ImGuiKey.M]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - if ImGui.Button("Modify") then doc.Dirty = true end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 564 --[[ImGuiKey.S]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - if ImGui.Button("Save") then doc:DoSave() end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 568 --[[ImGuiKey.W]]), 262144 --[[ImGuiInputFlags.Tooltip]]) - if ImGui.Button("Close") then self:QueueClose(doc) end - ImGui.ColorEdit3("color", doc.Color) -- Useful to test drag and drop and hold-dragged-to-open-tab behavior. - ImGui.PopID() +-- Display placeholder contents for the Document +function ExampleAppDocumentsMT:DisplayDocContents(doc) + ImGui.PushID(doc.UID) -- [Port] PushID(doc): no pointer IDs, UID is unique + ImGui.Text("Document \"%s\"", ImGui.TextBufferToString(doc.Name)) + ImGui.PushStyleColor(0 --[[ImGuiCol.Text]], doc.Color) + ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") + ImGui.PopStyleColor() + + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 563 --[[ImGuiKey.R]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + if ImGui.Button("Rename..") then + self.RenamingDoc = doc + self.RenamingStarted = true end - -- Display context menu for the Document - function app:DisplayDocContextMenu(doc) - if not ImGui.BeginPopupContextItem() then return end - if ImGui.MenuItem("Save " .. doc:Name(), "Ctrl+S", false, doc.Open) then doc:DoSave() end - if ImGui.MenuItem("Rename...", "Ctrl+R", false, doc.Open) then self.RenamingDoc = doc end - if ImGui.MenuItem("Close", "Ctrl+W", false, doc.Open) then self:QueueClose(doc) end - ImGui.EndPopup() + ImGui.SameLine() + + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 558 --[[ImGuiKey.M]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + if ImGui.Button("Modify") then + doc.Dirty = true end - -- [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. - -- If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, - -- as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for - -- the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has - -- disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively - -- give the impression of a flicker for one frame. - -- We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. - -- Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags.Reorderable flag. - function app:NotifyOfDocumentsClosedElsewhere() - for _, doc in ipairs(self.Documents) do - if not doc.Open and doc.OpenPrev then ImGui.SetTabItemClosed(doc:Name()) end - doc.OpenPrev = doc.Open + + ImGui.SameLine() + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 564 --[[ImGuiKey.S]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + if ImGui.Button("Save") then + doc:DoSave() + end + + ImGui.SameLine() + ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 568 --[[ImGuiKey.W]]), 262144 --[[ImGuiInputFlags.Tooltip]]) + if ImGui.Button("Close") then + self.CloseQueue:push_back(doc) + end + ImGui.ColorEdit3("color", doc.Color) -- Useful to test drag and drop and hold-dragged-to-open-tab behavior. + ImGui.PopID() +end + +-- Display context menu for the Document +function ExampleAppDocumentsMT:DisplayDocContextMenu(doc) + if not ImGui.BeginPopupContextItem() then + return + end + + local buf = string.format("Save %s", ImGui.TextBufferToString(doc.Name)) + if ImGui.MenuItem(buf, "Ctrl+S", false, doc.Open) then + doc:DoSave() + end + if ImGui.MenuItem("Rename...", "Ctrl+R", false, doc.Open) then + self.RenamingDoc = doc + end + if ImGui.MenuItem("Close", "Ctrl+W", false, doc.Open) then + self.CloseQueue:push_back(doc) + end + ImGui.EndPopup() +end + +-- [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. +-- If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, +-- as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for +-- the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has +-- disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively +-- give the impression of a flicker for one frame. +-- We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. +-- Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags.Reorderable flag. +function ExampleAppDocumentsMT:NotifyOfDocumentsClosedElsewhere() + for _, doc in self.Documents:iter() do + if not doc.Open and doc.OpenPrev then + ImGui.SetTabItemClosed(ImGui.TextBufferToString(doc.Name)) end + doc.OpenPrev = doc.Open end - return app end +S.ShowExampleAppDocuments = { + app = ExampleAppDocuments(), + opt_target = nil, -- set below to Target_Tab + opt_reorderable = true, + opt_fitting_flags = nil, -- set below to ImGuiTabBarFlags.FittingPolicyDefault_ +} function ShowExampleAppDocuments(p_open) - Docs = Docs or DocsInit() - local app = Docs + local s = S.ShowExampleAppDocuments + local app = s.app + -- Options - -- Target_Tab: Create documents as local tab into a local tab bar - -- Target_DockSpaceAndWindow: Create documents as regular windows, and create an embedded dockspace - local Target_Tab, Target_DockSpaceAndWindow = 1, 2 + local Target_None = 0 + local Target_Tab = 1 -- Create documents as local tab into a local tab bar + local Target_DockSpaceAndWindow = 2 -- Create documents as regular windows, and create an embedded dockspace + if s.opt_target == nil then s.opt_target = Target_Tab end + if s.opt_fitting_flags == nil then s.opt_fitting_flags = 128 --[[ImGuiTabBarFlags.FittingPolicyDefault_]] end -- When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant") -- that we emit gets docked into the same spot as the parent window ("Example: Documents"). @@ -27337,46 +31706,64 @@ function ShowExampleAppDocuments(p_open) local window_contents_visible p_open, window_contents_visible = ImGui.Begin("Example: Documents", p_open, 1024 --[[ImGuiWindowFlags.MenuBar]]) - if not window_contents_visible and app.opt_target ~= Target_DockSpaceAndWindow then + if not window_contents_visible and s.opt_target ~= Target_DockSpaceAndWindow then ImGui.End() return p_open end + IMGUI_DEMO_MARKER("Examples/Documents") -- Menu if ImGui.BeginMenuBar() then if ImGui.BeginMenu("File") then local open_count = 0 - for _, doc in ipairs(app.Documents) do if doc.Open then open_count = open_count + 1 end end - if ImGui.BeginMenu("Open", open_count < #app.Documents) then - for _, doc in ipairs(app.Documents) do - if not doc.Open and ImGui.MenuItem(doc:Name()) then doc:DoOpen() end + for _, doc in app.Documents:iter() do + open_count = open_count + (doc.Open and 1 or 0) + end + + if ImGui.BeginMenu("Open", open_count < app.Documents.Size) then + for _, doc in app.Documents:iter() do + if not doc.Open and ImGui.MenuItem(ImGui.TextBufferToString(doc.Name)) then + doc:DoOpen() + end end ImGui.EndMenu() end if ImGui.MenuItem("Close All Documents", nil, false, open_count > 0) then - for _, doc in ipairs(app.Documents) do app:QueueClose(doc) end + for _, doc in app.Documents:iter() do + app.CloseQueue:push_back(doc) + end + end + if ImGui.MenuItem("Exit") and p_open ~= nil then + p_open = false end - if ImGui.MenuItem("Exit") and p_open ~= nil then p_open = false end ImGui.EndMenu() end ImGui.EndMenuBar() end -- [Debug] List documents with one checkbox for each - for doc_n, doc in ipairs(app.Documents) do - if doc_n > 1 then ImGui.SameLine() end - ImGui.PushID("doc" .. doc.UID) + for doc_n = 0, app.Documents.Size - 1 do + local doc = app.Documents.Data[doc_n + 1] + if doc_n > 0 then + ImGui.SameLine() + end + ImGui.PushID(doc.UID) -- [Port] PushID(&doc): no pointer IDs, UID is unique local pressed - pressed, doc.Open = ImGui.Checkbox(doc:Name(), doc.Open) - if pressed and not doc.Open then doc:DoForceClose() end + pressed, doc.Open = ImGui.Checkbox(ImGui.TextBufferToString(doc.Name), doc.Open) + if pressed then + if not doc.Open then + doc:DoForceClose() + end + end ImGui.PopID() end ImGui.PushItemWidth(ImGui.GetFontSize() * 12) - app.opt_target = ImGui.Combo("Output", app.opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0") + s.opt_target = ImGui.Combo("Output", s.opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0") ImGui.PopItemWidth() local redock_all = false - if app.opt_target == Target_Tab then ImGui.SameLine(); _, app.opt_reorderable = ImGui.Checkbox("Reorderable Tabs", app.opt_reorderable) end - if app.opt_target == Target_DockSpaceAndWindow then ImGui.SameLine(); redock_all = ImGui.Button("Redock all") end + if s.opt_target == Target_Tab then ImGui.SameLine(); _, s.opt_reorderable = ImGui.Checkbox("Reorderable Tabs", s.opt_reorderable) end + if s.opt_target == Target_DockSpaceAndWindow then ImGui.SameLine(); redock_all = ImGui.Button("Redock all") end + ImGui.Separator() -- About the ImGuiWindowFlags.UnsavedDocument / ImGuiTabItemFlags.UnsavedDocument flags. @@ -27390,34 +31777,46 @@ function ShowExampleAppDocuments(p_open) -- The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole. -- Tabs - if app.opt_target == Target_Tab then - local tab_bar_flags = bit32.bor(app.opt_fitting_flags, app.opt_reorderable and 1 --[[ImGuiTabBarFlags.Reorderable]] or 0, 64 --[[ImGuiTabBarFlags.DrawSelectedOverline]]) + if s.opt_target == Target_Tab then + local tab_bar_flags = bit32.bor(s.opt_fitting_flags, s.opt_reorderable and 1 --[[ImGuiTabBarFlags.Reorderable]] or 0) + tab_bar_flags = bit32.bor(tab_bar_flags, 64 --[[ImGuiTabBarFlags.DrawSelectedOverline]]) if ImGui.BeginTabBar("##tabs", tab_bar_flags) then - if app.opt_reorderable then app:NotifyOfDocumentsClosedElsewhere() end + if s.opt_reorderable then + app:NotifyOfDocumentsClosedElsewhere() + end + + -- [DEBUG] Stress tests + --if ((ImGui.GetFrameCount() % 30) == 0) docs[1].Open ^= 1; -- [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. + --if (ImGui.GetIO().KeyCtrl) ImGui.SetTabItemSelected(docs[1].Name); -- [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. -- Submit Tabs - for _, doc in ipairs(app.Documents) do - if doc.Open then - -- As we allow to change document name, we append a never-changing document id so tabs are stable - local tab_flags = doc.Dirty and 1 --[[ImGuiTabItemFlags.UnsavedDocument]] or 0 - local visible - visible, doc.Open = ImGui.BeginTabItem(app:GetTabName(doc), doc.Open, tab_flags) - - -- Cancel attempt to close when unsaved add to save queue so we can display a popup. - if not doc.Open and doc.Dirty then - doc.Open = true - app:QueueClose(doc) - end - app:DisplayDocContextMenu(doc) - if visible then - app:DisplayDocContents(doc) - ImGui.EndTabItem() - end + for _, doc in app.Documents:iter() do repeat + if not doc.Open then + break -- continue end - end + + -- As we allow to change document name, we append a never-changing document id so tabs are stable + local doc_name_buf = app:GetTabName(doc) + local tab_flags = (doc.Dirty and 1 --[[ImGuiTabItemFlags.UnsavedDocument]] or 0) + local visible + visible, doc.Open = ImGui.BeginTabItem(doc_name_buf, doc.Open, tab_flags) + + -- Cancel attempt to close when unsaved add to save queue so we can display a popup. + if not doc.Open and doc.Dirty then + doc.Open = true + app.CloseQueue:push_back(doc) + end + + app:DisplayDocContextMenu(doc) + if visible then + app:DisplayDocContents(doc) + ImGui.EndTabItem() + end + until true end + ImGui.EndTabBar() end - elseif app.opt_target == Target_DockSpaceAndWindow then + elseif s.opt_target == Target_DockSpaceAndWindow then if bit32.band(ImGui.GetIO().ConfigFlags, 128 --[[ImGuiConfigFlags.DockingEnable]]) ~= 0 then app:NotifyOfDocumentsClosedElsewhere() @@ -27426,23 +31825,30 @@ function ShowExampleAppDocuments(p_open) ImGui.DockSpace(dockspace_id) -- Create Windows - for _, doc in ipairs(app.Documents) do - if doc.Open then - ImGui.SetNextWindowDockID(dockspace_id, redock_all and 1 --[[ImGuiCond.Always]] or 4 --[[ImGuiCond.FirstUseEver]]) - local window_flags = doc.Dirty and 262144 --[[ImGuiWindowFlags.UnsavedDocument]] or 0 - local visible - doc.Open, visible = ImGui.Begin(doc:Name(), doc.Open, window_flags) - - -- Cancel attempt to close when unsaved add to save queue so we can display a popup. - if not doc.Open and doc.Dirty then - doc.Open = true - app:QueueClose(doc) - end - app:DisplayDocContextMenu(doc) - if visible then app:DisplayDocContents(doc) end - ImGui.End() + for doc_n = 0, app.Documents.Size - 1 do repeat + local doc = app.Documents.Data[doc_n + 1] + if not doc.Open then + break -- continue end - end + + ImGui.SetNextWindowDockID(dockspace_id, redock_all and 1 --[[ImGuiCond.Always]] or 4 --[[ImGuiCond.FirstUseEver]]) + local window_flags = (doc.Dirty and 262144 --[[ImGuiWindowFlags.UnsavedDocument]] or 0) + local visible + doc.Open, visible = ImGui.Begin(ImGui.TextBufferToString(doc.Name), doc.Open, window_flags) + + -- Cancel attempt to close when unsaved add to save queue so we can display a popup. + if not doc.Open and doc.Dirty then + doc.Open = true + app.CloseQueue:push_back(doc) + end + + app:DisplayDocContextMenu(doc) + if visible then + app:DisplayDocContents(doc) + end + + ImGui.End() + until true end else ShowDockingDisabledMessage() end @@ -27456,14 +31862,18 @@ function ShowExampleAppDocuments(p_open) -- Display renaming UI if app.RenamingDoc ~= nil then - if app.RenamingStarted then ImGui.OpenPopup("Rename") end + if app.RenamingStarted then + ImGui.OpenPopup("Rename") + end if ImGui.BeginPopup("Rename") then ImGui.SetNextItemWidth(ImGui.GetFontSize() * 30) - if ImGui.InputText("###Name", app.RenamingDoc.NameBuf, 32, 64 --[[ImGuiInputTextFlags.EnterReturnsTrue]]) then + if ImGui.InputText("###Name", app.RenamingDoc.Name, 32, 64 --[[ImGuiInputTextFlags.EnterReturnsTrue]]) then ImGui.CloseCurrentPopup() app.RenamingDoc = nil end - if app.RenamingStarted then ImGui.SetKeyboardFocusHere(-1) end + if app.RenamingStarted then + ImGui.SetKeyboardFocusHere(-1) + end ImGui.EndPopup() else app.RenamingDoc = nil @@ -27472,2476 +31882,81 @@ function ShowExampleAppDocuments(p_open) end -- Display closing confirmation UI - if #app.CloseQueue > 0 then + if not app.CloseQueue:empty() then local close_queue_unsaved_documents = 0 - for _, doc in ipairs(app.CloseQueue) do if doc.Dirty then close_queue_unsaved_documents = close_queue_unsaved_documents + 1 end end + for n = 0, app.CloseQueue.Size - 1 do + if app.CloseQueue.Data[n + 1].Dirty then + close_queue_unsaved_documents = close_queue_unsaved_documents + 1 + end + end + if close_queue_unsaved_documents == 0 then -- Close documents when all are unsaved - for _, doc in ipairs(app.CloseQueue) do doc:DoForceClose() end - app.CloseQueue = {} + for n = 0, app.CloseQueue.Size - 1 do + app.CloseQueue.Data[n + 1]:DoForceClose() + end + app.CloseQueue:clear() else - if not ImGui.IsPopupOpen("Save?") then ImGui.OpenPopup("Save?") end + if not ImGui.IsPopupOpen("Save?") then + ImGui.OpenPopup("Save?") + end if ImGui.BeginPopupModal("Save?", nil, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) then ImGui.Text("Save change to the following items?") local item_height = ImGui.GetTextLineHeightWithSpacing() if ImGui.BeginChild(ImGui.GetID("frame"), ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 6.25 * item_height), 128 --[[ImGuiChildFlags.FrameStyle]]) then - for _, doc in ipairs(app.CloseQueue) do if doc.Dirty then ImGui.Text("%s", doc:Name()) end end + for _, doc in app.CloseQueue:iter() do + if doc.Dirty then + ImGui.Text("%s", ImGui.TextBufferToString(doc.Name)) + end + end end ImGui.EndChild() + local button_size = ImVec2(ImGui.GetFontSize() * 7.0, 0.0) if ImGui.Button("Yes", button_size) then - for _, doc in ipairs(app.CloseQueue) do - if doc.Dirty then doc:DoSave() end + for _, doc in app.CloseQueue:iter() do + if doc.Dirty then + doc:DoSave() + end doc:DoForceClose() end - app.CloseQueue = {} + app.CloseQueue:clear() ImGui.CloseCurrentPopup() end ImGui.SameLine() if ImGui.Button("No", button_size) then - for _, doc in ipairs(app.CloseQueue) do doc:DoForceClose() end - app.CloseQueue = {} + for _, doc in app.CloseQueue:iter() do + doc:DoForceClose() + end + app.CloseQueue:clear() ImGui.CloseCurrentPopup() end ImGui.SameLine() if ImGui.Button("Cancel", button_size) then - app.CloseQueue = {} + app.CloseQueue:clear() ImGui.CloseCurrentPopup() end ImGui.EndPopup() end end end + ImGui.End() return p_open end -end --[[ imgui_demo_apps.lua ]] - -do --[[ imgui_demo_widgets.lua ]] --- Demo: DemoWindowWidgets*() sections (port of imgui_demo.cpp). Globals picked up by DemoWindowWidgets() in imgui_demo.lua. -local _ -local function HSV(h, s, v, a) local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v) return ImVec4(r, g, b, a or 1.0) end -local Buf, BufStr = DemoBuf, DemoBufStr -local S = {} -- statics, one subtable per section - -local ExampleNames = { - "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper", - "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava", - "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber" } ------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsBasic() +-- [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser() ------------------------------------------------------------------------------- -S.basic = { clicked = 0, check = true, e = 0, counter = 0, str0 = Buf("Hello, world!", 128), str1 = Buf("", 128), - i0 = 123, f0 = 0.001, d0 = 999999.00000001, f1 = 1.e10, vec4a = { 0.10, 0.20, 0.30, 0.44 }, - di1 = 50, di2 = 42, di3 = 128, df1 = 1.0, df2 = 0.0067, si1 = 0, sf1 = 0.123, sf2 = 0.0, angle = 0.0, elem = 0, - col1 = { 1.0, 0.0, 0.2 }, col2 = { 0.4, 0.7, 0.0, 0.5 }, combo = 0, listbox = 1 } - -function DemoWindowWidgetsBasic() - if not ImGui.TreeNode("Basic") then return end - local s = S.basic - ImGui.SeparatorText("General") - if ImGui.Button("Button") then s.clicked = s.clicked + 1 end - if s.clicked % 2 == 1 then ImGui.SameLine(); ImGui.Text("Thanks for clicking me!") end - _, s.check = ImGui.Checkbox("checkbox", s.check) - _, s.e = ImGui.RadioButton("radio a", s.e, 0); ImGui.SameLine() - _, s.e = ImGui.RadioButton("radio b", s.e, 1); ImGui.SameLine() - _, s.e = ImGui.RadioButton("radio c", s.e, 2) - ImGui.AlignTextToFramePadding() - ImGui.TextLinkOpenURL("Hyperlink", "https://github.com/ocornut/imgui/wiki/Error-Handling") - - -- Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. - for i = 0, 6 do - if i > 0 then ImGui.SameLine() end - ImGui.PushID(i) - ImGui.PushStyleColor(22 --[[ImGuiCol.Button]], HSV(i / 7.0, 0.6, 0.6)) - ImGui.PushStyleColor(23 --[[ImGuiCol.ButtonHovered]], HSV(i / 7.0, 0.7, 0.7)) - ImGui.PushStyleColor(24 --[[ImGuiCol.ButtonActive]], HSV(i / 7.0, 0.8, 0.8)) - ImGui.Button("Click") - ImGui.PopStyleColor(3) - ImGui.PopID() - end - - -- Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements - -- (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) - -- See 'Demo->Layout->Text Baseline Alignment' for details. - ImGui.AlignTextToFramePadding() - ImGui.Text("Hold to repeat:") - ImGui.SameLine() - - -- Arrow buttons with Repeater - local spacing = ImGui.GetStyle().ItemInnerSpacing.x - ImGui.PushItemFlag(8 --[[ImGuiItemFlags.ButtonRepeat]], true) - if ImGui.ArrowButton("##left", 0 --[[ImGuiDir.Left]]) then s.counter = s.counter - 1 end - ImGui.SameLine(0.0, spacing) - if ImGui.ArrowButton("##right", 1 --[[ImGuiDir.Right]]) then s.counter = s.counter + 1 end - ImGui.PopItemFlag() - ImGui.SameLine() - ImGui.Text("%d", s.counter) - ImGui.Button("Tooltip") - ImGui.SetItemTooltip("I am a tooltip") - ImGui.LabelText("label", "Value") - - ImGui.SeparatorText("Inputs") - ImGui.InputText("input text", s.str0, 128) - ImGui.SameLine(); HelpMarker("USER:\nHold Shift or use mouse to select text.\nCtrl+Left/Right to word jump.\nCtrl+A or Double-Click to select all.\nCtrl+X,Ctrl+C,Ctrl+V for clipboard.\nCtrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.\nEscape to revert.") - ImGui.InputTextWithHint("input text (w/ hint)", "enter text here", s.str1, 128) - s.i0 = ImGui.InputInt("input int", s.i0) - s.f0 = ImGui.InputFloat("input float", s.f0, 0.01, 1.0, "%.3f") - s.d0 = ImGui.InputDouble("input double", s.d0, 0.01, 1.0, "%.8f") - s.f1 = ImGui.InputFloat("input scientific", s.f1, 0.0, 0.0, "%e") - ImGui.SameLine(); HelpMarker("You can input value using the scientific notation,\n e.g. \"1e+8\" becomes \"100000000\".") - ImGui.InputFloat3("input float3", s.vec4a) - - ImGui.SeparatorText("Drags") - s.di1 = ImGui.DragInt("drag int", s.di1, 1) - ImGui.SameLine(); HelpMarker("Click and drag to edit value.\nHold Shift/Alt for faster/slower edit.\nDouble-Click or Ctrl+Click to input value.") - s.di2 = ImGui.DragInt("drag int 0..100", s.di2, 1, 0, 100, "%d%%", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) - s.di3 = ImGui.DragInt("drag int wrap 100..200", s.di3, 1, 100, 200, "%d", 256 --[[ImGuiSliderFlags.WrapAround]]) - s.df1 = ImGui.DragFloat("drag float", s.df1, 0.005) - s.df2 = ImGui.DragFloat("drag small float", s.df2, 0.0001, 0.0, 0.0, "%.06f ns") - -- ImGui.DragFloat("drag wrap -1..1", f3, 0.005, -1.0, 1.0, nil, ImGuiSliderFlags.WrapAround) - - ImGui.SeparatorText("Sliders") - s.si1 = ImGui.SliderInt("slider int", s.si1, -1, 3) - ImGui.SameLine(); HelpMarker("Ctrl+Click to input value.") - s.sf1 = ImGui.SliderFloat("slider float", s.sf1, 0.0, 1.0, "ratio = %.3f") - s.sf2 = ImGui.SliderFloat("slider float (log)", s.sf2, -10.0, 10.0, "%.4f", 32 --[[ImGuiSliderFlags.Logarithmic]]) - s.angle = ImGui.SliderAngle("slider angle", s.angle) - - -- Using the format string to display a name instead of an integer. - -- Here we completely omit '%d' from the format string, so it'll only display a name. - -- This technique can also be used with DragInt(). - local elems_names = { "Fire", "Earth", "Air", "Water" } - local elem_name = elems_names[s.elem + 1] or "Unknown" - s.elem = ImGui.SliderInt("slider enum", s.elem, 0, 3, elem_name) -- Use ImGuiSliderFlags.NoInput flag to disable Ctrl+Click here. - ImGui.SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.") - - ImGui.SeparatorText("Selectors/Pickers") - ImGui.ColorEdit3("color 1", s.col1) - ImGui.SameLine(); HelpMarker("Click on the color square to open a color picker.\nClick and hold to use drag and drop.\nRight-Click on the color square to show options.\nCtrl+Click on individual component to input value.\n") - ImGui.ColorEdit4("color 2", s.col2) - - -- Using the _simplified_ one-liner Combo() api here - -- See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. - s.combo = ImGui.Combo("combo", s.combo, { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }) - ImGui.SameLine(); HelpMarker("Using the simplified one-liner Combo API here.") - - -- Using the _simplified_ one-liner ListBox() api here - -- See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. - s.listbox = ImGui.ListBox("listbox", s.listbox, { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }, 9, 4) - ImGui.SameLine(); HelpMarker("Using the simplified one-liner ListBox API here.") - ImGui.TreePop() -end - -S.chdr = { closable_group = true } - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsBullets() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsBullets() - if not ImGui.TreeNode("Bullets") then return end - ImGui.BulletText("Bullet point 1") - ImGui.BulletText("Bullet point 2\nOn multiple lines") - if ImGui.TreeNode("Tree node") then ImGui.BulletText("Another bullet point"); ImGui.TreePop() end - ImGui.Bullet(); ImGui.Text("Bullet point 3 (two calls)") - ImGui.Bullet(); ImGui.SmallButton("Button") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsCollapsingHeaders() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsCollapsingHeaders() - if not ImGui.TreeNode("Collapsing Headers") then return end - local s = S.chdr - _, s.closable_group = ImGui.Checkbox("Show 2nd header", s.closable_group) - if ImGui.CollapsingHeader("Header", 0 --[[ImGuiTreeNodeFlags.None]]) then - ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) - for i = 0, 4 do ImGui.Text("Some content %d", i) end - end - local open - open, s.closable_group = ImGui.CollapsingHeader("Header with a close button", s.closable_group) - if open then - ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) - for i = 0, 4 do ImGui.Text("More content %d", i) end - end - -- if ImGui.CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags.Bullet) then - -- ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered()) - -- end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsColorAndPickers() -------------------------------------------------------------------------------- - -IMGUI_PAYLOAD_TYPE_COLOR_3F = IMGUI_PAYLOAD_TYPE_COLOR_3F or "_COL3F" -IMGUI_PAYLOAD_TYPE_COLOR_4F = IMGUI_PAYLOAD_TYPE_COLOR_4F or "_COL4F" - -S.color = { color = ImVec4(114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 200.0 / 255.0), base_flags = 0, palette = nil, - backup = ImVec4(), no_border = false, ref_color = false, ref_color_v = ImVec4(1.0, 0.0, 1.0, 0.5), picker_mode = 0, - display_mode = 0, picker_flags = ImGuiColorEditFlags.AlphaBar, hsv = ImVec4(0.23, 1.0, 1.0, 1.0) } - -function DemoWindowWidgetsColorAndPickers() - if not ImGui.TreeNode("Color/Picker Widgets") then return end - local s = S.color - local CE = ImGuiColorEditFlags - local color = s.color - - ImGui.SeparatorText("Options") - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.base_flags, CE.NoAlpha) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", s.base_flags, CE.AlphaOpaque) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", s.base_flags, CE.AlphaNoBg) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", s.base_flags, CE.AlphaPreviewHalf) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoOptions", s.base_flags, CE.NoOptions); ImGui.SameLine(); HelpMarker("Right-click on the individual color widget to show options.") - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", s.base_flags, CE.NoDragDrop) - if CE.NoColorMarkers then _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoColorMarkers", s.base_flags, CE.NoColorMarkers) end - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_HDR", s.base_flags, CE.HDR); ImGui.SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.") - local base_flags = s.base_flags - - ImGui.SeparatorText("Inline color editor") - ImGui.Text("Color widget:") - ImGui.SameLine(); HelpMarker("Click on the color square to open a color picker.\nCtrl+Click on individual component to input value.\n") - ImGui.ColorEdit3("MyColor##1", color, base_flags) - ImGui.Text("Color widget HSV with Alpha:") - ImGui.ColorEdit4("MyColor##2", color, bit32.bor(CE.DisplayHSV, base_flags)) - ImGui.Text("Color widget with Float Display:") - ImGui.ColorEdit4("MyColor##2f", color, bit32.bor(CE.Float, base_flags)) - ImGui.Text("Color button with Picker:") - ImGui.SameLine(); HelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup.") - ImGui.ColorEdit4("MyColor##3", color, bit32.bor(CE.NoInputs, CE.NoLabel, base_flags)) - - ImGui.Text("Color button with Custom Picker Popup:") - - -- Generate a default palette. The palette will persist and can be edited. - if s.palette == nil then - s.palette = {} - for n = 0, 31 do s.palette[n] = HSV(n / 31.0, 0.8, 0.8, 1.0) end -- Alpha = 1.0 - end - local open_popup = ImGui.ColorButton("MyColor##3b", color, base_flags) - ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.x) - open_popup = ImGui.Button("Palette") or open_popup - if open_popup then - ImGui.OpenPopup("mypicker") - ImVec4_Copy(s.backup, color) - end - if ImGui.BeginPopup("mypicker") then - ImGui.Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!") - ImGui.Separator() - ImGui.ColorPicker4("##picker", color, bit32.bor(base_flags, CE.NoSidePreview, CE.NoSmallPreview)) - ImGui.SameLine() - ImGui.BeginGroup() -- Lock X position - ImGui.Text("Current") - ImGui.ColorButton("##current", color, bit32.bor(CE.NoPicker, CE.AlphaPreviewHalf), ImVec2(60, 40)) - ImGui.Text("Previous") - if ImGui.ColorButton("##previous", s.backup, bit32.bor(CE.NoPicker, CE.AlphaPreviewHalf), ImVec2(60, 40)) then - ImVec4_Copy(color, s.backup) - end - ImGui.Separator() - ImGui.Text("Palette") - for n = 0, 31 do - ImGui.PushID(n) - if n % 8 ~= 0 then ImGui.SameLine(0.0, ImGui.GetStyle().ItemSpacing.y) end - local pal = s.palette[n] - if ImGui.ColorButton("##palette", pal, bit32.bor(CE.NoAlpha, CE.NoPicker, CE.NoTooltip), ImVec2(20, 20)) then - color.x = pal.x; color.y = pal.y; color.z = pal.z -- Preserve alpha! - end - - -- Allow user to drop colors into each palette entry. Note that ColorButton() is already a - -- drag source by default, unless specifying the ImGuiColorEditFlags.NoDragDrop flag. - if ImGui.BeginDragDropTarget() then - local payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F) - if payload and payload.Data then pal.x, pal.y, pal.z = payload.Data[1], payload.Data[2], payload.Data[3] end - payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F) - if payload and payload.Data then pal.x, pal.y, pal.z, pal.w = payload.Data[1], payload.Data[2], payload.Data[3], payload.Data[4] end - ImGui.EndDragDropTarget() - end - ImGui.PopID() - end - ImGui.EndGroup() - ImGui.EndPopup() - end - - ImGui.Text("Color button only:") - _, s.no_border = ImGui.Checkbox("ImGuiColorEditFlags_NoBorder", s.no_border) - ImGui.ColorButton("MyColor##3c", color, bit32.bor(base_flags, s.no_border and CE.NoBorder or 0), ImVec2(80, 80)) - - ImGui.SeparatorText("Color picker") - ImGui.PushID("Color picker") - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.picker_flags, CE.NoAlpha) - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaBar", s.picker_flags, CE.AlphaBar) - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", s.picker_flags, CE.NoSidePreview) - if bit32.band(s.picker_flags, CE.NoSidePreview) ~= 0 then - ImGui.SameLine() - _, s.ref_color = ImGui.Checkbox("With Ref Color", s.ref_color) - if s.ref_color then - ImGui.SameLine() - ImGui.ColorEdit4("##RefColor", s.ref_color_v, bit32.bor(CE.NoInputs, base_flags)) - end - end - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_PickerNoRotate", s.picker_flags, CE.PickerNoRotate) - s.picker_mode = ImGui.Combo("Picker Mode", s.picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0") - ImGui.SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode.") - s.display_mode = ImGui.Combo("Display Mode", s.display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0") - ImGui.SameLine(); HelpMarker("ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex if you don't specify a display mode.\n\nYou can change the defaults using io.ConfigColorEditFlags.") - local flags = bit32.bor(base_flags, s.picker_flags) - if s.picker_mode == 1 then flags = bit32.bor(flags, CE.PickerHueBar) end - if s.picker_mode == 2 then flags = bit32.bor(flags, CE.PickerHueWheel) end - if s.display_mode == 1 then flags = bit32.bor(flags, CE.NoInputs) end -- Disable all RGB/HSV/Hex displays - if s.display_mode == 2 then flags = bit32.bor(flags, CE.DisplayRGB) end -- Override display mode - if s.display_mode == 3 then flags = bit32.bor(flags, CE.DisplayHSV) end - if s.display_mode == 4 then flags = bit32.bor(flags, CE.DisplayHex) end - ImGui.ColorPicker4("MyColor##4", color, flags, s.ref_color and s.ref_color_v or nil) - - ImGui.Text("Set defaults in code:") - ImGui.SameLine(); HelpMarker("io.ConfigColorEditFlags is designed to allow you to set boot-time default.") - if ImGui.Button("Overwrite default: Uint8 + HSV + Hue Bar") then - ImGui.GetIO().ConfigColorEditFlags = bit32.bor(CE.Uint8, CE.DisplayHSV, CE.PickerHueBar, CE.InputRGB) -- [port] + InputRGB: upstream omits it and then trips its own InputMask_ assert - end - if ImGui.Button("Overwrite default: Float + HDR + Hue Wheel") then - ImGui.GetIO().ConfigColorEditFlags = bit32.bor(CE.Float, CE.HDR, CE.PickerHueWheel, CE.DisplayRGB, CE.InputRGB) - end - - -- Always display a small version of both types of pickers - -- (that's in order to make it more visible in the demo to people who are skimming quickly through it) - ImGui.Text("Both types:") - local w = (ImGui.GetContentRegionAvail().x - ImGui.GetStyle().ItemSpacing.y) * 0.40 - ImGui.SetNextItemWidth(w) - ImGui.ColorPicker3("##MyColor##5", color, bit32.bor(CE.PickerHueBar, CE.NoSidePreview, CE.NoInputs, CE.NoAlpha)) - ImGui.SameLine() - ImGui.SetNextItemWidth(w) - ImGui.ColorPicker3("##MyColor##6", color, bit32.bor(CE.PickerHueWheel, CE.NoSidePreview, CE.NoInputs, CE.NoAlpha)) - ImGui.PopID() - - -- HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) - -- (s.hsv is stored as HSV!) - ImGui.Spacing() - ImGui.Text("HSV encoded colors") - ImGui.SameLine(); HelpMarker("By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV.") - ImGui.Text("Color widget with InputHSV:") - ImGui.ColorEdit4("HSV shown as RGB##1", s.hsv, bit32.bor(CE.DisplayRGB, CE.InputHSV, CE.Float)) - ImGui.ColorEdit4("HSV shown as HSV##1", s.hsv, bit32.bor(CE.DisplayHSV, CE.InputHSV, CE.Float)) - ImGui.DragFloat4("Raw HSV values", s.hsv, 0.01, 0.0, 1.0) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsComboBoxes() -------------------------------------------------------------------------------- - -S.combo = { flags = 0, sel = 0, filter = nil, c2 = 0, c3 = -1, c4 = 0 } -- sel: Here we store our selection data as an index. -function DemoWindowWidgetsComboBoxes() - if not ImGui.TreeNode("Combo") then return end - local s = S.combo - local CF = ImGuiComboFlags - local p - -- Combo Boxes are also called "Dropdown" in other systems - -- Expose flags as checkbox for the demo - _, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", s.flags, CF.PopupAlignLeft) - ImGui.SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo") - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoArrowButton", s.flags, CF.NoArrowButton) - if p then s.flags = bit32.band(s.flags, bit32.bnot(CF.NoPreview)) end -- Clear incompatible flags - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoPreview", s.flags, CF.NoPreview) - if p then s.flags = bit32.band(s.flags, bit32.bnot(bit32.bor(CF.NoArrowButton, CF.WidthFitPreview))) end -- Clear incompatible flags - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_WidthFitPreview", s.flags, CF.WidthFitPreview) - if p then s.flags = bit32.band(s.flags, bit32.bnot(CF.NoPreview)) end - - -- Override default popup height - for _, h in ipairs({ "HeightSmall", "HeightRegular", "HeightLargest" }) do - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_" .. h, s.flags, CF[h]) - if p then s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(CF.HeightMask_, bit32.bnot(CF[h])))) end - end - - -- Using the generic BeginCombo() API, you have full control over how to display the combo contents. - -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively - -- stored in the object itself, etc.) - local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } - - -- Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) - local combo_preview_value = items[s.sel + 1] - if ImGui.BeginCombo("combo 1", combo_preview_value, s.flags) then - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - if ImGui.Selectable(items[n + 1], is_selected) then s.sel = n end - - -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndCombo() - end - - -- Show case embedding a filter using a simple trick: displaying the filter inside combo contents. - -- See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives. - if ImGui.BeginCombo("combo 2 (w/ filter)", combo_preview_value, s.flags) then - s.filter = s.filter or ImGuiTextFilter() - if ImGui.IsWindowAppearing() then - ImGui.SetKeyboardFocusHere() - s.filter:Clear() - end - ImGui.SetNextItemShortcut(bit32.bor(4096 --[[ImGuiMod_Ctrl]], 551 --[[ImGuiKey.F]])) - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - s.filter:DrawWithHint("##Filter", "Filter (incl -excl)") - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - if s.filter:PassFilter(items[n + 1]) then - if ImGui.Selectable(items[n + 1], is_selected) then s.sel = n end - end - end - ImGui.EndCombo() - end - - ImGui.Spacing() - ImGui.SeparatorText("One-liner variants") - HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section.") - - -- Simplified one-liner Combo() API, using values packed in a single constant string - -- This is a convenience for when the selection set is small and known at compile-time. - s.c2 = ImGui.Combo("combo 3 (one-liner)", s.c2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0") - - -- Simplified one-liner Combo() using an array of strings - -- This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. - s.c3 = ImGui.Combo("combo 4 (array)", s.c3, items, #items) -- If the selection isn't within 0..count, Combo won't display a preview - - -- Simplified one-liner Combo() using an accessor function - s.c4 = ImGui.Combo("combo 5 (function)", s.c4, function(data, n) return data[n + 1] end, items, #items) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDataTypes() -------------------------------------------------------------------------------- - -S.dt = { s8 = 127, u8 = 255, s16 = 32767, u16 = 65535, s32 = -1, u32 = 0xFFFFFFFF, s64 = -1, u64 = 0, f32 = 0.123, f64 = 90000.01234567890123456789, - drag_clamp = false, inputs_step = true, flags = 0 } -function DemoWindowWidgetsDataTypes() - if not ImGui.TreeNode("Data Types") then return end - local s = S.dt - local DT = ImGuiDataType - -- DragScalar/InputScalar/SliderScalar functions allow various data types - -- - signed/unsigned - -- - 8/16/32/64-bits - -- - integer/float/double - -- To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum - -- to pass the type. - -- In practice, if you frequently use a given type that is not covered by the normal API entry points, - -- you can wrap it yourself inside a 1 line function which can take typed argument as value, - -- and then pass them to the generic function. For example: - -- local function MySliderU32(label, value, min, max, format) - -- return ImGui.SliderScalar(label, ImGuiDataType.U32, value, min or 0, max or 0, format or "%u") - -- end - - -- ponytail: Luau numbers are doubles, so S64/U64 are shown with S32/Double here (no 64-bit integer type) - -- Setup limits - -- Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. - local s32_min, s32_max = math.floor(-2147483648 / 2), math.floor(2147483647 / 2) - local u32_max = math.floor(4294967295 / 2) - local drag_speed = 0.2 - ImGui.SeparatorText("Drags") - _, s.drag_clamp = ImGui.Checkbox("Clamp integers to 0..50", s.drag_clamp) - ImGui.SameLine(); HelpMarker("As with every widget in dear imgui, we never modify values unless there is a user interaction.\nYou can override the clamping limits by using Ctrl+Click to input a value.") - local lo, hi = s.drag_clamp and 0 or nil, s.drag_clamp and 50 or nil - s.s8 = ImGui.DragScalar("drag s8", DT.S8, s.s8, drag_speed, lo, hi) - s.u8 = ImGui.DragScalar("drag u8", DT.U8, s.u8, drag_speed, lo, hi, "%u ms") - s.s16 = ImGui.DragScalar("drag s16", DT.S16, s.s16, drag_speed, lo, hi) - s.u16 = ImGui.DragScalar("drag u16", DT.U16, s.u16, drag_speed, lo, hi, "%u ms") - s.s32 = ImGui.DragScalar("drag s32", DT.S32, s.s32, drag_speed, lo, hi) - s.s32 = ImGui.DragScalar("drag s32 hex", DT.S32, s.s32, drag_speed, lo, hi, "0x%08X") - s.u32 = ImGui.DragScalar("drag u32", DT.U32, s.u32, drag_speed, lo, hi, "%u ms") - s.f32 = ImGui.DragScalar("drag float", DT.Float, s.f32, 0.005, 0.0, 1.0, "%f") - s.f32 = ImGui.DragScalar("drag float log", DT.Float, s.f32, 0.005, 0.0, 1.0, "%f", 32 --[[ImGuiSliderFlags.Logarithmic]]) - s.f64 = ImGui.DragScalar("drag double", DT.Double, s.f64, 0.0005, 0.0, nil, "%.10f grams") - s.f64 = ImGui.DragScalar("drag double log",DT.Double, s.f64, 0.0005, 0.0, 1.0, "0 < %.10f < 1", 32 --[[ImGuiSliderFlags.Logarithmic]]) - - ImGui.SeparatorText("Sliders") - s.s8 = ImGui.SliderScalar("slider s8 full", DT.S8, s.s8, -128, 127, "%d") - s.u8 = ImGui.SliderScalar("slider u8 full", DT.U8, s.u8, 0, 255, "%u") - s.s16 = ImGui.SliderScalar("slider s16 full", DT.S16, s.s16, -32768, 32767, "%d") - s.u16 = ImGui.SliderScalar("slider u16 full", DT.U16, s.u16, 0, 65535, "%u") - s.s32 = ImGui.SliderScalar("slider s32 low", DT.S32, s.s32, 0, 50, "%d") - s.s32 = ImGui.SliderScalar("slider s32 high", DT.S32, s.s32, s32_max - 100, s32_max, "%d") - s.s32 = ImGui.SliderScalar("slider s32 full", DT.S32, s.s32, s32_min, s32_max, "%d") - s.s32 = ImGui.SliderScalar("slider s32 hex", DT.S32, s.s32, 0, 50, "0x%04X") - s.u32 = ImGui.SliderScalar("slider u32 low", DT.U32, s.u32, 0, 50, "%u") - s.u32 = ImGui.SliderScalar("slider u32 high", DT.U32, s.u32, u32_max - 100, u32_max, "%u") - s.u32 = ImGui.SliderScalar("slider u32 full", DT.U32, s.u32, 0, u32_max, "%u") - s.f32 = ImGui.SliderScalar("slider float low", DT.Float, s.f32, 0.0, 1.0) - s.f32 = ImGui.SliderScalar("slider float low log", DT.Float, s.f32, 0.0, 1.0, "%.10f", 32 --[[ImGuiSliderFlags.Logarithmic]]) - s.f32 = ImGui.SliderScalar("slider float high", DT.Float, s.f32, -10000000000.0, 10000000000.0, "%e") - s.f64 = ImGui.SliderScalar("slider double low", DT.Double, s.f64, 0.0, 1.0, "%.10f grams") - s.f64 = ImGui.SliderScalar("slider double low log", DT.Double, s.f64, 0.0, 1.0, "%.10f", 32 --[[ImGuiSliderFlags.Logarithmic]]) - s.f64 = ImGui.SliderScalar("slider double high", DT.Double, s.f64, -1000000000000000.0, 1000000000000000.0, "%e grams") - - ImGui.SeparatorText("Sliders (reverse)") - s.s8 = ImGui.SliderScalar("slider s8 reverse", DT.S8, s.s8, 127, -128, "%d") - s.u8 = ImGui.SliderScalar("slider u8 reverse", DT.U8, s.u8, 255, 0, "%u") - s.s32 = ImGui.SliderScalar("slider s32 reverse", DT.S32, s.s32, 50, 0, "%d") - s.u32 = ImGui.SliderScalar("slider u32 reverse", DT.U32, s.u32, 50, 0, "%u") - - ImGui.SeparatorText("Inputs") - _, s.inputs_step = ImGui.Checkbox("Show step buttons", s.inputs_step) - _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, 512 --[[ImGuiInputTextFlags.ReadOnly]]) - if 8192 --[[ImGuiInputTextFlags.ParseEmptyRefVal]] then _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", s.flags, 8192 --[[ImGuiInputTextFlags.ParseEmptyRefVal]]) end - if 16384 --[[ImGuiInputTextFlags.DisplayEmptyRefVal]] then _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", s.flags, 16384 --[[ImGuiInputTextFlags.DisplayEmptyRefVal]]) end - local one = s.inputs_step and 1 or nil - s.s8 = ImGui.InputScalar("input s8", DT.S8, s.s8, one, nil, "%d", s.flags) - s.u8 = ImGui.InputScalar("input u8", DT.U8, s.u8, one, nil, "%u", s.flags) - s.s16 = ImGui.InputScalar("input s16", DT.S16, s.s16, one, nil, "%d", s.flags) - s.u16 = ImGui.InputScalar("input u16", DT.U16, s.u16, one, nil, "%u", s.flags) - s.s32 = ImGui.InputScalar("input s32", DT.S32, s.s32, one, nil, "%d", s.flags) - s.s32 = ImGui.InputScalar("input s32 hex", DT.S32, s.s32, one, nil, "%04X", s.flags) - s.u32 = ImGui.InputScalar("input u32", DT.U32, s.u32, one, nil, "%u", s.flags) - s.u32 = ImGui.InputScalar("input u32 hex", DT.U32, s.u32, one, nil, "%08X", s.flags) - s.f32 = ImGui.InputScalar("input float", DT.Float, s.f32, s.inputs_step and 1.0 or nil, nil, nil, s.flags) - s.f64 = ImGui.InputScalar("input double", DT.Double, s.f64, s.inputs_step and 1.0 or nil, nil, nil, s.flags) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDisableBlocks() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsDisableBlocks(demo_data) - if not ImGui.TreeNode("Disable Blocks") then return end - _, demo_data.DisableSections = ImGui.Checkbox("Disable entire section above", demo_data.DisableSections) - ImGui.SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections.") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDragAndDrop() -------------------------------------------------------------------------------- - -S.dnd = { col1 = { 1.0, 0.0, 0.2 }, col2 = { 0.4, 0.7, 0.0, 0.5 }, mode = 0, - names = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" }, - item_names = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }, col4 = ImVec4(1.0, 0.0, 0.2, 1.0) } -function DemoWindowWidgetsDragAndDrop() - if not ImGui.TreeNode("Drag and Drop") then return end - local s = S.dnd - if ImGui.TreeNode("Drag and drop in standard widgets") then - -- ColorEdit widgets automatically act as drag source and drag target. - -- They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F - -- to allow your own widgets to use colors in their drag and drop interaction. - -- Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. - HelpMarker("You can drag from the color squares.") - ImGui.ColorEdit3("color 1", s.col1) - ImGui.ColorEdit4("color 2", s.col2) - ImGui.TreePop() - end - - if ImGui.TreeNode("Drag and drop to copy/swap items") then - local Mode_Copy, Mode_Move, Mode_Swap = 0, 1, 2 - if ImGui.RadioButtonEx("Copy", s.mode == Mode_Copy) then s.mode = Mode_Copy end ImGui.SameLine() - if ImGui.RadioButtonEx("Move", s.mode == Mode_Move) then s.mode = Mode_Move end ImGui.SameLine() - if ImGui.RadioButtonEx("Swap", s.mode == Mode_Swap) then s.mode = Mode_Swap end - local names = s.names - for n = 0, #names - 1 do - ImGui.PushID(n) - if n % 3 ~= 0 then ImGui.SameLine() end - ImGui.Button(names[n + 1], ImVec2(60, 60)) - - -- Our buttons are both drag sources and drag targets here! - if ImGui.BeginDragDropSource(0 --[[ImGuiDragDropFlags.None]]) then - -- Set payload to carry the index of our item (could be anything) - ImGui.SetDragDropPayload("DND_DEMO_CELL", n, 4) - - -- Display preview (could be anything, e.g. when dragging an image we could decide to display - -- the filename and a small preview of the image, etc.) - if s.mode == Mode_Copy then ImGui.Text("Copy %s", names[n + 1]) end - if s.mode == Mode_Move then ImGui.Text("Move %s", names[n + 1]) end - if s.mode == Mode_Swap then ImGui.Text("Swap %s", names[n + 1]) end - ImGui.EndDragDropSource() - end - if ImGui.BeginDragDropTarget() then - local payload = ImGui.AcceptDragDropPayload("DND_DEMO_CELL") - if payload then - local payload_n = payload.Data - if s.mode == Mode_Copy then names[n + 1] = names[payload_n + 1] end - if s.mode == Mode_Move then names[n + 1] = names[payload_n + 1]; names[payload_n + 1] = "" end - if s.mode == Mode_Swap then names[n + 1], names[payload_n + 1] = names[payload_n + 1], names[n + 1] end - end - ImGui.EndDragDropTarget() - end - ImGui.PopID() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Drag to reorder items (simple)") then - -- FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. - -- This code was always slightly faulty but in a way which was not easily noticeable. - -- Until we fix this, enable ImGuiItemFlags.AllowDuplicateId to disable detecting the issue. - ImGui.PushItemFlag(32 --[[ImGuiItemFlags.AllowDuplicateId]], true) - - -- Simple reordering - HelpMarker("We don't use the drag and drop api at all here! Instead we query when the item is held but not hovered, and order items accordingly.") - local item_names = s.item_names - for n = 1, #item_names do - local item = item_names[n] - ImGui.Selectable(item) - if ImGui.IsItemActive() and not ImGui.IsItemHovered() then - local n_next = n + ((ImGui.GetMouseDragDelta(0).y < 0.0) and -1 or 1) - if n_next >= 1 and n_next <= #item_names then - item_names[n] = item_names[n_next] - item_names[n_next] = item - ImGui.ResetMouseDragDelta() - end - end - end - ImGui.PopItemFlag() - ImGui.TreePop() - end - - if ImGui.TreeNode("Tooltip at target location") then - for n = 0, 1 do - -- Drop targets - ImGui.Button((n == 1) and "drop here##1" or "drop here##0") - if ImGui.BeginDragDropTarget() then - local drop_target_flags = bit32.bor(1024 --[[ImGuiDragDropFlags.AcceptBeforeDelivery]], 4096 --[[ImGuiDragDropFlags.AcceptNoPreviewTooltip]]) - if ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags) then - ImGui.SetMouseCursor(10 --[[ImGuiMouseCursor.NotAllowed]]) - ImGui.SetTooltip("Cannot drop here!") - end - ImGui.EndDragDropTarget() - end - - -- Drop source - if n == 0 then ImGui.ColorButton("drag me", s.col4) end - end - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDragsAndSliders() -------------------------------------------------------------------------------- - -S.ds = { flags = 0, drag_f = 0.5, drag_f4 = { 0, 0, 0, 0 }, drag_i = 50, slider_f = 0.5, slider_f4 = { 0, 0, 0, 0 }, slider_i = 50 } -function DemoWindowWidgetsDragsAndSliders() - if not ImGui.TreeNode("Drag/Slider Flags") then return end - -- Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! - local s = S.ds - local SF = ImGuiSliderFlags - local function F(name, help) - if SF[name] == nil then return end - _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_" .. name, s.flags, SF[name]) - if help then ImGui.SameLine(); HelpMarker(help) end - end - F("AlwaysClamp") - F("ClampOnInput", "Clamp value to min/max bounds when input manually with Ctrl+Click. By default Ctrl+Click allows going out of bounds.") - F("ClampZeroRange", "Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.") - F("Logarithmic", "Enable logarithmic editing (more precision for small values).") - F("NoRoundToFormat", "Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).") - F("NoInput", "Disable Ctrl+Click or Enter key allowing to input text directly into the widget.") - F("NoSpeedTweaks", "Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.") - F("WrapAround", "Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)") - F("ColorMarkers") - local flags = s.flags - - -- Drags - ImGui.Text("Underlying float value: %f", s.drag_f) - s.drag_f = ImGui.DragFloat("DragFloat (0 -> 1)", s.drag_f, 0.005, 0.0, 1.0, "%.3f", flags) - s.drag_f = ImGui.DragFloat("DragFloat (0 -> +inf)", s.drag_f, 0.005, 0.0, 3.4028234663853e+38 --[[FLT_MAX]], "%.3f", flags) - s.drag_f = ImGui.DragFloat("DragFloat (-inf -> 1)", s.drag_f, 0.005, -3.4028234663853e+38 --[[FLT_MAX]], 1.0, "%.3f", flags) - s.drag_f = ImGui.DragFloat("DragFloat (-inf -> +inf)", s.drag_f, 0.005, -3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]], "%.3f", flags) - -- ImGui.DragFloat("DragFloat (0 -> 0)", drag_f, 0.005, 0.0, 0.0, "%.3f", flags) -- To test ClampZeroRange - -- ImGui.DragFloat("DragFloat (100 -> 100)", drag_f, 0.005, 100.0, 100.0, "%.3f", flags) - s.drag_i = ImGui.DragInt("DragInt (0 -> 100)", s.drag_i, 0.5, 0, 100, "%d", flags) - ImGui.DragFloat4("DragFloat4 (0 -> 1)", s.drag_f4, 0.005, 0.0, 1.0, "%.3f", flags) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags.ColorMarkers. - - -- Sliders - local flags_for_sliders = bit32.band(flags, bit32.bnot(SF.WrapAround)) - ImGui.Text("Underlying float value: %f", s.slider_f) - s.slider_f = ImGui.SliderFloat("SliderFloat (0 -> 1)", s.slider_f, 0.0, 1.0, "%.3f", flags_for_sliders) - s.slider_i = ImGui.SliderInt("SliderInt (0 -> 100)", s.slider_i, 0, 100, "%d", flags_for_sliders) - ImGui.SliderFloat4("SliderFloat4 (0 -> 1)", s.slider_f4, 0.0, 1.0, "%.3f", flags_for_sliders) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags.ColorMarkers. - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsFonts() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsFonts() - if not ImGui.TreeNode("Fonts") then return end - if ImGui.ShowFontAtlas then ImGui.ShowFontAtlas(ImGui.GetIO().Fonts) else DemoNotPorted("ShowFontAtlas") end - -- FIXME-NEWATLAS: Provide a demo to add/create a procedural font? - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsImages() -------------------------------------------------------------------------------- - -S.img = { viewer = nil, pressed_count = 0 } -function DemoWindowWidgetsImages() - if not ImGui.TreeNode("Images") then return end - local s = S.img - local io = ImGui.GetIO() - ImGui.TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!") - - -- Below we are displaying the font texture because it is the only texture we have access to inside the demo! - -- Read description about ImTextureID/ImTextureRef and FAQ for details about texture identifiers. - -- - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, - -- it will help you debug issues if you are confused about it. - -- - Consider using the lower-level ImDrawList:AddImage() API, via ImGui.GetWindowDrawList():AddImage(). - -- - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md - -- - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - - -- Grab the current texture identifier used by the font atlas. - local atlas = io.Fonts - local my_tex_id = atlas.TexRef - local my_tex_w = atlas.TexData and atlas.TexData.Width or 0 -- Regular user code should never have to care about TexData fields, but since we want to display the entire texture here, we pull Width/Height from it. - local my_tex_h = atlas.TexData and atlas.TexData.Height or 0 - ImGui.Text("%.0fx%.0f", my_tex_w, my_tex_h) - - -- Basic drawing - ImGui.SeparatorText("Image()/ImageWithBg() function") - ImGui.PushStyleVar(24 --[[ImGuiStyleVar.ImageBorderSize]], math.max(1.0, ImGui.GetStyle().ImageBorderSize)) - ImGui.ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0.0, 0.0), ImVec2(1.0, 1.0), ImVec4(0.0, 0.0, 0.0, 1.0)) -- uv_min: Top-left, uv_max: Lower-right - ImGui.PopStyleVar() - - -- Fancy widget - ImGui.SeparatorText("Interactive Image Viewer") - s.viewer = s.viewer or ExampleImageViewerData() - local canvas_size = ImVec2(ImGui.GetContentRegionAvail().x, my_tex_h * 2.0) - ExampleImageViewer_DrawOptions(s.viewer) - ExampleImageViewer_DrawCanvas(s.viewer, canvas_size, my_tex_id, my_tex_w, my_tex_h) - - ImGui.SeparatorText("Textured Buttons") - ImGui.TextWrapped("And now some textured buttons..") - for i = 0, 7 do - -- UV coordinates are often (0.0, 0.0) and (1.0, 1.0) to display an entire textures. - -- Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation. - -- Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - ImGui.PushID(i) - if i > 0 then ImGui.PushStyleVar(11 --[[ImGuiStyleVar.FramePadding]], ImVec2(i - 1.0, i - 1.0)) end - local size = ImVec2(32.0, 32.0) -- Size of the image we want to make visible - local uv0 = ImVec2(0.0, 0.0) -- UV coordinates for lower-left - local uv1 = ImVec2(32.0 / my_tex_w, 32.0 / my_tex_h) -- UV coordinates for (32,32) in our texture - -- bg_col: Black background, tint_col: No tint - if ImGui.ImageButton("", my_tex_id, size, uv0, uv1, ImVec4(0.0, 0.0, 0.0, 1.0), ImVec4(1.0, 1.0, 1.0, 1.0)) then - s.pressed_count = s.pressed_count + 1 - end - if i > 0 then ImGui.PopStyleVar() end - ImGui.PopID() - ImGui.SameLine() - end - ImGui.NewLine() - ImGui.Text("Pressed %d times.", s.pressed_count) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsListBoxes() -------------------------------------------------------------------------------- - -S.lb = { sel = 0, highlight = false } -- sel: Here we store our selected data as an index. -function DemoWindowWidgetsListBoxes() - if not ImGui.TreeNode("List Boxes") then return end - -- BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() - -- using the ImGuiChildFlags.FrameStyle flag for stylistic changes + displaying a label. - -- You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild() - -- to always be called (inconsistent with BeginListBox()/EndListBox()). - - -- Using the generic BeginListBox() API, you have full control over how to display the combo contents. - -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively - -- stored in the object itself, etc.) - local s = S.lb - local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } - local item_highlighted_idx = -1 -- Here we store our highlighted data as an index. - _, s.highlight = ImGui.Checkbox("Highlight hovered item in second listbox", s.highlight) - if ImGui.BeginListBox("listbox 1") then - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - if ImGui.Selectable(items[n + 1], is_selected) then s.sel = n end - if s.highlight and ImGui.IsItemHovered() then item_highlighted_idx = n end - -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndListBox() - end - ImGui.SameLine(); HelpMarker("Here we are sharing selection state between both boxes.") - - -- Custom size: use all width, 5 items tall - ImGui.Text("Full-width:") - if ImGui.BeginListBox("##listbox 2", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 5 * ImGui.GetTextLineHeightWithSpacing())) then - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - local flags = (item_highlighted_idx == n) and 32 --[[ImGuiSelectableFlags.Highlight]] or 0 - if ImGui.Selectable(items[n + 1], is_selected, flags) then s.sel = n end - -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndListBox() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsLiveEdit() -------------------------------------------------------------------------------- - -S.le = { str = Buf("", 32), i = 0, f = 0.0 } -function DemoWindowWidgetsLiveEdit(demo_data) - if not ImGui.TreeNode("Live Edit Flags") then return end - local s = S.le - ImGui.TextWrapped("Select whether to apply keyboard edits to backing variables _while_ typing.") - _, demo_data.LiveEditOverride = ImGui.Checkbox("Override Live Edit Flags in Demo Window", demo_data.LiveEditOverride) - if not demo_data.LiveEditOverride then demo_data.LiveEditFlags = ImGui.GetItemFlags() end - ImGui.BeginDisabled(demo_data.LiveEditOverride == false) - ImGui.Indent() - _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputText", demo_data.LiveEditFlags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) - _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputScalar", demo_data.LiveEditFlags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) - ImGui.Unindent() - ImGui.EndDisabled() - ImGui.Text("Try typing '123' and seeing effect on backing value:") - ImGui.InputText("str", s.str, 32) - ImGui.Text("Backing value: \"%s\"", BufStr(s.str)) - s.i = ImGui.InputInt("int", s.i, 0, 0) - ImGui.Text("Backing value: %d", s.i) - s.f = ImGui.SliderFloat("float", s.f, 0.0, 100.0) - ImGui.Text("Backing value: %f", s.f) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsMixedValues() -------------------------------------------------------------------------------- - -S.mv = { use_liveedit = false, items = { 12.0, 0.0, 0.0 } } -function DemoWindowWidgetsMixedValues() - if not ImGui.TreeNode("Mixed Values") then return end - local s = S.mv - local items = s.items - -- This is designed for advanced property editors which are generally reusable and data-driven. - HelpMarker("Using ImGuiItemFlags_MixedValue.") - _, s.use_liveedit = ImGui.Checkbox("ImGuiItemFlags_LiveEditOnInput", s.use_liveedit) - ImGui.SeparatorText("Scalar/Text Widgets") - local is_mixed = items[1] ~= items[2] or items[1] ~= items[3] - - -- Demonstrate Drags, Sliders, Inputs - ImGui.PushItemFlag(384 --[[ImGuiItemFlags.LiveEditOnInput]], s.use_liveedit) - ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], is_mixed) - local edited, e = false, false - items[1], e = ImGui.DragFloat("DragFloat", items[1]); edited = edited or e - items[1], e = ImGui.SliderFloat("SliderFloat", items[1], 0.0, 100.0); edited = edited or e - items[1], e = ImGui.InputFloat("InputFloat", items[1], 1.0); edited = edited or e - if edited then items[2] = items[1]; items[3] = items[1] end - ImGui.PopItemFlag() - ImGui.Text("Underlying data:") - items[1] = ImGui.InputFloat("item 0 (ref)", items[1]) - items[2] = ImGui.InputFloat("item 1", items[2]) - items[3] = ImGui.InputFloat("item 2", items[3]) - ImGui.PopItemFlag() - - -- Demonstrate Checkbox(), RadioButton(), Combo(), ColorEdit4() - ImGui.SeparatorText("Others Widgets") - ImGui.Text("(note: edits are not applied in this demo)") -- <-- Would need more state tracking. - ImGui.Checkbox("Checkbox On", true) - ImGui.Checkbox("Checkbox Off", false) - ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], true) - ImGui.Checkbox("Checkbox Mixed", false) - ImGui.RadioButtonEx("RadioButton Mixed", true) - ImGui.SameLine() - ImGui.RadioButtonEx("RadioButton Mixed##2", true) -- Showing 2 radio buttons makes the example more clear - ImGui.Combo("Combo", 0, "One\0Two\0Three\0") - ImGui.ColorEdit4("ColorEdit4", ImVec4(0.5, 0.5, 0.5, 0.5)) - ImGui.PopItemFlag() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsMultiComponents() -------------------------------------------------------------------------------- - -S.mc = { vec4f = { 0.10, 0.20, 0.30, 0.44 }, vec4i = { 1, 5, 100, 255 }, flags = 0, b = 10, e = 90, bi = 100, ei = 1000 } -function DemoWindowWidgetsMultiComponents() - if not ImGui.TreeNode("Multi-component Widgets") then return end - local s = S.mc - local f, i = s.vec4f, s.vec4i - if 4096 --[[ImGuiSliderFlags.ColorMarkers]] then _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ColorMarkers", s.flags, 4096 --[[ImGuiSliderFlags.ColorMarkers]]) end -- Only passing this to Drag/Sliders - local flags = s.flags - for _, n in ipairs({ 2, 3, 4 }) do - ImGui.SeparatorText(n .. "-wide") - ImGui["InputFloat" .. n]("input float" .. n, f) - ImGui["InputInt" .. n]("input int" .. n, i) - ImGui["DragFloat" .. n]("drag float" .. n, f, 0.01, 0.0, 1.0, nil, flags) - ImGui["DragInt" .. n]("drag int" .. n, i, 1, 0, 255, nil, flags) - ImGui["SliderFloat" .. n]("slider float" .. n, f, 0.0, 1.0, nil, flags) - ImGui["SliderInt" .. n]("slider int" .. n, i, 0, 255, nil, flags) - end - ImGui.SeparatorText("Ranges") - s.b, s.e = ImGui.DragFloatRange2("range float", s.b, s.e, 0.25, 0.0, 100.0, "Min: %.1f %%", "Max: %.1f %%", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) - s.bi, s.ei = ImGui.DragIntRange2("range int", s.bi, s.ei, 5, 0, 1000, "Min: %d units", "Max: %d units") - s.bi, s.ei = ImGui.DragIntRange2("range int (no bounds)", s.bi, s.ei, 5, 0, 0, "Min: %d units", "Max: %d units") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsPlotting() -------------------------------------------------------------------------------- - --- Plot/Graph widgets are not very good. --- Consider using a third-party library such as ImPlot: https://github.com/epezent/implot --- (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) -S.plot = { animate = true, arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, values = {}, values_offset = 0, refresh_time = 0.0, phase = 0.0, - func_type = 0, display_count = 70 } -for n = 1, 90 do S.plot.values[n] = 0.0 end -function DemoWindowWidgetsPlotting() - if not ImGui.TreeNode("Plotting") then return end - local s = S.plot - ImGui.Text("Need better plotting and graphing? Consider using ImPlot:") - ImGui.TextLinkOpenURL("https://github.com/epezent/implot") - ImGui.Separator() - _, s.animate = ImGui.Checkbox("Animate", s.animate) - - -- Plot as lines and plot as histogram - ImGui.PlotLines("Frame Times", s.arr, nil, #s.arr) - ImGui.PlotHistogram("Histogram", s.arr, nil, #s.arr, 0, nil, 0.0, 1.0, ImVec2(0, 80.0)) - -- ImGui.SameLine(); HelpMarker("Consider using ImPlot instead!") - - -- Fill an array of contiguous float values to plot - local values = s.values - if not s.animate or s.refresh_time == 0.0 then s.refresh_time = ImGui.GetTime() end - while s.refresh_time < ImGui.GetTime() do -- Create data at fixed 60 Hz rate for the demo - values[s.values_offset + 1] = math.cos(s.phase) - s.values_offset = (s.values_offset + 1) % #values - s.phase = s.phase + 0.10 * s.values_offset - s.refresh_time = s.refresh_time + 1.0 / 60.0 - end - - -- Plots can display overlay texts - -- (in this example, we will display an average value) - local average = 0.0 - for n = 1, #values do average = average + values[n] end - average = average / #values - ImGui.PlotLines("Lines", values, nil, #values, s.values_offset, string.format("avg %f", average), -1.0, 1.0, ImVec2(0, 80.0)) - - -- Use functions to generate output - -- FIXME: This is actually VERY awkward because current plot API only pass in indices. - -- We probably want an API passing floats and user provide sample rate/count. - -- Getters receive a 1-based index in this port - local function Sin(_, i) return math.sin((i - 1) * 0.1) end - local function Saw(_, i) return ((i - 1) % 2 == 1) and 1.0 or -1.0 end - ImGui.SeparatorText("Functions") - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - s.func_type = ImGui.Combo("func", s.func_type, "Sin\0Saw\0") - ImGui.SameLine() - s.display_count = ImGui.SliderInt("Sample count", s.display_count, 1, 400) - local func = (s.func_type == 0) and Sin or Saw - ImGui.PlotLines("Lines##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) - ImGui.PlotHistogram("Histogram##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsProgressBars() -------------------------------------------------------------------------------- - -S.pb = { accum = 0.0, dir = 1.0 } -function DemoWindowWidgetsProgressBars() - if not ImGui.TreeNode("Progress Bars") then return end - -- Animate a simple progress bar - local s = S.pb - s.accum = s.accum + s.dir * 0.4 * ImGui.GetIO().DeltaTime - if s.accum >= 1.1 then s.accum = 1.1; s.dir = -s.dir end - if s.accum <= -0.1 then s.accum = -0.1; s.dir = -s.dir end - local progress = DemoClamp(s.accum, 0.0, 1.0) - - -- Typically we would use ImVec2(-1.0,0.0) or ImVec2(-FLT_MIN,0.0) to use all available width, - -- or ImVec2(width,0.0) for a specified width. ImVec2(0.0,0.0) uses ItemWidth. - ImGui.ProgressBar(progress, ImVec2(0.0, 0.0)) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - ImGui.Text("Progress Bar") - ImGui.ProgressBar(progress, ImVec2(0.0, 0.0), string.format("%d/%d", math.floor(progress * 1753), 1753)) - - -- Pass an animated negative value, e.g. -1.0 * ImGui.GetTime() is the recommended value. - -- Adjust the factor if you want to adjust the animation speed. - ImGui.ProgressBar(-1.0 * ImGui.GetTime(), ImVec2(0.0, 0.0), "Searching..") - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - ImGui.Text("Indeterminate") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsQueryingStatuses() -------------------------------------------------------------------------------- - --- Selectable(label, bool* p_selected) overload: toggles on press -local function SelectableP(label, sel, flags, size) - local pressed = ImGui.Selectable(label, sel, flags, size) - if pressed then sel = not sel end - return pressed, sel -end - -local function B(v) return v and 1 or 0 end - -S.qs = { item_type = 4, item_disabled = false, item_mixedvalue = false, liveedit_override = false, liveedit_flags = 0, - b = false, col4f = { 1.0, 0.5, 0.0, 1.0 }, str = Buf("", 16), combo = 1, listbox = 1, unused = Buf("", 1), - embed = false, test_window = false } -function DemoWindowWidgetsQueryingStatuses() - local s = S.qs - if ImGui.TreeNode("Querying Item Status (Edited/Active/Hovered etc.)") then - -- Select an item type - local item_names = { "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", - "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" } - s.item_type = ImGui.Combo("Item Type", s.item_type, item_names, #item_names, #item_names) - ImGui.SameLine() - HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().") - _, s.item_disabled = ImGui.Checkbox("Item Disabled", s.item_disabled) - _, s.item_mixedvalue = ImGui.Checkbox("Item MixedValue", s.item_mixedvalue) - _, s.liveedit_override = ImGui.Checkbox("Override LiveEdit:", s.liveedit_override) - ImGui.SameLine() - if not s.liveedit_override then s.liveedit_flags = ImGui.GetItemFlags() end - ImGui.BeginDisabled(s.liveedit_override == false) - _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInput", s.liveedit_flags, 384 --[[ImGuiItemFlags.LiveEditOnInput]]) - ImGui.SameLine() - _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputText", s.liveedit_flags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) - ImGui.SameLine() - _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputScalar", s.liveedit_flags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) - ImGui.EndDisabled() - if s.liveedit_override then - ImGui.PushItemFlag(128 --[[ImGuiItemFlags.LiveEditOnInputText]], bit32.band(s.liveedit_flags, 128 --[[ImGuiItemFlags.LiveEditOnInputText]]) ~= 0) - ImGui.PushItemFlag(256 --[[ImGuiItemFlags.LiveEditOnInputScalar]], bit32.band(s.liveedit_flags, 256 --[[ImGuiItemFlags.LiveEditOnInputScalar]]) ~= 0) - end - - -- Submit selected items so we can query their status in the code following it. - local ret = false - local t = s.item_type - if s.item_disabled then ImGui.BeginDisabled(true) end - if s.item_mixedvalue then ImGui.PushItemFlag(4096 --[[ImGuiItemFlags.MixedValue]], true) end - if t == 0 then ImGui.Text("ITEM: Text") end -- Testing text items with no identifier/interaction - if t == 1 then ret = ImGui.Button("ITEM: Button") end -- Testing button - if t == 2 then ImGui.PushItemFlag(8 --[[ImGuiItemFlags.ButtonRepeat]], true); ret = ImGui.Button("ITEM: Button"); ImGui.PopItemFlag() end -- Testing button (with repeater) - if t == 3 then ret, s.b = ImGui.Checkbox("ITEM: Checkbox", s.b) end -- Testing checkbox - if t == 4 then s.col4f[1], ret = ImGui.SliderFloat("ITEM: SliderFloat", s.col4f[1], 0.0, 1.0) end -- Testing basic item - if t == 5 then ret = ImGui.InputText("ITEM: InputText", s.str, 16) end -- Testing input text (which handles tabbing) - if t == 6 then ret = ImGui.InputTextMultiline("ITEM: InputTextMultiline", s.str, 16) end -- Testing input text (which uses a child window) - if t == 7 then s.col4f[1], ret = ImGui.InputFloat("ITEM: InputFloat", s.col4f[1], 1.0) end -- Testing +/- buttons on scalar input - if t == 8 then ret = ImGui.InputFloat3("ITEM: InputFloat3", s.col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) - if t == 9 then ret = ImGui.ColorEdit4("ITEM: ColorEdit4", s.col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) - if t == 10 then ret = ImGui.Selectable("ITEM: Selectable") end -- Testing selectable item - if t == 11 then ret = ImGui.MenuItem("ITEM: MenuItem") end -- Testing menu item (they use ImGuiButtonFlags.PressedOnRelease button policy) - if t == 12 then ret = ImGui.TreeNode("ITEM: TreeNode"); if ret then ImGui.TreePop() end end -- Testing tree node - if t == 13 then ret = ImGui.TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", bit32.bor(64 --[[ImGuiTreeNodeFlags.OpenOnDoubleClick]], 8 --[[ImGuiTreeNodeFlags.NoTreePushOnOpen]])) end -- Testing tree node with ImGuiButtonFlags.PressedOnDoubleClick button policy. - if t == 14 then s.combo, ret = ImGui.Combo("ITEM: Combo", s.combo, { "Apple", "Banana", "Cherry", "Kiwi" }) end - if t == 15 then s.listbox, ret = ImGui.ListBox("ITEM: ListBox", s.listbox, { "Apple", "Banana", "Cherry", "Kiwi" }, 4, 4) end - - local HF = ImGuiHoveredFlags - local hovered_delay_none = ImGui.IsItemHovered() - local hovered_delay_stationary = ImGui.IsItemHovered(HF.Stationary) - local hovered_delay_short = ImGui.IsItemHovered(HF.DelayShort) - local hovered_delay_normal = ImGui.IsItemHovered(HF.DelayNormal) - local hovered_delay_tooltip = ImGui.IsItemHovered(HF.ForTooltip) -- = Normal + Stationary - - -- Display the values of IsItemHovered() and other common item state functions. - -- Note that the ImGuiHoveredFlags.XXX flags can be combined. - -- Because BulletText is an item itself and that would affect the output of IsItemXXX functions, - -- we query every state in a single call to avoid storing them and to simplify the code. - local rmin, rmax, rsize = ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ImGui.GetItemRectSize() - ImGui.BulletText( - "Return value = %d\nIsItemFocused() = %d\nIsItemHovered() = %d\nIsItemHovered(_AllowWhenBlockedByPopup) = %d\n" .. - "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\nIsItemHovered(_AllowWhenOverlappedByItem) = %d\n" .. - "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\nIsItemHovered(_AllowWhenDisabled) = %d\nIsItemHovered(_RectOnly) = %d\n" .. - "IsItemActive() = %d\nIsItemEdited() = %d\nIsItemActivated() = %d\nIsItemDeactivated() = %d\nIsItemDeactivatedAfterEdit() = %d\n" .. - "IsItemVisible() = %d\nIsItemClicked() = %d\nIsItemToggledOpen() = %d\n" .. - "GetItemRectMin() = (%.1f, %.1f)\nGetItemRectMax() = (%.1f, %.1f)\nGetItemRectSize() = (%.1f, %.1f)", - B(ret), B(ImGui.IsItemFocused()), B(ImGui.IsItemHovered()), B(ImGui.IsItemHovered(HF.AllowWhenBlockedByPopup)), - B(ImGui.IsItemHovered(HF.AllowWhenBlockedByActiveItem)), B(ImGui.IsItemHovered(HF.AllowWhenOverlappedByItem)), - B(ImGui.IsItemHovered(HF.AllowWhenOverlappedByWindow)), B(ImGui.IsItemHovered(HF.AllowWhenDisabled)), B(ImGui.IsItemHovered(HF.RectOnly)), - B(ImGui.IsItemActive()), B(ImGui.IsItemEdited()), B(ImGui.IsItemActivated()), B(ImGui.IsItemDeactivated()), B(ImGui.IsItemDeactivatedAfterEdit()), - B(ImGui.IsItemVisible()), B(ImGui.IsItemClicked()), B(ImGui.IsItemToggledOpen()), - rmin.x, rmin.y, rmax.x, rmax.y, rsize.x, rsize.y) - ImGui.BulletText( - "with Hovering Delay or Stationary test:\nIsItemHovered() = %d\nIsItemHovered(_Stationary) = %d\nIsItemHovered(_DelayShort) = %d\nIsItemHovered(_DelayNormal) = %d\nIsItemHovered(_Tooltip) = %d", - B(hovered_delay_none), B(hovered_delay_stationary), B(hovered_delay_short), B(hovered_delay_normal), B(hovered_delay_tooltip)) - - if s.liveedit_override then ImGui.PopItemFlag(); ImGui.PopItemFlag() end - if s.item_mixedvalue then ImGui.PopItemFlag() end - if s.item_disabled then ImGui.EndDisabled() end - - ImGui.InputText("unused", s.unused, 1, 512 --[[ImGuiInputTextFlags.ReadOnly]]) - ImGui.SameLine() - HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.") - ImGui.TreePop() - end - - if ImGui.TreeNode("Querying Window Status (Focused/Hovered etc.)") then - _, s.embed = ImGui.Checkbox("Embed everything inside a child window for testing _RootWindow flag.", s.embed) - if s.embed then ImGui.BeginChild("outer_child", ImVec2(0, ImGui.GetFontSize() * 20.0), 1 --[[ImGuiChildFlags.Borders]]) end - local FF, HF = ImGuiFocusedFlags, ImGuiHoveredFlags - local bor = bit32.bor - -- Testing IsWindowFocused() function with its various flags. - ImGui.BulletText( - "IsWindowFocused() = %d\nIsWindowFocused(_ChildWindows) = %d\nIsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" .. - "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\nIsWindowFocused(_ChildWindows|_RootWindow) = %d\n" .. - "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\nIsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" .. - "IsWindowFocused(_RootWindow) = %d\nIsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\nIsWindowFocused(_RootWindow|_DockHierarchy) = %d\n" .. - "IsWindowFocused(_AnyWindow) = %d\n", - B(ImGui.IsWindowFocused()), B(ImGui.IsWindowFocused(FF.ChildWindows)), B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.NoPopupHierarchy))), - B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.DockHierarchy))), B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.RootWindow))), - B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.RootWindow, FF.NoPopupHierarchy))), B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.RootWindow, FF.DockHierarchy))), - B(ImGui.IsWindowFocused(FF.RootWindow)), B(ImGui.IsWindowFocused(bor(FF.RootWindow, FF.NoPopupHierarchy))), B(ImGui.IsWindowFocused(bor(FF.RootWindow, FF.DockHierarchy))), - B(ImGui.IsWindowFocused(FF.AnyWindow))) - - -- Testing IsWindowHovered() function with its various flags. - ImGui.BulletText( - "IsWindowHovered() = %d\nIsWindowHovered(_AllowWhenBlockedByPopup) = %d\nIsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" .. - "IsWindowHovered(_ChildWindows) = %d\nIsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\nIsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n" .. - "IsWindowHovered(_ChildWindows|_RootWindow) = %d\nIsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" .. - "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\nIsWindowHovered(_RootWindow) = %d\nIsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" .. - "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\nIsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\nIsWindowHovered(_AnyWindow) = %d\n" .. - "IsWindowHovered(_Stationary) = %d\n", - B(ImGui.IsWindowHovered()), B(ImGui.IsWindowHovered(HF.AllowWhenBlockedByPopup)), B(ImGui.IsWindowHovered(HF.AllowWhenBlockedByActiveItem)), - B(ImGui.IsWindowHovered(HF.ChildWindows)), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.NoPopupHierarchy))), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.DockHierarchy))), - B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.RootWindow))), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.RootWindow, HF.NoPopupHierarchy))), - B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.RootWindow, HF.DockHierarchy))), B(ImGui.IsWindowHovered(HF.RootWindow)), B(ImGui.IsWindowHovered(bor(HF.RootWindow, HF.NoPopupHierarchy))), - B(ImGui.IsWindowHovered(bor(HF.RootWindow, HF.DockHierarchy))), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.AllowWhenBlockedByPopup))), B(ImGui.IsWindowHovered(HF.AnyWindow)), - B(ImGui.IsWindowHovered(HF.Stationary))) - ImGui.BeginChild("child", ImVec2(0, 50), 1 --[[ImGuiChildFlags.Borders]]) - ImGui.Text("This is another child window for testing the _ChildWindows flag.") - ImGui.EndChild() - if s.embed then ImGui.EndChild() end - - -- Calling IsItemHovered() after begin returns the hovered status of the title bar. - -- This is useful in particular if you want to create a context menu associated to the title bar of a window. - -- This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties). - _, s.test_window = ImGui.Checkbox("Hovered/Active tests after Begin() for title bar testing", s.test_window) - if s.test_window then - -- FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. - -- Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? - s.test_window = ImGui.Begin("Title bar Hovered/Active tests", s.test_window) - if ImGui.BeginPopupContextItem() then -- <-- This is using IsItemHovered() - if ImGui.MenuItem("Close") then s.test_window = false end - ImGui.EndPopup() - end - ImGui.Text("IsItemHovered() after begin = %d (== is title bar hovered)\nIsItemActive() after begin = %d (== is window being clicked/moved)\n", - B(ImGui.IsItemHovered()), B(ImGui.IsItemActive())) - ImGui.End() - end - ImGui.TreePop() - end -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsSelectables() -------------------------------------------------------------------------------- - -S.sel = { basic = { false, true, false, false }, multi = { false, false, false }, checked = { false, false, false, false, false }, selected_n = 0, - tables = {}, grid = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }, - align = { true, false, true, false, true, false, true, false, true } } -for i = 1, 10 do S.sel.tables[i] = false end -function DemoWindowWidgetsSelectables() - -- ImGui.SetNextItemOpen(true, ImGuiCond.Once) - if not ImGui.TreeNode("Selectables") then return end - local s = S.sel - -- Selectable() has 2 overloads: - -- - The one taking "bool selected" as a read-only selection information. - -- When Selectable() has been clicked it returns true and you can alter selection state accordingly. - -- - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) - -- (in this port: the SelectableP() helper above, which returns (pressed, selected)) - -- The earlier is more flexible, as in real application your selection may be stored in many different ways - -- and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). - if ImGui.TreeNode("Basic") then - local b = s.basic - _, b[1] = SelectableP("1. I am selectable", b[1]) - _, b[2] = SelectableP("2. I am selectable", b[2]) - _, b[3] = SelectableP("3. I am selectable", b[3]) - if ImGui.Selectable("4. I am double clickable", b[4], 4 --[[ImGuiSelectableFlags.AllowDoubleClick]]) then - if ImGui.IsMouseDoubleClicked(0) then b[4] = not b[4] end - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Multiple items on the same line") then - -- - Using SetNextItemAllowOverlap() - -- - Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. - local m = s.multi - ImGui.SetNextItemAllowOverlap(); _, m[1] = SelectableP("main.c", m[1]); ImGui.SameLine(); ImGui.SmallButton("Link 1") - ImGui.SetNextItemAllowOverlap(); _, m[2] = SelectableP("hello.cpp", m[2]); ImGui.SameLine(); ImGui.SmallButton("Link 2") - ImGui.SetNextItemAllowOverlap(); _, m[3] = SelectableP("hello.h", m[3]); ImGui.SameLine(); ImGui.SmallButton("Link 3") - - -- (2) - -- - Using ImGuiSelectableFlags.AllowOverlap is a shortcut for calling SetNextItemAllowOverlap() - -- - No visible label, display contents inside the selectable bounds. - -- - We don't maintain actual selection in this example to keep things simple. - ImGui.Spacing() - local color_marker_w = ImGui.CalcTextSize("x").x - for n = 0, 4 do - ImGui.PushID(n) - ImGui.AlignTextToFramePadding() - if ImGui.Selectable("##selectable", s.selected_n == n, 16 --[[ImGuiSelectableFlags.AllowOverlap]]) then s.selected_n = n end - ImGui.SameLine(0, 0) - _, s.checked[n + 1] = ImGui.Checkbox("##check", s.checked[n + 1]) - ImGui.SameLine() - local color = ImVec4((n % 2 == 1) and 1.0 or 0.2, (math.floor(n / 2) % 2 == 1) and 1.0 or 0.2, 0.2, 1.0) - ImGui.ColorButton("##color", color, 64 --[[ImGuiColorEditFlags.NoTooltip]], ImVec2(color_marker_w, 0)) - ImGui.SameLine() - ImGui.Text("Some label") - ImGui.PopID() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("In Tables") then - local sel = s.tables - local TF = ImGuiTableFlags - if ImGui.BeginTable("split1", 3, bit32.bor(TF.Resizable, TF.NoSavedSettings, TF.Borders)) then - for i = 0, 9 do - ImGui.TableNextColumn() - _, sel[i + 1] = SelectableP(string.format("Item %d", i), sel[i + 1]) -- FIXME-TABLE: Selection overlap - end - ImGui.EndTable() - end - ImGui.Spacing() - if ImGui.BeginTable("split2", 3, bit32.bor(TF.Resizable, TF.NoSavedSettings, TF.Borders)) then - for i = 0, 9 do - ImGui.TableNextRow() - ImGui.TableNextColumn() - _, sel[i + 1] = SelectableP(string.format("Item %d", i), sel[i + 1], 2 --[[ImGuiSelectableFlags.SpanAllColumns]]) - ImGui.TableNextColumn() - ImGui.Text("Some other contents") - ImGui.TableNextColumn() - ImGui.Text("123456") - end - ImGui.EndTable() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Grid") then - local g = s.grid - - -- Add in a bit of silly fun... - local time = ImGui.GetTime() - local winning_state = true - for y = 1, 4 do for x = 1, 4 do if g[y][x] == 0 then winning_state = false end end end -- If all cells are selected... - if winning_state then - ImGui.PushStyleVar(39 --[[ImGuiStyleVar.SelectableTextAlign]], ImVec2(0.5 + 0.5 * math.cos(time * 2.0), 0.5 + 0.5 * math.sin(time * 3.0))) - end - local size = ImGui.CalcTextSize("Sailor").x - for y = 1, 4 do - for x = 1, 4 do - if x > 1 then ImGui.SameLine() end - ImGui.PushID((y - 1) * 4 + (x - 1)) - if ImGui.Selectable("Sailor", g[y][x] ~= 0, 0, ImVec2(size, size)) then - -- Toggle clicked cell + toggle neighbors - g[y][x] = 1 - g[y][x] - if x > 1 then g[y][x - 1] = 1 - g[y][x - 1] end - if x < 4 then g[y][x + 1] = 1 - g[y][x + 1] end - if y > 1 then g[y - 1][x] = 1 - g[y - 1][x] end - if y < 4 then g[y + 1][x] = 1 - g[y + 1][x] end - end - ImGui.PopID() - end - end - if winning_state then ImGui.PopStyleVar() end - ImGui.TreePop() - end - - if ImGui.TreeNode("Alignment") then - HelpMarker("By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item basis using PushStyleVar(). You'll probably want to always keep your default situation to left-align otherwise it becomes difficult to layout multiple items on a same line") - local size = ImGui.CalcTextSize("(1.0,1.0)").x - for y = 0, 2 do - for x = 0, 2 do - local alignment = ImVec2(x / 2.0, y / 2.0) - local name = string.format("(%.1f,%.1f)", alignment.x, alignment.y) - if x > 0 then ImGui.SameLine() end - ImGui.PushStyleVar(39 --[[ImGuiStyleVar.SelectableTextAlign]], alignment) - _, s.align[3 * y + x + 1] = SelectableP(name, s.align[3 * y + x + 1], 0 --[[ImGuiSelectableFlags.None]], ImVec2(size, size)) - ImGui.PopStyleVar() - end - end - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTabs() -------------------------------------------------------------------------------- - -local function EditTabBarFittingPolicyFlags(flags) - local TB = ImGuiTabBarFlags - if bit32.band(flags, TB.FittingPolicyMask_) == 0 then flags = bit32.bor(flags, TB.FittingPolicyDefault_) end - for _, n in ipairs({ "FittingPolicyMixed", "FittingPolicyShrink", "FittingPolicyScroll" }) do - local p - p, flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_" .. n, flags, TB[n]) - if p then flags = bit32.band(flags, bit32.bnot(bit32.bxor(TB.FittingPolicyMask_, TB[n]))) end - end - return flags -end - -S.tabs = { adv_flags = ImGuiTabBarFlags.Reorderable, opened = { true, true, true, true }, active_tabs = {}, next_tab_id = 0, - show_leading = true, show_trailing = true, show_lt_tabs = false, - tib_flags = bit32.bor(ImGuiTabBarFlags.AutoSelectNewTabs, ImGuiTabBarFlags.Reorderable, ImGuiTabBarFlags.FittingPolicyMixed) } -function DemoWindowWidgetsTabs() - if not ImGui.TreeNode("Tabs") then return end - local s = S.tabs - local TB, TI = ImGuiTabBarFlags, ImGuiTabItemFlags - if ImGui.TreeNode("Basic") then - if ImGui.BeginTabBar("MyTabBar", TB.None) then - if ImGui.BeginTabItem("Avocado") then ImGui.Text("This is the Avocado tab!\nblah blah blah blah blah"); ImGui.EndTabItem() end - if ImGui.BeginTabItem("Broccoli") then ImGui.Text("This is the Broccoli tab!\nblah blah blah blah blah"); ImGui.EndTabItem() end - if ImGui.BeginTabItem("Cucumber") then ImGui.Text("This is the Cucumber tab!\nblah blah blah blah blah"); ImGui.EndTabItem() end - ImGui.EndTabBar() - end - ImGui.Separator() - ImGui.TreePop() - end - - if ImGui.TreeNode("Advanced & Close Button") then - -- Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). - for _, n in ipairs({ "Reorderable", "AutoSelectNewTabs", "TabListPopupButton", "NoCloseWithMiddleMouseButton", "DrawSelectedOverline" }) do - _, s.adv_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_" .. n, s.adv_flags, TB[n]) - end - s.adv_flags = EditTabBarFittingPolicyFlags(s.adv_flags) - - -- Tab Bar - ImGui.AlignTextToFramePadding() - ImGui.Text("Opened:") - local names = { "Artichoke", "Beetroot", "Celery", "Daikon" } - for n = 1, 4 do -- s.opened: Persistent user state - ImGui.SameLine() - _, s.opened[n] = ImGui.Checkbox(names[n], s.opened[n]) - end - - -- Passing an open flag to BeginTabItem() is similar to passing one to Begin(): - -- the returned open value will be false when the tab is closed. - if ImGui.BeginTabBar("MyTabBar", s.adv_flags) then - for n = 1, 4 do - if s.opened[n] then - local visible - visible, s.opened[n] = ImGui.BeginTabItem(names[n], s.opened[n], TI.None) - if visible then - ImGui.Text("This is the %s tab!", names[n]) - if (n - 1) % 2 == 1 then ImGui.Text("I am an odd tab.") end - ImGui.EndTabItem() - end - end - end - ImGui.EndTabBar() - end - ImGui.Separator() - ImGui.TreePop() - end - - if ImGui.TreeNode("TabItemButton & Leading/Trailing flags") then - if s.next_tab_id == 0 then -- Initialize with some default tabs - for _ = 1, 3 do s.active_tabs[#s.active_tabs + 1] = s.next_tab_id; s.next_tab_id = s.next_tab_id + 1 end - end - - -- TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. - -- (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... - -- but they tend to make more sense together) - _, s.show_leading = ImGui.Checkbox("Show Leading TabItemButton()", s.show_leading) - _, s.show_trailing = ImGui.Checkbox("Show Trailing TabItemButton()", s.show_trailing) - _, s.show_lt_tabs = ImGui.Checkbox("Show Leading+Trailing TabItem()", s.show_lt_tabs) - - -- Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs - s.tib_flags = EditTabBarFittingPolicyFlags(s.tib_flags) - - if ImGui.BeginTabBar("MyTabBar", s.tib_flags) then - -- Demo a Leading TabItemButton(): click the "?" button to open a menu - if s.show_leading then - if ImGui.TabItemButton("?", bit32.bor(TI.Leading, TI.NoTooltip)) then ImGui.OpenPopup("MyHelpMenu") end - end - if ImGui.BeginPopup("MyHelpMenu") then - ImGui.Selectable("Hello!") - ImGui.EndPopup() - end - - -- Demo Leading/Trailing Tabs - if s.show_lt_tabs then - if ImGui.BeginTabItem("Leading", nil, TI.Leading) then ImGui.EndTabItem() end - if ImGui.BeginTabItem("Trailing", nil, TI.Trailing) then ImGui.EndTabItem() end - end - - -- Demo Trailing Tabs: click the "+" button to add a new tab. - -- (In your app you may want to use a font icon instead of the "+") - -- We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags.Trailing flag it will always appear at the end. - if s.show_trailing then - if ImGui.TabItemButton("+", bit32.bor(TI.Trailing, TI.NoTooltip)) then - s.active_tabs[#s.active_tabs + 1] = s.next_tab_id; s.next_tab_id = s.next_tab_id + 1 -- Add new tab - end - end - - -- Submit our regular tabs - local n = 1 - while n <= #s.active_tabs do - local name = string.format("%04d", s.active_tabs[n]) - local visible, open = ImGui.BeginTabItem(name, true, TI.None) - if visible then - ImGui.Text("This is the %s tab!", name) - ImGui.EndTabItem() - end - if open == false then table.remove(s.active_tabs, n) else n = n + 1 end - end - ImGui.EndTabBar() - end - ImGui.Separator() - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsText() -------------------------------------------------------------------------------- - -S.text = { custom_size = 16.0, custom_scale = 1.0, wrap_width = 200.0, utf8 = Buf("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e", 32) } -function DemoWindowWidgetsText() - if not ImGui.TreeNode("Text") then return end - local s = S.text - if ImGui.TreeNode("Colorful Text") then - -- Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. - ImGui.TextColored(ImVec4(1.0, 0.0, 1.0, 1.0), "Pink") - ImGui.TextColored(ImVec4(1.0, 1.0, 0.0, 1.0), "Yellow") - ImGui.TextDisabled("Disabled") - ImGui.SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.") - ImGui.TreePop() - end - - if ImGui.TreeNode("Font Size") then - local style = ImGui.GetStyle() - local global_scale = style.FontScaleMain * style.FontScaleDpi - ImGui.Text("style.FontScaleMain = %0.2f", style.FontScaleMain) - ImGui.Text("style.FontScaleDpi = %0.2f", style.FontScaleDpi) - ImGui.Text("global_scale = ~%0.2f", global_scale) -- This is not technically accurate as internal scales may apply, but conceptually let's pretend it is. - ImGui.Text("FontSize = %0.2f", ImGui.GetFontSize()) - - ImGui.SeparatorText("") - s.custom_size = ImGui.SliderFloat("custom_size", s.custom_size, 10.0, 100.0, "%.0f") - ImGui.Text("ImGui::PushFont(nullptr, custom_size);") - ImGui.PushFont(nil, s.custom_size) - ImGui.Text("FontSize = %.2f (== %.2f * global_scale)", ImGui.GetFontSize(), s.custom_size) - ImGui.PopFont() - ImGui.SeparatorText("") - s.custom_scale = ImGui.SliderFloat("custom_scale", s.custom_scale, 0.5, 4.0, "%.2f") - ImGui.Text("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scale);") - ImGui.PushFont(nil, style.FontSizeBase * s.custom_scale) - ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), s.custom_scale) - ImGui.PopFont() - ImGui.SeparatorText("") - local scaling = 0.5 - while scaling <= 4.0 do - ImGui.PushFont(nil, style.FontSizeBase * scaling) - ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), scaling) - ImGui.PopFont() - scaling = scaling + 0.5 - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Word Wrapping") then - -- Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. - ImGui.TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages.") - ImGui.Spacing() - s.wrap_width = ImGui.SliderFloat("Wrap width", s.wrap_width, -20, 600, "%.0f") - local draw_list = ImGui.GetWindowDrawList() - for n = 0, 1 do - ImGui.Text("Test paragraph %d:", n) - local pos = ImGui.GetCursorScreenPos() - local marker_min = ImVec2(pos.x + s.wrap_width, pos.y) - local marker_max = ImVec2(pos.x + s.wrap_width + 10, pos.y + ImGui.GetTextLineHeight()) - ImGui.PushTextWrapPos(ImGui.GetCursorPos().x + s.wrap_width) - if n == 0 then - ImGui.Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", s.wrap_width) - else - ImGui.Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh") - end - - -- Draw actual text bounding box, following by marker of our expected limit (should not overlap!) - draw_list:AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), IM_COL32(255, 255, 0, 255)) - draw_list:AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)) - ImGui.PopTextWrapPos() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("UTF-8 Text") then - -- UTF-8 test with Japanese characters - -- (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) - -- - FOR THIS DEMO FILE ONLY, WE ARE *NOT* INCLUDING RAW UTF-8 - -- CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal escapes. - -- Note that characters values are preserved even by InputText() if the font cannot be displayed, - -- so you can safely copy & paste garbled characters into another application. - ImGui.TextWrapped("CJK text will only appear if the font was loaded with the appropriate CJK character ranges. Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. Read docs/FONTS.md for details.") - ImGui.Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)") - ImGui.Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)") - ImGui.InputText("UTF-8 input", s.utf8, 32) - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTextFilter() -------------------------------------------------------------------------------- - -S.tf = { filter = nil } -function DemoWindowWidgetsTextFilter() - if not ImGui.TreeNode("Text Filter") then return end - -- Helper class to easy setup a text filter. - -- You may want to implement a more feature-full filtering scheme in your own application. - S.tf.filter = S.tf.filter or ImGuiTextFilter() - local filter = S.tf.filter - HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.") - ImGui.Text("Filter usage:\n \"\" display all lines\n xxx display lines containing \"xxx\"\n xxx yyy display lines containing \"xxx\" and \"yyy\"\n \"xxx yyy\" display lines containing \"xxx yyy\"\n xxx,yyy display lines containing \"xxx\" or \"yyy\"\n -xxx hide lines containing \"xxx\"") - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - filter:DrawWithHint("##Filter", "Filter (incl -excl)") - if ImGui.BeginChild("##items", ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeightWithSpacing() * 15), 128 --[[ImGuiChildFlags.FrameStyle]]) then - for _, item in ipairs({ "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }) do - if filter:PassFilter(item) then ImGui.TextUnformatted(item) end - end - for _, item in ipairs(ExampleNames) do - if filter:PassFilter(item) then ImGui.TextUnformatted(item) end - end - end - ImGui.EndChild() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTextInput() -------------------------------------------------------------------------------- - -S.ti = { - text = Buf("/*\n The Pentium F00F bug, shorthand for F0 0F C7 C8,\n the hexadecimal encoding of one offending instruction,\n more formally, the invalid operand with locked CMPXCHG8B\n instruction bug, is a design flaw in the majority of\n Intel Pentium, Pentium MMX, and Pentium OverDrive\n processors (all in the P5 microarchitecture).\n*/\n\nlabel:\n\tlock cmpxchg8b eax\n", 1024 * 16), - ml_flags = ImGuiInputTextFlags.AllowTabInput, - f = { Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32) }, - password = Buf("password123", 64), cb1 = Buf("", 64), cb2 = Buf("", 64), cb3 = Buf("", 64), edit_count = { 0 }, - rs_flags = 0, rs = Buf("", 1024), - elide = Buf("/path/to/some/folder/with/long/filename.cpp", 128), elide_flags = ImGuiInputTextFlags.ElideLeft, - misc = Buf("", 16), misc_flags = ImGuiInputTextFlags.EscapeClearsAll } -function DemoWindowWidgetsTextInput() - if not ImGui.TreeNode("Text Input") then return end - local s = S.ti - local IT = ImGuiInputTextFlags - local function FlagBox(key, name) - if IT[name] then _, s[key] = ImGui.CheckboxFlags("ImGuiInputTextFlags_" .. name, s[key], IT[name]) end - end - if ImGui.TreeNode("Multi-line Text Input") then - -- WE ARE USING A FIXED-SIZE BUFFER FOR SIMPLICITY HERE. - HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type.") - FlagBox("ml_flags", "ReadOnly") - FlagBox("ml_flags", "WordWrap") - ImGui.SameLine(); HelpMarker("Feature is currently in Beta. Please read comments in imgui.h") - FlagBox("ml_flags", "AllowTabInput") - ImGui.SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets.") - FlagBox("ml_flags", "CtrlEnterForNewLine") - ImGui.InputTextMultiline("##source", s.text, 1024 * 16, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeight() * 16), s.ml_flags) - ImGui.TreePop() - end - - if ImGui.TreeNode("Filtered Text Input") then - local a, z, A, Z = string.byte("a"), string.byte("z"), string.byte("A"), string.byte("Z") - -- Modify character input by altering 'data.EventChar' (ImGuiInputTextFlags.CallbackCharFilter callback) - local function FilterCasingSwap(data) - local c = data.EventChar - if c >= a and c <= z then data.EventChar = c - (a - A) -- Lowercase becomes uppercase - elseif c >= A and c <= Z then data.EventChar = c + (a - A) end -- Uppercase becomes lowercase - return 0 - end - -- Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) - local function FilterImGuiLetters(data) - local c = data.EventChar - if c < 256 and string.find("imgui", string.char(c), 1, true) then return 0 end - return 1 - end - local f = s.f - ImGui.InputText("default", f[1], 32) - ImGui.InputText("decimal", f[2], 32, IT.CharsDecimal) - ImGui.InputText("hexadecimal", f[3], 32, bit32.bor(IT.CharsHexadecimal, IT.CharsUppercase)) - ImGui.InputText("uppercase", f[4], 32, IT.CharsUppercase) - ImGui.InputText("no blank", f[5], 32, IT.CharsNoBlank) - ImGui.InputText("casing swap", f[6], 32, IT.CallbackCharFilter, FilterCasingSwap) -- Use CharFilter callback to replace characters. - ImGui.InputText("\"imgui\"", f[7], 32, IT.CallbackCharFilter, FilterImGuiLetters) -- Use CharFilter callback to disable some characters. - ImGui.TreePop() - end - - if ImGui.TreeNode("Password Input") then - ImGui.InputText("password", s.password, 64, IT.Password) - ImGui.SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n") - ImGui.InputTextWithHint("password (w/ hint)", "", s.password, 64, IT.Password) - ImGui.InputText("password (clear)", s.password, 64) - ImGui.TreePop() - end - - if ImGui.TreeNode("Completion, History, Edit Callbacks") then - local function MyCallback(data) - if data.EventFlag == IT.CallbackCompletion then - data:InsertChars(data.CursorPos, "..") - elseif data.EventFlag == IT.CallbackHistory then - if data.EventKey == 515 --[[ImGuiKey.UpArrow]] then - data:DeleteChars(0, data.BufTextLen) - data:InsertChars(0, "Pressed Up!") - data:SelectAll() - elseif data.EventKey == 516 --[[ImGuiKey.DownArrow]] then - data:DeleteChars(0, data.BufTextLen) - data:InsertChars(0, "Pressed Down!") - data:SelectAll() - end - elseif data.EventFlag == IT.CallbackEdit then - -- Toggle casing of first character - local c = data.Buf[1] - if (c >= 97 and c <= 122) or (c >= 65 and c <= 90) then data.Buf[1] = bit32.bxor(c, 32) end - data.BufDirty = true - - -- Increment a counter - local p_int = data.UserData - p_int[1] = p_int[1] + 1 - end - return 0 - end - ImGui.InputText("Completion", s.cb1, 64, IT.CallbackCompletion, MyCallback) - ImGui.SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.") - ImGui.InputText("History", s.cb2, 64, IT.CallbackHistory, MyCallback) - ImGui.SameLine(); HelpMarker("Here we replace and select text each time Up/Down are pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.") - ImGui.InputText("Edit", s.cb3, 64, IT.CallbackEdit, MyCallback, s.edit_count) - ImGui.SameLine(); HelpMarker("Here we toggle the casing of the first character on every edit + count edits.") - ImGui.SameLine(); ImGui.Text("(%d)", s.edit_count[1]) - ImGui.TreePop() - end - - if ImGui.TreeNode("Resize Callback") then - HelpMarker("Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n(Lua port: fixed 1024 byte buffer, CallbackResize growth not supported)") - FlagBox("rs_flags", "WordWrap") - ImGui.InputTextMultiline("##MyStr", s.rs, 1024, ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], ImGui.GetTextLineHeight() * 16), s.rs_flags) - ImGui.Text("Size: %d\nCapacity: %d", #BufStr(s.rs) + 1, 1024) - ImGui.TreePop() - end - - if ImGui.TreeNode("Eliding, Alignment") then - FlagBox("elide_flags", "ElideLeft") - ImGui.InputText("Path", s.elide, 128, s.elide_flags) - ImGui.TreePop() - end - - if ImGui.TreeNode("Miscellaneous") then - FlagBox("misc_flags", "EscapeClearsAll") - FlagBox("misc_flags", "ReadOnly") - FlagBox("misc_flags", "NoUndoRedo") - ImGui.InputText("Hello", s.misc, 16, s.misc_flags) - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTooltips() -------------------------------------------------------------------------------- - -S.tt = { arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, always_on = 0 } -function DemoWindowWidgetsTooltips() - if not ImGui.TreeNode("Tooltips") then return end - local s = S.tt - local HF = ImGuiHoveredFlags - -- Tooltips are windows following the mouse. They do not take focus away. - ImGui.SeparatorText("General") - - -- Typical use cases: - -- - Short-form (text only): SetItemTooltip("Hello") - -- - Short-form (any contents): if BeginItemTooltip() then Text("Hello"); EndTooltip() end - - -- - Full-form (text only): if IsItemHovered(...) then SetTooltip("Hello") end - -- - Full-form (any contents): if IsItemHovered(...) and BeginTooltip() then Text("Hello"); EndTooltip() end - - HelpMarker("Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\nWe provide a helper SetItemTooltip() function to perform the two with standards flags.") - local sz = ImVec2(-1.1754943508223e-38 --[[FLT_MIN]], 0.0) - ImGui.Button("Basic", sz) - ImGui.SetItemTooltip("I am a tooltip") - ImGui.Button("Fancy", sz) - if ImGui.BeginItemTooltip() then - ImGui.Text("I am a fancy tooltip") - ImGui.PlotLines("Curve", s.arr, nil, #s.arr) - ImGui.Text("Sin(time) = %f", math.sin(ImGui.GetTime())) - ImGui.EndTooltip() - end - - ImGui.SeparatorText("Always On") - - -- Showcase NOT relying on a IsItemHovered() to emit a tooltip. - -- Here the tooltip is always emitted when 'always_on == true'. - _, s.always_on = ImGui.RadioButton("Off", s.always_on, 0) - ImGui.SameLine() - _, s.always_on = ImGui.RadioButton("Always On (Simple)", s.always_on, 1) - ImGui.SameLine() - _, s.always_on = ImGui.RadioButton("Always On (Advanced)", s.always_on, 2) - if s.always_on == 1 then - ImGui.SetTooltip("I am following you around.") - elseif s.always_on == 2 and ImGui.BeginTooltip() then - ImGui.ProgressBar(math.sin(ImGui.GetTime()) * 0.5 + 0.5, ImVec2(ImGui.GetFontSize() * 25, 0.0)) - ImGui.EndTooltip() - end - - ImGui.SeparatorText("Custom") - HelpMarker("Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize tooltip activation details across your application. You may however decide to use custom flags for a specific tooltip instance.") - - -- The following examples are passed for documentation purpose but may not be useful to most users. - -- Passing ImGuiHoveredFlags.ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from - -- 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. - -- With default settings, ImGuiHoveredFlags.ForTooltip is equivalent to ImGuiHoveredFlags.DelayShort + ImGuiHoveredFlags.Stationary. - ImGui.Button("Manual", sz) - if ImGui.IsItemHovered(HF.ForTooltip) then ImGui.SetTooltip("I am a manually emitted tooltip.") end - ImGui.Button("DelayNone", sz) - if ImGui.IsItemHovered(HF.DelayNone) then ImGui.SetTooltip("I am a tooltip with no delay.") end - ImGui.Button("DelayShort", sz) - if ImGui.IsItemHovered(bit32.bor(HF.DelayShort, HF.NoSharedDelay)) then ImGui.SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui.GetStyle().HoverDelayShort) end - ImGui.Button("DelayLong", sz) - if ImGui.IsItemHovered(bit32.bor(HF.DelayNormal, HF.NoSharedDelay)) then ImGui.SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui.GetStyle().HoverDelayNormal) end - ImGui.Button("Stationary", sz) - if ImGui.IsItemHovered(HF.Stationary) then ImGui.SetTooltip("I am a tooltip requiring mouse to be stationary before activating.") end - - -- Using ImGuiHoveredFlags.ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav', - -- which default value include the ImGuiHoveredFlags.AllowWhenDisabled flag. - ImGui.BeginDisabled() - ImGui.Button("Disabled item", sz) - if ImGui.IsItemHovered(HF.ForTooltip) then ImGui.SetTooltip("I am a tooltip for a disabled item.") end - ImGui.EndDisabled() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTreeNodes() -------------------------------------------------------------------------------- - -S.tn = { lines_flags = bit32.bor(ImGuiTreeNodeFlags.DrawLinesFull, ImGuiTreeNodeFlags.DefaultOpen), selection_mask = 0, - adv_flags = bit32.bor(ImGuiTreeNodeFlags.OpenOnArrow, ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.SpanAvailWidth), - align_label = false, use_dnd = false } -function DemoWindowWidgetsTreeNodes() - if not ImGui.TreeNode("Tree Nodes") then return end - local s = S.tn - local TN = ImGuiTreeNodeFlags - -- See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree. - if ImGui.TreeNode("Basic Trees") then - for i = 0, 4 do - -- Use SetNextItemOpen() so set the default state of a node to be open. We could - -- also use TreeNodeEx() with the ImGuiTreeNodeFlags.DefaultOpen flag to achieve the same thing! - if i == 0 then ImGui.SetNextItemOpen(true, 2 --[[ImGuiCond.Once]]) end - - -- Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict. - -- An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode(i, ...)', - -- aka pass a number value to be hashed. The demo below uses that technique. Both are fine. - ImGui.PushID(i) - if ImGui.TreeNode("", "Child %d", i) then - ImGui.Text("blah blah") - ImGui.SameLine() - if ImGui.SmallButton("button") then end - ImGui.TreePop() - end - ImGui.PopID() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Hierarchy Lines") then - HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") - _, s.lines_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", s.lines_flags, TN.DrawLinesNone) - _, s.lines_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", s.lines_flags, TN.DrawLinesFull) - _, s.lines_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", s.lines_flags, TN.DrawLinesToNodes) - local f = s.lines_flags - if ImGui.TreeNodeEx("Parent", f) then - if ImGui.TreeNodeEx("Child 1", f) then ImGui.Button("Button for Child 1"); ImGui.TreePop() end - if ImGui.TreeNodeEx("Child 2", f) then ImGui.Button("Button for Child 2"); ImGui.TreePop() end - ImGui.Text("Remaining contents") - ImGui.Text("Remaining contents") - ImGui.TreePop() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Clipping Large Trees") then - ImGui.TextWrapped("- Using ImGuiListClipper with trees is a less easy than on arrays or grids.\n- Refer to 'Demo->Examples->Property Editor' for an example of how to do that.\n- Discuss in #3823") - ImGui.TreePop() - end - - if ImGui.TreeNode("Selectable Nodes") then - HelpMarker("Manually implemented selectable nodes.\nClick to select, Ctrl+Click to toggle, click on arrows or double-click to open.") - - -- Hold in 'selection_mask' a simple representation of what may be user-side selection state. - -- - You may retain selection state inside or outside your objects in whatever format you see fit. - -- You may use ImGuiSelectionBasicStorage which is conceptually close to a set<> of identifiers. - -- - We record which node was clicked and then apply selection at the end of the loop. - -- - This is a manual and simplified reimplementation of multi-selection, which the full - -- BeginMultiSelect() API implements better, but which is not trivial to wire for trees. - local node_clicked_idx = -1 - for node_n = 0, 5 do - -- Disable the default "open on single-click behavior" + set Selected flag according to our selection. - -- To alter selection we use if 'IsItemClicked() and not IsItemToggledOpen()', so clicking on an arrow doesn't alter selection. - -- In a BeginMultiSelect()/EndMultiSelect() we could use IsItemToggledSelection() but here we reimplement and use our own logic. - local flags = bit32.bor(TN.OpenOnArrow, TN.OpenOnDoubleClick, TN.SpanAvailWidth) - if bit32.band(s.selection_mask, bit32.lshift(1, node_n)) ~= 0 then flags = bit32.bor(flags, TN.Selected) end - local is_open = ImGui.TreeNodeEx(node_n, flags, "Selectable Node %d", node_n) - if ImGui.IsItemClicked() and not ImGui.IsItemToggledOpen() then node_clicked_idx = node_n end - if is_open then - ImGui.BulletText("") - ImGui.TreePop() - end - end - if node_clicked_idx ~= -1 then - -- Update selection state (process outside of tree loop to avoid visual inconsistencies during the clicking frame) - if ImGui.GetIO().KeyCtrl then - s.selection_mask = bit32.bxor(s.selection_mask, bit32.lshift(1, node_clicked_idx)) -- Ctrl+Click to toggle - else -- if not (selection_mask & (1 << node_clicked_idx)) -- Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection - s.selection_mask = bit32.lshift(1, node_clicked_idx) -- Click to single-select - end - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Advanced") then - local function FB(name, help) - _, s.adv_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_" .. name, s.adv_flags, TN[name]) - if help then ImGui.SameLine(); HelpMarker(help) end - end - FB("OpenOnArrow"); FB("OpenOnDoubleClick") - FB("SpanAvailWidth", "Extend hit area to all available width instead of allowing more items to be laid out after the node.") - FB("SpanFullWidth") - FB("SpanLabelWidth", "Reduce hit area to the text label and a bit of margin.") - FB("SpanAllColumns", "For use in Tables only.") - FB("AllowOverlap") - FB("Framed", "Draw frame with background (e.g. for CollapsingHeader)") - FB("FramePadding"); FB("NavLeftJumpsToParent") - HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") - FB("DrawLinesNone"); FB("DrawLinesFull"); FB("DrawLinesToNodes") - _, s.align_label = ImGui.Checkbox("Align label with current X position", s.align_label) - _, s.use_dnd = ImGui.Checkbox("Make Tree Nodes as drag & drop sources", s.use_dnd) - if s.align_label then ImGui.Unindent(ImGui.GetTreeNodeToLabelSpacing()) end - for node_n = 0, 5 do - local node_flags = s.adv_flags - if node_n < 3 then - -- Items 0..2 are Tree Node - local is_open = ImGui.TreeNodeEx(node_n, node_flags, "Selectable Node %d", node_n) - if s.use_dnd and ImGui.BeginDragDropSource() then - ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) - ImGui.Text("This is a drag and drop source") - ImGui.EndDragDropSource() - end - if node_n == 2 and bit32.band(s.adv_flags, TN.SpanLabelWidth) ~= 0 then - -- Item 2 has an additional inline button to help demonstrate SpanLabelWidth. - ImGui.SameLine() - if ImGui.SmallButton("button") then end - end - if is_open then - ImGui.BulletText("Blah blah\nBlah Blah") - ImGui.SameLine() - ImGui.SmallButton("Button") - ImGui.TreePop() - end - else - -- Items 3..5 are Tree Leaves - -- The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can - -- use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). - node_flags = bit32.bor(node_flags, TN.Leaf, TN.NoTreePushOnOpen) -- ImGuiTreeNodeFlags.Bullet - ImGui.TreeNodeEx(node_n, node_flags, "Selectable Leaf %d", node_n) - if s.use_dnd and ImGui.BeginDragDropSource() then - ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) - ImGui.Text("This is a drag and drop source") - ImGui.EndDragDropSource() - end - end - end - if s.align_label then ImGui.Indent(ImGui.GetTreeNodeToLabelSpacing()) end - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsVerticalSliders() -------------------------------------------------------------------------------- - -S.vs = { int_value = 0, values = { 0.0, 0.60, 0.35, 0.9, 0.70, 0.20, 0.0 }, values2 = { 0.20, 0.80, 0.40, 0.25 } } -function DemoWindowWidgetsVerticalSliders() - if not ImGui.TreeNode("Vertical Sliders") then return end - local s = S.vs - local spacing = 4 - ImGui.PushStyleVar(14 --[[ImGuiStyleVar.ItemSpacing]], ImVec2(spacing, spacing)) - s.int_value = ImGui.VSliderInt("##int", ImVec2(18, 160), s.int_value, 0, 5) - ImGui.SameLine() - local values = s.values - ImGui.PushID("set1") - for i = 0, 6 do - if i > 0 then ImGui.SameLine() end - ImGui.PushID(i) - ImGui.PushStyleColor(7 --[[ImGuiCol.FrameBg]], HSV(i / 7.0, 0.5, 0.5)) - ImGui.PushStyleColor(8 --[[ImGuiCol.FrameBgHovered]], HSV(i / 7.0, 0.6, 0.5)) - ImGui.PushStyleColor(9 --[[ImGuiCol.FrameBgActive]], HSV(i / 7.0, 0.7, 0.5)) - ImGui.PushStyleColor(20 --[[ImGuiCol.SliderGrab]], HSV(i / 7.0, 0.9, 0.9)) - values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(18, 160), values[i + 1], 0.0, 1.0, "") - if ImGui.IsItemActive() or ImGui.IsItemHovered() then ImGui.SetTooltip("%.3f", values[i + 1]) end - ImGui.PopStyleColor(4) - ImGui.PopID() - end - ImGui.PopID() - - ImGui.SameLine() - ImGui.PushID("set2") - local rows = 3 - local small_slider_size = ImVec2(18, math.floor((160.0 - (rows - 1) * spacing) / rows)) - for nx = 0, 3 do - if nx > 0 then ImGui.SameLine() end - ImGui.BeginGroup() - for ny = 0, rows - 1 do - ImGui.PushID(nx * rows + ny) - s.values2[nx + 1] = ImGui.VSliderFloat("##v", small_slider_size, s.values2[nx + 1], 0.0, 1.0, "") - if ImGui.IsItemActive() or ImGui.IsItemHovered() then ImGui.SetTooltip("%.3f", s.values2[nx + 1]) end - ImGui.PopID() - end - ImGui.EndGroup() - end - ImGui.PopID() - - ImGui.SameLine() - ImGui.PushID("set3") - for i = 0, 3 do - if i > 0 then ImGui.SameLine() end - ImGui.PushID(i) - ImGui.PushStyleVar(21 --[[ImGuiStyleVar.GrabMinSize]], 40) - values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(40, 160), values[i + 1], 0.0, 1.0, "%.2f\nsec") - ImGui.PopStyleVar() - ImGui.PopID() - end - ImGui.PopID() - ImGui.PopStyleVar() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() -------------------------------------------------------------------------------- --- - ShowExampleAppMainMenuBar() --- - ShowExampleMenuFile() -------------------------------------------------------------------------------- - -S.menu = { enabled = true, f = 0.5, n = 0, b = true } --- Note that shortcuts are currently provided for display only --- (future version will add explicit flags to BeginMenu() to request processing shortcuts) -function ShowExampleMenuFile() - local s = S.menu - ImGui.MenuItem("(demo menu)", nil, false, false) - if ImGui.MenuItem("New") then end - if ImGui.MenuItem("Open", "Ctrl+O") then end - if ImGui.BeginMenu("Open Recent") then - ImGui.MenuItem("fish_hat.c") - ImGui.MenuItem("fish_hat.inl") - ImGui.MenuItem("fish_hat.h") - if ImGui.BeginMenu("More..") then - ImGui.MenuItem("Hello") - ImGui.MenuItem("Sailor") - if ImGui.BeginMenu("Recurse..") then - ShowExampleMenuFile() - ImGui.EndMenu() - end - ImGui.EndMenu() - end - ImGui.EndMenu() - end - if ImGui.MenuItem("Save", "Ctrl+S") then end - if ImGui.MenuItem("Save As..") then end - - ImGui.Separator() - if ImGui.BeginMenu("Options") then - _, s.enabled = ImGui.MenuItem("Enabled", "", s.enabled) - ImGui.BeginChild("child", ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 5.0), 1 --[[ImGuiChildFlags.Borders]]) - for i = 0, 9 do ImGui.Text("Scrolling Text %d", i) end - ImGui.EndChild() - s.f = ImGui.SliderFloat("Value", s.f, 0.0, 1.0) - s.f = ImGui.InputFloat("Input", s.f, 0.1) - s.n = ImGui.Combo("Combo", s.n, "Yes\0No\0Maybe\0\0") - ImGui.EndMenu() - end - - if ImGui.BeginMenu("Colors") then - local sz = ImGui.GetTextLineHeight() - for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do - local name = ImGui.GetStyleColorName(i) - local p = ImGui.GetCursorScreenPos() - ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui.GetColorU32(i)) - ImGui.Dummy(ImVec2(sz, sz)) - ImGui.SameLine() - ImGui.MenuItem(name) - end - ImGui.EndMenu() - end - - -- Here we demonstrate appending again to the "Options" menu (which we already created above) - -- Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. - -- In a real code-base using it would make senses to use this feature from very different code locations. - if ImGui.BeginMenu("Options") then -- <-- Append! - _, s.b = ImGui.Checkbox("SomeOption", s.b) - ImGui.EndMenu() - end - - if ImGui.BeginMenu("Disabled", false) then -- Disabled - assert(false) - end - if ImGui.MenuItem("Checked", nil, true) then end - ImGui.Separator() - if ImGui.MenuItem("Quit", "Alt+F4") then end -end - --- Demonstrate creating a "main" fullscreen menu bar and populating it. --- Note the difference between BeginMainMenuBar() and BeginMenuBar(): --- - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags.MenuBar flag!) --- - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. -function ShowExampleAppMainMenuBar() - if ImGui.BeginMainMenuBar() then - if ImGui.BeginMenu("File") then - ShowExampleMenuFile() - ImGui.EndMenu() - end - if ImGui.BeginMenu("Edit") then - if ImGui.MenuItem("Undo", "Ctrl+Z") then end - if ImGui.MenuItem("Redo", "Ctrl+Y", false, false) then end -- Disabled item - ImGui.Separator() - if ImGui.MenuItem("Cut", "Ctrl+X") then end - if ImGui.MenuItem("Copy", "Ctrl+C") then end - if ImGui.MenuItem("Paste", "Ctrl+V") then end - ImGui.EndMenu() - end - ImGui.EndMainMenuBar() - end -end - -------------------------------------------------------------------------------- --- [SECTION] Style Editor / ShowStyleEditor() -------------------------------------------------------------------------------- --- - ShowStyleSelector() --- - ShowStyleEditor() -------------------------------------------------------------------------------- - --- Deep copy of an ImGuiStyle (ImVec2/ImVec4 fields and Colors[] are copied by value) -local function StyleCopy(dst, src) - for k, v in pairs(src) do - if k == "Colors" then - dst.Colors = dst.Colors or {} - for i, c in pairs(v) do - if type(c) == "table" then dst.Colors[i] = dst.Colors[i] or ImVec4(); ImVec4_Copy(dst.Colors[i], c) else dst.Colors[i] = c end - end - elseif type(v) == "table" and getmetatable(v) ~= nil and type(v[1]) == "number" then - local c = dst[k] - if type(c) ~= "table" then c = setmetatable({}, getmetatable(v)); dst[k] = c end - for _, key in ipairs({ "x", "y", "z", "w" }) do if rawget(v, key) ~= nil then rawset(c, key, rawget(v, key)) end end - else - dst[k] = v - end - end - if getmetatable(dst) == nil then setmetatable(dst, getmetatable(src)) end - return dst -end - -local function ColorsEqual(a, b) return a[1] == b[1] and a[2] == b[2] and a[3] == b[3] and a[4] == b[4] end - -S.ss = { style_idx = -1 } --- Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. -function ImGui.ShowStyleSelector(label) - -- FIXME: This is a bit tricky to get right as style are functions, they don't register a name nor the fact that one is active. - -- So we keep track of last active one among our limited selection. - local s = S.ss - local style_names = { "Dark", "Light", "Classic" } - local ret = false - if ImGui.BeginCombo(label, style_names[s.style_idx + 1] or "") then - for n = 0, 2 do - if ImGui.Selectable(style_names[n + 1], s.style_idx == n, 64 --[[ImGuiSelectableFlags.SelectOnNav]]) then - s.style_idx = n - ret = true - if n == 0 then ImGui.StyleColorsDark() elseif n == 1 then ImGui.StyleColorsLight() else ImGui.StyleColorsClassic() end - elseif s.style_idx == n then - ImGui.SetItemDefaultFocus() - end - end - ImGui.EndCombo() - end - return ret -end - -local function GetTreeLinesFlagsName(flags) - local TN = ImGuiTreeNodeFlags - if flags == TN.DrawLinesNone then return "DrawLinesNone" end - if flags == TN.DrawLinesFull then return "DrawLinesFull" end - if flags == TN.DrawLinesToNodes then return "DrawLinesToNodes" end - return "" -end - -S.se = { ref_saved_style = nil, init = true, output_dest = 0, output_only_modified = true, alpha_flags = 0, filter = nil } -function ImGui.ShowStyleEditor(ref) - -- You can pass in a reference ImGuiStyle structure to compare to, revert to and save to - -- (without a reference style, we will use one compared locally as a reference) - local se = S.se - local style = ImGui.GetStyle() - if se.ref_saved_style == nil then se.ref_saved_style = {} end - - -- Default to using internal storage as reference - if se.init and ref == nil then StyleCopy(se.ref_saved_style, style) end - se.init = false - if ref == nil then ref = se.ref_saved_style end - - -- The logic behind dynamically changing 'max_border_size' is to not encourage people to increase border size too much: it'll likely reveal lots of subtle rendering artifacts and this isn't a priority right now. - -- Note that _MainScale is currently internal PLEASE DO NOT USE IN YOUR CODE. - local default_border_size = math.floor(style._MainScale or 1.0) - local max_border_size = math.max(default_border_size, 2.0) - local function SF(name, mn, mx, fmt) if style[name] ~= nil then style[name] = ImGui.SliderFloat(name, style[name], mn, mx, fmt or "%.0f") end end - local function SF2(name, mn, mx, fmt) if style[name] ~= nil then ImGui.SliderFloat2(name, style[name], mn, mx, fmt or "%.0f") end end - local function DF(name, speed, mn, mx, fmt, flags) if style[name] ~= nil then style[name] = ImGui.DragFloat(name, style[name], speed, mn, mx, fmt or "%.0f", flags) end end - - ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50) - - -- General - ImGui.SeparatorText("General") - if bit32.band(ImGui.GetIO().BackendFlags, 16 --[[ImGuiBackendFlags.RendererHasTextures]]) == 0 then - ImGui.BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!") - ImGui.BulletText("For instructions, see:") - ImGui.SameLine() - ImGui.TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md") - end - if ImGui.ShowStyleSelector("Colors##Selector") then StyleCopy(se.ref_saved_style, style) end - if ImGui.ShowFontSelector then ImGui.ShowFontSelector("Fonts##Selector") end - local changed - style.FontSizeBase, changed = ImGui.DragFloat("FontSizeBase", style.FontSizeBase, 0.20, 5.0, 100.0, "%.0f") - if changed then style._NextFrameFontSizeBase = style.FontSizeBase end -- FIXME: Temporary hack until we finish remaining work. - ImGui.SameLine(0.0, 0.0); ImGui.Text(" (out %.2f)", ImGui.GetFontSize()) - style.FontScaleMain = ImGui.DragFloat("FontScaleMain", style.FontScaleMain, 0.02, 0.5, 4.0) - ImGui.BeginDisabled(ImGui.GetIO().ConfigDpiScaleFonts == true) - style.FontScaleDpi = ImGui.DragFloat("FontScaleDpi", style.FontScaleDpi, 0.02, 0.5, 4.0) - ImGui.SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.") - ImGui.EndDisabled() - - -- Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0 or 1.0) - style.FrameRounding, changed = ImGui.SliderFloat("FrameRounding", style.FrameRounding, 0.0, 12.0, "%.0f") - if changed then style.GrabRounding = style.FrameRounding end -- Make GrabRounding always the same value as FrameRounding - local p, border - p, border = ImGui.Checkbox("WindowBorder", style.WindowBorderSize > 0.0); if p then style.WindowBorderSize = border and default_border_size or 0.0 end - ImGui.SameLine() - p, border = ImGui.Checkbox("FrameBorder", style.FrameBorderSize > 0.0); if p then style.FrameBorderSize = border and default_border_size or 0.0 end - ImGui.SameLine() - p, border = ImGui.Checkbox("PopupBorder", style.PopupBorderSize > 0.0); if p then style.PopupBorderSize = border and default_border_size or 0.0 end - - -- Save/Revert button - if ImGui.Button("Save Ref") then StyleCopy(se.ref_saved_style, style); if ref ~= se.ref_saved_style then StyleCopy(ref, style) end end - ImGui.SameLine() - if ImGui.Button("Revert Ref") then StyleCopy(style, ref) end - ImGui.SameLine() - HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export\" below to save them somewhere.") - - ImGui.SeparatorText("Details") - if ImGui.BeginTabBar("##tabs", 0 --[[ImGuiTabBarFlags.None]]) then - if ImGui.BeginTabItem("Sizes") then - ImGui.SeparatorText("Main") - SF2("WindowPadding", 0.0, 20.0); SF2("FramePadding", 0.0, 20.0); SF2("ItemSpacing", 0.0, 20.0) - SF2("ItemInnerSpacing", 0.0, 20.0); SF2("TouchExtraPadding", 0.0, 10.0) - SF("IndentSpacing", 0.0, 30.0); SF("GrabMinSize", 1.0, 20.0) - - ImGui.SeparatorText("Borders") - SF("WindowBorderSize", 0.0, max_border_size); SF("ChildBorderSize", 0.0, max_border_size) - SF("PopupBorderSize", 0.0, max_border_size); SF("FrameBorderSize", 0.0, max_border_size) - - ImGui.SeparatorText("Rounding") - SF("WindowRounding", 0.0, 12.0); SF("ChildRounding", 0.0, 12.0); SF("FrameRounding", 0.0, 12.0) - SF("PopupRounding", 0.0, 12.0); SF("GrabRounding", 0.0, 12.0); SF("MenuItemRounding", 0.0, 12.0) - -- NB: SelectableRounding is intentionally NOT made visible here. We don't want to encourage people using that. - - ImGui.SeparatorText("Scrollbar") - SF("ScrollbarSize", 1.0, 20.0); SF("ScrollbarRounding", 0.0, 12.0); SF("ScrollbarPadding", 0.0, 10.0) - - ImGui.SeparatorText("Tabs") - SF("TabBorderSize", 0.0, max_border_size); SF("TabBarBorderSize", 0.0, max_border_size) - SF("TabBarOverlineSize", 0.0, math.max(3.0, max_border_size)) - ImGui.SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.") - DF("TabMinWidthBase", 0.5, 1.0, 500.0); DF("TabMinWidthShrink", 0.5, 1.0, 500.0, "%0.f") - if style.TabCloseButtonMinWidthSelected ~= nil then - DF("TabCloseButtonMinWidthSelected", 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthSelected < 0.0) and "%.0f (Always)" or "%.0f") - DF("TabCloseButtonMinWidthUnselected", 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthUnselected < 0.0) and "%.0f (Always)" or "%.0f") - end - SF("TabRounding", 0.0, 12.0) - - ImGui.SeparatorText("Tables") - SF2("CellPadding", 0.0, 20.0) - style.TableAngledHeadersAngle = ImGui.SliderAngle("TableAngledHeadersAngle", style.TableAngledHeadersAngle, -50.0, 50.0) - SF2("TableAngledHeadersTextAlign", 0.0, 1.0, "%.2f") - - ImGui.SeparatorText("Trees") - local combo_open = ImGui.BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)) - ImGui.SameLine() - HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode.") - if combo_open then - local TN = ImGuiTreeNodeFlags - for _, option in ipairs({ TN.DrawLinesNone, TN.DrawLinesFull, TN.DrawLinesToNodes }) do - if ImGui.Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option) then style.TreeLinesFlags = option end - end - ImGui.EndCombo() - end - SF("TreeLinesSize", 0.0, max_border_size); SF("TreeLinesRounding", 0.0, 12.0) - - ImGui.SeparatorText("Windows") - SF2("WindowTitleAlign", 0.0, 1.0, "%.2f"); SF("WindowBorderHoverPadding", 1.0, 20.0) - local window_menu_button_position = style.WindowMenuButtonPosition + 1 - window_menu_button_position, changed = ImGui.Combo("WindowMenuButtonPosition", window_menu_button_position, "None\0Left\0Right\0") - if changed then style.WindowMenuButtonPosition = window_menu_button_position - 1 end - - ImGui.SeparatorText("Widgets") - SF("ColorMarkerSize", 0.0, 8.0) - style.ColorButtonPosition = ImGui.Combo("ColorButtonPosition", style.ColorButtonPosition, "Left\0Right\0") - SF2("ButtonTextAlign", 0.0, 1.0, "%.2f") - ImGui.SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.") - SF2("SelectableTextAlign", 0.0, 1.0, "%.2f") - ImGui.SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.") - SF("SeparatorSize", 0.0, 10.0); SF("SeparatorTextBorderSize", 0.0, 10.0) - SF2("SeparatorTextAlign", 0.0, 1.0, "%.2f"); SF2("SeparatorTextPadding", 0.0, 40.0) - SF("LogSliderDeadzone", 0.0, 12.0); SF("ImageRounding", 0.0, 12.0); SF("ImageBorderSize", 0.0, max_border_size) - - ImGui.SeparatorText("Docking") - -- SetCursorPosX(GetCursorPosX() + CalcItemWidth() - GetFrameHeight()) - _, style.DockingNodeHasCloseButton = ImGui.Checkbox("DockingNodeHasCloseButton", style.DockingNodeHasCloseButton) - SF("DockingSeparatorSize", 0.0, 12.0) - - ImGui.SeparatorText("Tooltips") - for n = 0, 1 do - local key = (n == 0) and "HoverFlagsForTooltipMouse" or "HoverFlagsForTooltipNav" - if ImGui.TreeNodeEx(key) then - for _, f in ipairs({ "DelayNone", "DelayShort", "DelayNormal", "Stationary", "NoSharedDelay" }) do - _, style[key] = ImGui.CheckboxFlags("ImGuiHoveredFlags_" .. f, style[key], ImGuiHoveredFlags[f]) - end - ImGui.TreePop() - end - end - - ImGui.SeparatorText("Misc") - SF2("DisplayWindowPadding", 0.0, 30.0); ImGui.SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.") - SF2("DisplaySafeAreaPadding", 0.0, 30.0); ImGui.SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).") - ImGui.EndTabItem() - end - - if ImGui.BeginTabItem("Colors") then - if ImGui.Button("Export") then - if se.output_dest == 0 then ImGui.LogToClipboard() else ImGui.LogToTTY() end - ImGui.LogText("ImVec4* colors = GetStyle().Colors;\n") - for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do - local col = style.Colors[i] - local name = ImGui.GetStyleColorName(i) - if not se.output_only_modified or not ColorsEqual(col, ref.Colors[i]) then - ImGui.LogText("colors[ImGuiCol_%s]%s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);\n", name, string.rep(" ", math.max(0, 23 - #name)), col.x, col.y, col.z, col.w) - end - end - ImGui.LogFinish() - end - ImGui.SameLine(); ImGui.SetNextItemWidth(ImGui.GetFontSize() * 10) - se.output_dest = ImGui.Combo("##output_type", se.output_dest, "To Clipboard\0To TTY\0") - ImGui.SameLine(); _, se.output_only_modified = ImGui.Checkbox("Only Modified Colors", se.output_only_modified) - - local CE = ImGuiColorEditFlags - if ImGui.RadioButtonEx("Opaque", se.alpha_flags == CE.AlphaOpaque) then se.alpha_flags = CE.AlphaOpaque end ImGui.SameLine() - if ImGui.RadioButtonEx("Alpha", se.alpha_flags == CE.None) then se.alpha_flags = CE.None end ImGui.SameLine() - if ImGui.RadioButtonEx("Both", se.alpha_flags == CE.AlphaPreviewHalf) then se.alpha_flags = CE.AlphaPreviewHalf end ImGui.SameLine() - HelpMarker("In the color list:\nLeft-click on color square to open color picker,\nRight-click to open edit options menu.") - - se.filter = se.filter or ImGuiTextFilter() - ImGui.SetNextItemWidth(-1.1754943508223e-38 --[[FLT_MIN]]) - se.filter:DrawWithHint("##FilterColors", "Filter Colors (incl -excl)") - - ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 10), ImVec2(3.4028234663853e+38 --[[FLT_MAX]], 3.4028234663853e+38 --[[FLT_MAX]])) - ImGui.BeginChild("##colors", ImVec2(0, 0), bit32.bor(1 --[[ImGuiChildFlags.Borders]], 256 --[[ImGuiChildFlags.NavFlattened]]), bit32.bor(16384 --[[ImGuiWindowFlags.AlwaysVerticalScrollbar]], 32768 --[[ImGuiWindowFlags.AlwaysHorizontalScrollbar]])) - ImGui.PushItemWidth(ImGui.GetFontSize() * -12) - -- [Luau] clipped: only visible rows are submitted (upstream submits every color) - local visible_cols = {} - for i = 0, 63 --[[ImGuiCol.COUNT]] - 1 do - if se.filter:PassFilter(ImGui.GetStyleColorName(i)) then visible_cols[#visible_cols + 1] = i end - end - local clipper = ImGuiListClipper() - clipper:Begin(#visible_cols) - while clipper:Step() do for row = clipper.DisplayStart, clipper.DisplayEnd - 1 do - local i = visible_cols[row + 1] - local name = ImGui.GetStyleColorName(i) - do - ImGui.PushID(i) - if ImGui.DebugFlashStyleColor then - if ImGui.Button("?") then ImGui.DebugFlashStyleColor(i) end - ImGui.SetItemTooltip("Flash given color to identify places where it is used.") - ImGui.SameLine() - end - ImGui.ColorEdit4("##color", style.Colors[i], bit32.bor(CE.AlphaBar, se.alpha_flags)) - if not ColorsEqual(style.Colors[i], ref.Colors[i]) then - -- Tips: in a real user application, you may want to merge and use an icon font into the main font, - -- so instead of "Save"/"Revert" you'd use icons! - -- Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! - ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Save") then ImVec4_Copy(ref.Colors[i], style.Colors[i]) end - ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Revert") then ImVec4_Copy(style.Colors[i], ref.Colors[i]) end - end - ImGui.SameLine(0.0, style.ItemInnerSpacing.x) - ImGui.TextUnformatted(name) - ImGui.PopID() - end - end end - clipper:End() - ImGui.PopItemWidth() - ImGui.EndChild() - ImGui.EndTabItem() - end - - if ImGui.BeginTabItem("Fonts") then - if ImGui.ShowFontAtlas then ImGui.ShowFontAtlas(ImGui.GetIO().Fonts) else DemoNotPorted("ShowFontAtlas") end - ImGui.EndTabItem() - end - - if ImGui.BeginTabItem("Rendering") then - _, style.AntiAliasedLines = ImGui.Checkbox("Anti-aliased lines", style.AntiAliasedLines) - ImGui.SameLine() - HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.") - ImGui.BeginDisabled(style.AntiAliasedLines == false) - _, style.AntiAliasedLineEnds = ImGui.Checkbox("Anti-aliased line ends", style.AntiAliasedLineEnds) - ImGui.EndDisabled() - _, style.AntiAliasedFill = ImGui.Checkbox("Anti-aliased fill", style.AntiAliasedFill) - local io = ImGui.GetIO() - _, io.ConfigDebugDrawListDefaultsToStrokeLegacy = ImGui.Checkbox("Debug: DrawList Defaults to _StrokeLegacy", io.ConfigDebugDrawListDefaultsToStrokeLegacy == true) - - ImGui.PushItemWidth(ImGui.GetFontSize() * 8) - -- [port] library still stores the pre-1.93 CurveTessellationTol (== MaxError * MaxError) - local curve_err = ImGui.DragFloat("Curve Tessellation Max Error", math.sqrt(style.CurveTessellationTol), 0.02, 0.10, 10.0, "%.2f") - if curve_err < 0.10 then curve_err = 0.10 end - style.CurveTessellationTol = curve_err * curve_err - - -- When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. - style.CircleTessellationMaxError = ImGui.DragFloat("Circle Tessellation Max Error", style.CircleTessellationMaxError, 0.005, 0.10, 5.0, "%.2f", 1536 --[[ImGuiSliderFlags.AlwaysClamp]]) - local show_samples = ImGui.IsItemActive() - if show_samples then ImGui.SetNextWindowPos(ImGui.GetCursorScreenPos()) end - if show_samples and ImGui.BeginTooltip() then - ImGui.TextUnformatted("(R = radius, N = approx number of segments)") - ImGui.Spacing() - local draw_list = ImGui.GetWindowDrawList() - local min_widget_width = ImGui.CalcTextSize("R: MMM\nN: MMM").x - for n = 0, 7 do - local RAD_MIN, RAD_MAX = 5.0, 70.0 - local rad = RAD_MIN + (RAD_MAX - RAD_MIN) * n / (8.0 - 1.0) - ImGui.BeginGroup() - - -- N is not always exact here due to how PathArcTo() function work internally - ImGui.Text("R: %.f\nN: %d", rad, draw_list:_CalcCircleAutoSegmentCount(rad)) - local canvas_width = math.max(min_widget_width, rad * 2.0) - local offset_x = math.floor(canvas_width * 0.5) - local offset_y = math.floor(RAD_MAX) - local p1 = ImGui.GetCursorScreenPos() - draw_list:AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui.GetColorU32(0 --[[ImGuiCol.Text]])) - ImGui.Dummy(ImVec2(canvas_width, RAD_MAX * 2)) - - -- local p2 = ImGui.GetCursorScreenPos() - -- draw_list:AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui.GetColorU32(ImGuiCol.Text)) - -- ImGui.Dummy(ImVec2(canvas_width, RAD_MAX * 2)) - - ImGui.EndGroup() - ImGui.SameLine() - end - ImGui.EndTooltip() - end - ImGui.SameLine() - HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically.") - style.Alpha = ImGui.DragFloat("Global Alpha", style.Alpha, 0.005, 0.20, 1.0, "%.2f") -- Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. - style.DisabledAlpha = ImGui.DragFloat("Disabled Alpha", style.DisabledAlpha, 0.005, 0.0, 1.0, "%.2f") - ImGui.SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).") - ImGui.PopItemWidth() - ImGui.EndTabItem() - end - ImGui.EndTabBar() - end - ImGui.PopItemWidth() -end -end --[[ imgui_demo_widgets.lua ]] - -do --[[ About window ]] --- Demo tools: ShowAboutWindow(), ShowFontAtlas(), ShowFontSelector(), ShowDebugLogWindow(), ShowIDStackToolWindow() -local _ - -------------------------------------------------------------------------------- --- [SECTION] About Window / ShowAboutWindow() --- Access from Dear ImGui Demo -> Tools -> About -------------------------------------------------------------------------------- - -local show_config_info = false -function ImGui.ShowAboutWindow(p_open) - local visible - p_open, visible = ImGui.Begin("About Dear ImGui", p_open, 64 --[[ImGuiWindowFlags.AlwaysAutoResize]]) - if not visible then ImGui.End(); return p_open end - ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, 19298 --[[IMGUI_VERSION_NUM]]) - ImGui.TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui"); ImGui.SameLine() - ImGui.TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Extensions", "https://github.com/ocornut/imgui/wiki/Useful-Extensions"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding") - ImGui.Separator() - ImGui.Text("(c) 2014-2026 Omar Cornut") - ImGui.Text("Developed by Omar Cornut and all Dear ImGui contributors.") - ImGui.Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.") - ImGui.Text("If your company uses this, please consider funding the project.") - ImGui.Text("Luau/Roblox port: imgui_impl_roblox (software rasterizer into EditableImage tiles).") - - _, show_config_info = ImGui.Checkbox("Config/Build Information", show_config_info) - if show_config_info then - local io = ImGui.GetIO() - local style = ImGui.GetStyle() - local copy_to_clipboard = ImGui.Button("Copy to clipboard") - local child_size = ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 18) - ImGui.BeginChild(ImGui.GetID("cfg_infos"), child_size, 128 --[[ImGuiChildFlags.FrameStyle]]) - if copy_to_clipboard then - ImGui.LogToClipboard() - ImGui.LogText("// (Copy from the next line. Keep the ``` markers for formatting.)\n") - ImGui.LogText("```cpp\n") -- Back quotes will make text appears without formatting when pasting on GitHub - end - ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, 19298 --[[IMGUI_VERSION_NUM]]) - ImGui.Separator() - ImGui.Text("define: IMGUI_HAS_VIEWPORT") - ImGui.Text("define: IMGUI_HAS_DOCK") - ImGui.Text("runtime: Luau (%s)", _VERSION or "?") - ImGui.Separator() - ImGui.Text("io.BackendPlatformName: %s", io.BackendPlatformName or "NULL") - ImGui.Text("io.BackendRendererName: %s", io.BackendRendererName or "NULL") - ImGui.Text("io.ConfigFlags: 0x%08X", io.ConfigFlags) - local CF = ImGuiConfigFlags - for _, n in ipairs({ "NavEnableKeyboard", "NavEnableGamepad", "NoMouse", "NoMouseCursorChange", "NoKeyboard", "DockingEnable", "ViewportsEnable" }) do - if CF[n] and bit32.band(io.ConfigFlags, CF[n]) ~= 0 then ImGui.Text(" %s", n) end - end - for _, n in ipairs({ "MouseDrawCursor", "ConfigDpiScaleFonts", "ConfigDpiScaleViewports", "ConfigViewportsNoAutoMerge", "ConfigViewportsNoTaskBarIcon", - "ConfigViewportsNoDecoration", "ConfigViewportsNoDefaultParent", "ConfigDockingNoSplit", "ConfigDockingNoDockingOver", "ConfigDockingWithShift", - "ConfigDockingAlwaysTabBar", "ConfigDockingTransparentPayload", "ConfigMacOSXBehaviors", "ConfigNavMoveSetMousePos", "ConfigNavCaptureKeyboard", - "ConfigInputTextCursorBlink", "ConfigWindowsResizeFromEdges", "ConfigWindowsMoveFromTitleBarOnly" }) do - if io[n] == true then ImGui.Text("io.%s", n) end - end - if (io.ConfigMemoryCompactTimer or -1) >= 0.0 then ImGui.Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer) end - ImGui.Text("io.BackendFlags: 0x%08X", io.BackendFlags) - local BF = ImGuiBackendFlags - for _, n in ipairs({ "HasGamepad", "HasMouseCursors", "HasSetMousePos", "PlatformHasViewports", "HasMouseHoveredViewport", "HasParentViewport", - "RendererHasVtxOffset", "RendererHasTextures", "RendererHasViewports" }) do - if BF[n] and bit32.band(io.BackendFlags, BF[n]) ~= 0 then ImGui.Text(" %s", n) end - end - ImGui.Separator() - local atlas = io.Fonts - ImGui.Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", atlas.Fonts.Size, atlas.Flags or 0, atlas.TexData and atlas.TexData.Width or 0, atlas.TexData and atlas.TexData.Height or 0) - ImGui.Text("io.Fonts->FontLoaderName: %s", atlas.FontLoaderName or "NULL") - ImGui.Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y) - ImGui.Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y) - ImGui.Separator() - ImGui.Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y) - ImGui.Text("style.WindowBorderSize: %.2f", style.WindowBorderSize) - ImGui.Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y) - ImGui.Text("style.FrameRounding: %.2f", style.FrameRounding) - ImGui.Text("style.FrameBorderSize: %.2f", style.FrameBorderSize) - ImGui.Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y) - ImGui.Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y) - if copy_to_clipboard then - ImGui.LogText("\n```\n") - ImGui.LogFinish() - end - ImGui.EndChild() - end +function ShowExampleAppAssetsBrowser(p_open) + IMGUI_DEMO_MARKER("Examples/Assets Browser") + -- [Port] TODO: ExampleAssetsBrowser needs BeginMultiSelect()/box-select + local open, visible = ImGui.Begin("Example: Assets Browser", p_open) + if visible then ImGui.TextDisabled("(multi-select API not ported yet)") end ImGui.End() - return p_open + return open end -end --[[ About window ]] return true end @@ -38545,6 +40560,32 @@ function ImGuiTextBufferMT:appendf(fmt, ...) self.Buf[#self.Buf + 1] = string.fo function ImGuiTextBufferMT:c_str() return table.concat(self.Buf) end function ImGuiTextBufferMT:size() return #self:c_str() end +-- Helpers: ImColor() implicitly converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float) +-- Prefer using IM_COL32() macros. Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. +-- **None of the ImGui API are using ImColor directly but you can use it as a convenience to pass colors in either ImU32 or ImVec4 formats. Explicitly cast to ImU32 or ImVec4 if needed. +-- [Luau] no implicit conversions: use :U32() / .Value (ImVec4). Overloads: ImColor(), ImColor(r, g, b, a) floats, +-- ImColor(ImVec4), ImColor(ImU32). The C++ int (0-255) overload can't be told apart from floats: use ImColor(IM_COL32(r, g, b, a)). +--- @class ImColor +local ImColorMT = {} +ImColorMT.__index = ImColorMT +ImColor = setmetatable({}, { __call = function(_, r, g, b, a) + local self = setmetatable({ Value = ImVec4() }, ImColorMT) + if type(r) == "table" then + ImVec4_Copy(self.Value, r) + elseif r ~= nil and g == nil then + local s = 1.0 / 255.0 + self.Value.x = bit32.band(bit32.rshift(r, 0 --[[IM_COL32_R_SHIFT]]), 0xFF) * s; self.Value.y = bit32.band(bit32.rshift(r, 8 --[[IM_COL32_G_SHIFT]]), 0xFF) * s + self.Value.z = bit32.band(bit32.rshift(r, 16 --[[IM_COL32_B_SHIFT]]), 0xFF) * s; self.Value.w = bit32.band(bit32.rshift(r, 24 --[[IM_COL32_A_SHIFT]]), 0xFF) * s + elseif r ~= nil then + self.Value.x = r; self.Value.y = g; self.Value.z = b; self.Value.w = a or 1.0 + end + return self +end }) +function ImColorMT:U32() return ImGui.ColorConvertFloat4ToU32(self.Value) end +-- FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. +function ImColorMT:SetHSV(h, s, v, a) self.Value.x, self.Value.y, self.Value.z = ImGui.ColorConvertHSVtoRGB(h, s, v); self.Value.w = a or 1.0 end +function ImColor.HSV(h, s, v, a) local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v); return ImColor(r, g, b, a or 1.0) end + --- @class ImGuiSettingsHandler --- Fns take (ctx, handler, ...) like upstream. ReadOpenFn(ctx, handler, name) returns entry; ReadLineFn(ctx, handler, entry, line); --- WriteAllFn(ctx, handler, buf: ImGuiTextBuffer) @@ -63489,21 +65530,12 @@ IM_INCLUDE('imgui_demo.lua') return { BuildLoadGlyphGetAdvanceOrFallback = BuildLoadGlyphGetAdvanceOrFallback, CalcNextScrollFromScrollTargetAndClamp = CalcNextScrollFromScrollTargetAndClamp, + CustomConstraints = CustomConstraints, DBL_MAX = DBL_MAX, - DemoB2I = DemoB2I, - DemoBuf = DemoBuf, - DemoBufStr = DemoBufStr, - DemoClamp = DemoClamp, - DemoCollapsingHeaderClosable = DemoCollapsingHeaderClosable, - DemoCombo = DemoCombo, - DemoHSV = DemoHSV, - DemoHas = DemoHas, - DemoItems = DemoItems, - DemoListBox = DemoListBox, - DemoNotPorted = DemoNotPorted, - DemoNotSupported = DemoNotSupported, - DemoTextFilter = DemoTextFilter, + DemoWindowColumns = DemoWindowColumns, + DemoWindowInputs = DemoWindowInputs, DemoWindowLayout = DemoWindowLayout, + DemoWindowMenuBar = DemoWindowMenuBar, DemoWindowPopups = DemoWindowPopups, DemoWindowTables = DemoWindowTables, DemoWindowWidgets = DemoWindowWidgets, @@ -63526,6 +65558,7 @@ return { DemoWindowWidgetsProgressBars = DemoWindowWidgetsProgressBars, DemoWindowWidgetsQueryingStatuses = DemoWindowWidgetsQueryingStatuses, DemoWindowWidgetsSelectables = DemoWindowWidgetsSelectables, + DemoWindowWidgetsSelectionAndMultiSelect = DemoWindowWidgetsSelectionAndMultiSelect, DemoWindowWidgetsTabs = DemoWindowWidgetsTabs, DemoWindowWidgetsText = DemoWindowWidgetsText, DemoWindowWidgetsTextFilter = DemoWindowWidgetsTextFilter, @@ -63541,10 +65574,23 @@ return { DockSettingsHandler_WriteAll = DockSettingsHandler_WriteAll, DockSettingsRemoveNodeReferences = DockSettingsRemoveNodeReferences, DockSettingsRenameNodeReferences = DockSettingsRenameNodeReferences, + EditTabBarFittingPolicyFlags = EditTabBarFittingPolicyFlags, + EditTableColumnsFlags = EditTableColumnsFlags, + EditTableSizingFlags = EditTableSizingFlags, + ExampleAppConsole = ExampleAppConsole, + ExampleAppConsoleMT = ExampleAppConsoleMT, + ExampleAppDocuments = ExampleAppDocuments, + ExampleAppLog = ExampleAppLog, + ExampleAppLogMT = ExampleAppLogMT, + ExampleAppPropertyEditor = ExampleAppPropertyEditor, + ExampleAppPropertyEditorMT = ExampleAppPropertyEditorMT, ExampleImageViewerData = ExampleImageViewerData, ExampleImageViewer_DrawCanvas = ExampleImageViewer_DrawCanvas, ExampleImageViewer_DrawOptions = ExampleImageViewer_DrawOptions, + ExampleMemberInfo = ExampleMemberInfo, + ExampleNames = ExampleNames, ExampleTreeNode = ExampleTreeNode, + ExampleTreeNodeMemberInfos = ExampleTreeNodeMemberInfos, ExampleTree_CreateDemoTree = ExampleTree_CreateDemoTree, ExampleTree_CreateNode = ExampleTree_CreateNode, ExampleTree_DestroyNode = ExampleTree_DestroyNode, @@ -63556,6 +65602,7 @@ return { GetDefaultFontDataProggyClean = GetDefaultFontDataProggyClean, GetDefaultFontDataProggyForever = GetDefaultFontDataProggyForever, GetMinimumStepAtDecimalPrecision = GetMinimumStepAtDecimalPrecision, + GetTreeLinesFlagsName = GetTreeLinesFlagsName, HelpMarker = HelpMarker, IMGUI_DEBUG_LOG_ACTIVEID = IMGUI_DEBUG_LOG_ACTIVEID, IMGUI_DEBUG_LOG_CLIPPER = IMGUI_DEBUG_LOG_CLIPPER, @@ -63634,6 +65681,7 @@ return { ImCharIsBlankW = ImCharIsBlankW, ImCharIsSeparatorW = ImCharIsSeparatorW, ImClamp = ImClamp, + ImColor = ImColor, ImCos = ImCos, ImCountSetBits = ImCountSetBits, ImDot = ImDot, @@ -63742,6 +65790,7 @@ return { ImGuiDataAuthority = ImGuiDataAuthority, ImGuiDataType = ImGuiDataType, ImGuiDebugLogFlags = ImGuiDebugLogFlags, + ImGuiDemoDockspaceArgs = ImGuiDemoDockspaceArgs, ImGuiDemoWindowData = ImGuiDemoWindowData, ImGuiDir = ImGuiDir, ImGuiDockContext = ImGuiDockContext, @@ -63838,6 +65887,7 @@ return { ImGuiStyleMod = ImGuiStyleMod, ImGuiStyleVar = ImGuiStyleVar, ImGuiStyleVarInfo = ImGuiStyleVarInfo, + ImGuiStyle_Copy = ImGuiStyle_Copy, ImGuiTabBar = ImGuiTabBar, ImGuiTabBarFlags = ImGuiTabBarFlags, ImGuiTabItem = ImGuiTabItem, @@ -63940,9 +65990,21 @@ return { ImVec4_Copy = ImVec4_Copy, ImVector = ImVector, ImWcharClass = ImWcharClass, + MyDocument = MyDocument, + MyItem = MyItem, + MyItemColumnID_Action = MyItemColumnID_Action, + MyItemColumnID_Description = MyItemColumnID_Description, + MyItemColumnID_ID = MyItemColumnID_ID, + MyItemColumnID_Name = MyItemColumnID_Name, + MyItemColumnID_Quantity = MyItemColumnID_Quantity, + MyItem_CompareWithSortSpecs = MyItem_CompareWithSortSpecs, + MyItem_SortWithSortSpecs = MyItem_SortWithSortSpecs, + MyItem_s_current_sort_specs = MyItem_s_current_sort_specs, NAV_ACTIVATE_HIGHLIGHT_TIMER = NAV_ACTIVATE_HIGHLIGHT_TIMER, NAV_ACTIVATE_INPUT_WITH_GAMEPAD_DELAY = NAV_ACTIVATE_INPUT_WITH_GAMEPAD_DELAY, NAV_WINDOWING_HIGHLIGHT_DELAY = NAV_WINDOWING_HIGHLIGHT_DELAY, + PopStyleCompact = PopStyleCompact, + PushStyleCompact = PushStyleCompact, STB_TEXTEDIT_K_BACKSPACE = STB_TEXTEDIT_K_BACKSPACE, STB_TEXTEDIT_K_DELETE = STB_TEXTEDIT_K_DELETE, STB_TEXTEDIT_K_DOWN = STB_TEXTEDIT_K_DOWN, @@ -63963,13 +66025,17 @@ return { STB_TEXTEDIT_NEWLINE = STB_TEXTEDIT_NEWLINE, STB_TexteditState = STB_TexteditState, ShowDockingDisabledMessage = ShowDockingDisabledMessage, + ShowExampleAppAssetsBrowser = ShowExampleAppAssetsBrowser, ShowExampleAppAutoResize = ShowExampleAppAutoResize, ShowExampleAppConsole = ShowExampleAppConsole, ShowExampleAppConstrainedResize = ShowExampleAppConstrainedResize, ShowExampleAppCustomRendering = ShowExampleAppCustomRendering, ShowExampleAppDockSpace = ShowExampleAppDockSpace, + ShowExampleAppDockSpaceAdvanced = ShowExampleAppDockSpaceAdvanced, + ShowExampleAppDockSpaceBasic = ShowExampleAppDockSpaceBasic, ShowExampleAppDocuments = ShowExampleAppDocuments, ShowExampleAppFullscreen = ShowExampleAppFullscreen, + ShowExampleAppImageViewer = ShowExampleAppImageViewer, ShowExampleAppLayout = ShowExampleAppLayout, ShowExampleAppLog = ShowExampleAppLog, ShowExampleAppLongText = ShowExampleAppLongText, @@ -63978,6 +66044,7 @@ return { ShowExampleAppSimpleOverlay = ShowExampleAppSimpleOverlay, ShowExampleAppWindowTitles = ShowExampleAppWindowTitles, ShowExampleMenuFile = ShowExampleMenuFile, + ShowTableColumnsStatusFlags = ShowTableColumnsStatusFlags, UINT_MAX = UINT_MAX, VTX_STRIDE = VTX_STRIDE, _PathArcToFastExXY = _PathArcToFastExXY, diff --git a/docs/PORT_STATUS.txt b/docs/PORT_STATUS.txt index 5cdffeb..d990c04 100644 --- a/docs/PORT_STATUS.txt +++ b/docs/PORT_STATUS.txt @@ -12,20 +12,20 @@ Known low scores that are not missing code: data-driven port code (e.g. DemoWind polyline stroker (AddPolyline), Lua-native replacements (ImGuiStorage, ImStr*, ImFormatString -> string.format). upstream file funcs ported by size similarity stubs -imgui.cpp 786 87.4% 93.5% 75.0% 2 +imgui.cpp 786 87.4% 93.5% 74.9% 2 imgui_widgets.cpp 308 82.8% 88.9% 78.5% 0 -imgui_draw.cpp 258 74.8% 75.4% 63.1% 2 +imgui_draw.cpp 258 75.2% 75.5% 63.1% 2 imgui_tables.cpp 113 96.5% 99.0% 74.0% 0 -imgui_demo.cpp 56 80.4% 91.7% 29.0% 0 -imgui.h 110 51.8% 37.1% 56.4% 0 +imgui_demo.cpp 56 82.1% 98.2% 50.8% 0 +imgui.h 110 52.7% 37.1% 56.4% 0 imgui_internal.h 269 55.4% 58.8% 67.6% 0 -TOTAL 1900 78.7% 89.5% 66.2% 4 +TOTAL 1900 78.8% 90.6% 69.7% 4 -upstream code reproduced (similarity x ported size / all upstream size): 59.2% +upstream code reproduced (similarity x ported size / all upstream size): 63.2% Public API (imgui.h, namespace ImGui) 365 / 376 97.1% Internal API (imgui_internal.h, namespace ImGui) 405 / 443 91.4% -Enum values (imgui.h + imgui_internal.h) 973 / 1078 90.3% -Struct fields (imgui.h + imgui_internal.h) 1746 / 1926 90.7% +Enum values (imgui.h + imgui_internal.h) 978 / 1078 90.7% +Struct fields (imgui.h + imgui_internal.h) 1759 / 1926 91.3% Legend: [x] ported (sim %) [~] stub [ ] not ported [-] excluded (c++-only / obsolete / os-specific / #if 0 / test-engine) @@ -44,23 +44,23 @@ imgui.cpp [x] 38% ImGuiStyle::ImGuiStyle imgui_internal.lua:1460 [x] 83% ImGuiStyle::ScaleAllSizes imgui.lua:4779 [x] 13% ImGuiIO::ImGuiIO imgui_h.lua:1181 - [x] 83% ImGuiIO::AddInputCharacter imgui.lua:7977 - [x] 83% ImGuiIO::AddInputCharacterUTF16 imgui.lua:7998 + [x] 83% ImGuiIO::AddInputCharacter imgui.lua:7983 + [x] 83% ImGuiIO::AddInputCharacterUTF16 imgui.lua:8004 [ ] ImGuiIO::AddInputCharactersUTF8 - [x] 83% ImGuiIO::ClearEventsQueue imgui.lua:8027 - [x] 80% ImGuiIO::ClearInputKeys imgui.lua:8034 - [x] 75% ImGuiIO::ClearInputMouse imgui.lua:8052 + [x] 83% ImGuiIO::ClearEventsQueue imgui.lua:8033 + [x] 80% ImGuiIO::ClearInputKeys imgui.lua:8040 + [x] 75% ImGuiIO::ClearInputMouse imgui.lua:8058 [ ] FindLatestInputEvent - [x] 89% ImGuiIO::AddKeyAnalogEvent imgui.lua:8105 - [x] 89% ImGuiIO::AddKeyEvent imgui.lua:8151 + [x] 89% ImGuiIO::AddKeyAnalogEvent imgui.lua:8111 + [x] 89% ImGuiIO::AddKeyEvent imgui.lua:8157 [ ] ImGuiIO::SetKeyEventNativeData - [x] 100% ImGuiIO::SetAppAcceptingEvents imgui.lua:8160 - [x] 75% ImGuiIO::AddMousePosEvent imgui.lua:8226 - [x] 87% ImGuiIO::AddMouseButtonEvent imgui.lua:8265 - [x] 87% ImGuiIO::AddMouseWheelEvent imgui.lua:8317 - [x] 96% ImGuiIO::AddMouseSourceEvent imgui.lua:8167 - [x] 87% ImGuiIO::AddMouseViewportEvent imgui.lua:8174 - [x] 84% ImGuiIO::AddFocusEvent imgui.lua:8203 + [x] 100% ImGuiIO::SetAppAcceptingEvents imgui.lua:8166 + [x] 75% ImGuiIO::AddMousePosEvent imgui.lua:8232 + [x] 87% ImGuiIO::AddMouseButtonEvent imgui.lua:8271 + [x] 87% ImGuiIO::AddMouseWheelEvent imgui.lua:8323 + [x] 96% ImGuiIO::AddMouseSourceEvent imgui.lua:8173 + [x] 87% ImGuiIO::AddMouseViewportEvent imgui.lua:8180 + [x] 84% ImGuiIO::AddFocusEvent imgui.lua:8209 [x] 15% ImGuiPlatformIO::ImGuiPlatformIO imgui_h.lua:1487 -- MISC HELPERS/UTILITIES (Geometry functions) @@ -116,11 +116,11 @@ imgui.cpp [x] 41% ImTextCountLines imgui_tables.lua:3782 -- MISC HELPERS/UTILITIES (Color functions) - [x] 73% ImAlphaBlendColors imgui.lua:14348 - [x] 41% ImGui::ColorConvertU32ToFloat4 imgui.lua:14359 - [x] 16% ImGui::ColorConvertFloat4ToU32 imgui.lua:14378 - [x] 87% ImGui::ColorConvertRGBtoHSV imgui.lua:14389 - [x] 61% ImGui::ColorConvertHSVtoRGB imgui.lua:14414 + [x] 73% ImAlphaBlendColors imgui.lua:14354 + [x] 41% ImGui::ColorConvertU32ToFloat4 imgui.lua:14365 + [x] 16% ImGui::ColorConvertFloat4ToU32 imgui.lua:14384 + [x] 87% ImGui::ColorConvertRGBtoHSV imgui.lua:14395 + [x] 61% ImGui::ColorConvertHSVtoRGB imgui.lua:14420 -- ImGuiStorage [x] 69% ImLowerBound imgui_widgets.lua:5186 @@ -141,11 +141,11 @@ imgui.cpp [ ] ImGuiStorage::SetAllInt -- ImGuiTextFilter - [x] 32% ImGuiTextFilter::ImGuiTextFilter imgui.lua:19301 - [x] 36% ImGuiTextFilter::Draw imgui.lua:19311 - [x] 62% ImGuiTextFilter::DrawWithHint imgui.lua:19318 - [x] 49% ImGuiTextFilter::Build imgui.lua:19333 - [x] 56% ImGuiTextFilter::PassFilter imgui.lua:19394 + [x] 32% ImGuiTextFilter::ImGuiTextFilter imgui.lua:19307 + [x] 36% ImGuiTextFilter::Draw imgui.lua:19317 + [x] 62% ImGuiTextFilter::DrawWithHint imgui.lua:19324 + [x] 49% ImGuiTextFilter::Build imgui.lua:19339 + [x] 56% ImGuiTextFilter::PassFilter imgui.lua:19400 -- ImGuiTextBuffer, ImGuiTextIndex [x] 5% ImGuiTextBuffer::append imgui_h.lua:2651 @@ -154,44 +154,44 @@ imgui.cpp [ ] ImGuiTextIndex::append -- ImGuiListClipper - [x] 86% GetSkipItemForListClipping imgui.lua:19432 - [x] 71% ImGuiListClipper_SortAndFuseRanges imgui.lua:19442 - [x] 89% ImGuiListClipper_SeekCursorAndSetupPrevLine imgui.lua:19466 - [x] 8% ImGuiListClipper::ImGuiListClipper imgui.lua:19499 + [x] 86% GetSkipItemForListClipping imgui.lua:19438 + [x] 71% ImGuiListClipper_SortAndFuseRanges imgui.lua:19448 + [x] 89% ImGuiListClipper_SeekCursorAndSetupPrevLine imgui.lua:19472 + [x] 8% ImGuiListClipper::ImGuiListClipper imgui.lua:19505 [-] ImGuiListClipper::~ImGuiListClipper c++-only - [x] 64% ImGuiListClipper::Begin imgui.lua:19506 - [x] 79% ImGuiListClipper::End imgui.lua:19535 - [x] 61% ImGuiListClipper::IncludeItemsByIndex imgui.lua:19561 - [x] 80% ImGuiListClipper::SeekCursorForItem imgui.lua:19572 - [x] 79% ImGuiListClipper_StepInternal imgui.lua:19579 - [x] 40% ImGuiListClipper::Step imgui.lua:19728 - [x] 79% ImGui::CalcClipRectVisibleItemsY imgui.lua:14446 + [x] 64% ImGuiListClipper::Begin imgui.lua:19512 + [x] 79% ImGuiListClipper::End imgui.lua:19541 + [x] 61% ImGuiListClipper::IncludeItemsByIndex imgui.lua:19567 + [x] 80% ImGuiListClipper::SeekCursorForItem imgui.lua:19578 + [x] 79% ImGuiListClipper_StepInternal imgui.lua:19585 + [x] 40% ImGuiListClipper::Step imgui.lua:19734 + [x] 79% ImGui::CalcClipRectVisibleItemsY imgui.lua:14452 -- STYLING - [x] 90% ImGui::GetStyle imgui.lua:14456 - [x] 71% ImGui::GetStyleColorVec4 imgui.lua:18851 - [x] 26% ImGui::GetColorU32 imgui.lua:14470 - [x] 50% ImGui::PushStyleColor imgui.lua:14508 - [x] 68% ImGui::PopStyleColor imgui.lua:14525 - [x] 74% ImGui::GetStyleVarInfo imgui.lua:14592 - [x] 56% ImGui::PushStyleVar imgui.lua:14600 - [x] 91% ImGui::PushStyleVarX imgui.lua:14619 - [x] 91% ImGui::PushStyleVarY imgui.lua:14630 - [x] 70% ImGui::PopStyleVar imgui.lua:14640 - [x] 1% ImGui::GetStyleColorName imgui.lua:19161 + [x] 90% ImGui::GetStyle imgui.lua:14462 + [x] 71% ImGui::GetStyleColorVec4 imgui.lua:18857 + [x] 26% ImGui::GetColorU32 imgui.lua:14476 + [x] 50% ImGui::PushStyleColor imgui.lua:14514 + [x] 68% ImGui::PopStyleColor imgui.lua:14531 + [x] 74% ImGui::GetStyleVarInfo imgui.lua:14598 + [x] 56% ImGui::PushStyleVar imgui.lua:14606 + [x] 91% ImGui::PushStyleVarX imgui.lua:14625 + [x] 91% ImGui::PushStyleVarY imgui.lua:14636 + [x] 70% ImGui::PopStyleVar imgui.lua:14646 + [x] 1% ImGui::GetStyleColorName imgui.lua:19167 -- RENDER HELPERS - [x] 46% ImGui::FindRenderedTextEnd imgui.lua:10057 - [x] 76% ImGui::RenderText imgui.lua:10078 - [x] 79% ImGui::RenderTextWrapped imgui.lua:10108 - [x] 85% ImGui::RenderTextClippedEx imgui.lua:10141 - [x] 80% ImGui::RenderTextClipped imgui.lua:10178 - [x] 90% ImGui::RenderTextEllipsis imgui.lua:10313 - [x] 86% ImGui::RenderFrame imgui.lua:10372 - [x] 94% ImGui::RenderFrameBorder imgui.lua:10392 - [x] 99% ImGui::RenderColorComponentMarker imgui.lua:10405 - [x] 85% ImGui::RenderNavCursor imgui.lua:10201 - [x] 85% ImGui::RenderMouseCursor imgui.lua:10261 + [x] 46% ImGui::FindRenderedTextEnd imgui.lua:10063 + [x] 76% ImGui::RenderText imgui.lua:10084 + [x] 79% ImGui::RenderTextWrapped imgui.lua:10114 + [x] 85% ImGui::RenderTextClippedEx imgui.lua:10147 + [x] 80% ImGui::RenderTextClipped imgui.lua:10184 + [x] 90% ImGui::RenderTextEllipsis imgui.lua:10319 + [x] 86% ImGui::RenderFrame imgui.lua:10378 + [x] 94% ImGui::RenderFrameBorder imgui.lua:10398 + [x] 99% ImGui::RenderColorComponentMarker imgui.lua:10411 + [x] 85% ImGui::RenderNavCursor imgui.lua:10207 + [x] 85% ImGui::RenderMouseCursor imgui.lua:10267 -- INITIALIZATION, SHUTDOWN [x] 100% ImGui::GetCurrentContext imgui.lua:5487 @@ -203,7 +203,7 @@ imgui.cpp [x] 6% ImGuiContext::ImGuiContext imgui_internal.lua:2018 [-] ImGuiContext::~ImGuiContext c++-only [x] 78% ImGui::Initialize imgui.lua:5538 - [x] 41% ImGui::Shutdown imgui.lua:14265 + [x] 41% ImGui::Shutdown imgui.lua:14271 [ ] ImGui::SetContextName [ ] ImGui::AddContextHook [ ] ImGui::RemoveContextHook @@ -212,179 +212,179 @@ imgui.cpp -- MAIN CODE (most of the code! lots of stuff, needs tidying up!) [x] 11% ImGuiWindow::ImGuiWindow imgui_internal.lua:2602 [-] ImGuiWindow::~ImGuiWindow c++-only - [x] 74% SetCurrentWindow imgui.lua:10793 - [x] 70% ImGui::GcCompactTransientMiscBuffers imgui.lua:10814 - [x] 94% ImGui::GcCompactTransientWindowBuffers imgui.lua:10831 - [x] 96% ImGui::GcAwakeTransientWindowBuffers imgui.lua:10843 - [x] 86% ImGui::SetActiveID imgui.lua:7423 - [x] 100% ImGui::ClearActiveID imgui.lua:7489 - [x] 98% ImGui::SetHoveredID imgui.lua:7603 - [x] 84% ImGui::GetHoveredID imgui.lua:7094 - [x] 85% ImGui::MarkItemEdited imgui.lua:7637 - [x] 93% ImGui::IsWindowContentHoverable imgui.lua:7670 - [x] 87% CalcDelayFromHoveredFlags imgui.lua:7615 - [x] 50% ApplyHoverFlagsForTooltip imgui.lua:7628 - [x] 87% ImGui::IsItemHovered imgui.lua:7710 - [x] 85% ImGui::ItemHoverable imgui.lua:7842 - [x] 64% ImGui::IsClippedEx imgui.lua:7931 - [x] 91% ImGui::SetLastItemData imgui.lua:7952 - [x] 98% ImGui::SetLastItemDataForWindow imgui.lua:7963 - [x] 93% ImGui::SetLastItemDataForChildWindowItem imgui.lua:11271 - [x] 95% ImGui::CalcWrapWidthForPos imgui.lua:10025 + [x] 74% SetCurrentWindow imgui.lua:10799 + [x] 70% ImGui::GcCompactTransientMiscBuffers imgui.lua:10820 + [x] 94% ImGui::GcCompactTransientWindowBuffers imgui.lua:10837 + [x] 96% ImGui::GcAwakeTransientWindowBuffers imgui.lua:10849 + [x] 86% ImGui::SetActiveID imgui.lua:7429 + [x] 100% ImGui::ClearActiveID imgui.lua:7495 + [x] 98% ImGui::SetHoveredID imgui.lua:7609 + [x] 84% ImGui::GetHoveredID imgui.lua:7100 + [x] 85% ImGui::MarkItemEdited imgui.lua:7643 + [x] 93% ImGui::IsWindowContentHoverable imgui.lua:7676 + [x] 87% CalcDelayFromHoveredFlags imgui.lua:7621 + [x] 50% ApplyHoverFlagsForTooltip imgui.lua:7634 + [x] 87% ImGui::IsItemHovered imgui.lua:7716 + [x] 85% ImGui::ItemHoverable imgui.lua:7848 + [x] 64% ImGui::IsClippedEx imgui.lua:7937 + [x] 91% ImGui::SetLastItemData imgui.lua:7958 + [x] 98% ImGui::SetLastItemDataForWindow imgui.lua:7969 + [x] 93% ImGui::SetLastItemDataForChildWindowItem imgui.lua:11277 + [x] 95% ImGui::CalcWrapWidthForPos imgui.lua:10031 [x] 77% ImGui::MemAlloc imgui.lua:457 [x] 79% ImGui::MemFree imgui.lua:470 [ ] ImGui::DemoMarker [x] 79% ImGui::DebugAllocHook imgui.lua:485 - [x] 91% ImGui::GetClipboardText imgui.lua:14301 - [x] 100% ImGui::SetClipboardText imgui.lua:14307 - [x] 100% ImGui::GetVersion imgui.lua:19158 - [x] 57% ImGui::GetIO imgui.lua:14314 - [x] 90% ImGui::GetPlatformIO imgui.lua:14317 - [x] 86% ImGui::GetDrawData imgui.lua:14254 - [x] 100% ImGui::GetTime imgui.lua:14260 - [x] 100% ImGui::GetFrameCount imgui.lua:19150 - [x] 82% GetViewportBgFgDrawList imgui.lua:13605 - [x] 80% ImGui::GetBackgroundDrawList imgui.lua:13628 - [x] 80% ImGui::GetForegroundDrawList imgui.lua:13640 - [x] 100% ImGui::GetDrawListSharedData imgui.lua:11519 - [x] 90% ImGui::StartMouseMovingWindow imgui.lua:11448 + [x] 91% ImGui::GetClipboardText imgui.lua:14307 + [x] 100% ImGui::SetClipboardText imgui.lua:14313 + [x] 100% ImGui::GetVersion imgui.lua:19164 + [x] 57% ImGui::GetIO imgui.lua:14320 + [x] 90% ImGui::GetPlatformIO imgui.lua:14323 + [x] 86% ImGui::GetDrawData imgui.lua:14260 + [x] 100% ImGui::GetTime imgui.lua:14266 + [x] 100% ImGui::GetFrameCount imgui.lua:19156 + [x] 82% GetViewportBgFgDrawList imgui.lua:13611 + [x] 80% ImGui::GetBackgroundDrawList imgui.lua:13634 + [x] 80% ImGui::GetForegroundDrawList imgui.lua:13646 + [x] 100% ImGui::GetDrawListSharedData imgui.lua:11525 + [x] 90% ImGui::StartMouseMovingWindow imgui.lua:11454 [x] 94% ImGui::StartMouseMovingWindowOrNode imgui.lua:4527 - [x] 85% ImGui::StopMouseMovingWindow imgui.lua:7394 - [x] 95% ImGui::UpdateMouseMovingWindowNewFrame imgui.lua:11480 - [x] 88% ImGui::UpdateMouseMovingWindowEndFrame imgui.lua:11577 - [x] 65% TranslateWindow imgui.lua:11648 - [x] 88% ScaleWindow imgui.lua:14868 - [x] 100% IsWindowActiveAndVisible imgui.lua:9558 - [x] 93% ImGui::UpdateHoveredWindowAndCaptureFlags imgui.lua:13011 - [x] 55% SetupDrawListSharedData imgui.lua:13488 - [x] 87% ImGui::NewFrame imgui.lua:13734 - [x] 63% ChildWindowComparer imgui.lua:13654 - [x] 89% AddWindowToSortBuffer imgui.lua:13669 - [x] 86% AddWindowToDrawData imgui.lua:13683 - [x] 64% GetWindowDisplayLayer imgui.lua:13699 - [x] 100% AddRootWindowToDrawData imgui.lua:13705 - [x] 63% FlattenDrawDataIntoSingleLayer imgui.lua:13710 - [x] 83% InitViewportDrawData imgui.lua:13514 - [x] 52% ImGui::PushClipRect imgui.lua:13583 - [x] 42% ImGui::PopClipRect imgui.lua:13592 - [x] 60% ImGui::RenderDimmedBackgroundBehindWindow imgui.lua:18932 - [x] 83% ImGui::FindBottomMostVisibleWindowWithinBeginStack imgui.lua:18905 - [x] 80% ImGui::RenderDimmedBackgrounds imgui.lua:18953 - [x] 84% ImGui::EndFrame imgui.lua:14030 - [x] 74% ImGui::Render imgui.lua:14141 - [x] 17% ImGui::CalcTextSize imgui.lua:14214 - [x] 79% ImGui::FindHoveredWindowEx imgui.lua:12925 - [x] 95% ImGui::IsItemActive imgui.lua:6973 - [x] 97% ImGui::IsItemActivated imgui.lua:7014 - [x] 95% ImGui::IsItemDeactivated imgui.lua:7000 - [x] 100% ImGui::IsItemDeactivatedAfterEdit imgui.lua:7009 - [x] 100% ImGui::IsItemFocused imgui.lua:6984 - [x] 67% ImGui::IsItemClicked imgui.lua:7027 - [x] 57% ImGui::IsItemToggledOpen imgui.lua:7032 - [x] 84% ImGui::IsItemToggledSelection imgui.lua:7042 - [x] 100% ImGui::IsAnyItemHovered imgui.lua:7051 - [x] 67% ImGui::IsAnyItemActive imgui.lua:7056 - [x] 100% ImGui::IsAnyItemFocused imgui.lua:7060 - [x] 74% ImGui::IsItemVisible imgui.lua:7065 - [x] 74% ImGui::IsItemEdited imgui.lua:7069 - [x] 71% ImGui::SetNextItemAllowOverlap imgui.lua:7076 - [x] 93% ImGui::SetActiveIdUsingAllKeyboardKeys imgui.lua:11101 - [x] 67% ImGui::GetItemID imgui.lua:7081 - [x] 100% ImGui::GetItemRectMin imgui.lua:11110 - [x] 100% ImGui::GetItemRectMax imgui.lua:11116 - [x] 67% ImGui::GetItemRectSize imgui.lua:7090 - [x] 67% ImGui::GetItemFlags imgui.lua:7085 - [x] 43% ImGui::BeginChild imgui.lua:11260 - [x] 81% ImGui::BeginChildEx imgui.lua:11126 - [x] 90% ImGui::EndChild imgui.lua:11276 + [x] 85% ImGui::StopMouseMovingWindow imgui.lua:7400 + [x] 95% ImGui::UpdateMouseMovingWindowNewFrame imgui.lua:11486 + [x] 88% ImGui::UpdateMouseMovingWindowEndFrame imgui.lua:11583 + [x] 65% TranslateWindow imgui.lua:11654 + [x] 88% ScaleWindow imgui.lua:14874 + [x] 100% IsWindowActiveAndVisible imgui.lua:9564 + [x] 93% ImGui::UpdateHoveredWindowAndCaptureFlags imgui.lua:13017 + [x] 55% SetupDrawListSharedData imgui.lua:13494 + [x] 87% ImGui::NewFrame imgui.lua:13740 + [x] 63% ChildWindowComparer imgui.lua:13660 + [x] 89% AddWindowToSortBuffer imgui.lua:13675 + [x] 86% AddWindowToDrawData imgui.lua:13689 + [x] 64% GetWindowDisplayLayer imgui.lua:13705 + [x] 100% AddRootWindowToDrawData imgui.lua:13711 + [x] 63% FlattenDrawDataIntoSingleLayer imgui.lua:13716 + [x] 83% InitViewportDrawData imgui.lua:13520 + [x] 52% ImGui::PushClipRect imgui.lua:13589 + [x] 42% ImGui::PopClipRect imgui.lua:13598 + [x] 60% ImGui::RenderDimmedBackgroundBehindWindow imgui.lua:18938 + [x] 83% ImGui::FindBottomMostVisibleWindowWithinBeginStack imgui.lua:18911 + [x] 80% ImGui::RenderDimmedBackgrounds imgui.lua:18959 + [x] 84% ImGui::EndFrame imgui.lua:14036 + [x] 74% ImGui::Render imgui.lua:14147 + [x] 17% ImGui::CalcTextSize imgui.lua:14220 + [x] 79% ImGui::FindHoveredWindowEx imgui.lua:12931 + [x] 95% ImGui::IsItemActive imgui.lua:6979 + [x] 97% ImGui::IsItemActivated imgui.lua:7020 + [x] 95% ImGui::IsItemDeactivated imgui.lua:7006 + [x] 100% ImGui::IsItemDeactivatedAfterEdit imgui.lua:7015 + [x] 100% ImGui::IsItemFocused imgui.lua:6990 + [x] 67% ImGui::IsItemClicked imgui.lua:7033 + [x] 57% ImGui::IsItemToggledOpen imgui.lua:7038 + [x] 84% ImGui::IsItemToggledSelection imgui.lua:7048 + [x] 100% ImGui::IsAnyItemHovered imgui.lua:7057 + [x] 67% ImGui::IsAnyItemActive imgui.lua:7062 + [x] 100% ImGui::IsAnyItemFocused imgui.lua:7066 + [x] 74% ImGui::IsItemVisible imgui.lua:7071 + [x] 74% ImGui::IsItemEdited imgui.lua:7075 + [x] 71% ImGui::SetNextItemAllowOverlap imgui.lua:7082 + [x] 93% ImGui::SetActiveIdUsingAllKeyboardKeys imgui.lua:11107 + [x] 67% ImGui::GetItemID imgui.lua:7087 + [x] 100% ImGui::GetItemRectMin imgui.lua:11116 + [x] 100% ImGui::GetItemRectMax imgui.lua:11122 + [x] 67% ImGui::GetItemRectSize imgui.lua:7096 + [x] 67% ImGui::GetItemFlags imgui.lua:7091 + [x] 43% ImGui::BeginChild imgui.lua:11266 + [x] 81% ImGui::BeginChildEx imgui.lua:11132 + [x] 90% ImGui::EndChild imgui.lua:11282 [x] 83% ImGui::FindFrontMostVisibleChildWindow imgui.lua:5629 [x] 42% SetWindowConditionAllowFlags imgui.lua:5641 - [x] 73% ImGui::FindWindowByID imgui.lua:11661 - [x] 100% ImGui::FindWindowByName imgui.lua:11671 + [x] 73% ImGui::FindWindowByID imgui.lua:11667 + [x] 100% ImGui::FindWindowByName imgui.lua:11677 [x] 86% ApplyWindowSettings imgui.lua:5655 [x] 61% InitOrLoadWindowSettings imgui.lua:5694 [x] 73% CreateNewWindow imgui.lua:5715 [x] 75% GetWindowForTitleDisplay imgui.lua:6236 [ ] GetWindowForTitleAndMenuHeight - [x] 72% CalcWindowMinSize imgui.lua:9564 - [x] 86% CalcWindowSizeAfterConstraint imgui.lua:9609 - [x] 79% CalcWindowContentSizes imgui.lua:9644 - [x] 86% CalcWindowAutoFitSize imgui.lua:9669 - [x] 85% ImGui::CalcWindowNextAutoFitSize imgui.lua:9718 - [x] 84% GetWindowBgColorIdx imgui.lua:9729 - [x] 89% CalcResizePosSizeFromAnyCorner imgui.lua:9744 + [x] 72% CalcWindowMinSize imgui.lua:9570 + [x] 86% CalcWindowSizeAfterConstraint imgui.lua:9615 + [x] 79% CalcWindowContentSizes imgui.lua:9650 + [x] 86% CalcWindowAutoFitSize imgui.lua:9675 + [x] 85% ImGui::CalcWindowNextAutoFitSize imgui.lua:9724 + [x] 84% GetWindowBgColorIdx imgui.lua:9735 + [x] 89% CalcResizePosSizeFromAnyCorner imgui.lua:9750 [x] 94% GetResizeBorderRect imgui.lua:4856 [ ] ImGui::GetWindowResizeCornerID [ ] ImGui::GetWindowResizeBorderID - [x] 71% ImGui::UpdateWindowManualResize imgui.lua:9787 + [x] 71% ImGui::UpdateWindowManualResize imgui.lua:9793 [ ] ClampWindowPos - [x] 95% RenderWindowOuterSingleBorder imgui.lua:10418 - [x] 93% ImGui::RenderWindowOuterBorders imgui.lua:10593 = RenderWindowOuterBorders - [x] 83% ImGui::RenderWindowDecorations imgui.lua:10462 - [x] 93% ImGui::RenderWindowTitleBarContents imgui.lua:10603 - [x] 85% ImGui::UpdateWindowParentAndRootLinks imgui.lua:10699 - [x] 33% ImGui::UpdateWindowSkipRefresh imgui.lua:10729 - [x] 92% SetWindowActiveForSkipRefresh imgui.lua:10781 - [x] 81% ImGui::Begin imgui.lua:11688 - [x] 86% ImGui::End imgui.lua:12745 - [x] 84% ImGui::PushItemFlag imgui.lua:12834 - [x] 96% ImGui::PopItemFlag imgui.lua:12849 - [x] 79% ImGui::BeginDisabled imgui.lua:12864 - [x] 87% ImGui::EndDisabled imgui.lua:12880 - [x] 78% ImGui::BeginDisabledOverrideReenable imgui.lua:12896 - [x] 88% ImGui::EndDisabledOverrideReenable imgui.lua:12907 - [x] 54% ImGui::PushTextWrapPos imgui.lua:14665 - [x] 69% ImGui::PopTextWrapPos imgui.lua:14676 - [x] 100% GetCombinedRootWindow imgui.lua:14688 - [x] 100% ImGui::IsWindowChildOf imgui.lua:14707 - [x] 84% ImGui::IsWindowInBeginStack imgui.lua:14727 - [x] 100% ImGui::IsWindowWithinBeginStackOf imgui.lua:14739 - [x] 91% ImGui::IsWindowAbove imgui.lua:14757 - [x] 90% ImGui::IsWindowHovered imgui.lua:14783 + [x] 95% RenderWindowOuterSingleBorder imgui.lua:10424 + [x] 93% ImGui::RenderWindowOuterBorders imgui.lua:10599 = RenderWindowOuterBorders + [x] 83% ImGui::RenderWindowDecorations imgui.lua:10468 + [x] 93% ImGui::RenderWindowTitleBarContents imgui.lua:10609 + [x] 85% ImGui::UpdateWindowParentAndRootLinks imgui.lua:10705 + [x] 33% ImGui::UpdateWindowSkipRefresh imgui.lua:10735 + [x] 92% SetWindowActiveForSkipRefresh imgui.lua:10787 + [x] 81% ImGui::Begin imgui.lua:11694 + [x] 86% ImGui::End imgui.lua:12751 + [x] 84% ImGui::PushItemFlag imgui.lua:12840 + [x] 96% ImGui::PopItemFlag imgui.lua:12855 + [x] 79% ImGui::BeginDisabled imgui.lua:12870 + [x] 87% ImGui::EndDisabled imgui.lua:12886 + [x] 78% ImGui::BeginDisabledOverrideReenable imgui.lua:12902 + [x] 88% ImGui::EndDisabledOverrideReenable imgui.lua:12913 + [x] 54% ImGui::PushTextWrapPos imgui.lua:14671 + [x] 69% ImGui::PopTextWrapPos imgui.lua:14682 + [x] 100% GetCombinedRootWindow imgui.lua:14694 + [x] 100% ImGui::IsWindowChildOf imgui.lua:14713 + [x] 84% ImGui::IsWindowInBeginStack imgui.lua:14733 + [x] 100% ImGui::IsWindowWithinBeginStackOf imgui.lua:14745 + [x] 91% ImGui::IsWindowAbove imgui.lua:14763 + [x] 90% ImGui::IsWindowHovered imgui.lua:14789 [x] 67% ImGui::GetWindowDockID imgui.lua:4511 [x] 67% ImGui::IsWindowDocked imgui.lua:4515 - [x] 100% ImGui::GetWindowWidth imgui.lua:10853 - [x] 74% ImGui::GetWindowHeight imgui.lua:10986 - [x] 56% ImGui::GetWindowPos imgui.lua:10991 - [x] 61% ImGui::SetWindowPos imgui.lua:10861 - [x] 55% ImGui::GetWindowSize imgui.lua:10996 - [x] 76% ImGui::SetWindowSize imgui.lua:10903 - [x] 55% ImGui::SetWindowCollapsed imgui.lua:10948 - [x] 59% ImGui::SetWindowHitTestHole imgui.lua:10972 - [x] 97% ImGui::SetWindowHiddenAndSkipItemsForCurrentFrame imgui.lua:11019 - [x] 55% ImGui::IsWindowCollapsed imgui.lua:10978 - [x] 55% ImGui::IsWindowAppearing imgui.lua:10982 - [x] 72% ImGui::SetNextWindowPos imgui.lua:11028 - [x] 74% ImGui::SetNextWindowSize imgui.lua:11044 - [x] 87% ImGui::SetNextWindowSizeConstraints imgui.lua:11063 - [x] 65% ImGui::SetNextWindowContentSize imgui.lua:11362 - [x] 74% ImGui::SetNextWindowScroll imgui.lua:11369 - [x] 77% ImGui::SetNextWindowCollapsed imgui.lua:11377 - [x] 80% ImGui::SetNextWindowBgAlpha imgui.lua:11072 - [x] 80% ImGui::SetNextWindowViewport imgui.lua:11392 + [x] 100% ImGui::GetWindowWidth imgui.lua:10859 + [x] 74% ImGui::GetWindowHeight imgui.lua:10992 + [x] 56% ImGui::GetWindowPos imgui.lua:10997 + [x] 61% ImGui::SetWindowPos imgui.lua:10867 + [x] 55% ImGui::GetWindowSize imgui.lua:11002 + [x] 76% ImGui::SetWindowSize imgui.lua:10909 + [x] 55% ImGui::SetWindowCollapsed imgui.lua:10954 + [x] 59% ImGui::SetWindowHitTestHole imgui.lua:10978 + [x] 97% ImGui::SetWindowHiddenAndSkipItemsForCurrentFrame imgui.lua:11025 + [x] 55% ImGui::IsWindowCollapsed imgui.lua:10984 + [x] 55% ImGui::IsWindowAppearing imgui.lua:10988 + [x] 72% ImGui::SetNextWindowPos imgui.lua:11034 + [x] 74% ImGui::SetNextWindowSize imgui.lua:11050 + [x] 87% ImGui::SetNextWindowSizeConstraints imgui.lua:11069 + [x] 65% ImGui::SetNextWindowContentSize imgui.lua:11368 + [x] 74% ImGui::SetNextWindowScroll imgui.lua:11375 + [x] 77% ImGui::SetNextWindowCollapsed imgui.lua:11383 + [x] 80% ImGui::SetNextWindowBgAlpha imgui.lua:11078 + [x] 80% ImGui::SetNextWindowViewport imgui.lua:11398 [x] 76% ImGui::SetNextWindowDockID imgui.lua:4519 - [x] 50% ImGui::SetNextWindowClass imgui.lua:11399 - [x] 69% ImGui::SetNextWindowRefreshPolicy imgui.lua:11409 - [x] 47% ImGui::SetNextWindowFlags imgui.lua:11343 - [x] 47% ImGui::SetNextWindowChildFlags imgui.lua:11325 - [x] 100% ImGui::GetWindowDrawList imgui.lua:11078 - [x] 22% ImGui::GetWindowDpiScale imgui.lua:11429 - [x] 42% ImGui::GetWindowViewport imgui.lua:11433 - [x] 100% ImGui::GetFont imgui.lua:11083 + [x] 50% ImGui::SetNextWindowClass imgui.lua:11405 + [x] 69% ImGui::SetNextWindowRefreshPolicy imgui.lua:11415 + [x] 47% ImGui::SetNextWindowFlags imgui.lua:11349 + [x] 47% ImGui::SetNextWindowChildFlags imgui.lua:11331 + [x] 100% ImGui::GetWindowDrawList imgui.lua:11084 + [x] 22% ImGui::GetWindowDpiScale imgui.lua:11435 + [x] 42% ImGui::GetWindowViewport imgui.lua:11439 + [x] 100% ImGui::GetFont imgui.lua:11089 [ ] ImGui::GetFontBaked - [x] 100% ImGui::GetFontSize imgui.lua:11090 - [x] 100% ImGui::GetFontTexUvWhitePixel imgui.lua:11095 + [x] 100% ImGui::GetFontSize imgui.lua:11096 + [x] 100% ImGui::GetFontTexUvWhitePixel imgui.lua:11101 [-] ImGui::SetWindowFontScale obsolete - [x] 93% ImGui::PushFocusScope imgui.lua:15873 - [x] 56% ImGui::PopFocusScope imgui.lua:15882 - [x] 91% ImGui::IsInNavFocusRoute imgui.lua:15894 - [x] 71% ImGui::SetNavFocusScope imgui.lua:15908 - [x] 76% ImGui::FocusItem imgui.lua:19121 - [x] 100% ImGui::ActivateItemByID imgui.lua:19134 - [x] 81% ImGui::SetKeyboardFocusHere imgui.lua:19093 - [x] 98% ImGui::SetItemDefaultFocus imgui.lua:15948 - [x] 91% ImGui::SetStateStorage imgui.lua:19152 - [x] 74% ImGui::GetStateStorage imgui.lua:19151 + [x] 93% ImGui::PushFocusScope imgui.lua:15879 + [x] 56% ImGui::PopFocusScope imgui.lua:15888 + [x] 91% ImGui::IsInNavFocusRoute imgui.lua:15900 + [x] 71% ImGui::SetNavFocusScope imgui.lua:15914 + [x] 76% ImGui::FocusItem imgui.lua:19127 + [x] 100% ImGui::ActivateItemByID imgui.lua:19140 + [x] 81% ImGui::SetKeyboardFocusHere imgui.lua:19099 + [x] 98% ImGui::SetItemDefaultFocus imgui.lua:15954 + [x] 91% ImGui::SetStateStorage imgui.lua:19158 + [x] 74% ImGui::GetStateStorage imgui.lua:19157 [x] 72% ImGui::IsRectVisible imgui.lua:6795 -- FONTS, TEXTURES @@ -404,90 +404,90 @@ imgui.cpp [x] 86% ImGui::PopFont imgui.lua:5359 -- ID STACK - [x] 46% ImGuiWindow::GetID imgui.lua:7536 - [x] 76% ImGuiWindow::GetIDFromPos imgui.lua:7557 - [x] 47% ImGuiWindow::GetIDFromRectangle imgui.lua:7566 - [x] 53% ImGui::PushID imgui.lua:7499 - [x] 62% ImGui::PushOverrideID imgui.lua:7511 - [x] 39% ImGui::GetIDWithSeed imgui.lua:7588 - [x] 68% ImGui::PopID imgui.lua:7524 - [x] 38% ImGui::GetID imgui.lua:7576 + [x] 46% ImGuiWindow::GetID imgui.lua:7542 + [x] 76% ImGuiWindow::GetIDFromPos imgui.lua:7563 + [x] 47% ImGuiWindow::GetIDFromRectangle imgui.lua:7572 + [x] 53% ImGui::PushID imgui.lua:7505 + [x] 62% ImGui::PushOverrideID imgui.lua:7517 + [x] 39% ImGui::GetIDWithSeed imgui.lua:7594 + [x] 68% ImGui::PopID imgui.lua:7530 + [x] 38% ImGui::GetID imgui.lua:7582 -- INPUTS - [x] 84% GetModForLRModKey imgui.lua:8405 - [x] 74% ImGui::FixupKeyChord imgui.lua:8422 - [x] 52% ImGui::GetKeyData imgui.lua:8434 - [x] 85% ImGui::GetKeyName imgui.lua:8635 - [x] 43% ImGui::GetKeyChordName imgui.lua:8592 - [x] 76% ImGui::CalcTypematicRepeatAmount imgui.lua:8677 - [x] 81% ImGui::GetTypematicRepeatRate imgui.lua:8708 - [x] 96% ImGui::GetKeyPressedAmount imgui.lua:8721 - [x] 77% ImGui::GetKeyMagnitude2d imgui.lua:8452 - [x] 83% ImGui::UpdateKeyRoutingTable imgui.lua:8736 - [x] 70% GetRoutingIdFromOwnerId imgui.lua:8782 - [x] 84% ImGui::GetShortcutRoutingData imgui.lua:8789 - [x] 86% CalcRoutingScore imgui.lua:8841 - [x] 69% IsKeyChordPotentiallyCharInput imgui.lua:8895 - [x] 73% ImGui::SetShortcutRouting imgui.lua:8922 + [x] 84% GetModForLRModKey imgui.lua:8411 + [x] 74% ImGui::FixupKeyChord imgui.lua:8428 + [x] 52% ImGui::GetKeyData imgui.lua:8440 + [x] 85% ImGui::GetKeyName imgui.lua:8641 + [x] 43% ImGui::GetKeyChordName imgui.lua:8598 + [x] 76% ImGui::CalcTypematicRepeatAmount imgui.lua:8683 + [x] 81% ImGui::GetTypematicRepeatRate imgui.lua:8714 + [x] 96% ImGui::GetKeyPressedAmount imgui.lua:8727 + [x] 77% ImGui::GetKeyMagnitude2d imgui.lua:8458 + [x] 83% ImGui::UpdateKeyRoutingTable imgui.lua:8742 + [x] 70% GetRoutingIdFromOwnerId imgui.lua:8788 + [x] 84% ImGui::GetShortcutRoutingData imgui.lua:8795 + [x] 86% CalcRoutingScore imgui.lua:8847 + [x] 69% IsKeyChordPotentiallyCharInput imgui.lua:8901 + [x] 73% ImGui::SetShortcutRouting imgui.lua:8928 [ ] ImGui::TestShortcutRouting - [x] 81% ImGui::IsKeyDown imgui.lua:8501 - [x] 9% ImGui::IsKeyPressed imgui.lua:8516 - [x] 84% ImGui::IsKeyReleased imgui.lua:8525 - [x] 69% ImGui::IsMouseDown imgui.lua:9037 - [x] 13% ImGui::IsMouseClicked imgui.lua:9047 - [x] 69% ImGui::IsMouseReleased imgui.lua:9088 - [x] 86% ImGui::IsMouseReleasedWithDelay imgui.lua:9102 - [x] 71% ImGui::IsMouseDoubleClicked imgui.lua:9118 - [x] 83% ImGui::GetMouseClickedCount imgui.lua:9126 - [x] 99% LastItemOverlayButtonForNullId imgui.lua:9134 - [x] 91% ImGui::GetItemClickedCountWithSingleClickDelay imgui.lua:9170 + [x] 81% ImGui::IsKeyDown imgui.lua:8507 + [x] 9% ImGui::IsKeyPressed imgui.lua:8522 + [x] 84% ImGui::IsKeyReleased imgui.lua:8531 + [x] 69% ImGui::IsMouseDown imgui.lua:9043 + [x] 13% ImGui::IsMouseClicked imgui.lua:9053 + [x] 69% ImGui::IsMouseReleased imgui.lua:9094 + [x] 86% ImGui::IsMouseReleasedWithDelay imgui.lua:9108 + [x] 71% ImGui::IsMouseDoubleClicked imgui.lua:9124 + [x] 83% ImGui::GetMouseClickedCount imgui.lua:9132 + [x] 99% LastItemOverlayButtonForNullId imgui.lua:9140 + [x] 91% ImGui::GetItemClickedCountWithSingleClickDelay imgui.lua:9176 [x] 29% ImGui::IsMouseHoveringRect imgui.lua:6266 [x] 81% ImGui::IsMouseDragPastThreshold imgui.lua:6299 [x] 77% ImGui::IsMouseDragging imgui.lua:6312 - [x] 67% ImGui::GetMousePos imgui.lua:9196 + [x] 67% ImGui::GetMousePos imgui.lua:9202 [x] 85% ImGui::TeleportMousePos imgui.lua:6326 - [x] 93% ImGui::GetMousePosOnOpeningCurrentPopup imgui.lua:9201 - [x] 80% ImGui::IsMousePosValid imgui.lua:9016 - [x] 75% ImGui::IsAnyMouseDown imgui.lua:9025 - [x] 87% ImGui::GetMouseDragDelta imgui.lua:9215 - [x] 71% ImGui::ResetMouseDragDelta imgui.lua:9234 - [x] 100% ImGui::GetMouseCursor imgui.lua:14326 - [x] 100% ImGui::SetMouseCursor imgui.lua:14335 - [x] 92% UpdateAliasKey imgui.lua:13105 - [x] 42% GetMergedModsFromKeys imgui.lua:13113 - [x] 85% ImGui::UpdateKeyboardInputs imgui.lua:13126 - [x] 88% ImGui::UpdateMouseInputs imgui.lua:13204 - [x] 91% LockWheelingWindow imgui.lua:13312 - [x] 76% FindBestWheelingWindow imgui.lua:13333 - [x] 92% ImGui::UpdateMouseWheel imgui.lua:13383 - [x] 60% ImGui::SetNextFrameWantCaptureKeyboard imgui.lua:19156 - [x] 60% ImGui::SetNextFrameWantCaptureMouse imgui.lua:19157 + [x] 93% ImGui::GetMousePosOnOpeningCurrentPopup imgui.lua:9207 + [x] 80% ImGui::IsMousePosValid imgui.lua:9022 + [x] 75% ImGui::IsAnyMouseDown imgui.lua:9031 + [x] 87% ImGui::GetMouseDragDelta imgui.lua:9221 + [x] 71% ImGui::ResetMouseDragDelta imgui.lua:9240 + [x] 100% ImGui::GetMouseCursor imgui.lua:14332 + [x] 100% ImGui::SetMouseCursor imgui.lua:14341 + [x] 92% UpdateAliasKey imgui.lua:13111 + [x] 42% GetMergedModsFromKeys imgui.lua:13119 + [x] 85% ImGui::UpdateKeyboardInputs imgui.lua:13132 + [x] 88% ImGui::UpdateMouseInputs imgui.lua:13210 + [x] 91% LockWheelingWindow imgui.lua:13318 + [x] 76% FindBestWheelingWindow imgui.lua:13339 + [x] 92% ImGui::UpdateMouseWheel imgui.lua:13389 + [x] 60% ImGui::SetNextFrameWantCaptureKeyboard imgui.lua:19162 + [x] 60% ImGui::SetNextFrameWantCaptureMouse imgui.lua:19163 [ ] GetInputSourceName [ ] GetMouseSourceName [ ] DebugPrintInputEvent - [x] 78% ImGui::UpdateInputEvents imgui.lua:9251 - [x] 80% ImGui::GetKeyOwner imgui.lua:8651 - [x] 84% ImGui::TestKeyOwner imgui.lua:8465 - [x] 80% ImGui::SetKeyOwner imgui.lua:9406 - [x] 59% ImGui::SetKeyOwnersForKeyChord imgui.lua:9428 - [x] 79% ImGui::SetItemKeyOwner imgui.lua:9456 - [x] 85% ImGui::IsKeyChordPressed imgui.lua:9482 - [x] 76% ImGui::SetNextItemShortcut imgui.lua:9503 + [x] 78% ImGui::UpdateInputEvents imgui.lua:9257 + [x] 80% ImGui::GetKeyOwner imgui.lua:8657 + [x] 84% ImGui::TestKeyOwner imgui.lua:8471 + [x] 80% ImGui::SetKeyOwner imgui.lua:9412 + [x] 59% ImGui::SetKeyOwnersForKeyChord imgui.lua:9434 + [x] 79% ImGui::SetItemKeyOwner imgui.lua:9462 + [x] 85% ImGui::IsKeyChordPressed imgui.lua:9488 + [x] 76% ImGui::SetNextItemShortcut imgui.lua:9509 [x] 88% ImGui::ItemHandleShortcut imgui.lua:6337 - [x] 78% ImGui::Shortcut imgui.lua:9515 + [x] 78% ImGui::Shortcut imgui.lua:9521 -- ERROR CHECKING, STATE RECOVERY [ ] ImGui::DebugCheckVersionAndDataLayout - [x] 86% ImGui::ErrorCheckUsingSetCursorPosToExtendParentBoundaries imgui.lua:18868 + [x] 86% ImGui::ErrorCheckUsingSetCursorPosToExtendParentBoundaries imgui.lua:18874 [ ] ImGui::ErrorCheckNewFrameSanityChecks [ ] ImGui::ErrorCheckEndFrameSanityChecks - [x] 100% ImGui::ErrorRecoveryStoreState imgui.lua:19763 - [x] 91% ImGui::ErrorRecoveryTryToRecoverState imgui.lua:19781 - [x] 91% ImGui::ErrorRecoveryTryToRecoverWindowState imgui.lua:19810 - [x] 86% ImGui::ErrorLog imgui.lua:19899 - [x] 80% ImGui::ErrorCheckEndFrameFinalizeErrorTooltip imgui.lua:19943 - [x] 77% ImGui::BeginErrorTooltip imgui.lua:19981 - [x] 100% ImGui::EndErrorTooltip imgui.lua:20003 + [x] 100% ImGui::ErrorRecoveryStoreState imgui.lua:19769 + [x] 91% ImGui::ErrorRecoveryTryToRecoverState imgui.lua:19787 + [x] 91% ImGui::ErrorRecoveryTryToRecoverWindowState imgui.lua:19816 + [x] 86% ImGui::ErrorLog imgui.lua:19905 + [x] 80% ImGui::ErrorCheckEndFrameFinalizeErrorTooltip imgui.lua:19949 + [x] 77% ImGui::BeginErrorTooltip imgui.lua:19987 + [x] 100% ImGui::EndErrorTooltip imgui.lua:20009 -- ITEM SUBMISSION [x] 100% ImGui::KeepAliveID imgui.lua:6247 @@ -512,8 +512,8 @@ imgui.cpp [x] 90% ImGui::PushMultiItemsWidths imgui.lua:6659 [x] 68% ImGui::PopItemWidth imgui.lua:6645 [x] 73% ImGui::CalcItemWidth imgui.lua:6913 - [x] 66% ImGui::CalcItemSize imgui.lua:6943 - [x] 100% ImGui::GetTextLineHeight imgui.lua:6968 + [x] 19% ImGui::CalcItemSize imgui.lua:6943 + [x] 100% ImGui::GetTextLineHeight imgui.lua:6974 [x] 100% ImGui::GetTextLineHeightWithSpacing imgui.lua:6769 [x] 100% ImGui::GetFrameHeight imgui.lua:6677 [x] 100% ImGui::GetFrameHeightWithSpacing imgui.lua:6764 @@ -525,126 +525,126 @@ imgui.cpp [x] 91% ImGui::EndGroup imgui.lua:6839 -- SCROLLING - [x] 100% CalcScrollEdgeSnap imgui.lua:14907 - [x] 89% CalcNextScrollFromScrollTargetAndClamp imgui.lua:14918 - [x] 78% ImGui::ScrollToItem imgui.lua:15044 - [x] 86% ImGui::ScrollToRect imgui.lua:15052 - [x] 88% ImGui::ScrollToRectEx imgui.lua:14950 - [x] 74% ImGui::GetScrollX imgui.lua:15035 - [x] 74% ImGui::GetScrollY imgui.lua:15039 - [x] 74% ImGui::GetScrollMaxX imgui.lua:15031 - [x] 100% ImGui::GetScrollMaxY imgui.lua:15026 - [x] 75% ImGui::SetScrollX imgui.lua:15087 - [x] 75% ImGui::SetScrollY imgui.lua:15096 - [x] 78% ImGui::SetScrollFromPosX imgui.lua:15116 - [x] 78% ImGui::SetScrollFromPosY imgui.lua:15128 - [x] 95% ImGui::SetScrollHereX imgui.lua:15058 - [x] 95% ImGui::SetScrollHereY imgui.lua:15072 + [x] 100% CalcScrollEdgeSnap imgui.lua:14913 + [x] 89% CalcNextScrollFromScrollTargetAndClamp imgui.lua:14924 + [x] 78% ImGui::ScrollToItem imgui.lua:15050 + [x] 86% ImGui::ScrollToRect imgui.lua:15058 + [x] 88% ImGui::ScrollToRectEx imgui.lua:14956 + [x] 74% ImGui::GetScrollX imgui.lua:15041 + [x] 74% ImGui::GetScrollY imgui.lua:15045 + [x] 74% ImGui::GetScrollMaxX imgui.lua:15037 + [x] 100% ImGui::GetScrollMaxY imgui.lua:15032 + [x] 75% ImGui::SetScrollX imgui.lua:15093 + [x] 75% ImGui::SetScrollY imgui.lua:15102 + [x] 78% ImGui::SetScrollFromPosX imgui.lua:15122 + [x] 78% ImGui::SetScrollFromPosY imgui.lua:15134 + [x] 95% ImGui::SetScrollHereX imgui.lua:15064 + [x] 95% ImGui::SetScrollHereY imgui.lua:15078 -- TOOLTIPS - [x] 100% ImGui::BeginTooltip imgui.lua:15196 - [x] 100% ImGui::BeginItemTooltip imgui.lua:15200 - [x] 83% ImGui::BeginTooltipEx imgui.lua:15143 - [x] 73% ImGui::EndTooltip imgui.lua:15207 - [x] 21% ImGui::SetTooltip imgui.lua:15214 + [x] 100% ImGui::BeginTooltip imgui.lua:15202 + [x] 100% ImGui::BeginItemTooltip imgui.lua:15206 + [x] 83% ImGui::BeginTooltipEx imgui.lua:15149 + [x] 73% ImGui::EndTooltip imgui.lua:15213 + [x] 21% ImGui::SetTooltip imgui.lua:15220 [ ] ImGui::SetTooltipV - [x] 52% ImGui::SetItemTooltip imgui.lua:15226 + [x] 52% ImGui::SetItemTooltip imgui.lua:15232 [ ] ImGui::SetItemTooltipV -- POPUPS - [x] 73% ImGui::IsPopupOpen imgui.lua:11526 - [x] 82% ImGui::GetTopMostPopupModal imgui.lua:11561 - [x] 81% ImGui::GetTopMostAndVisiblePopupModal imgui.lua:18921 - [x] 79% ImGui::FindBlockingModal imgui.lua:15250 - [x] 26% ImGui::OpenPopup imgui.lua:15283 - [x] 86% ImGui::OpenPopupEx imgui.lua:15304 - [x] 73% ImGui::ClosePopupsOverWindow imgui.lua:15367 - [x] 80% ImGui::ClosePopupsExceptModals imgui.lua:18987 - [x] 62% ImGui::ClosePopupToLevel imgui.lua:15425 - [x] 81% ImGui::CloseCurrentPopup imgui.lua:15461 - [x] 81% ImGui::BeginPopupEx imgui.lua:15501 - [x] 80% ImGui::BeginPopupMenuEx imgui.lua:15524 - [x] 83% ImGui::BeginPopup imgui.lua:15550 - [x] 83% ImGui::BeginPopupModal imgui.lua:19005 - [x] 95% ImGui::EndPopup imgui.lua:15563 - [x] 38% ImGui::GetMouseButtonFromPopupFlags imgui.lua:15784 - [x] 94% ImGui::IsPopupOpenRequestForItem imgui.lua:15796 - [x] 85% ImGui::IsPopupOpenRequestForWindow imgui.lua:19035 - [x] 83% ImGui::OpenPopupOnItemClick imgui.lua:15813 - [x] 83% ImGui::BeginPopupContextItem imgui.lua:15847 - [x] 85% ImGui::BeginPopupContextWindow imgui.lua:19049 - [x] 88% ImGui::BeginPopupContextVoid imgui.lua:19059 - [x] 87% ImGui::FindBestWindowPosForPopupEx imgui.lua:15600 - [x] 87% ImGui::GetPopupAllowedExtentRect imgui.lua:15693 - [x] 92% ImGui::FindBestWindowPosForPopup imgui.lua:15716 + [x] 73% ImGui::IsPopupOpen imgui.lua:11532 + [x] 82% ImGui::GetTopMostPopupModal imgui.lua:11567 + [x] 81% ImGui::GetTopMostAndVisiblePopupModal imgui.lua:18927 + [x] 79% ImGui::FindBlockingModal imgui.lua:15256 + [x] 26% ImGui::OpenPopup imgui.lua:15289 + [x] 86% ImGui::OpenPopupEx imgui.lua:15310 + [x] 73% ImGui::ClosePopupsOverWindow imgui.lua:15373 + [x] 80% ImGui::ClosePopupsExceptModals imgui.lua:18993 + [x] 62% ImGui::ClosePopupToLevel imgui.lua:15431 + [x] 81% ImGui::CloseCurrentPopup imgui.lua:15467 + [x] 81% ImGui::BeginPopupEx imgui.lua:15507 + [x] 80% ImGui::BeginPopupMenuEx imgui.lua:15530 + [x] 83% ImGui::BeginPopup imgui.lua:15556 + [x] 83% ImGui::BeginPopupModal imgui.lua:19011 + [x] 95% ImGui::EndPopup imgui.lua:15569 + [x] 38% ImGui::GetMouseButtonFromPopupFlags imgui.lua:15790 + [x] 94% ImGui::IsPopupOpenRequestForItem imgui.lua:15802 + [x] 85% ImGui::IsPopupOpenRequestForWindow imgui.lua:19041 + [x] 83% ImGui::OpenPopupOnItemClick imgui.lua:15819 + [x] 83% ImGui::BeginPopupContextItem imgui.lua:15853 + [x] 85% ImGui::BeginPopupContextWindow imgui.lua:19055 + [x] 88% ImGui::BeginPopupContextVoid imgui.lua:19065 + [x] 87% ImGui::FindBestWindowPosForPopupEx imgui.lua:15606 + [x] 87% ImGui::GetPopupAllowedExtentRect imgui.lua:15699 + [x] 92% ImGui::FindBestWindowPosForPopup imgui.lua:15722 -- WINDOW FOCUS - [x] 51% ImGui::SetWindowFocus imgui.lua:11002 - [x] 71% ImGui::SetNextWindowFocus imgui.lua:11386 - [x] 87% ImGui::IsWindowFocused imgui.lua:14839 - [x] 94% ImGui::FindWindowFocusIndex imgui.lua:7197 - [x] 81% ImGui::UpdateWindowInFocusOrderList imgui.lua:7232 - [x] 82% ImGui::BringWindowToFocusFront imgui.lua:7257 - [x] 56% ImGui::BringWindowToDisplayFront imgui.lua:7283 - [x] 54% ImGui::BringWindowToDisplayBack imgui.lua:18895 - [x] 35% ImGui::BringWindowToDisplayBehind imgui.lua:7304 - [x] 41% ImGui::FindWindowDisplayIndex imgui.lua:18889 - [x] 87% ImGui::FocusWindow imgui.lua:7118 - [x] 84% ImGui::FocusTopMostWindowUnderOne imgui.lua:7316 + [x] 51% ImGui::SetWindowFocus imgui.lua:11008 + [x] 71% ImGui::SetNextWindowFocus imgui.lua:11392 + [x] 87% ImGui::IsWindowFocused imgui.lua:14845 + [x] 94% ImGui::FindWindowFocusIndex imgui.lua:7203 + [x] 81% ImGui::UpdateWindowInFocusOrderList imgui.lua:7238 + [x] 82% ImGui::BringWindowToFocusFront imgui.lua:7263 + [x] 56% ImGui::BringWindowToDisplayFront imgui.lua:7289 + [x] 54% ImGui::BringWindowToDisplayBack imgui.lua:18901 + [x] 35% ImGui::BringWindowToDisplayBehind imgui.lua:7310 + [x] 41% ImGui::FindWindowDisplayIndex imgui.lua:18895 + [x] 87% ImGui::FocusWindow imgui.lua:7124 + [x] 84% ImGui::FocusTopMostWindowUnderOne imgui.lua:7322 -- KEYBOARD/GAMEPAD NAVIGATION - [x] 93% ImGui::SetNavCursorVisible imgui.lua:19140 - [x] 94% ImGui::SetNavCursorVisibleAfterMove imgui.lua:15969 - [x] 80% ImGui::SetNavWindow imgui.lua:15985 - [x] 100% ImGui::NavHighlightActivated imgui.lua:16065 - [x] 100% ImGui::NavClearPreferredPosForAxis imgui.lua:15999 - [x] 95% ImGui::SetNavID imgui.lua:16008 - [x] 96% ImGui::SetFocusID imgui.lua:7356 - [x] 90% ImGetDirQuadrantFromDelta imgui.lua:17035 - [x] 100% NavScoreItemDistInterval imgui.lua:17042 - [x] 77% ImGui::NavScoreItem imgui.lua:17056 - [x] 93% ImGui::NavApplyItemToResult imgui.lua:17162 - [x] 100% ImGui::NavUpdateCurrentWindowIsScrollPushableX imgui.lua:17489 - [x] 94% ImGui::NavProcessItem imgui.lua:17254 - [x] 90% ImGui::NavProcessItemForTabbingRequest imgui.lua:17194 - [x] 100% ImGui::NavMoveRequestButNoResultYet imgui.lua:17030 - [x] 89% ImGui::NavMoveRequestSubmit imgui.lua:16508 - [x] 92% ImGui::NavMoveRequestResolveWithLastItem imgui.lua:17177 - [x] 92% ImGui::NavMoveRequestResolveWithPastTreeNode imgui.lua:17498 - [x] 93% ImGui::NavMoveRequestCancel imgui.lua:17509 - [x] 95% ImGui::NavMoveRequestForward imgui.lua:17521 - [x] 78% ImGui::NavMoveRequestTryWrapping imgui.lua:17536 - [x] 93% ImGui::NavSaveLastChildNavWindowIntoParent imgui.lua:16026 - [x] 57% ImGui::NavRestoreLastChildNavWindow imgui.lua:16039 - [x] 86% ImGui::NavRestoreLayer imgui.lua:16047 - [x] 100% ImGui::NavUpdateAnyRequestFlag imgui.lua:16071 - [x] 88% ImGui::NavInitWindow imgui.lua:16082 - [x] 97% ImGui::NavCalcPreferredRefPosSource imgui.lua:16114 - [x] 94% ImGui::NavCalcPreferredRefPos imgui.lua:16133 - [x] 91% ImGui::GetNavTweakPressedAmount imgui.lua:16175 - [x] 85% ImGui::NavUpdate imgui.lua:16777 - [x] 88% ImGui::NavInitRequestApplyResult imgui.lua:17328 - [x] 81% NavBiasScoringRect imgui.lua:16537 - [x] 83% ImGui::NavUpdateCreateMoveRequest imgui.lua:16638 - [x] 87% ImGui::NavUpdateCreateTabbingRequest imgui.lua:16748 - [x] 85% ImGui::NavMoveRequestApplyResult imgui.lua:17359 - [x] 91% ImGui::NavUpdateCancelRequest imgui.lua:16985 - [x] 83% ImGui::NavUpdateContextMenuRequest imgui.lua:16473 - [x] 90% ImGui::NavUpdatePageUpPageDown imgui.lua:16569 - [x] 81% ImGui::NavEndFrame imgui.lua:19275 - [x] 83% ImGui::NavUpdateCreateWrappingRequest imgui.lua:19219 - [x] 85% ImGui::IsWindowNavFocusable imgui.lua:7211 - [x] 67% FindWindowNavFocusable imgui.lua:7219 - [x] 86% NavUpdateWindowingTarget imgui.lua:16203 - [x] 92% ImGui::NavUpdateWindowingApplyFocus imgui.lua:16226 - [x] 88% ImGui::NavUpdateWindowing imgui.lua:16264 - [x] 67% GetFallbackWindowNameForWindowingList imgui.lua:19176 - [x] 84% ImGui::NavUpdateWindowingOverlay imgui.lua:19190 + [x] 93% ImGui::SetNavCursorVisible imgui.lua:19146 + [x] 94% ImGui::SetNavCursorVisibleAfterMove imgui.lua:15975 + [x] 80% ImGui::SetNavWindow imgui.lua:15991 + [x] 100% ImGui::NavHighlightActivated imgui.lua:16071 + [x] 100% ImGui::NavClearPreferredPosForAxis imgui.lua:16005 + [x] 95% ImGui::SetNavID imgui.lua:16014 + [x] 96% ImGui::SetFocusID imgui.lua:7362 + [x] 90% ImGetDirQuadrantFromDelta imgui.lua:17041 + [x] 100% NavScoreItemDistInterval imgui.lua:17048 + [x] 77% ImGui::NavScoreItem imgui.lua:17062 + [x] 93% ImGui::NavApplyItemToResult imgui.lua:17168 + [x] 100% ImGui::NavUpdateCurrentWindowIsScrollPushableX imgui.lua:17495 + [x] 94% ImGui::NavProcessItem imgui.lua:17260 + [x] 90% ImGui::NavProcessItemForTabbingRequest imgui.lua:17200 + [x] 100% ImGui::NavMoveRequestButNoResultYet imgui.lua:17036 + [x] 89% ImGui::NavMoveRequestSubmit imgui.lua:16514 + [x] 92% ImGui::NavMoveRequestResolveWithLastItem imgui.lua:17183 + [x] 92% ImGui::NavMoveRequestResolveWithPastTreeNode imgui.lua:17504 + [x] 93% ImGui::NavMoveRequestCancel imgui.lua:17515 + [x] 95% ImGui::NavMoveRequestForward imgui.lua:17527 + [x] 78% ImGui::NavMoveRequestTryWrapping imgui.lua:17542 + [x] 93% ImGui::NavSaveLastChildNavWindowIntoParent imgui.lua:16032 + [x] 57% ImGui::NavRestoreLastChildNavWindow imgui.lua:16045 + [x] 86% ImGui::NavRestoreLayer imgui.lua:16053 + [x] 100% ImGui::NavUpdateAnyRequestFlag imgui.lua:16077 + [x] 88% ImGui::NavInitWindow imgui.lua:16088 + [x] 97% ImGui::NavCalcPreferredRefPosSource imgui.lua:16120 + [x] 94% ImGui::NavCalcPreferredRefPos imgui.lua:16139 + [x] 91% ImGui::GetNavTweakPressedAmount imgui.lua:16181 + [x] 85% ImGui::NavUpdate imgui.lua:16783 + [x] 88% ImGui::NavInitRequestApplyResult imgui.lua:17334 + [x] 81% NavBiasScoringRect imgui.lua:16543 + [x] 83% ImGui::NavUpdateCreateMoveRequest imgui.lua:16644 + [x] 87% ImGui::NavUpdateCreateTabbingRequest imgui.lua:16754 + [x] 85% ImGui::NavMoveRequestApplyResult imgui.lua:17365 + [x] 91% ImGui::NavUpdateCancelRequest imgui.lua:16991 + [x] 83% ImGui::NavUpdateContextMenuRequest imgui.lua:16479 + [x] 90% ImGui::NavUpdatePageUpPageDown imgui.lua:16575 + [x] 81% ImGui::NavEndFrame imgui.lua:19281 + [x] 83% ImGui::NavUpdateCreateWrappingRequest imgui.lua:19225 + [x] 85% ImGui::IsWindowNavFocusable imgui.lua:7217 + [x] 67% FindWindowNavFocusable imgui.lua:7225 + [x] 86% NavUpdateWindowingTarget imgui.lua:16209 + [x] 92% ImGui::NavUpdateWindowingApplyFocus imgui.lua:16232 + [x] 88% ImGui::NavUpdateWindowing imgui.lua:16270 + [x] 67% GetFallbackWindowNameForWindowingList imgui.lua:19182 + [x] 84% ImGui::NavUpdateWindowingOverlay imgui.lua:19196 -- DRAG AND DROP [x] 55% ImGui::IsDragDropActive imgui.lua:525 [x] 73% ImGui::ClearDragDrop imgui.lua:529 - [x] 82% ImGui::BeginTooltipHidden imgui.lua:19072 + [x] 82% ImGui::BeginTooltipHidden imgui.lua:19078 [x] 88% ImGui::BeginDragDropSource imgui.lua:547 [x] 86% ImGui::EndDragDropSource imgui.lua:648 [x] 62% ImGui::SetDragDropPayload imgui.lua:665 @@ -697,38 +697,38 @@ imgui.cpp [x] 78% WindowSettingsHandler_WriteAll imgui.lua:6001 -- LOCALIZATION - [x] 84% ImGui::LocalizeRegisterEntries imgui.lua:17562 + [x] 84% ImGui::LocalizeRegisterEntries imgui.lua:17568 -- VIEWPORTS, PLATFORM WINDOWS - [x] 83% ImGuiViewport::GetDebugName imgui.lua:17596 - [x] 76% ImGuiPlatformIO::ClearPlatformHandlers imgui.lua:17601 - [x] 69% ImGuiPlatformIO::ClearRendererHandlers imgui.lua:17615 - [x] 78% ImGui::GetMainViewport imgui.lua:17624 - [x] 88% ImGui::FindViewportByID imgui.lua:17633 + [x] 83% ImGuiViewport::GetDebugName imgui.lua:17602 + [x] 76% ImGuiPlatformIO::ClearPlatformHandlers imgui.lua:17607 + [x] 69% ImGuiPlatformIO::ClearRendererHandlers imgui.lua:17621 + [x] 78% ImGui::GetMainViewport imgui.lua:17630 + [x] 88% ImGui::FindViewportByID imgui.lua:17639 [ ] ImGui::FindViewportByPlatformHandle - [x] 98% ImGui::SetCurrentViewport imgui.lua:17645 - [x] 99% ImGui::SetWindowViewport imgui.lua:17673 - [x] 86% ImGui::GetWindowAlwaysWantOwnViewport imgui.lua:17686 - [x] 86% IsViewportAbove imgui.lua:17708 - [x] 89% ImGui::UpdateTryMergeWindowIntoHostViewport imgui.lua:17733 - [x] 83% ImGui::UpdateTryMergeWindowIntoHostViewports imgui.lua:17793 - [x] 88% ImGui::TranslateWindowsInViewport imgui.lua:17805 - [x] 94% ImGui::ScaleWindowsInViewport imgui.lua:14879 - [x] 85% ImGui::FindHoveredViewportFromPlatformWindowStack imgui.lua:17831 - [x] 87% ImGui::UpdateViewportsNewFrame imgui.lua:17848 - [x] 78% ImGui::UpdateViewportsEndFrame imgui.lua:18135 - [x] 81% ImGui::AddUpdateViewport imgui.lua:18169 - [x] 80% ImGui::DestroyViewport imgui.lua:18249 - [x] 93% ImGui::WindowSelectViewport imgui.lua:18275 - [x] 73% ImGui::WindowSyncOwnedViewport imgui.lua:18401 - [x] 88% ImGui::UpdatePlatformWindows imgui.lua:18505 - [x] 85% ImGui::RenderPlatformWindowsDefault imgui.lua:18623 - [x] 87% ImGui::FindPlatformMonitorForPos imgui.lua:18655 - [x] 78% ImGui::FindPlatformMonitorForRect imgui.lua:18671 - [x] 93% ImGui::UpdateViewportPlatformMonitor imgui.lua:18712 - [x] 89% ImGui::GetViewportPlatformMonitor imgui.lua:18719 - [x] 97% ImGui::DestroyPlatformWindow imgui.lua:18731 - [x] 77% ImGui::DestroyPlatformWindows imgui.lua:18757 + [x] 98% ImGui::SetCurrentViewport imgui.lua:17651 + [x] 99% ImGui::SetWindowViewport imgui.lua:17679 + [x] 86% ImGui::GetWindowAlwaysWantOwnViewport imgui.lua:17692 + [x] 86% IsViewportAbove imgui.lua:17714 + [x] 89% ImGui::UpdateTryMergeWindowIntoHostViewport imgui.lua:17739 + [x] 83% ImGui::UpdateTryMergeWindowIntoHostViewports imgui.lua:17799 + [x] 88% ImGui::TranslateWindowsInViewport imgui.lua:17811 + [x] 94% ImGui::ScaleWindowsInViewport imgui.lua:14885 + [x] 85% ImGui::FindHoveredViewportFromPlatformWindowStack imgui.lua:17837 + [x] 87% ImGui::UpdateViewportsNewFrame imgui.lua:17854 + [x] 78% ImGui::UpdateViewportsEndFrame imgui.lua:18141 + [x] 81% ImGui::AddUpdateViewport imgui.lua:18175 + [x] 80% ImGui::DestroyViewport imgui.lua:18255 + [x] 93% ImGui::WindowSelectViewport imgui.lua:18281 + [x] 73% ImGui::WindowSyncOwnedViewport imgui.lua:18407 + [x] 88% ImGui::UpdatePlatformWindows imgui.lua:18511 + [x] 85% ImGui::RenderPlatformWindowsDefault imgui.lua:18629 + [x] 87% ImGui::FindPlatformMonitorForPos imgui.lua:18661 + [x] 78% ImGui::FindPlatformMonitorForRect imgui.lua:18677 + [x] 93% ImGui::UpdateViewportPlatformMonitor imgui.lua:18718 + [x] 89% ImGui::GetViewportPlatformMonitor imgui.lua:18725 + [x] 97% ImGui::DestroyPlatformWindow imgui.lua:18737 + [x] 77% ImGui::DestroyPlatformWindows imgui.lua:18763 -- DOCKING [x] 61% ImGuiDockRequest::ImGuiDockRequest imgui.lua:1019 @@ -845,47 +845,47 @@ imgui.cpp [ ] InitializeDefaultPlatformHandlers -- METRICS/DEBUGGER WINDOW - [x] 97% MetricsHelpMarker imgui.lua:20039 = MetricsHelpMarker - [x] 93% ImGui::DebugRenderViewportThumbnail imgui.lua:18780 - [x] 92% RenderViewportsThumbnails imgui.lua:18819 + [x] 97% MetricsHelpMarker imgui.lua:20045 = MetricsHelpMarker + [x] 93% ImGui::DebugRenderViewportThumbnail imgui.lua:18786 + [x] 92% RenderViewportsThumbnails imgui.lua:18825 [ ] ViewportComparerByLastFocusedStampCount [ ] ImGui::DebugRenderKeyboardPreview - [x] 52% ImGui::DebugTextEncoding imgui.lua:20941 + [x] 52% ImGui::DebugTextEncoding imgui.lua:20947 [ ] DebugFlashStyleColorStop [ ] ImGui::DebugFlashStyleColor [ ] ImGui::UpdateDebugToolFlashStyleColor [ ] ImGui::DebugTextureIDToU64 [ ] FormatTextureRefForDebugDisplay - [x] 52% ImGui::ShowFontAtlas imgui.lua:20240 - [x] 84% ImGui::DebugNodeTexture imgui.lua:20207 - [x] 42% ImGui::ShowMetricsWindow imgui.lua:21006 + [x] 52% ImGui::ShowFontAtlas imgui.lua:20246 + [x] 84% ImGui::DebugNodeTexture imgui.lua:20213 + [x] 42% ImGui::ShowMetricsWindow imgui.lua:21012 [ ] ImGui::DebugBreakClearData [ ] ImGui::DebugBreakButtonTooltip [ ] ImGui::DebugBreakButton - [x] 87% ImGui::DebugNodeColumns imgui.lua:20585 - [x] 48% DebugNodeDockNodeFlags imgui.lua:20773 - [x] 79% ImGui::DebugNodeDockNode imgui.lua:20790 - [x] 28% ImGui::DebugNodeDrawList imgui.lua:20607 + [x] 87% ImGui::DebugNodeColumns imgui.lua:20591 + [x] 48% DebugNodeDockNodeFlags imgui.lua:20779 + [x] 79% ImGui::DebugNodeDockNode imgui.lua:20796 + [x] 28% ImGui::DebugNodeDrawList imgui.lua:20613 [ ] ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox [ ] CalcFontGlyphSrcOverlapMask - [x] 60% ImGui::DebugNodeFont imgui.lua:20130 - [x] 59% ImGui::DebugNodeFontGlyphsForSrcMask imgui.lua:20075 - [x] 89% ImGui::DebugNodeFontGlyph imgui.lua:20061 - [x] 37% ImGui::DebugNodeStorage imgui.lua:20595 - [x] 68% ImGui::DebugNodeTabBar imgui.lua:20668 - [x] 62% ImGui::DebugNodeViewport imgui.lua:20923 + [x] 60% ImGui::DebugNodeFont imgui.lua:20136 + [x] 59% ImGui::DebugNodeFontGlyphsForSrcMask imgui.lua:20081 + [x] 89% ImGui::DebugNodeFontGlyph imgui.lua:20067 + [x] 37% ImGui::DebugNodeStorage imgui.lua:20601 + [x] 68% ImGui::DebugNodeTabBar imgui.lua:20674 + [x] 62% ImGui::DebugNodeViewport imgui.lua:20929 [ ] ImGui::DebugNodePlatformMonitor - [x] 70% ImGui::DebugNodeWindow imgui.lua:20834 - [x] 87% ImGui::DebugNodeWindowSettings imgui.lua:20892 - [x] 73% ImGui::DebugNodeWindowsList imgui.lua:20898 - [x] 67% ImGui::DebugNodeWindowsListByBeginStackParent imgui.lua:20909 + [x] 70% ImGui::DebugNodeWindow imgui.lua:20840 + [x] 87% ImGui::DebugNodeWindowSettings imgui.lua:20898 + [x] 73% ImGui::DebugNodeWindowsList imgui.lua:20904 + [x] 67% ImGui::DebugNodeWindowsListByBeginStackParent imgui.lua:20915 -- DEBUG LOG WINDOW - [x] 5% ImGui::DebugLog imgui.lua:19880 + [x] 5% ImGui::DebugLog imgui.lua:19886 [ ] ImGui::DebugLogV - [x] 93% SameLineOrWrap imgui.lua:20312 - [x] 61% ShowDebugLogFlag imgui.lua:20319 - [x] 65% ImGui::ShowDebugLogWindow imgui.lua:20332 + [x] 93% SameLineOrWrap imgui.lua:20318 + [x] 61% ShowDebugLogFlag imgui.lua:20325 + [x] 65% ImGui::ShowDebugLogWindow imgui.lua:20338 [ ] ImGui::DebugTextUnformattedWithLocateItem -- OTHER DEBUG TOOLS (ITEM PICKER, ID STACK TOOL) @@ -897,63 +897,63 @@ imgui.cpp [ ] ImGui::DebugLocateItemResolveWithLastItem [ ] ImGui::DebugStartItemPicker [ ] ImGui::UpdateDebugToolItemPicker - [x] 75% DebugItemPathQuery_UpdateAndGetHookId imgui.lua:20403 - [x] 49% ImGui::UpdateDebugToolItemPathQuery imgui.lua:20432 - [x] 47% ImGui::DebugHookIdInfo imgui.lua:20444 + [x] 75% DebugItemPathQuery_UpdateAndGetHookId imgui.lua:20409 + [x] 49% ImGui::UpdateDebugToolItemPathQuery imgui.lua:20438 + [x] 47% ImGui::DebugHookIdInfo imgui.lua:20450 [ ] DebugItemPathQuery_FormatLevelInfo [ ] DebugItemPathQuery_GetResultAsPath - [x] 51% ImGui::ShowIDStackToolWindow imgui.lua:20503 - [x] 78% ImGui::ShowFontSelector imgui.lua:20045 + [x] 51% ImGui::ShowIDStackToolWindow imgui.lua:20509 + [x] 78% ImGui::ShowFontSelector imgui.lua:20051 ==================================================================================================== imgui_widgets.cpp ==================================================================================================== -- Widgets: Text, etc. - [x] 69% ImGui::TextEx imgui_widgets.lua:79 - [x] 100% ImGui::TextUnformatted imgui_widgets.lua:200 - [x] 29% ImGui::Text imgui_widgets.lua:221 - [x] 60% ImGui::TextV imgui_widgets.lua:207 - [x] 30% ImGui::TextColored imgui_widgets.lua:232 + [x] 69% ImGui::TextEx imgui_widgets.lua:80 + [x] 100% ImGui::TextUnformatted imgui_widgets.lua:201 + [x] 29% ImGui::Text imgui_widgets.lua:222 + [x] 60% ImGui::TextV imgui_widgets.lua:208 + [x] 30% ImGui::TextColored imgui_widgets.lua:233 [x] 83% ImGui::TextColoredV imgui_widgets.lua:7423 = ImGui . TextColored(...) - [x] 17% ImGui::TextDisabled imgui_widgets.lua:240 + [x] 17% ImGui::TextDisabled imgui_widgets.lua:241 [x] 89% ImGui::TextDisabledV imgui_widgets.lua:7424 = ImGui . TextDisabled(...) - [x] 10% ImGui::TextWrapped imgui_widgets.lua:249 + [x] 10% ImGui::TextWrapped imgui_widgets.lua:250 [x] 91% ImGui::TextWrappedV imgui_widgets.lua:7425 = ImGui . TextWrapped(...) - [x] 1% ImGui::TextAligned imgui_widgets.lua:268 + [x] 2% ImGui::TextAligned imgui_widgets.lua:269 [x] 67% ImGui::TextAlignedV imgui_widgets.lua:7426 = ImGui . TextAligned(...) - [x] 4% ImGui::LabelText imgui_widgets.lua:304 + [x] 4% ImGui::LabelText imgui_widgets.lua:305 [x] 89% ImGui::LabelTextV imgui_widgets.lua:7427 = ImGui . LabelText(...) - [x] 2% ImGui::BulletText imgui_widgets.lua:339 + [x] 2% ImGui::BulletText imgui_widgets.lua:340 [x] 77% ImGui::BulletTextV imgui_widgets.lua:7428 = ImGui . BulletText(...) -- Widgets: Main - [x] 85% ImGui::ButtonBehavior imgui_widgets.lua:487 - [x] 64% ImGui::ButtonEx imgui_widgets.lua:744 - [x] 100% ImGui::Button imgui_widgets.lua:806 - [x] 99% ImGui::SmallButton imgui_widgets.lua:813 - [x] 72% ImGui::InvisibleButton imgui_widgets.lua:827 - [x] 87% ImGui::ArrowButtonEx imgui_widgets.lua:858 - [x] 97% ImGui::ArrowButton imgui_widgets.lua:890 - [x] 79% ImGui::CloseButton imgui_widgets.lua:899 + [x] 85% ImGui::ButtonBehavior imgui_widgets.lua:488 + [x] 64% ImGui::ButtonEx imgui_widgets.lua:745 + [x] 100% ImGui::Button imgui_widgets.lua:807 + [x] 99% ImGui::SmallButton imgui_widgets.lua:814 + [x] 71% ImGui::InvisibleButton imgui_widgets.lua:828 + [x] 87% ImGui::ArrowButtonEx imgui_widgets.lua:859 + [x] 97% ImGui::ArrowButton imgui_widgets.lua:891 + [x] 79% ImGui::CloseButton imgui_widgets.lua:900 [x] 90% ImGui::CollapseButton imgui.lua:4558 - [x] 52% ImGui::GetWindowScrollbarID imgui_widgets.lua:975 - [x] 90% ImGui::GetWindowScrollbarRect imgui_widgets.lua:988 - [x] 99% ImGui::ExtendHitBoxWhenNearViewportEdge imgui_widgets.lua:1011 - [x] 77% ImGui::Scrollbar imgui_widgets.lua:1188 - [x] 85% ImGui::ScrollbarEx imgui_widgets.lua:1039 - [x] 84% ImGui::ImageWithBg imgui_widgets.lua:1213 - [x] 28% ImGui::Image imgui_widgets.lua:1251 - [x] 92% ImGui::ImageButtonEx imgui_widgets.lua:1263 - [x] 98% ImGui::ImageButton imgui_widgets.lua:1307 - [x] 76% ImGui::Checkbox imgui_widgets.lua:1322 - [x] 79% ImGui::CheckboxFlagsT imgui_widgets.lua:1435 = ImGui . CheckboxFlags - [x] 7% ImGui::CheckboxFlags imgui_widgets.lua:1414 - [x] 5% ImGui::RadioButton imgui_widgets.lua:1509 - [x] 93% ImGui::ProgressBar imgui_widgets.lua:1521 - [x] 97% ImGui::Bullet imgui_widgets.lua:1584 - [x] 86% ImGui::TextLink imgui_widgets.lua:1611 - [x] 95% ImGui::TextLinkOpenURL imgui_widgets.lua:1666 + [x] 52% ImGui::GetWindowScrollbarID imgui_widgets.lua:976 + [x] 90% ImGui::GetWindowScrollbarRect imgui_widgets.lua:989 + [x] 99% ImGui::ExtendHitBoxWhenNearViewportEdge imgui_widgets.lua:1012 + [x] 77% ImGui::Scrollbar imgui_widgets.lua:1189 + [x] 85% ImGui::ScrollbarEx imgui_widgets.lua:1040 + [x] 84% ImGui::ImageWithBg imgui_widgets.lua:1214 + [x] 28% ImGui::Image imgui_widgets.lua:1252 + [x] 92% ImGui::ImageButtonEx imgui_widgets.lua:1264 + [x] 98% ImGui::ImageButton imgui_widgets.lua:1308 + [x] 76% ImGui::Checkbox imgui_widgets.lua:1323 + [x] 79% ImGui::CheckboxFlagsT imgui_widgets.lua:1436 = ImGui . CheckboxFlags + [x] 7% ImGui::CheckboxFlags imgui_widgets.lua:1415 + [x] 5% ImGui::RadioButton imgui_widgets.lua:1510 + [x] 93% ImGui::ProgressBar imgui_widgets.lua:1522 + [x] 97% ImGui::Bullet imgui_widgets.lua:1585 + [x] 86% ImGui::TextLink imgui_widgets.lua:1612 + [x] 95% ImGui::TextLinkOpenURL imgui_widgets.lua:1667 -- Widgets: Low-level Layout helpers [x] 82% ImGui::Spacing imgui_widgets.lua:1702 @@ -1199,7 +1199,7 @@ imgui_widgets.cpp [x] 41% ImGui::PlotHistogram imgui_widgets.lua:8623 -- Widgets: Value helpers - [x] 21% ImGui::Value imgui_widgets.lua:383 + [x] 21% ImGui::Value imgui_widgets.lua:384 -- MenuItem, BeginMenu, EndMenu, etc. [x] 49% ImGuiMenuColumns::Update imgui_widgets.lua:8655 @@ -1291,8 +1291,8 @@ imgui_draw.cpp [x] 91% ImDrawList::_OnChangedVtxOffset imgui_draw.lua:3878 [x] 57% ImDrawList::_CalcCircleAutoSegmentCount imgui_draw.lua:4966 [x] 86% ImDrawList::PushClipRect imgui_draw.lua:4978 - [ ] ImDrawList::PushClipRectFullScreen - [x] 39% ImDrawList::PopClipRect imgui_draw.lua:5001 + [x] 60% ImDrawList::PushClipRectFullScreen imgui_draw.lua:5001 + [x] 39% ImDrawList::PopClipRect imgui_draw.lua:5006 [x] 67% ImDrawList::PushTexture imgui_draw.lua:4189 [x] 81% ImDrawList::PopTexture imgui_draw.lua:4198 [ ] ImDrawList::PushDrawFlag @@ -1310,17 +1310,17 @@ imgui_draw.cpp [ ] ImDrawList::_AddPolyline [x] 30% ImDrawList::AddConvexPolyFilled imgui_draw.lua:4100 [ ] CalcCornerArcStepAndCount - [x] 63% ImDrawList::_PathArcToFastEx imgui_draw.lua:5118 - [x] 63% ImDrawList::_PathArcToN imgui_draw.lua:5138 - [x] 10% ImDrawList::PathArcToFast imgui_draw.lua:5124 - [x] 43% ImDrawList::PathArcTo imgui_draw.lua:5164 - [x] 61% ImDrawList::PathEllipticalArcTo imgui_draw.lua:5753 - [x] 88% ImBezierCubicCalc imgui_draw.lua:5765 - [x] 89% ImBezierQuadraticCalc imgui_draw.lua:5771 - [x] 85% PathBezierCubicCurveToCasteljau imgui_draw.lua:5778 - [x] 90% PathBezierQuadraticCurveToCasteljau imgui_draw.lua:5796 - [x] 81% ImDrawList::PathBezierCubicCurveTo imgui_draw.lua:5810 - [x] 78% ImDrawList::PathBezierQuadraticCurveTo imgui_draw.lua:5820 + [x] 63% ImDrawList::_PathArcToFastEx imgui_draw.lua:5123 + [x] 63% ImDrawList::_PathArcToN imgui_draw.lua:5143 + [x] 10% ImDrawList::PathArcToFast imgui_draw.lua:5129 + [x] 43% ImDrawList::PathArcTo imgui_draw.lua:5169 + [x] 61% ImDrawList::PathEllipticalArcTo imgui_draw.lua:5758 + [x] 88% ImBezierCubicCalc imgui_draw.lua:5770 + [x] 89% ImBezierQuadraticCalc imgui_draw.lua:5776 + [x] 85% PathBezierCubicCurveToCasteljau imgui_draw.lua:5783 + [x] 90% PathBezierQuadraticCurveToCasteljau imgui_draw.lua:5801 + [x] 81% ImDrawList::PathBezierCubicCurveTo imgui_draw.lua:5815 + [x] 78% ImDrawList::PathBezierQuadraticCurveTo imgui_draw.lua:5825 [x] 7% ImDrawList::PathRect imgui_draw.lua:4617 [ ] ImDrawList::_AddLine [x] 38% ImDrawList::AddLine imgui_draw.lua:4712 @@ -1339,12 +1339,12 @@ imgui_draw.cpp [ ] ApproxApothem [x] 19% ImDrawList::AddCircle imgui_draw.lua:4798 [x] 20% ImDrawList::AddCircleFilled imgui_draw.lua:4826 - [x] 34% ImDrawList::AddNgon imgui_draw.lua:5831 - [x] 65% ImDrawList::AddNgonFilled imgui_draw.lua:5841 - [x] 47% ImDrawList::AddEllipse imgui_draw.lua:5850 - [x] 53% ImDrawList::AddEllipseFilled imgui_draw.lua:5861 - [x] 83% ImDrawList::AddBezierCubic imgui_draw.lua:5872 - [x] 82% ImDrawList::AddBezierQuadratic imgui_draw.lua:5880 + [x] 34% ImDrawList::AddNgon imgui_draw.lua:5836 + [x] 65% ImDrawList::AddNgonFilled imgui_draw.lua:5846 + [x] 47% ImDrawList::AddEllipse imgui_draw.lua:5855 + [x] 53% ImDrawList::AddEllipseFilled imgui_draw.lua:5866 + [x] 83% ImDrawList::AddBezierCubic imgui_draw.lua:5877 + [x] 82% ImDrawList::AddBezierQuadratic imgui_draw.lua:5885 [x] 65% ImDrawList::AddText imgui_draw.lua:4861 [x] 69% ImDrawList::AddImage imgui_draw.lua:4904 [ ] ImDrawList::AddImageQuad @@ -1364,7 +1364,7 @@ imgui_draw.cpp [ ] ImTriangulator::FlipNodeList [ ] ImTriangulator::IsEar [ ] ImTriangulator::ReclassifyNode - [x] 17% ImDrawList::AddConcavePolyFilled imgui_draw.lua:5889 + [x] 17% ImDrawList::AddConcavePolyFilled imgui_draw.lua:5894 -- ImDrawListSplitter [x] 58% ImDrawListSplitter::ClearFreeMemory imgui_draw.lua:3913 @@ -1551,19 +1551,19 @@ imgui_draw.cpp [x] 49% ImFontCalcTextSizeEx imgui_draw.lua:3049 [x] 91% ImFont::CalcTextSizeA imgui_draw.lua:3210 [x] 85% ImFont::RenderChar imgui_draw.lua:3223 - [x] 66% ImFont::RenderText imgui_draw.lua:5222 + [x] 66% ImFont::RenderText imgui_draw.lua:5227 -- ImGui Internal Render Helpers - [x] 58% ImGui::RenderArrow imgui_draw.lua:5468 - [x] 88% ImGui::RenderBullet imgui_draw.lua:5500 - [x] 63% ImGui::RenderCheckMark imgui_draw.lua:5512 - [x] 90% ImGui::RenderArrowPointingAt imgui_draw.lua:5537 + [x] 58% ImGui::RenderArrow imgui_draw.lua:5473 + [x] 88% ImGui::RenderBullet imgui_draw.lua:5505 + [x] 63% ImGui::RenderCheckMark imgui_draw.lua:5517 + [x] 90% ImGui::RenderArrowPointingAt imgui_draw.lua:5542 [x] 93% ImGui::RenderArrowDockMenu imgui.lua:4551 - [x] 100% ImAcos01 imgui_draw.lua:5550 - [x] 95% ImGui::RenderRectFilledInRangeH imgui_draw.lua:5566 - [x] 75% ImGui::RenderRectFilledWithHole imgui_draw.lua:5730 - [x] 76% ImGui::CalcRoundingFlagsForRectInRect imgui_draw.lua:5621 - [x] 68% ImGui::RenderColorRectWithAlphaCheckerboard imgui_draw.lua:5657 + [x] 100% ImAcos01 imgui_draw.lua:5555 + [x] 95% ImGui::RenderRectFilledInRangeH imgui_draw.lua:5571 + [x] 75% ImGui::RenderRectFilledWithHole imgui_draw.lua:5735 + [x] 76% ImGui::CalcRoundingFlagsForRectInRect imgui_draw.lua:5626 + [x] 68% ImGui::RenderColorRectWithAlphaCheckerboard imgui_draw.lua:5662 -- Decompression code [ ] stb_decompress_length @@ -1697,8 +1697,8 @@ imgui_tables.cpp -- Tables: Debugging [ ] DebugNodeTableGetSizingPolicyDesc - [x] 16% ImGui::DebugNodeTable imgui.lua:20726 - [x] 69% ImGui::DebugNodeTableSettings imgui.lua:20708 + [x] 16% ImGui::DebugNodeTable imgui.lua:20732 + [x] 69% ImGui::DebugNodeTableSettings imgui.lua:20714 -- Columns, BeginColumns, EndColumns, etc. [x] 24% ImGui::SetWindowClipRectBeforeSetChannel imgui_tables.lua:2070 @@ -1727,81 +1727,81 @@ imgui_demo.cpp ==================================================================================================== -- Helpers - [x] 97% HelpMarker imgui_demo.lua:125 - [x] 85% ShowDockingDisabledMessage imgui_demo.lua:135 + [x] 97% HelpMarker imgui_demo.lua:196 + [x] 85% ShowDockingDisabledMessage imgui_demo.lua:206 -- Demo Window / ShowDemoWindow() [-] ImGuiDemoWindowData::~ImGuiDemoWindowData c++-only - [x] 47% ImGui::ShowDemoWindow imgui_demo.lua:795 + [x] 23% ImGui::ShowDemoWindow imgui_demo.lua:287 -- DemoWindowMenuBar() - [x] 54% DemoWindowMenuBar imgui_demo.lua:500 + [x] 60% DemoWindowMenuBar imgui_demo.lua:652 -- Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) - [x] 52% ExampleTree_CreateNode imgui_demo.lua:335 - [x] 0% ExampleTree_DestroyNode imgui_demo.lua:347 - [x] 69% ExampleTree_CreateDemoTree imgui_demo.lua:352 + [x] 52% ExampleTree_CreateNode imgui_demo.lua:760 + [x] 67% ExampleTree_DestroyNode imgui_demo.lua:772 + [x] 65% ExampleTree_CreateDemoTree imgui_demo.lua:786 -- Helpers: ExampleImageViewer - [x] 89% ExampleImageViewer_DrawOptions imgui_demo.lua:399 - [x] 91% ExampleImageViewer_DrawCanvas imgui_demo.lua:412 + [x] 89% ExampleImageViewer_DrawOptions imgui_demo.lua:839 + [x] 93% ExampleImageViewer_DrawCanvas imgui_demo.lua:852 -- DemoWindowWidgetsBasic() - [x] 70% DemoWindowWidgetsBasic imgui_demo.lua:6010 + [x] 77% DemoWindowWidgetsBasic imgui_demo.lua:935 -- DemoWindowWidgetsBullets() - [x] 89% DemoWindowWidgetsBullets imgui_demo.lua:6113 + [x] 97% DemoWindowWidgetsBullets imgui_demo.lua:1135 -- DemoWindowWidgetsCollapsingHeaders() - [x] 68% DemoWindowWidgetsCollapsingHeaders imgui_demo.lua:6127 + [x] 68% DemoWindowWidgetsCollapsingHeaders imgui_demo.lua:1158 -- DemoWindowWidgetsColorAndPickers() - [x] 63% DemoWindowWidgetsColorAndPickers imgui_demo.lua:6158 + [x] 73% DemoWindowWidgetsColorAndPickers imgui_demo.lua:1210 -- DemoWindowWidgetsComboBoxes() - [x] 57% DemoWindowWidgetsComboBoxes imgui_demo.lua:6306 + [x] 70% DemoWindowWidgetsComboBoxes imgui_demo.lua:1415 -- DemoWindowWidgetsDataTypes() - [x] 27% DemoWindowWidgetsDataTypes imgui_demo.lua:6389 + [x] 65% DemoWindowWidgetsDataTypes imgui_demo.lua:1536 -- DemoWindowWidgetsDisableBlocks() - [x] 76% DemoWindowWidgetsDisableBlocks imgui_demo.lua:6476 + [x] 84% DemoWindowWidgetsDisableBlocks imgui_demo.lua:1652 -- DemoWindowWidgetsDragAndDrop() - [x] 73% DemoWindowWidgetsDragAndDrop imgui_demo.lua:6490 + [x] 76% DemoWindowWidgetsDragAndDrop imgui_demo.lua:1679 -- DemoWindowWidgetsDragsAndSliders() - [x] 54% DemoWindowWidgetsDragsAndSliders imgui_demo.lua:6593 + [x] 79% DemoWindowWidgetsDragsAndSliders imgui_demo.lua:1821 -- DemoWindowWidgetsFonts() - [x] 39% DemoWindowWidgetsFonts imgui_demo.lua:6638 + [x] 94% DemoWindowWidgetsFonts imgui_demo.lua:1871 -- DemoWindowWidgetsImages() - [x] 67% DemoWindowWidgetsImages imgui_demo.lua:6650 + [x] 89% DemoWindowWidgetsImages imgui_demo.lua:1889 -- DemoWindowWidgetsListBoxes() - [x] 79% DemoWindowWidgetsListBoxes imgui_demo.lua:6713 + [x] 82% DemoWindowWidgetsListBoxes imgui_demo.lua:1974 -- DemoWindowWidgetsLiveEdit() - [x] 72% DemoWindowWidgetsLiveEdit imgui_demo.lua:6759 + [x] 81% DemoWindowWidgetsLiveEdit imgui_demo.lua:2044 -- DemoWindowWidgetsMixedValues() - [x] 60% DemoWindowWidgetsMixedValues imgui_demo.lua:6786 + [x] 66% DemoWindowWidgetsMixedValues imgui_demo.lua:2083 -- DemoWindowWidgetsMultiComponents() - [x] 44% DemoWindowWidgetsMultiComponents imgui_demo.lua:6832 + [x] 86% DemoWindowWidgetsMultiComponents imgui_demo.lua:2151 -- DemoWindowWidgetsPlotting() - [x] 66% DemoWindowWidgetsPlotting imgui_demo.lua:6864 + [x] 70% DemoWindowWidgetsPlotting imgui_demo.lua:2217 -- DemoWindowWidgetsProgressBars() - [x] 60% DemoWindowWidgetsProgressBars imgui_demo.lua:6916 + [x] 78% DemoWindowWidgetsProgressBars imgui_demo.lua:2287 -- DemoWindowWidgetsQueryingStatuses() - [x] 59% DemoWindowWidgetsQueryingStatuses imgui_demo.lua:6956 + [x] 74% DemoWindowWidgetsQueryingStatuses imgui_demo.lua:2338 -- DemoWindowWidgetsSelectables() - [x] 53% DemoWindowWidgetsSelectables imgui_demo.lua:7108 + [x] 66% DemoWindowWidgetsSelectables imgui_demo.lua:2588 -- DemoWindowWidgetsSelectionAndMultiSelect() [ ] ExampleSelectionWithDeletion::ApplyDeletionPreLoop @@ -1812,48 +1812,48 @@ imgui_demo.cpp [ ] ExampleDualListBox::CompareItemsByValue [ ] ExampleDualListBox::SortItems [ ] ExampleDualListBox::Show - [ ] DemoWindowWidgetsSelectionAndMultiSelect + [x] 1% DemoWindowWidgetsSelectionAndMultiSelect imgui_demo.lua:2758 -- DemoWindowWidgetsTabs() - [x] 16% EditTabBarFittingPolicyFlags imgui_demo.lua:7238 - [x] 54% DemoWindowWidgetsTabs imgui_demo.lua:7252 + [x] 58% EditTabBarFittingPolicyFlags imgui_demo.lua:2772 + [x] 70% DemoWindowWidgetsTabs imgui_demo.lua:2802 -- DemoWindowWidgetsText() - [x] 87% DemoWindowWidgetsText imgui_demo.lua:7367 + [x] 89% DemoWindowWidgetsText imgui_demo.lua:2958 -- DemoWindowWidgetsTextFilter() - [x] 72% DemoWindowWidgetsTextFilter imgui_demo.lua:7457 + [x] 84% DemoWindowWidgetsTextFilter imgui_demo.lua:3072 -- DemoWindowWidgetsTextInput() - [x] 40% DemoWindowWidgetsTextInput imgui_demo.lua:7491 + [x] 75% DemoWindowWidgetsTextInput imgui_demo.lua:3147 -- DemoWindowWidgetsTooltips() - [x] 80% DemoWindowWidgetsTooltips imgui_demo.lua:7610 + [x] 84% DemoWindowWidgetsTooltips imgui_demo.lua:3331 -- DemoWindowWidgetsTreeNodes() - [x] 54% DemoWindowWidgetsTreeNodes imgui_demo.lua:7686 + [x] 75% DemoWindowWidgetsTreeNodes imgui_demo.lua:3438 -- DemoWindowWidgetsVerticalSliders() - [x] 82% DemoWindowWidgetsVerticalSliders imgui_demo.lua:7830 + [x] 83% DemoWindowWidgetsVerticalSliders imgui_demo.lua:3619 -- DemoWindowWidgets() - [x] 19% DemoWindowWidgets imgui_demo.lua:960 + [x] 97% DemoWindowWidgets imgui_demo.lua:3687 -- DemoWindowLayout() - [x] 71% DemoWindowLayout imgui_demo.lua:1982 + [x] 81% DemoWindowLayout imgui_demo.lua:3794 -- DemoWindowPopups() - [x] 55% DemoWindowPopups imgui_demo.lua:2252 + [x] 59% DemoWindowPopups imgui_demo.lua:4638 [ ] MyItem::SortWithSortSpecs [ ] MyItem::CompareWithSortSpecs - [x] 96% PushStyleCompact imgui_demo.lua:2357 - [x] 100% PopStyleCompact imgui_demo.lua:2363 - [x] 69% EditTableSizingFlags imgui_demo.lua:2369 - [x] 50% EditTableColumnsFlags imgui_demo.lua:2411 - [x] 100% ShowTableColumnsStatusFlags imgui_demo.lua:2438 + [x] 96% PushStyleCompact imgui_demo.lua:5000 + [x] 100% PopStyleCompact imgui_demo.lua:5006 + [x] 69% EditTableSizingFlags imgui_demo.lua:5013 + [x] 74% EditTableColumnsFlags imgui_demo.lua:5065 + [x] 100% ShowTableColumnsStatusFlags imgui_demo.lua:5095 -- DemoWindowTables() - [x] 6% DemoWindowTables imgui_demo.lua:4302 + [x] 41% DemoWindowTables imgui_demo.lua:5241 ==================================================================================================== imgui.h @@ -1923,8 +1923,8 @@ imgui.h -- Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) [ ] ImGuiOnceUponAFrame::ImGuiOnceUponAFrame [-] ImGuiOnceUponAFrame::operatorbool c++-only - [x] 80% ImGuiTextFilter::Clear imgui.lua:19328 - [x] 100% ImGuiTextFilter::IsActive imgui.lua:19329 + [x] 80% ImGuiTextFilter::Clear imgui.lua:19334 + [x] 100% ImGuiTextFilter::IsActive imgui.lua:19335 [-] ImGuiTextFilter::Draw obsolete [x] 0% ImGuiTextBuffer::ImGuiTextBuffer imgui_h.lua:2648 [ ] ImGuiTextBuffer::begin @@ -1937,7 +1937,7 @@ imgui.h [x] 31% ImGuiTextBuffer::c_str imgui_h.lua:2653 [ ] ImGuiStoragePair::ImGuiStoragePair [ ] ImGuiStorage::Clear - [x] 100% ImGuiListClipper::IncludeItemByIndex imgui.lua:19559 + [x] 100% ImGuiListClipper::IncludeItemByIndex imgui.lua:19565 [-] operator+ c++-only [-] operator- c++-only [-] operator* c++-only @@ -1948,7 +1948,7 @@ imgui.h [-] operator/= c++-only [-] operator== c++-only [-] operator!= c++-only - [ ] IM_MSVC_RUNTIME_CHECKS_RESTORE::ImColor + [x] n/a IM_MSVC_RUNTIME_CHECKS_RESTORE::ImColor imgui_h.lua:2664 = setmetatable ( { } , { [-] IM_MSVC_RUNTIME_CHECKS_RESTORE::operatorImU32 c++-only [-] IM_MSVC_RUNTIME_CHECKS_RESTORE::operatorImVec4 c++-only [ ] IM_MSVC_RUNTIME_CHECKS_RESTORE::SetHSV @@ -1969,7 +1969,7 @@ imgui.h [x] 16% ImDrawList::PathLineTo imgui_internal.lua:1001 [x] 48% ImDrawList::PathLineToMergeDuplicate imgui_internal.lua:1011 [x] 88% ImDrawList::PathFillConvex imgui_internal.lua:1019 - [x] 94% ImDrawList::PathFillConcave imgui_draw.lua:5930 + [x] 94% ImDrawList::PathFillConcave imgui_draw.lua:5935 [x] 67% ImDrawList::PathStroke imgui_internal.lua:1027 [x] 89% ImDrawList::ChannelsSplit imgui_draw.lua:4089 [x] 80% ImDrawList::ChannelsMerge imgui_draw.lua:4090 @@ -2196,7 +2196,7 @@ imgui_internal.h [x] 20% ImGuiNextItemData::ImGuiNextItemData imgui_internal.lua:1327 [ ] ImGuiNextItemData::ClearFlags [x] 11% ImGuiLastItemData::ImGuiLastItemData imgui_internal.lua:1247 - [x] 8% ImGuiErrorRecoveryState::ImGuiErrorRecoveryState imgui.lua:19756 + [x] 8% ImGuiErrorRecoveryState::ImGuiErrorRecoveryState imgui.lua:19762 [ ] ImGuiPtrOrIndex::ImGuiPtrOrIndex -- Popup support @@ -2265,7 +2265,7 @@ imgui_internal.h -- Settings support [x] 18% ImGuiWindowSettings::ImGuiWindowSettings imgui_internal.lua:2409 [ ] ImGuiWindowSettings::GetName - [x] 13% ImGuiSettingsHandler::ImGuiSettingsHandler imgui_h.lua:2659 + [x] 13% ImGuiSettingsHandler::ImGuiSettingsHandler imgui_h.lua:2685 -- Metrics, Debug Tools [x] 7% ImGuiDebugAllocInfo::ImGuiDebugAllocInfo imgui_internal.lua:1790 @@ -2298,9 +2298,9 @@ imgui_internal.h [x] 86% TableGetInstanceID imgui_tables.lua:445 -- ImGui internal API - [x] 100% GetScale imgui.lua:13552 - [x] 100% GetCurrentWindowRead imgui.lua:13558 - [x] 100% GetCurrentWindow imgui.lua:13565 + [x] 100% GetScale imgui.lua:13558 + [x] 100% GetCurrentWindowRead imgui.lua:13564 + [x] 100% GetCurrentWindow imgui.lua:13571 [ ] SetWindowParentWindowForFocusRoute [x] 99% WindowRectAbsToRel imgui_internal.lua:641 [x] 99% WindowRectRelToAbs imgui_internal.lua:646 @@ -2308,7 +2308,7 @@ imgui_internal.h [ ] WindowPosRelToAbs [ ] GetPixelDensity [x] 55% GetRoundedFontSize imgui_internal.lua:635 - [x] 15% GetForegroundDrawList imgui.lua:13640 + [x] 15% GetForegroundDrawList imgui.lua:13646 [x] 80% LocalizeGetMsg imgui_internal.lua:3433 [ ] ScrollToBringRectIntoView [ ] GetItemStatusFlags @@ -2324,7 +2324,7 @@ imgui_internal.h [x] 60% IsAliasKey imgui_internal.lua:569 [x] 100% IsLRModKey imgui_internal.lua:574 [x] 76% ConvertSingleModFlagToKey imgui_internal.lua:586 - [x] 17% GetKeyData imgui.lua:8434 + [x] 17% GetKeyData imgui.lua:8440 [x] 97% MouseButtonToKey imgui_internal.lua:546 [x] 81% IsActiveIdUsingNavDir imgui_internal.lua:650 [x] 88% GetKeyOwnerData imgui_internal.lua:612 @@ -2506,7 +2506,7 @@ Enums (values ported / total; missing listed) ImTextureStatus 5 / 5 ImTriangulatorNodeType 0 / 3 missing: ImTriangulatorNodeType_Convex, ImTriangulatorNodeType_Ear, ImTriangulatorNodeType_Reflex ImWcharClass 3 / 3 - MyItemColumnID 0 / 5 missing: MyItemColumnID_ID, MyItemColumnID_Name, MyItemColumnID_Action, MyItemColumnID_Quantity, MyItemColumnID_Description + MyItemColumnID 5 / 5 ==================================================================================================== Struct fields (name found in the port / total; missing listed). Field names are matched globally, so common names may over-count. @@ -2562,7 +2562,7 @@ Struct fields (name found in the port / total; missing listed). Field names are ImGuiFocusScopeData 2 / 2 ImGuiGroupData 14 / 14 ImGuiIDStackTool 4 / 4 - ImGuiIO 96 / 117 missing: FontAllowUserScaling, ConfigNavSwapGamepadButtons, ConfigNavMoveSetMousePos, ConfigNavCaptureKeyboard, ConfigNavEscapeClearFocusItem, ConfigNavEscapeClearFocusWindow, ConfigDpiScaleFonts, ConfigDpiScaleViewports, ConfigInputTextCursorBlink, ConfigInputTextEnterKeepActive, ConfigDragClickToInputText, ConfigScrollbarScrollByPage, ConfigIniSettingsSaveLastUsedDate, ConfigIniSettingsAutoDiscardMonths, ConfigDebugIsDebuggerPresent, ConfigDebugBeginReturnValueOnce, ConfigDebugIgnoreFocusLoss, BackendPlatformName, BackendRendererName, BackendLanguageUserData, PenPressure + ImGuiIO 109 / 117 missing: FontAllowUserScaling, ConfigDpiScaleFonts, ConfigDpiScaleViewports, ConfigIniSettingsAutoDiscardMonths, BackendPlatformName, BackendRendererName, BackendLanguageUserData, PenPressure ImGuiInputEvent 10 / 11 missing: AddedByTestEngine ImGuiInputEventAppFocused 1 / 1 ImGuiInputEventKey 3 / 3 diff --git a/imgui_demo.lua b/imgui_demo.lua index 9feb05d..894bdf8 100644 --- a/imgui_demo.lua +++ b/imgui_demo.lua @@ -1,16 +1,13 @@ -- dear imgui demo (Luau port of imgui_demo.cpp). Optional: the library never calls into this file. - -do --[[ imgui_demo.lua ]] -- dear imgui, v1.93.0 WIP --- (demo code) Port of imgui_demo.cpp (docking branch) --- This file: shared demo helpers, ShowDemoWindow(), DemoWindowMenuBar(), DemoWindowWidgets() dispatcher, example tree/image viewer helpers. --- Other parts (all global functions, loaded from the same bundle): +-- (demo code) -- Help: -- - Read FAQ at http://dearimgui.com/faq --- - Call and read ImGui.ShowDemoWindow() in imgui_demo.lua. +-- - Call and read ImGui.ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. -- - Need help integrating Dear ImGui in your codebase? -- - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started +-- - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. -- Read top of imgui.cpp and imgui.h for many details, documentation, comments, links. -- Get the latest version at https://github.com/ocornut/imgui @@ -28,17 +25,20 @@ do --[[ imgui_demo.lua ]] -- Also include Metrics! ItemPicker! DebugLog! and other debug features. -- Removing this file from your project is hindering access to documentation for everyone in your team, -- likely leading you to poorer usage of the library. --- Whenever you have Dear ImGui available you probably want this to be available for reference. +-- Everything in this file will be stripped out by the linker if you don't call ImGui.ShowDemoWindow(). +-- If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be +-- linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. +-- [Port] There is no linker here: build the bundle with `tools/bundle.py --no-demo` to leave this file out. +-- In another situation, whenever you have Dear ImGui available you probably want this to be available for reference. -- Thank you, -- -Your beloved friend, imgui_demo.cpp (which you won't delete) ---------------------------------------------- -- ABOUT THE MEANING OF THE 'static' KEYWORD: ---------------------------------------------- --- In the upstream C++ demo code, 'static' variables inside functions are frequently used. +-- In this demo code, we frequently use 'static' variables inside functions. -- A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function. -- Think of "static int n = 0;" as "global int n = 0;" ! --- (PORT: Lua has no function-local statics; this port keeps them as fields of file-level tables, e.g. `S`, `SL`, `ST`.) -- We do this IN THE DEMO because we want: -- - to gather code and data in the same place. -- - to make the demo source code faster to read, faster to change, smaller in size. @@ -46,79 +46,150 @@ do --[[ imgui_demo.lua ]] -- doesn't need to be reentrant or used in multiple threads. -- This might be a pattern you will want to use in your code, but most of the data you would be working -- with in a complex codebase is likely going to be stored outside your functions. +-- [Port] Lua has no function-level 'static': they are fields of the file-level table S (S.FunctionName.x). ------------------------------------------- -- ABOUT THE CODING STYLE OF OUR DEMO CODE ------------------------------------------- -- The Demo code in this file is designed to be easy to copy-and-paste into your application! -- Because of this: --- - We never omit the ImGui. prefix when calling functions. +-- - We never omit the ImGui. prefix when calling functions, even though most code here is in the same namespace. +-- - We try to declare static variables in the local scope, as close as possible to the code using them. +-- - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API. +-- - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided +-- by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional +-- and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. +-- Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp. -- Navigating this file: +-- - In Visual Studio: Ctrl+Comma ("Edit.GoToAll") can follow symbols inside comments, whereas Ctrl+F12 ("Edit.GoToImplementation") cannot. +-- - In Visual Studio w/ Visual Assist installed: Alt+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. +-- - In VS Code, CLion, etc.: Ctrl+Click can follow symbols inside comments. -- - You can search/grep for all sections listed in the index to find the section. --- Index of this file: --- --- [SECTION] Helpers --- [SECTION] Demo Window / ShowDemoWindow() --- [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) --- [SECTION] Helpers: ExampleImageViewer --- [SECTION] DemoWindowWidgetsBasic() --- [SECTION] DemoWindowWidgetsBullets() --- [SECTION] DemoWindowWidgetsCollapsingHeaders() --- [SECTION] DemoWindowWidgetsComboBoxes() --- [SECTION] DemoWindowWidgetsColorAndPickers() --- [SECTION] DemoWindowWidgetsDataTypes() --- [SECTION] DemoWindowWidgetsDisableBlocks() --- [SECTION] DemoWindowWidgetsDragAndDrop() --- [SECTION] DemoWindowWidgetsDragsAndSliders() --- [SECTION] DemoWindowWidgetsFonts() --- [SECTION] DemoWindowWidgetsImages() --- [SECTION] DemoWindowWidgetsListBoxes() --- [SECTION] DemoWindowWidgetsLiveEdit() --- [SECTION] DemoWindowWidgetsMixedValues() --- [SECTION] DemoWindowWidgetsMultiComponents() --- [SECTION] DemoWindowWidgetsPlotting() --- [SECTION] DemoWindowWidgetsProgressBars() --- [SECTION] DemoWindowWidgetsQueryingStatuses() --- [SECTION] DemoWindowWidgetsSelectables() --- [SECTION] DemoWindowWidgetsTabs() --- [SECTION] DemoWindowWidgetsText() --- [SECTION] DemoWindowWidgetsTextFilter() --- [SECTION] DemoWindowWidgetsTextInput() --- [SECTION] DemoWindowWidgetsTooltips() --- [SECTION] DemoWindowWidgetsTreeNodes() --- [SECTION] DemoWindowWidgetsVerticalSliders() --- [SECTION] DemoWindowWidgets() --- [SECTION] DemoWindowLayout() --- [SECTION] DemoWindowPopups() --- [SECTION] DemoWindowTables() --- [SECTION] About Window / ShowAboutWindow() --- [SECTION] Style Editor / ShowStyleEditor() --- [SECTION] User Guide / ShowUserGuide() --- [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() --- [SECTION] Example App: Debug Console / ShowExampleAppConsole() --- [SECTION] Example App: Debug Log / ShowExampleAppLog() --- [SECTION] Example App: Simple Layout / ShowExampleAppLayout() --- [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() --- [SECTION] Example App: Long Text / ShowExampleAppLongText() --- [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() --- [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() --- [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() --- [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() --- [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() --- [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() --- [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() --- [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() +--[[ -local _ +Index of this file: + +// [SECTION] Forward Declarations +// [SECTION] Helpers +// [SECTION] Demo Window / ShowDemoWindow() +// [SECTION] DemoWindowMenuBar() +// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) +// [SECTION] Helpers: ExampleImageViewer +// [SECTION] DemoWindowWidgetsBasic() +// [SECTION] DemoWindowWidgetsBullets() +// [SECTION] DemoWindowWidgetsCollapsingHeaders() +// [SECTION] DemoWindowWidgetsComboBoxes() +// [SECTION] DemoWindowWidgetsColorAndPickers() +// [SECTION] DemoWindowWidgetsDataTypes() +// [SECTION] DemoWindowWidgetsDisableBlocks() +// [SECTION] DemoWindowWidgetsDragAndDrop() +// [SECTION] DemoWindowWidgetsDragsAndSliders() +// [SECTION] DemoWindowWidgetsFonts() +// [SECTION] DemoWindowWidgetsImages() +// [SECTION] DemoWindowWidgetsListBoxes() +// [SECTION] DemoWindowWidgetsLiveEdit() +// [SECTION] DemoWindowWidgetsMixedValues() +// [SECTION] DemoWindowWidgetsMultiComponents() +// [SECTION] DemoWindowWidgetsPlotting() +// [SECTION] DemoWindowWidgetsProgressBars() +// [SECTION] DemoWindowWidgetsQueryingStatuses() +// [SECTION] DemoWindowWidgetsSelectables() +// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect() +// [SECTION] DemoWindowWidgetsTabs() +// [SECTION] DemoWindowWidgetsText() +// [SECTION] DemoWindowWidgetsTextFilter() +// [SECTION] DemoWindowWidgetsTextInput() +// [SECTION] DemoWindowWidgetsTooltips() +// [SECTION] DemoWindowWidgetsTreeNodes() +// [SECTION] DemoWindowWidgetsVerticalSliders() +// [SECTION] DemoWindowWidgets() +// [SECTION] DemoWindowLayout() +// [SECTION] DemoWindowPopups() +// [SECTION] DemoWindowTables() +// [SECTION] DemoWindowInputs() +// [SECTION] About Window / ShowAboutWindow() +// [SECTION] Style Editor / ShowStyleEditor() +// [SECTION] User Guide / ShowUserGuide() +// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +// [SECTION] Example App: Debug Console / ShowExampleAppConsole() +// [SECTION] Example App: Image Viewer / ShowExampleAppImageViewer() +// [SECTION] Example App: Debug Log / ShowExampleAppLog() +// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() +// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() +// [SECTION] Example App: Long Text / ShowExampleAppLongText() +// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() +// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() +// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() +// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() +// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser() + +]] + +-- [Port] C includes, compiler warning pragmas, snprintf/PRId64/IMGUI_CDECL defines dropped (C only). + +-- Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) +-- [Port] IM_NEWLINE is always "\n" here. + +-- Helpers macros +-- We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, +-- but making an exception here as those are largely simplifying code... +-- In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. +-- [Port] IM_MIN/IM_MAX/IM_CLAMP -> the library globals ImMin/ImMax/ImClamp. + +------------------------------------------------------------------------------- +-- [SECTION] Forward Declarations +------------------------------------------------------------------------------- + +-- Forward Declarations +-- [Port] Not needed in Lua (globals are resolved at call time). Upstream list kept for reference: +-- struct ImGuiDemoWindowData; +-- static void ShowExampleAppMainMenuBar(); +-- static void ShowExampleAppAssetsBrowser(bool* p_open); +-- static void ShowExampleAppConsole(bool* p_open); +-- static void ShowExampleAppCustomRendering(bool* p_open); +-- static void ShowExampleAppDockSpace(bool* p_open); +-- static void ShowExampleAppDocuments(bool* p_open); +-- static void ShowExampleAppImageViewer(bool* p_open); +-- static void ShowExampleAppLog(bool* p_open); +-- static void ShowExampleAppLayout(bool* p_open); +-- static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data); +-- static void ShowExampleAppSimpleOverlay(bool* p_open); +-- static void ShowExampleAppAutoResize(bool* p_open); +-- static void ShowExampleAppConstrainedResize(bool* p_open); +-- static void ShowExampleAppFullscreen(bool* p_open); +-- static void ShowExampleAppLongText(bool* p_open); +-- static void ShowExampleAppWindowTitles(bool* p_open); +-- static void ShowExampleMenuFile(); + +-- We split the contents of the big ShowDemoWindow() function into smaller functions +-- (because the link time of very large functions tends to grow non-linearly) +-- static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data); +-- static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data); +-- static void DemoWindowLayout(); +-- static void DemoWindowPopups(); +-- static void DemoWindowTables(); +-- static void DemoWindowColumns(); +-- static void DemoWindowInputs(); + +-- Helper tree functions used by Property Editor & Multi-Select demos +-- struct ExampleTreeNode; +-- static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent); +-- static void ExampleTree_DestroyNode(ExampleTreeNode* node); ------------------------------------------------------------------------------- -- [SECTION] Helpers ------------------------------------------------------------------------------- --- Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer) -function IMGUI_DEMO_MARKER(_) end -- upstream hook, no-op here +-- [Port] Storage for C++ function-level `static` variables: one sub-table per upstream function (S.FunctionName), +-- declared right above the function. Shared by every part of this file. +local S = {} +local _ -- [Port] discard target for unused return values (`_, v = ImGui.Checkbox(...)`) -- Helper to display a little (?) mark which shows a tooltip when hovered. -- In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md) @@ -142,138 +213,17 @@ function ShowDockingDisabledMessage() end end -function DemoNotSupported() ImGui.TextDisabled("(not supported on Roblox)") end -function DemoNotPorted(what) ImGui.TextDisabled("(not ported yet%s)", what and (": " .. what) or "") end -function DemoB2I(b) return b and 1 or 0 end -function DemoHas(flags, f) return bit32.band(flags, f) ~= 0 end -function DemoClamp(v, mn, mx) return (v < mn) and mn or (v > mx) and mx or v end +-- Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer) +function IMGUI_DEMO_MARKER(section) end -- [Port] no ImGui.DemoMarker() hook in this port: no-op ---- `char buf[size] = "str"` -> zero-terminated byte table -function DemoBuf(str, size) - local t = {} - for i = 1, #str do t[i] = string.byte(str, i) end - t[#str + 1] = 0 - if size then for i = #str + 2, size do t[i] = 0 end end - return t -end ---- byte table -> Lua string (up to the zero terminator) -function DemoBufStr(buf) - local n = 0 - while buf[n + 1] ~= nil and buf[n + 1] ~= 0 do n = n + 1 end - if n == 0 then return "" end - return ImGui._ByteArrayToString(buf, 1, n + 1) -end - ---- "a\0b\0c\0\0" -> { "a", "b", "c" } -function DemoItems(s) - if type(s) == "table" then return s end - local t = {} - for item in string.gmatch(s, "([^%z]+)") do t[#t + 1] = item end - return t -end - ---- Combo() one-liner. `idx` is 0-based; `items` is a table of strings (1-based) or a "\0"-separated string. ---- Uses ImGui.Combo if it exists, falls back to BeginCombo/Selectable. ---- @return int idx, bool changed -function DemoCombo(label, idx, items, popup_max_height_in_items) - items = DemoItems(items) - if ImGui.Combo then - return ImGui.Combo(label, idx, items, #items, popup_max_height_in_items or -1) - end - local changed = false - local preview = (idx >= 0 and idx < #items) and items[idx + 1] or "" - if ImGui.BeginCombo(label, preview) then - for n = 0, #items - 1 do - local is_selected = (idx == n) - if ImGui.Selectable(items[n + 1], is_selected) then - idx = n - changed = true - end - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndCombo() - end - return idx, changed -end - ---- ListBox() one-liner (see DemoCombo) -function DemoListBox(label, idx, items, height_in_items) - items = DemoItems(items) - if ImGui.ListBox then - return ImGui.ListBox(label, idx, items, #items, height_in_items or -1) - end - local changed = false - if height_in_items == nil or height_in_items < 0 then height_in_items = math.min(#items, 7) end - local height_in_items_f = height_in_items + 0.25 - local height_in_pixels = math.floor(ImGui.GetTextLineHeightWithSpacing() * height_in_items_f + ImGui.GetStyle().FramePadding.y * 2.0) - if ImGui.BeginListBox and ImGui.BeginListBox(label, ImVec2(0.0, height_in_pixels)) then - for n = 0, #items - 1 do - local is_selected = (idx == n) - if ImGui.Selectable(items[n + 1], is_selected) then - idx = n - changed = true - end - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndListBox() - elseif not ImGui.BeginListBox then - DemoNotPorted("ListBox") - end - return idx, changed -end - ---- Closable header: CollapsingHeader(label, &p_open). Returns visible, open. -function DemoCollapsingHeaderClosable(label, open) - return ImGui.CollapsingHeader(label, open) -end - ---- ImColor::HSV() as ImVec4 -function DemoHSV(h, s, v, a) - local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v) - return ImVec4(r, g, b, a or 1.0) -end - ---- Minimal ImGuiTextFilter when the library one isn't available (Draw/DrawWithHint/PassFilter/Clear/IsActive) -function DemoTextFilter() - if ImGuiTextFilter then return ImGuiTextFilter() end - local f = { InputBuf = DemoBuf("", 256) } - local function parse(self) - local inc, exc = {}, {} - for tok in string.gmatch(string.lower(DemoBufStr(self.InputBuf)), "[^,%s]+") do - if string.sub(tok, 1, 1) == "-" then - if #tok > 1 then exc[#exc + 1] = string.sub(tok, 2) end - else - inc[#inc + 1] = tok - end - end - return inc, exc - end - function f:Draw(label, width) - if width and width ~= 0 then ImGui.SetNextItemWidth(width) end - return ImGui.InputText(label or "Filter (inc,-exc)", self.InputBuf, 256) - end - function f:DrawWithHint(label, hint, width) - if width and width ~= 0 then ImGui.SetNextItemWidth(width) end - return ImGui.InputTextWithHint(label, hint, self.InputBuf, 256) - end - function f:Clear() self.InputBuf[1] = 0 end - function f:IsActive() return self.InputBuf[1] ~= 0 and self.InputBuf[1] ~= nil end - function f:PassFilter(text) - local inc, exc = parse(self) - text = string.lower(text) - for _, e in ipairs(exc) do if string.find(text, e, 1, true) then return false end end - if #inc == 0 then return true end - for _, i in ipairs(inc) do if string.find(text, i, 1, true) then return true end end - return false - end - return f -end +-- Sneakily forward declare functions which aren't worth putting in public API yet +-- [Port] ImGui.ShowFontAtlas(atlas) and ImGui.TreeNodeSetOpen(storage_id, is_open) are already public here. ------------------------------------------------------------------------------- --- [SECTION] Demo Window data +-- [SECTION] Demo Window / ShowDemoWindow() ------------------------------------------------------------------------------- ---- Data to be shared across different functions of the demo. +-- Data to be shared across different functions of the demo. function ImGuiDemoWindowData() return { -- Examples Apps (accessible from the "Examples" menu) @@ -304,11 +254,466 @@ function ImGuiDemoWindowData() -- Other data DisableSections = false, LiveEditOverride = false, - LiveEditFlags = ImGuiItemFlags.LiveEditOnInputText or 0, + LiveEditFlags = ImGuiItemFlags.LiveEditOnInputText, DemoTree = nil, + + -- [Port] no destructor: DemoTree is garbage collected (upstream calls ExampleTree_DestroyNode(DemoTree)). } end +S.ShowDemoWindow = { + -- Stored data + demo_data = ImGuiDemoWindowData(), + + -- Demonstrate the various window flags. Typically you would just use the default! + no_titlebar = false, + no_scrollbar = false, + no_menu = false, + no_move = false, + no_resize = false, + no_collapse = false, + no_close = false, + no_nav = false, + no_background = false, + no_bring_to_front = false, + no_docking = false, + unsaved_document = false, +} + +-- Demonstrate most Dear ImGui features (this is big function!) +-- You may execute this function to experiment with the UI and understand what it does. +-- You may then search for keywords in the code when you are interested by a specific feature. +-- [Port] p_open: true/false/nil (nil = no close button). Returns the new p_open value. +function ImGui.ShowDemoWindow(p_open) + local s = S.ShowDemoWindow + + -- Exceptionally add an extra assert here for people confused about initial Dear ImGui setup + -- Most functions would normally just assert/crash if the context is missing. + IM_ASSERT(ImGui.GetCurrentContext() ~= nil, "Missing Dear ImGui context. Refer to examples app!") + + -- Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues. + -- [Port] IMGUI_CHECKVERSION() dropped: no ABI to verify. + + -- Stored data + local demo_data = s.demo_data + + -- Examples Apps (accessible from the "Examples" menu) + if demo_data.ShowMainMenuBar then ShowExampleAppMainMenuBar() end + if demo_data.ShowAppDockSpace then demo_data.ShowAppDockSpace = ShowExampleAppDockSpace(demo_data.ShowAppDockSpace) end -- Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) + if demo_data.ShowAppDocuments then demo_data.ShowAppDocuments = ShowExampleAppDocuments(demo_data.ShowAppDocuments) end -- ...process the Document app next, as it may also use a DockSpace() + if demo_data.ShowAppAssetsBrowser then demo_data.ShowAppAssetsBrowser = ShowExampleAppAssetsBrowser(demo_data.ShowAppAssetsBrowser) end + if demo_data.ShowAppConsole then demo_data.ShowAppConsole = ShowExampleAppConsole(demo_data.ShowAppConsole) end + if demo_data.ShowAppCustomRendering then demo_data.ShowAppCustomRendering = ShowExampleAppCustomRendering(demo_data.ShowAppCustomRendering) end + if demo_data.ShowAppImageViewer then demo_data.ShowAppImageViewer = ShowExampleAppImageViewer(demo_data.ShowAppImageViewer) end + if demo_data.ShowAppLog then demo_data.ShowAppLog = ShowExampleAppLog(demo_data.ShowAppLog) end + if demo_data.ShowAppLayout then demo_data.ShowAppLayout = ShowExampleAppLayout(demo_data.ShowAppLayout) end + if demo_data.ShowAppPropertyEditor then demo_data.ShowAppPropertyEditor = ShowExampleAppPropertyEditor(demo_data.ShowAppPropertyEditor, demo_data) end + if demo_data.ShowAppSimpleOverlay then demo_data.ShowAppSimpleOverlay = ShowExampleAppSimpleOverlay(demo_data.ShowAppSimpleOverlay) end + if demo_data.ShowAppAutoResize then demo_data.ShowAppAutoResize = ShowExampleAppAutoResize(demo_data.ShowAppAutoResize) end + if demo_data.ShowAppConstrainedResize then demo_data.ShowAppConstrainedResize = ShowExampleAppConstrainedResize(demo_data.ShowAppConstrainedResize) end + if demo_data.ShowAppFullscreen then demo_data.ShowAppFullscreen = ShowExampleAppFullscreen(demo_data.ShowAppFullscreen) end + if demo_data.ShowAppLongText then demo_data.ShowAppLongText = ShowExampleAppLongText(demo_data.ShowAppLongText) end + if demo_data.ShowAppWindowTitles then demo_data.ShowAppWindowTitles = ShowExampleAppWindowTitles(demo_data.ShowAppWindowTitles) end + + -- Dear ImGui Tools (accessible from the "Tools" menu) + if demo_data.ShowMetrics then demo_data.ShowMetrics = ImGui.ShowMetricsWindow(demo_data.ShowMetrics) end + if demo_data.ShowDebugLog then demo_data.ShowDebugLog = ImGui.ShowDebugLogWindow(demo_data.ShowDebugLog) end + if demo_data.ShowIDStackTool then demo_data.ShowIDStackTool = ImGui.ShowIDStackToolWindow(demo_data.ShowIDStackTool) end + if demo_data.ShowAbout then demo_data.ShowAbout = ImGui.ShowAboutWindow(demo_data.ShowAbout) end + if demo_data.ShowStyleEditor then + demo_data.ShowStyleEditor = ImGui.Begin("Dear ImGui Style Editor", demo_data.ShowStyleEditor) + ImGui.ShowStyleEditor() + ImGui.End() + end + + -- Demonstrate the various window flags. Typically you would just use the default! + local window_flags = 0 + if s.no_titlebar then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoTitleBar) end + if s.no_scrollbar then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoScrollbar) end + if not s.no_menu then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.MenuBar) end + if s.no_move then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoMove) end + if s.no_resize then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoResize) end + if s.no_collapse then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoCollapse) end + if s.no_nav then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoNav) end + if s.no_background then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoBackground) end + if s.no_bring_to_front then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoBringToFrontOnFocus) end + if s.no_docking then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoDocking) end + if s.unsaved_document then window_flags = bit32.bor(window_flags, ImGuiWindowFlags.UnsavedDocument) end + local begin_p_open = p_open -- [Port] keep the caller's value intact when not passed to Begin() + if s.no_close then begin_p_open = nil end -- Don't pass our bool* to Begin + + -- We specify a default position/size in case there's no data in the .ini file. + -- We only do it to make the demo applications a little more welcoming, but typically this isn't required. + local main_viewport = ImGui.GetMainViewport() + ImGui.SetNextWindowPos(ImVec2(main_viewport.WorkPos.x + 650, main_viewport.WorkPos.y + 20), ImGuiCond.FirstUseEver) + ImGui.SetNextWindowSize(ImVec2(550, 680), ImGuiCond.FirstUseEver) + + -- Main body of the Demo window starts here. + local open, visible = ImGui.Begin("Dear ImGui Demo", begin_p_open, window_flags) + if begin_p_open ~= nil then p_open = open end -- [Port] write back the bool* output + if not visible then + -- Early out if the window is collapsed, as an optimization. + ImGui.End() + return p_open + end + + -- Most framed widgets share a common width settings. Remaining width is used for the label. + -- The width of the frame may be changed with PushItemWidth() or SetNextItemWidth(). + -- - Positive value for absolute size, negative value for right-alignment. + -- - The default value is about GetWindowWidth() * 0.65f. + -- - See 'Demo->Layout->Widgets Width' for details. + -- Here we change the frame width based on how much width we want to give to the label. + local label_width_base = ImGui.GetFontSize() * 12 -- Some amount of width for label, based on font size. + local label_width_max = ImGui.GetContentRegionAvail().x * 0.40 -- ...but always leave some room for framed widgets. + local label_width = ImMin(label_width_base, label_width_max) + ImGui.PushItemWidth(-label_width) -- Right-align: framed items will leave 'label_width' available for the label. + --ImGui.PushItemWidth(ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for framed widgets, leaving 60% width for labels. + --ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for labels, leaving 60% width for framed widgets. + --ImGui.PushItemWidth(ImGui.GetFontSize() * -12) -- e.g. Use XXX width for labels, leaving the rest for framed widgets. + + -- Menu Bar + DemoWindowMenuBar(demo_data) + + ImGui.Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM) + ImGui.Spacing() + + if ImGui.CollapsingHeader("Help") then + IMGUI_DEMO_MARKER("Help") + ImGui.SeparatorText("ABOUT THIS DEMO:") + ImGui.BulletText("Sections below are demonstrating many aspects of the library.") + ImGui.BulletText("The \"Examples\" menu above leads to more demo contents.") + ImGui.BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" .. + "and Metrics/Debugger (general purpose Dear ImGui debugging tool).") + ImGui.BulletText("Web demo (w/ source code browser): ") + ImGui.SameLine(0, 0) + ImGui.TextLinkOpenURL("https://pthom.github.io/imgui_explorer") + + ImGui.SeparatorText("PROGRAMMER GUIDE:") + ImGui.BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!") + ImGui.BulletText("See comments in imgui.cpp.") + ImGui.BulletText("See example applications in the examples/ folder.") + ImGui.BulletText("Read the FAQ at ") + ImGui.SameLine(0, 0) + ImGui.TextLinkOpenURL("https://www.dearimgui.com/faq/") + ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.") + ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.") + + ImGui.SeparatorText("USER GUIDE:") + ImGui.ShowUserGuide() + end + + if ImGui.CollapsingHeader("Configuration") then + local io = ImGui.GetIO() + + if ImGui.TreeNode("Configuration##2") then + IMGUI_DEMO_MARKER("Configuration") + ImGui.SeparatorText("General") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", io.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) + ImGui.SameLine(); HelpMarker("Enable keyboard controls.") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NavEnableGamepad", io.ConfigFlags, ImGuiConfigFlags.NavEnableGamepad) + ImGui.SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NoMouse", io.ConfigFlags, ImGuiConfigFlags.NoMouse) + ImGui.SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.") + + -- The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: + if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NoMouse) ~= 0 then + if math.fmod(ImGui.GetTime(), 0.40) < 0.20 then + ImGui.SameLine() + ImGui.Text("<>") + end + -- Prevent both being checked + if ImGui.IsKeyPressed(ImGuiKey.Space) or bit32.band(io.ConfigFlags, ImGuiConfigFlags.NoKeyboard) ~= 0 then + io.ConfigFlags = bit32.band(io.ConfigFlags, bit32.bnot(ImGuiConfigFlags.NoMouse)) + end + end + + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", io.ConfigFlags, ImGuiConfigFlags.NoMouseCursorChange) + ImGui.SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: NoKeyboard", io.ConfigFlags, ImGuiConfigFlags.NoKeyboard) + ImGui.SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.") + + _, io.ConfigInputTrickleEventQueue = ImGui.Checkbox("io.ConfigInputTrickleEventQueue", io.ConfigInputTrickleEventQueue) + ImGui.SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.") + _, io.MouseDrawCursor = ImGui.Checkbox("io.MouseDrawCursor", io.MouseDrawCursor) + ImGui.SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).") + + ImGui.SeparatorText("Keyboard/Gamepad Navigation") + _, io.ConfigNavSwapGamepadButtons = ImGui.Checkbox("io.ConfigNavSwapGamepadButtons", io.ConfigNavSwapGamepadButtons) + _, io.ConfigNavMoveSetMousePos = ImGui.Checkbox("io.ConfigNavMoveSetMousePos", io.ConfigNavMoveSetMousePos) + ImGui.SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult") + _, io.ConfigNavCaptureKeyboard = ImGui.Checkbox("io.ConfigNavCaptureKeyboard", io.ConfigNavCaptureKeyboard) + _, io.ConfigNavEscapeClearFocusItem = ImGui.Checkbox("io.ConfigNavEscapeClearFocusItem", io.ConfigNavEscapeClearFocusItem) + ImGui.SameLine(); HelpMarker("Pressing Escape clears focused item.") + _, io.ConfigNavEscapeClearFocusWindow = ImGui.Checkbox("io.ConfigNavEscapeClearFocusWindow", io.ConfigNavEscapeClearFocusWindow) + ImGui.SameLine(); HelpMarker("Pressing Escape clears focused window.") + _, io.ConfigNavCursorVisibleAuto = ImGui.Checkbox("io.ConfigNavCursorVisibleAuto", io.ConfigNavCursorVisibleAuto) + ImGui.SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.") + _, io.ConfigNavCursorVisibleAlways = ImGui.Checkbox("io.ConfigNavCursorVisibleAlways", io.ConfigNavCursorVisibleAlways) + ImGui.SameLine(); HelpMarker("Navigation cursor is always visible.") + + ImGui.SeparatorText("Docking") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: DockingEnable", io.ConfigFlags, ImGuiConfigFlags.DockingEnable) + ImGui.SameLine() + if io.ConfigDockingWithShift then + HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") + else + HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") + end + if bit32.band(io.ConfigFlags, ImGuiConfigFlags.DockingEnable) ~= 0 then + ImGui.Indent() + _, io.ConfigDockingNoSplit = ImGui.Checkbox("io.ConfigDockingNoSplit", io.ConfigDockingNoSplit) + ImGui.SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.") + _, io.ConfigDockingNoDockingOver = ImGui.Checkbox("io.ConfigDockingNoDockingOver", io.ConfigDockingNoDockingOver) + ImGui.SameLine(); HelpMarker("Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows.") + _, io.ConfigDockingWithShift = ImGui.Checkbox("io.ConfigDockingWithShift", io.ConfigDockingWithShift) + ImGui.SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)") + _, io.ConfigDockingAlwaysTabBar = ImGui.Checkbox("io.ConfigDockingAlwaysTabBar", io.ConfigDockingAlwaysTabBar) + ImGui.SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.") + _, io.ConfigDockingTransparentPayload = ImGui.Checkbox("io.ConfigDockingTransparentPayload", io.ConfigDockingTransparentPayload) + ImGui.SameLine(); HelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.") + ImGui.Unindent() + end + + ImGui.SeparatorText("Multi-viewports") + _, io.ConfigFlags = ImGui.CheckboxFlags("io.ConfigFlags: ViewportsEnable", io.ConfigFlags, ImGuiConfigFlags.ViewportsEnable) + ImGui.SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.") + if bit32.band(io.ConfigFlags, ImGuiConfigFlags.ViewportsEnable) ~= 0 then + ImGui.Indent() + _, io.ConfigViewportsNoAutoMerge = ImGui.Checkbox("io.ConfigViewportsNoAutoMerge", io.ConfigViewportsNoAutoMerge) + ImGui.SameLine(); HelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.") + _, io.ConfigViewportsNoTaskBarIcon = ImGui.Checkbox("io.ConfigViewportsNoTaskBarIcon", io.ConfigViewportsNoTaskBarIcon) + ImGui.SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)") + _, io.ConfigViewportsNoDecoration = ImGui.Checkbox("io.ConfigViewportsNoDecoration", io.ConfigViewportsNoDecoration) + ImGui.SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)") + _, io.ConfigViewportsNoDefaultParent = ImGui.Checkbox("io.ConfigViewportsNoDefaultParent", io.ConfigViewportsNoDefaultParent) + ImGui.SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)") + _, io.ConfigViewportsPlatformFocusSetsImGuiFocus = ImGui.Checkbox("io.ConfigViewportsPlatformFocusSetsImGuiFocus", io.ConfigViewportsPlatformFocusSetsImGuiFocus) + ImGui.SameLine(); HelpMarker("When a platform window is focused (e.g. using Alt+Tab, clicking Platform Title Bar), apply corresponding focus on imgui windows (may clear focus/active id from imgui windows location in other platform windows). In principle this is better enabled but we provide an opt-out, because some Linux window managers tend to eagerly focus windows (e.g. on mouse hover, or even a simple window pos/size change).") + ImGui.Unindent() + end + + --ImGui.SeparatorText("DPI/Scaling") + --_, io.ConfigDpiScaleFonts = ImGui.Checkbox("io.ConfigDpiScaleFonts", io.ConfigDpiScaleFonts) + --ImGui.SameLine(); HelpMarker("Experimental: Automatically update style.FontScaleDpi when Monitor DPI changes. This will scale fonts but NOT style sizes/padding for now.") + --_, io.ConfigDpiScaleViewports = ImGui.Checkbox("io.ConfigDpiScaleViewports", io.ConfigDpiScaleViewports) + --ImGui.SameLine(); HelpMarker("Experimental: Scale Dear ImGui and Platform Windows when Monitor DPI changes.") + + ImGui.SeparatorText("Windows") + _, io.ConfigWindowsResizeFromEdges = ImGui.Checkbox("io.ConfigWindowsResizeFromEdges", io.ConfigWindowsResizeFromEdges) + ImGui.SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.") + _, io.ConfigWindowsMoveFromTitleBarOnly = ImGui.Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", io.ConfigWindowsMoveFromTitleBarOnly) + _, io.ConfigWindowsCopyContentsWithCtrlC = ImGui.Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", io.ConfigWindowsCopyContentsWithCtrlC) -- [EXPERIMENTAL] + ImGui.SameLine(); HelpMarker("*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.") + _, io.ConfigScrollbarScrollByPage = ImGui.Checkbox("io.ConfigScrollbarScrollByPage", io.ConfigScrollbarScrollByPage) + ImGui.SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.") + + ImGui.SeparatorText("Widgets") + _, io.ConfigInputTextCursorBlink = ImGui.Checkbox("io.ConfigInputTextCursorBlink", io.ConfigInputTextCursorBlink) + ImGui.SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).") + _, io.ConfigInputTextEnterKeepActive = ImGui.Checkbox("io.ConfigInputTextEnterKeepActive", io.ConfigInputTextEnterKeepActive) + ImGui.SameLine(); HelpMarker("Pressing Enter will reactivate item and select all text (single-line only).") + _, io.ConfigDragClickToInputText = ImGui.Checkbox("io.ConfigDragClickToInputText", io.ConfigDragClickToInputText) + ImGui.SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).") + _, io.ConfigMacOSXBehaviors = ImGui.Checkbox("io.ConfigMacOSXBehaviors", io.ConfigMacOSXBehaviors) + ImGui.SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.") + ImGui.Text("Also see Style->Rendering for rendering options.") + + ImGui.SeparatorText("Settings") + _, io.ConfigIniSettingsSaveLastUsedDate = ImGui.Checkbox("io.ConfigIniSettingsSaveLastUsedDate", io.ConfigIniSettingsSaveLastUsedDate) + + -- Also read: https://github.com/ocornut/imgui/wiki/Error-Handling + ImGui.SeparatorText("Error Handling") + + _, io.ConfigErrorRecovery = ImGui.Checkbox("io.ConfigErrorRecovery", io.ConfigErrorRecovery) + ImGui.SameLine(); HelpMarker( + "Options to configure how we handle recoverable errors.\n" .. + "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n" .. + "- You not are not supposed to rely on it in the course of a normal application run.\n" .. + "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n" .. + "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call! " .. + "Otherwise it would severely hinder your ability to catch and correct mistakes!") + _, io.ConfigErrorRecoveryEnableAssert = ImGui.Checkbox("io.ConfigErrorRecoveryEnableAssert", io.ConfigErrorRecoveryEnableAssert) + _, io.ConfigErrorRecoveryEnableDebugLog = ImGui.Checkbox("io.ConfigErrorRecoveryEnableDebugLog", io.ConfigErrorRecoveryEnableDebugLog) + _, io.ConfigErrorRecoveryEnableTooltip = ImGui.Checkbox("io.ConfigErrorRecoveryEnableTooltip", io.ConfigErrorRecoveryEnableTooltip) + if not io.ConfigErrorRecoveryEnableAssert and not io.ConfigErrorRecoveryEnableDebugLog and not io.ConfigErrorRecoveryEnableTooltip then + io.ConfigErrorRecoveryEnableAssert = true; io.ConfigErrorRecoveryEnableDebugLog = true; io.ConfigErrorRecoveryEnableTooltip = true + end + + -- Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools + ImGui.SeparatorText("Debug") + _, io.ConfigDebugIsDebuggerPresent = ImGui.Checkbox("io.ConfigDebugIsDebuggerPresent", io.ConfigDebugIsDebuggerPresent) + ImGui.SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.") + _, io.ConfigDebugHighlightIdConflicts = ImGui.Checkbox("io.ConfigDebugHighlightIdConflicts", io.ConfigDebugHighlightIdConflicts) + ImGui.SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.") + ImGui.BeginDisabled() + _, io.ConfigDebugBeginReturnValueOnce = ImGui.Checkbox("io.ConfigDebugBeginReturnValueOnce", io.ConfigDebugBeginReturnValueOnce) + ImGui.EndDisabled() + ImGui.SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.") + _, io.ConfigDebugBeginReturnValueLoop = ImGui.Checkbox("io.ConfigDebugBeginReturnValueLoop", io.ConfigDebugBeginReturnValueLoop) + ImGui.SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.") + _, io.ConfigDebugIgnoreFocusLoss = ImGui.Checkbox("io.ConfigDebugIgnoreFocusLoss", io.ConfigDebugIgnoreFocusLoss) + ImGui.SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.") + _, io.ConfigDebugDrawListDefaultsToStrokeLegacy = ImGui.Checkbox("io.ConfigDebugDrawListDefaultsToStrokeLegacy", io.ConfigDebugDrawListDefaultsToStrokeLegacy) + ImGui.SameLine(); HelpMarker("Option to default all ImDrawList to ImDrawFlags_StrokeLegacy mode, mimicking pre-1.93.0 rendering.") + _, io.ConfigDebugIniSettings = ImGui.Checkbox("io.ConfigDebugIniSettings", io.ConfigDebugIniSettings) + ImGui.SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).") + + ImGui.TreePop() + ImGui.Spacing() + end + + if ImGui.TreeNode("Backend Flags") then + IMGUI_DEMO_MARKER("Configuration/Backend Flags") + HelpMarker( + "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" .. + "Here we expose them as read-only fields to avoid breaking interactions with your backend.") + + -- Make a local copy to avoid modifying actual backend flags. + -- FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright? + ImGui.BeginDisabled() + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasGamepad", io.BackendFlags, ImGuiBackendFlags.HasGamepad) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseCursors", io.BackendFlags, ImGuiBackendFlags.HasMouseCursors) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasSetMousePos", io.BackendFlags, ImGuiBackendFlags.HasSetMousePos) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: PlatformHasViewports", io.BackendFlags, ImGuiBackendFlags.PlatformHasViewports) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",io.BackendFlags, ImGuiBackendFlags.HasMouseHoveredViewport) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasParentViewport", io.BackendFlags, ImGuiBackendFlags.HasParentViewport) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", io.BackendFlags, ImGuiBackendFlags.RendererHasVtxOffset) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasTextures", io.BackendFlags, ImGuiBackendFlags.RendererHasTextures) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasViewports", io.BackendFlags, ImGuiBackendFlags.RendererHasViewports) + ImGui.EndDisabled() + + ImGui.TreePop() + ImGui.Spacing() + end + + if ImGui.TreeNode("Style, Fonts") then + IMGUI_DEMO_MARKER("Configuration/Style, Fonts") + _, demo_data.ShowStyleEditor = ImGui.Checkbox("Style Editor", demo_data.ShowStyleEditor) + ImGui.SameLine() + HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.") + ImGui.TreePop() + ImGui.Spacing() + end + + if ImGui.TreeNode("Capture/Logging") then + IMGUI_DEMO_MARKER("Configuration/Capture, Logging") + HelpMarker( + "The logging API redirects all text output so you can easily capture the content of " .. + "a window or a block. Tree nodes can be automatically expanded.\n" .. + "Try opening any of the contents below in this window and then click one of the \"Log To\" button.") + ImGui.LogButtons() + + HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.") + if ImGui.Button("Copy \"Hello, world!\" to clipboard") then + ImGui.LogToClipboard() + ImGui.LogText("Hello, world!") + ImGui.LogFinish() + end + ImGui.TreePop() + end + end + + if ImGui.CollapsingHeader("Window options") then + IMGUI_DEMO_MARKER("Window options") + if ImGui.BeginTable("split", 3) then + ImGui.TableNextColumn(); _, s.no_titlebar = ImGui.Checkbox("No titlebar", s.no_titlebar) + ImGui.TableNextColumn(); _, s.no_scrollbar = ImGui.Checkbox("No scrollbar", s.no_scrollbar) + ImGui.TableNextColumn(); _, s.no_menu = ImGui.Checkbox("No menu", s.no_menu) + ImGui.TableNextColumn(); _, s.no_move = ImGui.Checkbox("No move", s.no_move) + ImGui.TableNextColumn(); _, s.no_resize = ImGui.Checkbox("No resize", s.no_resize) + ImGui.TableNextColumn(); _, s.no_collapse = ImGui.Checkbox("No collapse", s.no_collapse) + ImGui.TableNextColumn(); _, s.no_close = ImGui.Checkbox("No close", s.no_close) + ImGui.TableNextColumn(); _, s.no_nav = ImGui.Checkbox("No nav", s.no_nav) + ImGui.TableNextColumn(); _, s.no_background = ImGui.Checkbox("No background", s.no_background) + ImGui.TableNextColumn(); _, s.no_bring_to_front = ImGui.Checkbox("No bring to front", s.no_bring_to_front) + ImGui.TableNextColumn(); _, s.no_docking = ImGui.Checkbox("No docking", s.no_docking) + ImGui.TableNextColumn(); _, s.unsaved_document = ImGui.Checkbox("Unsaved document", s.unsaved_document) + ImGui.EndTable() + end + end + + -- All demo contents + DemoWindowWidgets(demo_data) + DemoWindowLayout() + DemoWindowPopups() + DemoWindowTables() + DemoWindowInputs() + + -- End of ShowDemoWindow() + ImGui.PopItemWidth() + ImGui.End() + return p_open +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowMenuBar() +------------------------------------------------------------------------------- + +function DemoWindowMenuBar(demo_data) + if ImGui.BeginMenuBar() then + if ImGui.BeginMenu("Menu") then + IMGUI_DEMO_MARKER("Menu/File") + ShowExampleMenuFile() + ImGui.EndMenu() + end + if ImGui.BeginMenu("Examples") then + IMGUI_DEMO_MARKER("Menu/Examples") + _, demo_data.ShowMainMenuBar = ImGui.MenuItem("Main menu bar", nil, demo_data.ShowMainMenuBar) + + ImGui.SeparatorText("Mini apps") + _, demo_data.ShowAppAssetsBrowser = ImGui.MenuItem("Assets Browser", nil, demo_data.ShowAppAssetsBrowser) + _, demo_data.ShowAppConsole = ImGui.MenuItem("Console", nil, demo_data.ShowAppConsole) + _, demo_data.ShowAppCustomRendering = ImGui.MenuItem("Custom rendering", nil, demo_data.ShowAppCustomRendering) + _, demo_data.ShowAppDocuments = ImGui.MenuItem("Documents", nil, demo_data.ShowAppDocuments) + _, demo_data.ShowAppDockSpace = ImGui.MenuItem("Dockspace", nil, demo_data.ShowAppDockSpace) + _, demo_data.ShowAppImageViewer = ImGui.MenuItem("Image Viewer", nil, demo_data.ShowAppImageViewer) + _, demo_data.ShowAppLog = ImGui.MenuItem("Log", nil, demo_data.ShowAppLog) + _, demo_data.ShowAppPropertyEditor = ImGui.MenuItem("Property editor", nil, demo_data.ShowAppPropertyEditor) + _, demo_data.ShowAppLayout = ImGui.MenuItem("Simple layout", nil, demo_data.ShowAppLayout) + _, demo_data.ShowAppSimpleOverlay = ImGui.MenuItem("Simple overlay", nil, demo_data.ShowAppSimpleOverlay) + + ImGui.SeparatorText("Concepts") + _, demo_data.ShowAppAutoResize = ImGui.MenuItem("Auto-resizing window", nil, demo_data.ShowAppAutoResize) + _, demo_data.ShowAppConstrainedResize = ImGui.MenuItem("Constrained-resizing window", nil, demo_data.ShowAppConstrainedResize) + _, demo_data.ShowAppFullscreen = ImGui.MenuItem("Fullscreen window", nil, demo_data.ShowAppFullscreen) + _, demo_data.ShowAppLongText = ImGui.MenuItem("Long text display", nil, demo_data.ShowAppLongText) + _, demo_data.ShowAppWindowTitles = ImGui.MenuItem("Manipulating window titles", nil, demo_data.ShowAppWindowTitles) + + ImGui.EndMenu() + end + --if ImGui.MenuItem("MenuItem") then end -- You can also use MenuItem() inside a menu bar! + if ImGui.BeginMenu("Tools") then + IMGUI_DEMO_MARKER("Menu/Tools") + local io = ImGui.GetIO() + local has_debug_tools = true -- [Port] IMGUI_DISABLE_DEBUG_TOOLS is never defined here + _, demo_data.ShowMetrics = ImGui.MenuItem("Metrics/Debugger", nil, demo_data.ShowMetrics, has_debug_tools) + if ImGui.BeginMenu("Debug Options") then + ImGui.BeginDisabled(not has_debug_tools) + _, io.ConfigDebugHighlightIdConflicts = ImGui.Checkbox("Highlight ID Conflicts", io.ConfigDebugHighlightIdConflicts) + ImGui.EndDisabled() + _, io.ConfigErrorRecoveryEnableAssert = ImGui.Checkbox("Assert on error recovery", io.ConfigErrorRecoveryEnableAssert) + ImGui.TextDisabled("(see Demo->Configuration for more)") + ImGui.EndMenu() + end + _, demo_data.ShowDebugLog = ImGui.MenuItem("Debug Log", nil, demo_data.ShowDebugLog, has_debug_tools) + _, demo_data.ShowIDStackTool = ImGui.MenuItem("ID Stack Tool", nil, demo_data.ShowIDStackTool, has_debug_tools) + local is_debugger_present = io.ConfigDebugIsDebuggerPresent + local has_item_picker = ImGui.DebugStartItemPicker ~= nil -- [Port] ImGui.DebugStartItemPicker() is not ported yet: menu item disabled until it is + if ImGui.MenuItem("Item Picker", nil, false, has_debug_tools and has_item_picker) then -- and is_debugger_present + ImGui.DebugStartItemPicker() + end + if not is_debugger_present then + ImGui.SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application.") + end + _, demo_data.ShowStyleEditor = ImGui.MenuItem("Style Editor", nil, demo_data.ShowStyleEditor) + _, demo_data.ShowAbout = ImGui.MenuItem("About Dear ImGui", nil, demo_data.ShowAbout) + + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end +end + ------------------------------------------------------------------------------- -- [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) ------------------------------------------------------------------------------- @@ -318,23 +723,43 @@ end function ExampleTreeNode() return { -- Tree structure - Name = "", + Name = "", -- [Port] Lua string (upstream char Name[28]), max 27 bytes UID = 0, Parent = nil, - Childs = {}, -- 1-based - IndexInParent = 0, -- 0-based. Maintaining this allows us to implement linear traversal more easily + Childs = {}, -- [Port] plain 1-based Lua array (upstream ImVector): #Childs, Childs[n + 1] + IndexInParent = 0, -- Maintaining this allows us to implement linear traversal more easily (0-based) -- Leaf Data - HasData = false, -- All leaves have data + HasData = false, -- All leaves have data DataMyBool = true, DataMyInt = 128, DataMyVec2 = ImVec2(0.0, 3.141592), } end +-- Simple representation of struct metadata/serialization data. +-- (this is a minimal version of what a typical advanced application may provide) +function ExampleMemberInfo(name, data_type, data_count, offset) + return { + Name = name, -- Member name + DataType = data_type, -- Member type + DataCount = data_count, -- Member count (1 when scalar) + Offset = offset, -- Offset inside parent structure -- [Port] field key in the node table (no offsetof) + } +end + +-- Metadata description of ExampleTreeNode struct. +ExampleTreeNodeMemberInfos = +{ + ExampleMemberInfo("MyName", ImGuiDataType.String, 1, "Name"), + ExampleMemberInfo("MyBool", ImGuiDataType.Bool, 1, "DataMyBool"), + ExampleMemberInfo("MyInt", ImGuiDataType.S32, 1, "DataMyInt"), + ExampleMemberInfo("MyVec2", ImGuiDataType.Float, 2, "DataMyVec2"), +} + function ExampleTree_CreateNode(name, uid, parent) local node = ExampleTreeNode() - node.Name = string.sub(name, 1, 27) + node.Name = string.sub(name, 1, 27) -- [Port] snprintf() into char[28] node.UID = uid node.Parent = parent node.IndexInParent = parent and #parent.Childs or 0 @@ -344,34 +769,49 @@ function ExampleTree_CreateNode(name, uid, parent) return node end -function ExampleTree_DestroyNode(node) end -- GC +function ExampleTree_DestroyNode(node) + for _, child_node in ipairs(node.Childs) do + ExampleTree_DestroyNode(child_node) + end + -- [Port] IM_DELETE(node): nothing to do, garbage collected +end + +S.ExampleTree_CreateDemoTree = { + category_names = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" }, +} -- Create example tree data -- (warning: this can allocates MANY MANY more times than other code in all of Dear ImGui + demo combined) -- (a real application managing one million nodes would likely store its tree data differently) function ExampleTree_CreateDemoTree() + local s = S.ExampleTree_CreateDemoTree + -- 20 root nodes -> 211 total nodes, ~261 allocs. -- 1000 root nodes -> ~11K total nodes, ~14K allocs. -- 10000 root nodes -> ~123K total nodes, ~154K allocs. -- 100000 root nodes -> ~1338K total nodes, ~1666K allocs. local ROOT_ITEMS_COUNT = 20 - local category_names = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" } + + local category_names = s.category_names local category_count = #category_names + local name_buf -- [Port] Lua string, truncated to sizeof(ExampleTreeNode::Name) by ExampleTree_CreateNode() local uid = 0 uid = uid + 1 local node_L0 = ExampleTree_CreateNode("", uid, nil) for idx_L0 = 0, ROOT_ITEMS_COUNT - 1 do - local name_buf = string.format("%s %d", category_names[math.floor(idx_L0 / math.floor(ROOT_ITEMS_COUNT / category_count)) + 1], idx_L0 % math.floor(ROOT_ITEMS_COUNT / category_count)) + name_buf = string.format("%s %d", category_names[math.floor(idx_L0 / math.floor(ROOT_ITEMS_COUNT / category_count)) + 1], idx_L0 % math.floor(ROOT_ITEMS_COUNT / category_count)) uid = uid + 1 local node_L1 = ExampleTree_CreateNode(name_buf, uid, node_L0) local number_of_childs = #node_L1.Name for idx_L1 = 0, number_of_childs - 1 do + name_buf = string.format("Child %d", idx_L1) uid = uid + 1 - local node_L2 = ExampleTree_CreateNode(string.format("Child %d", idx_L1), uid, node_L1) + local node_L2 = ExampleTree_CreateNode(name_buf, uid, node_L1) node_L2.HasData = true if idx_L1 == 0 then + name_buf = string.format("Sub-child %d", 0) uid = uid + 1 - local node_L3 = ExampleTree_CreateNode(string.format("Sub-child %d", 0), uid, node_L2) + local node_L3 = ExampleTree_CreateNode(name_buf, uid, node_L2) node_L3.HasData = true end end @@ -386,13 +826,13 @@ end function ExampleImageViewerData() return { ImageBgColor = IM_COL32(100, 100, 100, 255), - GridColor = IM_COL32(255, 255, 255, 100), - GridEnabled = true, - ViewReset = true, - ViewOffset = ImVec2(0, 0), -- in image space - Zoom = 10.0, - ZoomMin = 1.0, - ZoomMax = 10000.0, + GridColor = IM_COL32(255, 255, 255, 100), + GridEnabled = true, + ViewReset = true, + ViewOffset = ImVec2(0.0, 0.0), -- in image space + Zoom = 10.0, + ZoomMin = 1.0, + ZoomMax = 10000.0, } end @@ -428,7 +868,7 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w -- Handle inputs if ImGui.SetItemKeyOwner(ImGuiKey.MouseWheelY) then if io.MouseWheel ~= 0.0 then - data.Zoom = DemoClamp(data.Zoom * (1.0 + io.MouseWheel * 0.10), data.ZoomMin, data.ZoomMax) + data.Zoom = ImClamp(data.Zoom * (1.0 + io.MouseWheel * 0.10), data.ZoomMin, data.ZoomMax) end end local zoom = data.Zoom -- (float)(int)ViewZoom; @@ -438,11 +878,11 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w end -- Display image - local image_min = ImVec2(); local image_max = ImVec2() - image_min.x = math.floor((canvas_min.x - (data.ViewOffset.x * zoom)) + (canvas_size.x * 0.5)) - image_min.y = math.floor((canvas_min.y - (data.ViewOffset.y * zoom)) + (canvas_size.y * 0.5)) - image_max.x = math.floor(image_min.x + image_w * zoom) - image_max.y = math.floor(image_min.y + image_h * zoom) + local image_min, image_max = ImVec2(), ImVec2() + image_min.x = ImTrunc((canvas_min.x - (data.ViewOffset.x * zoom)) + (canvas_size.x * 0.5)) + image_min.y = ImTrunc((canvas_min.y - (data.ViewOffset.y * zoom)) + (canvas_size.y * 0.5)) + image_max.x = ImTrunc(image_min.x + image_w * zoom) + image_max.y = ImTrunc(image_min.y + image_h * zoom) draw_list:AddRect(ImVec2(canvas_min.x - 1.0, canvas_min.y - 1.0), ImVec2(canvas_max.x + 1.0, canvas_max.y + 1.0), IM_COL32(255, 255, 255, 255)) draw_list:PushClipRect(canvas_min, canvas_max, true) draw_list:AddRectFilled(image_min, image_max, data.ImageBgColor) @@ -457,10 +897,10 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w -- Display grid lines for visible pixels if data.GridEnabled and zoom > 6.0 then local step = zoom - for px = math.floor((canvas_min.x - image_min.x) / step), math.floor((canvas_max.x - image_min.x) / step) do + for px = ImTrunc((canvas_min.x - image_min.x) / step), ImTrunc((canvas_max.x - image_min.x) / step) do draw_list:AddLineV(image_min.x + px * step, canvas_min.y, canvas_max.y, data.GridColor, 1.0) end - for py = math.floor((canvas_min.y - image_min.y) / step), math.floor((canvas_max.y - image_min.y) / step) do + for py = ImTrunc((canvas_min.y - image_min.y) / step), ImTrunc((canvas_max.y - image_min.y) / step) do draw_list:AddLineH(canvas_min.x, canvas_max.x, image_min.y + py * step, data.GridColor, 1.0) end end @@ -468,547 +908,2834 @@ function ExampleImageViewer_DrawCanvas(data, canvas_size, image_tex_ref, image_w end ------------------------------------------------------------------------------- --- [SECTION] Demo Window / ShowDemoWindow() +-- [SECTION] DemoWindowWidgetsBasic() ------------------------------------------------------------------------------- --- Stored data -local demo_data = ImGuiDemoWindowData() +S.DemoWindowWidgetsBasic = { + clicked = 0, + check = true, + e = 0, + counter = 0, + inputs = { + str0 = ImGui.NewTextBuffer("Hello, world!", 128), + str1 = ImGui.NewTextBuffer("", 128), + i0 = 123, + f0 = 0.001, + d0 = 999999.00000001, + f1 = 1.e10, + vec4a = { 0.10, 0.20, 0.30, 0.44 }, + }, + drags = { i1 = 50, i2 = 42, i3 = 128, f1 = 1.00, f2 = 0.0067 }, + sliders = { i1 = 0, f1 = 0.123, f2 = 0.0, angle = 0.0, elem = 0 }, + pickers = { col1 = { 1.0, 0.0, 0.2 }, col2 = { 0.4, 0.7, 0.0, 0.5 } }, + combo = { item_current = 0 }, + listbox = { item_current = 1 }, +} -local no_titlebar = false -local no_scrollbar = false -local no_menu = false -local no_move = false -local no_resize = false -local no_collapse = false -local no_close = false -local no_nav = false -local no_background = false -local no_bring_to_front = false -local no_docking = false -local unsaved_document = false - ---- Shows an example app: `if X then X.open = X(open) end`. Example apps return the new p_open. -local function RunApp(fn, key, ...) - if fn then - demo_data[key] = fn(demo_data[key], ...) - if demo_data[key] == nil then demo_data[key] = false end - else - demo_data[key] = false - end -end - -local function DemoWindowMenuBar(data) - if ImGui.BeginMenuBar() then - if ImGui.BeginMenu("Menu") then - IMGUI_DEMO_MARKER("Menu/File") - ShowExampleMenuFile() - ImGui.EndMenu() - end - if ImGui.BeginMenu("Examples") then - IMGUI_DEMO_MARKER("Menu/Examples") - _, data.ShowMainMenuBar = ImGui.MenuItem("Main menu bar", nil, data.ShowMainMenuBar) - - ImGui.SeparatorText("Mini apps") - _, data.ShowAppAssetsBrowser = ImGui.MenuItem("Assets Browser", nil, data.ShowAppAssetsBrowser) - _, data.ShowAppConsole = ImGui.MenuItem("Console", nil, data.ShowAppConsole) - _, data.ShowAppCustomRendering = ImGui.MenuItem("Custom rendering", nil, data.ShowAppCustomRendering) - _, data.ShowAppDocuments = ImGui.MenuItem("Documents", nil, data.ShowAppDocuments) - _, data.ShowAppDockSpace = ImGui.MenuItem("Dockspace", nil, data.ShowAppDockSpace) - _, data.ShowAppImageViewer = ImGui.MenuItem("Image Viewer", nil, data.ShowAppImageViewer) - _, data.ShowAppLog = ImGui.MenuItem("Log", nil, data.ShowAppLog) - _, data.ShowAppPropertyEditor = ImGui.MenuItem("Property editor", nil, data.ShowAppPropertyEditor) - _, data.ShowAppLayout = ImGui.MenuItem("Simple layout", nil, data.ShowAppLayout) - _, data.ShowAppSimpleOverlay = ImGui.MenuItem("Simple overlay", nil, data.ShowAppSimpleOverlay) - - ImGui.SeparatorText("Concepts") - _, data.ShowAppAutoResize = ImGui.MenuItem("Auto-resizing window", nil, data.ShowAppAutoResize) - _, data.ShowAppConstrainedResize = ImGui.MenuItem("Constrained-resizing window", nil, data.ShowAppConstrainedResize) - _, data.ShowAppFullscreen = ImGui.MenuItem("Fullscreen window", nil, data.ShowAppFullscreen) - _, data.ShowAppLongText = ImGui.MenuItem("Long text display", nil, data.ShowAppLongText) - _, data.ShowAppWindowTitles = ImGui.MenuItem("Manipulating window titles", nil, data.ShowAppWindowTitles) - - ImGui.EndMenu() - end - -- if ImGui.MenuItem("MenuItem") then end -- You can also use MenuItem() inside a menu bar! - if ImGui.BeginMenu("Tools") then - IMGUI_DEMO_MARKER("Menu/Tools") - local io = ImGui.GetIO() - local has_debug_tools = not IMGUI_DISABLE_DEBUG_TOOLS - _, data.ShowMetrics = ImGui.MenuItem("Metrics/Debugger", nil, data.ShowMetrics, has_debug_tools and ImGui.ShowMetricsWindow ~= nil) - if ImGui.BeginMenu("Debug Options") then - ImGui.BeginDisabled(not has_debug_tools) - _, io.ConfigDebugHighlightIdConflicts = ImGui.Checkbox("Highlight ID Conflicts", io.ConfigDebugHighlightIdConflicts) - ImGui.EndDisabled() - _, io.ConfigErrorRecoveryEnableAssert = ImGui.Checkbox("Assert on error recovery", io.ConfigErrorRecoveryEnableAssert) - ImGui.TextDisabled("(see Demo->Configuration for more)") - ImGui.EndMenu() - end - _, data.ShowDebugLog = ImGui.MenuItem("Debug Log", nil, data.ShowDebugLog, has_debug_tools and ImGui.ShowDebugLogWindow ~= nil) - _, data.ShowIDStackTool = ImGui.MenuItem("ID Stack Tool", nil, data.ShowIDStackTool, has_debug_tools and ImGui.ShowIDStackToolWindow ~= nil) - local is_debugger_present = io.ConfigDebugIsDebuggerPresent - if ImGui.MenuItem("Item Picker", nil, false, has_debug_tools and ImGui.DebugStartItemPicker ~= nil) then -- and is_debugger_present - ImGui.DebugStartItemPicker() - end - if not is_debugger_present then - ImGui.SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application.") - end - _, data.ShowStyleEditor = ImGui.MenuItem("Style Editor", nil, data.ShowStyleEditor) - _, data.ShowAbout = ImGui.MenuItem("About Dear ImGui", nil, data.ShowAbout) - - ImGui.EndMenu() - end - ImGui.EndMenuBar() - end -end - ---- Configuration header contents (split from ShowDemoWindow to keep the function small) -local function DemoWindowConfiguration(io) - local F = ImGuiConfigFlags - local function CF(label, flag) - local pressed - pressed, io.ConfigFlags = ImGui.CheckboxFlags(label, io.ConfigFlags, flag) - return pressed - end - local function CB(label, field) - local pressed - pressed, io[field] = ImGui.Checkbox(label, io[field]) - return pressed - end - local function HM(desc) ImGui.SameLine(); HelpMarker(desc) end - - if ImGui.TreeNode("Configuration##2") then - IMGUI_DEMO_MARKER("Configuration") +function DemoWindowWidgetsBasic() + local _ + if ImGui.TreeNode("Basic") then + local s = S.DemoWindowWidgetsBasic + IMGUI_DEMO_MARKER("Widgets/Basic") ImGui.SeparatorText("General") - CF("io.ConfigFlags: NavEnableKeyboard", F.NavEnableKeyboard) - HM("Enable keyboard controls.") - CF("io.ConfigFlags: NavEnableGamepad", F.NavEnableGamepad) - HM("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.") - CF("io.ConfigFlags: NoMouse", F.NoMouse) - HM("Instruct dear imgui to disable mouse inputs and interactions.") - -- The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: - if DemoHas(io.ConfigFlags, F.NoMouse) then - if (ImGui.GetTime() % 0.40) < 0.20 then + IMGUI_DEMO_MARKER("Widgets/Basic/Button") + if ImGui.Button("Button") then + s.clicked = s.clicked + 1 + end + if bit32.band(s.clicked, 1) ~= 0 then + ImGui.SameLine() + ImGui.Text("Thanks for clicking me!") + end + + IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox") + _, s.check = ImGui.Checkbox("checkbox", s.check) + + IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton") + _, s.e = ImGui.RadioButton("radio a", s.e, 0); ImGui.SameLine() + _, s.e = ImGui.RadioButton("radio b", s.e, 1); ImGui.SameLine() + _, s.e = ImGui.RadioButton("radio c", s.e, 2) + + ImGui.AlignTextToFramePadding() + ImGui.TextLinkOpenURL("Hyperlink", "https://github.com/ocornut/imgui/wiki/Error-Handling") + + -- Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)") + for i = 0, 6 do + if i > 0 then ImGui.SameLine() - ImGui.Text("<>") - end - -- Prevent both being checked - if ImGui.IsKeyPressed(ImGuiKey.Space) or DemoHas(io.ConfigFlags, F.NoKeyboard) then - io.ConfigFlags = bit32.band(io.ConfigFlags, bit32.bnot(F.NoMouse)) end + ImGui.PushID(i) + ImGui.PushStyleColor(ImGuiCol.Button, ImColor.HSV(i / 7.0, 0.6, 0.6).Value) + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, ImColor.HSV(i / 7.0, 0.7, 0.7).Value) + ImGui.PushStyleColor(ImGuiCol.ButtonActive, ImColor.HSV(i / 7.0, 0.8, 0.8).Value) + ImGui.Button("Click") + ImGui.PopStyleColor(3) + ImGui.PopID() end - CF("io.ConfigFlags: NoMouseCursorChange", F.NoMouseCursorChange) - HM("Instruct backend to not alter mouse cursor shape and visibility.") - CF("io.ConfigFlags: NoKeyboard", F.NoKeyboard) - HM("Instruct dear imgui to disable keyboard inputs and interactions.") - - CB("io.ConfigInputTrickleEventQueue", "ConfigInputTrickleEventQueue") - HM("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.") - CB("io.MouseDrawCursor", "MouseDrawCursor") - HM("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).") - - ImGui.SeparatorText("Keyboard/Gamepad Navigation") - CB("io.ConfigNavSwapGamepadButtons", "ConfigNavSwapGamepadButtons") - CB("io.ConfigNavMoveSetMousePos", "ConfigNavMoveSetMousePos") - HM("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult") - CB("io.ConfigNavCaptureKeyboard", "ConfigNavCaptureKeyboard") - CB("io.ConfigNavEscapeClearFocusItem", "ConfigNavEscapeClearFocusItem") - HM("Pressing Escape clears focused item.") - CB("io.ConfigNavEscapeClearFocusWindow", "ConfigNavEscapeClearFocusWindow") - HM("Pressing Escape clears focused window.") - CB("io.ConfigNavCursorVisibleAuto", "ConfigNavCursorVisibleAuto") - HM("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.") - CB("io.ConfigNavCursorVisibleAlways", "ConfigNavCursorVisibleAlways") - HM("Navigation cursor is always visible.") - - ImGui.SeparatorText("Docking") - CF("io.ConfigFlags: DockingEnable", F.DockingEnable) + -- Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements + -- (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) + -- See 'Demo->Layout->Text Baseline Alignment' for details. + ImGui.AlignTextToFramePadding() + ImGui.Text("Hold to repeat:") ImGui.SameLine() - if io.ConfigDockingWithShift then - HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") - else - HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).") - end - if DemoHas(io.ConfigFlags, F.DockingEnable) then - ImGui.Indent() - CB("io.ConfigDockingNoSplit", "ConfigDockingNoSplit") - HM("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.") - CB("io.ConfigDockingNoDockingOver", "ConfigDockingNoDockingOver") - HM("Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows.") - CB("io.ConfigDockingWithShift", "ConfigDockingWithShift") - HM("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)") - CB("io.ConfigDockingAlwaysTabBar", "ConfigDockingAlwaysTabBar") - HM("Create a docking node and tab-bar on single floating windows.") - CB("io.ConfigDockingTransparentPayload", "ConfigDockingTransparentPayload") - HM("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.") - ImGui.Unindent() + + -- Arrow buttons with Repeater + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)") + local spacing = ImGui.GetStyle().ItemInnerSpacing.x + ImGui.PushItemFlag(ImGuiItemFlags.ButtonRepeat, true) + if ImGui.ArrowButton("##left", ImGuiDir.Left) then s.counter = s.counter - 1 end + ImGui.SameLine(0.0, spacing) + if ImGui.ArrowButton("##right", ImGuiDir.Right) then s.counter = s.counter + 1 end + ImGui.PopItemFlag() + ImGui.SameLine() + ImGui.Text("%d", s.counter) + + ImGui.Button("Tooltip") + ImGui.SetItemTooltip("I am a tooltip") + + ImGui.LabelText("label", "Value") + + ImGui.SeparatorText("Inputs") + + do + local s = S.DemoWindowWidgetsBasic.inputs + -- If you want to use InputText() with std::string or any custom dynamic string type: + -- - For std::string: use the wrapper in misc/cpp/imgui_stdlib.h/.cpp + -- - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize. + IMGUI_DEMO_MARKER("Widgets/Basic/InputText") + ImGui.InputText("input text", s.str0, 128) + ImGui.SameLine(); HelpMarker( + "USER:\n" .. + "Hold Shift or use mouse to select text.\n" .. + "Ctrl+Left/Right to word jump.\n" .. + "Ctrl+A or Double-Click to select all.\n" .. + "Ctrl+X,Ctrl+C,Ctrl+V for clipboard.\n" .. + "Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.\n" .. + "Escape to revert.\n\n" .. + "PROGRAMMER:\n" .. + "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " .. + "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " .. + "in imgui_demo.cpp).") + + ImGui.InputTextWithHint("input text (w/ hint)", "enter text here", s.str1, 128) + + IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat") + s.i0 = ImGui.InputInt("input int", s.i0) + + s.f0 = ImGui.InputFloat("input float", s.f0, 0.01, 1.0, "%.3f") + + s.d0 = ImGui.InputDouble("input double", s.d0, 0.01, 1.0, "%.8f") + + s.f1 = ImGui.InputFloat("input scientific", s.f1, 0.0, 0.0, "%e") + ImGui.SameLine(); HelpMarker( + "You can input value using the scientific notation,\n" .. + " e.g. \"1e+8\" becomes \"100000000\".") + + ImGui.InputFloat3("input float3", s.vec4a) end - ImGui.SeparatorText("Multi-viewports") - CF("io.ConfigFlags: ViewportsEnable", F.ViewportsEnable) - HM("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.") - if DemoHas(io.ConfigFlags, F.ViewportsEnable) then - ImGui.Indent() - DemoNotSupported() - ImGui.Unindent() + ImGui.SeparatorText("Drags") + + do + local s = S.DemoWindowWidgetsBasic.drags + IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat") + s.i1 = ImGui.DragInt("drag int", s.i1, 1) + ImGui.SameLine(); HelpMarker( + "Click and drag to edit value.\n" .. + "Hold Shift/Alt for faster/slower edit.\n" .. + "Double-Click or Ctrl+Click to input value.") + s.i2 = ImGui.DragInt("drag int 0..100", s.i2, 1, 0, 100, "%d%%", ImGuiSliderFlags.AlwaysClamp) + s.i3 = ImGui.DragInt("drag int wrap 100..200", s.i3, 1, 100, 200, "%d", ImGuiSliderFlags.WrapAround) + + s.f1 = ImGui.DragFloat("drag float", s.f1, 0.005) + s.f2 = ImGui.DragFloat("drag small float", s.f2, 0.0001, 0.0, 0.0, "%.06f ns") + --ImGui.DragFloat("drag wrap -1..1", f3, 0.005, -1.0, 1.0, nil, ImGuiSliderFlags.WrapAround) end - -- ImGui.SeparatorText("DPI/Scaling") - -- CB("io.ConfigDpiScaleFonts", "ConfigDpiScaleFonts") - -- HM("Experimental: Automatically update style.FontScaleDpi when Monitor DPI changes. This will scale fonts but NOT style sizes/padding for now.") - -- CB("io.ConfigDpiScaleViewports", "ConfigDpiScaleViewports") - -- HM("Experimental: Scale Dear ImGui and Platform Windows when Monitor DPI changes.") + ImGui.SeparatorText("Sliders") - ImGui.SeparatorText("Windows") - CB("io.ConfigWindowsResizeFromEdges", "ConfigWindowsResizeFromEdges") - HM("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.") - CB("io.ConfigWindowsMoveFromTitleBarOnly", "ConfigWindowsMoveFromTitleBarOnly") - CB("io.ConfigWindowsCopyContentsWithCtrlC", "ConfigWindowsCopyContentsWithCtrlC") -- [EXPERIMENTAL] - HM("*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.") - CB("io.ConfigScrollbarScrollByPage", "ConfigScrollbarScrollByPage") - HM("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.") + do + local s = S.DemoWindowWidgetsBasic.sliders + IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat") + s.i1 = ImGui.SliderInt("slider int", s.i1, -1, 3) + ImGui.SameLine(); HelpMarker("Ctrl+Click to input value.") - ImGui.SeparatorText("Widgets") - CB("io.ConfigInputTextCursorBlink", "ConfigInputTextCursorBlink") - HM("Enable blinking cursor (optional as some users consider it to be distracting).") - CB("io.ConfigInputTextEnterKeepActive", "ConfigInputTextEnterKeepActive") - HM("Pressing Enter will reactivate item and select all text (single-line only).") - CB("io.ConfigDragClickToInputText", "ConfigDragClickToInputText") - HM("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).") - CB("io.ConfigMacOSXBehaviors", "ConfigMacOSXBehaviors") - HM("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.") - ImGui.Text("Also see Style->Rendering for rendering options.") + s.f1 = ImGui.SliderFloat("slider float", s.f1, 0.0, 1.0, "ratio = %.3f") + s.f2 = ImGui.SliderFloat("slider float (log)", s.f2, -10.0, 10.0, "%.4f", ImGuiSliderFlags.Logarithmic) - ImGui.SeparatorText("Settings") - CB("io.ConfigIniSettingsSaveLastUsedDate", "ConfigIniSettingsSaveLastUsedDate") + IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle") + s.angle = ImGui.SliderAngle("slider angle", s.angle) - -- Also read: https://github.com/ocornut/imgui/wiki/Error-Handling - ImGui.SeparatorText("Error Handling") - - CB("io.ConfigErrorRecovery", "ConfigErrorRecovery") - HM( - "Options to configure how we handle recoverable errors.\n" .. - "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n" .. - "- You not are not supposed to rely on it in the course of a normal application run.\n" .. - "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n" .. - "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call! " .. - "Otherwise it would severely hinder your ability to catch and correct mistakes!") - CB("io.ConfigErrorRecoveryEnableAssert", "ConfigErrorRecoveryEnableAssert") - CB("io.ConfigErrorRecoveryEnableDebugLog", "ConfigErrorRecoveryEnableDebugLog") - CB("io.ConfigErrorRecoveryEnableTooltip", "ConfigErrorRecoveryEnableTooltip") - if not io.ConfigErrorRecoveryEnableAssert and not io.ConfigErrorRecoveryEnableDebugLog and not io.ConfigErrorRecoveryEnableTooltip then - io.ConfigErrorRecoveryEnableAssert = true - io.ConfigErrorRecoveryEnableDebugLog = true - io.ConfigErrorRecoveryEnableTooltip = true + -- Using the format string to display a name instead of an integer. + -- Here we completely omit '%d' from the format string, so it'll only display a name. + -- This technique can also be used with DragInt(). + IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)") + local Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT = 0, 1, 2, 3, 4 + local elems_names = { "Fire", "Earth", "Air", "Water" } + local elem_name = (s.elem >= 0 and s.elem < Element_COUNT) and elems_names[s.elem + 1] or "Unknown" + s.elem = ImGui.SliderInt("slider enum", s.elem, 0, Element_COUNT - 1, elem_name) -- Use ImGuiSliderFlags_NoInput flag to disable Ctrl+Click here. + ImGui.SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.") end - -- Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools - ImGui.SeparatorText("Debug") - CB("io.ConfigDebugIsDebuggerPresent", "ConfigDebugIsDebuggerPresent") - HM("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.") - CB("io.ConfigDebugHighlightIdConflicts", "ConfigDebugHighlightIdConflicts") - HM("Highlight and show an error message when multiple items have conflicting identifiers.") - ImGui.BeginDisabled() - CB("io.ConfigDebugBeginReturnValueOnce", "ConfigDebugBeginReturnValueOnce") - ImGui.EndDisabled() - HM("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.") - CB("io.ConfigDebugBeginReturnValueLoop", "ConfigDebugBeginReturnValueLoop") - HM("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.") - CB("io.ConfigDebugIgnoreFocusLoss", "ConfigDebugIgnoreFocusLoss") - HM("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.") - CB("io.ConfigDebugDrawListDefaultsToStrokeLegacy", "ConfigDebugDrawListDefaultsToStrokeLegacy") - HM("Option to default all ImDrawList to ImDrawFlags_StrokeLegacy mode, mimicking pre-1.93.0 rendering.") - CB("io.ConfigDebugIniSettings", "ConfigDebugIniSettings") - HM("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).") + ImGui.SeparatorText("Selectors/Pickers") + + do + local s = S.DemoWindowWidgetsBasic.pickers + IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4") + ImGui.ColorEdit3("color 1", s.col1) + ImGui.SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" .. + "Click and hold to use drag and drop.\n" .. + "Right-Click on the color square to show options.\n" .. + "Ctrl+Click on individual component to input value.\n") + + ImGui.ColorEdit4("color 2", s.col2) + end + + do + local s = S.DemoWindowWidgetsBasic.combo + -- Using the _simplified_ one-liner Combo() api here + -- See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. + IMGUI_DEMO_MARKER("Widgets/Basic/Combo") + local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" } + s.item_current = ImGui.Combo("combo", s.item_current, items, #items) + ImGui.SameLine(); HelpMarker( + "Using the simplified one-liner Combo API here.\n" .. + "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.") + end + + do + local s = S.DemoWindowWidgetsBasic.listbox + -- Using the _simplified_ one-liner ListBox() api here + -- See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. + IMGUI_DEMO_MARKER("Widgets/Basic/ListBox") + local items = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" } + s.item_current = ImGui.ListBox("listbox", s.item_current, items, #items, 4) + ImGui.SameLine(); HelpMarker( + "Using the simplified one-liner ListBox API here.\n" .. + "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.") + end + + -- Testing ImGuiOnceUponAFrame helper. + --static ImGuiOnceUponAFrame once; + --for (int i = 0; i < 5; i++) + -- if (once) + -- ImGui.Text("This will be displayed only once."); ImGui.TreePop() - ImGui.Spacing() end +end - if ImGui.TreeNode("Backend Flags") then - IMGUI_DEMO_MARKER("Configuration/Backend Flags") - HelpMarker( - "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" .. - "Here we expose them as read-only fields to avoid breaking interactions with your backend.") +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsBullets() +------------------------------------------------------------------------------- - -- Make a local copy to avoid modifying actual backend flags. - -- FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright? - local B = ImGuiBackendFlags - local backend_flags = io.BackendFlags - ImGui.BeginDisabled() - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasGamepad", backend_flags, B.HasGamepad) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseCursors", backend_flags, B.HasMouseCursors) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasSetMousePos", backend_flags, B.HasSetMousePos) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: PlatformHasViewports", backend_flags, B.PlatformHasViewports) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport", backend_flags, B.HasMouseHoveredViewport) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: HasParentViewport", backend_flags, B.HasParentViewport) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", backend_flags, B.RendererHasVtxOffset) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasTextures", backend_flags, B.RendererHasTextures) - _, backend_flags = ImGui.CheckboxFlags("io.BackendFlags: RendererHasViewports", backend_flags, B.RendererHasViewports) +function DemoWindowWidgetsBullets() + if ImGui.TreeNode("Bullets") then + IMGUI_DEMO_MARKER("Widgets/Bullets") + ImGui.BulletText("Bullet point 1") + ImGui.BulletText("Bullet point 2\nOn multiple lines") + if ImGui.TreeNode("Tree node") then + ImGui.BulletText("Another bullet point") + ImGui.TreePop() + end + ImGui.Bullet(); ImGui.Text("Bullet point 3 (two calls)") + ImGui.Bullet(); ImGui.SmallButton("Button") + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsCollapsingHeaders() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsCollapsingHeaders = { + closable_group = true, +} + +function DemoWindowWidgetsCollapsingHeaders() + local _ + if ImGui.TreeNode("Collapsing Headers") then + local s = S.DemoWindowWidgetsCollapsingHeaders + IMGUI_DEMO_MARKER("Widgets/Collapsing Headers") + _, s.closable_group = ImGui.Checkbox("Show 2nd header", s.closable_group) + if ImGui.CollapsingHeader("Header", ImGuiTreeNodeFlags.None) then + ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) + for i = 0, 4 do + ImGui.Text("Some content %d", i) + end + end + local open + open, s.closable_group = ImGui.CollapsingHeader("Header with a close button", s.closable_group) + if open then + ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) + for i = 0, 4 do + ImGui.Text("More content %d", i) + end + end + --[[ + if ImGui.CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags.Bullet) then + ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered()) + end + ]] + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsColorAndPickers() +------------------------------------------------------------------------------- + +-- [Port] the library does not define the standard color payload types (ColorButton drag source is not ported yet) +IMGUI_PAYLOAD_TYPE_COLOR_3F = IMGUI_PAYLOAD_TYPE_COLOR_3F or "_COL3F" +IMGUI_PAYLOAD_TYPE_COLOR_4F = IMGUI_PAYLOAD_TYPE_COLOR_4F or "_COL4F" + +S.DemoWindowWidgetsColorAndPickers = { + color = ImVec4(114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 200.0 / 255.0), + base_flags = ImGuiColorEditFlags.None, + saved_palette_init = true, + saved_palette = {}, -- 32 x ImVec4, 1-based + backup_color = ImVec4(), + no_border = false, + ref_color = false, + ref_color_v = ImVec4(1.0, 0.0, 1.0, 0.5), + picker_mode = 0, + display_mode = 0, + color_picker_flags = ImGuiColorEditFlags.AlphaBar, + color_hsv = ImVec4(0.23, 1.0, 1.0, 1.0), -- Stored as HSV! +} + +function DemoWindowWidgetsColorAndPickers() + local _ + if ImGui.TreeNode("Color/Picker Widgets") then + local s = S.DemoWindowWidgetsColorAndPickers + IMGUI_DEMO_MARKER("Widgets/Color") + local color = s.color + + ImGui.SeparatorText("Options") + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.base_flags, ImGuiColorEditFlags.NoAlpha) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", s.base_flags, ImGuiColorEditFlags.AlphaOpaque) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", s.base_flags, ImGuiColorEditFlags.AlphaNoBg) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", s.base_flags, ImGuiColorEditFlags.AlphaPreviewHalf) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoOptions", s.base_flags, ImGuiColorEditFlags.NoOptions); ImGui.SameLine(); HelpMarker("Right-click on the individual color widget to show options.") + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", s.base_flags, ImGuiColorEditFlags.NoDragDrop) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoColorMarkers", s.base_flags, ImGuiColorEditFlags.NoColorMarkers) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_HDR", s.base_flags, ImGuiColorEditFlags.HDR); ImGui.SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.") + local base_flags = s.base_flags + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit") + ImGui.SeparatorText("Inline color editor") + ImGui.Text("Color widget:") + ImGui.SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" .. + "Ctrl+Click on individual component to input value.\n") + ImGui.ColorEdit3("MyColor##1", color, base_flags) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)") + ImGui.Text("Color widget HSV with Alpha:") + ImGui.ColorEdit4("MyColor##2", color, bit32.bor(ImGuiColorEditFlags.DisplayHSV, base_flags)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)") + ImGui.Text("Color widget with Float Display:") + ImGui.ColorEdit4("MyColor##2f", color, bit32.bor(ImGuiColorEditFlags.Float, base_flags)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)") + ImGui.Text("Color button with Picker:") + ImGui.SameLine(); HelpMarker( + "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" .. + "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " .. + "be used for the tooltip and picker popup.") + ImGui.ColorEdit4("MyColor##3", color, bit32.bor(ImGuiColorEditFlags.NoInputs, ImGuiColorEditFlags.NoLabel, base_flags)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)") + ImGui.Text("Color button with Custom Picker Popup:") + + -- Generate a default palette. The palette will persist and can be edited. + local saved_palette = s.saved_palette + if s.saved_palette_init then + for n = 0, 32 - 1 do + saved_palette[n + 1] = ImVec4() + saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z = ImGui.ColorConvertHSVtoRGB(n / 31.0, 0.8, 0.8) + saved_palette[n + 1].w = 1.0 -- Alpha + end + s.saved_palette_init = false + end + + local open_popup = ImGui.ColorButton("MyColor##3b", color, base_flags) + ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.x) + open_popup = ImGui.Button("Palette") or open_popup + if open_popup then + ImGui.OpenPopup("mypicker") + ImVec4_Copy(s.backup_color, color) + end + if ImGui.BeginPopup("mypicker") then + ImGui.Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!") + ImGui.Separator() + ImGui.ColorPicker4("##picker", color, bit32.bor(base_flags, ImGuiColorEditFlags.NoSidePreview, ImGuiColorEditFlags.NoSmallPreview)) + ImGui.SameLine() + + ImGui.BeginGroup() -- Lock X position + ImGui.Text("Current") + ImGui.ColorButton("##current", color, bit32.bor(ImGuiColorEditFlags.NoPicker, ImGuiColorEditFlags.AlphaPreviewHalf), ImVec2(60, 40)) + ImGui.Text("Previous") + if ImGui.ColorButton("##previous", s.backup_color, bit32.bor(ImGuiColorEditFlags.NoPicker, ImGuiColorEditFlags.AlphaPreviewHalf), ImVec2(60, 40)) then + ImVec4_Copy(color, s.backup_color) + end + ImGui.Separator() + ImGui.Text("Palette") + for n = 0, #saved_palette - 1 do + ImGui.PushID(n) + if (n % 8) ~= 0 then + ImGui.SameLine(0.0, ImGui.GetStyle().ItemSpacing.y) + end + + local palette_button_flags = bit32.bor(ImGuiColorEditFlags.NoAlpha, ImGuiColorEditFlags.NoPicker, ImGuiColorEditFlags.NoTooltip) + if ImGui.ColorButton("##palette", saved_palette[n + 1], palette_button_flags, ImVec2(20, 20)) then + color.x, color.y, color.z = saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z -- Preserve alpha! + end + + -- Allow user to drop colors into each palette entry. Note that ColorButton() is already a + -- drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. + if ImGui.BeginDragDropTarget() then + local payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F) + if payload then + local d = payload.Data -- [Port] memcpy -> copy components (Data is a 1-based float array or ImVec4) + saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z = d[1], d[2], d[3] + end + payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F) + if payload then + local d = payload.Data -- [Port] memcpy -> copy components + saved_palette[n + 1].x, saved_palette[n + 1].y, saved_palette[n + 1].z, saved_palette[n + 1].w = d[1], d[2], d[3], d[4] + end + ImGui.EndDragDropTarget() + end + + ImGui.PopID() + end + ImGui.EndGroup() + ImGui.EndPopup() + end + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)") + ImGui.Text("Color button only:") + _, s.no_border = ImGui.Checkbox("ImGuiColorEditFlags_NoBorder", s.no_border) + ImGui.ColorButton("MyColor##3c", color, bit32.bor(base_flags, s.no_border and ImGuiColorEditFlags.NoBorder or 0), ImVec2(80, 80)) + + IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker") + ImGui.SeparatorText("Color picker") + + ImGui.PushID("Color picker") + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.color_picker_flags, ImGuiColorEditFlags.NoAlpha) + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaBar", s.color_picker_flags, ImGuiColorEditFlags.AlphaBar) + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", s.color_picker_flags, ImGuiColorEditFlags.NoSidePreview) + if bit32.band(s.color_picker_flags, ImGuiColorEditFlags.NoSidePreview) ~= 0 then + ImGui.SameLine() + _, s.ref_color = ImGui.Checkbox("With Ref Color", s.ref_color) + if s.ref_color then + ImGui.SameLine() + ImGui.ColorEdit4("##RefColor", s.ref_color_v, bit32.bor(ImGuiColorEditFlags.NoInputs, base_flags)) + end + end + _, s.color_picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_PickerNoRotate", s.color_picker_flags, ImGuiColorEditFlags.PickerNoRotate) + + s.picker_mode = ImGui.Combo("Picker Mode", s.picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0") + ImGui.SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode.") + + s.display_mode = ImGui.Combo("Display Mode", s.display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0") + ImGui.SameLine(); HelpMarker( + "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " .. + "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex " .. + "if you don't specify a display mode.\n\nYou can change the defaults using io.ConfigColorEditFlags.") + + local flags = bit32.bor(base_flags, s.color_picker_flags) + if s.picker_mode == 1 then flags = bit32.bor(flags, ImGuiColorEditFlags.PickerHueBar) end + if s.picker_mode == 2 then flags = bit32.bor(flags, ImGuiColorEditFlags.PickerHueWheel) end + if s.display_mode == 1 then flags = bit32.bor(flags, ImGuiColorEditFlags.NoInputs) end -- Disable all RGB/HSV/Hex displays + if s.display_mode == 2 then flags = bit32.bor(flags, ImGuiColorEditFlags.DisplayRGB) end -- Override display mode + if s.display_mode == 3 then flags = bit32.bor(flags, ImGuiColorEditFlags.DisplayHSV) end + if s.display_mode == 4 then flags = bit32.bor(flags, ImGuiColorEditFlags.DisplayHex) end + ImGui.ColorPicker4("MyColor##4", color, flags, s.ref_color and s.ref_color_v or nil) + + ImGui.Text("Set defaults in code:") + ImGui.SameLine(); HelpMarker( + "io.ConfigColorEditFlags is designed to allow you to set boot-time default.\n" .. + "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " .. + "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " .. + "encouraging you to persistently save values that aren't forward-compatible.") + if ImGui.Button("Overwrite default: Uint8 + HSV + Hue Bar") then + ImGui.GetIO().ConfigColorEditFlags = bit32.bor(ImGuiColorEditFlags.Uint8, ImGuiColorEditFlags.DisplayHSV, ImGuiColorEditFlags.PickerHueBar, ImGuiColorEditFlags.InputRGB) -- [Port] + InputRGB: without it ColorEdit4's InputMask_ power-of-two assert trips + end + if ImGui.Button("Overwrite default: Float + HDR + Hue Wheel") then + ImGui.GetIO().ConfigColorEditFlags = bit32.bor(ImGuiColorEditFlags.Float, ImGuiColorEditFlags.HDR, ImGuiColorEditFlags.PickerHueWheel, ImGuiColorEditFlags.DisplayRGB, ImGuiColorEditFlags.InputRGB) -- [Port] + DisplayRGB + InputRGB: same asserts (DisplayMask_/InputMask_) + end + + -- Always display a small version of both types of pickers + -- (that's in order to make it more visible in the demo to people who are skimming quickly through it) + ImGui.Text("Both types:") + local w = (ImGui.GetContentRegionAvail().x - ImGui.GetStyle().ItemSpacing.y) * 0.40 + ImGui.SetNextItemWidth(w) + ImGui.ColorPicker3("##MyColor##5", color, bit32.bor(ImGuiColorEditFlags.PickerHueBar, ImGuiColorEditFlags.NoSidePreview, ImGuiColorEditFlags.NoInputs, ImGuiColorEditFlags.NoAlpha)) + ImGui.SameLine() + ImGui.SetNextItemWidth(w) + ImGui.ColorPicker3("##MyColor##6", color, bit32.bor(ImGuiColorEditFlags.PickerHueWheel, ImGuiColorEditFlags.NoSidePreview, ImGuiColorEditFlags.NoInputs, ImGuiColorEditFlags.NoAlpha)) + ImGui.PopID() + + -- HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) + local color_hsv = s.color_hsv -- Stored as HSV! + ImGui.Spacing() + ImGui.Text("HSV encoded colors") + ImGui.SameLine(); HelpMarker( + "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV " .. + "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the " .. + "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.") + ImGui.Text("Color widget with InputHSV:") + ImGui.ColorEdit4("HSV shown as RGB##1", color_hsv, bit32.bor(ImGuiColorEditFlags.DisplayRGB, ImGuiColorEditFlags.InputHSV, ImGuiColorEditFlags.Float)) + ImGui.ColorEdit4("HSV shown as HSV##1", color_hsv, bit32.bor(ImGuiColorEditFlags.DisplayHSV, ImGuiColorEditFlags.InputHSV, ImGuiColorEditFlags.Float)) + ImGui.DragFloat4("Raw HSV values", color_hsv, 0.01, 0.0, 1.0) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsComboBoxes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsComboBoxes = { + flags = 0, + item_selected_idx = 0, -- Here we store our selection data as an index. + filter = nil, -- ImGuiTextFilter, created lazily + item_current_2 = 0, + item_current_3 = -1, -- If the selection isn't within 0..count, Combo won't display a preview + item_current_4 = 0, +} + +function DemoWindowWidgetsComboBoxes() + local _, pressed + if ImGui.TreeNode("Combo") then + local s = S.DemoWindowWidgetsComboBoxes + IMGUI_DEMO_MARKER("Widgets/Combo") + -- Combo Boxes are also called "Dropdown" in other systems + -- Expose flags as checkbox for the demo + _, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", s.flags, ImGuiComboFlags.PopupAlignLeft) + ImGui.SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo") + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoArrowButton", s.flags, ImGuiComboFlags.NoArrowButton) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(ImGuiComboFlags.NoPreview)) -- Clear incompatible flags + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoPreview", s.flags, ImGuiComboFlags.NoPreview) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.bor(ImGuiComboFlags.NoArrowButton, ImGuiComboFlags.WidthFitPreview))) -- Clear incompatible flags + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_WidthFitPreview", s.flags, ImGuiComboFlags.WidthFitPreview) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(ImGuiComboFlags.NoPreview)) + end + + -- Override default popup height + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_HeightSmall", s.flags, ImGuiComboFlags.HeightSmall) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(ImGuiComboFlags.HeightMask_, bit32.bnot(ImGuiComboFlags.HeightSmall)))) + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_HeightRegular", s.flags, ImGuiComboFlags.HeightRegular) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(ImGuiComboFlags.HeightMask_, bit32.bnot(ImGuiComboFlags.HeightRegular)))) + end + pressed, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_HeightLargest", s.flags, ImGuiComboFlags.HeightLargest) + if pressed then + s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(ImGuiComboFlags.HeightMask_, bit32.bnot(ImGuiComboFlags.HeightLargest)))) + end + + -- Using the generic BeginCombo() API, you have full control over how to display the combo contents. + -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + -- stored in the object itself, etc.) + local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } + + -- Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) + local combo_preview_value = items[s.item_selected_idx + 1] + if ImGui.BeginCombo("combo 1", combo_preview_value, s.flags) then + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + if ImGui.Selectable(items[n + 1], is_selected) then + s.item_selected_idx = n + end + + -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if is_selected then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndCombo() + end + + -- Show case embedding a filter using a simple trick: displaying the filter inside combo contents. + -- See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives. + if ImGui.BeginCombo("combo 2 (w/ filter)", combo_preview_value, s.flags) then + if s.filter == nil then s.filter = ImGuiTextFilter() end + local filter = s.filter + if ImGui.IsWindowAppearing() then + ImGui.SetKeyboardFocusHere() + filter:Clear() + end + ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.F)) + ImGui.SetNextItemWidth(-FLT_MIN) + filter:DrawWithHint("##Filter", "Filter (incl -excl)") + + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + if filter:PassFilter(items[n + 1]) then + if ImGui.Selectable(items[n + 1], is_selected) then + s.item_selected_idx = n + end + end + end + ImGui.EndCombo() + end + + ImGui.Spacing() + ImGui.SeparatorText("One-liner variants") + HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section.") + + -- Simplified one-liner Combo() API, using values packed in a single constant string + -- This is a convenience for when the selection set is small and known at compile-time. + s.item_current_2 = ImGui.Combo("combo 3 (one-liner)", s.item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0") + + -- Simplified one-liner Combo() using an array of const char* + -- This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. + s.item_current_3 = ImGui.Combo("combo 4 (array)", s.item_current_3, items, #items) + + -- Simplified one-liner Combo() using an accessor function + s.item_current_4 = ImGui.Combo("combo 5 (function)", s.item_current_4, function(data, n) return data[n + 1] end, items, #items) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDataTypes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsDataTypes = { + -- State + s8_v = 127, + u8_v = 255, + s16_v = 32767, + u16_v = 65535, + s32_v = -1, + u32_v = 4294967295, -- (ImU32)-1 + -- [Port] s64_v / u64_v: 64-bit integer types are not supported (Lua numbers are doubles) + f32_v = 0.123, + f64_v = 90000.01234567890123456789, + drag_clamp = false, + inputs_step = true, + flags = ImGuiInputTextFlags.None, +} + +function DemoWindowWidgetsDataTypes() + local _ + if ImGui.TreeNode("Data Types") then + local s = S.DemoWindowWidgetsDataTypes + IMGUI_DEMO_MARKER("Widgets/Data Types") + -- DragScalar/InputScalar/SliderScalar functions allow various data types + -- - signed/unsigned + -- - 8/16/32/64-bits + -- - integer/float/double + -- To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum + -- to pass the type, and passing all arguments by pointer. + -- This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type. + -- In practice, if you frequently use a given type that is not covered by the normal API entry points, + -- you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, + -- and then pass their address to the generic function. For example: + -- bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") + -- { + -- return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); + -- } + -- [Port] in this port the value is passed and returned by value: `v = ImGui.SliderScalar(label, data_type, v, min, max, format)` + + -- Setup limits (as helper variables so we can take their address, as explained above) + -- Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. + -- [Port] LLONG_MIN/LLONG_MAX/ULLONG_MAX fallback block dropped: no 64-bit integer types + local s8_zero, s8_one, s8_fifty, s8_min, s8_max = 0, 1, 50, -128, 127 + local u8_zero, u8_one, u8_fifty, u8_min, u8_max = 0, 1, 50, 0, 255 + local s16_zero, s16_one, s16_fifty, s16_min, s16_max = 0, 1, 50, -32768, 32767 + local u16_zero, u16_one, u16_fifty, u16_min, u16_max = 0, 1, 50, 0, 65535 + local s32_zero, s32_one, s32_fifty, s32_min, s32_max, s32_hi_a, s32_hi_b = 0, 1, 50, -1073741824, 1073741823, 1073741823 - 100, 1073741823 -- INT_MIN/2, INT_MAX/2 + local u32_zero, u32_one, u32_fifty, u32_min, u32_max, u32_hi_a, u32_hi_b = 0, 1, 50, 0, 2147483647, 2147483647 - 100, 2147483647 -- UINT_MAX/2 + -- [Port] s64_* / u64_* limits: ImGuiDataType.S64/U64 are not supported + local f32_zero, f32_one, f32_lo_a, f32_hi_a = 0.0, 1.0, -10000000000.0, 10000000000.0 + local f64_zero, f64_one, f64_lo_a, f64_hi_a = 0.0, 1.0, -1000000000000000.0, 1000000000000000.0 + + -- State + -- (see S.DemoWindowWidgetsDataTypes) + + local drag_speed = 0.2 + IMGUI_DEMO_MARKER("Widgets/Data Types/Drags") + ImGui.SeparatorText("Drags") + _, s.drag_clamp = ImGui.Checkbox("Clamp integers to 0..50", s.drag_clamp) + ImGui.SameLine(); HelpMarker( + "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" .. + "You can override the clamping limits by using Ctrl+Click to input a value.") + local drag_clamp = s.drag_clamp + s.s8_v = ImGui.DragScalar("drag s8", ImGuiDataType.S8, s.s8_v, drag_speed, drag_clamp and s8_zero or nil, drag_clamp and s8_fifty or nil) + s.u8_v = ImGui.DragScalar("drag u8", ImGuiDataType.U8, s.u8_v, drag_speed, drag_clamp and u8_zero or nil, drag_clamp and u8_fifty or nil, "%u ms") + s.s16_v = ImGui.DragScalar("drag s16", ImGuiDataType.S16, s.s16_v, drag_speed, drag_clamp and s16_zero or nil, drag_clamp and s16_fifty or nil) + s.u16_v = ImGui.DragScalar("drag u16", ImGuiDataType.U16, s.u16_v, drag_speed, drag_clamp and u16_zero or nil, drag_clamp and u16_fifty or nil, "%u ms") + s.s32_v = ImGui.DragScalar("drag s32", ImGuiDataType.S32, s.s32_v, drag_speed, drag_clamp and s32_zero or nil, drag_clamp and s32_fifty or nil) + s.s32_v = ImGui.DragScalar("drag s32 hex", ImGuiDataType.S32, s.s32_v, drag_speed, drag_clamp and s32_zero or nil, drag_clamp and s32_fifty or nil, "0x%08X") + s.u32_v = ImGui.DragScalar("drag u32", ImGuiDataType.U32, s.u32_v, drag_speed, drag_clamp and u32_zero or nil, drag_clamp and u32_fifty or nil, "%u ms") + -- [Port] ImGui.DragScalar("drag s64", ImGuiDataType.S64, s64_v, ...) -- 64-bit types not supported + -- [Port] ImGui.DragScalar("drag u64", ImGuiDataType.U64, u64_v, ...) -- 64-bit types not supported + s.f32_v = ImGui.DragScalar("drag float", ImGuiDataType.Float, s.f32_v, 0.005, f32_zero, f32_one, "%f") + s.f32_v = ImGui.DragScalar("drag float log", ImGuiDataType.Float, s.f32_v, 0.005, f32_zero, f32_one, "%f", ImGuiSliderFlags.Logarithmic) + s.f64_v = ImGui.DragScalar("drag double", ImGuiDataType.Double, s.f64_v, 0.0005, f64_zero, nil, "%.10f grams") + s.f64_v = ImGui.DragScalar("drag double log",ImGuiDataType.Double, s.f64_v, 0.0005, f64_zero, f64_one, "0 < %.10f < 1", ImGuiSliderFlags.Logarithmic) + + IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders") + ImGui.SeparatorText("Sliders") + s.s8_v = ImGui.SliderScalar("slider s8 full", ImGuiDataType.S8, s.s8_v, s8_min, s8_max, "%d") + s.u8_v = ImGui.SliderScalar("slider u8 full", ImGuiDataType.U8, s.u8_v, u8_min, u8_max, "%u") + s.s16_v = ImGui.SliderScalar("slider s16 full", ImGuiDataType.S16, s.s16_v, s16_min, s16_max, "%d") + s.u16_v = ImGui.SliderScalar("slider u16 full", ImGuiDataType.U16, s.u16_v, u16_min, u16_max, "%u") + s.s32_v = ImGui.SliderScalar("slider s32 low", ImGuiDataType.S32, s.s32_v, s32_zero, s32_fifty,"%d") + s.s32_v = ImGui.SliderScalar("slider s32 high", ImGuiDataType.S32, s.s32_v, s32_hi_a, s32_hi_b, "%d") + s.s32_v = ImGui.SliderScalar("slider s32 full", ImGuiDataType.S32, s.s32_v, s32_min, s32_max, "%d") + s.s32_v = ImGui.SliderScalar("slider s32 hex", ImGuiDataType.S32, s.s32_v, s32_zero, s32_fifty, "0x%04X") + s.u32_v = ImGui.SliderScalar("slider u32 low", ImGuiDataType.U32, s.u32_v, u32_zero, u32_fifty,"%u") + s.u32_v = ImGui.SliderScalar("slider u32 high", ImGuiDataType.U32, s.u32_v, u32_hi_a, u32_hi_b, "%u") + s.u32_v = ImGui.SliderScalar("slider u32 full", ImGuiDataType.U32, s.u32_v, u32_min, u32_max, "%u") + -- [Port] "slider s64 low" / "slider s64 high" / "slider s64 full" (ImGuiDataType.S64): 64-bit types not supported + -- [Port] "slider u64 low" / "slider u64 high" / "slider u64 full" (ImGuiDataType.U64): 64-bit types not supported + s.f32_v = ImGui.SliderScalar("slider float low", ImGuiDataType.Float, s.f32_v, f32_zero, f32_one) + s.f32_v = ImGui.SliderScalar("slider float low log", ImGuiDataType.Float, s.f32_v, f32_zero, f32_one, "%.10f", ImGuiSliderFlags.Logarithmic) + s.f32_v = ImGui.SliderScalar("slider float high", ImGuiDataType.Float, s.f32_v, f32_lo_a, f32_hi_a, "%e") + s.f64_v = ImGui.SliderScalar("slider double low", ImGuiDataType.Double, s.f64_v, f64_zero, f64_one, "%.10f grams") + s.f64_v = ImGui.SliderScalar("slider double low log",ImGuiDataType.Double, s.f64_v, f64_zero, f64_one, "%.10f", ImGuiSliderFlags.Logarithmic) + s.f64_v = ImGui.SliderScalar("slider double high", ImGuiDataType.Double, s.f64_v, f64_lo_a, f64_hi_a, "%e grams") + + ImGui.SeparatorText("Sliders (reverse)") + s.s8_v = ImGui.SliderScalar("slider s8 reverse", ImGuiDataType.S8, s.s8_v, s8_max, s8_min, "%d") + s.u8_v = ImGui.SliderScalar("slider u8 reverse", ImGuiDataType.U8, s.u8_v, u8_max, u8_min, "%u") + s.s32_v = ImGui.SliderScalar("slider s32 reverse", ImGuiDataType.S32, s.s32_v, s32_fifty, s32_zero, "%d") + s.u32_v = ImGui.SliderScalar("slider u32 reverse", ImGuiDataType.U32, s.u32_v, u32_fifty, u32_zero, "%u") + -- [Port] "slider s64 reverse" / "slider u64 reverse": 64-bit types not supported + + IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs") + ImGui.SeparatorText("Inputs") + _, s.inputs_step = ImGui.Checkbox("Show step buttons", s.inputs_step) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, ImGuiInputTextFlags.ReadOnly) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", s.flags, ImGuiInputTextFlags.ParseEmptyRefVal) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", s.flags, ImGuiInputTextFlags.DisplayEmptyRefVal) + local inputs_step, flags = s.inputs_step, s.flags + s.s8_v = ImGui.InputScalar("input s8", ImGuiDataType.S8, s.s8_v, inputs_step and s8_one or nil, nil, "%d", flags) + s.u8_v = ImGui.InputScalar("input u8", ImGuiDataType.U8, s.u8_v, inputs_step and u8_one or nil, nil, "%u", flags) + s.s16_v = ImGui.InputScalar("input s16", ImGuiDataType.S16, s.s16_v, inputs_step and s16_one or nil, nil, "%d", flags) + s.u16_v = ImGui.InputScalar("input u16", ImGuiDataType.U16, s.u16_v, inputs_step and u16_one or nil, nil, "%u", flags) + s.s32_v = ImGui.InputScalar("input s32", ImGuiDataType.S32, s.s32_v, inputs_step and s32_one or nil, nil, "%d", flags) + s.s32_v = ImGui.InputScalar("input s32 hex", ImGuiDataType.S32, s.s32_v, inputs_step and s32_one or nil, nil, "%04X", flags) + s.u32_v = ImGui.InputScalar("input u32", ImGuiDataType.U32, s.u32_v, inputs_step and u32_one or nil, nil, "%u", flags) + s.u32_v = ImGui.InputScalar("input u32 hex", ImGuiDataType.U32, s.u32_v, inputs_step and u32_one or nil, nil, "%08X", flags) + -- [Port] ImGui.InputScalar("input s64", ImGuiDataType.S64, ...) -- 64-bit types not supported + -- [Port] ImGui.InputScalar("input u64", ImGuiDataType.U64, ...) -- 64-bit types not supported + s.f32_v = ImGui.InputScalar("input float", ImGuiDataType.Float, s.f32_v, inputs_step and f32_one or nil, nil, nil, flags) + s.f64_v = ImGui.InputScalar("input double", ImGuiDataType.Double, s.f64_v, inputs_step and f64_one or nil, nil, nil, flags) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDisableBlocks() +------------------------------------------------------------------------------- + +function DemoWindowWidgetsDisableBlocks(demo_data) + local _ + if ImGui.TreeNode("Disable Blocks") then + IMGUI_DEMO_MARKER("Widgets/Disable Blocks") + _, demo_data.DisableSections = ImGui.Checkbox("Disable entire section above", demo_data.DisableSections) + ImGui.SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections.") + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDragAndDrop() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsDragAndDrop = { + col1 = { 1.0, 0.0, 0.2 }, + col2 = { 0.4, 0.7, 0.0, 0.5 }, + mode = 0, + names = { -- 1-based + "Bobby", "Beatrice", "Betty", + "Brianna", "Barry", "Bernard", + "Bibi", "Blaine", "Bryn" + }, + item_names = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }, -- 1-based + col4 = ImVec4(1.0, 0.0, 0.2, 1.0), +} + +function DemoWindowWidgetsDragAndDrop() + if ImGui.TreeNode("Drag and Drop") then + local s = S.DemoWindowWidgetsDragAndDrop + IMGUI_DEMO_MARKER("Widgets/Drag and drop") + if ImGui.TreeNode("Drag and drop in standard widgets") then + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets") + -- ColorEdit widgets automatically act as drag source and drag target. + -- They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F + -- to allow your own widgets to use colors in their drag and drop interaction. + -- Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. + HelpMarker("You can drag from the color squares.") + ImGui.ColorEdit3("color 1", s.col1) + ImGui.ColorEdit4("color 2", s.col2) + ImGui.TreePop() + end + + if ImGui.TreeNode("Drag and drop to copy/swap items") then + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items") + local Mode_Copy, Mode_Move, Mode_Swap = 0, 1, 2 + if ImGui.RadioButtonEx("Copy", s.mode == Mode_Copy) then s.mode = Mode_Copy end ImGui.SameLine() + if ImGui.RadioButtonEx("Move", s.mode == Mode_Move) then s.mode = Mode_Move end ImGui.SameLine() + if ImGui.RadioButtonEx("Swap", s.mode == Mode_Swap) then s.mode = Mode_Swap end + local names = s.names + for n = 0, #names - 1 do + ImGui.PushID(n) + if (n % 3) ~= 0 then + ImGui.SameLine() + end + ImGui.Button(names[n + 1], ImVec2(60, 60)) + + -- Our buttons are both drag sources and drag targets here! + if ImGui.BeginDragDropSource(ImGuiDragDropFlags.None) then + -- Set payload to carry the index of our item (could be anything) + ImGui.SetDragDropPayload("DND_DEMO_CELL", n, 4) -- [Port] sizeof(int) -> 4, payload carries the Lua value + + -- Display preview (could be anything, e.g. when dragging an image we could decide to display + -- the filename and a small preview of the image, etc.) + if s.mode == Mode_Copy then ImGui.Text("Copy %s", names[n + 1]) end + if s.mode == Mode_Move then ImGui.Text("Move %s", names[n + 1]) end + if s.mode == Mode_Swap then ImGui.Text("Swap %s", names[n + 1]) end + ImGui.EndDragDropSource() + end + if ImGui.BeginDragDropTarget() then + local payload = ImGui.AcceptDragDropPayload("DND_DEMO_CELL") + if payload then + IM_ASSERT(payload.DataSize == 4) + local payload_n = payload.Data + if s.mode == Mode_Copy then + names[n + 1] = names[payload_n + 1] + end + if s.mode == Mode_Move then + names[n + 1] = names[payload_n + 1] + names[payload_n + 1] = "" + end + if s.mode == Mode_Swap then + local tmp = names[n + 1] + names[n + 1] = names[payload_n + 1] + names[payload_n + 1] = tmp + end + end + ImGui.EndDragDropTarget() + end + ImGui.PopID() + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Drag to reorder items (simple)") then + IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)") + -- FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. + -- This code was always slightly faulty but in a way which was not easily noticeable. + -- Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue. + ImGui.PushItemFlag(ImGuiItemFlags.AllowDuplicateId, true) + + -- Simple reordering + HelpMarker( + "We don't use the drag and drop api at all here! " .. + "Instead we query when the item is held but not hovered, and order items accordingly.") + local item_names = s.item_names + for n = 0, #item_names - 1 do + local item = item_names[n + 1] + ImGui.Selectable(item) + + if ImGui.IsItemActive() and not ImGui.IsItemHovered() then + local n_next = n + ((ImGui.GetMouseDragDelta(0).y < 0.0) and -1 or 1) + if n_next >= 0 and n_next < #item_names then + item_names[n + 1] = item_names[n_next + 1] + item_names[n_next + 1] = item + ImGui.ResetMouseDragDelta() + end + end + end + + ImGui.PopItemFlag() + ImGui.TreePop() + end + + if ImGui.TreeNode("Tooltip at target location") then + IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location") + for n = 0, 1 do + -- Drop targets + ImGui.Button((n ~= 0) and "drop here##1" or "drop here##0") + if ImGui.BeginDragDropTarget() then + local drop_target_flags = bit32.bor(ImGuiDragDropFlags.AcceptBeforeDelivery, ImGuiDragDropFlags.AcceptNoPreviewTooltip) + local payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags) + if payload then + -- IM_UNUSED(payload) + ImGui.SetMouseCursor(ImGuiMouseCursor.NotAllowed) + ImGui.SetTooltip("Cannot drop here!") + end + ImGui.EndDragDropTarget() + end + + -- Drop source + if n == 0 then + ImGui.ColorButton("drag me", s.col4) + end + + end + ImGui.TreePop() + end + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsDragsAndSliders() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsDragsAndSliders = { + flags = ImGuiSliderFlags.None, + -- Drags + drag_f = 0.5, + drag_f4 = { 0.0, 0.0, 0.0, 0.0 }, + drag_i = 50, + -- Sliders + slider_f = 0.5, + slider_f4 = { 0.0, 0.0, 0.0, 0.0 }, + slider_i = 50, +} + +function DemoWindowWidgetsDragsAndSliders() + local _ + if ImGui.TreeNode("Drag/Slider Flags") then + local s = S.DemoWindowWidgetsDragsAndSliders + IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags") + -- Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", s.flags, ImGuiSliderFlags.AlwaysClamp) + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ClampOnInput", s.flags, ImGuiSliderFlags.ClampOnInput) + ImGui.SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with Ctrl+Click. By default Ctrl+Click allows going out of bounds.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", s.flags, ImGuiSliderFlags.ClampZeroRange) + ImGui.SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_Logarithmic", s.flags, ImGuiSliderFlags.Logarithmic) + ImGui.SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", s.flags, ImGuiSliderFlags.NoRoundToFormat) + ImGui.SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_NoInput", s.flags, ImGuiSliderFlags.NoInput) + ImGui.SameLine(); HelpMarker("Disable Ctrl+Click or Enter key allowing to input text directly into the widget.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_NoSpeedTweaks", s.flags, ImGuiSliderFlags.NoSpeedTweaks) + ImGui.SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_WrapAround", s.flags, ImGuiSliderFlags.WrapAround) + ImGui.SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)") + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ColorMarkers", s.flags, ImGuiSliderFlags.ColorMarkers) + local flags = s.flags + + -- Drags + ImGui.Text("Underlying float value: %f", s.drag_f) + s.drag_f = ImGui.DragFloat("DragFloat (0 -> 1)", s.drag_f, 0.005, 0.0, 1.0, "%.3f", flags) + s.drag_f = ImGui.DragFloat("DragFloat (0 -> +inf)", s.drag_f, 0.005, 0.0, FLT_MAX, "%.3f", flags) + s.drag_f = ImGui.DragFloat("DragFloat (-inf -> 1)", s.drag_f, 0.005, -FLT_MAX, 1.0, "%.3f", flags) + s.drag_f = ImGui.DragFloat("DragFloat (-inf -> +inf)", s.drag_f, 0.005, -FLT_MAX, FLT_MAX, "%.3f", flags) + --ImGui.DragFloat("DragFloat (0 -> 0)", drag_f, 0.005, 0.0, 0.0, "%.3f", flags) -- To test ClampZeroRange + --ImGui.DragFloat("DragFloat (100 -> 100)", drag_f, 0.005, 100.0, 100.0, "%.3f", flags) + s.drag_i = ImGui.DragInt("DragInt (0 -> 100)", s.drag_i, 0.5, 0, 100, "%d", flags) + ImGui.DragFloat4("DragFloat4 (0 -> 1)", s.drag_f4, 0.005, 0.0, 1.0, "%.3f", flags) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers. + + -- Sliders + local flags_for_sliders = bit32.band(flags, bit32.bnot(ImGuiSliderFlags.WrapAround)) + ImGui.Text("Underlying float value: %f", s.slider_f) + s.slider_f = ImGui.SliderFloat("SliderFloat (0 -> 1)", s.slider_f, 0.0, 1.0, "%.3f", flags_for_sliders) + s.slider_i = ImGui.SliderInt("SliderInt (0 -> 100)", s.slider_i, 0, 100, "%d", flags_for_sliders) + ImGui.SliderFloat4("SliderFloat4 (0 -> 1)", s.slider_f4, 0.0, 1.0, "%.3f", flags_for_sliders) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers. -- [Port] flags_for_sliders: upstream passes `flags`, which trips SliderScalar's WrapAround assert + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsFonts() +------------------------------------------------------------------------------- + +function DemoWindowWidgetsFonts() + if ImGui.TreeNode("Fonts") then + IMGUI_DEMO_MARKER("Widgets/Fonts") + local atlas = ImGui.GetIO().Fonts + ImGui.ShowFontAtlas(atlas) + -- FIXME-NEWATLAS: Provide a demo to add/create a procedural font? + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsImages() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsImages = { + image_viewer = ExampleImageViewerData(), + pressed_count = 0, +} +function DemoWindowWidgetsImages() + local s = S.DemoWindowWidgetsImages + if ImGui.TreeNode("Images") then + IMGUI_DEMO_MARKER("Widgets/Images") + local io = ImGui.GetIO() + ImGui.TextWrapped( + "Below we are displaying the font texture (which is the only texture we have access to in this demo). " .. + "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " .. + "Hover the texture for a zoomed view!") + + -- Below we are displaying the font texture because it is the only texture we have access to inside the demo! + -- Read description about ImTextureID/ImTextureRef and FAQ for details about texture identifiers. + -- If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top + -- of their respective source file to specify what they are using as texture identifier, for example: + -- - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. + -- - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. + -- So with the DirectX11 backend, you call ImGui.Image() with a 'ID3D11ShaderResourceView*' cast to ImTextureID. + -- - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers + -- to ImGui.Image(), and gather width/height through your own functions, etc. + -- - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, + -- it will help you debug issues if you are confused about it. + -- - Consider using the lower-level ImDrawList::AddImage() API, via ImGui.GetWindowDrawList():AddImage(). + -- - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md + -- - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + + -- Grab the current texture identifier used by the font atlas. + local atlas = io.Fonts + local my_tex_id = atlas.TexRef + local my_tex_w = atlas.TexData.Width -- Regular user code should never have to care about TexData-> fields, but since we want to display the entire texture here, we pull Width/Height from it. + local my_tex_h = atlas.TexData.Height + ImGui.Text("%.0fx%.0f", my_tex_w, my_tex_h) + + -- Basic drawing + ImGui.SeparatorText("Image()/ImageWithBg() function") + local uv_min = ImVec2(0.0, 0.0) -- Top-left + local uv_max = ImVec2(1.0, 1.0) -- Lower-right + ImGui.PushStyleVar(ImGuiStyleVar.ImageBorderSize, ImMax(1.0, ImGui.GetStyle().ImageBorderSize)) + ImGui.ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0, 0.0, 0.0, 1.0)) + ImGui.PopStyleVar() + + -- Fancy widget + ImGui.SeparatorText("Interactive Image Viewer") + local canvas_size = ImVec2(ImGui.GetContentRegionAvail().x, my_tex_h * 2.0) + ExampleImageViewer_DrawOptions(s.image_viewer) + ExampleImageViewer_DrawCanvas(s.image_viewer, canvas_size, my_tex_id, math.floor(my_tex_w), math.floor(my_tex_h)) + + IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons") + ImGui.SeparatorText("Textured Buttons") + ImGui.TextWrapped("And now some textured buttons..") + for i = 0, 7 do + -- UV coordinates are often (0.0, 0.0) and (1.0, 1.0) to display an entire textures. + -- Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation. + -- Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + ImGui.PushID(i) + if i > 0 then + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(i - 1.0, i - 1.0)) + end + local size = ImVec2(32.0, 32.0) -- Size of the image we want to make visible + local uv0 = ImVec2(0.0, 0.0) -- UV coordinates for lower-left + local uv1 = ImVec2(32.0 / my_tex_w, 32.0 / my_tex_h) -- UV coordinates for (32,32) in our texture + local bg_col = ImVec4(0.0, 0.0, 0.0, 1.0) -- Black background + local tint_col = ImVec4(1.0, 1.0, 1.0, 1.0) -- No tint + if ImGui.ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col) then + s.pressed_count = s.pressed_count + 1 + end + if i > 0 then + ImGui.PopStyleVar() + end + ImGui.PopID() + ImGui.SameLine() + end + ImGui.NewLine() + ImGui.Text("Pressed %d times.", s.pressed_count) + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsListBoxes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsListBoxes = { + item_selected_idx = 0, -- Here we store our selected data as an index. + item_highlight = false, +} +function DemoWindowWidgetsListBoxes() + local s = S.DemoWindowWidgetsListBoxes + if ImGui.TreeNode("List Boxes") then + IMGUI_DEMO_MARKER("Widgets/List Boxes") + -- BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() + -- using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. + -- You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild() + -- to always be called (inconsistent with BeginListBox()/EndListBox()). + + -- Using the generic BeginListBox() API, you have full control over how to display the combo contents. + -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + -- stored in the object itself, etc.) + local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } + -- static int item_selected_idx = 0; // Here we store our selected data as an index. + + local item_highlighted_idx = -1 -- Here we store our highlighted data as an index. + _, s.item_highlight = ImGui.Checkbox("Highlight hovered item in second listbox", s.item_highlight) + + if ImGui.BeginListBox("listbox 1") then + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + if ImGui.Selectable(items[n + 1], is_selected) then + s.item_selected_idx = n + end + + if s.item_highlight and ImGui.IsItemHovered() then + item_highlighted_idx = n + end + + -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if is_selected then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndListBox() + end + ImGui.SameLine(); HelpMarker("Here we are sharing selection state between both boxes.") + + -- Custom size: use all width, 5 items tall + ImGui.Text("Full-width:") + if ImGui.BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui.GetTextLineHeightWithSpacing())) then + for n = 0, #items - 1 do + local is_selected = (s.item_selected_idx == n) + local flags = 0 + if item_highlighted_idx == n then flags = ImGuiSelectableFlags.Highlight end + if ImGui.Selectable(items[n + 1], is_selected, flags) then + s.item_selected_idx = n + end + + -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if is_selected then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndListBox() + end + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsLiveEdit() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsLiveEdit = { + str = ImGui.NewTextBuffer("", 32), + i = 0, + f = 0.0, +} +function DemoWindowWidgetsLiveEdit(demo_data) + local s = S.DemoWindowWidgetsLiveEdit + if ImGui.TreeNode("Live Edit Flags") then + IMGUI_DEMO_MARKER("Widgets/Live Edit Flags") + + ImGui.TextWrapped("Select whether to apply keyboard edits to backing variables _while_ typing.") + + _, demo_data.LiveEditOverride = ImGui.Checkbox("Override Live Edit Flags in Demo Window", demo_data.LiveEditOverride) + if not demo_data.LiveEditOverride then + demo_data.LiveEditFlags = ImGui.GetItemFlags() + end + + ImGui.BeginDisabled(demo_data.LiveEditOverride == false) + ImGui.Indent() + _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputText", demo_data.LiveEditFlags, ImGuiItemFlags.LiveEditOnInputText) + _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputScalar", demo_data.LiveEditFlags, ImGuiItemFlags.LiveEditOnInputScalar) + ImGui.Unindent() ImGui.EndDisabled() - ImGui.TreePop() - ImGui.Spacing() - end + ImGui.Text("Try typing '123' and seeing effect on backing value:") + ImGui.InputText("str", s.str, 32) + ImGui.Text("Backing value: \"%s\"", ImGui.TextBufferToString(s.str)) + s.i = ImGui.InputInt("int", s.i, 0, 0) + ImGui.Text("Backing value: %d", s.i) + s.f = ImGui.SliderFloat("float", s.f, 0.0, 100.0) + ImGui.Text("Backing value: %f", s.f) - if ImGui.TreeNode("Style, Fonts") then - IMGUI_DEMO_MARKER("Configuration/Style, Fonts") - _, demo_data.ShowStyleEditor = ImGui.Checkbox("Style Editor", demo_data.ShowStyleEditor) + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsMixedValues() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsMixedValues = { + use_liveedit = false, + items = { 12.0, 0.0, 0.0 }, +} +function DemoWindowWidgetsMixedValues() + local s = S.DemoWindowWidgetsMixedValues + if ImGui.TreeNode("Mixed Values") then + -- This is designed for advanced property editors which are generally reusable and data-driven. + HelpMarker("Using ImGuiItemFlags_MixedValue.") + + local items = s.items + local item_ref = 1 -- [Port] index of the reference item (C++: float* item_ref = &items[0]) + _, s.use_liveedit = ImGui.Checkbox("ImGuiItemFlags_LiveEditOnInput", s.use_liveedit) + + ImGui.SeparatorText("Scalar/Text Widgets") + local is_mixed = items[1] ~= items[2] or items[1] ~= items[3] + + -- Demonstrate Drags, Sliders, Inputs + ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInput, s.use_liveedit) + ImGui.PushItemFlag(ImGuiItemFlags.MixedValue, is_mixed) + local edited = false + local changed + items[item_ref], changed = ImGui.DragFloat("DragFloat", items[item_ref]); edited = edited or changed + items[item_ref], changed = ImGui.SliderFloat("SliderFloat", items[item_ref], 0.0, 100.0); edited = edited or changed + items[item_ref], changed = ImGui.InputFloat("InputFloat", items[item_ref], 1.0); edited = edited or changed + if edited then + for n = 1, #items do + if n ~= item_ref then + items[n] = items[item_ref] + end + end + end + ImGui.PopItemFlag() + + ImGui.Text("Underlying data:") + items[1] = ImGui.InputFloat("item 0 (ref)", items[1]) + items[2] = ImGui.InputFloat("item 1", items[2]) + items[3] = ImGui.InputFloat("item 2", items[3]) + ImGui.PopItemFlag() + + -- Demonstrate Checkbox(), RadioButton(), Combo(), ColorEdit4() + ImGui.SeparatorText("Others Widgets") + ImGui.Text("(note: edits are not applied in this demo)") -- <-- Would need more state tracking. + local b_on, b_off = true, false + _, b_on = ImGui.Checkbox("Checkbox On", b_on) + _, b_off = ImGui.Checkbox("Checkbox Off", b_off) + ImGui.PushItemFlag(ImGuiItemFlags.MixedValue, true) + _, b_off = ImGui.Checkbox("Checkbox Mixed", b_off) + ImGui.RadioButtonEx("RadioButton Mixed", true) -- [Port] RadioButton(label, bool active) overload is RadioButtonEx ImGui.SameLine() - HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.") - ImGui.TreePop() - ImGui.Spacing() - end + ImGui.RadioButtonEx("RadioButton Mixed##2", true) -- Showing 2 radio buttons makes the example more clear + local combo_idx = 0 + combo_idx = ImGui.Combo("Combo", combo_idx, "One\0Two\0Three\0") + local color = ImVec4(0.5, 0.5, 0.5, 0.5) + ImGui.ColorEdit4("ColorEdit4", color) + ImGui.PopItemFlag() - if ImGui.TreeNode("Capture/Logging") then - IMGUI_DEMO_MARKER("Configuration/Capture, Logging") - HelpMarker( - "The logging API redirects all text output so you can easily capture the content of " .. - "a window or a block. Tree nodes can be automatically expanded.\n" .. - "Try opening any of the contents below in this window and then click one of the \"Log To\" button.") - if ImGui.LogButtons then - ImGui.LogButtons() - else - DemoNotPorted("LogButtons") + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsMultiComponents() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsMultiComponents = { + vec4f = { 0.10, 0.20, 0.30, 0.44 }, + vec4i = { 1, 5, 100, 255 }, + flags = 0, + begin = 10, ["end"] = 90, + begin_i = 100, end_i = 1000, +} +function DemoWindowWidgetsMultiComponents() + local s = S.DemoWindowWidgetsMultiComponents + if ImGui.TreeNode("Multi-component Widgets") then + IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets") + local vec4f = s.vec4f + local vec4i = s.vec4i + + _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ColorMarkers", s.flags, ImGuiSliderFlags.ColorMarkers) -- Only passing this to Drag/Sliders + local flags = s.flags + + ImGui.SeparatorText("2-wide") + ImGui.InputFloat2("input float2", vec4f) + ImGui.InputInt2("input int2", vec4i) + ImGui.DragFloat2("drag float2", vec4f, 0.01, 0.0, 1.0, nil, flags) + ImGui.DragInt2("drag int2", vec4i, 1, 0, 255, nil, flags) + ImGui.SliderFloat2("slider float2", vec4f, 0.0, 1.0, nil, flags) + ImGui.SliderInt2("slider int2", vec4i, 0, 255, nil, flags) + + ImGui.SeparatorText("3-wide") + ImGui.InputFloat3("input float3", vec4f) + ImGui.InputInt3("input int3", vec4i) + ImGui.DragFloat3("drag float3", vec4f, 0.01, 0.0, 1.0, nil, flags) + ImGui.DragInt3("drag int3", vec4i, 1, 0, 255, nil, flags) + ImGui.SliderFloat3("slider float3", vec4f, 0.0, 1.0, nil, flags) + ImGui.SliderInt3("slider int3", vec4i, 0, 255, nil, flags) + + ImGui.SeparatorText("4-wide") + ImGui.InputFloat4("input float4", vec4f) + ImGui.InputInt4("input int4", vec4i) + ImGui.DragFloat4("drag float4", vec4f, 0.01, 0.0, 1.0, nil, flags) + ImGui.DragInt4("drag int4", vec4i, 1, 0, 255, nil, flags) + ImGui.SliderFloat4("slider float4", vec4f, 0.0, 1.0, nil, flags) + ImGui.SliderInt4("slider int4", vec4i, 0, 255, nil, flags) + + ImGui.SeparatorText("Ranges") + s.begin, s["end"] = ImGui.DragFloatRange2("range float", s.begin, s["end"], 0.25, 0.0, 100.0, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags.AlwaysClamp) + s.begin_i, s.end_i = ImGui.DragIntRange2("range int", s.begin_i, s.end_i, 5, 0, 1000, "Min: %d units", "Max: %d units") + s.begin_i, s.end_i = ImGui.DragIntRange2("range int (no bounds)", s.begin_i, s.end_i, 5, 0, 0, "Min: %d units", "Max: %d units") + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsPlotting() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsPlotting = { + animate = true, + arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, + values = {}, -- 90 zeros, filled below + values_offset = 0, + refresh_time = 0.0, + phase = 0.0, + func_type = 0, display_count = 70, +} +for n = 1, 90 do S.DemoWindowWidgetsPlotting.values[n] = 0.0 end + +-- Use functions to generate output +-- [Port] struct Funcs hoisted out of the function to avoid per-frame closures. +-- Plot getters receive a 1-based index in this port: convert back to upstream's 0-based i. +local DemoPlottingFuncs = { + Sin = function(_, idx) local i = idx - 1; return math.sin(i * 0.1) end, + Saw = function(_, idx) local i = idx - 1; if bit32.band(i, 1) ~= 0 then return 1.0 end return -1.0 end, +} + +function DemoWindowWidgetsPlotting() + local s = S.DemoWindowWidgetsPlotting + -- Plot/Graph widgets are not very good. + -- Consider using a third-party library such as ImPlot: https://github.com/epezent/implot + -- (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) + if ImGui.TreeNode("Plotting") then + IMGUI_DEMO_MARKER("Widgets/Plotting") + ImGui.Text("Need better plotting and graphing? Consider using ImPlot:") + ImGui.TextLinkOpenURL("https://github.com/epezent/implot") + ImGui.Separator() + + _, s.animate = ImGui.Checkbox("Animate", s.animate) + + -- Plot as lines and plot as histogram + local arr = s.arr + ImGui.PlotLines("Frame Times", arr, nil, #arr) + ImGui.PlotHistogram("Histogram", arr, nil, #arr, 0, nil, 0.0, 1.0, ImVec2(0, 80.0)) + -- ImGui.SameLine(); HelpMarker("Consider using ImPlot instead!") + + -- Fill an array of contiguous float values to plot + -- Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float + -- and the sizeof() of your structure in the "stride" parameter. + local values = s.values + if not s.animate or s.refresh_time == 0.0 then + s.refresh_time = ImGui.GetTime() + end + while s.refresh_time < ImGui.GetTime() do -- Create data at fixed 60 Hz rate for the demo + values[s.values_offset + 1] = math.cos(s.phase) + s.values_offset = (s.values_offset + 1) % #values + s.phase = s.phase + 0.10 * s.values_offset + s.refresh_time = s.refresh_time + 1.0 / 60.0 end - HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.") - if ImGui.Button("Copy \"Hello, world!\" to clipboard") then - if ImGui.LogToClipboard then - ImGui.LogToClipboard() - ImGui.LogText("Hello, world!") - ImGui.LogFinish() - else - ImGui.SetClipboardText("Hello, world!") -- internal clipboard only on Roblox + -- Plots can display overlay texts + -- (in this example, we will display an average value) + do + local average = 0.0 + for n = 0, #values - 1 do + average = average + values[n + 1] end + average = average / #values + local overlay = string.format("avg %f", average) + ImGui.PlotLines("Lines", values, nil, #values, s.values_offset, overlay, -1.0, 1.0, ImVec2(0, 80.0)) + end + + -- Use functions to generate output + -- FIXME: This is actually VERY awkward because current plot API only pass in indices. + -- We probably want an API passing floats and user provide sample rate/count. + local Funcs = DemoPlottingFuncs + ImGui.SeparatorText("Functions") + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.func_type = ImGui.Combo("func", s.func_type, "Sin\0Saw\0") + ImGui.SameLine() + s.display_count = ImGui.SliderInt("Sample count", s.display_count, 1, 400) + local func = Funcs.Saw + if s.func_type == 0 then func = Funcs.Sin end + ImGui.PlotLines("Lines##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) + ImGui.PlotHistogram("Histogram##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsProgressBars() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsProgressBars = { + progress_accum = 0.0, progress_dir = 1.0, +} +function DemoWindowWidgetsProgressBars() + local s = S.DemoWindowWidgetsProgressBars + if ImGui.TreeNode("Progress Bars") then + IMGUI_DEMO_MARKER("Widgets/Progress Bars") + -- Animate a simple progress bar + s.progress_accum = s.progress_accum + s.progress_dir * 0.4 * ImGui.GetIO().DeltaTime + if s.progress_accum >= 1.1 then s.progress_accum = 1.1; s.progress_dir = s.progress_dir * -1.0 end + if s.progress_accum <= -0.1 then s.progress_accum = -0.1; s.progress_dir = s.progress_dir * -1.0 end + + local progress = ImClamp(s.progress_accum, 0.0, 1.0) + + -- Typically we would use ImVec2(-1.0,0.0) or ImVec2(-FLT_MIN,0.0) to use all available width, + -- or ImVec2(width,0.0) for a specified width. ImVec2(0.0,0.0) uses ItemWidth. + ImGui.ProgressBar(progress, ImVec2(0.0, 0.0)) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + ImGui.Text("Progress Bar") + + local buf = string.format("%d/%d", math.floor(progress * 1753), 1753) + ImGui.ProgressBar(progress, ImVec2(0.0, 0.0), buf) + + -- Pass an animated negative value, e.g. -1.0 * ImGui.GetTime() is the recommended value. + -- Adjust the factor if you want to adjust the animation speed. + ImGui.ProgressBar(-1.0 * ImGui.GetTime(), ImVec2(0.0, 0.0), "Searching..") + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + ImGui.Text("Indeterminate") + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsQueryingStatuses() +------------------------------------------------------------------------------- + +-- [Port] C++ passes bools to "%d"; string.format needs numbers. +local function DemoBoolToInt(b) if b then return 1 end return 0 end + +S.DemoWindowWidgetsQueryingStatuses = { + item_type = 4, + item_disabled = false, + item_mixedvalue = false, + liveedit_flags_override = false, + liveedit_flags = 0, + b = false, + col4f = { 1.0, 0.5, 0.0, 1.0 }, + str = ImGui.NewTextBuffer("", 16), + current = 1, -- item_type == 14 + current_2 = 1, -- item_type == 15 + embed_all_inside_a_child_window = false, + test_window = false, +} +function DemoWindowWidgetsQueryingStatuses() + local s = S.DemoWindowWidgetsQueryingStatuses + local B = DemoBoolToInt + if ImGui.TreeNode("Querying Item Status (Edited/Active/Hovered etc.)") then + IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)") + -- Select an item type + local item_names = + { + "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", + "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" + } + s.item_type = ImGui.Combo("Item Type", s.item_type, item_names, #item_names, #item_names) + ImGui.SameLine() + HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().") + _, s.item_disabled = ImGui.Checkbox("Item Disabled", s.item_disabled) + _, s.item_mixedvalue = ImGui.Checkbox("Item MixedValue", s.item_mixedvalue) + _, s.liveedit_flags_override = ImGui.Checkbox("Override LiveEdit:", s.liveedit_flags_override) + ImGui.SameLine() + if not s.liveedit_flags_override then + s.liveedit_flags = ImGui.GetItemFlags() + end + ImGui.BeginDisabled(s.liveedit_flags_override == false) + _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInput", s.liveedit_flags, ImGuiItemFlags.LiveEditOnInput) + ImGui.SameLine() + _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputText", s.liveedit_flags, ImGuiItemFlags.LiveEditOnInputText) + ImGui.SameLine() + _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputScalar", s.liveedit_flags, ImGuiItemFlags.LiveEditOnInputScalar) + ImGui.EndDisabled() + if s.liveedit_flags_override then + ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInputText, bit32.band(s.liveedit_flags, ImGuiItemFlags.LiveEditOnInputText) ~= 0) + ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInputScalar, bit32.band(s.liveedit_flags, ImGuiItemFlags.LiveEditOnInputScalar) ~= 0) + end + + -- Submit selected items so we can query their status in the code following it. + local ret = false + local item_type = s.item_type + local col4f = s.col4f + if s.item_disabled then + ImGui.BeginDisabled(true) + end + if s.item_mixedvalue then + ImGui.PushItemFlag(ImGuiItemFlags.MixedValue, true) + end + if item_type == 0 then ImGui.Text("ITEM: Text") end -- Testing text items with no identifier/interaction + if item_type == 1 then ret = ImGui.Button("ITEM: Button") end -- Testing button + if item_type == 2 then ImGui.PushItemFlag(ImGuiItemFlags.ButtonRepeat, true); ret = ImGui.Button("ITEM: Button"); ImGui.PopItemFlag() end -- Testing button (with repeater) + if item_type == 3 then ret, s.b = ImGui.Checkbox("ITEM: Checkbox", s.b) end -- Testing checkbox + if item_type == 4 then col4f[1], ret = ImGui.SliderFloat("ITEM: SliderFloat", col4f[1], 0.0, 1.0) end -- Testing basic item + if item_type == 5 then ret = ImGui.InputText("ITEM: InputText", s.str, 16) end -- Testing input text (which handles tabbing) + if item_type == 6 then ret = ImGui.InputTextMultiline("ITEM: InputTextMultiline", s.str, 16) end -- Testing input text (which uses a child window) + if item_type == 7 then col4f[1], ret = ImGui.InputFloat("ITEM: InputFloat", col4f[1], 1.0) end -- Testing +/- buttons on scalar input + if item_type == 8 then ret = ImGui.InputFloat3("ITEM: InputFloat3", col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) + if item_type == 9 then ret = ImGui.ColorEdit4("ITEM: ColorEdit4", col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) + if item_type == 10 then ret = ImGui.Selectable("ITEM: Selectable") end -- Testing selectable item + if item_type == 11 then ret = ImGui.MenuItem("ITEM: MenuItem") end -- Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) + if item_type == 12 then ret = ImGui.TreeNode("ITEM: TreeNode"); if ret then ImGui.TreePop() end end -- Testing tree node + if item_type == 13 then ret = ImGui.TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", bit32.bor(ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.NoTreePushOnOpen)) end -- Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if item_type == 14 then local items = { "Apple", "Banana", "Cherry", "Kiwi" }; s.current, ret = ImGui.Combo("ITEM: Combo", s.current, items, #items) end + if item_type == 15 then local items = { "Apple", "Banana", "Cherry", "Kiwi" }; s.current_2, ret = ImGui.ListBox("ITEM: ListBox", s.current_2, items, #items, #items) end + + local hovered_delay_none = ImGui.IsItemHovered() + local hovered_delay_stationary = ImGui.IsItemHovered(ImGuiHoveredFlags.Stationary) + local hovered_delay_short = ImGui.IsItemHovered(ImGuiHoveredFlags.DelayShort) + local hovered_delay_normal = ImGui.IsItemHovered(ImGuiHoveredFlags.DelayNormal) + local hovered_delay_tooltip = ImGui.IsItemHovered(ImGuiHoveredFlags.ForTooltip) -- = Normal + Stationary + + -- Display the values of IsItemHovered() and other common item state functions. + -- Note that the ImGuiHoveredFlags_XXX flags can be combined. + -- Because BulletText is an item itself and that would affect the output of IsItemXXX functions, + -- we query every state in a single call to avoid storing them and to simplify the code. + ImGui.BulletText( + "Return value = %d\n" .. + "IsItemFocused() = %d\n" .. + "IsItemHovered() = %d\n" .. + "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" .. + "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" .. + "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n" .. + "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n" .. + "IsItemHovered(_AllowWhenDisabled) = %d\n" .. + "IsItemHovered(_RectOnly) = %d\n" .. + "IsItemActive() = %d\n" .. + "IsItemEdited() = %d\n" .. + "IsItemActivated() = %d\n" .. + "IsItemDeactivated() = %d\n" .. + "IsItemDeactivatedAfterEdit() = %d\n" .. + "IsItemVisible() = %d\n" .. + "IsItemClicked() = %d\n" .. + "IsItemToggledOpen() = %d\n" .. + "GetItemRectMin() = (%.1f, %.1f)\n" .. + "GetItemRectMax() = (%.1f, %.1f)\n" .. + "GetItemRectSize() = (%.1f, %.1f)", + B(ret), + B(ImGui.IsItemFocused()), + B(ImGui.IsItemHovered()), + B(ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByPopup)), + B(ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem)), + B(ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenOverlappedByItem)), + B(ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenOverlappedByWindow)), + B(ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)), + B(ImGui.IsItemHovered(ImGuiHoveredFlags.RectOnly)), + B(ImGui.IsItemActive()), + B(ImGui.IsItemEdited()), + B(ImGui.IsItemActivated()), + B(ImGui.IsItemDeactivated()), + B(ImGui.IsItemDeactivatedAfterEdit()), + B(ImGui.IsItemVisible()), + B(ImGui.IsItemClicked()), + B(ImGui.IsItemToggledOpen()), + ImGui.GetItemRectMin().x, ImGui.GetItemRectMin().y, + ImGui.GetItemRectMax().x, ImGui.GetItemRectMax().y, + ImGui.GetItemRectSize().x, ImGui.GetItemRectSize().y + ) + ImGui.BulletText( + "with Hovering Delay or Stationary test:\n" .. + "IsItemHovered() = %d\n" .. + "IsItemHovered(_Stationary) = %d\n" .. + "IsItemHovered(_DelayShort) = %d\n" .. + "IsItemHovered(_DelayNormal) = %d\n" .. + "IsItemHovered(_Tooltip) = %d", + B(hovered_delay_none), B(hovered_delay_stationary), B(hovered_delay_short), B(hovered_delay_normal), B(hovered_delay_tooltip)) + + if s.liveedit_flags_override then + ImGui.PopItemFlag() + ImGui.PopItemFlag() + end + if s.item_mixedvalue then + ImGui.PopItemFlag() + end + if s.item_disabled then + ImGui.EndDisabled() + end + + local buf = ImGui.NewTextBuffer("", 1) + ImGui.InputText("unused", buf, 1, ImGuiInputTextFlags.ReadOnly) + ImGui.SameLine() + HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.") + + ImGui.TreePop() + end + + if ImGui.TreeNode("Querying Window Status (Focused/Hovered etc.)") then + IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)") + _, s.embed_all_inside_a_child_window = ImGui.Checkbox("Embed everything inside a child window for testing _RootWindow flag.", s.embed_all_inside_a_child_window) + if s.embed_all_inside_a_child_window then + ImGui.BeginChild("outer_child", ImVec2(0, ImGui.GetFontSize() * 20.0), ImGuiChildFlags.Borders) + end + + -- Testing IsWindowFocused() function with its various flags. + ImGui.BulletText( + "IsWindowFocused() = %d\n" .. + "IsWindowFocused(_ChildWindows) = %d\n" .. + "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" .. + "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n" .. + "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" .. + "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowFocused(_RootWindow) = %d\n" .. + "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowFocused(_AnyWindow) = %d\n", + B(ImGui.IsWindowFocused()), + B(ImGui.IsWindowFocused(ImGuiFocusedFlags.ChildWindows)), + B(ImGui.IsWindowFocused(bit32.bor(ImGuiFocusedFlags.ChildWindows, ImGuiFocusedFlags.NoPopupHierarchy))), + B(ImGui.IsWindowFocused(bit32.bor(ImGuiFocusedFlags.ChildWindows, ImGuiFocusedFlags.DockHierarchy))), + B(ImGui.IsWindowFocused(bit32.bor(ImGuiFocusedFlags.ChildWindows, ImGuiFocusedFlags.RootWindow))), + B(ImGui.IsWindowFocused(bit32.bor(ImGuiFocusedFlags.ChildWindows, ImGuiFocusedFlags.RootWindow, ImGuiFocusedFlags.NoPopupHierarchy))), + B(ImGui.IsWindowFocused(bit32.bor(ImGuiFocusedFlags.ChildWindows, ImGuiFocusedFlags.RootWindow, ImGuiFocusedFlags.DockHierarchy))), + B(ImGui.IsWindowFocused(ImGuiFocusedFlags.RootWindow)), + B(ImGui.IsWindowFocused(bit32.bor(ImGuiFocusedFlags.RootWindow, ImGuiFocusedFlags.NoPopupHierarchy))), + B(ImGui.IsWindowFocused(bit32.bor(ImGuiFocusedFlags.RootWindow, ImGuiFocusedFlags.DockHierarchy))), + B(ImGui.IsWindowFocused(ImGuiFocusedFlags.AnyWindow))) + + -- Testing IsWindowHovered() function with its various flags. + ImGui.BulletText( + "IsWindowHovered() = %d\n" .. + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" .. + "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" .. + "IsWindowHovered(_ChildWindows) = %d\n" .. + "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" .. + "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowHovered(_RootWindow) = %d\n" .. + "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" .. + "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n" .. + "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" .. + "IsWindowHovered(_AnyWindow) = %d\n" .. + "IsWindowHovered(_Stationary) = %d\n", + B(ImGui.IsWindowHovered()), + B(ImGui.IsWindowHovered(ImGuiHoveredFlags.AllowWhenBlockedByPopup)), + B(ImGui.IsWindowHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem)), + B(ImGui.IsWindowHovered(ImGuiHoveredFlags.ChildWindows)), + B(ImGui.IsWindowHovered(bit32.bor(ImGuiHoveredFlags.ChildWindows, ImGuiHoveredFlags.NoPopupHierarchy))), + B(ImGui.IsWindowHovered(bit32.bor(ImGuiHoveredFlags.ChildWindows, ImGuiHoveredFlags.DockHierarchy))), + B(ImGui.IsWindowHovered(bit32.bor(ImGuiHoveredFlags.ChildWindows, ImGuiHoveredFlags.RootWindow))), + B(ImGui.IsWindowHovered(bit32.bor(ImGuiHoveredFlags.ChildWindows, ImGuiHoveredFlags.RootWindow, ImGuiHoveredFlags.NoPopupHierarchy))), + B(ImGui.IsWindowHovered(bit32.bor(ImGuiHoveredFlags.ChildWindows, ImGuiHoveredFlags.RootWindow, ImGuiHoveredFlags.DockHierarchy))), + B(ImGui.IsWindowHovered(ImGuiHoveredFlags.RootWindow)), + B(ImGui.IsWindowHovered(bit32.bor(ImGuiHoveredFlags.RootWindow, ImGuiHoveredFlags.NoPopupHierarchy))), + B(ImGui.IsWindowHovered(bit32.bor(ImGuiHoveredFlags.RootWindow, ImGuiHoveredFlags.DockHierarchy))), + B(ImGui.IsWindowHovered(bit32.bor(ImGuiHoveredFlags.ChildWindows, ImGuiHoveredFlags.AllowWhenBlockedByPopup))), + B(ImGui.IsWindowHovered(ImGuiHoveredFlags.AnyWindow)), + B(ImGui.IsWindowHovered(ImGuiHoveredFlags.Stationary))) + + ImGui.BeginChild("child", ImVec2(0, 50), ImGuiChildFlags.Borders) + ImGui.Text("This is another child window for testing the _ChildWindows flag.") + ImGui.EndChild() + if s.embed_all_inside_a_child_window then + ImGui.EndChild() + end + + -- Calling IsItemHovered() after begin returns the hovered status of the title bar. + -- This is useful in particular if you want to create a context menu associated to the title bar of a window. + -- This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties). + _, s.test_window = ImGui.Checkbox("Hovered/Active tests after Begin() for title bar testing", s.test_window) + if s.test_window then + -- FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. + -- Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? + s.test_window = ImGui.Begin("Title bar Hovered/Active tests", s.test_window) + if ImGui.BeginPopupContextItem() then -- <-- This is using IsItemHovered() + if ImGui.MenuItem("Close") then s.test_window = false end + ImGui.EndPopup() + end + ImGui.Text( + "IsItemHovered() after begin = %d (== is title bar hovered)\n" .. + "IsItemActive() after begin = %d (== is window being clicked/moved)\n", + B(ImGui.IsItemHovered()), B(ImGui.IsItemActive())) + ImGui.End() + end + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsSelectables() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsSelectables = { + selection = { false, true, false, false, false }, -- Basic + selected_multi = { false, false, false }, -- Multiple items on the same line (1) + checked = { false, false, false, false, false }, -- Multiple items on the same line (2) + selected_n = 0, + selected_tables = { false, false, false, false, false, false, false, false, false, false }, -- In Tables + selected_grid = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }, -- Grid + selected_align = { true, false, true, false, true, false, true, false, true }, -- Alignment +} +-- [Port] The Selectable(label, bool* p_selected) overload doesn't exist in this port (Selectable returns pressed, selected +-- without toggling): written as `if ImGui.Selectable(label, sel) then sel = not sel end`. +function DemoWindowWidgetsSelectables() + local s = S.DemoWindowWidgetsSelectables + -- ImGui.SetNextItemOpen(true, ImGuiCond.Once) + if ImGui.TreeNode("Selectables") then + IMGUI_DEMO_MARKER("Widgets/Selectables") + -- Selectable() has 2 overloads: + -- - The one taking "bool selected" as a read-only selection information. + -- When Selectable() has been clicked it returns true and you can alter selection state accordingly. + -- - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) + -- The earlier is more flexible, as in real application your selection may be stored in many different ways + -- and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). + IMGUI_DEMO_MARKER("Widgets/Selectables/Basic") + if ImGui.TreeNode("Basic") then + local selection = s.selection + if ImGui.Selectable("1. I am selectable", selection[1]) then selection[1] = not selection[1] end + if ImGui.Selectable("2. I am selectable", selection[2]) then selection[2] = not selection[2] end + if ImGui.Selectable("3. I am selectable", selection[3]) then selection[3] = not selection[3] end + if ImGui.Selectable("4. I am double clickable", selection[4], ImGuiSelectableFlags.AllowDoubleClick) then + if ImGui.IsMouseDoubleClicked(0) then + selection[4] = not selection[4] + end + end + ImGui.TreePop() + end + + IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line") + if ImGui.TreeNode("Multiple items on the same line") then + IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple items on the same line") + -- - Using SetNextItemAllowOverlap() + -- - Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. + do + local selected = s.selected_multi + ImGui.SetNextItemAllowOverlap(); if ImGui.Selectable("main.c", selected[1]) then selected[1] = not selected[1] end; ImGui.SameLine(); ImGui.SmallButton("Link 1") + ImGui.SetNextItemAllowOverlap(); if ImGui.Selectable("hello.cpp", selected[2]) then selected[2] = not selected[2] end; ImGui.SameLine(); ImGui.SmallButton("Link 2") + ImGui.SetNextItemAllowOverlap(); if ImGui.Selectable("hello.h", selected[3]) then selected[3] = not selected[3] end; ImGui.SameLine(); ImGui.SmallButton("Link 3") + end + + -- (2) + -- - Using ImGuiSelectableFlags_AllowOverlap is a shortcut for calling SetNextItemAllowOverlap() + -- - No visible label, display contents inside the selectable bounds. + -- - We don't maintain actual selection in this example to keep things simple. + ImGui.Spacing() + do + local checked = s.checked + local color_marker_w = ImGui.CalcTextSize("x").x + for n = 0, 4 do + ImGui.PushID(n) + ImGui.AlignTextToFramePadding() + if ImGui.Selectable("##selectable", s.selected_n == n, ImGuiSelectableFlags.AllowOverlap) then + s.selected_n = n + end + ImGui.SameLine(0, 0) + _, checked[n + 1] = ImGui.Checkbox("##check", checked[n + 1]) + ImGui.SameLine() + local color = ImVec4(bit32.band(n, 1) ~= 0 and 1.0 or 0.2, bit32.band(n, 2) ~= 0 and 1.0 or 0.2, 0.2, 1.0) + ImGui.ColorButton("##color", color, ImGuiColorEditFlags.NoTooltip, ImVec2(color_marker_w, 0)) + ImGui.SameLine() + ImGui.Text("Some label") + ImGui.PopID() + end + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("In Tables") then + IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables") + local selected = s.selected_tables + + if ImGui.BeginTable("split1", 3, bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.NoSavedSettings, ImGuiTableFlags.Borders)) then + for i = 0, 9 do + local label = string.format("Item %d", i) + ImGui.TableNextColumn() + if ImGui.Selectable(label, selected[i + 1]) then selected[i + 1] = not selected[i + 1] end -- FIXME-TABLE: Selection overlap + end + ImGui.EndTable() + end + ImGui.Spacing() + if ImGui.BeginTable("split2", 3, bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.NoSavedSettings, ImGuiTableFlags.Borders)) then + for i = 0, 9 do + local label = string.format("Item %d", i) + ImGui.TableNextRow() + ImGui.TableNextColumn() + if ImGui.Selectable(label, selected[i + 1], ImGuiSelectableFlags.SpanAllColumns) then selected[i + 1] = not selected[i + 1] end + ImGui.TableNextColumn() + ImGui.Text("Some other contents") + ImGui.TableNextColumn() + ImGui.Text("123456") + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Grid") then + IMGUI_DEMO_MARKER("Widgets/Selectables/Grid") + local selected = s.selected_grid + + -- Add in a bit of silly fun... + local time = ImGui.GetTime() + local winning_state = true -- If all cells are selected... + for y = 1, 4 do for x = 1, 4 do if selected[y][x] == 0 then winning_state = false end end end -- [Port] memchr(selected, 0, sizeof(selected)) == NULL + if winning_state then + ImGui.PushStyleVar(ImGuiStyleVar.SelectableTextAlign, ImVec2(0.5 + 0.5 * math.cos(time * 2.0), 0.5 + 0.5 * math.sin(time * 3.0))) + end + + local size = ImGui.CalcTextSize("Sailor").x + for y = 0, 3 do + for x = 0, 3 do + if x > 0 then + ImGui.SameLine() + end + ImGui.PushID(y * 4 + x) + if ImGui.Selectable("Sailor", selected[y + 1][x + 1] ~= 0, 0, ImVec2(size, size)) then + -- Toggle clicked cell + toggle neighbors + selected[y + 1][x + 1] = bit32.bxor(selected[y + 1][x + 1], 1) + if x > 0 then selected[y + 1][x] = bit32.bxor(selected[y + 1][x], 1) end + if x < 3 then selected[y + 1][x + 2] = bit32.bxor(selected[y + 1][x + 2], 1) end + if y > 0 then selected[y][x + 1] = bit32.bxor(selected[y][x + 1], 1) end + if y < 3 then selected[y + 2][x + 1] = bit32.bxor(selected[y + 2][x + 1], 1) end + end + ImGui.PopID() + end + end + + if winning_state then + ImGui.PopStyleVar() + end + ImGui.TreePop() + end + if ImGui.TreeNode("Alignment") then + IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment") + HelpMarker( + "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " .. + "basis using PushStyleVar(). You'll probably want to always keep your default situation to " .. + "left-align otherwise it becomes difficult to layout multiple items on a same line") + + local selected = s.selected_align + local size = ImGui.CalcTextSize("(1.0,1.0)").x + for y = 0, 2 do + for x = 0, 2 do + local alignment = ImVec2(x / 2.0, y / 2.0) + local name = string.format("(%.1f,%.1f)", alignment.x, alignment.y) + if x > 0 then ImGui.SameLine() end + ImGui.PushStyleVar(ImGuiStyleVar.SelectableTextAlign, alignment) + local idx = 3 * y + x + 1 + if ImGui.Selectable(name, selected[idx], ImGuiSelectableFlags.None, ImVec2(size, size)) then selected[idx] = not selected[idx] end + ImGui.PopStyleVar() + end + end + ImGui.TreePop() end ImGui.TreePop() end end --- Demonstrate most Dear ImGui features (this is big function!) --- You may execute this function to experiment with the UI and understand what it does. --- You may then search for keywords in the code when you are interested by a specific feature. ---- @param p_open? bool ---- @return bool? p_open -function ImGui.ShowDemoWindow(p_open) - -- Exceptionally add an extra assert here for people confused about initial Dear ImGui setup - -- Most functions would normally just assert/crash if the context is missing. - IM_ASSERT(ImGui.GetCurrentContext() ~= nil, "Missing Dear ImGui context. Refer to examples app!") +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsSelectionAndMultiSelect() +------------------------------------------------------------------------------- +-- Multi-selection demos +-- Also read: https://github.com/ocornut/imgui/wiki/Multi-Select +------------------------------------------------------------------------------- - local data = demo_data +ExampleNames = +{ + "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper", + "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava", + "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber" +} - -- Examples Apps (accessible from the "Examples" menu) - if data.ShowMainMenuBar then - if ShowExampleAppMainMenuBar then ShowExampleAppMainMenuBar() end +function DemoWindowWidgetsSelectionAndMultiSelect(demo_data) + if ImGui.TreeNode("Selection State & Multi-Select") then + IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select") + HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.") + ImGui.TextDisabled("(multi-select API not ported yet)") -- [Port] TODO: BeginMultiSelect()/EndMultiSelect() + ImGui.TreePop() end - if data.ShowAppDockSpace then RunApp(ShowExampleAppDockSpace, "ShowAppDockSpace") end -- Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) - if data.ShowAppDocuments then RunApp(ShowExampleAppDocuments, "ShowAppDocuments") end -- ...process the Document app next, as it may also use a DockSpace() - if data.ShowAppAssetsBrowser then RunApp(ShowExampleAppAssetsBrowser, "ShowAppAssetsBrowser") end - if data.ShowAppConsole then RunApp(ShowExampleAppConsole, "ShowAppConsole") end - if data.ShowAppCustomRendering then RunApp(ShowExampleAppCustomRendering, "ShowAppCustomRendering") end - if data.ShowAppImageViewer then RunApp(ShowExampleAppImageViewer, "ShowAppImageViewer") end - if data.ShowAppLog then RunApp(ShowExampleAppLog, "ShowAppLog") end - if data.ShowAppLayout then RunApp(ShowExampleAppLayout, "ShowAppLayout") end - if data.ShowAppPropertyEditor then RunApp(ShowExampleAppPropertyEditor, "ShowAppPropertyEditor", data) end - if data.ShowAppSimpleOverlay then RunApp(ShowExampleAppSimpleOverlay, "ShowAppSimpleOverlay") end - if data.ShowAppAutoResize then RunApp(ShowExampleAppAutoResize, "ShowAppAutoResize") end - if data.ShowAppConstrainedResize then RunApp(ShowExampleAppConstrainedResize, "ShowAppConstrainedResize") end - if data.ShowAppFullscreen then RunApp(ShowExampleAppFullscreen, "ShowAppFullscreen") end - if data.ShowAppLongText then RunApp(ShowExampleAppLongText, "ShowAppLongText") end - if data.ShowAppWindowTitles then RunApp(ShowExampleAppWindowTitles, "ShowAppWindowTitles") end +end - -- Dear ImGui Tools (accessible from the "Tools" menu) - if data.ShowMetrics then RunApp(ImGui.ShowMetricsWindow, "ShowMetrics") end - if data.ShowDebugLog then RunApp(ImGui.ShowDebugLogWindow, "ShowDebugLog") end - if data.ShowIDStackTool then RunApp(ImGui.ShowIDStackToolWindow, "ShowIDStackTool") end - if data.ShowAbout then RunApp(ImGui.ShowAboutWindow, "ShowAbout") end - if data.ShowStyleEditor then - local visible - data.ShowStyleEditor, visible = ImGui.Begin("Dear ImGui Style Editor", data.ShowStyleEditor) - if visible then - ImGui.ShowStyleEditor() +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTabs() +------------------------------------------------------------------------------- + +-- [Port] ImGuiTabBarFlags* p_flags -> takes flags, returns the new flags +function EditTabBarFittingPolicyFlags(p_flags) + if bit32.band(p_flags, ImGuiTabBarFlags.FittingPolicyMask_) == 0 then + p_flags = bit32.bor(p_flags, ImGuiTabBarFlags.FittingPolicyDefault_) + end + local pressed + pressed, p_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyMixed", p_flags, ImGuiTabBarFlags.FittingPolicyMixed) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(ImGuiTabBarFlags.FittingPolicyMask_, ImGuiTabBarFlags.FittingPolicyMixed))) + end + pressed, p_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyShrink", p_flags, ImGuiTabBarFlags.FittingPolicyShrink) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(ImGuiTabBarFlags.FittingPolicyMask_, ImGuiTabBarFlags.FittingPolicyShrink))) + end + pressed, p_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", p_flags, ImGuiTabBarFlags.FittingPolicyScroll) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(ImGuiTabBarFlags.FittingPolicyMask_, ImGuiTabBarFlags.FittingPolicyScroll))) + end + return p_flags +end + +S.DemoWindowWidgetsTabs = { + tab_bar_flags = ImGuiTabBarFlags.Reorderable, + opened = { true, true, true, true }, -- Persistent user state + active_tabs = ImVector(), + next_tab_id = 0, + show_leading_button = true, + show_trailing_button = true, + show_leading_trailing_tabs = false, + tab_bar_flags_2 = bit32.bor(ImGuiTabBarFlags.AutoSelectNewTabs, ImGuiTabBarFlags.Reorderable, ImGuiTabBarFlags.FittingPolicyMixed), +} +function DemoWindowWidgetsTabs() + local s = S.DemoWindowWidgetsTabs + if ImGui.TreeNode("Tabs") then + IMGUI_DEMO_MARKER("Widgets/Tabs") + if ImGui.TreeNode("Basic") then + IMGUI_DEMO_MARKER("Widgets/Tabs/Basic") + local tab_bar_flags = ImGuiTabBarFlags.None + if ImGui.BeginTabBar("MyTabBar", tab_bar_flags) then + if ImGui.BeginTabItem("Avocado") then + ImGui.Text("This is the Avocado tab!\nblah blah blah blah blah") + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Broccoli") then + ImGui.Text("This is the Broccoli tab!\nblah blah blah blah blah") + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Cucumber") then + ImGui.Text("This is the Cucumber tab!\nblah blah blah blah blah") + ImGui.EndTabItem() + end + ImGui.EndTabBar() + end + ImGui.Separator() + ImGui.TreePop() end - ImGui.End() - end - -- Demonstrate the various window flags. Typically you would just use the default! - local W = ImGuiWindowFlags - local window_flags = 0 - if no_titlebar then window_flags = bit32.bor(window_flags, W.NoTitleBar) end - if no_scrollbar then window_flags = bit32.bor(window_flags, W.NoScrollbar) end - if not no_menu then window_flags = bit32.bor(window_flags, W.MenuBar) end - if no_move then window_flags = bit32.bor(window_flags, W.NoMove) end - if no_resize then window_flags = bit32.bor(window_flags, W.NoResize) end - if no_collapse then window_flags = bit32.bor(window_flags, W.NoCollapse) end - if no_nav then window_flags = bit32.bor(window_flags, W.NoNav) end - if no_background then window_flags = bit32.bor(window_flags, W.NoBackground) end - if no_bring_to_front then window_flags = bit32.bor(window_flags, W.NoBringToFrontOnFocus) end - if no_docking then window_flags = bit32.bor(window_flags, W.NoDocking) end - if unsaved_document then window_flags = bit32.bor(window_flags, W.UnsavedDocument) end - if no_close then p_open = nil end -- Don't pass our bool* to Begin + if ImGui.TreeNode("Advanced & Close Button") then + IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button") + -- Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_Reorderable", s.tab_bar_flags, ImGuiTabBarFlags.Reorderable) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", s.tab_bar_flags, ImGuiTabBarFlags.AutoSelectNewTabs) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", s.tab_bar_flags, ImGuiTabBarFlags.TabListPopupButton) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", s.tab_bar_flags, ImGuiTabBarFlags.NoCloseWithMiddleMouseButton) + _, s.tab_bar_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", s.tab_bar_flags, ImGuiTabBarFlags.DrawSelectedOverline) + s.tab_bar_flags = EditTabBarFittingPolicyFlags(s.tab_bar_flags) - -- We specify a default position/size in case there's no data in the .ini file. - -- We only do it to make the demo applications a little more welcoming, but typically this isn't required. - local main_viewport = ImGui.GetMainViewport() - ImGui.SetNextWindowPos(ImVec2(main_viewport.WorkPos.x + 650, main_viewport.WorkPos.y + 20), ImGuiCond.FirstUseEver) - ImGui.SetNextWindowSize(ImVec2(550, 680), ImGuiCond.FirstUseEver) + -- Tab Bar + ImGui.AlignTextToFramePadding() + ImGui.Text("Opened:") + local names = { "Artichoke", "Beetroot", "Celery", "Daikon" } + local opened = s.opened -- Persistent user state + for n = 0, #opened - 1 do + ImGui.SameLine() + _, opened[n + 1] = ImGui.Checkbox(names[n + 1], opened[n + 1]) + end - -- Main body of the Demo window starts here. - local visible - p_open, visible = ImGui.Begin("Dear ImGui Demo", p_open, window_flags) - if no_close then p_open = nil end - if not visible then - -- Early out if the window is collapsed, as an optimization. - ImGui.End() - return p_open - end - - -- Most framed widgets share a common width settings. Remaining width is used for the label. - -- The width of the frame may be changed with PushItemWidth() or SetNextItemWidth(). - -- - Positive value for absolute size, negative value for right-alignment. - -- - The default value is about GetWindowWidth() * 0.65f. - -- - See 'Demo->Layout->Widgets Width' for details. - -- Here we change the frame width based on how much width we want to give to the label. - local label_width_base = ImGui.GetFontSize() * 12 -- Some amount of width for label, based on font size. - local label_width_max = ImGui.GetContentRegionAvail().x * 0.40 -- ...but always leave some room for framed widgets. - local label_width = math.min(label_width_base, label_width_max) - ImGui.PushItemWidth(-label_width) -- Right-align: framed items will leave 'label_width' available for the label. - -- ImGui.PushItemWidth(ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for framed widgets, leaving 60% width for labels. - -- ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.40) -- e.g. Use 40% width for labels, leaving 60% width for framed widgets. - -- ImGui.PushItemWidth(ImGui.GetFontSize() * -12) -- e.g. Use XXX width for labels, leaving the rest for framed widgets. - - -- Menu Bar - DemoWindowMenuBar(data) - - ImGui.Text("Dear ImGui says hello! (%s) (%d)", IMGUI_VERSION or "WIP", IMGUI_VERSION_NUM or 0) - ImGui.Spacing() - - if ImGui.CollapsingHeader("Help") then - IMGUI_DEMO_MARKER("Help") - ImGui.SeparatorText("ABOUT THIS DEMO:") - ImGui.BulletText("Sections below are demonstrating many aspects of the library.") - ImGui.BulletText("The \"Examples\" menu above leads to more demo contents.") - ImGui.BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" .. - "and Metrics/Debugger (general purpose Dear ImGui debugging tool).") - ImGui.BulletText("Web demo (w/ source code browser): ") - ImGui.SameLine(0, 0) - ImGui.TextLinkOpenURL("https://pthom.github.io/imgui_explorer") - - ImGui.SeparatorText("PROGRAMMER GUIDE:") - ImGui.BulletText("See the ShowDemoWindow() code in imgui_demo.lua. <- you are here!") - ImGui.BulletText("See comments in imgui.lua.") - ImGui.BulletText("See example applications in the examples/ folder.") - ImGui.BulletText("Read the FAQ at ") - ImGui.SameLine(0, 0) - ImGui.TextLinkOpenURL("https://www.dearimgui.com/faq/") - ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.") - ImGui.BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.") - - ImGui.SeparatorText("USER GUIDE:") - ImGui.ShowUserGuide() - end - - if ImGui.CollapsingHeader("Configuration") then - DemoWindowConfiguration(ImGui.GetIO()) - end - - if ImGui.CollapsingHeader("Window options") then - IMGUI_DEMO_MARKER("Window options") - if ImGui.BeginTable("split", 3) then - ImGui.TableNextColumn(); _, no_titlebar = ImGui.Checkbox("No titlebar", no_titlebar) - ImGui.TableNextColumn(); _, no_scrollbar = ImGui.Checkbox("No scrollbar", no_scrollbar) - ImGui.TableNextColumn(); _, no_menu = ImGui.Checkbox("No menu", no_menu) - ImGui.TableNextColumn(); _, no_move = ImGui.Checkbox("No move", no_move) - ImGui.TableNextColumn(); _, no_resize = ImGui.Checkbox("No resize", no_resize) - ImGui.TableNextColumn(); _, no_collapse = ImGui.Checkbox("No collapse", no_collapse) - ImGui.TableNextColumn(); _, no_close = ImGui.Checkbox("No close", no_close) - ImGui.TableNextColumn(); _, no_nav = ImGui.Checkbox("No nav", no_nav) - ImGui.TableNextColumn(); _, no_background = ImGui.Checkbox("No background", no_background) - ImGui.TableNextColumn(); _, no_bring_to_front = ImGui.Checkbox("No bring to front", no_bring_to_front) - ImGui.TableNextColumn(); _, no_docking = ImGui.Checkbox("No docking", no_docking) - ImGui.TableNextColumn(); _, unsaved_document = ImGui.Checkbox("Unsaved document", unsaved_document) - ImGui.EndTable() + -- Passing a bool* to BeginTabItem() is similar to passing one to Begin(): + -- the underlying bool will be set to false when the tab is closed. + if ImGui.BeginTabBar("MyTabBar", s.tab_bar_flags) then + for n = 0, #opened - 1 do + if opened[n + 1] then + local visible + visible, opened[n + 1] = ImGui.BeginTabItem(names[n + 1], opened[n + 1], ImGuiTabItemFlags.None) + if visible then + ImGui.Text("This is the %s tab!", names[n + 1]) + if bit32.band(n, 1) ~= 0 then + ImGui.Text("I am an odd tab.") + end + ImGui.EndTabItem() + end + end + end + ImGui.EndTabBar() + end + ImGui.Separator() + ImGui.TreePop() end + + if ImGui.TreeNode("TabItemButton & Leading/Trailing flags") then + IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags") + local active_tabs = s.active_tabs + if s.next_tab_id == 0 then -- Initialize with some default tabs + for i = 0, 2 do + active_tabs:push_back(s.next_tab_id); s.next_tab_id = s.next_tab_id + 1 + end + end + + -- TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. + -- (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... + -- but they tend to make more sense together) + _, s.show_leading_button = ImGui.Checkbox("Show Leading TabItemButton()", s.show_leading_button) + _, s.show_trailing_button = ImGui.Checkbox("Show Trailing TabItemButton()", s.show_trailing_button) + _, s.show_leading_trailing_tabs = ImGui.Checkbox("Show Leading+Trailing TabItem()", s.show_leading_trailing_tabs) + + -- Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs + s.tab_bar_flags_2 = EditTabBarFittingPolicyFlags(s.tab_bar_flags_2) + + if ImGui.BeginTabBar("MyTabBar", s.tab_bar_flags_2) then + -- Demo a Leading TabItemButton(): click the "?" button to open a menu + if s.show_leading_button then + if ImGui.TabItemButton("?", bit32.bor(ImGuiTabItemFlags.Leading, ImGuiTabItemFlags.NoTooltip)) then + ImGui.OpenPopup("MyHelpMenu") + end + end + if ImGui.BeginPopup("MyHelpMenu") then + ImGui.Selectable("Hello!") + ImGui.EndPopup() + end + + -- Demo Leading/Trailing Tabs + if s.show_leading_trailing_tabs then + if ImGui.BeginTabItem("Leading", nil, ImGuiTabItemFlags.Leading) then + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Trailing", nil, ImGuiTabItemFlags.Trailing) then + ImGui.EndTabItem() + end + end + + -- Demo Trailing Tabs: click the "+" button to add a new tab. + -- (In your app you may want to use a font icon instead of the "+") + -- We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end. + if s.show_trailing_button then + if ImGui.TabItemButton("+", bit32.bor(ImGuiTabItemFlags.Trailing, ImGuiTabItemFlags.NoTooltip)) then + active_tabs:push_back(s.next_tab_id); s.next_tab_id = s.next_tab_id + 1 -- Add new tab + end + end + + -- Submit our regular tabs + local n = 0 + while n < active_tabs.Size do + local open = true + local name = string.format("%04d", active_tabs.Data[n + 1]) + local visible + visible, open = ImGui.BeginTabItem(name, open, ImGuiTabItemFlags.None) + if visible then + ImGui.Text("This is the %s tab!", name) + ImGui.EndTabItem() + end + + if not open then + active_tabs:erase(n + 1) + else + n = n + 1 + end + end + + ImGui.EndTabBar() + end + ImGui.Separator() + ImGui.TreePop() + end + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsText() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsText = { + custom_size = 16.0, + custom_scale = 1.0, + wrap_width = 200.0, + buf = ImGui.NewTextBuffer("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e", 32), +} +function DemoWindowWidgetsText() + local s = S.DemoWindowWidgetsText + if ImGui.TreeNode("Text") then + IMGUI_DEMO_MARKER("Widgets/Text") + if ImGui.TreeNode("Colorful Text") then + IMGUI_DEMO_MARKER("Widgets/Text/Colored Text") + -- Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. + ImGui.TextColored(ImVec4(1.0, 0.0, 1.0, 1.0), "Pink") + ImGui.TextColored(ImVec4(1.0, 1.0, 0.0, 1.0), "Yellow") + ImGui.TextDisabled("Disabled") + ImGui.SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.") + ImGui.TreePop() + end + + if ImGui.TreeNode("Font Size") then + IMGUI_DEMO_MARKER("Widgets/Text/Font Size") + local style = ImGui.GetStyle() + local global_scale = style.FontScaleMain * style.FontScaleDpi + ImGui.Text("style.FontScaleMain = %0.2f", style.FontScaleMain) + ImGui.Text("style.FontScaleDpi = %0.2f", style.FontScaleDpi) + ImGui.Text("global_scale = ~%0.2f", global_scale) -- This is not technically accurate as internal scales may apply, but conceptually let's pretend it is. + ImGui.Text("FontSize = %0.2f", ImGui.GetFontSize()) + + ImGui.SeparatorText("") + s.custom_size = ImGui.SliderFloat("custom_size", s.custom_size, 10.0, 100.0, "%.0f") + ImGui.Text("ImGui::PushFont(nullptr, custom_size);") + ImGui.PushFont(nil, s.custom_size) + ImGui.Text("FontSize = %.2f (== %.2f * global_scale)", ImGui.GetFontSize(), s.custom_size) + ImGui.PopFont() + + ImGui.SeparatorText("") + s.custom_scale = ImGui.SliderFloat("custom_scale", s.custom_scale, 0.5, 4.0, "%.2f") + ImGui.Text("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scale);") + ImGui.PushFont(nil, style.FontSizeBase * s.custom_scale) + ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), s.custom_scale) + ImGui.PopFont() + + ImGui.SeparatorText("") + local scaling = 0.5 + while scaling <= 4.0 do + ImGui.PushFont(nil, style.FontSizeBase * scaling) + ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), scaling) + ImGui.PopFont() + scaling = scaling + 0.5 + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Word Wrapping") then + IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping") + -- Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. + ImGui.TextWrapped( + "This text should automatically wrap on the edge of the window. The current implementation " .. + "for text wrapping follows simple rules suitable for English and possibly other languages.") + ImGui.Spacing() + + s.wrap_width = ImGui.SliderFloat("Wrap width", s.wrap_width, -20, 600, "%.0f") + + local draw_list = ImGui.GetWindowDrawList() + for n = 0, 1 do + ImGui.Text("Test paragraph %d:", n) + local pos = ImGui.GetCursorScreenPos() + local marker_min = ImVec2(pos.x + s.wrap_width, pos.y) + local marker_max = ImVec2(pos.x + s.wrap_width + 10, pos.y + ImGui.GetTextLineHeight()) + ImGui.PushTextWrapPos(ImGui.GetCursorPos().x + s.wrap_width) + if n == 0 then + ImGui.Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", s.wrap_width) + else + ImGui.Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh") + end + + -- Draw actual text bounding box, following by marker of our expected limit (should not overlap!) + draw_list:AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), IM_COL32(255, 255, 0, 255)) + draw_list:AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)) + ImGui.PopTextWrapPos() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("UTF-8 Text") then + IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text") + -- UTF-8 test with Japanese characters + -- (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) + -- - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 + -- - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you + -- can save your source files as 'UTF-8 without signature'). + -- - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 + -- CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. + -- Don't do this in your application! Please use u8"text in any language" in your application! + -- Note that characters values are preserved even by InputText() if the font cannot be displayed, + -- so you can safely copy & paste garbled characters into another application. + ImGui.TextWrapped( + "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. " .. + "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. " .. + "Read docs/FONTS.md for details.") + ImGui.Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)") + ImGui.Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)") + --static char buf[32] = u8"NIHONGO"; -- <- this is how you would write it with C++11, using real kanjis + ImGui.InputText("UTF-8 input", s.buf, 32) + ImGui.TreePop() + end + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTextFilter() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTextFilter = { + filter = ImGuiTextFilter(), +} +function DemoWindowWidgetsTextFilter() + local s = S.DemoWindowWidgetsTextFilter + if ImGui.TreeNode("Text Filter") then + IMGUI_DEMO_MARKER("Widgets/Text Filter") + -- Helper class to easy setup a text filter. + -- You may want to implement a more feature-full filtering scheme in your own application. + HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.") + local filter = s.filter + ImGui.Text("Filter usage:\n" .. + " \"\" display all lines\n" .. + " xxx display lines containing \"xxx\"\n" .. + " xxx yyy display lines containing \"xxx\" and \"yyy\"\n" .. + " \"xxx yyy\" display lines containing \"xxx yyy\"\n" .. + " xxx,yyy display lines containing \"xxx\" or \"yyy\"\n" .. + " -xxx hide lines containing \"xxx\"") + ImGui.SetNextItemWidth(-FLT_MIN) + filter:DrawWithHint("##Filter", "Filter (incl -excl)") + if ImGui.BeginChild("##items", ImVec2(-FLT_MIN, ImGui.GetTextLineHeightWithSpacing() * 15), ImGuiChildFlags.FrameStyle) then + local lines = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" } + for _, item in ipairs(lines) do + if filter:PassFilter(item) then + ImGui.TextUnformatted(item) + end + end + for _, item in ipairs(ExampleNames) do + if filter:PassFilter(item) then + ImGui.TextUnformatted(item) + end + end + end + ImGui.EndChild() + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTextInput() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTextInput = { + -- "Multi-line Text Input" + ml = { + text = ImGui.NewTextBuffer( + "/*\n" .. + " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" .. + " the hexadecimal encoding of one offending instruction,\n" .. + " more formally, the invalid operand with locked CMPXCHG8B\n" .. + " instruction bug, is a design flaw in the majority of\n" .. + " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" .. + " processors (all in the P5 microarchitecture).\n" .. + "*/\n\n" .. + "label:\n" .. + "\tlock cmpxchg8b eax\n", 1024 * 16), + flags = ImGuiInputTextFlags.AllowTabInput, + }, + -- "Filtered Text Input" + filtered = { + buf1 = ImGui.NewTextBuffer("", 32), buf2 = ImGui.NewTextBuffer("", 32), buf3 = ImGui.NewTextBuffer("", 32), + buf4 = ImGui.NewTextBuffer("", 32), buf5 = ImGui.NewTextBuffer("", 32), buf6 = ImGui.NewTextBuffer("", 32), + buf7 = ImGui.NewTextBuffer("", 32), + }, + -- "Password Input" + password = { password = ImGui.NewTextBuffer("password123", 64) }, + -- "Completion, History, Edit Callbacks" + callbacks = { + buf1 = ImGui.NewTextBuffer("", 64), buf2 = ImGui.NewTextBuffer("", 64), buf3 = ImGui.NewTextBuffer("", 64), + edit_count = 0, + }, + -- "Resize Callback" + resize = { flags = ImGuiInputTextFlags.None, my_str = ImVector() }, + -- "Eliding, Alignment" + eliding = { buf1 = ImGui.NewTextBuffer("/path/to/some/folder/with/long/filename.cpp", 128), flags = ImGuiInputTextFlags.ElideLeft }, + -- "Miscellaneous" + misc = { buf1 = ImGui.NewTextBuffer("", 16), flags = ImGuiInputTextFlags.EscapeClearsAll }, +} +function DemoWindowWidgetsTextInput() + local S_ti = S.DemoWindowWidgetsTextInput + -- To wire InputText() with std::string or any other custom string type, + -- see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + if ImGui.TreeNode("Text Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input") + if ImGui.TreeNode("Multi-line Text Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input") + local s = S_ti.ml + -- WE ARE USING A FIXED-SIZE BUFFER FOR SIMPLICITY HERE. + -- If you want to use InputText() with std::string or any custom dynamic string type: + -- - For std::string: use the wrapper in misc/cpp/imgui_stdlib.h/.cpp + -- - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize. + HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include in here)") + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, ImGuiInputTextFlags.ReadOnly) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_WordWrap", s.flags, ImGuiInputTextFlags.WordWrap) + ImGui.SameLine(); HelpMarker("Feature is currently in Beta. Please read comments in imgui.h") + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", s.flags, ImGuiInputTextFlags.AllowTabInput) + ImGui.SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets.") + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", s.flags, ImGuiInputTextFlags.CtrlEnterForNewLine) + ImGui.InputTextMultiline("##source", s.text, 1024 * 16, ImVec2(-FLT_MIN, ImGui.GetTextLineHeight() * 16), s.flags) + ImGui.TreePop() + end + + if ImGui.TreeNode("Filtered Text Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input") + local s = S_ti.filtered + local TextFilters = {} + -- Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback) + function TextFilters.FilterCasingSwap(data) + if data.EventChar >= string.byte('a') and data.EventChar <= string.byte('z') then data.EventChar = data.EventChar - (string.byte('a') - string.byte('A')) -- Lowercase becomes uppercase + elseif data.EventChar >= string.byte('A') and data.EventChar <= string.byte('Z') then data.EventChar = data.EventChar + (string.byte('a') - string.byte('A')) end -- Uppercase becomes lowercase + return 0 + end + + -- Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) + function TextFilters.FilterImGuiLetters(data) + if data.EventChar < 256 and string.find("imgui", string.char(data.EventChar), 1, true) then + return 0 + end + return 1 + end + + ImGui.InputText("default", s.buf1, 32) + ImGui.InputText("decimal", s.buf2, 32, ImGuiInputTextFlags.CharsDecimal) + ImGui.InputText("hexadecimal", s.buf3, 32, bit32.bor(ImGuiInputTextFlags.CharsHexadecimal, ImGuiInputTextFlags.CharsUppercase)) + ImGui.InputText("uppercase", s.buf4, 32, ImGuiInputTextFlags.CharsUppercase) + ImGui.InputText("no blank", s.buf5, 32, ImGuiInputTextFlags.CharsNoBlank) + ImGui.InputText("casing swap", s.buf6, 32, ImGuiInputTextFlags.CallbackCharFilter, TextFilters.FilterCasingSwap) -- Use CharFilter callback to replace characters. + ImGui.InputText("\"imgui\"", s.buf7, 32, ImGuiInputTextFlags.CallbackCharFilter, TextFilters.FilterImGuiLetters) -- Use CharFilter callback to disable some characters. + ImGui.TreePop() + end + + if ImGui.TreeNode("Password Input") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Password input") + local s = S_ti.password + ImGui.InputText("password", s.password, 64, ImGuiInputTextFlags.Password) + ImGui.SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n") + ImGui.InputTextWithHint("password (w/ hint)", "", s.password, 64, ImGuiInputTextFlags.Password) + ImGui.InputText("password (clear)", s.password, 64) + ImGui.TreePop() + end + + if ImGui.TreeNode("Completion, History, Edit Callbacks") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks") + local s = S_ti.callbacks + local Funcs = {} + function Funcs.MyCallback(data) + if data.EventFlag == ImGuiInputTextFlags.CallbackCompletion then + data:InsertChars(data.CursorPos, "..") + elseif data.EventFlag == ImGuiInputTextFlags.CallbackHistory then + if data.EventKey == ImGuiKey.UpArrow then + data:DeleteChars(0, data.BufTextLen) + data:InsertChars(0, "Pressed Up!") + data:SelectAll() + elseif data.EventKey == ImGuiKey.DownArrow then + data:DeleteChars(0, data.BufTextLen) + data:InsertChars(0, "Pressed Down!") + data:SelectAll() + end + elseif data.EventFlag == ImGuiInputTextFlags.CallbackEdit then + -- Toggle casing of first character + local c = data.Buf[1] + if (c >= string.byte('a') and c <= string.byte('z')) or (c >= string.byte('A') and c <= string.byte('Z')) then data.Buf[1] = bit32.bxor(data.Buf[1], 32) end + data.BufDirty = true + + -- Increment a counter + local p_int = data.UserData -- [Port] int* -> the statics table, counter in .edit_count + p_int.edit_count = p_int.edit_count + 1 + end + return 0 + end + ImGui.InputText("Completion", s.buf1, 64, ImGuiInputTextFlags.CallbackCompletion, Funcs.MyCallback) + ImGui.SameLine(); HelpMarker( + "Here we append \"..\" each time Tab is pressed. " .. + "See 'Examples>Console' for a more meaningful demonstration of using this callback.") + + ImGui.InputText("History", s.buf2, 64, ImGuiInputTextFlags.CallbackHistory, Funcs.MyCallback) + ImGui.SameLine(); HelpMarker( + "Here we replace and select text each time Up/Down are pressed. " .. + "See 'Examples>Console' for a more meaningful demonstration of using this callback.") + + ImGui.InputText("Edit", s.buf3, 64, ImGuiInputTextFlags.CallbackEdit, Funcs.MyCallback, s) -- [Port] (void*)&edit_count -> s + ImGui.SameLine(); HelpMarker( + "Here we toggle the casing of the first character on every edit + count edits.") + ImGui.SameLine(); ImGui.Text("(%d)", s.edit_count) + + ImGui.TreePop() + end + + if ImGui.TreeNode("Resize Callback") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback") + local s = S_ti.resize + -- To wire InputText() with std::string or any other custom string type, + -- you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper + -- using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. + HelpMarker( + "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" .. + "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.") + local Funcs = {} + function Funcs.MyResizeCallback(data) + if data.EventFlag == ImGuiInputTextFlags.CallbackResize then + local my_str = data.UserData + IM_ASSERT(my_str.Data == data.Buf) + my_str:resize(data.BufSize, 0) -- NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 -- [Port] new bytes filled with 0 + data.Buf = my_str.Data + end + return 0 + end + + -- Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. + -- For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' + function Funcs.MyInputTextMultiline(label, my_str, size, flags) + if size == nil then size = ImVec2(0, 0) end + if flags == nil then flags = 0 end + IM_ASSERT(bit32.band(flags, ImGuiInputTextFlags.CallbackResize) == 0) + return ImGui.InputTextMultiline(label, my_str.Data, my_str.Size, size, bit32.bor(flags, ImGuiInputTextFlags.CallbackResize), Funcs.MyResizeCallback, my_str) + end + + -- For this demo we are using ImVector as a string container. + -- Note that because we need to store a terminating zero character, our size/capacity are 1 more + -- than usually reported by a typical string class. + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_WordWrap", s.flags, ImGuiInputTextFlags.WordWrap) + + local my_str = s.my_str + if my_str:empty() then + my_str:push_back(0) + end + Funcs.MyInputTextMultiline("##MyStr", my_str, ImVec2(-FLT_MIN, ImGui.GetTextLineHeight() * 16), s.flags) + ImGui.Text("Data: %s\nSize: %d\nCapacity: %d", tostring(my_str.Data), my_str.Size, my_str.Capacity) -- [Port] %p -> %s + tostring + ImGui.TreePop() + end + + if ImGui.TreeNode("Eliding, Alignment") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment") + local s = S_ti.eliding + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ElideLeft", s.flags, ImGuiInputTextFlags.ElideLeft) + ImGui.InputText("Path", s.buf1, 128, s.flags) + ImGui.TreePop() + end + + if ImGui.TreeNode("Miscellaneous") then + IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous") + local s = S_ti.misc + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", s.flags, ImGuiInputTextFlags.EscapeClearsAll) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, ImGuiInputTextFlags.ReadOnly) + _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", s.flags, ImGuiInputTextFlags.NoUndoRedo) + ImGui.InputText("Hello", s.buf1, 16, s.flags) + ImGui.TreePop() + end + + ImGui.TreePop() end - -- All demo contents - DemoWindowWidgets(data) - if DemoWindowLayout then DemoWindowLayout() end - if DemoWindowPopups then DemoWindowPopups() end - if DemoWindowTables then DemoWindowTables() end - if DemoWindowInputs then DemoWindowInputs() end +end - -- End of ShowDemoWindow() - ImGui.PopItemWidth() - ImGui.End() - return p_open +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTooltips() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTooltips = { + arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, + always_on = 0, +} +function DemoWindowWidgetsTooltips() + local s = S.DemoWindowWidgetsTooltips + if ImGui.TreeNode("Tooltips") then + IMGUI_DEMO_MARKER("Widgets/Tooltips") + -- Tooltips are windows following the mouse. They do not take focus away. + ImGui.SeparatorText("General") + + -- Typical use cases: + -- - Short-form (text only): SetItemTooltip("Hello"); + -- - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); } + + -- - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); } + -- - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); } + + HelpMarker( + "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n" .. + "We provide a helper SetItemTooltip() function to perform the two with standards flags.") + + local sz = ImVec2(-FLT_MIN, 0.0) + + ImGui.Button("Basic", sz) + ImGui.SetItemTooltip("I am a tooltip") + + ImGui.Button("Fancy", sz) + if ImGui.BeginItemTooltip() then + ImGui.Text("I am a fancy tooltip") + ImGui.PlotLines("Curve", s.arr, nil, #s.arr) + ImGui.Text("Sin(time) = %f", math.sin(ImGui.GetTime())) + ImGui.EndTooltip() + end + + ImGui.SeparatorText("Always On") + + -- Showcase NOT relying on a IsItemHovered() to emit a tooltip. + -- Here the tooltip is always emitted when 'always_on == true'. + _, s.always_on = ImGui.RadioButton("Off", s.always_on, 0) + ImGui.SameLine() + _, s.always_on = ImGui.RadioButton("Always On (Simple)", s.always_on, 1) + ImGui.SameLine() + _, s.always_on = ImGui.RadioButton("Always On (Advanced)", s.always_on, 2) + if s.always_on == 1 then + ImGui.SetTooltip("I am following you around.") + elseif s.always_on == 2 and ImGui.BeginTooltip() then + ImGui.ProgressBar(math.sin(ImGui.GetTime()) * 0.5 + 0.5, ImVec2(ImGui.GetFontSize() * 25, 0.0)) + ImGui.EndTooltip() + end + + ImGui.SeparatorText("Custom") + + HelpMarker( + "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize " .. + "tooltip activation details across your application. You may however decide to use custom " .. + "flags for a specific tooltip instance.") + + -- The following examples are passed for documentation purpose but may not be useful to most users. + -- Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from + -- 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. + -- With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. + ImGui.Button("Manual", sz) + if ImGui.IsItemHovered(ImGuiHoveredFlags.ForTooltip) then + ImGui.SetTooltip("I am a manually emitted tooltip.") + end + + ImGui.Button("DelayNone", sz) + if ImGui.IsItemHovered(ImGuiHoveredFlags.DelayNone) then + ImGui.SetTooltip("I am a tooltip with no delay.") + end + + ImGui.Button("DelayShort", sz) + if ImGui.IsItemHovered(bit32.bor(ImGuiHoveredFlags.DelayShort, ImGuiHoveredFlags.NoSharedDelay)) then + ImGui.SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui.GetStyle().HoverDelayShort) + end + + ImGui.Button("DelayLong", sz) + if ImGui.IsItemHovered(bit32.bor(ImGuiHoveredFlags.DelayNormal, ImGuiHoveredFlags.NoSharedDelay)) then + ImGui.SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui.GetStyle().HoverDelayNormal) + end + + ImGui.Button("Stationary", sz) + if ImGui.IsItemHovered(ImGuiHoveredFlags.Stationary) then + ImGui.SetTooltip("I am a tooltip requiring mouse to be stationary before activating.") + end + + -- Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav', + -- which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag. + ImGui.BeginDisabled() + ImGui.Button("Disabled item", sz) + if ImGui.IsItemHovered(ImGuiHoveredFlags.ForTooltip) then + ImGui.SetTooltip("I am a tooltip for a disabled item.") + end + ImGui.EndDisabled() + + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsTreeNodes() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsTreeNodes = { + base_flags = bit32.bor(ImGuiTreeNodeFlags.DrawLinesFull, ImGuiTreeNodeFlags.DefaultOpen), -- "Hierarchy Lines" + selection_mask = 0x00, + base_flags_2 = bit32.bor(ImGuiTreeNodeFlags.OpenOnArrow, ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.SpanAvailWidth), -- "Advanced" + align_label_with_current_x_position = false, + use_drag_and_drop = false, +} +function DemoWindowWidgetsTreeNodes() + local s = S.DemoWindowWidgetsTreeNodes + if ImGui.TreeNode("Tree Nodes") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes") + -- See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree. + if ImGui.TreeNode("Basic Trees") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic Trees") + for i = 0, 4 do + -- Use SetNextItemOpen() so set the default state of a node to be open. We could + -- also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! + if i == 0 then + ImGui.SetNextItemOpen(true, ImGuiCond.Once) + end + + -- Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict. + -- An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)', + -- aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine. + ImGui.PushID(i) + if ImGui.TreeNode("", "Child %d", i) then + ImGui.Text("blah blah") + ImGui.SameLine() + if ImGui.SmallButton("button") then end + ImGui.TreePop() + end + ImGui.PopID() + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Hierarchy Lines") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy Lines") + HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") + _, s.base_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", s.base_flags, ImGuiTreeNodeFlags.DrawLinesNone) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", s.base_flags, ImGuiTreeNodeFlags.DrawLinesFull) + _, s.base_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", s.base_flags, ImGuiTreeNodeFlags.DrawLinesToNodes) + + if ImGui.TreeNodeEx("Parent", s.base_flags) then + if ImGui.TreeNodeEx("Child 1", s.base_flags) then + ImGui.Button("Button for Child 1") + ImGui.TreePop() + end + if ImGui.TreeNodeEx("Child 2", s.base_flags) then + ImGui.Button("Button for Child 2") + ImGui.TreePop() + end + ImGui.Text("Remaining contents") + ImGui.Text("Remaining contents") + ImGui.TreePop() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Clipping Large Trees") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Clipping Large Trees") + ImGui.TextWrapped( + "- Using ImGuiListClipper with trees is a less easy than on arrays or grids.\n" .. + "- Refer to 'Demo->Examples->Property Editor' for an example of how to do that.\n" .. + "- Discuss in #3823") + ImGui.TreePop() + end + + if ImGui.TreeNode("Selectable Nodes") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Selectable Nodes") + HelpMarker( + "Manually implemented selectable nodes.\n" .. + "Click to select, Ctrl+Click to toggle, click on arrows or double-click to open.\n\n" .. + "You may also use the multi-select API (see 'Demo->Widgets->Selection State & Multi-Select') for more advanced multi-selection features.") + + -- Hold in 'selection_mask' a simple representation of what may be user-side selection state. + -- - You may retain selection state inside or outside your objects in whatever format you see fit. + -- You may use ImGuiSelectionBasicStorage which is conceptually close to a set<> of identifiers. + -- - We record which node was clicked and then apply selection at the end of the loop. + -- - This is a manual and simplified reimplementation of multi-selection, which the full + -- BeginMultiSelect() API implements better, but which is not trivial to wire for trees. + local node_clicked_idx = -1 + for node_n = 0, 5 do + -- Disable the default "open on single-click behavior" + set Selected flag according to our selection. + -- To alter selection we use if 'IsItemClicked() && !IsItemToggledOpen()', so clicking on an arrow doesn't alter selection. + -- In a BeginMultiSelect()/EndMultiSelect() we could use IsItemToggledSelection() but here we reimplement and use our own logic. + local flags = bit32.bor(ImGuiTreeNodeFlags.OpenOnArrow, ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.SpanAvailWidth) + if bit32.band(s.selection_mask, bit32.lshift(1, node_n)) ~= 0 then + flags = bit32.bor(flags, ImGuiTreeNodeFlags.Selected) + end + + local is_open = ImGui.TreeNodeEx(node_n, flags, "Selectable Node %d", node_n) -- [Port] (void*)(intptr_t)node_n -> node_n + if ImGui.IsItemClicked() and not ImGui.IsItemToggledOpen() then + node_clicked_idx = node_n + end + if is_open then + ImGui.BulletText("") + ImGui.TreePop() + end + end + if node_clicked_idx ~= -1 then + -- Update selection state (process outside of tree loop to avoid visual inconsistencies during the clicking frame) + if ImGui.GetIO().KeyCtrl then + s.selection_mask = bit32.bxor(s.selection_mask, bit32.lshift(1, node_clicked_idx)) -- Ctrl+Click to toggle + else --if (!(selection_mask & (1 << node_clicked_idx))) -- Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection + s.selection_mask = bit32.lshift(1, node_clicked_idx) -- Click to single-select + end + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Advanced") then + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", s.base_flags_2, ImGuiTreeNodeFlags.OpenOnArrow) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", s.base_flags_2, ImGuiTreeNodeFlags.OpenOnDoubleClick) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", s.base_flags_2, ImGuiTreeNodeFlags.SpanAvailWidth); ImGui.SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", s.base_flags_2, ImGuiTreeNodeFlags.SpanFullWidth) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", s.base_flags_2, ImGuiTreeNodeFlags.SpanLabelWidth); ImGui.SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin.") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", s.base_flags_2, ImGuiTreeNodeFlags.SpanAllColumns); ImGui.SameLine(); HelpMarker("For use in Tables only.") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", s.base_flags_2, ImGuiTreeNodeFlags.AllowOverlap) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_Framed", s.base_flags_2, ImGuiTreeNodeFlags.Framed); ImGui.SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_FramePadding", s.base_flags_2, ImGuiTreeNodeFlags.FramePadding) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsToParent", s.base_flags_2, ImGuiTreeNodeFlags.NavLeftJumpsToParent) + + HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", s.base_flags_2, ImGuiTreeNodeFlags.DrawLinesNone) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", s.base_flags_2, ImGuiTreeNodeFlags.DrawLinesFull) + _, s.base_flags_2 = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", s.base_flags_2, ImGuiTreeNodeFlags.DrawLinesToNodes) + + _, s.align_label_with_current_x_position = ImGui.Checkbox("Align label with current X position", s.align_label_with_current_x_position) + _, s.use_drag_and_drop = ImGui.Checkbox("Make Tree Nodes as drag & drop sources", s.use_drag_and_drop) + if s.align_label_with_current_x_position then + ImGui.Unindent(ImGui.GetTreeNodeToLabelSpacing()) + end + + for node_n = 0, 5 do + local node_flags = s.base_flags_2 + if node_n < 3 then + -- Items 0..2 are Tree Node + local is_open = ImGui.TreeNodeEx(node_n, node_flags, "Selectable Node %d", node_n) + if s.use_drag_and_drop and ImGui.BeginDragDropSource() then + ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) + ImGui.Text("This is a drag and drop source") + ImGui.EndDragDropSource() + end + if node_n == 2 and bit32.band(s.base_flags_2, ImGuiTreeNodeFlags.SpanLabelWidth) ~= 0 then + -- Item 2 has an additional inline button to help demonstrate SpanLabelWidth. + ImGui.SameLine() + if ImGui.SmallButton("button") then end + end + if is_open then + ImGui.BulletText("Blah blah\nBlah Blah") + ImGui.SameLine() + ImGui.SmallButton("Button") + ImGui.TreePop() + end + else + -- Items 3..5 are Tree Leaves + -- The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can + -- use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). + node_flags = bit32.bor(node_flags, ImGuiTreeNodeFlags.Leaf, ImGuiTreeNodeFlags.NoTreePushOnOpen) -- ImGuiTreeNodeFlags_Bullet + ImGui.TreeNodeEx(node_n, node_flags, "Selectable Leaf %d", node_n) + if s.use_drag_and_drop and ImGui.BeginDragDropSource() then + ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) + ImGui.Text("This is a drag and drop source") + ImGui.EndDragDropSource() + end + end + end + if s.align_label_with_current_x_position then + ImGui.Indent(ImGui.GetTreeNodeToLabelSpacing()) + end + ImGui.TreePop() + end + ImGui.TreePop() + end +end + +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowWidgetsVerticalSliders() +------------------------------------------------------------------------------- + +S.DemoWindowWidgetsVerticalSliders = { + int_value = 0, + values = { 0.0, 0.60, 0.35, 0.9, 0.70, 0.20, 0.0 }, + values2 = { 0.20, 0.80, 0.40, 0.25 }, +} +function DemoWindowWidgetsVerticalSliders() + local s = S.DemoWindowWidgetsVerticalSliders + if ImGui.TreeNode("Vertical Sliders") then + IMGUI_DEMO_MARKER("Widgets/Vertical Sliders") + local spacing = 4 + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(spacing, spacing)) + + s.int_value = ImGui.VSliderInt("##int", ImVec2(18, 160), s.int_value, 0, 5) + ImGui.SameLine() + + local values = s.values + ImGui.PushID("set1") + for i = 0, 6 do + if i > 0 then ImGui.SameLine() end + ImGui.PushID(i) + ImGui.PushStyleColor(ImGuiCol.FrameBg, ImColor.HSV(i / 7.0, 0.5, 0.5).Value) + ImGui.PushStyleColor(ImGuiCol.FrameBgHovered, ImColor.HSV(i / 7.0, 0.6, 0.5).Value) + ImGui.PushStyleColor(ImGuiCol.FrameBgActive, ImColor.HSV(i / 7.0, 0.7, 0.5).Value) + ImGui.PushStyleColor(ImGuiCol.SliderGrab, ImColor.HSV(i / 7.0, 0.9, 0.9).Value) + values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(18, 160), values[i + 1], 0.0, 1.0, "") + if ImGui.IsItemActive() or ImGui.IsItemHovered() then + ImGui.SetTooltip("%.3f", values[i + 1]) + end + ImGui.PopStyleColor(4) + ImGui.PopID() + end + ImGui.PopID() + + ImGui.SameLine() + ImGui.PushID("set2") + local values2 = s.values2 + local rows = 3 + local small_slider_size = ImVec2(18, math.floor((160.0 - (rows - 1) * spacing) / rows)) + for nx = 0, 3 do + if nx > 0 then ImGui.SameLine() end + ImGui.BeginGroup() + for ny = 0, rows - 1 do + ImGui.PushID(nx * rows + ny) + values2[nx + 1] = ImGui.VSliderFloat("##v", small_slider_size, values2[nx + 1], 0.0, 1.0, "") + if ImGui.IsItemActive() or ImGui.IsItemHovered() then + ImGui.SetTooltip("%.3f", values2[nx + 1]) + end + ImGui.PopID() + end + ImGui.EndGroup() + end + ImGui.PopID() + + ImGui.SameLine() + ImGui.PushID("set3") + for i = 0, 3 do + if i > 0 then ImGui.SameLine() end + ImGui.PushID(i) + ImGui.PushStyleVar(ImGuiStyleVar.GrabMinSize, 40) + values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(40, 160), values[i + 1], 0.0, 1.0, "%.2f\nsec") + ImGui.PopStyleVar() + ImGui.PopID() + end + ImGui.PopID() + ImGui.PopStyleVar() + ImGui.TreePop() + end end ------------------------------------------------------------------------------- -- [SECTION] DemoWindowWidgets() ------------------------------------------------------------------------------- ---- Calls a (global) demo section if it exists, otherwise shows a placeholder -local function Sub(fn, title, ...) - if fn then fn(...) else - if ImGui.TreeNode(title) then DemoNotPorted(title) ImGui.TreePop() end - end -end - -function DemoWindowWidgets(data) - -- ImGui.SetNextItemOpen(true, ImGuiCond.Once) +function DemoWindowWidgets(demo_data) + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) if not ImGui.CollapsingHeader("Widgets") then return end - -- IMGUI_DEMO_MARKER("Widgets") + -- IMGUI_DEMO_MARKER("Widgets"); - local disable_all = data.DisableSections -- The Checkbox for that is inside the "Disabled" section at the bottom - local override_liveedit = data.LiveEditOverride + local disable_all = demo_data.DisableSections -- The Checkbox for that is inside the "Disabled" section at the bottom + local override_liveedit = demo_data.LiveEditOverride if disable_all then ImGui.BeginDisabled() end if override_liveedit then - ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInputText, DemoHas(data.LiveEditFlags, ImGuiItemFlags.LiveEditOnInputText)) - ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInputScalar, DemoHas(data.LiveEditFlags, ImGuiItemFlags.LiveEditOnInputScalar)) + ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInputText, bit32.band(demo_data.LiveEditFlags, ImGuiItemFlags.LiveEditOnInputText) ~= 0) + ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInputScalar, bit32.band(demo_data.LiveEditFlags, ImGuiItemFlags.LiveEditOnInputScalar) ~= 0) end - Sub(DemoWindowWidgetsBasic, "Basic") - Sub(DemoWindowWidgetsBullets, "Bullets") - Sub(DemoWindowWidgetsCollapsingHeaders, "Collapsing Headers") - Sub(DemoWindowWidgetsComboBoxes, "Combo") - Sub(DemoWindowWidgetsColorAndPickers, "Color/Picker Widgets") - Sub(DemoWindowWidgetsDataTypes, "Data Types") + DemoWindowWidgetsBasic() + DemoWindowWidgetsBullets() + DemoWindowWidgetsCollapsingHeaders() + DemoWindowWidgetsComboBoxes() + DemoWindowWidgetsColorAndPickers() + DemoWindowWidgetsDataTypes() if disable_all then ImGui.EndDisabled() end - Sub(DemoWindowWidgetsDisableBlocks, "Disable Blocks", data) + DemoWindowWidgetsDisableBlocks(demo_data) if disable_all then ImGui.BeginDisabled() end - Sub(DemoWindowWidgetsDragAndDrop, "Drag and Drop") - Sub(DemoWindowWidgetsDragsAndSliders, "Drag/Slider Flags") - Sub(DemoWindowWidgetsFonts, "Fonts") - Sub(DemoWindowWidgetsImages, "Images") - Sub(DemoWindowWidgetsListBoxes, "List Boxes") - Sub(DemoWindowWidgetsLiveEdit, "Live Edit Flags", data) - Sub(DemoWindowWidgetsMixedValues, "Mixed Values") - Sub(DemoWindowWidgetsMultiComponents, "Multi-component Widgets") - Sub(DemoWindowWidgetsPlotting, "Plotting") - Sub(DemoWindowWidgetsProgressBars, "Progress Bars") - Sub(DemoWindowWidgetsQueryingStatuses, "Querying Item Status (Edited/Active/Hovered etc.)") - Sub(DemoWindowWidgetsSelectables, "Selectables") - Sub(DemoWindowWidgetsSelectionAndMultiSelect, "Selection State & Multi-Select", data) - Sub(DemoWindowWidgetsTabs, "Tabs") - Sub(DemoWindowWidgetsText, "Text") - Sub(DemoWindowWidgetsTextFilter, "Text Filter") - Sub(DemoWindowWidgetsTextInput, "Text Input") - Sub(DemoWindowWidgetsTooltips, "Tooltips") - Sub(DemoWindowWidgetsTreeNodes, "Tree Nodes") - Sub(DemoWindowWidgetsVerticalSliders, "Vertical Sliders") + DemoWindowWidgetsDragAndDrop() + DemoWindowWidgetsDragsAndSliders() + DemoWindowWidgetsFonts() + DemoWindowWidgetsImages() + DemoWindowWidgetsListBoxes() + DemoWindowWidgetsLiveEdit(demo_data) + DemoWindowWidgetsMixedValues() + DemoWindowWidgetsMultiComponents() + DemoWindowWidgetsPlotting() + DemoWindowWidgetsProgressBars() + DemoWindowWidgetsQueryingStatuses() + DemoWindowWidgetsSelectables() + DemoWindowWidgetsSelectionAndMultiSelect(demo_data) + DemoWindowWidgetsTabs() + DemoWindowWidgetsText() + DemoWindowWidgetsTextFilter() + DemoWindowWidgetsTextInput() + DemoWindowWidgetsTooltips() + DemoWindowWidgetsTreeNodes() + DemoWindowWidgetsVerticalSliders() if override_liveedit then ImGui.PopItemFlag() @@ -1019,1237 +3746,897 @@ function DemoWindowWidgets(data) end end -------------------------------------------------------------------------------- --- [SECTION] User Guide / ShowUserGuide() -------------------------------------------------------------------------------- - -function ImGui.ShowUserGuide() - local io = ImGui.GetIO() - ImGui.BulletText("Double-click on title bar to collapse window.") - ImGui.BulletText( - "Click and drag on lower corner or border to resize window.\n" .. - "(double-click to auto fit window to its contents)") - ImGui.BulletText("Ctrl+Click on a slider or drag box to input value as text.") - ImGui.BulletText("Tab/Shift+Tab to cycle through keyboard editable fields.") - ImGui.BulletText("Ctrl+Tab/Ctrl+Shift+Tab to focus windows.") - if io.FontAllowUserScaling then - ImGui.BulletText("Ctrl+Mouse Wheel to zoom window contents.") - end - ImGui.BulletText("While inputting text:\n") - ImGui.Indent() - ImGui.BulletText("Ctrl+Left/Right to word jump.") - ImGui.BulletText("Ctrl+A or double-click to select all.") - ImGui.BulletText("Ctrl+X/C/V to use clipboard cut/copy/paste.") - ImGui.BulletText("Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.") - ImGui.BulletText("Escape to revert.") - ImGui.Unindent() - ImGui.BulletText("With Keyboard controls enabled:") - ImGui.Indent() - ImGui.BulletText("Arrow keys or Home/End/PageUp/PageDown to navigate.") - ImGui.BulletText("Space to activate a widget.") - ImGui.BulletText("Return to input text into a widget.") - ImGui.BulletText("Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus.") - ImGui.BulletText("Alt to jump to the menu layer of a window.") - ImGui.BulletText("Menu or Shift+F10 to open a context menu.") - ImGui.Unindent() - ImGui.BulletText("With Gamepad controls enabled:") - ImGui.Indent() - ImGui.BulletText("D-Pad: Navigate / Tweak / Resize (in Windowing mode).") - ImGui.BulletText("%s Face button: Activate / Open / Toggle. Hold: activate with text input.", io.ConfigNavSwapGamepadButtons and "East" or "South") - ImGui.BulletText("%s Face button: Cancel / Close / Exit.", io.ConfigNavSwapGamepadButtons and "South" or "East") - ImGui.BulletText("West Face button: Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows).") - ImGui.BulletText("North Face button: Open Context Menu.") - ImGui.BulletText("L1/R1: Tweak Slower/Faster, Focus Previous/Next (in Windowing Mode).") - ImGui.Unindent() -end -end --[[ imgui_demo.lua ]] - -do --[[ imgui_demo_2.lua ]] ---- Dear ImGui WIP --- (Demo Code, part 2): DemoWindowLayout(), DemoWindowPopups(), DemoWindowTables(), DemoWindowColumns(), --- DemoWindowInputs() and all ShowExampleAppXXX() example apps. --- Port of imgui_demo.cpp (docking branch). Globals are shared with imgui_demo.lua (HelpMarker, ShowExampleMenuFile, ...) - --- Helpers macros --- We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, --- but making an exception here as those are largely simplifying code... --- In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. -local IM_MIN = math.min -local IM_MAX = math.max -local function IM_CLAMP(V, MN, MX) return (V < MN) and MN or (V > MX) and MX or V end -local _ -local function IMGUI_DEMO_MARKER(_) end -- upstream hook, no-op here - ---- `char buf[size] = "str"` -> zero-terminated byte table -local function Buf(str, size) - local t = {} - for i = 1, #str do t[i] = string.byte(str, i) end - t[#str + 1] = 0 - if size then for i = #str + 2, size do t[i] = 0 end end - return t -end ---- byte table -> Lua string (up to the zero terminator) -local function BufStr(buf) - local n = 0 - while buf[n + 1] ~= nil and buf[n + 1] ~= 0 do n = n + 1 end - return ImGui._ByteArrayToString(buf, 1, n + 1) -end -local function BufSet(buf, str) - for i = 1, #str do buf[i] = string.byte(str, i) end - buf[#str + 1] = 0 -end - ---- ImColor::HSV() as ImVec4 -local function HSV(h, s, v, a) - local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v) - return ImVec4(r, g, b, a or 1.0) -end -local function B2I(b) return b and 1 or 0 end - -local function Has(flags, f) return bit32.band(flags, f) ~= 0 end -local function NotSupported() ImGui.TextDisabled("(not supported on Roblox)") end -local function NotPorted(what) ImGui.TextDisabled("(not ported yet%s)", what and (": " .. what) or "") end - -local function DemoHelpMarker(desc) - if HelpMarker then HelpMarker(desc) return end - ImGui.TextDisabled("(?)") - if ImGui.BeginItemTooltip() then - ImGui.PushTextWrapPos(ImGui.GetFontSize() * 35.0) - ImGui.TextUnformatted(desc) - ImGui.PopTextWrapPos() - ImGui.EndTooltip() - end -end -local function DemoMenuFile() if ShowExampleMenuFile then ShowExampleMenuFile() end end - ---- Minimal ImGuiTextFilter stand-in when the library one isn't available -local function MakeTextFilter() - if ImGuiTextFilter then return ImGuiTextFilter() end - local f = { InputBuf = Buf("", 256) } - function f:Draw(label, width) - if width and width ~= 0 then ImGui.SetNextItemWidth(width) end - return ImGui.InputText(label or "Filter (inc,-exc)", self.InputBuf, 256) - end - function f:IsActive() return self.InputBuf[1] ~= 0 end - function f:Clear() self.InputBuf[1] = 0 end - function f:Build() end - function f:PassFilter(text, text_end) - if text_end then text = string.sub(text, 1, text_end - 1) end - local s = BufStr(self.InputBuf) - if s == "" then return true end - local any_inc, pass_inc = false, false - for tok in string.gmatch(s, "[^,]+") do - tok = string.match(tok, "^%s*(.-)%s*$") - if tok ~= "" then - if string.sub(tok, 1, 1) == "-" then - if #tok > 1 and string.find(string.lower(text), string.lower(string.sub(tok, 2)), 1, true) then return false end - else - any_inc = true - if string.find(string.lower(text), string.lower(tok), 1, true) then pass_inc = true end - end - end - end - return (not any_inc) or pass_inc - end - return f -end - --- ImGuiInputTextCallbackData helpers (the port's callback data has no methods). Buf is a 1-based zero-terminated --- byte table, positions are 0-based like C++. -local function CB_DeleteChars(data, pos, bytes_count) - local buf = data.Buf - local len = data.BufTextLen - for i = pos + 1, len - bytes_count + 1 do buf[i] = buf[i + bytes_count] end - for i = len - bytes_count + 2, len + 1 do buf[i] = 0 end - if data.CursorPos >= pos + bytes_count then data.CursorPos = data.CursorPos - bytes_count - elseif data.CursorPos >= pos then data.CursorPos = pos end - data.SelectionStart = data.CursorPos; data.SelectionEnd = data.CursorPos - data.BufDirty = true - data.BufTextLen = len - bytes_count -end -local function CB_InsertChars(data, pos, text) - local n = #text - if n == 0 then return end - if data.BufTextLen + n >= data.BufSize then return end - local buf = data.Buf - for i = data.BufTextLen + 1, pos + 1, -1 do buf[i + n] = buf[i] end - for i = 1, n do buf[pos + i] = string.byte(text, i) end - if data.CursorPos >= pos then data.CursorPos = data.CursorPos + n end - data.SelectionStart = data.CursorPos; data.SelectionEnd = data.CursorPos - data.BufDirty = true - data.BufTextLen = data.BufTextLen + n -end -local function CB_SelectAll(data) data.SelectionStart = 0; data.SelectionEnd = data.BufTextLen end - ---- ImGui::BeginChild() wrapper accepting upstream args -local function BeginChild(id, size, child_flags, window_flags) - return ImGui.BeginChild(id, size or ImVec2(0, 0), child_flags or 0, window_flags or 0) -end - ------------------------------------------------------------------------------- -- [SECTION] DemoWindowLayout() ------------------------------------------------------------------------------- -local SL = { - disable_mouse_wheel = false, disable_menu = false, - draw_lines = 3, max_height_in_lines = 10, - offset_x = 0, override_bg_color = true, child_flags = nil, - f = 0.0, show_indented_items = true, +S.DemoWindowLayout = { + -- Child windows + disable_mouse_wheel = false, + disable_menu = false, + draw_lines = 3, + max_height_in_lines = 10, + offset_x = 0, + override_bg_color = true, + child_flags = bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.ResizeX, ImGuiChildFlags.ResizeY), + -- Widgets Width + f = 0.0, + show_indented_items = true, + -- Basic Horizontal Layout c1 = false, c2 = false, c3 = false, c4 = false, - f0 = 1.0, f1 = 2.0, f2 = 3.0, item = -1, selection = { 0, 1, 2, 3 }, - track_item = 50, enable_track = true, enable_extra_decorations = false, scroll_to_off_px = 0.0, scroll_to_pos_px = 200.0, - lines = 7, show_horizontal_contents_size_demo_window = false, - show_h_scrollbar = true, show_button = true, show_tree_nodes = true, show_text_wrapped = false, show_columns = true, - show_tab_bar = true, show_child = false, explicit_content_size = false, contents_size_x = 300.0, - clip_size = nil, clip_offset = nil, + f0 = 1.0, f1 = 2.0, f2 = 3.0, + item = -1, + selection = { 0, 1, 2, 3 }, + -- Scrolling + track_item = 50, + enable_track = true, + enable_extra_decorations = false, + scroll_to_off_px = 0.0, + scroll_to_pos_px = 200.0, + lines = 7, + show_horizontal_contents_size_demo_window = false, + show_h_scrollbar = true, + show_button = true, + show_tree_nodes = true, + show_text_wrapped = false, + show_columns = true, + show_tab_bar = true, + show_child = false, + explicit_content_size = false, + contents_size_x = 300.0, + -- Text Clipping + size = ImVec2(100.0, 100.0), + offset = ImVec2(30.0, 30.0), + -- Overlap Mode enable_allow_overlap = true, } -local function DemoWindowLayout_ChildWindows() - IMGUI_DEMO_MARKER("Layout/Child windows") - ImGui.SeparatorText("Child windows") - - DemoHelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.") - _, SL.disable_mouse_wheel = ImGui.Checkbox("Disable Mouse Wheel", SL.disable_mouse_wheel) - _, SL.disable_menu = ImGui.Checkbox("Disable Menu", SL.disable_menu) - - -- Child 1: no border, enable horizontal scrollbar - do - local window_flags = ImGuiWindowFlags.HorizontalScrollbar - if SL.disable_mouse_wheel then - window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoScrollWithMouse) - end - BeginChild("ChildL", ImVec2(ImGui.GetContentRegionAvail().x * 0.5, 260), ImGuiChildFlags.None, window_flags) - for i = 0, 99 do - ImGui.Text("%04d: scrollable region", i) - end - ImGui.EndChild() +function DemoWindowLayout() + local s = S.DemoWindowLayout + if not ImGui.CollapsingHeader("Layout & Scrolling") then + return end - ImGui.SameLine() + if ImGui.TreeNode("Child windows") then + IMGUI_DEMO_MARKER("Layout/Child windows") + ImGui.SeparatorText("Child windows") - -- Child 2: rounded border - do - local window_flags = ImGuiWindowFlags.None - if SL.disable_mouse_wheel then - window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoScrollWithMouse) - end - if not SL.disable_menu then - window_flags = bit32.bor(window_flags, ImGuiWindowFlags.MenuBar) - end - ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 5.0) - BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags.Borders, window_flags) - if not SL.disable_menu and ImGui.BeginMenuBar() then - if ImGui.BeginMenu("Menu") then - DemoMenuFile() - ImGui.EndMenu() + HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.") + _, s.disable_mouse_wheel = ImGui.Checkbox("Disable Mouse Wheel", s.disable_mouse_wheel) + _, s.disable_menu = ImGui.Checkbox("Disable Menu", s.disable_menu) + + -- Child 1: no border, enable horizontal scrollbar + do + local window_flags = ImGuiWindowFlags.HorizontalScrollbar + if s.disable_mouse_wheel then + window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoScrollWithMouse) end - ImGui.EndMenuBar() - end - if ImGui.BeginTable("split", 2, bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.NoSavedSettings)) then + ImGui.BeginChild("ChildL", ImVec2(ImGui.GetContentRegionAvail().x * 0.5, 260), ImGuiChildFlags.None, window_flags) for i = 0, 99 do - local buf = string.format("%03d", i) - ImGui.TableNextColumn() - ImGui.Button(buf, ImVec2(-FLT_MIN, 0.0)) + ImGui.Text("%04d: scrollable region", i) end - ImGui.EndTable() + ImGui.EndChild() end - ImGui.EndChild() - ImGui.PopStyleVar() - end - -- Child 3: manual-resize - ImGui.SeparatorText("Manual-resize") - do - DemoHelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.") - -- if ImGui.Button("Set Height to 200") then - -- ImGui.SetNextWindowSize(ImVec2(-FLT_MIN, 200.0)) - -- end + ImGui.SameLine() - ImGui.PushStyleColor(ImGuiCol.ChildBg, ImGui.GetStyleColorVec4(ImGuiCol.FrameBg)) - if BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui.GetTextLineHeightWithSpacing() * 8), bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.ResizeY)) then - for n = 0, 9 do - ImGui.Text("Line %04d", n) + -- Child 2: rounded border + do + local window_flags = ImGuiWindowFlags.None + if s.disable_mouse_wheel then + window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoScrollWithMouse) end - end - ImGui.PopStyleColor() - ImGui.EndChild() - end - - -- Child 4: auto-resizing height with a limit - ImGui.SeparatorText("Auto-resize with constraints") - do - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - SL.draw_lines = ImGui.DragInt("Lines Count", SL.draw_lines, 0.2) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - SL.max_height_in_lines = ImGui.DragInt("Max Height (in Lines)", SL.max_height_in_lines, 0.2) - - ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui.GetTextLineHeightWithSpacing() * SL.max_height_in_lines)) - if BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0), bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.AutoResizeY)) then - for n = 0, SL.draw_lines - 1 do - ImGui.Text("Line %04d", n) + if not s.disable_menu then + window_flags = bit32.bor(window_flags, ImGuiWindowFlags.MenuBar) end - end - ImGui.EndChild() - end - - ImGui.SeparatorText("Misc/Advanced") - - -- Demonstrate a few extra things - -- - Changing ImGuiCol.ChildBg (which is transparent black in default styles) - -- - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) - -- You can also call SetNextWindowPos() to position the child window. The parent window will effectively - -- layout from this position. - -- - Using ImGui.GetItemRectMin/Max() to query the "item" state (because the child window is an item from - -- the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details. - do - if SL.child_flags == nil then SL.child_flags = bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.ResizeX, ImGuiChildFlags.ResizeY) end - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - SL.offset_x = ImGui.DragInt("Offset X", SL.offset_x, 1.0, -1000, 1000) - _, SL.override_bg_color = ImGui.Checkbox("Override ChildBg color", SL.override_bg_color) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_Borders", SL.child_flags, ImGuiChildFlags.Borders) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", SL.child_flags, ImGuiChildFlags.AlwaysUseWindowPadding) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeX", SL.child_flags, ImGuiChildFlags.ResizeX) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeY", SL.child_flags, ImGuiChildFlags.ResizeY) - _, SL.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_FrameStyle", SL.child_flags, ImGuiChildFlags.FrameStyle) - ImGui.SameLine(); DemoHelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.") - if Has(SL.child_flags, ImGuiChildFlags.FrameStyle) then - SL.override_bg_color = false + ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 5.0) + ImGui.BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags.Borders, window_flags) + if not s.disable_menu and ImGui.BeginMenuBar() then + if ImGui.BeginMenu("Menu") then + ShowExampleMenuFile() + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end + if ImGui.BeginTable("split", 2, bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.NoSavedSettings)) then + for i = 0, 99 do + local buf = string.format("%03d", i) + ImGui.TableNextColumn() + ImGui.Button(buf, ImVec2(-FLT_MIN, 0.0)) + end + ImGui.EndTable() + end + ImGui.EndChild() + ImGui.PopStyleVar() end - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + SL.offset_x) - if SL.override_bg_color then - ImGui.PushStyleColor(ImGuiCol.ChildBg, IM_COL32(255, 0, 0, 100)) - end - BeginChild("Red", ImVec2(200, 100), SL.child_flags, ImGuiWindowFlags.None) - if SL.override_bg_color then + -- Child 3: manual-resize + ImGui.SeparatorText("Manual-resize") + do + HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.") + --if (ImGui.Button("Set Height to 200")) + -- ImGui.SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f)); + + ImGui.PushStyleColor(ImGuiCol.ChildBg, ImGui.GetStyleColorVec4(ImGuiCol.FrameBg)) + if ImGui.BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui.GetTextLineHeightWithSpacing() * 8), bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.ResizeY)) then + for n = 0, 9 do + ImGui.Text("Line %04d", n) + end + end ImGui.PopStyleColor() + ImGui.EndChild() end - for n = 0, 49 do - ImGui.Text("Some test %d", n) + -- Child 4: auto-resizing height with a limit + ImGui.SeparatorText("Auto-resize with constraints") + do + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.draw_lines = ImGui.DragInt("Lines Count", s.draw_lines, 0.2) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.max_height_in_lines = ImGui.DragInt("Max Height (in Lines)", s.max_height_in_lines, 0.2) + + ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui.GetTextLineHeightWithSpacing() * s.max_height_in_lines)) + if ImGui.BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0), bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.AutoResizeY)) then + for n = 0, s.draw_lines - 1 do + ImGui.Text("Line %04d", n) + end + end + ImGui.EndChild() end - ImGui.EndChild() - local child_is_hovered = ImGui.IsItemHovered() - local child_rect_min = ImGui.GetItemRectMin() - local child_rect_max = ImGui.GetItemRectMax() - ImGui.Text("Hovered: %d", B2I(child_is_hovered)) - ImGui.Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y) + + ImGui.SeparatorText("Misc/Advanced") + + -- Demonstrate a few extra things + -- - Changing ImGuiCol.ChildBg (which is transparent black in default styles) + -- - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) + -- You can also call SetNextWindowPos() to position the child window. The parent window will effectively + -- layout from this position. + -- - Using ImGui.GetItemRectMin/Max() to query the "item" state (because the child window is an item from + -- the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details. + do + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.offset_x = ImGui.DragInt("Offset X", s.offset_x, 1.0, -1000, 1000) + _, s.override_bg_color = ImGui.Checkbox("Override ChildBg color", s.override_bg_color) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_Borders", s.child_flags, ImGuiChildFlags.Borders) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", s.child_flags, ImGuiChildFlags.AlwaysUseWindowPadding) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeX", s.child_flags, ImGuiChildFlags.ResizeX) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_ResizeY", s.child_flags, ImGuiChildFlags.ResizeY) + _, s.child_flags = ImGui.CheckboxFlags("ImGuiChildFlags_FrameStyle", s.child_flags, ImGuiChildFlags.FrameStyle) + ImGui.SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.") + if bit32.band(s.child_flags, ImGuiChildFlags.FrameStyle) ~= 0 then + s.override_bg_color = false + end + + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + s.offset_x) + if s.override_bg_color then + ImGui.PushStyleColor(ImGuiCol.ChildBg, IM_COL32(255, 0, 0, 100)) + end + ImGui.BeginChild("Red", ImVec2(200, 100), s.child_flags, ImGuiWindowFlags.None) + if s.override_bg_color then + ImGui.PopStyleColor() + end + + for n = 0, 49 do + ImGui.Text("Some test %d", n) + end + ImGui.EndChild() + local child_is_hovered = ImGui.IsItemHovered() + local child_rect_min = ImGui.GetItemRectMin() + local child_rect_max = ImGui.GetItemRectMax() + ImGui.Text("Hovered: %d", child_is_hovered and 1 or 0) + ImGui.Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y) + end + + ImGui.TreePop() end -end -local function DemoWindowLayout_WidgetsWidth() - IMGUI_DEMO_MARKER("Layout/Widgets Width") - _, SL.show_indented_items = ImGui.Checkbox("Show indented items", SL.show_indented_items) + if ImGui.TreeNode("Widgets Width") then + IMGUI_DEMO_MARKER("Layout/Widgets Width") + _, s.show_indented_items = ImGui.Checkbox("Show indented items", s.show_indented_items) - -- Use SetNextItemWidth() to set the width of a single upcoming item. - -- Use PushItemWidth()/PopItemWidth() to set the width of a group of items. - -- In real code use you'll probably want to choose width values that are proportional to your font size - -- e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. + -- Use SetNextItemWidth() to set the width of a single upcoming item. + -- Use PushItemWidth()/PopItemWidth() to set the width of a group of items. + -- In real code use you'll probably want to choose width values that are proportional to your font size + -- e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. - local function block(text, help, width, l1, l2) - ImGui.Text(text) - if help then ImGui.SameLine(); DemoHelpMarker(help) end - ImGui.PushItemWidth(width) - SL.f = ImGui.DragFloat(l1, SL.f) - if SL.show_indented_items then + ImGui.Text("SetNextItemWidth/PushItemWidth(100)") + ImGui.SameLine(); HelpMarker("Fixed width.") + ImGui.PushItemWidth(100) + s.f = ImGui.DragFloat("float##1b", s.f) + if s.show_indented_items then ImGui.Indent() - SL.f = ImGui.DragFloat(l2, SL.f) + s.f = ImGui.DragFloat("float (indented)##1b", s.f) ImGui.Unindent() end ImGui.PopItemWidth() - end - block("SetNextItemWidth/PushItemWidth(100)", "Fixed width.", 100, "float##1b", "float (indented)##1b") - block("SetNextItemWidth/PushItemWidth(-100)", "Align to right edge minus 100", -100, "float##2a", "float (indented)##2b") - block("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)", "Half of available width.\n(~ right-cursor_pos)\n(works within a column set)", ImGui.GetContentRegionAvail().x * 0.5, "float##3a", "float (indented)##3b") - block("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)", "Align to right edge minus half", -ImGui.GetContentRegionAvail().x * 0.5, "float##4a", "float (indented)##4b") - block("SetNextItemWidth/PushItemWidth(-Min(GetContentRegionAvail().x * 0.40f, GetFontSize() * 12))", nil, -IM_MIN(ImGui.GetFontSize() * 12, ImGui.GetContentRegionAvail().x * 0.40), "float##5a", "float (indented)##5b") - -- Demonstrate using PushItemWidth to surround three items. - -- Calling SetNextItemWidth() before each of them would have the same effect. - block("SetNextItemWidth/PushItemWidth(-FLT_MIN)", "Align to right edge", -FLT_MIN, "##float6a", "float (indented)##6b") -end -local function DemoWindowLayout_BasicHorizontal() - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout") - ImGui.TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)") - - -- Text - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine") - ImGui.Text("Two items: Hello"); ImGui.SameLine() - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") - - -- Adjust spacing - ImGui.Text("More spacing: Hello"); ImGui.SameLine(0, 20) - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") - - -- Button - ImGui.AlignTextToFramePadding() - ImGui.Text("Normal buttons"); ImGui.SameLine() - ImGui.Button("Banana"); ImGui.SameLine() - ImGui.Button("Apple"); ImGui.SameLine() - ImGui.Button("Corniflower") - - -- Button - ImGui.Text("Small buttons"); ImGui.SameLine() - ImGui.SmallButton("Like this one"); ImGui.SameLine() - ImGui.Text("can fit within a text block.") - - -- Aligned to arbitrary position. Easy/cheap column. - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)") - ImGui.Text("Aligned") - ImGui.SameLine(150); ImGui.Text("x=150") - ImGui.SameLine(300); ImGui.Text("x=300") - ImGui.Text("Aligned") - ImGui.SameLine(150); ImGui.SmallButton("x=150") - ImGui.SameLine(300); ImGui.SmallButton("x=300") - - -- Checkbox - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)") - _, SL.c1 = ImGui.Checkbox("My", SL.c1); ImGui.SameLine() - _, SL.c2 = ImGui.Checkbox("Tailor", SL.c2); ImGui.SameLine() - _, SL.c3 = ImGui.Checkbox("Is", SL.c3); ImGui.SameLine() - _, SL.c4 = ImGui.Checkbox("Rich", SL.c4) - - -- Various - ImGui.PushItemWidth(ImGui.CalcTextSize("AAAAAAA").x) - local items = { "AAAA", "BBBB", "CCCC", "DDDD" } - if ImGui.Combo then - SL.item = ImGui.Combo("Combo", SL.item, items, #items) - else - NotPorted("Combo") - end - ImGui.SameLine() - SL.f0 = ImGui.SliderFloat("X", SL.f0, 0.0, 5.0); ImGui.SameLine() - SL.f1 = ImGui.SliderFloat("Y", SL.f1, 0.0, 5.0); ImGui.SameLine() - SL.f2 = ImGui.SliderFloat("Z", SL.f2, 0.0, 5.0) - - ImGui.Text("Lists:") - for i = 1, 4 do - if i > 1 then ImGui.SameLine() end - ImGui.PushID(i - 1) - if ImGui.ListBox then - SL.selection[i] = ImGui.ListBox("", SL.selection[i], items, #items) - else - NotPorted("ListBox") + ImGui.Text("SetNextItemWidth/PushItemWidth(-100)") + ImGui.SameLine(); HelpMarker("Align to right edge minus 100") + ImGui.PushItemWidth(-100) + s.f = ImGui.DragFloat("float##2a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##2b", s.f) + ImGui.Unindent() end - ImGui.PopID() - -- ImGui.SetItemTooltip("ListBox %d hovered", i) + ImGui.PopItemWidth() + + ImGui.Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)") + ImGui.SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)") + ImGui.PushItemWidth(ImGui.GetContentRegionAvail().x * 0.5) + s.f = ImGui.DragFloat("float##3a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##3b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + ImGui.Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)") + ImGui.SameLine(); HelpMarker("Align to right edge minus half") + ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.5) + s.f = ImGui.DragFloat("float##4a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##4b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + ImGui.Text("SetNextItemWidth/PushItemWidth(-Min(GetContentRegionAvail().x * 0.40f, GetFontSize() * 12))") + ImGui.PushItemWidth(-ImMin(ImGui.GetFontSize() * 12, ImGui.GetContentRegionAvail().x * 0.40)) + s.f = ImGui.DragFloat("float##5a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##5b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + -- Demonstrate using PushItemWidth to surround three items. + -- Calling SetNextItemWidth() before each of them would have the same effect. + ImGui.Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)") + ImGui.SameLine(); HelpMarker("Align to right edge") + ImGui.PushItemWidth(-FLT_MIN) + s.f = ImGui.DragFloat("##float6a", s.f) + if s.show_indented_items then + ImGui.Indent() + s.f = ImGui.DragFloat("float (indented)##6b", s.f) + ImGui.Unindent() + end + ImGui.PopItemWidth() + + ImGui.TreePop() end - ImGui.PopItemWidth() - -- Dummy - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy") - local button_sz = ImVec2(40, 40) - ImGui.Button("A", button_sz); ImGui.SameLine() - ImGui.Dummy(button_sz); ImGui.SameLine() - ImGui.Button("B", button_sz) + if ImGui.TreeNode("Basic Horizontal Layout") then + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout") + ImGui.TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)") - -- Manually wrapping - -- (we should eventually provide this as an automatic layout feature, but for now you can do it manually) - IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping") - ImGui.Text("Manual wrapping:") - local style = ImGui.GetStyle() - local buttons_count = 20 - local window_visible_x2 = ImGui.GetCursorScreenPos().x + ImGui.GetContentRegionAvail().x - for n = 0, buttons_count - 1 do - ImGui.PushID(n) - ImGui.Button("Box", button_sz) - local last_button_x2 = ImGui.GetItemRectMax().x - local next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x -- Expected position if next button was on same line - if n + 1 < buttons_count and next_button_x2 < window_visible_x2 then + -- Text + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine") + ImGui.Text("Two items: Hello"); ImGui.SameLine() + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") + + -- Adjust spacing + ImGui.Text("More spacing: Hello"); ImGui.SameLine(0, 20) + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Sailor") + + -- Button + ImGui.AlignTextToFramePadding() + ImGui.Text("Normal buttons"); ImGui.SameLine() + ImGui.Button("Banana"); ImGui.SameLine() + ImGui.Button("Apple"); ImGui.SameLine() + ImGui.Button("Corniflower") + + -- Button + ImGui.Text("Small buttons"); ImGui.SameLine() + ImGui.SmallButton("Like this one"); ImGui.SameLine() + ImGui.Text("can fit within a text block.") + + -- Aligned to arbitrary position. Easy/cheap column. + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)") + ImGui.Text("Aligned") + ImGui.SameLine(150); ImGui.Text("x=150") + ImGui.SameLine(300); ImGui.Text("x=300") + ImGui.Text("Aligned") + ImGui.SameLine(150); ImGui.SmallButton("x=150") + ImGui.SameLine(300); ImGui.SmallButton("x=300") + + -- Checkbox + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)") + _, s.c1 = ImGui.Checkbox("My", s.c1); ImGui.SameLine() + _, s.c2 = ImGui.Checkbox("Tailor", s.c2); ImGui.SameLine() + _, s.c3 = ImGui.Checkbox("Is", s.c3); ImGui.SameLine() + _, s.c4 = ImGui.Checkbox("Rich", s.c4) + + -- Various + ImGui.PushItemWidth(ImGui.CalcTextSize("AAAAAAA").x) + local items = { "AAAA", "BBBB", "CCCC", "DDDD" } + s.item = ImGui.Combo("Combo", s.item, items, #items); ImGui.SameLine() + s.f0 = ImGui.SliderFloat("X", s.f0, 0.0, 5.0); ImGui.SameLine() + s.f1 = ImGui.SliderFloat("Y", s.f1, 0.0, 5.0); ImGui.SameLine() + s.f2 = ImGui.SliderFloat("Z", s.f2, 0.0, 5.0) + + ImGui.Text("Lists:") + for i = 0, 3 do + if i > 0 then ImGui.SameLine() end + ImGui.PushID(i) + s.selection[i + 1] = ImGui.ListBox("", s.selection[i + 1], items, #items) + ImGui.PopID() + --ImGui.SetItemTooltip("ListBox %d hovered", i); + end + ImGui.PopItemWidth() + + -- Dummy + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy") + local button_sz = ImVec2(40, 40) + ImGui.Button("A", button_sz); ImGui.SameLine() + ImGui.Dummy(button_sz); ImGui.SameLine() + ImGui.Button("B", button_sz) + + -- Manually wrapping + -- (we should eventually provide this as an automatic layout feature, but for now you can do it manually) + IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping") + ImGui.Text("Manual wrapping:") + local style = ImGui.GetStyle() + local buttons_count = 20 + local window_visible_x2 = ImGui.GetCursorScreenPos().x + ImGui.GetContentRegionAvail().x + for n = 0, buttons_count - 1 do + ImGui.PushID(n) + ImGui.Button("Box", button_sz) + local last_button_x2 = ImGui.GetItemRectMax().x + local next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x -- Expected position if next button was on same line + if n + 1 < buttons_count and next_button_x2 < window_visible_x2 then + ImGui.SameLine() + end + ImGui.PopID() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Groups") then + IMGUI_DEMO_MARKER("Layout/Groups") + HelpMarker( + "BeginGroup() basically locks the horizontal position for new line. " .. + "EndGroup() bundles the whole group so that you can use \"item\" functions such as " .. + "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.") + ImGui.BeginGroup() + do + ImGui.BeginGroup() + ImGui.Button("AAA") ImGui.SameLine() + ImGui.Button("BBB") + ImGui.SameLine() + ImGui.BeginGroup() + ImGui.Button("CCC") + ImGui.Button("DDD") + ImGui.EndGroup() + ImGui.SameLine() + ImGui.Button("EEE") + ImGui.EndGroup() + ImGui.SetItemTooltip("First group hovered") end - ImGui.PopID() - end -end + -- Capture the group size and create widgets using the same size + local size = ImGui.GetItemRectSize() + local values = { 0.5, 0.20, 0.80, 0.60, 0.25 } + ImGui.PlotHistogram("##values", values, nil, #values, 0, nil, 0.0, 1.0, size) -local function DemoWindowLayout_Groups() - IMGUI_DEMO_MARKER("Layout/Groups") - DemoHelpMarker( - "BeginGroup() basically locks the horizontal position for new line. " .. - "EndGroup() bundles the whole group so that you can use \"item\" functions such as " .. - "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.") - ImGui.BeginGroup() - do - ImGui.BeginGroup() - ImGui.Button("AAA") + ImGui.Button("ACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) ImGui.SameLine() - ImGui.Button("BBB") - ImGui.SameLine() - ImGui.BeginGroup() - ImGui.Button("CCC") - ImGui.Button("DDD") + ImGui.Button("REACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) ImGui.EndGroup() ImGui.SameLine() - ImGui.Button("EEE") - ImGui.EndGroup() - ImGui.SetItemTooltip("First group hovered") - end - -- Capture the group size and create widgets using the same size - local size = ImGui.GetItemRectSize() - local values = { 0.5, 0.20, 0.80, 0.60, 0.25 } - ImGui.PlotHistogram("##values", values, nil, #values, 0, nil, 0.0, 1.0, size) - ImGui.Button("ACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) - ImGui.SameLine() - ImGui.Button("REACTION", ImVec2((size.x - ImGui.GetStyle().ItemSpacing.x) * 0.5, size.y)) - ImGui.EndGroup() - ImGui.SameLine() - - ImGui.Button("LEVERAGE\nBUZZWORD", size) - ImGui.SameLine() - - if ImGui.BeginListBox and ImGui.BeginListBox("List", size) then - ImGui.Selectable("Selected", true) - ImGui.Selectable("Not Selected", false) - ImGui.EndListBox() - end -end - -local function DemoWindowLayout_TextBaseline() - IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment") - do - ImGui.BulletText("Text baseline:") - ImGui.SameLine(); DemoHelpMarker( - "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " .. - "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.") - ImGui.Indent() - - ImGui.Text("KO Blahblah"); ImGui.SameLine() - ImGui.Button("Some framed item"); ImGui.SameLine() - DemoHelpMarker("Baseline of button will look misaligned with text..") - - -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. - -- (because we don't know what's coming after the Text() statement, we need to move the text baseline - -- down by FramePadding.y ahead of time) - ImGui.AlignTextToFramePadding() - ImGui.Text("OK Blahblah"); ImGui.SameLine() - ImGui.Button("Some framed item##2"); ImGui.SameLine() - DemoHelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y") - - -- SmallButton() uses the same vertical padding as Text - ImGui.Button("TEST##1"); ImGui.SameLine() - ImGui.Text("TEST"); ImGui.SameLine() - ImGui.SmallButton("TEST##2") - - -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. - ImGui.AlignTextToFramePadding() - ImGui.Text("Text aligned to framed item"); ImGui.SameLine() - ImGui.Button("Item##1"); ImGui.SameLine() - ImGui.Text("Item"); ImGui.SameLine() - ImGui.SmallButton("Item##2"); ImGui.SameLine() - ImGui.Button("Item##3") - - ImGui.Unindent() - end - - ImGui.Spacing() - - do - ImGui.BulletText("Multi-line text:") - ImGui.Indent() - ImGui.Text("One\nTwo\nThree"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("Banana") - - ImGui.Text("Banana"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("One\nTwo\nThree") - - ImGui.Button("HOP##1"); ImGui.SameLine() - ImGui.Text("Banana"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("Banana") - - ImGui.Button("HOP##2"); ImGui.SameLine() - ImGui.Text("Hello\nWorld"); ImGui.SameLine() - ImGui.Text("Banana") - ImGui.Unindent() - end - - ImGui.Spacing() - - do - ImGui.BulletText("Misc items:") - ImGui.Indent() - - -- SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. - ImGui.Button("80x80", ImVec2(80, 80)) + ImGui.Button("LEVERAGE\nBUZZWORD", size) ImGui.SameLine() - ImGui.Button("50x50", ImVec2(50, 50)) - ImGui.SameLine() - ImGui.Button("Button()") - ImGui.SameLine() - ImGui.SmallButton("SmallButton()") - -- Tree - -- (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags.DrawLinesNone to disable hierarchy outline) - local spacing = ImGui.GetStyle().ItemInnerSpacing.x - ImGui.Button("Button##1") -- Will make line higher - ImGui.SameLine(0.0, spacing) - if ImGui.TreeNodeEx("Node##1", ImGuiTreeNodeFlags.DrawLinesNone) then - -- Placeholder tree data - for i = 0, 5 do - ImGui.BulletText("Item %d..", i) - end - ImGui.TreePop() + if ImGui.BeginListBox("List", size) then + ImGui.Selectable("Selected", true) + ImGui.Selectable("Not Selected", false) + ImGui.EndListBox() end - local padding = math.floor(ImGui.GetFontSize() * 1.20) -- Large padding - ImGui.PushStyleVarY(ImGuiStyleVar.FramePadding, padding) - ImGui.Button("Button##2") - ImGui.PopStyleVar() - ImGui.SameLine(0.0, spacing) - if ImGui.TreeNodeEx("Node##2", ImGuiTreeNodeFlags.DrawLinesNone) then - ImGui.TreePop() + ImGui.TreePop() + end + + if ImGui.TreeNode("Text Baseline Alignment") then + IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment") + do + ImGui.BulletText("Text baseline:") + ImGui.SameLine(); HelpMarker( + "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " .. + "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.") + ImGui.Indent() + + ImGui.Text("KO Blahblah"); ImGui.SameLine() + ImGui.Button("Some framed item"); ImGui.SameLine() + HelpMarker("Baseline of button will look misaligned with text..") + + -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. + -- (because we don't know what's coming after the Text() statement, we need to move the text baseline + -- down by FramePadding.y ahead of time) + ImGui.AlignTextToFramePadding() + ImGui.Text("OK Blahblah"); ImGui.SameLine() + ImGui.Button("Some framed item##2"); ImGui.SameLine() + HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y") + + -- SmallButton() uses the same vertical padding as Text + ImGui.Button("TEST##1"); ImGui.SameLine() + ImGui.Text("TEST"); ImGui.SameLine() + ImGui.SmallButton("TEST##2") + + -- If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. + ImGui.AlignTextToFramePadding() + ImGui.Text("Text aligned to framed item"); ImGui.SameLine() + ImGui.Button("Item##1"); ImGui.SameLine() + ImGui.Text("Item"); ImGui.SameLine() + ImGui.SmallButton("Item##2"); ImGui.SameLine() + ImGui.Button("Item##3") + + ImGui.Unindent() end - -- Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. - -- Otherwise you can use SmallButton() (smaller fit). - ImGui.AlignTextToFramePadding() + ImGui.Spacing() - -- Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add - -- other contents "inside" the node. - local node_open = ImGui.TreeNode("Node##3") - ImGui.SameLine(0.0, spacing); ImGui.Button("Button##3") - if node_open then - -- Placeholder tree data - for i = 0, 5 do - ImGui.BulletText("Item %d..", i) - end - ImGui.TreePop() + do + ImGui.BulletText("Multi-line text:") + ImGui.Indent() + ImGui.Text("One\nTwo\nThree"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("Banana") + + ImGui.Text("Banana"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("One\nTwo\nThree") + + ImGui.Button("HOP##1"); ImGui.SameLine() + ImGui.Text("Banana"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("Banana") + + ImGui.Button("HOP##2"); ImGui.SameLine() + ImGui.Text("Hello\nWorld"); ImGui.SameLine() + ImGui.Text("Banana") + ImGui.Unindent() end - -- Bullet - ImGui.Button("Button##4") - ImGui.SameLine(0.0, spacing) - ImGui.BulletText("Bullet text") + ImGui.Spacing() - ImGui.AlignTextToFramePadding() - ImGui.BulletText("Node") - ImGui.SameLine(0.0, spacing); ImGui.Button("Button##5") - ImGui.Unindent() - end -end + do + ImGui.BulletText("Misc items:") + ImGui.Indent() -local function DemoWindowLayout_HorizontalContentsSizeWindow() - if SL.explicit_content_size then - ImGui.SetNextWindowContentSize(ImVec2(SL.contents_size_x, 0.0)) - end - SL.show_horizontal_contents_size_demo_window = ImGui.Begin("Horizontal contents size demo window", SL.show_horizontal_contents_size_demo_window, SL.show_h_scrollbar and ImGuiWindowFlags.HorizontalScrollbar or 0) - IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window") - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(2, 0)) - ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(2, 0)) - DemoHelpMarker( - "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n" .. - "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.") - _, SL.show_h_scrollbar = ImGui.Checkbox("H-scrollbar", SL.show_h_scrollbar) - _, SL.show_button = ImGui.Checkbox("Button", SL.show_button) -- Will grow contents size (unless explicitly overwritten) - _, SL.show_tree_nodes = ImGui.Checkbox("Tree nodes", SL.show_tree_nodes) -- Will grow contents size and display highlight over full width - _, SL.show_text_wrapped = ImGui.Checkbox("Text wrapped", SL.show_text_wrapped) -- Will grow and use contents size - _, SL.show_columns = ImGui.Checkbox("Columns", SL.show_columns) -- Will use contents size - _, SL.show_tab_bar = ImGui.Checkbox("Tab bar", SL.show_tab_bar) -- Will use contents size - _, SL.show_child = ImGui.Checkbox("Child", SL.show_child) -- Will grow and use contents size - _, SL.explicit_content_size = ImGui.Checkbox("Explicit content size", SL.explicit_content_size) - ImGui.Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui.GetScrollX(), ImGui.GetScrollMaxX(), ImGui.GetScrollY(), ImGui.GetScrollMaxY()) - if SL.explicit_content_size then - ImGui.SameLine() - ImGui.SetNextItemWidth(ImGui.CalcTextSize("123456").x) - SL.contents_size_x = ImGui.DragFloat("##csx", SL.contents_size_x) - local p = ImGui.GetCursorScreenPos() - ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE) - ImGui.GetWindowDrawList():AddRectFilled(ImVec2(p.x + SL.contents_size_x - 10, p.y), ImVec2(p.x + SL.contents_size_x, p.y + 10), IM_COL32_WHITE) - ImGui.Dummy(ImVec2(0, 10)) - end - ImGui.PopStyleVar(2) - ImGui.Separator() - if SL.show_button then - ImGui.Button("this is a 300-wide button", ImVec2(300, 0)) - end - if SL.show_tree_nodes then - local open = true - if ImGui.TreeNode("this is a tree node") then - if ImGui.TreeNode("another one of those tree node...") then - ImGui.Text("Some tree contents") + -- SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. + ImGui.Button("80x80", ImVec2(80, 80)) + ImGui.SameLine() + ImGui.Button("50x50", ImVec2(50, 50)) + ImGui.SameLine() + ImGui.Button("Button()") + ImGui.SameLine() + ImGui.SmallButton("SmallButton()") + + -- Tree + -- (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags.DrawLinesNone to disable hierarchy outline) + local spacing = ImGui.GetStyle().ItemInnerSpacing.x + ImGui.Button("Button##1") -- Will make line higher + ImGui.SameLine(0.0, spacing) + if ImGui.TreeNodeEx("Node##1", ImGuiTreeNodeFlags.DrawLinesNone) then + -- Placeholder tree data + for i = 0, 5 do + ImGui.BulletText("Item %d..", i) + end ImGui.TreePop() end - ImGui.TreePop() - end - ImGui.CollapsingHeader("CollapsingHeader", open) - end - if SL.show_text_wrapped then - ImGui.TextWrapped("This text should automatically wrap on the edge of the work rectangle.") - end - if SL.show_columns then - ImGui.Text("Tables:") - if ImGui.BeginTable("table", 4, ImGuiTableFlags.Borders) then - for n = 0, 3 do - ImGui.TableNextColumn() - ImGui.Text("Width %.2f", ImGui.GetContentRegionAvail().x) + + local padding = math.floor(ImGui.GetFontSize() * 1.20) -- Large padding + ImGui.PushStyleVarY(ImGuiStyleVar.FramePadding, padding) + ImGui.Button("Button##2") + ImGui.PopStyleVar() + ImGui.SameLine(0.0, spacing) + if ImGui.TreeNodeEx("Node##2", ImGuiTreeNodeFlags.DrawLinesNone) then + ImGui.TreePop() end - ImGui.EndTable() - end - ImGui.Text("Columns:") - if ImGui.Columns then - ImGui.Columns(4) - for n = 0, 3 do - ImGui.Text("Width %.2f", ImGui.GetColumnWidth()) - ImGui.NextColumn() + + -- Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. + -- Otherwise you can use SmallButton() (smaller fit). + ImGui.AlignTextToFramePadding() + + -- Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add + -- other contents "inside" the node. + local node_open = ImGui.TreeNode("Node##3") + ImGui.SameLine(0.0, spacing); ImGui.Button("Button##3") + if node_open then + -- Placeholder tree data + for i = 0, 5 do + ImGui.BulletText("Item %d..", i) + end + ImGui.TreePop() end - ImGui.Columns(1) - else - NotPorted("Columns") + + -- Bullet + ImGui.Button("Button##4") + ImGui.SameLine(0.0, spacing) + ImGui.BulletText("Bullet text") + + ImGui.AlignTextToFramePadding() + ImGui.BulletText("Node") + ImGui.SameLine(0.0, spacing); ImGui.Button("Button##5") + ImGui.Unindent() end - end - if SL.show_tab_bar and ImGui.BeginTabBar and ImGui.BeginTabBar("Hello") then - if ImGui.BeginTabItem("OneOneOne") then ImGui.EndTabItem() end - if ImGui.BeginTabItem("TwoTwoTwo") then ImGui.EndTabItem() end - if ImGui.BeginTabItem("ThreeThreeThree") then ImGui.EndTabItem() end - if ImGui.BeginTabItem("FourFourFour") then ImGui.EndTabItem() end - ImGui.EndTabBar() - end - if SL.show_child then - BeginChild("child", ImVec2(0, 0), ImGuiChildFlags.Borders) - ImGui.EndChild() - end - ImGui.End() -end -local function DemoWindowLayout_Scrolling() - IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical") - -- Vertical scroll functions - DemoHelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.") - - _, SL.enable_extra_decorations = ImGui.Checkbox("Decoration", SL.enable_extra_decorations) - - ImGui.PushItemWidth(ImGui.GetFontSize() * 10) - local changed - SL.track_item, changed = ImGui.DragInt("##item", SL.track_item, 0.25, 0, 99, "Item = %d") - SL.enable_track = SL.enable_track or changed - ImGui.SameLine() - _, SL.enable_track = ImGui.Checkbox("Track", SL.enable_track) - - local scroll_to_off - SL.scroll_to_off_px, scroll_to_off = ImGui.DragFloat("##off", SL.scroll_to_off_px, 1.00, 0, FLT_MAX, "+%.0f px") - ImGui.SameLine() - scroll_to_off = ImGui.Button("Scroll Offset") or scroll_to_off - - local scroll_to_pos - SL.scroll_to_pos_px, scroll_to_pos = ImGui.DragFloat("##pos", SL.scroll_to_pos_px, 1.00, -10, FLT_MAX, "X/Y = %.0f px") - ImGui.SameLine() - scroll_to_pos = ImGui.Button("Scroll To Pos") or scroll_to_pos - ImGui.PopItemWidth() - - if scroll_to_off or scroll_to_pos then - SL.enable_track = false + ImGui.TreePop() end - local style = ImGui.GetStyle() - local child_w = (ImGui.GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5 - if child_w < 1.0 then - child_w = 1.0 - end - ImGui.PushID("##VerticalScrolling") - local vnames = { "Top", "25%", "Center", "75%", "Bottom" } - for i = 0, 4 do - if i > 0 then ImGui.SameLine() end - ImGui.BeginGroup() - ImGui.TextUnformatted(vnames[i + 1]) + if ImGui.TreeNode("Scrolling") then + IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical") + -- Vertical scroll functions + HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.") - local child_flags = SL.enable_extra_decorations and ImGuiWindowFlags.MenuBar or 0 - local child_id = ImGui.GetID(i) - local child_is_visible = BeginChild(child_id, ImVec2(child_w, 200.0), ImGuiChildFlags.Borders, child_flags) - if ImGui.BeginMenuBar() then - ImGui.TextUnformatted("abc") - ImGui.EndMenuBar() + _, s.enable_extra_decorations = ImGui.Checkbox("Decoration", s.enable_extra_decorations) + + ImGui.PushItemWidth(ImGui.GetFontSize() * 10) + local track_changed + s.track_item, track_changed = ImGui.DragInt("##item", s.track_item, 0.25, 0, 99, "Item = %d") + s.enable_track = s.enable_track or track_changed + ImGui.SameLine() + _, s.enable_track = ImGui.Checkbox("Track", s.enable_track) + + local scroll_to_off + s.scroll_to_off_px, scroll_to_off = ImGui.DragFloat("##off", s.scroll_to_off_px, 1.00, 0, FLT_MAX, "+%.0f px") + ImGui.SameLine() + scroll_to_off = ImGui.Button("Scroll Offset") or scroll_to_off + + local scroll_to_pos + s.scroll_to_pos_px, scroll_to_pos = ImGui.DragFloat("##pos", s.scroll_to_pos_px, 1.00, -10, FLT_MAX, "X/Y = %.0f px") + ImGui.SameLine() + scroll_to_pos = ImGui.Button("Scroll To Pos") or scroll_to_pos + ImGui.PopItemWidth() + + if scroll_to_off or scroll_to_pos then + s.enable_track = false end - if scroll_to_off then - ImGui.SetScrollY(SL.scroll_to_off_px) + + local style = ImGui.GetStyle() + local child_w = (ImGui.GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5 + if child_w < 1.0 then + child_w = 1.0 end - if scroll_to_pos then - ImGui.SetScrollFromPosY(ImGui.GetCursorStartPos().y + SL.scroll_to_pos_px, i * 0.25) - end - if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items - for item = 0, 99 do - if SL.enable_track and item == SL.track_item then - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) - ImGui.SetScrollHereY(i * 0.25) -- 0.0f:top, 0.5f:center, 1.0f:bottom - else - ImGui.Text("Item %d", item) + ImGui.PushID("##VerticalScrolling") + for i = 0, 4 do + if i > 0 then ImGui.SameLine() end + ImGui.BeginGroup() + local names = { "Top", "25%", "Center", "75%", "Bottom" } + ImGui.TextUnformatted(names[i + 1]) + + local child_flags = 0 + if s.enable_extra_decorations then child_flags = ImGuiWindowFlags.MenuBar end + local child_id = ImGui.GetID(i) + local child_is_visible = ImGui.BeginChild(child_id, ImVec2(child_w, 200.0), ImGuiChildFlags.Borders, child_flags) + if ImGui.BeginMenuBar() then + ImGui.TextUnformatted("abc") + ImGui.EndMenuBar() + end + if scroll_to_off then + ImGui.SetScrollY(s.scroll_to_off_px) + end + if scroll_to_pos then + ImGui.SetScrollFromPosY(ImGui.GetCursorStartPos().y + s.scroll_to_pos_px, i * 0.25) + end + if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items + for item = 0, 99 do + if s.enable_track and item == s.track_item then + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) + ImGui.SetScrollHereY(i * 0.25) -- 0.0f:top, 0.5f:center, 1.0f:bottom + else + ImGui.Text("Item %d", item) + end end end + local scroll_y = ImGui.GetScrollY() + local scroll_max_y = ImGui.GetScrollMaxY() + ImGui.EndChild() + ImGui.Text("%.0f/%.0f", scroll_y, scroll_max_y) + ImGui.EndGroup() end - local scroll_y = ImGui.GetScrollY() - local scroll_max_y = ImGui.GetScrollMaxY() - ImGui.EndChild() - ImGui.Text("%.0f/%.0f", scroll_y, scroll_max_y) - ImGui.EndGroup() - end - ImGui.PopID() + ImGui.PopID() - -- Horizontal scroll functions - IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal") - ImGui.Spacing() - DemoHelpMarker( - "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" .. - "Because the clipping rectangle of most window hides half worth of WindowPadding on the " .. - "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " .. - "equivalent SetScrollFromPosY(+1) wouldn't.") - ImGui.PushID("##HorizontalScrolling") - local hnames = { "Left", "25%", "Center", "75%", "Right" } - for i = 0, 4 do - local child_height = ImGui.GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0 - local child_flags = bit32.bor(ImGuiWindowFlags.HorizontalScrollbar, SL.enable_extra_decorations and ImGuiWindowFlags.AlwaysVerticalScrollbar or 0) - local child_id = ImGui.GetID(i) - local child_is_visible = BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags.Borders, child_flags) - if scroll_to_off then - ImGui.SetScrollX(SL.scroll_to_off_px) - end - if scroll_to_pos then - ImGui.SetScrollFromPosX(ImGui.GetCursorStartPos().x + SL.scroll_to_pos_px, i * 0.25) - end - if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items - for item = 0, 99 do - if item > 0 then - ImGui.SameLine() - end - if SL.enable_track and item == SL.track_item then - ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) - ImGui.SetScrollHereX(i * 0.25) -- 0.0f:left, 0.5f:center, 1.0f:right - else - ImGui.Text("Item %d", item) + -- Horizontal scroll functions + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal") + ImGui.Spacing() + HelpMarker( + "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" .. + "Because the clipping rectangle of most window hides half worth of WindowPadding on the " .. + "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " .. + "equivalent SetScrollFromPosY(+1) wouldn't.") + ImGui.PushID("##HorizontalScrolling") + for i = 0, 4 do + local child_height = ImGui.GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0 + local child_flags = ImGuiWindowFlags.HorizontalScrollbar + if s.enable_extra_decorations then child_flags = bit32.bor(child_flags, ImGuiWindowFlags.AlwaysVerticalScrollbar) end + local child_id = ImGui.GetID(i) + local child_is_visible = ImGui.BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags.Borders, child_flags) + if scroll_to_off then + ImGui.SetScrollX(s.scroll_to_off_px) + end + if scroll_to_pos then + ImGui.SetScrollFromPosX(ImGui.GetCursorStartPos().x + s.scroll_to_pos_px, i * 0.25) + end + if child_is_visible then -- Avoid calling SetScrollHereY when running with culled items + for item = 0, 99 do + if item > 0 then + ImGui.SameLine() + end + if s.enable_track and item == s.track_item then + ImGui.TextColored(ImVec4(1, 1, 0, 1), "Item %d", item) + ImGui.SetScrollHereX(i * 0.25) -- 0.0f:left, 0.5f:center, 1.0f:right + else + ImGui.Text("Item %d", item) + end end end + local scroll_x = ImGui.GetScrollX() + local scroll_max_x = ImGui.GetScrollMaxX() + ImGui.EndChild() + ImGui.SameLine() + local names = { "Left", "25%", "Center", "75%", "Right" } + ImGui.Text("%s\n%.0f/%.0f", names[i + 1], scroll_x, scroll_max_x) + ImGui.Spacing() + end + ImGui.PopID() + + -- Miscellaneous Horizontal Scrolling Demo + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)") + HelpMarker( + "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" .. + "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().") + s.lines = ImGui.SliderInt("Lines", s.lines, 1, 15) + ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 3.0) + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(2.0, 1.0)) + local scrolling_child_size = ImVec2(0, ImGui.GetFrameHeightWithSpacing() * 7 + 30) + ImGui.BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags.Borders, ImGuiWindowFlags.HorizontalScrollbar) + for line = 0, s.lines - 1 do + -- Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() + -- If you want to create your own time line for a real application you may be better off manipulating + -- the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets + -- yourself. You may also want to use the lower-level ImDrawList API. + local num_buttons = 10 + ((line % 2 == 1) and line * 9 or line * 3) + local base_w = ImGui.GetFontSize() * 3 + for n = 0, num_buttons - 1 do + if n > 0 then ImGui.SameLine() end + ImGui.PushID(n + line * 1000) + local num_buf = string.format("%d", n) + local label = num_buf + if n % 15 == 0 then label = "FizzBuzz" elseif n % 3 == 0 then label = "Fizz" elseif n % 5 == 0 then label = "Buzz" end + local hue = n * 0.05 + ImGui.PushStyleColor(ImGuiCol.Button, ImColor.HSV(hue, 0.6, 0.6).Value) + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, ImColor.HSV(hue, 0.7, 0.7).Value) + ImGui.PushStyleColor(ImGuiCol.ButtonActive, ImColor.HSV(hue, 0.8, 0.8).Value) + ImGui.Button(label, ImVec2(base_w + math.sin(line + n) * base_w * 0.5, 0.0)) + ImGui.PopStyleColor(3) + ImGui.PopID() + end end local scroll_x = ImGui.GetScrollX() local scroll_max_x = ImGui.GetScrollMaxX() ImGui.EndChild() + ImGui.PopStyleVar(2) + local scroll_x_delta = 0.0 + ImGui.SmallButton("<<") + if ImGui.IsItemActive() then + scroll_x_delta = -ImGui.GetIO().DeltaTime * 1000.0 + end ImGui.SameLine() - ImGui.Text("%s\n%.0f/%.0f", hnames[i + 1], scroll_x, scroll_max_x) + ImGui.Text("Scroll from code"); ImGui.SameLine() + ImGui.SmallButton(">>") + if ImGui.IsItemActive() then + scroll_x_delta = ImGui.GetIO().DeltaTime * 1000.0 + end + ImGui.SameLine() + ImGui.Text("%.0f/%.0f", scroll_x, scroll_max_x) + if scroll_x_delta ~= 0.0 then + -- Demonstrate a trick: you can use Begin to set yourself in the context of another window + -- (here we are already out of your child window) + ImGui.BeginChild("scrolling") + ImGui.SetScrollX(ImGui.GetScrollX() + scroll_x_delta) + ImGui.EndChild() + end ImGui.Spacing() - end - ImGui.PopID() - -- Miscellaneous Horizontal Scrolling Demo - IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)") - DemoHelpMarker( - "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" .. - "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().") - SL.lines = ImGui.SliderInt("Lines", SL.lines, 1, 15) - ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 3.0) - ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(2.0, 1.0)) - local scrolling_child_size = ImVec2(0, ImGui.GetFrameHeightWithSpacing() * 7 + 30) - BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags.Borders, ImGuiWindowFlags.HorizontalScrollbar) - for line = 0, SL.lines - 1 do - -- Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() - -- If you want to create your own time line for a real application you may be better off manipulating - -- the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets - -- yourself. You may also want to use the lower-level ImDrawList API. - local num_buttons = 10 + ((line % 2 == 1) and line * 9 or line * 3) - local base_w = ImGui.GetFontSize() * 3 - for n = 0, num_buttons - 1 do - if n > 0 then ImGui.SameLine() end - ImGui.PushID(n + line * 1000) - local label = (n % 15 == 0) and "FizzBuzz" or (n % 3 == 0) and "Fizz" or (n % 5 == 0) and "Buzz" or tostring(n) - local hue = n * 0.05 - ImGui.PushStyleColor(ImGuiCol.Button, HSV(hue, 0.6, 0.6)) - ImGui.PushStyleColor(ImGuiCol.ButtonHovered, HSV(hue, 0.7, 0.7)) - ImGui.PushStyleColor(ImGuiCol.ButtonActive, HSV(hue, 0.8, 0.8)) - ImGui.Button(label, ImVec2(base_w + math.sin(line + n) * base_w * 0.5, 0.0)) - ImGui.PopStyleColor(3) + _, s.show_horizontal_contents_size_demo_window = ImGui.Checkbox("Show Horizontal contents size demo window", s.show_horizontal_contents_size_demo_window) + + if s.show_horizontal_contents_size_demo_window then + if s.explicit_content_size then + ImGui.SetNextWindowContentSize(ImVec2(s.contents_size_x, 0.0)) + end + local window_flags = 0 + if s.show_h_scrollbar then window_flags = ImGuiWindowFlags.HorizontalScrollbar end + s.show_horizontal_contents_size_demo_window = ImGui.Begin("Horizontal contents size demo window", s.show_horizontal_contents_size_demo_window, window_flags) + IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window") + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(2, 0)) + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(2, 0)) + HelpMarker( + "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n" .. + "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.") + _, s.show_h_scrollbar = ImGui.Checkbox("H-scrollbar", s.show_h_scrollbar) + _, s.show_button = ImGui.Checkbox("Button", s.show_button) -- Will grow contents size (unless explicitly overwritten) + _, s.show_tree_nodes = ImGui.Checkbox("Tree nodes", s.show_tree_nodes) -- Will grow contents size and display highlight over full width + _, s.show_text_wrapped = ImGui.Checkbox("Text wrapped", s.show_text_wrapped)-- Will grow and use contents size + _, s.show_columns = ImGui.Checkbox("Columns", s.show_columns) -- Will use contents size + _, s.show_tab_bar = ImGui.Checkbox("Tab bar", s.show_tab_bar) -- Will use contents size + _, s.show_child = ImGui.Checkbox("Child", s.show_child) -- Will grow and use contents size + _, s.explicit_content_size = ImGui.Checkbox("Explicit content size", s.explicit_content_size) + ImGui.Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui.GetScrollX(), ImGui.GetScrollMaxX(), ImGui.GetScrollY(), ImGui.GetScrollMaxY()) + if s.explicit_content_size then + ImGui.SameLine() + ImGui.SetNextItemWidth(ImGui.CalcTextSize("123456").x) + s.contents_size_x = ImGui.DragFloat("##csx", s.contents_size_x) + local p = ImGui.GetCursorScreenPos() + ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE) + ImGui.GetWindowDrawList():AddRectFilled(ImVec2(p.x + s.contents_size_x - 10, p.y), ImVec2(p.x + s.contents_size_x, p.y + 10), IM_COL32_WHITE) + ImGui.Dummy(ImVec2(0, 10)) + end + ImGui.PopStyleVar(2) + ImGui.Separator() + if s.show_button then + ImGui.Button("this is a 300-wide button", ImVec2(300, 0)) + end + if s.show_tree_nodes then + local open = true + if ImGui.TreeNode("this is a tree node") then + if ImGui.TreeNode("another one of those tree node...") then + ImGui.Text("Some tree contents") + ImGui.TreePop() + end + ImGui.TreePop() + end + _, open = ImGui.CollapsingHeader("CollapsingHeader", open) + end + if s.show_text_wrapped then + ImGui.TextWrapped("This text should automatically wrap on the edge of the work rectangle.") + end + if s.show_columns then + ImGui.Text("Tables:") + if ImGui.BeginTable("table", 4, ImGuiTableFlags.Borders) then + for n = 0, 3 do + ImGui.TableNextColumn() + ImGui.Text("Width %.2f", ImGui.GetContentRegionAvail().x) + end + ImGui.EndTable() + end + ImGui.Text("Columns:") + ImGui.Columns(4) + for n = 0, 3 do + ImGui.Text("Width %.2f", ImGui.GetColumnWidth()) + ImGui.NextColumn() + end + ImGui.Columns(1) + end + if s.show_tab_bar and ImGui.BeginTabBar("Hello") then + if ImGui.BeginTabItem("OneOneOne") then ImGui.EndTabItem() end + if ImGui.BeginTabItem("TwoTwoTwo") then ImGui.EndTabItem() end + if ImGui.BeginTabItem("ThreeThreeThree") then ImGui.EndTabItem() end + if ImGui.BeginTabItem("FourFourFour") then ImGui.EndTabItem() end + ImGui.EndTabBar() + end + if s.show_child then + ImGui.BeginChild("child", ImVec2(0, 0), ImGuiChildFlags.Borders) + ImGui.EndChild() + end + ImGui.End() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Text Clipping") then + IMGUI_DEMO_MARKER("Layout/Text Clipping") + local size = s.size + local offset = s.offset + ImGui.DragFloat2("size", size, 0.5, 1.0, 200.0, "%.0f") + ImGui.TextWrapped("(Click and drag to scroll)") + + HelpMarker( + "(Left) Using ImGui::PushClipRect():\n" .. + "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" .. + "(use this if you want your clipping rectangle to affect interactions)\n\n" .. + "(Center) Using ImDrawList::PushClipRect():\n" .. + "Will alter ImDrawList rendering only.\n" .. + "(use this as a shortcut if you are only using ImDrawList calls)\n\n" .. + "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n" .. + "Will alter only this specific ImDrawList::AddText() rendering.\n" .. + "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.") + + for n = 0, 2 do repeat + if n > 0 then + ImGui.SameLine() + end + + ImGui.PushID(n) + ImGui.InvisibleButton("##canvas", size) + if ImGui.IsItemActive() and ImGui.IsMouseDragging(ImGuiMouseButton.Left) then + offset.x = offset.x + ImGui.GetIO().MouseDelta.x + offset.y = offset.y + ImGui.GetIO().MouseDelta.y + end ImGui.PopID() + if not ImGui.IsItemVisible() then -- Skip rendering as ImDrawList elements are not clipped. + break -- continue + end + + local p0 = ImGui.GetItemRectMin() + local p1 = ImGui.GetItemRectMax() + local text_str = "Line 1 hello\nLine 2 clip me!" + local text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y) + local draw_list = ImGui.GetWindowDrawList() + if n == 0 then + ImGui.PushClipRect(p0, p1, true) + draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) + draw_list:AddText(text_pos, IM_COL32_WHITE, text_str) + ImGui.PopClipRect() + elseif n == 1 then + draw_list:PushClipRect(p0, p1, true) + draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) + draw_list:AddText(text_pos, IM_COL32_WHITE, text_str) + draw_list:PopClipRect() + elseif n == 2 then + local clip_rect = ImVec4(p0.x, p0.y, p1.x, p1.y) -- AddText() takes a ImVec4* here so let's convert. + draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) + draw_list:AddText(ImGui.GetFont(), ImGui.GetFontSize(), text_pos, IM_COL32_WHITE, text_str, 1, #text_str + 1, 0.0, clip_rect) -- [Port] explicit text_begin/text_end (port's AddText needs text_end) + end + until true end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Overlap Mode") then + IMGUI_DEMO_MARKER("Layout/Overlap Mode") + + HelpMarker( + "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n" .. + "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. " .. + "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.") + _, s.enable_allow_overlap = ImGui.Checkbox("Enable AllowOverlap", s.enable_allow_overlap) + + local button1_pos = ImGui.GetCursorScreenPos() + local button2_pos = ImVec2(button1_pos.x + 50.0, button1_pos.y + 50.0) + if s.enable_allow_overlap then + ImGui.SetNextItemAllowOverlap() end - end - local scroll_x = ImGui.GetScrollX() - local scroll_max_x = ImGui.GetScrollMaxX() - ImGui.EndChild() - ImGui.PopStyleVar(2) - local scroll_x_delta = 0.0 - ImGui.SmallButton("<<") - if ImGui.IsItemActive() then - scroll_x_delta = -ImGui.GetIO().DeltaTime * 1000.0 - end - ImGui.SameLine() - ImGui.Text("Scroll from code"); ImGui.SameLine() - ImGui.SmallButton(">>") - if ImGui.IsItemActive() then - scroll_x_delta = ImGui.GetIO().DeltaTime * 1000.0 - end - ImGui.SameLine() - ImGui.Text("%.0f/%.0f", scroll_x, scroll_max_x) - if scroll_x_delta ~= 0.0 then - -- Demonstrate a trick: you can use Begin to set yourself in the context of another window - -- (here we are already out of your child window) - BeginChild("scrolling") - ImGui.SetScrollX(ImGui.GetScrollX() + scroll_x_delta) - ImGui.EndChild() - end - ImGui.Spacing() + ImGui.Button("Button 1", ImVec2(80, 80)) + ImGui.SetCursorScreenPos(button2_pos) + ImGui.Button("Button 2", ImVec2(80, 80)) - _, SL.show_horizontal_contents_size_demo_window = ImGui.Checkbox("Show Horizontal contents size demo window", SL.show_horizontal_contents_size_demo_window) - - if SL.show_horizontal_contents_size_demo_window then - DemoWindowLayout_HorizontalContentsSizeWindow() - end -end - -local function DemoWindowLayout_TextClipping() - IMGUI_DEMO_MARKER("Layout/Text Clipping") - if SL.clip_size == nil then SL.clip_size = { 100.0, 100.0 }; SL.clip_offset = ImVec2(30.0, 30.0) end - ImGui.DragFloat2("size", SL.clip_size, 0.5, 1.0, 200.0, "%.0f") - ImGui.TextWrapped("(Click and drag to scroll)") - - DemoHelpMarker( - "(Left) Using ImGui::PushClipRect():\n" .. - "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" .. - "(use this if you want your clipping rectangle to affect interactions)\n\n" .. - "(Center) Using ImDrawList::PushClipRect():\n" .. - "Will alter ImDrawList rendering only.\n" .. - "(use this as a shortcut if you are only using ImDrawList calls)\n\n" .. - "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n" .. - "Will alter only this specific ImDrawList::AddText() rendering.\n" .. - "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.") - - local size = ImVec2(SL.clip_size[1], SL.clip_size[2]) - local offset = SL.clip_offset - for n = 0, 2 do repeat - if n > 0 then - ImGui.SameLine() + -- This is typically used with width-spanning items. + -- (note that Selectable() has a dedicated flag ImGuiSelectableFlags.AllowOverlap, which is a shortcut + -- for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.) + if s.enable_allow_overlap then + ImGui.SetNextItemAllowOverlap() end + ImGui.Selectable("Some Selectable", false) + ImGui.SameLine() + ImGui.SmallButton("++") - ImGui.PushID(n) - ImGui.InvisibleButton("##canvas", size) - if ImGui.IsItemActive() and ImGui.IsMouseDragging(ImGuiMouseButton.Left) then - offset.x = offset.x + ImGui.GetIO().MouseDelta.x - offset.y = offset.y + ImGui.GetIO().MouseDelta.y - end - ImGui.PopID() - if not ImGui.IsItemVisible() then -- Skip rendering as ImDrawList elements are not clipped. - break - end - - local p0 = ImGui.GetItemRectMin() - local p1 = ImGui.GetItemRectMax() - local text_str = "Line 1 hello\nLine 2 clip me!" - local text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y) - local draw_list = ImGui.GetWindowDrawList() - if n == 0 then - ImGui.PushClipRect(p0, p1, true) - draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) - draw_list:AddText(text_pos, IM_COL32_WHITE, text_str) - ImGui.PopClipRect() - elseif n == 1 then - draw_list:PushClipRect(p0, p1, true) - draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) - draw_list:AddText(text_pos, IM_COL32_WHITE, text_str) - draw_list:PopClipRect() - else - local clip_rect = ImVec4(p0.x, p0.y, p1.x, p1.y) -- AddText() takes a ImVec4 here so let's convert. - draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)) - draw_list:AddText(ImGui.GetFont(), ImGui.GetFontSize(), text_pos, IM_COL32_WHITE, text_str, 1, #text_str + 1, 0.0, clip_rect) - end - until true end -end - -local function DemoWindowLayout_OverlapMode() - IMGUI_DEMO_MARKER("Layout/Overlap Mode") - DemoHelpMarker( - "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n" .. - "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. " .. - "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.") - _, SL.enable_allow_overlap = ImGui.Checkbox("Enable AllowOverlap", SL.enable_allow_overlap) - - local button1_pos = ImGui.GetCursorScreenPos() - local button2_pos = ImVec2(button1_pos.x + 50.0, button1_pos.y + 50.0) - if SL.enable_allow_overlap then - ImGui.SetNextItemAllowOverlap() + ImGui.TreePop() end - ImGui.Button("Button 1", ImVec2(80, 80)) - ImGui.SetCursorScreenPos(button2_pos) - ImGui.Button("Button 2", ImVec2(80, 80)) - - -- This is typically used with width-spanning items. - -- (note that Selectable() has a dedicated flag ImGuiSelectableFlags.AllowOverlap, which is a shortcut - -- for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.) - if SL.enable_allow_overlap then - ImGui.SetNextItemAllowOverlap() - end - ImGui.Selectable("Some Selectable", false) - ImGui.SameLine() - ImGui.SmallButton("++") -end - -function DemoWindowLayout() - if not ImGui.CollapsingHeader("Layout & Scrolling") then - return - end - if ImGui.TreeNode("Child windows") then DemoWindowLayout_ChildWindows(); ImGui.TreePop() end - if ImGui.TreeNode("Widgets Width") then DemoWindowLayout_WidgetsWidth(); ImGui.TreePop() end - if ImGui.TreeNode("Basic Horizontal Layout") then DemoWindowLayout_BasicHorizontal(); ImGui.TreePop() end - if ImGui.TreeNode("Groups") then DemoWindowLayout_Groups(); ImGui.TreePop() end - if ImGui.TreeNode("Text Baseline Alignment") then DemoWindowLayout_TextBaseline(); ImGui.TreePop() end - if ImGui.TreeNode("Scrolling") then DemoWindowLayout_Scrolling(); ImGui.TreePop() end - if ImGui.TreeNode("Text Clipping") then DemoWindowLayout_TextClipping(); ImGui.TreePop() end - if ImGui.TreeNode("Overlap Mode") then DemoWindowLayout_OverlapMode(); ImGui.TreePop() end end ------------------------------------------------------------------------------- -- [SECTION] DemoWindowPopups() ------------------------------------------------------------------------------- -local SP = { - selected_fish = -1, toggles = { true, false, false, false, false }, - ctx_selected = -1, value = 0.5, name = nil, - dont_ask_me_next_time = false, item = 1, color = { 0.4, 0.7, 0.0, 0.5 }, +S.DemoWindowPopups = { + selected_fish = -1, -- static int selected_fish = -1; + toggles = { true, false, false, false, false }, -- static bool toggles[] = { true, false, false, false, false }; + selected = -1, -- static int selected = -1; + value = 0.5, -- static float value = 0.5f; + name = ImGui.NewTextBuffer("Label1", 32), -- static char name[32] = "Label1"; + dont_ask_me_next_time = false, -- static bool dont_ask_me_next_time = false; + item = 1, -- static int item = 1; + color = { 0.4, 0.7, 0.0, 0.5 }, -- static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; } - -local function DemoWindowPopups_Popups() - IMGUI_DEMO_MARKER("Popups/Popups") - ImGui.TextWrapped( - "When a popup is active, it inhibits interacting with windows that are behind the popup. " .. - "Clicking outside the popup closes it.") - - local names = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" } - local toggles = SP.toggles - - -- Simple selection popup (if you want to show the current selection inside the Button itself, - -- you may want to build a string using the "###" operator to preserve a constant ID with a variable label) - if ImGui.Button("Select..") then - ImGui.OpenPopup("my_select_popup") - end - ImGui.SameLine() - ImGui.TextUnformatted(SP.selected_fish == -1 and "" or names[SP.selected_fish + 1]) - if ImGui.BeginPopup("my_select_popup") then - ImGui.SeparatorText("Aquarium") - for i = 1, #names do - if ImGui.Selectable(names[i]) then - SP.selected_fish = i - 1 - end - end - ImGui.EndPopup() - end - - -- Showing a menu with toggles - if ImGui.Button("Toggle..") then - ImGui.OpenPopup("my_toggle_popup") - end - if ImGui.BeginPopup("my_toggle_popup") then - for i = 1, #names do - _, toggles[i] = ImGui.MenuItem(names[i], "", toggles[i]) - end - if ImGui.BeginMenu("Sub-menu") then - ImGui.MenuItem("Click me") - ImGui.EndMenu() - end - - ImGui.Separator() - ImGui.Text("Tooltip here") - ImGui.SetItemTooltip("I am a tooltip over a popup") - - if ImGui.Button("Stacked Popup") then - ImGui.OpenPopup("another popup") - end - if ImGui.BeginPopup("another popup") then - for i = 1, #names do - _, toggles[i] = ImGui.MenuItem(names[i], "", toggles[i]) - end - if ImGui.BeginMenu("Sub-menu") then - ImGui.MenuItem("Click me") - if ImGui.Button("Stacked Popup") then - ImGui.OpenPopup("another popup") - end - if ImGui.BeginPopup("another popup") then - ImGui.Text("I am the last one here.") - ImGui.EndPopup() - end - ImGui.EndMenu() - end - ImGui.EndPopup() - end - ImGui.EndPopup() - end - - -- Call the more complete ShowExampleMenuFile which we use in various places of this demo - if ImGui.Button("With a menu..") then - ImGui.OpenPopup("my_file_popup") - end - if ImGui.BeginPopup("my_file_popup", ImGuiWindowFlags.MenuBar) then - if ImGui.BeginMenuBar() then - if ImGui.BeginMenu("File") then - DemoMenuFile() - ImGui.EndMenu() - end - if ImGui.BeginMenu("Edit") then - ImGui.MenuItem("Dummy") - ImGui.EndMenu() - end - ImGui.EndMenuBar() - end - ImGui.Text("Hello from popup!") - ImGui.Button("This is a dummy button..") - ImGui.EndPopup() - end -end - -local function DemoWindowPopups_ContextMenus() - IMGUI_DEMO_MARKER("Popups/Context menus") - DemoHelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.") - - -- BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: - -- if id == 0 then - -- id = GetItemID() -- Use last item id - -- end - -- if IsItemHovered() and IsMouseReleased(ImGuiMouseButton.Right) then - -- OpenPopup(id) - -- end - -- return BeginPopup(id) - -- For advanced uses you may want to replicate and customize this code. - -- See more details in BeginPopupContextItem(). - - -- Example 1 - -- When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(), - -- and BeginPopupContextItem() will use the last item ID as the popup ID. - do - local names = { "Label1", "Label2", "Label3", "Label4", "Label5" } - for n = 0, 4 do - if ImGui.Selectable(names[n + 1], SP.ctx_selected == n) then - SP.ctx_selected = n - end - if ImGui.BeginPopupContextItem() then -- <-- use last item id as popup id - SP.ctx_selected = n - ImGui.Text("This is a popup for \"%s\"!", names[n + 1]) - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - ImGui.SetItemTooltip("Right-click to open popup") - end - end - - -- Example 2 - -- Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem(). - -- Using an explicit identifier is also convenient if you want to activate the popups from different locations. - do - DemoHelpMarker("Text() elements don't have stable identifiers so we need to provide one.") - ImGui.Text("Value = %.3f <-- (1) right-click this text", SP.value) - if ImGui.BeginPopupContextItem("my popup") then - if ImGui.Selectable("Set to zero") then SP.value = 0.0 end - if ImGui.Selectable("Set to PI") then SP.value = 3.1415 end - ImGui.SetNextItemWidth(-FLT_MIN) - SP.value = ImGui.DragFloat("##Value", SP.value, 0.1, 0.0, 0.0) - ImGui.EndPopup() - end - - -- We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup. - -- Here we make it that right-clicking this other text element opens the same popup as above. - -- The popup itself will be submitted by the code above. - ImGui.Text("(2) Or right-click this text") - ImGui.OpenPopupOnItemClick("my popup", ImGuiPopupFlags.MouseButtonRight) - - -- Back to square one: manually open the same popup. - if ImGui.Button("(3) Or click this button") then - ImGui.OpenPopup("my popup") - end - end - - -- Example 3 - -- When using BeginPopupContextItem() with an implicit identifier (nil == use last item ID), - -- we need to make sure your item identifier is stable. - -- In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ). - do - DemoHelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.") - if SP.name == nil then SP.name = Buf("Label1", 32) end - local buf = string.format("Button: %s###Button", BufStr(SP.name)) -- ### operator override ID ignoring the preceding label - ImGui.Button(buf) - if ImGui.BeginPopupContextItem() then - ImGui.Text("Edit name:") - ImGui.InputText("##edit", SP.name, 32) - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - ImGui.SameLine(); ImGui.Text("(<-- right-click here)") - end -end - -local function DemoWindowPopups_Modals() - IMGUI_DEMO_MARKER("Popups/Modals") - ImGui.TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.") - - if ImGui.Button("Delete..") then - ImGui.OpenPopup("Delete?") - end - - -- Always center this window when appearing - local center = ImGui.GetMainViewport():GetCenter() - ImGui.SetNextWindowPos(center, ImGuiCond.Appearing, ImVec2(0.5, 0.5)) - - if ImGui.BeginPopupModal("Delete?", nil, ImGuiWindowFlags.AlwaysAutoResize) then - ImGui.Text("All those beautiful files will be deleted.\nThis operation cannot be undone!") - ImGui.Separator() - - -- local unused_i = 0 - -- unused_i = ImGui.Combo("Combo", unused_i, "Delete\0Delete harder\0") - - ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(0, 0)) - _, SP.dont_ask_me_next_time = ImGui.Checkbox("Don't ask me next time", SP.dont_ask_me_next_time) - ImGui.PopStyleVar() - - if ImGui.Button("OK", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end - ImGui.SetItemDefaultFocus() - ImGui.SameLine() - if ImGui.Button("Cancel", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end - ImGui.EndPopup() - end - - if ImGui.Button("Stacked modals..") then - ImGui.OpenPopup("Stacked 1") - end - if ImGui.BeginPopupModal("Stacked 1", nil, ImGuiWindowFlags.MenuBar) then - if ImGui.BeginMenuBar() then - if ImGui.BeginMenu("File") then - if ImGui.MenuItem("Some menu item") then end - ImGui.EndMenu() - end - ImGui.EndMenuBar() - end - ImGui.Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.") - - -- Testing behavior of widgets stacking their own regular popups over the modal. - if ImGui.Combo then - SP.item = ImGui.Combo("Combo", SP.item, { "aaaa", "bbbb", "cccc", "dddd", "eeee" }, 5) - else - NotPorted("Combo") - end - ImGui.ColorEdit4("Color", SP.color) - - if ImGui.Button("Add another modal..") then - ImGui.OpenPopup("Stacked 2") - end - - -- Also demonstrate passing a p_open bool to BeginPopupModal(), this will create a regular close button which - -- will close the popup. Note that the visibility state of popups is owned by imgui, so the input value - -- of the bool actually doesn't matter here. - local unused_open = true - if ImGui.BeginPopupModal("Stacked 2", unused_open) then - ImGui.Text("Hello from Stacked The Second!") - ImGui.ColorEdit4("Color", SP.color) -- Allow opening another nested popup - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end -end - function DemoWindowPopups() + local s = S.DemoWindowPopups if not ImGui.CollapsingHeader("Popups & Modal windows") then return end @@ -2265,17 +4652,259 @@ function DemoWindowPopups() -- popups at any time. -- Typical use for regular windows: - -- local my_tool_is_active = false; if ImGui.Button("Open") then my_tool_is_active = true end; [...] if my_tool_is_active then my_tool_is_active, visible = ImGui.Begin("My Tool", my_tool_is_active); [...] ImGui.End() end + -- bool my_tool_is_active = false; if (ImGui.Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", my_tool_is_active) { [...] } End(); -- Typical use for popups: - -- if ImGui.Button("Open") then ImGui.OpenPopup("MyPopup") end; if ImGui.BeginPopup("MyPopup") then [...] ImGui.EndPopup() end + -- if (ImGui.Button("Open")) ImGui.OpenPopup("MyPopup"); if (ImGui.BeginPopup("MyPopup")) { [...] EndPopup(); } -- With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. -- This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. - if ImGui.TreeNode("Popups") then DemoWindowPopups_Popups(); ImGui.TreePop() end - if ImGui.TreeNode("Context menus") then DemoWindowPopups_ContextMenus(); ImGui.TreePop() end + if ImGui.TreeNode("Popups") then + IMGUI_DEMO_MARKER("Popups/Popups") + ImGui.TextWrapped( + "When a popup is active, it inhibits interacting with windows that are behind the popup. " .. + "Clicking outside the popup closes it.") + + local names = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" } + local toggles = s.toggles + + -- Simple selection popup (if you want to show the current selection inside the Button itself, + -- you may want to build a string using the "###" operator to preserve a constant ID with a variable label) + if ImGui.Button("Select..") then + ImGui.OpenPopup("my_select_popup") + end + ImGui.SameLine() + local fish_name = "" + if s.selected_fish ~= -1 then fish_name = names[s.selected_fish + 1] end + ImGui.TextUnformatted(fish_name) + if ImGui.BeginPopup("my_select_popup") then + ImGui.SeparatorText("Aquarium") + for i = 0, #names - 1 do + if ImGui.Selectable(names[i + 1]) then + s.selected_fish = i + end + end + ImGui.EndPopup() + end + + -- Showing a menu with toggles + if ImGui.Button("Toggle..") then + ImGui.OpenPopup("my_toggle_popup") + end + if ImGui.BeginPopup("my_toggle_popup") then + for i = 0, #names - 1 do + _, toggles[i + 1] = ImGui.MenuItem(names[i + 1], "", toggles[i + 1]) + end + if ImGui.BeginMenu("Sub-menu") then + ImGui.MenuItem("Click me") + ImGui.EndMenu() + end + + ImGui.Separator() + ImGui.Text("Tooltip here") + ImGui.SetItemTooltip("I am a tooltip over a popup") + + if ImGui.Button("Stacked Popup") then + ImGui.OpenPopup("another popup") + end + if ImGui.BeginPopup("another popup") then + for i = 0, #names - 1 do + _, toggles[i + 1] = ImGui.MenuItem(names[i + 1], "", toggles[i + 1]) + end + if ImGui.BeginMenu("Sub-menu") then + ImGui.MenuItem("Click me") + if ImGui.Button("Stacked Popup") then + ImGui.OpenPopup("another popup") + end + if ImGui.BeginPopup("another popup") then + ImGui.Text("I am the last one here.") + ImGui.EndPopup() + end + ImGui.EndMenu() + end + ImGui.EndPopup() + end + ImGui.EndPopup() + end + + -- Call the more complete ShowExampleMenuFile which we use in various places of this demo + if ImGui.Button("With a menu..") then + ImGui.OpenPopup("my_file_popup") + end + if ImGui.BeginPopup("my_file_popup", ImGuiWindowFlags.MenuBar) then + if ImGui.BeginMenuBar() then + if ImGui.BeginMenu("File") then + ShowExampleMenuFile() + ImGui.EndMenu() + end + if ImGui.BeginMenu("Edit") then + ImGui.MenuItem("Dummy") + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end + ImGui.Text("Hello from popup!") + ImGui.Button("This is a dummy button..") + ImGui.EndPopup() + end + + ImGui.TreePop() + end + + if ImGui.TreeNode("Context menus") then + IMGUI_DEMO_MARKER("Popups/Context menus") + HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.") + + -- BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: + -- if (id == 0) + -- id = GetItemID(); -- Use last item id + -- if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton.Right)) + -- OpenPopup(id); + -- return BeginPopup(id); + -- For advanced uses you may want to replicate and customize this code. + -- See more details in BeginPopupContextItem(). + + -- Example 1 + -- When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(), + -- and BeginPopupContextItem() will use the last item ID as the popup ID. + do + local names = { "Label1", "Label2", "Label3", "Label4", "Label5" } + for n = 0, 4 do + if ImGui.Selectable(names[n + 1], s.selected == n) then + s.selected = n + end + if ImGui.BeginPopupContextItem() then -- <-- use last item id as popup id + s.selected = n + ImGui.Text("This is a popup for \"%s\"!", names[n + 1]) + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.SetItemTooltip("Right-click to open popup") + end + end + + -- Example 2 + -- Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem(). + -- Using an explicit identifier is also convenient if you want to activate the popups from different locations. + do + HelpMarker("Text() elements don't have stable identifiers so we need to provide one.") + ImGui.Text("Value = %.3f <-- (1) right-click this text", s.value) + if ImGui.BeginPopupContextItem("my popup") then + if ImGui.Selectable("Set to zero") then s.value = 0.0 end + if ImGui.Selectable("Set to PI") then s.value = 3.1415 end + ImGui.SetNextItemWidth(-FLT_MIN) + s.value = ImGui.DragFloat("##Value", s.value, 0.1, 0.0, 0.0) + ImGui.EndPopup() + end + + -- We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup. + -- Here we make it that right-clicking this other text element opens the same popup as above. + -- The popup itself will be submitted by the code above. + ImGui.Text("(2) Or right-click this text") + ImGui.OpenPopupOnItemClick("my popup", ImGuiPopupFlags.MouseButtonRight) + + -- Back to square one: manually open the same popup. + if ImGui.Button("(3) Or click this button") then + ImGui.OpenPopup("my popup") + end + end + + -- Example 3 + -- When using BeginPopupContextItem() with an implicit identifier (nil == use last item ID), + -- we need to make sure your item identifier is stable. + -- In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ). + do + HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.") + local buf = string.format("Button: %s###Button", ImGui.TextBufferToString(s.name)) -- ### operator override ID ignoring the preceding label + ImGui.Button(buf) + if ImGui.BeginPopupContextItem() then + ImGui.Text("Edit name:") + ImGui.InputText("##edit", s.name, 32) + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.SameLine(); ImGui.Text("(<-- right-click here)") + end + + ImGui.TreePop() + end + if ImGui.TreeNode("Modals") then - if ImGui.BeginPopupModal then DemoWindowPopups_Modals() else NotPorted("BeginPopupModal") end + IMGUI_DEMO_MARKER("Popups/Modals") + ImGui.TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.") + + if ImGui.Button("Delete..") then + ImGui.OpenPopup("Delete?") + end + + -- Always center this window when appearing + local center = ImGui.GetMainViewport():GetCenter() + ImGui.SetNextWindowPos(center, ImGuiCond.Appearing, ImVec2(0.5, 0.5)) + + if ImGui.BeginPopupModal("Delete?", nil, ImGuiWindowFlags.AlwaysAutoResize) then + ImGui.Text("All those beautiful files will be deleted.\nThis operation cannot be undone!") + ImGui.Separator() + + --static int unused_i = 0; + --ImGui.Combo("Combo", unused_i, "Delete\0Delete harder\0"); + + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(0, 0)) + _, s.dont_ask_me_next_time = ImGui.Checkbox("Don't ask me next time", s.dont_ask_me_next_time) + ImGui.PopStyleVar() + + if ImGui.Button("OK", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end + ImGui.SetItemDefaultFocus() + ImGui.SameLine() + if ImGui.Button("Cancel", ImVec2(120, 0)) then ImGui.CloseCurrentPopup() end + ImGui.EndPopup() + end + + if ImGui.Button("Stacked modals..") then + ImGui.OpenPopup("Stacked 1") + end + if ImGui.BeginPopupModal("Stacked 1", nil, ImGuiWindowFlags.MenuBar) then + if ImGui.BeginMenuBar() then + if ImGui.BeginMenu("File") then + if ImGui.MenuItem("Some menu item") then end + ImGui.EndMenu() + end + ImGui.EndMenuBar() + end + ImGui.Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.") + + -- Testing behavior of widgets stacking their own regular popups over the modal. + s.item = ImGui.Combo("Combo", s.item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0") + ImGui.ColorEdit4("Color", s.color) + + if ImGui.Button("Add another modal..") then + ImGui.OpenPopup("Stacked 2") + end + + -- Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which + -- will close the popup. Note that the visibility state of popups is owned by imgui, so the input value + -- of the bool actually doesn't matter here. + local unused_open = true + local visible + visible, unused_open = ImGui.BeginPopupModal("Stacked 2", unused_open) + if visible then + ImGui.Text("Hello from Stacked The Second!") + ImGui.ColorEdit4("Color", s.color) -- Allow opening another nested popup + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.TreePop() end @@ -2286,7 +4915,7 @@ function DemoWindowPopups() ImGui.MenuItem("Menu item", "Ctrl+M") if ImGui.BeginMenu("Menu inside a regular window") then - DemoMenuFile() + ShowExampleMenuFile() ImGui.EndMenu() end ImGui.Separator() @@ -2294,99 +4923,123 @@ function DemoWindowPopups() end end -------------------------------------------------------------------------------- --- [SECTION] DemoWindowTables() -------------------------------------------------------------------------------- - -- Dummy data structure that we use for the Table demo. +-- (pre-C++11 doesn't allow us to instantiate ImVector template if this structure is defined inside the demo function) +-- [Port] namespace { ... } -> globals with a MyItem prefix (part 08_tables uses them). -- We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code. -- This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID. -- But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex) -- If you don't use sorting, you will generally never care about giving column an ID! --- MyItemColumnID -local MyItemColumnID_ID, MyItemColumnID_Name, MyItemColumnID_Action, MyItemColumnID_Quantity, MyItemColumnID_Description = 0, 1, 2, 3, 4 +-- enum MyItemColumnID +MyItemColumnID_ID = 0 +MyItemColumnID_Name = 1 +MyItemColumnID_Action = 2 +MyItemColumnID_Quantity = 3 +MyItemColumnID_Description = 4 -local function MyItem(id, name, quantity) return { ID = id, Name = name, Quantity = quantity } end +-- struct MyItem: [Port] constructor; fields ID (int), Name (string), Quantity (int) +function MyItem(ID, Name, Quantity) + return { ID = ID, Name = Name, Quantity = Quantity } +end ---- Sort a Lua array (1-based) of MyItem with ImGuiTableSortSpecs (Specs is 1-based array or ImVector) -local function MyItem_SortWithSortSpecs(sort_specs, items, items_count) - if items_count <= 1 then return end - local specs = sort_specs.Specs - local function get_spec(n) -- n: 0-based - if specs.Data then return specs.Data[n + 1] end - return specs[n + 1] - end - local function cmp(a, b) -- returns <0, 0, >0 - for n = 0, sort_specs.SpecsCount - 1 do - -- Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn() - -- We could also choose to identify columns based on their index (sort_spec.ColumnIndex), which is simpler! - local sort_spec = get_spec(n) - local delta = 0 - local uid = sort_spec.ColumnUserID - if uid == MyItemColumnID_ID then delta = a.ID - b.ID - elseif uid == MyItemColumnID_Name then delta = (a.Name < b.Name) and -1 or (a.Name > b.Name) and 1 or 0 - elseif uid == MyItemColumnID_Quantity then delta = a.Quantity - b.Quantity - elseif uid == MyItemColumnID_Description then delta = (a.Name < b.Name) and -1 or (a.Name > b.Name) and 1 or 0 - else IM_ASSERT(false) end - if delta > 0 then - return (sort_spec.SortDirection == ImGuiSortDirection.Ascending) and 1 or -1 - end - if delta < 0 then - return (sort_spec.SortDirection == ImGuiSortDirection.Ascending) and -1 or 1 - end +-- We have a problem which is affecting _only this demo_ and should not affect your code: +-- As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(), +-- however qsort doesn't allow passing user data to comparing function. +-- As a workaround, we are storing the sort specs in a static/global for the comparing function to access. +-- In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global. +-- We could technically call ImGui.TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called +-- very often by the sorting algorithm it would be a little wasteful. +MyItem_s_current_sort_specs = nil + +-- [Port] items: 1-based Lua array of MyItem (e.g. ImVector .Data), sorted in place over [1, items_count]. +local function MyItem_Less(a, b) return MyItem_CompareWithSortSpecs(a, b) < 0 end -- [Port] table.sort wants a "less than" predicate +function MyItem_SortWithSortSpecs(sort_specs, items, items_count) + MyItem_s_current_sort_specs = sort_specs -- Store in variable accessible by the sort function. + if items_count > 1 then + if items_count == #items then + table.sort(items, MyItem_Less) + else -- [Port] sort only the used range + local tmp = {} + for i = 1, items_count do tmp[i] = items[i] end + table.sort(tmp, MyItem_Less) + for i = 1, items_count do items[i] = tmp[i] end end + end + MyItem_s_current_sort_specs = nil +end - -- table.sort() is instable so always return a way to differentiate items. - -- Your own compare function may want to avoid fallback on implicit sort specs. - -- e.g. a Name compare if it wasn't already part of the sort specs. - return a.ID - b.ID - end - local arr = items.Data or items - if items.Data then - -- ImVector: sort only the used range - local tmp = {} - for i = 1, items_count do tmp[i] = arr[i] end - table.sort(tmp, function(a, b) return cmp(a, b) < 0 end) - for i = 1, items_count do arr[i] = tmp[i] end - else - table.sort(arr, function(a, b) return cmp(a, b) < 0 end) +-- Compare function to be used by qsort() +-- [Port] strcmp -> Lua string comparison; returns <0, 0, >0 like upstream (strict weak order via the ID fallback). +function MyItem_CompareWithSortSpecs(a, b) + for n = 0, MyItem_s_current_sort_specs.SpecsCount - 1 do + -- Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn() + -- We could also choose to identify columns based on their index (sort_spec.ColumnIndex), which is simpler! + local sort_spec = MyItem_s_current_sort_specs.Specs[n + 1] -- [Port] Specs is a 1-based array + local delta = 0 + local id = sort_spec.ColumnUserID + if id == MyItemColumnID_ID then delta = (a.ID - b.ID) + elseif id == MyItemColumnID_Name then delta = (a.Name < b.Name and -1 or (a.Name > b.Name and 1 or 0)) + elseif id == MyItemColumnID_Quantity then delta = (a.Quantity - b.Quantity) + elseif id == MyItemColumnID_Description then delta = (a.Name < b.Name and -1 or (a.Name > b.Name and 1 or 0)) + else IM_ASSERT(false) end + if delta > 0 then + return (sort_spec.SortDirection == ImGuiSortDirection.Ascending) and 1 or -1 + end + if delta < 0 then + return (sort_spec.SortDirection == ImGuiSortDirection.Ascending) and -1 or 1 + end end + + -- qsort() is instable so always return a way to differentiate items. + -- Your own compare function may want to avoid fallback on implicit sort specs. + -- e.g. a Name compare if it wasn't already part of the sort specs. + return a.ID - b.ID end -- Make the UI compact because there are so many fields -local function PushStyleCompact() +function PushStyleCompact() local style = ImGui.GetStyle() ImGui.PushStyleVarY(ImGuiStyleVar.FramePadding, math.floor(style.FramePadding.y * 0.60)) ImGui.PushStyleVarY(ImGuiStyleVar.ItemSpacing, math.floor(style.ItemSpacing.y * 0.60)) end -local function PopStyleCompact() +function PopStyleCompact() ImGui.PopStyleVar(2) end -local table_sizing_policies = nil +S.EditTableSizingFlags = { policies = nil } -- Show a combo box with a choice of sizing policies -local function EditTableSizingFlags(flags) - if table_sizing_policies == nil then - table_sizing_policies = { - { Value = ImGuiTableFlags.None, Name = "Default", Tooltip = "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." }, - { Value = ImGuiTableFlags.SizingFixedFit, Name = "ImGuiTableFlags_SizingFixedFit", Tooltip = "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." }, - { Value = ImGuiTableFlags.SizingFixedSame, Name = "ImGuiTableFlags_SizingFixedSame", Tooltip = "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." }, - { Value = ImGuiTableFlags.SizingStretchProp, Name = "ImGuiTableFlags_SizingStretchProp", Tooltip = "Columns default to _WidthStretch with weights proportional to their widths." }, - { Value = ImGuiTableFlags.SizingStretchSame, Name = "ImGuiTableFlags_SizingStretchSame", Tooltip = "Columns default to _WidthStretch with same weights." }, +-- [Port] p_flags -> takes flags, returns the new flags. +function EditTableSizingFlags(p_flags) + local s = S.EditTableSizingFlags + -- struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; }; + if s.policies == nil then + s.policies = + { + { Value = ImGuiTableFlags.None, Name = "Default", Tooltip = "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." }, + { Value = ImGuiTableFlags.SizingFixedFit, Name = "ImGuiTableFlags_SizingFixedFit", Tooltip = "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." }, + { Value = ImGuiTableFlags.SizingFixedSame, Name = "ImGuiTableFlags_SizingFixedSame", Tooltip = "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." }, + { Value = ImGuiTableFlags.SizingStretchProp, Name = "ImGuiTableFlags_SizingStretchProp", Tooltip = "Columns default to _WidthStretch with weights proportional to their widths." }, + { Value = ImGuiTableFlags.SizingStretchSame, Name = "ImGuiTableFlags_SizingStretchSame", Tooltip = "Columns default to _WidthStretch with same weights." }, } end - local policies = table_sizing_policies - local idx = 1 - while idx <= #policies do - if policies[idx].Value == bit32.band(flags, ImGuiTableFlags.SizingMask_) then break end + local policies = s.policies + local idx = 0 + while idx < #policies do + if policies[idx + 1].Value == bit32.band(p_flags, ImGuiTableFlags.SizingMask_) then + break + end idx = idx + 1 end - local preview_text = (idx <= #policies) and (idx > 1 and string.sub(policies[idx].Name, #"ImGuiTableFlags" + 1) or policies[idx].Name) or "" + local preview_text = "" + if idx < #policies then + preview_text = policies[idx + 1].Name + if idx > 0 then preview_text = string.sub(preview_text, #"ImGuiTableFlags" + 1) end + end if ImGui.BeginCombo("Sizing Policy", preview_text) then - for n = 1, #policies do - if ImGui.Selectable(policies[n].Name, idx == n) then - flags = bit32.bor(bit32.band(flags, bit32.bnot(ImGuiTableFlags.SizingMask_)), policies[n].Value) + for n = 0, #policies - 1 do + if ImGui.Selectable(policies[n + 1].Name, idx == n) then + p_flags = bit32.bor(bit32.band(p_flags, bit32.bnot(ImGuiTableFlags.SizingMask_)), policies[n + 1].Value) end end ImGui.EndCombo() @@ -2395,1256 +5048,1507 @@ local function EditTableSizingFlags(flags) ImGui.TextDisabled("(?)") if ImGui.BeginItemTooltip() then ImGui.PushTextWrapPos(ImGui.GetFontSize() * 50.0) - for m = 1, #policies do + for m = 0, #policies - 1 do ImGui.Separator() - ImGui.Text("%s:", policies[m].Name) + ImGui.Text("%s:", policies[m + 1].Name) ImGui.Separator() ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().IndentSpacing * 0.5) - ImGui.TextUnformatted(policies[m].Tooltip) + ImGui.TextUnformatted(policies[m + 1].Tooltip) end ImGui.PopTextWrapPos() ImGui.EndTooltip() end - return flags + return p_flags end -local function EditTableColumnsFlags(f) - local p - local F = ImGuiTableColumnFlags - _, f = ImGui.CheckboxFlags("_Disabled", f, F.Disabled); ImGui.SameLine(); DemoHelpMarker("Master disable flag (also hide from context menu)") - _, f = ImGui.CheckboxFlags("_DefaultHide", f, F.DefaultHide) - _, f = ImGui.CheckboxFlags("_DefaultSort", f, F.DefaultSort) - p, f = ImGui.CheckboxFlags("_WidthStretch", f, F.WidthStretch) - if p then f = bit32.band(f, bit32.bnot(bit32.bxor(F.WidthMask_, F.WidthStretch))) end - p, f = ImGui.CheckboxFlags("_WidthFixed", f, F.WidthFixed) - if p then f = bit32.band(f, bit32.bnot(bit32.bxor(F.WidthMask_, F.WidthFixed))) end - _, f = ImGui.CheckboxFlags("_NoResize", f, F.NoResize) - _, f = ImGui.CheckboxFlags("_NoReorder", f, F.NoReorder) - _, f = ImGui.CheckboxFlags("_NoHide", f, F.NoHide) - _, f = ImGui.CheckboxFlags("_NoClip", f, F.NoClip) - _, f = ImGui.CheckboxFlags("_NoSort", f, F.NoSort) - _, f = ImGui.CheckboxFlags("_NoSortAscending", f, F.NoSortAscending) - _, f = ImGui.CheckboxFlags("_NoSortDescending", f, F.NoSortDescending) - _, f = ImGui.CheckboxFlags("_NoHeaderLabel", f, F.NoHeaderLabel) - _, f = ImGui.CheckboxFlags("_NoHeaderWidth", f, F.NoHeaderWidth) - _, f = ImGui.CheckboxFlags("_PreferSortAscending", f, F.PreferSortAscending) - _, f = ImGui.CheckboxFlags("_PreferSortDescending", f, F.PreferSortDescending) - _, f = ImGui.CheckboxFlags("_IndentEnable", f, F.IndentEnable); ImGui.SameLine(); DemoHelpMarker("Default for column 0") - _, f = ImGui.CheckboxFlags("_IndentDisable", f, F.IndentDisable); ImGui.SameLine(); DemoHelpMarker("Default for column >0") - _, f = ImGui.CheckboxFlags("_AngledHeader", f, F.AngledHeader) - return f +-- [Port] p_flags -> takes flags, returns the new flags. +function EditTableColumnsFlags(p_flags) + local pressed + _, p_flags = ImGui.CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags.Disabled); ImGui.SameLine(); HelpMarker("Master disable flag (also hide from context menu)") + _, p_flags = ImGui.CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags.DefaultHide) + _, p_flags = ImGui.CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags.DefaultSort) + pressed, p_flags = ImGui.CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags.WidthStretch) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(ImGuiTableColumnFlags.WidthMask_, ImGuiTableColumnFlags.WidthStretch))) + end + pressed, p_flags = ImGui.CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags.WidthFixed) + if pressed then + p_flags = bit32.band(p_flags, bit32.bnot(bit32.bxor(ImGuiTableColumnFlags.WidthMask_, ImGuiTableColumnFlags.WidthFixed))) + end + _, p_flags = ImGui.CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags.NoResize) + _, p_flags = ImGui.CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags.NoReorder) + _, p_flags = ImGui.CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags.NoHide) + _, p_flags = ImGui.CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags.NoClip) + _, p_flags = ImGui.CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags.NoSort) + _, p_flags = ImGui.CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags.NoSortAscending) + _, p_flags = ImGui.CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags.NoSortDescending) + _, p_flags = ImGui.CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags.NoHeaderLabel) + _, p_flags = ImGui.CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags.NoHeaderWidth) + _, p_flags = ImGui.CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags.PreferSortAscending) + _, p_flags = ImGui.CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags.PreferSortDescending) + _, p_flags = ImGui.CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags.IndentEnable); ImGui.SameLine(); HelpMarker("Default for column 0") + _, p_flags = ImGui.CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags.IndentDisable); ImGui.SameLine(); HelpMarker("Default for column >0") + _, p_flags = ImGui.CheckboxFlags("_AngledHeader", p_flags, ImGuiTableColumnFlags.AngledHeader) + return p_flags end -local function ShowTableColumnsStatusFlags(flags) +function ShowTableColumnsStatusFlags(flags) ImGui.CheckboxFlags("_IsEnabled", flags, ImGuiTableColumnFlags.IsEnabled) ImGui.CheckboxFlags("_IsVisible", flags, ImGuiTableColumnFlags.IsVisible) ImGui.CheckboxFlags("_IsSorted", flags, ImGuiTableColumnFlags.IsSorted) ImGui.CheckboxFlags("_IsHovered", flags, ImGuiTableColumnFlags.IsHovered) end -local function bor(...) return bit32.bor(...) end -local TF = setmetatable({}, { __index = function(_, k) return ImGuiTableFlags[k] end }) +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowTables() +------------------------------------------------------------------------------- -local ST = {} -- statics for DemoWindowTables (one sub-table per section) --- Using those as a base value to create width/height that are factor of the size of our font -local TEXT_BASE_WIDTH, TEXT_BASE_HEIGHT = 0, 0 +S.DemoWindowTables = { -- statics of DemoWindowTables(), one sub-table per TreeNode + disable_indent = false, + BordersBackground = { + flags = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg), + display_headers = false, + contents_type = 0, -- CT_Text + }, + ResizableStretch = { + flags = bit32.bor(ImGuiTableFlags.SizingStretchSame, ImGuiTableFlags.Resizable, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.ContextMenuInBody), + }, + ResizableFixed = { + flags = bit32.bor(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.Resizable, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.ContextMenuInBody), + }, + ResizableMixed = { + flags = bit32.bor(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.RowBg, ImGuiTableFlags.Borders, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable), + }, + Reorderable = { + flags = bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV), + }, + Padding = { + flags1 = ImGuiTableFlags.BordersV, + show_headers = false, + flags2 = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg), + cell_padding = ImVec2(0.0, 0.0), + show_widget_frame_bg = true, + text_bufs = {}, -- 1-based, cell + 1 + init = true, + }, + SizingPolicies = { + flags1 = bit32.bor(ImGuiTableFlags.BordersV, ImGuiTableFlags.BordersOuterH, ImGuiTableFlags.RowBg, ImGuiTableFlags.ContextMenuInBody), + sizing_policy_flags = { ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.SizingFixedSame, ImGuiTableFlags.SizingStretchProp, ImGuiTableFlags.SizingStretchSame }, + flags = bit32.bor(ImGuiTableFlags.ScrollY, ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg, ImGuiTableFlags.Resizable), + contents_type = 0, -- CT_ShowWidth + column_count = 3, + text_buf = ImGui.NewTextBuffer("", 32), + }, + VerticalScrolling = { + flags = bit32.bor(ImGuiTableFlags.ScrollY, ImGuiTableFlags.RowBg, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable), + }, + HorizontalScrolling = { + flags = bit32.bor(ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, ImGuiTableFlags.RowBg, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable), + freeze_cols = 1, + freeze_rows = 1, + flags2 = bit32.bor(ImGuiTableFlags.SizingStretchSame, ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.RowBg, ImGuiTableFlags.ContextMenuInBody), + inner_width = 1000.0, + }, + ColumnsFlags = { + column_flags = { ImGuiTableColumnFlags.DefaultSort, ImGuiTableColumnFlags.None, ImGuiTableColumnFlags.DefaultHide }, + column_flags_out = { 0, 0, 0 }, -- Output from TableGetColumnFlags() + }, + ColumnsWidths = { + flags1 = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.NoBordersInBodyUntilResize), + flags2 = ImGuiTableFlags.None, + }, + OuterSize = { + flags = bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.Resizable, ImGuiTableFlags.ContextMenuInBody, ImGuiTableFlags.RowBg, ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.NoHostExtendX), + }, + BackgroundColor = { + flags = ImGuiTableFlags.RowBg, + row_bg_type = 1, + row_bg_target = 1, + cell_bg_type = 1, + }, + TreeView = { + table_flags = bit32.bor(ImGuiTableFlags.BordersV, ImGuiTableFlags.BordersOuterH, ImGuiTableFlags.Resizable, ImGuiTableFlags.RowBg, ImGuiTableFlags.NoBordersInBody), + tree_node_flags_base = bit32.bor(ImGuiTreeNodeFlags.SpanAllColumns, ImGuiTreeNodeFlags.DefaultOpen, ImGuiTreeNodeFlags.DrawLinesFull), + MyTreeNode = nil, -- [Port] local struct, created once on first use + nodes = { -- 1-based; ChildIdx stays 0-based like upstream + { Name = "Root with Long Name", Type = "Folder", Size = -1, ChildIdx = 1, ChildCount = 3 }, -- 0 + { Name = "Music", Type = "Folder", Size = -1, ChildIdx = 4, ChildCount = 2 }, -- 1 + { Name = "Textures", Type = "Folder", Size = -1, ChildIdx = 6, ChildCount = 3 }, -- 2 + { Name = "desktop.ini", Type = "System file", Size = 1024, ChildIdx = -1, ChildCount = -1 }, -- 3 + { Name = "File1_a.wav", Type = "Audio file", Size = 123000, ChildIdx = -1, ChildCount = -1 }, -- 4 + { Name = "File1_b.wav", Type = "Audio file", Size = 456000, ChildIdx = -1, ChildCount = -1 }, -- 5 + { Name = "Image001.png", Type = "Image file", Size = 203128, ChildIdx = -1, ChildCount = -1 }, -- 6 + { Name = "Copy of Image001.png", Type = "Image file", Size = 203256, ChildIdx = -1, ChildCount = -1 }, -- 7 + { Name = "Copy of Image001 (Final2).png", Type = "Image file", Size = 203512, ChildIdx = -1, ChildCount = -1 }, -- 8 + }, + }, + ItemWidth = { + dummy_f = 0.0, + }, + CustomHeaders = { + column_selected = { false, false, false }, + }, + AngledHeaders = { + table_flags = bit32.bor(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersInnerH, ImGuiTableFlags.Hideable, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.HighlightHoveredColumn), + column_flags = bit32.bor(ImGuiTableColumnFlags.AngledHeader, ImGuiTableColumnFlags.WidthFixed), + bools = {}, -- 1-based, filled with false on first use + frozen_cols = 1, + frozen_rows = 2, + }, + ContextMenus = { + flags1 = bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Borders, ImGuiTableFlags.ContextMenuInBody), + }, + SyncedInstances = { + flags = bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Borders, ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.NoSavedSettings), + }, + template_items_names = { + "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango", + "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot" + }, + Sorting = { + items = ImVector(), + flags = bit32.bor( + ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Sortable, ImGuiTableFlags.SortMulti, + ImGuiTableFlags.RowBg, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV, ImGuiTableFlags.NoBordersInBody, + ImGuiTableFlags.ScrollY), + }, + Advanced = { + flags = bit32.bor( + ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, + ImGuiTableFlags.Sortable, ImGuiTableFlags.SortMulti, + ImGuiTableFlags.RowBg, ImGuiTableFlags.Borders, ImGuiTableFlags.NoBordersInBody, + ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY, + ImGuiTableFlags.SizingFixedFit), + columns_base_flags = ImGuiTableColumnFlags.None, + contents_type = 5, -- CT_SelectableSpanRow + freeze_cols = 1, + freeze_rows = 1, + items_count = 0, -- IM_COUNTOF(template_items_names) * 2, set below + outer_size_value = nil, -- ImVec2(0.0f, TEXT_BASE_HEIGHT * 12), set lazily (needs font) + row_min_height = 0.0, -- Auto + inner_width_with_scroll = 0.0, -- Auto-extend + outer_size_enabled = true, + show_headers = true, + show_wrapped_text = false, + items = ImVector(), + selection = ImVector(), + items_need_sort = false, + show_debug_details = false, + }, +} +S.DemoWindowTables.Advanced.items_count = #S.DemoWindowTables.template_items_names * 2 -local function Tables_Basic() - IMGUI_DEMO_MARKER("Tables/Basic") - -- Here we will showcase three different ways to output a table. - -- They are very simple variations of a same thing! - - -- [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. - -- In many situations, this is the most flexible and easy to use pattern. - DemoHelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.") - if ImGui.BeginTable("table1", 3) then - for row = 0, 3 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Row %d Column %d", row, column) - end - end - ImGui.EndTable() +function DemoWindowTables() + local _ + local s = S.DemoWindowTables + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) + if not ImGui.CollapsingHeader("Tables & Columns") then + return end - -- [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). - -- This is generally more convenient when you have code manually submitting the contents of each column. - DemoHelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.") - if ImGui.BeginTable("table2", 3) then - for row = 0, 3 do - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.Text("Row %d", row) - ImGui.TableNextColumn() - ImGui.Text("Some contents") - ImGui.TableNextColumn() - ImGui.Text("123.456") - end - ImGui.EndTable() + -- Using those as a base value to create width/height that are factor of the size of our font + local TEXT_BASE_WIDTH = ImGui.CalcTextSize("A").x + local TEXT_BASE_HEIGHT = ImGui.GetTextLineHeightWithSpacing() + + ImGui.PushID("Tables") + + local open_action = -1 + if ImGui.Button("Expand all") then + open_action = 1 end - - -- [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), - -- as TableNextColumn() will automatically wrap around and create new rows as needed. - -- This is generally more convenient when your cells all contains the same type of data. - DemoHelpMarker( - "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains " .. - "the same type of contents.\n This is also more similar to the old NextColumn() function of the " .. - "Columns API, and provided to facilitate the Columns->Tables API transition.") - if ImGui.BeginTable("table3", 3) then - for item = 0, 13 do - ImGui.TableNextColumn() - ImGui.Text("Item %d", item) - end - ImGui.EndTable() - end -end - -local function Tables_BordersBackground() - IMGUI_DEMO_MARKER("Tables/Borders, background") - -- Expose a few Borders related flags interactively - local CT_Text, CT_FillButton = 0, 1 - local s = ST.borders - if s == nil then s = { flags = bor(TF.Borders, TF.RowBg), display_headers = false, contents_type = CT_Text }; ST.borders = s end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, TF.RowBg) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, TF.Borders) - ImGui.SameLine(); DemoHelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH") - ImGui.Indent() - - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, TF.BordersH) - ImGui.Indent() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, TF.BordersOuterH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, TF.BordersInnerH) - ImGui.Unindent() - - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, TF.BordersV) - ImGui.Indent() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, TF.BordersOuterV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, TF.BordersInnerV) - ImGui.Unindent() - - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags, TF.BordersOuter) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags, TF.BordersInner) - ImGui.Unindent() - - ImGui.AlignTextToFramePadding(); ImGui.Text("Cell contents:") - ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("Text", s.contents_type, CT_Text) - ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("FillButton", s.contents_type, CT_FillButton) - _, s.display_headers = ImGui.Checkbox("Display headers", s.display_headers) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, TF.NoBordersInBody); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") - PopStyleCompact() - - if ImGui.BeginTable("table1", 3, s.flags) then - -- Display headers so we can inspect their interaction with borders - -- (Headers are not the main purpose of this section of the demo, so we are not elaborating on them now. See other sections for details) - if s.display_headers then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - end - - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - local buf = string.format("Hello %d,%d", column, row) - if s.contents_type == CT_Text then - ImGui.TextUnformatted(buf) - elseif s.contents_type == CT_FillButton then - ImGui.Button(buf, ImVec2(-FLT_MIN, 0.0)) - end - end - end - ImGui.EndTable() - end -end - -local function Tables_HelloGrid(id, flags, rows, cols, fmt) - if ImGui.BeginTable(id, cols, flags) then - for row = 0, rows - 1 do - ImGui.TableNextRow() - for column = 0, cols - 1 do - ImGui.TableSetColumnIndex(column) - ImGui.Text(fmt or "Hello %d,%d", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_ResizableStretch() - IMGUI_DEMO_MARKER("Tables/Resizable, stretch") - -- By default, if we don't enable ScrollX the sizing policy for each column is "Stretch" - -- All columns maintain a sizing weight, and they will occupy all available width. - local s = ST.rstretch - if s == nil then s = { flags = bor(TF.SizingStretchSame, TF.Resizable, TF.BordersOuter, TF.BordersV, TF.ContextMenuInBody) }; ST.rstretch = s end - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, TF.BordersV) - ImGui.SameLine(); DemoHelpMarker( - "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, " .. - "this is why the resize borders are still showing when unchecking this.") - PopStyleCompact() - - Tables_HelloGrid("table1", s.flags, 5, 3) -end - -local function Tables_ResizableFixed() - IMGUI_DEMO_MARKER("Tables/Resizable, fixed") - -- Here we use ImGuiTableFlags.SizingFixedFit (even though _ScrollX is not set) - -- So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) - -- If there is not enough available width to fit all columns, they will however be resized down. - -- FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings - DemoHelpMarker( - "Using _Resizable + _SizingFixedFit flags.\n" .. - "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" .. - "Double-click a column border to auto-fit the column to its contents.") - PushStyleCompact() - local s = ST.rfixed - if s == nil then s = { flags = bor(TF.SizingFixedFit, TF.Resizable, TF.BordersOuter, TF.BordersV, TF.ContextMenuInBody) }; ST.rfixed = s end - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, TF.NoHostExtendX) - PopStyleCompact() - - Tables_HelloGrid("table1", s.flags, 5, 3) -end - -local function Tables_ResizableMixed() - IMGUI_DEMO_MARKER("Tables/Resizable, mixed") - DemoHelpMarker( - "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" .. - "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.") - local flags = bor(TF.SizingFixedFit, TF.RowBg, TF.Borders, TF.Resizable, TF.Reorderable, TF.Hideable) - local CF = ImGuiTableColumnFlags - - if ImGui.BeginTable("table1", 3, flags) then - ImGui.TableSetupColumn("AAA", CF.WidthFixed) - ImGui.TableSetupColumn("BBB", CF.WidthFixed) - ImGui.TableSetupColumn("CCC", CF.WidthStretch) - ImGui.TableHeadersRow() - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s %d,%d", (column == 2) and "Stretch" or "Fixed", column, row) - end - end - ImGui.EndTable() - end - if ImGui.BeginTable("table2", 6, flags) then - ImGui.TableSetupColumn("AAA", CF.WidthFixed) - ImGui.TableSetupColumn("BBB", CF.WidthFixed) - ImGui.TableSetupColumn("CCC", bor(CF.WidthFixed, CF.DefaultHide)) - ImGui.TableSetupColumn("DDD", CF.WidthStretch) - ImGui.TableSetupColumn("EEE", CF.WidthStretch) - ImGui.TableSetupColumn("FFF", bor(CF.WidthStretch, CF.DefaultHide)) - ImGui.TableHeadersRow() - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 5 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s %d,%d", (column >= 3) and "Stretch" or "Fixed", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_Reorderable() - IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers") - DemoHelpMarker( - "Click and drag column headers to reorder columns.\n\n" .. - "Right-click on a header to open a context menu.") - local s = ST.reorder - if s == nil then s = { flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.BordersOuter, TF.BordersV) }; ST.reorder = s end - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, TF.Reorderable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, TF.Hideable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, TF.NoBordersInBody) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, TF.NoBordersInBodyUntilResize); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, TF.HighlightHoveredColumn) - PopStyleCompact() - - if ImGui.BeginTable("table1", 3, s.flags) then - -- Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column. - -- (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.) - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - for row = 0, 5 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Hello %d,%d", column, row) - end - end - ImGui.EndTable() - end - - -- Use outer_size.x == 0.0f instead of default to make the table as tight as possible - -- (only valid when no scrolling and no stretch column) - if ImGui.BeginTable("table2", 3, bor(s.flags, TF.SizingFixedFit), ImVec2(0.0, 0.0)) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - for row = 0, 5 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Fixed %d,%d", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_Padding() - IMGUI_DEMO_MARKER("Tables/Padding") - -- First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding. - -- We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding. - DemoHelpMarker( - "We often want outer padding activated when any using features which makes the edges of a column visible:\n" .. - "e.g.:\n" .. - "- BorderOuterV\n" .. - "- any form of row selection\n" .. - "Because of this, activating BorderOuterV sets the default to PadOuterX. " .. - "Using PadOuterX or NoPadOuterX you can override the default.\n\n" .. - "Actual padding values are using style.CellPadding.\n\n" .. - "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.") - - local s = ST.padding - if s == nil then - s = { flags1 = TF.BordersV, show_headers = false, flags2 = bor(TF.Borders, TF.RowBg), cell_padding = ImVec2(0.0, 0.0), - show_widget_frame_bg = true, text_bufs = {}, init = true } -- text_bufs: Mini text storage for 3x5 cells - ST.padding = s - end - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags1, TF.PadOuterX) - ImGui.SameLine(); DemoHelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)") - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags1, TF.NoPadOuterX) - ImGui.SameLine(); DemoHelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)") - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags1, TF.NoPadInnerX) - ImGui.SameLine(); DemoHelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)") - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags1, TF.BordersOuterV) - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags1, TF.BordersInnerV) - _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) - PopStyleCompact() - - if ImGui.BeginTable("table_padding", 3, s.flags1) then - if s.show_headers then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableHeadersRow() - end - - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - if row == 0 then - ImGui.Text("Avail %.2f", ImGui.GetContentRegionAvail().x) - else - local buf = string.format("Hello %d,%d", column, row) - ImGui.Button(buf, ImVec2(-FLT_MIN, 0.0)) - end - -- if bit32.band(ImGui.TableGetColumnFlags(), ImGuiTableColumnFlags.IsHovered) ~= 0 then - -- ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, IM_COL32(0, 100, 0, 255)) - -- end - end - end - ImGui.EndTable() - end - - -- Second example: set style.CellPadding to (0.0) or a custom value. - -- FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one... - DemoHelpMarker("Setting style.CellPadding to (0,0) or a custom value.") - - PushStyleCompact() - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags2, TF.Borders) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags2, TF.BordersH) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags2, TF.BordersV) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags2, TF.BordersInner) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags2, TF.BordersOuter) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags2, TF.RowBg) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags2, TF.Resizable) - _, s.show_widget_frame_bg = ImGui.Checkbox("show_widget_frame_bg", s.show_widget_frame_bg) - ImGui.SliderFloat2("CellPadding", s.cell_padding, 0.0, 10.0, "%.0f") - PopStyleCompact() - - ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, s.cell_padding) - if ImGui.BeginTable("table_padding_2", 3, s.flags2) then - if not s.show_widget_frame_bg then - ImGui.PushStyleColor(ImGuiCol.FrameBg, 0) - end - for cell = 0, 3 * 5 - 1 do - ImGui.TableNextColumn() - if s.init then - s.text_bufs[cell + 1] = Buf("edit me", 16) - end - ImGui.SetNextItemWidth(-FLT_MIN) - ImGui.PushID(cell) - ImGui.InputText("##cell", s.text_bufs[cell + 1], 16) - ImGui.PopID() - end - if not s.show_widget_frame_bg then - ImGui.PopStyleColor() - end - s.init = false - ImGui.EndTable() - end - ImGui.PopStyleVar() -end - -local function Tables_SizingPolicies() - IMGUI_DEMO_MARKER("Tables/Explicit widths") - local s = ST.sizing - if s == nil then - s = { flags1 = bor(TF.BordersV, TF.BordersOuterH, TF.RowBg, TF.ContextMenuInBody), - sizing_policy_flags = { TF.SizingFixedFit, TF.SizingFixedSame, TF.SizingStretchProp, TF.SizingStretchSame }, - flags = bor(TF.ScrollY, TF.Borders, TF.RowBg, TF.Resizable), contents_type = 0, column_count = 3, text_buf = Buf("", 32) } - ST.sizing = s - end - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, TF.Resizable) - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags1, TF.NoHostExtendX) - PopStyleCompact() - - for table_n = 0, 3 do - ImGui.PushID(table_n) - ImGui.SetNextItemWidth(TEXT_BASE_WIDTH * 30) - s.sizing_policy_flags[table_n + 1] = EditTableSizingFlags(s.sizing_policy_flags[table_n + 1]) - - -- To make it easier to understand the different sizing policy, - -- For each policy: we display one table where the columns have equal contents width, - -- and one where the columns have different contents width. - if ImGui.BeginTable("table1", 3, bor(s.sizing_policy_flags[table_n + 1], s.flags1)) then - for row = 0, 2 do - ImGui.TableNextRow() - ImGui.TableNextColumn(); ImGui.Text("Oh dear") - ImGui.TableNextColumn(); ImGui.Text("Oh dear") - ImGui.TableNextColumn(); ImGui.Text("Oh dear") - end - ImGui.EndTable() - end - if ImGui.BeginTable("table2", 3, bor(s.sizing_policy_flags[table_n + 1], s.flags1)) then - for row = 0, 2 do - ImGui.TableNextRow() - ImGui.TableNextColumn(); ImGui.Text("AAAA") - ImGui.TableNextColumn(); ImGui.Text("BBBBBBBB") - ImGui.TableNextColumn(); ImGui.Text("CCCCCCCCCCCC") - end - ImGui.EndTable() - end - ImGui.PopID() - end - - ImGui.Spacing() - ImGui.TextUnformatted("Advanced") ImGui.SameLine() - DemoHelpMarker( - "This section allows you to interact and see the effect of various sizing policies " .. - "depending on whether Scroll is enabled and the contents of your columns.") - - local CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText = 0, 1, 2, 3, 4, 5 - - PushStyleCompact() - ImGui.PushID("Advanced") - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) - s.flags = EditTableSizingFlags(s.flags) - if ImGui.Combo then - s.contents_type = ImGui.Combo("Contents", s.contents_type, { "Show width", "Short Text", "Long Text", "Button", "Fill Button", "InputText" }, 6) - else - NotPorted("Combo") + if ImGui.Button("Collapse all") then + open_action = 0 end - if s.contents_type == CT_FillButton then - ImGui.SameLine() - DemoHelpMarker( - "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop " .. - "where contents width can feed into auto-column width can feed into contents width.") + ImGui.SameLine() + + -- Options + _, s.disable_indent = ImGui.Checkbox("Disable tree indentation", s.disable_indent) + ImGui.SameLine() + HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.") + ImGui.Separator() + if s.disable_indent then + ImGui.PushStyleVar(ImGuiStyleVar.IndentSpacing, 0.0) end - s.column_count = ImGui.DragInt("Columns", s.column_count, 0.1, 1, 64, "%d", ImGuiSliderFlags.AlwaysClamp) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, TF.PreciseWidths) - ImGui.SameLine(); DemoHelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, TF.ScrollX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, TF.NoClip) - ImGui.PopItemWidth() - ImGui.PopID() - PopStyleCompact() - if ImGui.BeginTable("table2", s.column_count, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 7)) then - for cell = 0, 10 * s.column_count - 1 do - ImGui.TableNextColumn() - local column = ImGui.TableGetColumnIndex() - local row = ImGui.TableGetRowIndex() + -- About Styling of tables + -- Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs. + -- There are however a few settings that a shared and part of the ImGuiStyle structure: + -- style.CellPadding -- Padding within each cell + -- style.Colors[ImGuiCol.TableHeaderBg] -- Table header background + -- style.Colors[ImGuiCol.TableBorderStrong] -- Table outer and header borders + -- style.Colors[ImGuiCol.TableBorderLight] -- Table inner borders + -- style.Colors[ImGuiCol.TableRowBg] -- Table row background when ImGuiTableFlags_RowBg is enabled (even rows) + -- style.Colors[ImGuiCol.TableRowBgAlt] -- Table row background when ImGuiTableFlags_RowBg is enabled (odds rows) - ImGui.PushID(cell) - local label = string.format("Hello %d,%d", column, row) - local ct = s.contents_type - if ct == CT_ShortText then ImGui.TextUnformatted(label) - elseif ct == CT_LongText then ImGui.Text("Some %s text %d,%d\nOver two lines..", column == 0 and "long" or "longeeer", column, row) - elseif ct == CT_ShowWidth then ImGui.Text("W: %.1f", ImGui.GetContentRegionAvail().x) - elseif ct == CT_Button then ImGui.Button(label) - elseif ct == CT_FillButton then ImGui.Button(label, ImVec2(-FLT_MIN, 0.0)) - elseif ct == CT_InputText then ImGui.SetNextItemWidth(-FLT_MIN); ImGui.InputText("##", s.text_buf, 32) - end - ImGui.PopID() - end - ImGui.EndTable() + -- Demos + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) end -end + if ImGui.TreeNode("Basic") then + IMGUI_DEMO_MARKER("Tables/Basic") + -- Here we will showcase three different ways to output a table. + -- They are very simple variations of a same thing! -local function Tables_VerticalScrolling() - IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping") - DemoHelpMarker( - "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n" .. - "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.") - local s = ST.vscroll - if s == nil then s = { flags = bor(TF.ScrollY, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.Resizable, TF.Reorderable, TF.Hideable) }; ST.vscroll = s end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - PopStyleCompact() - - -- When using ScrollX or ScrollY we need to specify a size for our table container! - -- Otherwise by default the table will fit all available space, like a BeginChild() call. - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) - if ImGui.BeginTable("table_scrolly", 3, s.flags, outer_size) then - ImGui.TableSetupScrollFreeze(0, 1) -- Make top row always visible - ImGui.TableSetupColumn("One", ImGuiTableColumnFlags.None) - ImGui.TableSetupColumn("Two", ImGuiTableColumnFlags.None) - ImGui.TableSetupColumn("Three", ImGuiTableColumnFlags.None) - ImGui.TableHeadersRow() - - -- Demonstrate using clipper for large vertical lists - local clipper = ImGuiListClipper() - clipper:Begin(1000) - while clipper:Step() do - for row = clipper.DisplayStart, clipper.DisplayEnd - 1 do + -- [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. + -- In many situations, this is the most flexible and easy to use pattern. + HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.") + if ImGui.BeginTable("table1", 3) then + for row = 0, 4 - 1 do ImGui.TableNextRow() - for column = 0, 2 do + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Row %d Column %d", row, column) + end + end + ImGui.EndTable() + end + + -- [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex(). + -- This is generally more convenient when you have code manually submitting the contents of each column. + HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.") + if ImGui.BeginTable("table2", 3) then + for row = 0, 4 - 1 do + ImGui.TableNextRow() + ImGui.TableNextColumn() + ImGui.Text("Row %d", row) + ImGui.TableNextColumn() + ImGui.Text("Some contents") + ImGui.TableNextColumn() + ImGui.Text("123.456") + end + ImGui.EndTable() + end + + -- [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), + -- as TableNextColumn() will automatically wrap around and create new rows as needed. + -- This is generally more convenient when your cells all contains the same type of data. + HelpMarker( + "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains " .. + "the same type of contents.\n This is also more similar to the old NextColumn() function of the " .. + "Columns API, and provided to facilitate the Columns->Tables API transition.") + if ImGui.BeginTable("table3", 3) then + for item = 0, 14 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Item %d", item) + end + ImGui.EndTable() + end + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Borders, background") then + IMGUI_DEMO_MARKER("Tables/Borders, background") + -- Expose a few Borders related flags interactively + local CT_Text, CT_FillButton = 0, 1 -- enum ContentsType + local s = s.BordersBackground + + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, ImGuiTableFlags.RowBg) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, ImGuiTableFlags.Borders) + ImGui.SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH") + ImGui.Indent() + + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, ImGuiTableFlags.BordersH) + ImGui.Indent() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, ImGuiTableFlags.BordersOuterH) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, ImGuiTableFlags.BordersInnerH) + ImGui.Unindent() + + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, ImGuiTableFlags.BordersV) + ImGui.Indent() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, ImGuiTableFlags.BordersOuterV) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, ImGuiTableFlags.BordersInnerV) + ImGui.Unindent() + + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags, ImGuiTableFlags.BordersOuter) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags, ImGuiTableFlags.BordersInner) + ImGui.Unindent() + + ImGui.AlignTextToFramePadding(); ImGui.Text("Cell contents:") + ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("Text", s.contents_type, CT_Text) + ImGui.SameLine(); _, s.contents_type = ImGui.RadioButton("FillButton", s.contents_type, CT_FillButton) + _, s.display_headers = ImGui.Checkbox("Display headers", s.display_headers) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, ImGuiTableFlags.NoBordersInBody); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") + PopStyleCompact() + + if ImGui.BeginTable("table1", 3, s.flags) then + -- Display headers so we can inspect their interaction with borders + -- (Headers are not the main purpose of this section of the demo, so we are not elaborating on them now. See other sections for details) + if s.display_headers then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + end + + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + local buf = string.format("Hello %d,%d", column, row) + if s.contents_type == CT_Text then + ImGui.TextUnformatted(buf) + elseif s.contents_type == CT_FillButton then + ImGui.Button(buf, ImVec2(-FLT_MIN, 0.0)) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Resizable, stretch") then + IMGUI_DEMO_MARKER("Tables/Resizable, stretch") + -- By default, if we don't enable ScrollX the sizing policy for each column is "Stretch" + -- All columns maintain a sizing weight, and they will occupy all available width. + local s = s.ResizableStretch + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, ImGuiTableFlags.Resizable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, ImGuiTableFlags.BordersV) + ImGui.SameLine(); HelpMarker( + "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, " .. + "this is why the resize borders are still showing when unchecking this.") + PopStyleCompact() + + if ImGui.BeginTable("table1", 3, s.flags) then + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do ImGui.TableSetColumnIndex(column) ImGui.Text("Hello %d,%d", column, row) end end + ImGui.EndTable() end - ImGui.EndTable() - end -end - -local function Tables_HorizontalScrolling() - IMGUI_DEMO_MARKER("Tables/Horizontal scrolling") - DemoHelpMarker( - "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " .. - "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" .. - "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, " .. - "because the container window won't automatically extend vertically to fix contents " .. - "(this may be improved in future versions).") - local s = ST.hscroll - if s == nil then - s = { flags = bor(TF.ScrollX, TF.ScrollY, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.Resizable, TF.Reorderable, TF.Hideable), - freeze_cols = 1, freeze_rows = 1, - flags2 = bor(TF.SizingStretchSame, TF.ScrollX, TF.ScrollY, TF.BordersOuter, TF.RowBg, TF.ContextMenuInBody), inner_width = 1000.0 } - ST.hscroll = s - end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, TF.ScrollX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, ImGuiSliderFlags.NoInput) - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, ImGuiSliderFlags.NoInput) - PopStyleCompact() - - -- When using ScrollX or ScrollY we need to specify a size for our table container! - -- Otherwise by default the table will fit all available space, like a BeginChild() call. - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) - if ImGui.BeginTable("table_scrollx", 7, s.flags, outer_size) then - ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) - ImGui.TableSetupColumn("Line #", ImGuiTableColumnFlags.NoHide) -- Make the first column not hideable to match our use of TableSetupScrollFreeze() - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - ImGui.TableSetupColumn("Four") - ImGui.TableSetupColumn("Five") - ImGui.TableSetupColumn("Six") - ImGui.TableHeadersRow() - for row = 0, 19 do - ImGui.TableNextRow() - for column = 0, 6 do repeat - -- Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement. - -- Because here we know that: - -- - A) all our columns are contributing the same to row height - -- - B) column 0 is always visible, - -- We only always submit this one column and can skip others. - -- More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags(). - if not ImGui.TableSetColumnIndex(column) and column > 0 then - break -- continue - end - if column == 0 then - ImGui.Text("Line %d", row) - else - ImGui.Text("Hello world %d,%d", column, row) - end - until true end - end - ImGui.EndTable() - end - - ImGui.Spacing() - ImGui.TextUnformatted("Stretch + ScrollX") - ImGui.SameLine() - DemoHelpMarker( - "Showcase using Stretch columns + ScrollX together: " .. - "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" .. - "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns " .. - "along with ScrollX doesn't make sense.") - PushStyleCompact() - ImGui.PushID("flags3") - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags2, TF.ScrollX) - s.inner_width = ImGui.DragFloat("inner_width", s.inner_width, 1.0, 0.0, FLT_MAX, "%.1f") - ImGui.PopItemWidth() - ImGui.PopID() - PopStyleCompact() - if ImGui.BeginTable("table2", 7, s.flags2, outer_size, s.inner_width) then - for cell = 0, 20 * 7 - 1 do - ImGui.TableNextColumn() - ImGui.Text("Hello world %d,%d", ImGui.TableGetColumnIndex(), ImGui.TableGetRowIndex()) - end - ImGui.EndTable() - end -end - -local function Tables_ColumnsFlags() - IMGUI_DEMO_MARKER("Tables/Columns flags") - -- Create a first table just to show all the options/flags we want to make visible in our example! - local column_count = 3 - local column_names = { "One", "Two", "Three" } - local s = ST.colflags - if s == nil then - s = { column_flags = { ImGuiTableColumnFlags.DefaultSort, ImGuiTableColumnFlags.None, ImGuiTableColumnFlags.DefaultHide }, column_flags_out = { 0, 0, 0 } } -- column_flags_out: Output from TableGetColumnFlags() - ST.colflags = s - end - - if ImGui.BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags.None) then - PushStyleCompact() - for column = 1, column_count do - ImGui.TableNextColumn() - ImGui.PushID(column - 1) - ImGui.AlignTextToFramePadding() -- FIXME-TABLE: Workaround for wrong text baseline propagation across columns - ImGui.Text("'%s'", column_names[column]) - ImGui.Spacing() - ImGui.Text("Input flags:") - s.column_flags[column] = EditTableColumnsFlags(s.column_flags[column]) - ImGui.Spacing() - ImGui.Text("Output flags:") - ImGui.BeginDisabled() - ShowTableColumnsStatusFlags(s.column_flags_out[column]) - ImGui.EndDisabled() - ImGui.PopID() - end - PopStyleCompact() - ImGui.EndTable() - end - - -- Create the real table we care about for the example! - -- We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, - -- otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible - -- + resizing the parent window down). - local flags = bor(TF.SizingFixedFit, TF.ScrollX, TF.ScrollY, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.Resizable, TF.Reorderable, TF.Hideable, TF.Sortable) - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 9) - if ImGui.BeginTable("table_columns_flags", column_count, flags, outer_size) then - local has_angled_header = false - for column = 1, column_count do - has_angled_header = has_angled_header or Has(s.column_flags[column], ImGuiTableColumnFlags.AngledHeader) - ImGui.TableSetupColumn(column_names[column], s.column_flags[column]) - end - if has_angled_header then - ImGui.TableAngledHeadersRow() - end - ImGui.TableHeadersRow() - for column = 1, column_count do - s.column_flags_out[column] = ImGui.TableGetColumnFlags(column - 1) - end - local indent_step = math.floor(math.floor(TEXT_BASE_WIDTH) / 2) - for row = 0, 7 do - -- Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags. - ImGui.Indent(indent_step) - ImGui.TableNextRow() - for column = 0, column_count - 1 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s %s", (column == 0) and "Indented" or "Hello", ImGui.TableGetColumnName(column)) - end - end - ImGui.Unindent(indent_step * 8.0) - - ImGui.EndTable() - end -end - -local function Tables_ColumnsWidths() - IMGUI_DEMO_MARKER("Tables/Columns widths") - DemoHelpMarker("Using TableSetupColumn() to setup default width.") - local s = ST.colwidths - if s == nil then s = { flags1 = bor(TF.Borders, TF.NoBordersInBodyUntilResize), flags2 = TF.None }; ST.colwidths = s end - local CF = ImGuiTableColumnFlags - - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, TF.Resizable) - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags1, TF.NoBordersInBodyUntilResize) - PopStyleCompact() - if ImGui.BeginTable("table1", 3, s.flags1) then - -- We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. - ImGui.TableSetupColumn("one", CF.WidthFixed, 100.0) -- Default to 100.0f - ImGui.TableSetupColumn("two", CF.WidthFixed, 200.0) -- Default to 200.0f - ImGui.TableSetupColumn("three", CF.WidthFixed) -- Default to auto - ImGui.TableHeadersRow() - for row = 0, 3 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableSetColumnIndex(column) - if row == 0 then - ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) - else - ImGui.Text("Hello %d,%d", column, row) - end - end - end - ImGui.EndTable() - end - - DemoHelpMarker( - "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, " .. - "fixed columns with set width may still be shrunk down if there's not enough space in the host.") - - PushStyleCompact() - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags2, TF.NoKeepColumnsVisible) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags2, TF.BordersInnerV) - _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags2, TF.BordersOuterV) - PopStyleCompact() - if ImGui.BeginTable("table2", 4, s.flags2) then - -- We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns - -- will default to ImGuiTableColumnFlags_WidthFixed. - ImGui.TableSetupColumn("", CF.WidthFixed, 100.0) - ImGui.TableSetupColumn("", CF.WidthFixed, TEXT_BASE_WIDTH * 15.0) - ImGui.TableSetupColumn("", CF.WidthFixed, TEXT_BASE_WIDTH * 30.0) - ImGui.TableSetupColumn("", CF.WidthFixed, TEXT_BASE_WIDTH * 15.0) - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 3 do - ImGui.TableSetColumnIndex(column) - if row == 0 then - ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) - else - ImGui.Text("Hello %d,%d", column, row) - end - end - end - ImGui.EndTable() - end -end - -local function Tables_Nested() - IMGUI_DEMO_MARKER("Tables/Nested tables") - DemoHelpMarker("This demonstrates embedding a table into another table cell.") - - if ImGui.BeginTable("table_nested1", 2, bor(TF.Borders, TF.Resizable, TF.Reorderable, TF.Hideable)) then - ImGui.TableSetupColumn("A0") - ImGui.TableSetupColumn("A1") - ImGui.TableHeadersRow() - - ImGui.TableNextColumn() - ImGui.Text("A0 Row 0") - do - local rows_height = (TEXT_BASE_HEIGHT * 2.0) + (ImGui.GetStyle().CellPadding.y * 2.0) - if ImGui.BeginTable("table_nested2", 2, bor(TF.Borders, TF.Resizable, TF.Reorderable, TF.Hideable)) then - ImGui.TableSetupColumn("B0") - ImGui.TableSetupColumn("B1") - ImGui.TableHeadersRow() - - ImGui.TableNextRow(ImGuiTableRowFlags.None, rows_height) - ImGui.TableNextColumn() - ImGui.Text("B0 Row 0") - ImGui.TableNextColumn() - ImGui.Text("B1 Row 0") - ImGui.TableNextRow(ImGuiTableRowFlags.None, rows_height) - ImGui.TableNextColumn() - ImGui.Text("B0 Row 1") - ImGui.TableNextColumn() - ImGui.Text("B1 Row 1") - - ImGui.EndTable() - end - end - ImGui.TableNextColumn(); ImGui.Text("A1 Row 0") - ImGui.TableNextColumn(); ImGui.Text("A0 Row 1") - ImGui.TableNextColumn(); ImGui.Text("A1 Row 1") - ImGui.EndTable() - end -end - -local function Tables_RowHeight() - IMGUI_DEMO_MARKER("Tables/Row height") - DemoHelpMarker( - "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, " .. - "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n" .. - "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.") - if ImGui.BeginTable("table_row_height", 1, TF.Borders) then - for row = 0, 7 do - local min_row_height = math.floor(TEXT_BASE_HEIGHT * 0.30 * row + ImGui.GetStyle().CellPadding.y * 2.0) - ImGui.TableNextRow(ImGuiTableRowFlags.None, min_row_height) - ImGui.TableNextColumn() - ImGui.Text("min_row_height = %.2f", min_row_height) - end - ImGui.EndTable() - end - - DemoHelpMarker( - "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n" .. - "Please note that Tables Row Height is not the same thing as Current Line Height, " .. - "as a table cell may contains multiple lines.") - if ImGui.BeginTable("table_share_lineheight", 2, TF.Borders) then - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.ColorButton("##1", ImVec4(0.13, 0.26, 0.40, 1.0), ImGuiColorEditFlags.None, ImVec2(40, 40)) - ImGui.TableNextColumn() - ImGui.Text("Line 1") - ImGui.Text("Line 2") - - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.ColorButton("##2", ImVec4(0.13, 0.26, 0.40, 1.0), ImGuiColorEditFlags.None, ImVec2(40, 40)) - ImGui.TableNextColumn() - ImGui.SameLine(0.0, 0.0) -- Reuse line height from previous column - ImGui.Text("Line 1, with SameLine(0,0)") - ImGui.Text("Line 2") - - ImGui.EndTable() - end - - DemoHelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.") - if ImGui.BeginTable("table_changing_cellpadding_y", 1, TF.Borders) then - local style = ImGui.GetStyle() - for row = 0, 7 do - if (row % 3) == 2 then - ImGui.PushStyleVarY(ImGuiStyleVar.CellPadding, 20.0) - end - ImGui.TableNextRow(ImGuiTableRowFlags.None) - ImGui.TableNextColumn() - ImGui.Text("CellPadding.y = %.2f", style.CellPadding.y) - if (row % 3) == 2 then - ImGui.PopStyleVar() - end - end - ImGui.EndTable() - end -end - -local function Tables_OuterSize() - IMGUI_DEMO_MARKER("Tables/Outer size") - -- Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY - -- Important to that note how the two flags have slightly different behaviors! - ImGui.Text("Using NoHostExtendX and NoHostExtendY:") - PushStyleCompact() - local s = ST.outer - if s == nil then s = { flags = bor(TF.Borders, TF.Resizable, TF.ContextMenuInBody, TF.RowBg, TF.SizingFixedFit, TF.NoHostExtendX) }; ST.outer = s end - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, TF.NoHostExtendX) - ImGui.SameLine(); DemoHelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, TF.NoHostExtendY) - ImGui.SameLine(); DemoHelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") - PopStyleCompact() - - local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 5.5) - if ImGui.BeginTable("table1", 3, s.flags, outer_size) then - for row = 0, 9 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableNextColumn() - ImGui.Text("Cell %d,%d", column, row) - end - end - ImGui.EndTable() - end - ImGui.SameLine() - ImGui.Text("Hello!") - - ImGui.Spacing() - - ImGui.Text("Using explicit size:") - if ImGui.BeginTable("table2", 3, bor(TF.Borders, TF.RowBg), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - ImGui.TableNextColumn() - ImGui.Text("Cell %d,%d", column, row) - end - end - ImGui.EndTable() - end - ImGui.SameLine() - if ImGui.BeginTable("table3", 3, bor(TF.Borders, TF.RowBg), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then - local rows_height = TEXT_BASE_HEIGHT * 1.5 + ImGui.GetStyle().CellPadding.y * 2.0 - for row = 0, 2 do - ImGui.TableNextRow(0, rows_height) - for column = 0, 2 do - ImGui.TableNextColumn() - ImGui.Text("Cell %d,%d", column, row) - end - end - ImGui.EndTable() - end -end - -local function Tables_BackgroundColor() - IMGUI_DEMO_MARKER("Tables/Background color") - local s = ST.bgcolor - if s == nil then s = { flags = TF.RowBg, row_bg_type = 1, row_bg_target = 1, cell_bg_type = 1 }; ST.bgcolor = s end - - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, TF.Borders) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, TF.RowBg) - ImGui.SameLine(); DemoHelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.") - if ImGui.Combo then - s.row_bg_type = ImGui.Combo("row bg type", s.row_bg_type, { "None", "Red", "Gradient" }, 3) - s.row_bg_target = ImGui.Combo("row bg target", s.row_bg_target, { "RowBg0", "RowBg1" }, 2); ImGui.SameLine(); DemoHelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.") - s.cell_bg_type = ImGui.Combo("cell bg type", s.cell_bg_type, { "None", "Blue" }, 2); ImGui.SameLine(); DemoHelpMarker("We are colorizing cells to B1->C2 here.") - else - NotPorted("Combo") - end - IM_ASSERT(s.row_bg_type >= 0 and s.row_bg_type <= 2) - IM_ASSERT(s.row_bg_target >= 0 and s.row_bg_target <= 1) - IM_ASSERT(s.cell_bg_type >= 0 and s.cell_bg_type <= 1) - PopStyleCompact() - - if ImGui.BeginTable("table1", 5, s.flags) then - for row = 0, 5 do - ImGui.TableNextRow() - - -- Demonstrate setting a row background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBgX, ...)' - -- We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag. - if s.row_bg_type ~= 0 then - local row_bg_color = ImGui.GetColorU32(s.row_bg_type == 1 and ImVec4(0.7, 0.3, 0.3, 0.65) or ImVec4(0.2 + row * 0.1, 0.2, 0.2, 0.65)) -- Flat or Gradient? - ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0 + s.row_bg_target, row_bg_color) - end - - -- Fill cells - for column = 0, 4 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("%s%s", string.char(65 + row), string.char(48 + column)) - - -- Change background of Cells B1->C2 - -- Demonstrate setting a cell background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ...)' - -- (the CellBg color will be blended over the RowBg and ColumnBg colors) - -- We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop. - if row >= 1 and row <= 2 and column >= 1 and column <= 2 and s.cell_bg_type == 1 then - local cell_bg_color = ImGui.GetColorU32(ImVec4(0.3, 0.3, 0.7, 0.65)) - ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, cell_bg_color) - end - end - end - ImGui.EndTable() - end -end - --- Simple storage to output a dummy file-system. -local tree_view_nodes = { - { Name = "Root with Long Name", Type = "Folder", Size = -1, ChildIdx = 1, ChildCount = 3 }, -- 0 - { Name = "Music", Type = "Folder", Size = -1, ChildIdx = 4, ChildCount = 2 }, -- 1 - { Name = "Textures", Type = "Folder", Size = -1, ChildIdx = 6, ChildCount = 3 }, -- 2 - { Name = "desktop.ini", Type = "System file", Size = 1024, ChildIdx = -1, ChildCount = -1 }, -- 3 - { Name = "File1_a.wav", Type = "Audio file", Size = 123000, ChildIdx = -1, ChildCount = -1 }, -- 4 - { Name = "File1_b.wav", Type = "Audio file", Size = 456000, ChildIdx = -1, ChildCount = -1 }, -- 5 - { Name = "Image001.png", Type = "Image file", Size = 203128, ChildIdx = -1, ChildCount = -1 }, -- 6 - { Name = "Copy of Image001.png", Type = "Image file", Size = 203256, ChildIdx = -1, ChildCount = -1 }, -- 7 - { Name = "Copy of Image001 (Final2).png", Type = "Image file", Size = 203512, ChildIdx = -1, ChildCount = -1 }, -- 8 -} - -local function MyTreeNode_DisplayNode(node, all_nodes, tree_node_flags_base) - ImGui.TableNextRow() - ImGui.TableNextColumn() - local is_folder = (node.ChildCount > 0) - - local node_flags = tree_node_flags_base - if node ~= all_nodes[1] then - node_flags = bit32.band(node_flags, bit32.bnot(ImGuiTreeNodeFlags.LabelSpanAllColumns)) -- Only demonstrate this on the root node. - end - - if is_folder then - local open = ImGui.TreeNodeEx(node.Name, node_flags) - if bit32.band(node_flags, ImGuiTreeNodeFlags.LabelSpanAllColumns) == 0 then - ImGui.TableNextColumn() - ImGui.TextDisabled("--") - ImGui.TableNextColumn() - ImGui.TextUnformatted(node.Type) - end - if open then - for child_n = 0, node.ChildCount - 1 do - MyTreeNode_DisplayNode(all_nodes[node.ChildIdx + child_n + 1], all_nodes, tree_node_flags_base) - end - ImGui.TreePop() - end - else - ImGui.TreeNodeEx(node.Name, bor(node_flags, ImGuiTreeNodeFlags.Leaf, ImGuiTreeNodeFlags.Bullet, ImGuiTreeNodeFlags.NoTreePushOnOpen)) - ImGui.TableNextColumn() - ImGui.Text("%d", node.Size) - ImGui.TableNextColumn() - ImGui.TextUnformatted(node.Type) - end -end - -local function Tables_TreeView() - IMGUI_DEMO_MARKER("Tables/Tree view") - local s = ST.treeview - if s == nil then - s = { table_flags = bor(TF.BordersV, TF.BordersOuterH, TF.Resizable, TF.RowBg, TF.NoBordersInBody), - tree_node_flags_base = bor(ImGuiTreeNodeFlags.SpanAllColumns, ImGuiTreeNodeFlags.DefaultOpen, ImGuiTreeNodeFlags.DrawLinesFull) } - ST.treeview = s - end - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", s.tree_node_flags_base, ImGuiTreeNodeFlags.SpanFullWidth) - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", s.tree_node_flags_base, ImGuiTreeNodeFlags.SpanLabelWidth) - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", s.tree_node_flags_base, ImGuiTreeNodeFlags.SpanAllColumns) - _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", s.tree_node_flags_base, ImGuiTreeNodeFlags.LabelSpanAllColumns) - ImGui.SameLine(); DemoHelpMarker("Useful if you know that you aren't displaying contents in other columns") - - DemoHelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.") - if ImGui.BeginTable("3ways", 3, s.table_flags) then - -- The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On - ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.NoHide) - ImGui.TableSetupColumn("Size", ImGuiTableColumnFlags.WidthFixed, TEXT_BASE_WIDTH * 12.0) - ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthFixed, TEXT_BASE_WIDTH * 18.0) - ImGui.TableHeadersRow() - - MyTreeNode_DisplayNode(tree_view_nodes[1], tree_view_nodes, s.tree_node_flags_base) - - ImGui.EndTable() - end -end - -local function Tables_ItemWidth() - IMGUI_DEMO_MARKER("Tables/Item width") - DemoHelpMarker( - "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" .. - "Note that on auto-resizing non-resizable fixed columns, querying the content width for " .. - "e.g. right-alignment doesn't make sense.") - if ImGui.BeginTable("table_item_width", 3, TF.Borders) then - ImGui.TableSetupColumn("small") - ImGui.TableSetupColumn("half") - ImGui.TableSetupColumn("right-align") - ImGui.TableHeadersRow() - - for row = 0, 2 do - ImGui.TableNextRow() - if row == 0 then - -- Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient) - ImGui.TableSetColumnIndex(0) - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 3.0) -- Small - ImGui.TableSetColumnIndex(1) - ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.5) - ImGui.TableSetColumnIndex(2) - ImGui.PushItemWidth(-FLT_MIN) -- Right-aligned - end - - -- Draw our contents - ImGui.PushID(row) - ImGui.TableSetColumnIndex(0) - ST.dummy_f = ImGui.SliderFloat("float0", ST.dummy_f or 0.0, 0.0, 1.0) - ImGui.TableSetColumnIndex(1) - ST.dummy_f = ImGui.SliderFloat("float1", ST.dummy_f, 0.0, 1.0) - ImGui.TableSetColumnIndex(2) - ST.dummy_f = ImGui.SliderFloat("##float2", ST.dummy_f, 0.0, 1.0) -- No visible label since right-aligned - ImGui.PopID() - end - ImGui.EndTable() - end -end - --- Demonstrate using TableHeader() calls instead of TableHeadersRow() -local function Tables_CustomHeaders() - IMGUI_DEMO_MARKER("Tables/Custom headers") - local COLUMNS_COUNT = 3 - if ImGui.BeginTable("table_custom_headers", COLUMNS_COUNT, bor(TF.Borders, TF.Reorderable, TF.Hideable)) then - ImGui.TableSetupColumn("Apricot") - ImGui.TableSetupColumn("Banana") - ImGui.TableSetupColumn("Cherry") - - -- Dummy entire-column selection storage - -- FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. - if ST.column_selected == nil then ST.column_selected = { false, false, false } end - local column_selected = ST.column_selected - - -- Instead of calling TableHeadersRow() we'll submit custom headers ourselves. - -- (A different approach is also possible: - -- - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call. - -- - Call TableHeadersRow() normally. This will submit TableHeader() with no name. - -- - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().) - ImGui.TableNextRow(ImGuiTableRowFlags.Headers) - for column = 0, COLUMNS_COUNT - 1 do - ImGui.TableSetColumnIndex(column) - local column_name = ImGui.TableGetColumnName(column) -- Retrieve name passed to TableSetupColumn() - ImGui.PushID(column) - ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(0, 0)) - _, column_selected[column + 1] = ImGui.Checkbox("##checkall", column_selected[column + 1]) - ImGui.PopStyleVar() - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - ImGui.TableHeader(column_name) - ImGui.PopID() - end - - -- Submit table contents - for row = 0, 4 do - ImGui.TableNextRow() - for column = 0, 2 do - local buf = string.format("Cell %d,%d", column, row) - ImGui.TableSetColumnIndex(column) - ImGui.Selectable(buf, column_selected[column + 1]) - end - end - ImGui.EndTable() - end -end - --- Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers -local function Tables_AngledHeaders() - IMGUI_DEMO_MARKER("Tables/Angled headers") - local column_names = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" } - local columns_count = #column_names - local rows_count = 12 - - local s = ST.angled - if s == nil then - s = { table_flags = bor(TF.SizingFixedFit, TF.ScrollX, TF.ScrollY, TF.BordersOuter, TF.BordersInnerH, TF.Hideable, TF.Resizable, TF.Reorderable, TF.HighlightHoveredColumn), - column_flags = bor(ImGuiTableColumnFlags.AngledHeader, ImGuiTableColumnFlags.WidthFixed), - bools = {}, frozen_cols = 1, frozen_rows = 2 } -- bools: Dummy storage selection storage - for i = 1, columns_count * rows_count do s.bools[i] = false end - ST.angled = s - end - _, s.table_flags = ImGui.CheckboxFlags("_ScrollX", s.table_flags, TF.ScrollX) - _, s.table_flags = ImGui.CheckboxFlags("_ScrollY", s.table_flags, TF.ScrollY) - _, s.table_flags = ImGui.CheckboxFlags("_Resizable", s.table_flags, TF.Resizable) - _, s.table_flags = ImGui.CheckboxFlags("_Sortable", s.table_flags, TF.Sortable) - _, s.table_flags = ImGui.CheckboxFlags("_NoBordersInBody", s.table_flags, TF.NoBordersInBody) - _, s.table_flags = ImGui.CheckboxFlags("_HighlightHoveredColumn", s.table_flags, TF.HighlightHoveredColumn) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - s.frozen_cols = ImGui.SliderInt("Frozen columns", s.frozen_cols, 0, 2) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - s.frozen_rows = ImGui.SliderInt("Frozen rows", s.frozen_rows, 0, 2) - _, s.column_flags = ImGui.CheckboxFlags("Disable header contributing to column width", s.column_flags, ImGuiTableColumnFlags.NoHeaderWidth) - - if ImGui.TreeNode("Style settings") then - ImGui.SameLine() - DemoHelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.") - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - local style = ImGui.GetStyle() - style.TableAngledHeadersAngle = ImGui.SliderAngle("style.TableAngledHeadersAngle", style.TableAngledHeadersAngle, -50.0, 50.0) - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - ImGui.SliderFloat2("style.TableAngledHeadersTextAlign", style.TableAngledHeadersTextAlign, 0.0, 1.0, "%.2f") ImGui.TreePop() end - if ImGui.BeginTable("table_angled_headers", columns_count, s.table_flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 12)) then - ImGui.TableSetupColumn(column_names[1], bor(ImGuiTableColumnFlags.NoHide, ImGuiTableColumnFlags.NoReorder)) - for n = 2, columns_count do - ImGui.TableSetupColumn(column_names[n], s.column_flags) - end - ImGui.TableSetupScrollFreeze(s.frozen_cols, s.frozen_rows) + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Resizable, fixed") then + IMGUI_DEMO_MARKER("Tables/Resizable, fixed") + -- Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set) + -- So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) + -- If there is not enough available width to fit all columns, they will however be resized down. + -- FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings + HelpMarker( + "Using _Resizable + _SizingFixedFit flags.\n" .. + "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" .. + "Double-click a column border to auto-fit the column to its contents.") + PushStyleCompact() + local s = s.ResizableFixed + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, ImGuiTableFlags.NoHostExtendX) + PopStyleCompact() - ImGui.TableAngledHeadersRow() -- Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag. - ImGui.TableHeadersRow() -- Draw remaining headers and allow access to context-menu and other functions. - for row = 0, rows_count - 1 do - ImGui.PushID(row) - ImGui.TableNextRow() - ImGui.TableSetColumnIndex(0) - ImGui.AlignTextToFramePadding() - ImGui.Text("Track %d", row) - for column = 1, columns_count - 1 do - if ImGui.TableSetColumnIndex(column) then - ImGui.PushID(column) - local idx = row * columns_count + column + 1 - _, s.bools[idx] = ImGui.Checkbox("", s.bools[idx]) - ImGui.PopID() + if ImGui.BeginTable("table1", 3, s.flags) then + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Hello %d,%d", column, row) end end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Resizable, mixed") then + IMGUI_DEMO_MARKER("Tables/Resizable, mixed") + HelpMarker( + "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n" .. + "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.") + local s = s.ResizableMixed + + if ImGui.BeginTable("table1", 3, s.flags) then + ImGui.TableSetupColumn("AAA", ImGuiTableColumnFlags.WidthFixed) + ImGui.TableSetupColumn("BBB", ImGuiTableColumnFlags.WidthFixed) + ImGui.TableSetupColumn("CCC", ImGuiTableColumnFlags.WidthStretch) + ImGui.TableHeadersRow() + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%s %d,%d", (column == 2) and "Stretch" or "Fixed", column, row) + end + end + ImGui.EndTable() + end + if ImGui.BeginTable("table2", 6, s.flags) then + ImGui.TableSetupColumn("AAA", ImGuiTableColumnFlags.WidthFixed) + ImGui.TableSetupColumn("BBB", ImGuiTableColumnFlags.WidthFixed) + ImGui.TableSetupColumn("CCC", bit32.bor(ImGuiTableColumnFlags.WidthFixed, ImGuiTableColumnFlags.DefaultHide)) + ImGui.TableSetupColumn("DDD", ImGuiTableColumnFlags.WidthStretch) + ImGui.TableSetupColumn("EEE", ImGuiTableColumnFlags.WidthStretch) + ImGui.TableSetupColumn("FFF", bit32.bor(ImGuiTableColumnFlags.WidthStretch, ImGuiTableColumnFlags.DefaultHide)) + ImGui.TableHeadersRow() + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 6 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%s %d,%d", (column >= 3) and "Stretch" or "Fixed", column, row) + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Reorderable, hideable, with headers") then + IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers") + HelpMarker( + "Click and drag column headers to reorder columns.\n\n" .. + "Right-click on a header to open a context menu.") + local s = s.Reorderable + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, ImGuiTableFlags.Resizable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, ImGuiTableFlags.Reorderable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, ImGuiTableFlags.Hideable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, ImGuiTableFlags.NoBordersInBody) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, ImGuiTableFlags.NoBordersInBodyUntilResize); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, ImGuiTableFlags.HighlightHoveredColumn) + PopStyleCompact() + + if ImGui.BeginTable("table1", 3, s.flags) then + -- Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column. + -- (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.) + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + for row = 0, 6 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Hello %d,%d", column, row) + end + end + ImGui.EndTable() + end + + -- Use outer_size.x == 0.0f instead of default to make the table as tight as possible + -- (only valid when no scrolling and no stretch column) + if ImGui.BeginTable("table2", 3, bit32.bor(s.flags, ImGuiTableFlags.SizingFixedFit), ImVec2(0.0, 0.0)) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + for row = 0, 6 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Fixed %d,%d", column, row) + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Padding") then + IMGUI_DEMO_MARKER("Tables/Padding") + -- First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding. + -- We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding. + HelpMarker( + "We often want outer padding activated when any using features which makes the edges of a column visible:\n" .. + "e.g.:\n" .. + "- BorderOuterV\n" .. + "- any form of row selection\n" .. + "Because of this, activating BorderOuterV sets the default to PadOuterX. " .. + "Using PadOuterX or NoPadOuterX you can override the default.\n\n" .. + "Actual padding values are using style.CellPadding.\n\n" .. + "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.") + + local s = s.Padding + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags1, ImGuiTableFlags.PadOuterX) + ImGui.SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)") + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags1, ImGuiTableFlags.NoPadOuterX) + ImGui.SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)") + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags1, ImGuiTableFlags.NoPadInnerX) + ImGui.SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)") + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags1, ImGuiTableFlags.BordersOuterV) + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags1, ImGuiTableFlags.BordersInnerV) + _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) + PopStyleCompact() + + if ImGui.BeginTable("table_padding", 3, s.flags1) then + if s.show_headers then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + end + + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + if row == 0 then + ImGui.Text("Avail %.2f", ImGui.GetContentRegionAvail().x) + else + local buf = string.format("Hello %d,%d", column, row) + ImGui.Button(buf, ImVec2(-FLT_MIN, 0.0)) + end + --if bit32.band(ImGui.TableGetColumnFlags(), ImGuiTableColumnFlags.IsHovered) ~= 0 then + -- ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, IM_COL32(0, 100, 0, 255)) end + end + end + ImGui.EndTable() + end + + -- Second example: set style.CellPadding to (0.0) or a custom value. + -- FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one... + HelpMarker("Setting style.CellPadding to (0,0) or a custom value.") + + PushStyleCompact() + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags2, ImGuiTableFlags.Borders) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags2, ImGuiTableFlags.BordersH) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags2, ImGuiTableFlags.BordersV) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInner", s.flags2, ImGuiTableFlags.BordersInner) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuter", s.flags2, ImGuiTableFlags.BordersOuter) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags2, ImGuiTableFlags.RowBg) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags2, ImGuiTableFlags.Resizable) + _, s.show_widget_frame_bg = ImGui.Checkbox("show_widget_frame_bg", s.show_widget_frame_bg) + ImGui.SliderFloat2("CellPadding", s.cell_padding, 0.0, 10.0, "%.0f") + PopStyleCompact() + + ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, s.cell_padding) + if ImGui.BeginTable("table_padding_2", 3, s.flags2) then + -- static char text_bufs[3 * 5][16] -- Mini text storage for 3x5 cells + if not s.show_widget_frame_bg then + ImGui.PushStyleColor(ImGuiCol.FrameBg, 0) + end + for cell = 0, 3 * 5 - 1 do + ImGui.TableNextColumn() + if s.init then + s.text_bufs[cell + 1] = ImGui.NewTextBuffer("edit me", 16) -- [Port] strcpy() -> new buffer + end + ImGui.SetNextItemWidth(-FLT_MIN) + ImGui.PushID(cell) + ImGui.InputText("##cell", s.text_bufs[cell + 1], 16) + ImGui.PopID() + end + if not s.show_widget_frame_bg then + ImGui.PopStyleColor() + end + s.init = false + ImGui.EndTable() + end + ImGui.PopStyleVar() + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Sizing policies") then + IMGUI_DEMO_MARKER("Tables/Explicit widths") + local s = s.SizingPolicies + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, ImGuiTableFlags.Resizable) + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags1, ImGuiTableFlags.NoHostExtendX) + PopStyleCompact() + + local sizing_policy_flags = s.sizing_policy_flags -- 1-based + for table_n = 0, 4 - 1 do + ImGui.PushID(table_n) + ImGui.SetNextItemWidth(TEXT_BASE_WIDTH * 30) + sizing_policy_flags[table_n + 1] = EditTableSizingFlags(sizing_policy_flags[table_n + 1]) + + -- To make it easier to understand the different sizing policy, + -- For each policy: we display one table where the columns have equal contents width, + -- and one where the columns have different contents width. + if ImGui.BeginTable("table1", 3, bit32.bor(sizing_policy_flags[table_n + 1], s.flags1)) then + for row = 0, 3 - 1 do + ImGui.TableNextRow() + ImGui.TableNextColumn(); ImGui.Text("Oh dear") + ImGui.TableNextColumn(); ImGui.Text("Oh dear") + ImGui.TableNextColumn(); ImGui.Text("Oh dear") + end + ImGui.EndTable() + end + if ImGui.BeginTable("table2", 3, bit32.bor(sizing_policy_flags[table_n + 1], s.flags1)) then + for row = 0, 3 - 1 do + ImGui.TableNextRow() + ImGui.TableNextColumn(); ImGui.Text("AAAA") + ImGui.TableNextColumn(); ImGui.Text("BBBBBBBB") + ImGui.TableNextColumn(); ImGui.Text("CCCCCCCCCCCC") + end + ImGui.EndTable() + end ImGui.PopID() end - ImGui.EndTable() - end -end --- Demonstrate creating custom context menus inside columns, --- while playing it nice with context menus provided by TableHeadersRow()/TableHeader() -local function Tables_ContextMenus() - IMGUI_DEMO_MARKER("Tables/Context menus") - DemoHelpMarker( - "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n" .. - "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.") - local s = ST.ctxmenu - if s == nil then s = { flags1 = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Borders, TF.ContextMenuInBody) }; ST.ctxmenu = s end + ImGui.Spacing() + ImGui.TextUnformatted("Advanced") + ImGui.SameLine() + HelpMarker( + "This section allows you to interact and see the effect of various sizing policies " .. + "depending on whether Scroll is enabled and the contents of your columns.") - PushStyleCompact() - _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags1, TF.ContextMenuInBody) - PopStyleCompact() + local CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText = 0, 1, 2, 3, 4, 5 -- enum ContentsType - -- Context Menus: first example - -- [1.1] Right-click on the TableHeadersRow() line to open the default table context menu. - -- [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set) - local COLUMNS_COUNT = 3 - if ImGui.BeginTable("table_context_menu", COLUMNS_COUNT, s.flags1) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") - - -- [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu. - ImGui.TableHeadersRow() - - -- Submit dummy contents - for row = 0, 3 do - ImGui.TableNextRow() - for column = 0, COLUMNS_COUNT - 1 do - ImGui.TableSetColumnIndex(column) - ImGui.Text("Cell %d,%d", column, row) - end + PushStyleCompact() + ImGui.PushID("Advanced") + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) + s.flags = EditTableSizingFlags(s.flags) + s.contents_type = ImGui.Combo("Contents", s.contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0") + if s.contents_type == CT_FillButton then + ImGui.SameLine() + HelpMarker( + "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop " .. + "where contents width can feed into auto-column width can feed into contents width.") end - ImGui.EndTable() + s.column_count = ImGui.DragInt("Columns", s.column_count, 0.1, 1, 64, "%d", ImGuiSliderFlags.AlwaysClamp) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, ImGuiTableFlags.Resizable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, ImGuiTableFlags.PreciseWidths) + ImGui.SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, ImGuiTableFlags.ScrollX) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, ImGuiTableFlags.ScrollY) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, ImGuiTableFlags.NoClip) + ImGui.PopItemWidth() + ImGui.PopID() + PopStyleCompact() + + if ImGui.BeginTable("table2", s.column_count, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 7)) then + for cell = 0, 10 * s.column_count - 1 do + ImGui.TableNextColumn() + local column = ImGui.TableGetColumnIndex() + local row = ImGui.TableGetRowIndex() + + ImGui.PushID(cell) + local label = string.format("Hello %d,%d", column, row) + local contents_type = s.contents_type + if contents_type == CT_ShortText then ImGui.TextUnformatted(label) + elseif contents_type == CT_LongText then ImGui.Text("Some %s text %d,%d\nOver two lines..", (column == 0) and "long" or "longeeer", column, row) + elseif contents_type == CT_ShowWidth then ImGui.Text("W: %.1f", ImGui.GetContentRegionAvail().x) + elseif contents_type == CT_Button then ImGui.Button(label) + elseif contents_type == CT_FillButton then ImGui.Button(label, ImVec2(-FLT_MIN, 0.0)) + elseif contents_type == CT_InputText then ImGui.SetNextItemWidth(-FLT_MIN); ImGui.InputText("##", s.text_buf, 32) + end + ImGui.PopID() + end + ImGui.EndTable() + end + ImGui.TreePop() end - -- Context Menus: second example - -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. - -- [2.2] Right-click on the ".." to open a custom popup - -- [2.3] Right-click in columns to open another custom popup - DemoHelpMarker( - "Demonstrate mixing table context menu (over header), item context button (over button) " .. - "and custom per-column context menu (over column body).") - local flags2 = bor(TF.Resizable, TF.SizingFixedFit, TF.Reorderable, TF.Hideable, TF.Borders) - if ImGui.BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Vertical scrolling, with clipping") then + IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping") + HelpMarker( + "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n" .. + "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.") + local s = s.VerticalScrolling - -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. - ImGui.TableHeadersRow() - for row = 0, 3 do + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, ImGuiTableFlags.ScrollY) + PopStyleCompact() + + -- When using ScrollX or ScrollY we need to specify a size for our table container! + -- Otherwise by default the table will fit all available space, like a BeginChild() call. + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) + if ImGui.BeginTable("table_scrolly", 3, s.flags, outer_size) then + ImGui.TableSetupScrollFreeze(0, 1) -- Make top row always visible + ImGui.TableSetupColumn("One", ImGuiTableColumnFlags.None) + ImGui.TableSetupColumn("Two", ImGuiTableColumnFlags.None) + ImGui.TableSetupColumn("Three", ImGuiTableColumnFlags.None) + ImGui.TableHeadersRow() + + -- Demonstrate using clipper for large vertical lists + local clipper = ImGuiListClipper() + clipper:Begin(1000) + while clipper:Step() do + for row = clipper.DisplayStart, clipper.DisplayEnd - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Hello %d,%d", column, row) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Horizontal scrolling") then + IMGUI_DEMO_MARKER("Tables/Horizontal scrolling") + HelpMarker( + "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, " .. + "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" .. + "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, " .. + "because the container window won't automatically extend vertically to fix contents " .. + "(this may be improved in future versions).") + local s = s.HorizontalScrolling + + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, ImGuiTableFlags.Resizable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, ImGuiTableFlags.ScrollX) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, ImGuiTableFlags.ScrollY) + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, ImGuiSliderFlags.NoInput) + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, ImGuiSliderFlags.NoInput) + PopStyleCompact() + + -- When using ScrollX or ScrollY we need to specify a size for our table container! + -- Otherwise by default the table will fit all available space, like a BeginChild() call. + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 8) + if ImGui.BeginTable("table_scrollx", 7, s.flags, outer_size) then + ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) + ImGui.TableSetupColumn("Line #", ImGuiTableColumnFlags.NoHide) -- Make the first column not hideable to match our use of TableSetupScrollFreeze() + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableSetupColumn("Four") + ImGui.TableSetupColumn("Five") + ImGui.TableSetupColumn("Six") + ImGui.TableHeadersRow() + for row = 0, 20 - 1 do + ImGui.TableNextRow() + for column = 0, 7 - 1 do repeat + -- Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement. + -- Because here we know that: + -- - A) all our columns are contributing the same to row height + -- - B) column 0 is always visible, + -- We only always submit this one column and can skip others. + -- More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags(). + if not ImGui.TableSetColumnIndex(column) and column > 0 then + break -- continue + end + if column == 0 then + ImGui.Text("Line %d", row) + else + ImGui.Text("Hello world %d,%d", column, row) + end + until true end + end + ImGui.EndTable() + end + + ImGui.Spacing() + ImGui.TextUnformatted("Stretch + ScrollX") + ImGui.SameLine() + HelpMarker( + "Showcase using Stretch columns + ScrollX together: " .. + "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n" .. + "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns " .. + "along with ScrollX doesn't make sense.") + PushStyleCompact() + ImGui.PushID("flags3") + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 30) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags2, ImGuiTableFlags.ScrollX) + s.inner_width = ImGui.DragFloat("inner_width", s.inner_width, 1.0, 0.0, FLT_MAX, "%.1f") + ImGui.PopItemWidth() + ImGui.PopID() + PopStyleCompact() + if ImGui.BeginTable("table2", 7, s.flags2, outer_size, s.inner_width) then + for cell = 0, 20 * 7 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Hello world %d,%d", ImGui.TableGetColumnIndex(), ImGui.TableGetRowIndex()) + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Columns flags") then + IMGUI_DEMO_MARKER("Tables/Columns flags") + -- Create a first table just to show all the options/flags we want to make visible in our example! + local column_count = 3 + local column_names = { "One", "Two", "Three" } -- 1-based + local column_flags = s.ColumnsFlags.column_flags -- 1-based + local column_flags_out = s.ColumnsFlags.column_flags_out -- Output from TableGetColumnFlags() + + if ImGui.BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags.None) then + PushStyleCompact() + for column = 0, column_count - 1 do + ImGui.TableNextColumn() + ImGui.PushID(column) + ImGui.AlignTextToFramePadding() -- FIXME-TABLE: Workaround for wrong text baseline propagation across columns + ImGui.Text("'%s'", column_names[column + 1]) + ImGui.Spacing() + ImGui.Text("Input flags:") + column_flags[column + 1] = EditTableColumnsFlags(column_flags[column + 1]) + ImGui.Spacing() + ImGui.Text("Output flags:") + ImGui.BeginDisabled() + ShowTableColumnsStatusFlags(column_flags_out[column + 1]) + ImGui.EndDisabled() + ImGui.PopID() + end + PopStyleCompact() + ImGui.EndTable() + end + + -- Create the real table we care about for the example! + -- We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, + -- otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + -- + resizing the parent window down). + local flags + = bit32.bor(ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.ScrollX, ImGuiTableFlags.ScrollY + , ImGuiTableFlags.RowBg, ImGuiTableFlags.BordersOuter, ImGuiTableFlags.BordersV + , ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Sortable) + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 9) + if ImGui.BeginTable("table_columns_flags", column_count, flags, outer_size) then + local has_angled_header = false + for column = 0, column_count - 1 do + has_angled_header = has_angled_header or (bit32.band(column_flags[column + 1], ImGuiTableColumnFlags.AngledHeader) ~= 0) + ImGui.TableSetupColumn(column_names[column + 1], column_flags[column + 1]) + end + if has_angled_header then + ImGui.TableAngledHeadersRow() + end + ImGui.TableHeadersRow() + for column = 0, column_count - 1 do + column_flags_out[column + 1] = ImGui.TableGetColumnFlags(column) + end + local indent_step = math.floor(math.floor(TEXT_BASE_WIDTH) / 2) + for row = 0, 8 - 1 do + -- Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags. + ImGui.Indent(indent_step) + ImGui.TableNextRow() + for column = 0, column_count - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%s %s", (column == 0) and "Indented" or "Hello", ImGui.TableGetColumnName(column)) + end + end + ImGui.Unindent(indent_step * 8.0) + + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Columns widths") then + IMGUI_DEMO_MARKER("Tables/Columns widths") + HelpMarker("Using TableSetupColumn() to setup default width.") + + local s = s.ColumnsWidths + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags1, ImGuiTableFlags.Resizable) + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags1, ImGuiTableFlags.NoBordersInBodyUntilResize) + PopStyleCompact() + if ImGui.BeginTable("table1", 3, s.flags1) then + -- We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. + ImGui.TableSetupColumn("one", ImGuiTableColumnFlags.WidthFixed, 100.0) -- Default to 100.0f + ImGui.TableSetupColumn("two", ImGuiTableColumnFlags.WidthFixed, 200.0) -- Default to 200.0f + ImGui.TableSetupColumn("three", ImGuiTableColumnFlags.WidthFixed) -- Default to auto + ImGui.TableHeadersRow() + for row = 0, 4 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableSetColumnIndex(column) + if row == 0 then + ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) + else + ImGui.Text("Hello %d,%d", column, row) + end + end + end + ImGui.EndTable() + end + + HelpMarker( + "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, " .. + "fixed columns with set width may still be shrunk down if there's not enough space in the host.") + + PushStyleCompact() + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags2, ImGuiTableFlags.NoKeepColumnsVisible) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags2, ImGuiTableFlags.BordersInnerV) + _, s.flags2 = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags2, ImGuiTableFlags.BordersOuterV) + PopStyleCompact() + if ImGui.BeginTable("table2", 4, s.flags2) then + -- We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns + -- will default to ImGuiTableColumnFlags_WidthFixed. + ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 100.0) + ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, TEXT_BASE_WIDTH * 15.0) + ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, TEXT_BASE_WIDTH * 30.0) + ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, TEXT_BASE_WIDTH * 15.0) + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 4 - 1 do + ImGui.TableSetColumnIndex(column) + if row == 0 then + ImGui.Text("(w: %5.1f)", ImGui.GetContentRegionAvail().x) + else + ImGui.Text("Hello %d,%d", column, row) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Nested tables") then + IMGUI_DEMO_MARKER("Tables/Nested tables") + HelpMarker("This demonstrates embedding a table into another table cell.") + + if ImGui.BeginTable("table_nested1", 2, bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable)) then + ImGui.TableSetupColumn("A0") + ImGui.TableSetupColumn("A1") + ImGui.TableHeadersRow() + + ImGui.TableNextColumn() + ImGui.Text("A0 Row 0") + do + local rows_height = (TEXT_BASE_HEIGHT * 2.0) + (ImGui.GetStyle().CellPadding.y * 2.0) + if ImGui.BeginTable("table_nested2", 2, bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.Resizable, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable)) then + ImGui.TableSetupColumn("B0") + ImGui.TableSetupColumn("B1") + ImGui.TableHeadersRow() + + ImGui.TableNextRow(ImGuiTableRowFlags.None, rows_height) + ImGui.TableNextColumn() + ImGui.Text("B0 Row 0") + ImGui.TableNextColumn() + ImGui.Text("B1 Row 0") + ImGui.TableNextRow(ImGuiTableRowFlags.None, rows_height) + ImGui.TableNextColumn() + ImGui.Text("B0 Row 1") + ImGui.TableNextColumn() + ImGui.Text("B1 Row 1") + + ImGui.EndTable() + end + end + ImGui.TableNextColumn(); ImGui.Text("A1 Row 0") + ImGui.TableNextColumn(); ImGui.Text("A0 Row 1") + ImGui.TableNextColumn(); ImGui.Text("A1 Row 1") + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Row height") then + IMGUI_DEMO_MARKER("Tables/Row height") + HelpMarker( + "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, " .. + "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n" .. + "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.") + if ImGui.BeginTable("table_row_height", 1, ImGuiTableFlags.Borders) then + for row = 0, 8 - 1 do + local min_row_height = math.floor(TEXT_BASE_HEIGHT * 0.30 * row + ImGui.GetStyle().CellPadding.y * 2.0) + ImGui.TableNextRow(ImGuiTableRowFlags.None, min_row_height) + ImGui.TableNextColumn() + ImGui.Text("min_row_height = %.2f", min_row_height) + end + ImGui.EndTable() + end + + HelpMarker( + "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n" .. + "Please note that Tables Row Height is not the same thing as Current Line Height, " .. + "as a table cell may contains multiple lines.") + if ImGui.BeginTable("table_share_lineheight", 2, ImGuiTableFlags.Borders) then ImGui.TableNextRow() - for column = 0, COLUMNS_COUNT - 1 do - -- Submit dummy contents - ImGui.TableSetColumnIndex(column) - ImGui.Text("Cell %d,%d", column, row) - ImGui.SameLine() + ImGui.TableNextColumn() + ImGui.ColorButton("##1", ImVec4(0.13, 0.26, 0.40, 1.0), ImGuiColorEditFlags.None, ImVec2(40, 40)) + ImGui.TableNextColumn() + ImGui.Text("Line 1") + ImGui.Text("Line 2") - -- [2.2] Right-click on the ".." to open a custom popup - ImGui.PushID(row * COLUMNS_COUNT + column) - ImGui.SmallButton("..") - if ImGui.BeginPopupContextItem() then - ImGui.Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row) + ImGui.TableNextRow() + ImGui.TableNextColumn() + ImGui.ColorButton("##2", ImVec4(0.13, 0.26, 0.40, 1.0), ImGuiColorEditFlags.None, ImVec2(40, 40)) + ImGui.TableNextColumn() + ImGui.SameLine(0.0, 0.0) -- Reuse line height from previous column + ImGui.Text("Line 1, with SameLine(0,0)") + ImGui.Text("Line 2") + + ImGui.EndTable() + end + + HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.") + if ImGui.BeginTable("table_changing_cellpadding_y", 1, ImGuiTableFlags.Borders) then + local style = ImGui.GetStyle() + for row = 0, 8 - 1 do + if (row % 3) == 2 then + ImGui.PushStyleVarY(ImGuiStyleVar.CellPadding, 20.0) + end + ImGui.TableNextRow(ImGuiTableRowFlags.None) + ImGui.TableNextColumn() + ImGui.Text("CellPadding.y = %.2f", style.CellPadding.y) + if (row % 3) == 2 then + ImGui.PopStyleVar() + end + end + ImGui.EndTable() + end + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Outer size") then + IMGUI_DEMO_MARKER("Tables/Outer size") + -- Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY + -- Important to that note how the two flags have slightly different behaviors! + ImGui.Text("Using NoHostExtendX and NoHostExtendY:") + PushStyleCompact() + local s = s.OuterSize + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, ImGuiTableFlags.NoHostExtendX) + ImGui.SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, ImGuiTableFlags.NoHostExtendY) + ImGui.SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") + PopStyleCompact() + + local outer_size = ImVec2(0.0, TEXT_BASE_HEIGHT * 5.5) + if ImGui.BeginTable("table1", 3, s.flags, outer_size) then + for row = 0, 10 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + ImGui.SameLine() + ImGui.Text("Hello!") + + ImGui.Spacing() + + ImGui.Text("Using explicit size:") + if ImGui.BeginTable("table2", 3, bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + ImGui.SameLine() + if ImGui.BeginTable("table3", 3, bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.RowBg), ImVec2(TEXT_BASE_WIDTH * 30, 0.0)) then + local rows_height = TEXT_BASE_HEIGHT * 1.5 + ImGui.GetStyle().CellPadding.y * 2.0 + for row = 0, 3 - 1 do + ImGui.TableNextRow(0, rows_height) + for column = 0, 3 - 1 do + ImGui.TableNextColumn() + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Background color") then + IMGUI_DEMO_MARKER("Tables/Background color") + local s = s.BackgroundColor + + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Borders", s.flags, ImGuiTableFlags.Borders) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, ImGuiTableFlags.RowBg) + ImGui.SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.") + s.row_bg_type = ImGui.Combo("row bg type", s.row_bg_type, "None\0Red\0Gradient\0") + s.row_bg_target = ImGui.Combo("row bg target", s.row_bg_target, "RowBg0\0RowBg1\0"); ImGui.SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.") + s.cell_bg_type = ImGui.Combo("cell bg type", s.cell_bg_type, "None\0Blue\0"); ImGui.SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.") + IM_ASSERT(s.row_bg_type >= 0 and s.row_bg_type <= 2) + IM_ASSERT(s.row_bg_target >= 0 and s.row_bg_target <= 1) + IM_ASSERT(s.cell_bg_type >= 0 and s.cell_bg_type <= 1) + PopStyleCompact() + + if ImGui.BeginTable("table1", 5, s.flags) then + for row = 0, 6 - 1 do + ImGui.TableNextRow() + + -- Demonstrate setting a row background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBgX, ...)' + -- We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag. + if s.row_bg_type ~= 0 then + local row_bg_color = ImGui.GetColorU32((s.row_bg_type == 1) and ImVec4(0.7, 0.3, 0.3, 0.65) or ImVec4(0.2 + row * 0.1, 0.2, 0.2, 0.65)) -- Flat or Gradient? + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0 + s.row_bg_target, row_bg_color) + end + + -- Fill cells + for column = 0, 5 - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("%c%c", string.byte("A") + row, string.byte("0") + column) + + -- Change background of Cells B1->C2 + -- Demonstrate setting a cell background color with 'ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ...)' + -- (the CellBg color will be blended over the RowBg and ColumnBg colors) + -- We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop. + if row >= 1 and row <= 2 and column >= 1 and column <= 2 and s.cell_bg_type == 1 then + local cell_bg_color = ImGui.GetColorU32(ImVec4(0.3, 0.3, 0.7, 0.65)) + ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, cell_bg_color) + end + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Tree view") then + IMGUI_DEMO_MARKER("Tables/Tree view") + local s = s.TreeView + + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", s.tree_node_flags_base, ImGuiTreeNodeFlags.SpanFullWidth) + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", s.tree_node_flags_base, ImGuiTreeNodeFlags.SpanLabelWidth) + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", s.tree_node_flags_base, ImGuiTreeNodeFlags.SpanAllColumns) + _, s.tree_node_flags_base = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", s.tree_node_flags_base, ImGuiTreeNodeFlags.LabelSpanAllColumns) + ImGui.SameLine(); HelpMarker("Useful if you know that you aren't displaying contents in other columns") + + HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.") + if ImGui.BeginTable("3ways", 3, s.table_flags) then + -- The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On + ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.NoHide) + ImGui.TableSetupColumn("Size", ImGuiTableColumnFlags.WidthFixed, TEXT_BASE_WIDTH * 12.0) + ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthFixed, TEXT_BASE_WIDTH * 18.0) + ImGui.TableHeadersRow() + + -- Simple storage to output a dummy file-system. + -- struct MyTreeNode { Name, Type, Size, ChildIdx, ChildCount } (see s.nodes) + local MyTreeNode = s.MyTreeNode + if MyTreeNode == nil then -- [Port] local struct with a static method, created once and kept in statics + MyTreeNode = {} + function MyTreeNode.DisplayNode(node, all_nodes) + ImGui.TableNextRow() + ImGui.TableNextColumn() + local is_folder = (node.ChildCount > 0) + + local node_flags = s.tree_node_flags_base + if node ~= all_nodes[1] then + node_flags = bit32.band(node_flags, bit32.bnot(ImGuiTreeNodeFlags.LabelSpanAllColumns)) -- Only demonstrate this on the root node. + end + + if is_folder then + local open = ImGui.TreeNodeEx(node.Name, node_flags) + if bit32.band(node_flags, ImGuiTreeNodeFlags.LabelSpanAllColumns) == 0 then + ImGui.TableNextColumn() + ImGui.TextDisabled("--") + ImGui.TableNextColumn() + ImGui.TextUnformatted(node.Type) + end + if open then + for child_n = 0, node.ChildCount - 1 do + MyTreeNode.DisplayNode(all_nodes[node.ChildIdx + child_n + 1], all_nodes) + end + ImGui.TreePop() + end + else + ImGui.TreeNodeEx(node.Name, bit32.bor(node_flags, ImGuiTreeNodeFlags.Leaf, ImGuiTreeNodeFlags.Bullet, ImGuiTreeNodeFlags.NoTreePushOnOpen)) + ImGui.TableNextColumn() + ImGui.Text("%d", node.Size) + ImGui.TableNextColumn() + ImGui.TextUnformatted(node.Type) + end + end + s.MyTreeNode = MyTreeNode + end + local nodes = s.nodes + + MyTreeNode.DisplayNode(nodes[1], nodes) + + ImGui.EndTable() + end + ImGui.TreePop() + end + + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Item width") then + IMGUI_DEMO_MARKER("Tables/Item width") + HelpMarker( + "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n" .. + "Note that on auto-resizing non-resizable fixed columns, querying the content width for " .. + "e.g. right-alignment doesn't make sense.") + if ImGui.BeginTable("table_item_width", 3, ImGuiTableFlags.Borders) then + ImGui.TableSetupColumn("small") + ImGui.TableSetupColumn("half") + ImGui.TableSetupColumn("right-align") + ImGui.TableHeadersRow() + + for row = 0, 3 - 1 do + ImGui.TableNextRow() + if row == 0 then + -- Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient) + ImGui.TableSetColumnIndex(0) + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 3.0) -- Small + ImGui.TableSetColumnIndex(1) + ImGui.PushItemWidth(-ImGui.GetContentRegionAvail().x * 0.5) + ImGui.TableSetColumnIndex(2) + ImGui.PushItemWidth(-FLT_MIN) -- Right-aligned + end + + -- Draw our contents + local s = s.ItemWidth + ImGui.PushID(row) + ImGui.TableSetColumnIndex(0) + s.dummy_f = ImGui.SliderFloat("float0", s.dummy_f, 0.0, 1.0) + ImGui.TableSetColumnIndex(1) + s.dummy_f = ImGui.SliderFloat("float1", s.dummy_f, 0.0, 1.0) + ImGui.TableSetColumnIndex(2) + s.dummy_f = ImGui.SliderFloat("##float2", s.dummy_f, 0.0, 1.0) -- No visible label since right-aligned + ImGui.PopID() + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + -- Demonstrate using TableHeader() calls instead of TableHeadersRow() + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Custom headers") then + IMGUI_DEMO_MARKER("Tables/Custom headers") + local COLUMNS_COUNT = 3 + if ImGui.BeginTable("table_custom_headers", COLUMNS_COUNT, bit32.bor(ImGuiTableFlags.Borders, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable)) then + ImGui.TableSetupColumn("Apricot") + ImGui.TableSetupColumn("Banana") + ImGui.TableSetupColumn("Cherry") + + -- Dummy entire-column selection storage + -- FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. + local column_selected = s.CustomHeaders.column_selected -- 1-based + + -- Instead of calling TableHeadersRow() we'll submit custom headers ourselves. + -- (A different approach is also possible: + -- - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call. + -- - Call TableHeadersRow() normally. This will submit TableHeader() with no name. + -- - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().) + ImGui.TableNextRow(ImGuiTableRowFlags.Headers) + for column = 0, COLUMNS_COUNT - 1 do + ImGui.TableSetColumnIndex(column) + local column_name = ImGui.TableGetColumnName(column) -- Retrieve name passed to TableSetupColumn() + ImGui.PushID(column) + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(0, 0)) + _, column_selected[column + 1] = ImGui.Checkbox("##checkall", column_selected[column + 1]) + ImGui.PopStyleVar() + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + ImGui.TableHeader(column_name) + ImGui.PopID() + end + + -- Submit table contents + for row = 0, 5 - 1 do + ImGui.TableNextRow() + for column = 0, 3 - 1 do + local buf = string.format("Cell %d,%d", column, row) + ImGui.TableSetColumnIndex(column) + ImGui.Selectable(buf, column_selected[column + 1]) + end + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + -- Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Angled headers") then + IMGUI_DEMO_MARKER("Tables/Angled headers") + local column_names = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" } -- 1-based + local columns_count = #column_names + local rows_count = 12 + + local s = s.AngledHeaders + -- static bool bools[columns_count * rows_count] = {} -- Dummy storage selection storage + local bools = s.bools -- 1-based + if #bools == 0 then + for n = 1, columns_count * rows_count do bools[n] = false end + end + _, s.table_flags = ImGui.CheckboxFlags("_ScrollX", s.table_flags, ImGuiTableFlags.ScrollX) + _, s.table_flags = ImGui.CheckboxFlags("_ScrollY", s.table_flags, ImGuiTableFlags.ScrollY) + _, s.table_flags = ImGui.CheckboxFlags("_Resizable", s.table_flags, ImGuiTableFlags.Resizable) + _, s.table_flags = ImGui.CheckboxFlags("_Sortable", s.table_flags, ImGuiTableFlags.Sortable) + _, s.table_flags = ImGui.CheckboxFlags("_NoBordersInBody", s.table_flags, ImGuiTableFlags.NoBordersInBody) + _, s.table_flags = ImGui.CheckboxFlags("_HighlightHoveredColumn", s.table_flags, ImGuiTableFlags.HighlightHoveredColumn) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.frozen_cols = ImGui.SliderInt("Frozen columns", s.frozen_cols, 0, 2) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + s.frozen_rows = ImGui.SliderInt("Frozen rows", s.frozen_rows, 0, 2) + _, s.column_flags = ImGui.CheckboxFlags("Disable header contributing to column width", s.column_flags, ImGuiTableColumnFlags.NoHeaderWidth) + + if ImGui.TreeNode("Style settings") then + ImGui.SameLine() + HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.") + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + ImGui.GetStyle().TableAngledHeadersAngle = ImGui.SliderAngle("style.TableAngledHeadersAngle", ImGui.GetStyle().TableAngledHeadersAngle, -50.0, 50.0) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) + ImGui.SliderFloat2("style.TableAngledHeadersTextAlign", ImGui.GetStyle().TableAngledHeadersTextAlign, 0.0, 1.0, "%.2f") + ImGui.TreePop() + end + + if ImGui.BeginTable("table_angled_headers", columns_count, s.table_flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 12)) then + ImGui.TableSetupColumn(column_names[1], bit32.bor(ImGuiTableColumnFlags.NoHide, ImGuiTableColumnFlags.NoReorder)) + for n = 1, columns_count - 1 do + ImGui.TableSetupColumn(column_names[n + 1], s.column_flags) + end + ImGui.TableSetupScrollFreeze(s.frozen_cols, s.frozen_rows) + + ImGui.TableAngledHeadersRow() -- Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag. + ImGui.TableHeadersRow() -- Draw remaining headers and allow access to context-menu and other functions. + for row = 0, rows_count - 1 do + ImGui.PushID(row) + ImGui.TableNextRow() + ImGui.TableSetColumnIndex(0) + ImGui.AlignTextToFramePadding() + ImGui.Text("Track %d", row) + for column = 1, columns_count - 1 do + if ImGui.TableSetColumnIndex(column) then + ImGui.PushID(column) + _, bools[row * columns_count + column + 1] = ImGui.Checkbox("", bools[row * columns_count + column + 1]) + ImGui.PopID() + end + end + ImGui.PopID() + end + ImGui.EndTable() + end + ImGui.TreePop() + end + + -- Demonstrate creating custom context menus inside columns, + -- while playing it nice with context menus provided by TableHeadersRow()/TableHeader() + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Context menus") then + IMGUI_DEMO_MARKER("Tables/Context menus") + HelpMarker( + "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n" .. + "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.") + local s = s.ContextMenus + + PushStyleCompact() + _, s.flags1 = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags1, ImGuiTableFlags.ContextMenuInBody) + PopStyleCompact() + + -- Context Menus: first example + -- [1.1] Right-click on the TableHeadersRow() line to open the default table context menu. + -- [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set) + local COLUMNS_COUNT = 3 + if ImGui.BeginTable("table_context_menu", COLUMNS_COUNT, s.flags1) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + + -- [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu. + ImGui.TableHeadersRow() + + -- Submit dummy contents + for row = 0, 4 - 1 do + ImGui.TableNextRow() + for column = 0, COLUMNS_COUNT - 1 do + ImGui.TableSetColumnIndex(column) + ImGui.Text("Cell %d,%d", column, row) + end + end + ImGui.EndTable() + end + + -- Context Menus: second example + -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. + -- [2.2] Right-click on the ".." to open a custom popup + -- [2.3] Right-click in columns to open another custom popup + HelpMarker( + "Demonstrate mixing table context menu (over header), item context button (over button) " .. + "and custom per-column context menu (over column body).") + local flags2 = bit32.bor(ImGuiTableFlags.Resizable, ImGuiTableFlags.SizingFixedFit, ImGuiTableFlags.Reorderable, ImGuiTableFlags.Hideable, ImGuiTableFlags.Borders) + if ImGui.BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + + -- [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. + ImGui.TableHeadersRow() + for row = 0, 4 - 1 do + ImGui.TableNextRow() + for column = 0, COLUMNS_COUNT - 1 do + -- Submit dummy contents + ImGui.TableSetColumnIndex(column) + ImGui.Text("Cell %d,%d", column, row) + ImGui.SameLine() + + -- [2.2] Right-click on the ".." to open a custom popup + ImGui.PushID(row * COLUMNS_COUNT + column) + ImGui.SmallButton("..") + if ImGui.BeginPopupContextItem() then + ImGui.Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row) + if ImGui.Button("Close") then + ImGui.CloseCurrentPopup() + end + ImGui.EndPopup() + end + ImGui.PopID() + end + end + + -- [2.3] Right-click anywhere in columns to open another custom popup + -- (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup + -- to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping) + local hovered_column = -1 + for column = 0, COLUMNS_COUNT + 1 - 1 do + ImGui.PushID(column) + if bit32.band(ImGui.TableGetColumnFlags(column), ImGuiTableColumnFlags.IsHovered) ~= 0 then + hovered_column = column + end + if hovered_column == column and not ImGui.IsAnyItemHovered() and ImGui.IsMouseReleased(1) then + ImGui.OpenPopup("MyPopup") + end + if ImGui.BeginPopup("MyPopup") then + if column == COLUMNS_COUNT then + ImGui.Text("This is a custom popup for unused space after the last column.") + else + ImGui.Text("This is a custom popup for Column %d", column) + end if ImGui.Button("Close") then ImGui.CloseCurrentPopup() end @@ -3652,442 +6556,434 @@ local function Tables_ContextMenus() end ImGui.PopID() end - end - -- [2.3] Right-click anywhere in columns to open another custom popup - -- (instead of testing for not IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup - -- to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping) - local hovered_column = -1 - for column = 0, COLUMNS_COUNT do - ImGui.PushID(column) - if Has(ImGui.TableGetColumnFlags(column), ImGuiTableColumnFlags.IsHovered) then - hovered_column = column - end - if hovered_column == column and not ImGui.IsAnyItemHovered() and ImGui.IsMouseReleased(1) then - ImGui.OpenPopup("MyPopup") - end - if ImGui.BeginPopup("MyPopup") then - if column == COLUMNS_COUNT then - ImGui.Text("This is a custom popup for unused space after the last column.") - else - ImGui.Text("This is a custom popup for Column %d", column) - end - if ImGui.Button("Close") then - ImGui.CloseCurrentPopup() - end - ImGui.EndPopup() - end - ImGui.PopID() + ImGui.EndTable() + ImGui.Text("Hovered column: %d", hovered_column) end - - ImGui.EndTable() - ImGui.Text("Hovered column: %d", hovered_column) + ImGui.TreePop() end -end --- Demonstrate creating multiple tables with the same ID -local function Tables_SyncedInstances() - IMGUI_DEMO_MARKER("Tables/Synced instances") - DemoHelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.") + -- Demonstrate creating multiple tables with the same ID + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Synced instances") then + IMGUI_DEMO_MARKER("Tables/Synced instances") + HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.") - local s = ST.synced - if s == nil then s = { flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Borders, TF.SizingFixedFit, TF.NoSavedSettings) }; ST.synced = s end - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SizingFixedFit", s.flags, TF.SizingFixedFit) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, TF.HighlightHoveredColumn) - for n = 0, 2 do - local buf = string.format("Synced Table %d", n) - local open = ImGui.CollapsingHeader(buf, ImGuiTreeNodeFlags.DefaultOpen) - if open and ImGui.BeginTable("Table", 3, s.flags, ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 5)) then - ImGui.TableSetupColumn("One") - ImGui.TableSetupColumn("Two") - ImGui.TableSetupColumn("Three") + local s = s.SyncedInstances + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, ImGuiTableFlags.Resizable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, ImGuiTableFlags.ScrollY) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SizingFixedFit", s.flags, ImGuiTableFlags.SizingFixedFit) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, ImGuiTableFlags.HighlightHoveredColumn) + for n = 0, 3 - 1 do + local buf = string.format("Synced Table %d", n) + local open = ImGui.CollapsingHeader(buf, ImGuiTreeNodeFlags.DefaultOpen) + if open and ImGui.BeginTable("Table", 3, s.flags, ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 5)) then + ImGui.TableSetupColumn("One") + ImGui.TableSetupColumn("Two") + ImGui.TableSetupColumn("Three") + ImGui.TableHeadersRow() + local cell_count = (n == 1) and 27 or 9 -- Make second table have a scrollbar to verify that additional decoration is not affecting column positions. + for cell = 0, cell_count - 1 do + ImGui.TableNextColumn() + ImGui.Text("this cell %d", cell) + end + ImGui.EndTable() + end + end + ImGui.TreePop() + end + + -- Demonstrate using Sorting facilities + -- This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting. + -- Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified) + local template_items_names = s.template_items_names -- 1-based + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) + end + if ImGui.TreeNode("Sorting") then + IMGUI_DEMO_MARKER("Tables/Sorting") + local s = s.Sorting + -- Create item list + local items = s.items + if items.Size == 0 then + items:resize(50) + for n = 0, items.Size - 1 do + local template_n = n % #template_items_names + local item = MyItem(); items.Data[n + 1] = item -- [Port] resize(50, MyItem()) would share one table + item.ID = n + item.Name = template_items_names[template_n + 1] + item.Quantity = (n * n - n) % 20 -- Assign default quantities + end + end + + -- Options + PushStyleCompact() + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, ImGuiTableFlags.SortMulti) + ImGui.SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, ImGuiTableFlags.SortTristate) + ImGui.SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") + PopStyleCompact() + + if ImGui.BeginTable("table_sorting", 4, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 15), 0.0) then + -- Declare columns + -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. + -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! + -- Demonstrate using a mixture of flags among available sort-related flags: + -- - ImGuiTableColumnFlags_DefaultSort + -- - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending + -- - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending + ImGui.TableSetupColumn("ID", bit32.bor(ImGuiTableColumnFlags.DefaultSort, ImGuiTableColumnFlags.WidthFixed), 0.0, MyItemColumnID_ID) + ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthFixed, 0.0, MyItemColumnID_Name) + ImGui.TableSetupColumn("Action", bit32.bor(ImGuiTableColumnFlags.NoSort, ImGuiTableColumnFlags.WidthFixed), 0.0, MyItemColumnID_Action) + ImGui.TableSetupColumn("Quantity", bit32.bor(ImGuiTableColumnFlags.PreferSortDescending, ImGuiTableColumnFlags.WidthStretch), 0.0, MyItemColumnID_Quantity) + ImGui.TableSetupScrollFreeze(0, 1) -- Make row always visible ImGui.TableHeadersRow() - local cell_count = (n == 1) and 27 or 9 -- Make second table have a scrollbar to verify that additional decoration is not affecting column positions. - for cell = 0, cell_count - 1 do - ImGui.TableNextColumn() - ImGui.Text("this cell %d", cell) + + -- Sort our data if sort specs have been changed! + local sort_specs = ImGui.TableGetSortSpecs() + if sort_specs then + if sort_specs.SpecsDirty then + MyItem_SortWithSortSpecs(sort_specs, items.Data, items.Size) + sort_specs.SpecsDirty = false + end + end + + -- Demonstrate using clipper for large vertical lists + local clipper = ImGuiListClipper() + clipper:Begin(items.Size) + while clipper:Step() do + for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do + -- Display a data item + local item = items.Data[row_n + 1] + ImGui.PushID(item.ID) + ImGui.TableNextRow() + ImGui.TableNextColumn() + ImGui.Text("%04d", item.ID) + ImGui.TableNextColumn() + ImGui.TextUnformatted(item.Name) + ImGui.TableNextColumn() + ImGui.SmallButton("None") + ImGui.TableNextColumn() + ImGui.Text("%d", item.Quantity) + ImGui.PopID() + end end ImGui.EndTable() end + ImGui.TreePop() end -end --- Demonstrate using Sorting facilities --- This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting. --- Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified) -local template_items_names = { - "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango", - "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot" -} - -local function Tables_Sorting() - IMGUI_DEMO_MARKER("Tables/Sorting") - -- Create item list - local s = ST.sorting - if s == nil then - s = { items = {}, - flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Sortable, TF.SortMulti, TF.RowBg, TF.BordersOuter, TF.BordersV, TF.NoBordersInBody, TF.ScrollY) } - for n = 0, 49 do - local template_n = n % #template_items_names - s.items[n + 1] = MyItem(n, template_items_names[template_n + 1], (n * n - n) % 20) -- Assign default quantities - end - ST.sorting = s + -- In this example we'll expose most table flags and settings. + -- For specific flags and settings refer to the corresponding section for more detailed explanation. + -- This section is mostly useful to experiment with combining certain flags or settings with each others. + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) -- [DEBUG] + if open_action ~= -1 then + ImGui.SetNextItemOpen(open_action ~= 0) end - local items = s.items + if ImGui.TreeNode("Advanced") then + IMGUI_DEMO_MARKER("Tables/Advanced") + local s = s.Advanced - -- Options - PushStyleCompact() - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, TF.SortMulti) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, TF.SortTristate) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") - PopStyleCompact() + local CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow = 0, 1, 2, 3, 4, 5 -- enum ContentsType + local contents_type_names = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" } + if s.outer_size_value == nil then s.outer_size_value = ImVec2(0.0, TEXT_BASE_HEIGHT * 12) end + -- static float row_min_height = 0.0f -- Auto + -- static float inner_width_with_scroll = 0.0f -- Auto-extend + --static ImGuiTextFilter filter + --ImGui.SetNextItemOpen(true, ImGuiCond.Once) -- FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing + if ImGui.TreeNode("Options") then + -- Make the UI compact because there are so many fields + PushStyleCompact() + ImGui.PushItemWidth(TEXT_BASE_WIDTH * 28.0) - if ImGui.BeginTable("table_sorting", 4, s.flags, ImVec2(0.0, TEXT_BASE_HEIGHT * 15), 0.0) then - local CF = ImGuiTableColumnFlags - -- Declare columns - -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. - -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! - -- Demonstrate using a mixture of flags among available sort-related flags: - -- - ImGuiTableColumnFlags_DefaultSort - -- - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending - -- - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending - ImGui.TableSetupColumn("ID", bor(CF.DefaultSort, CF.WidthFixed), 0.0, MyItemColumnID_ID) - ImGui.TableSetupColumn("Name", CF.WidthFixed, 0.0, MyItemColumnID_Name) - ImGui.TableSetupColumn("Action", bor(CF.NoSort, CF.WidthFixed), 0.0, MyItemColumnID_Action) - ImGui.TableSetupColumn("Quantity", bor(CF.PreferSortDescending, CF.WidthStretch), 0.0, MyItemColumnID_Quantity) - ImGui.TableSetupScrollFreeze(0, 1) -- Make row always visible - ImGui.TableHeadersRow() + if ImGui.TreeNodeEx("Features:", ImGuiTreeNodeFlags.DefaultOpen) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, ImGuiTableFlags.Resizable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, ImGuiTableFlags.Reorderable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, ImGuiTableFlags.Hideable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Sortable", s.flags, ImGuiTableFlags.Sortable) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoSavedSettings", s.flags, ImGuiTableFlags.NoSavedSettings) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags, ImGuiTableFlags.ContextMenuInBody) + ImGui.TreePop() + end - -- Sort our data if sort specs have been changed! - local sort_specs = ImGui.TableGetSortSpecs() - if sort_specs and sort_specs.SpecsDirty then - MyItem_SortWithSortSpecs(sort_specs, items, #items) - sort_specs.SpecsDirty = false + if ImGui.TreeNodeEx("Decorations:", ImGuiTreeNodeFlags.DefaultOpen) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, ImGuiTableFlags.RowBg) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, ImGuiTableFlags.BordersV) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, ImGuiTableFlags.BordersOuterV) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, ImGuiTableFlags.BordersInnerV) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, ImGuiTableFlags.BordersH) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, ImGuiTableFlags.BordersOuterH) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, ImGuiTableFlags.BordersInnerH) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, ImGuiTableFlags.NoBordersInBody); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, ImGuiTableFlags.NoBordersInBodyUntilResize); ImGui.SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Sizing:", ImGuiTreeNodeFlags.DefaultOpen) then + s.flags = EditTableSizingFlags(s.flags) + ImGui.SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, ImGuiTableFlags.NoHostExtendX) + ImGui.SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, ImGuiTableFlags.NoHostExtendY) + ImGui.SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags, ImGuiTableFlags.NoKeepColumnsVisible) + ImGui.SameLine(); HelpMarker("Only available if ScrollX is disabled.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, ImGuiTableFlags.PreciseWidths) + ImGui.SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, ImGuiTableFlags.NoClip) + ImGui.SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Padding:", ImGuiTreeNodeFlags.DefaultOpen) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags, ImGuiTableFlags.PadOuterX) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags, ImGuiTableFlags.NoPadOuterX) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags, ImGuiTableFlags.NoPadInnerX) + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags.DefaultOpen) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, ImGuiTableFlags.ScrollX) + ImGui.SameLine() + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, ImGuiSliderFlags.NoInput) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, ImGuiTableFlags.ScrollY) + ImGui.SameLine() + ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) + s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, ImGuiSliderFlags.NoInput) + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Sorting:", ImGuiTreeNodeFlags.DefaultOpen) then + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, ImGuiTableFlags.SortMulti) + ImGui.SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, ImGuiTableFlags.SortTristate) + ImGui.SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Headers:", ImGuiTreeNodeFlags.DefaultOpen) then + _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) + _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, ImGuiTableFlags.HighlightHoveredColumn) + _, s.columns_base_flags = ImGui.CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", s.columns_base_flags, ImGuiTableColumnFlags.AngledHeader) + ImGui.SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).") + ImGui.TreePop() + end + + if ImGui.TreeNodeEx("Other:", ImGuiTreeNodeFlags.DefaultOpen) then + _, s.show_wrapped_text = ImGui.Checkbox("show_wrapped_text", s.show_wrapped_text) + + ImGui.DragFloat2("##OuterSize", s.outer_size_value) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + _, s.outer_size_enabled = ImGui.Checkbox("outer_size", s.outer_size_enabled) + ImGui.SameLine() + HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n" .. + "- The table is output directly in the parent window.\n" .. + "- OuterSize.x < 0.0f will right-align the table.\n" .. + "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n" .. + "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).") + + -- From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling. + -- To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled. + s.inner_width_with_scroll = ImGui.DragFloat("inner_width (when ScrollX active)", s.inner_width_with_scroll, 1.0, 0.0, FLT_MAX) + + s.row_min_height = ImGui.DragFloat("row_min_height", s.row_min_height, 1.0, 0.0, FLT_MAX) + ImGui.SameLine(); HelpMarker("Specify height of the Selectable item.") + + s.items_count = ImGui.DragInt("items_count", s.items_count, 0.1, 0, 9999) + s.contents_type = ImGui.Combo("items_type (first column)", s.contents_type, contents_type_names, #contents_type_names) + --filter.Draw("filter") + ImGui.TreePop() + end + + ImGui.PopItemWidth() + PopStyleCompact() + ImGui.Spacing() + ImGui.TreePop() end - -- Demonstrate using clipper for large vertical lists - local clipper = ImGuiListClipper() - clipper:Begin(#items) - while clipper:Step() do - for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do - -- Display a data item - local item = items[row_n + 1] - ImGui.PushID(item.ID) - ImGui.TableNextRow() - ImGui.TableNextColumn() - ImGui.Text("%04d", item.ID) - ImGui.TableNextColumn() - ImGui.TextUnformatted(item.Name) - ImGui.TableNextColumn() - ImGui.SmallButton("None") - ImGui.TableNextColumn() - ImGui.Text("%d", item.Quantity) - ImGui.PopID() + -- Update item list if we changed the number of items + local items = s.items + local selection = s.selection + if items.Size ~= s.items_count then + items:resize(s.items_count) + for n = 0, s.items_count - 1 do + local template_n = n % #template_items_names + local item = items.Data[n + 1] + if item == nil then item = MyItem(); items.Data[n + 1] = item end -- [Port] resize(n, MyItem()) would share one table + item.ID = n + item.Name = template_items_names[template_n + 1] + item.Quantity = (template_n == 3) and 10 or (template_n == 4) and 20 or 0 -- Assign default quantities end end - ImGui.EndTable() - end -end -local function Tables_AdvancedOptions(s) - -- Make the UI compact because there are so many fields - PushStyleCompact() - ImGui.PushItemWidth(TEXT_BASE_WIDTH * 28.0) + local parent_draw_list = ImGui.GetWindowDrawList() + local parent_draw_list_draw_cmd_count = parent_draw_list.CmdBuffer.Size + local table_scroll_cur, table_scroll_max -- For debug display + local table_draw_list = nil -- " - if ImGui.TreeNodeEx("Features:", ImGuiTreeNodeFlags.DefaultOpen) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Resizable", s.flags, TF.Resizable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Reorderable", s.flags, TF.Reorderable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Hideable", s.flags, TF.Hideable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_Sortable", s.flags, TF.Sortable) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoSavedSettings", s.flags, TF.NoSavedSettings) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", s.flags, TF.ContextMenuInBody) - ImGui.TreePop() - end + -- Submit table + local flags = s.flags + local columns_base_flags = s.columns_base_flags + local inner_width_to_use = (bit32.band(flags, ImGuiTableFlags.ScrollX) ~= 0) and s.inner_width_with_scroll or 0.0 + if ImGui.BeginTable("table_advanced", 6, flags, s.outer_size_enabled and s.outer_size_value or ImVec2(0, 0), inner_width_to_use) then + -- Declare columns + -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. + -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! + ImGui.TableSetupColumn("ID", bit32.bor(columns_base_flags, ImGuiTableColumnFlags.DefaultSort, ImGuiTableColumnFlags.WidthFixed, ImGuiTableColumnFlags.NoHide), 0.0, MyItemColumnID_ID) + ImGui.TableSetupColumn("Name", bit32.bor(columns_base_flags, ImGuiTableColumnFlags.WidthFixed), 0.0, MyItemColumnID_Name) + ImGui.TableSetupColumn("Action", bit32.bor(columns_base_flags, ImGuiTableColumnFlags.NoSort, ImGuiTableColumnFlags.WidthFixed), 0.0, MyItemColumnID_Action) + ImGui.TableSetupColumn("Quantity", bit32.bor(columns_base_flags, ImGuiTableColumnFlags.PreferSortDescending), 0.0, MyItemColumnID_Quantity) + ImGui.TableSetupColumn("Description", bit32.bor(columns_base_flags, (bit32.band(flags, ImGuiTableFlags.NoHostExtendX) ~= 0) and 0 or ImGuiTableColumnFlags.WidthStretch), 0.0, MyItemColumnID_Description) + ImGui.TableSetupColumn("Hidden", bit32.bor(columns_base_flags, ImGuiTableColumnFlags.DefaultHide, ImGuiTableColumnFlags.NoSort)) + ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) - if ImGui.TreeNodeEx("Decorations:", ImGuiTreeNodeFlags.DefaultOpen) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_RowBg", s.flags, TF.RowBg) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersV", s.flags, TF.BordersV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterV", s.flags, TF.BordersOuterV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerV", s.flags, TF.BordersInnerV) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersH", s.flags, TF.BordersH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersOuterH", s.flags, TF.BordersOuterH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_BordersInnerH", s.flags, TF.BordersInnerH) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBody", s.flags, TF.NoBordersInBody); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", s.flags, TF.NoBordersInBodyUntilResize); ImGui.SameLine(); DemoHelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)") - ImGui.TreePop() - end + -- Sort our data if sort specs have been changed! + local sort_specs = ImGui.TableGetSortSpecs() + if sort_specs and sort_specs.SpecsDirty then + s.items_need_sort = true + end + if sort_specs and s.items_need_sort and items.Size > 1 then + MyItem_SortWithSortSpecs(sort_specs, items.Data, items.Size) + sort_specs.SpecsDirty = false + end + s.items_need_sort = false - if ImGui.TreeNodeEx("Sizing:", ImGuiTreeNodeFlags.DefaultOpen) then - s.flags = EditTableSizingFlags(s.flags) - ImGui.SameLine(); DemoHelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendX", s.flags, TF.NoHostExtendX) - ImGui.SameLine(); DemoHelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoHostExtendY", s.flags, TF.NoHostExtendY) - ImGui.SameLine(); DemoHelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", s.flags, TF.NoKeepColumnsVisible) - ImGui.SameLine(); DemoHelpMarker("Only available if ScrollX is disabled.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PreciseWidths", s.flags, TF.PreciseWidths) - ImGui.SameLine(); DemoHelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoClip", s.flags, TF.NoClip) - ImGui.SameLine(); DemoHelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.") - ImGui.TreePop() - end + -- Take note of whether we are currently sorting based on the Quantity field, + -- we will use this to trigger sorting when we know the data of this column has been modified. + local sorts_specs_using_quantity = bit32.band(ImGui.TableGetColumnFlags(3), ImGuiTableColumnFlags.IsSorted) ~= 0 - if ImGui.TreeNodeEx("Padding:", ImGuiTreeNodeFlags.DefaultOpen) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_PadOuterX", s.flags, TF.PadOuterX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadOuterX", s.flags, TF.NoPadOuterX) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_NoPadInnerX", s.flags, TF.NoPadInnerX) - ImGui.TreePop() - end + -- Show headers + if s.show_headers and bit32.band(columns_base_flags, ImGuiTableColumnFlags.AngledHeader) ~= 0 then + ImGui.TableAngledHeadersRow() + end + if s.show_headers then + ImGui.TableHeadersRow() + end - if ImGui.TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags.DefaultOpen) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollX", s.flags, TF.ScrollX) - ImGui.SameLine() - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_cols = ImGui.DragInt("freeze_cols", s.freeze_cols, 0.2, 0, 9, nil, ImGuiSliderFlags.NoInput) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_ScrollY", s.flags, TF.ScrollY) - ImGui.SameLine() - ImGui.SetNextItemWidth(ImGui.GetFrameHeight()) - s.freeze_rows = ImGui.DragInt("freeze_rows", s.freeze_rows, 0.2, 0, 9, nil, ImGuiSliderFlags.NoInput) - ImGui.TreePop() - end + -- Show data + -- FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here? + -- Demonstrate using clipper for large vertical lists + local clipper = ImGuiListClipper() + clipper:Begin(items.Size) + while clipper:Step() do + for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do + local item = items.Data[row_n + 1] + --if not filter:PassFilter(item.Name) then + -- continue - if ImGui.TreeNodeEx("Sorting:", ImGuiTreeNodeFlags.DefaultOpen) then - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortMulti", s.flags, TF.SortMulti) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).") - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_SortTristate", s.flags, TF.SortTristate) - ImGui.SameLine(); DemoHelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).") - ImGui.TreePop() - end + local item_is_selected = selection:contains(item.ID) + ImGui.PushID(item.ID) + ImGui.TableNextRow(ImGuiTableRowFlags.None, s.row_min_height) - if ImGui.TreeNodeEx("Headers:", ImGuiTreeNodeFlags.DefaultOpen) then - _, s.show_headers = ImGui.Checkbox("show_headers", s.show_headers) - _, s.flags = ImGui.CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", s.flags, TF.HighlightHoveredColumn) - _, s.columns_base_flags = ImGui.CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", s.columns_base_flags, ImGuiTableColumnFlags.AngledHeader) - ImGui.SameLine(); DemoHelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).") - ImGui.TreePop() - end - - if ImGui.TreeNodeEx("Other:", ImGuiTreeNodeFlags.DefaultOpen) then - _, s.show_wrapped_text = ImGui.Checkbox("show_wrapped_text", s.show_wrapped_text) - - ImGui.DragFloat2("##OuterSize", s.outer_size_value) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - _, s.outer_size_enabled = ImGui.Checkbox("outer_size", s.outer_size_enabled) - ImGui.SameLine() - DemoHelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n" .. - "- The table is output directly in the parent window.\n" .. - "- OuterSize.x < 0.0f will right-align the table.\n" .. - "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n" .. - "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).") - - -- From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling. - -- To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled. - s.inner_width_with_scroll = ImGui.DragFloat("inner_width (when ScrollX active)", s.inner_width_with_scroll, 1.0, 0.0, FLT_MAX) - - s.row_min_height = ImGui.DragFloat("row_min_height", s.row_min_height, 1.0, 0.0, FLT_MAX) - ImGui.SameLine(); DemoHelpMarker("Specify height of the Selectable item.") - - s.items_count = ImGui.DragInt("items_count", s.items_count, 0.1, 0, 9999) - local contents_type_names = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" } - if ImGui.Combo then - s.contents_type = ImGui.Combo("items_type (first column)", s.contents_type, contents_type_names, #contents_type_names) - else - NotPorted("Combo") - end - ImGui.TreePop() - end - - ImGui.PopItemWidth() - PopStyleCompact() - ImGui.Spacing() -end - --- In this example we'll expose most table flags and settings. --- For specific flags and settings refer to the corresponding section for more detailed explanation. --- This section is mostly useful to experiment with combining certain flags or settings with each others. -local function Tables_Advanced() - IMGUI_DEMO_MARKER("Tables/Advanced") - local CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow = 0, 1, 2, 3, 4, 5 - local s = ST.advanced - if s == nil then - s = { flags = bor(TF.Resizable, TF.Reorderable, TF.Hideable, TF.Sortable, TF.SortMulti, TF.RowBg, TF.Borders, TF.NoBordersInBody, TF.ScrollX, TF.ScrollY, TF.SizingFixedFit), - columns_base_flags = ImGuiTableColumnFlags.None, contents_type = CT_SelectableSpanRow, - freeze_cols = 1, freeze_rows = 1, items_count = #template_items_names * 2, - outer_size_value = ImVec2(0.0, TEXT_BASE_HEIGHT * 12), row_min_height = 0.0, inner_width_with_scroll = 0.0, - outer_size_enabled = true, show_headers = true, show_wrapped_text = false, - items = {}, selection = {}, items_need_sort = false, show_debug_details = false } - ST.advanced = s - end - --ImGui.SetNextItemOpen(true, ImGuiCond.Once) -- FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing - if ImGui.TreeNode("Options") then - Tables_AdvancedOptions(s) - ImGui.TreePop() - end - - -- Update item list if we changed the number of items - local items = s.items - local selection = s.selection - if #items ~= s.items_count then - for n = #items, s.items_count + 1, -1 do items[n] = nil end - for n = 0, s.items_count - 1 do - local template_n = n % #template_items_names - items[n + 1] = MyItem(n, template_items_names[template_n + 1], (template_n == 3) and 10 or (template_n == 4) and 20 or 0) -- Assign default quantities - end - end - - local parent_draw_list = ImGui.GetWindowDrawList() - local parent_draw_list_draw_cmd_count = parent_draw_list.CmdBuffer.Size - local table_scroll_cur, table_scroll_max -- For debug display - local table_draw_list = nil -- " - - -- Submit table - local flags = s.flags - local columns_base_flags = s.columns_base_flags - local inner_width_to_use = Has(flags, TF.ScrollX) and s.inner_width_with_scroll or 0.0 - local CF = ImGuiTableColumnFlags - if ImGui.BeginTable("table_advanced", 6, flags, s.outer_size_enabled and s.outer_size_value or ImVec2(0, 0), inner_width_to_use) then - -- Declare columns - -- We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. - -- This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! - ImGui.TableSetupColumn("ID", bor(columns_base_flags, CF.DefaultSort, CF.WidthFixed, CF.NoHide), 0.0, MyItemColumnID_ID) - ImGui.TableSetupColumn("Name", bor(columns_base_flags, CF.WidthFixed), 0.0, MyItemColumnID_Name) - ImGui.TableSetupColumn("Action", bor(columns_base_flags, CF.NoSort, CF.WidthFixed), 0.0, MyItemColumnID_Action) - ImGui.TableSetupColumn("Quantity", bor(columns_base_flags, CF.PreferSortDescending), 0.0, MyItemColumnID_Quantity) - ImGui.TableSetupColumn("Description", bor(columns_base_flags, Has(flags, TF.NoHostExtendX) and 0 or CF.WidthStretch), 0.0, MyItemColumnID_Description) - ImGui.TableSetupColumn("Hidden", bor(columns_base_flags, CF.DefaultHide, CF.NoSort)) - ImGui.TableSetupScrollFreeze(s.freeze_cols, s.freeze_rows) - - -- Sort our data if sort specs have been changed! - local sort_specs = ImGui.TableGetSortSpecs() - if sort_specs and sort_specs.SpecsDirty then - s.items_need_sort = true - end - if sort_specs and s.items_need_sort and #items > 1 then - MyItem_SortWithSortSpecs(sort_specs, items, #items) - sort_specs.SpecsDirty = false - end - s.items_need_sort = false - - -- Take note of whether we are currently sorting based on the Quantity field, - -- we will use this to trigger sorting when we know the data of this column has been modified. - local sorts_specs_using_quantity = Has(ImGui.TableGetColumnFlags(3), CF.IsSorted) - - -- Show headers - if s.show_headers and Has(columns_base_flags, CF.AngledHeader) then - ImGui.TableAngledHeadersRow() - end - if s.show_headers then - ImGui.TableHeadersRow() - end - - -- Show data - -- FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here? - -- Demonstrate using clipper for large vertical lists - local clipper = ImGuiListClipper() - clipper:Begin(#items) - while clipper:Step() do - for row_n = clipper.DisplayStart, clipper.DisplayEnd - 1 do - local item = items[row_n + 1] - - local item_is_selected = table.find(selection, item.ID) ~= nil - ImGui.PushID(item.ID) - ImGui.TableNextRow(ImGuiTableRowFlags.None, s.row_min_height) - - -- For the demo purpose we can select among different type of items submitted in the first column - ImGui.TableSetColumnIndex(0) - local label = string.format("%04d", item.ID) - local ct = s.contents_type - if ct == CT_Text then - ImGui.TextUnformatted(label) - elseif ct == CT_Button then - ImGui.Button(label) - elseif ct == CT_SmallButton then - ImGui.SmallButton(label) - elseif ct == CT_FillButton then - ImGui.Button(label, ImVec2(-FLT_MIN, 0.0)) - elseif ct == CT_Selectable or ct == CT_SelectableSpanRow then - local selectable_flags = (ct == CT_SelectableSpanRow) and bor(ImGuiSelectableFlags.SpanAllColumns, ImGuiSelectableFlags.AllowOverlap) or ImGuiSelectableFlags.None - if ImGui.Selectable(label, item_is_selected, selectable_flags, ImVec2(0, s.row_min_height)) then - if ImGui.GetIO().KeyCtrl then - if item_is_selected then - table.remove(selection, table.find(selection, item.ID)) + -- For the demo purpose we can select among different type of items submitted in the first column + ImGui.TableSetColumnIndex(0) + local label = string.format("%04d", item.ID) + local contents_type = s.contents_type + if contents_type == CT_Text then + ImGui.TextUnformatted(label) + elseif contents_type == CT_Button then + ImGui.Button(label) + elseif contents_type == CT_SmallButton then + ImGui.SmallButton(label) + elseif contents_type == CT_FillButton then + ImGui.Button(label, ImVec2(-FLT_MIN, 0.0)) + elseif contents_type == CT_Selectable or contents_type == CT_SelectableSpanRow then + local selectable_flags = (contents_type == CT_SelectableSpanRow) and bit32.bor(ImGuiSelectableFlags.SpanAllColumns, ImGuiSelectableFlags.AllowOverlap) or ImGuiSelectableFlags.None + if ImGui.Selectable(label, item_is_selected, selectable_flags, ImVec2(0, s.row_min_height)) then + if ImGui.GetIO().KeyCtrl then + if item_is_selected then + selection:find_erase_unsorted(item.ID) + else + selection:push_back(item.ID) + end else - table.insert(selection, item.ID) + selection:clear() + selection:push_back(item.ID) end - else - table.clear(selection) - table.insert(selection, item.ID) end end - end - if ImGui.TableSetColumnIndex(1) then - ImGui.TextUnformatted(item.Name) - end + if ImGui.TableSetColumnIndex(1) then + ImGui.TextUnformatted(item.Name) + end - -- Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity, - -- and we are currently sorting on the column showing the Quantity. - -- To avoid triggering a sort while holding the button, we only trigger it when the button has been released. - -- You will probably need some extra logic if you want to automatically sort when a specific entry changes. - if ImGui.TableSetColumnIndex(2) then - if ImGui.SmallButton("Chop") then item.Quantity = item.Quantity + 1 end - if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end - ImGui.SameLine() - if ImGui.SmallButton("Eat") then item.Quantity = item.Quantity - 1 end - if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end - end + -- Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity, + -- and we are currently sorting on the column showing the Quantity. + -- To avoid triggering a sort while holding the button, we only trigger it when the button has been released. + -- You will probably need some extra logic if you want to automatically sort when a specific entry changes. + if ImGui.TableSetColumnIndex(2) then + if ImGui.SmallButton("Chop") then item.Quantity = item.Quantity + 1 end + if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end + ImGui.SameLine() + if ImGui.SmallButton("Eat") then item.Quantity = item.Quantity - 1 end + if sorts_specs_using_quantity and ImGui.IsItemDeactivated() then s.items_need_sort = true end + end - if ImGui.TableSetColumnIndex(3) then - ImGui.Text("%d", item.Quantity) - end + if ImGui.TableSetColumnIndex(3) then + ImGui.Text("%d", item.Quantity) + end - ImGui.TableSetColumnIndex(4) - if s.show_wrapped_text then - ImGui.TextWrapped("Lorem ipsum dolor sit amet") - else - ImGui.Text("Lorem ipsum dolor sit amet") - end + ImGui.TableSetColumnIndex(4) + if s.show_wrapped_text then + ImGui.TextWrapped("Lorem ipsum dolor sit amet") + else + ImGui.Text("Lorem ipsum dolor sit amet") + end - if ImGui.TableSetColumnIndex(5) then - ImGui.Text("1234") - end + if ImGui.TableSetColumnIndex(5) then + ImGui.Text("1234") + end - ImGui.PopID() + ImGui.PopID() + end + end + + -- Store some info to display debug details below + table_scroll_cur = ImVec2(ImGui.GetScrollX(), ImGui.GetScrollY()) + table_scroll_max = ImVec2(ImGui.GetScrollMaxX(), ImGui.GetScrollMaxY()) + table_draw_list = ImGui.GetWindowDrawList() + ImGui.EndTable() + end + _, s.show_debug_details = ImGui.Checkbox("Debug details", s.show_debug_details) + if s.show_debug_details and table_draw_list then + ImGui.SameLine(0.0, 0.0) + local table_draw_list_draw_cmd_count = table_draw_list.CmdBuffer.Size + if table_draw_list == parent_draw_list then + ImGui.Text(": DrawCmd: +%d (in same window)", + table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count) + else + ImGui.Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", + table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y) end end - - -- Store some info to display debug details below - table_scroll_cur = ImVec2(ImGui.GetScrollX(), ImGui.GetScrollY()) - table_scroll_max = ImVec2(ImGui.GetScrollMaxX(), ImGui.GetScrollMaxY()) - table_draw_list = ImGui.GetWindowDrawList() - ImGui.EndTable() + ImGui.TreePop() end - _, s.show_debug_details = ImGui.Checkbox("Debug details", s.show_debug_details) - if s.show_debug_details and table_draw_list then - ImGui.SameLine(0.0, 0.0) - local table_draw_list_draw_cmd_count = table_draw_list.CmdBuffer.Size - if table_draw_list == parent_draw_list then - ImGui.Text(": DrawCmd: +%d (in same window)", - table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count) - else - ImGui.Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", - table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y) - end + + ImGui.PopID() + + DemoWindowColumns() + + if s.disable_indent then + ImGui.PopStyleVar() end end -local DCS = { selected = -1, h_borders = true, v_borders = true, columns_count = 4, foo = 1.0, bar = 1.0 } - --- Demonstrate old/legacy Columns API! --- [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!] -local function DemoWindowColumns() +S.DemoWindowColumns = { + selected = -1, + h_borders = true, + v_borders = true, + columns_count = 4, + foo = 1.0, + bar = 1.0, +} +function DemoWindowColumns() + local s = S.DemoWindowColumns local open = ImGui.TreeNode("Legacy Columns API") ImGui.SameLine() - DemoHelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!") + HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!") if not open then return end @@ -4096,12 +6992,12 @@ local function DemoWindowColumns() if ImGui.TreeNode("Basic") then IMGUI_DEMO_MARKER("Columns (legacy API)/Basic") ImGui.Text("Without border:") - ImGui.Columns(3, "mycolumns3", false) -- 3-ways, no border + ImGui.Columns(3, "mycolumns3", false) -- 3-ways, no border ImGui.Separator() for n = 0, 13 do local label = string.format("Item %d", n) if ImGui.Selectable(label) then end - --if ImGui.Button(label, ImVec2(-FLT_MIN,0.0)) then end + --if (ImGui.Button(label, ImVec2(-FLT_MIN,0.0))) {} ImGui.NextColumn() end ImGui.Columns(1) @@ -4119,8 +7015,8 @@ local function DemoWindowColumns() local paths = { "/path/one", "/path/two", "/path/three" } for i = 0, 2 do local label = string.format("%04d", i) - if ImGui.Selectable(label, DCS.selected == i, ImGuiSelectableFlags.SpanAllColumns) then - DCS.selected = i + if ImGui.Selectable(label, s.selected == i, ImGuiSelectableFlags.SpanAllColumns) then + s.selected = i end local hovered = ImGui.IsItemHovered() ImGui.NextColumn() @@ -4138,17 +7034,17 @@ local function DemoWindowColumns() -- NB: Future columns API should allow automatic horizontal borders. local lines_count = 3 ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - DCS.columns_count = ImGui.DragInt("##columns_count", DCS.columns_count, 0.1, 2, 10, "%d columns") - if DCS.columns_count < 2 then - DCS.columns_count = 2 + s.columns_count = ImGui.DragInt("##columns_count", s.columns_count, 0.1, 2, 10, "%d columns") + if s.columns_count < 2 then + s.columns_count = 2 end ImGui.SameLine() - _, DCS.h_borders = ImGui.Checkbox("horizontal", DCS.h_borders) + _, s.h_borders = ImGui.Checkbox("horizontal", s.h_borders) ImGui.SameLine() - _, DCS.v_borders = ImGui.Checkbox("vertical", DCS.v_borders) - ImGui.Columns(DCS.columns_count, nil, DCS.v_borders) - for i = 0, DCS.columns_count * lines_count - 1 do - if DCS.h_borders and ImGui.GetColumnIndex() == 0 then + _, s.v_borders = ImGui.Checkbox("vertical", s.v_borders) + ImGui.Columns(s.columns_count, nil, s.v_borders) + for i = 0, s.columns_count * lines_count - 1 do + if s.h_borders and ImGui.GetColumnIndex() == 0 then ImGui.Separator() end ImGui.PushID(i) @@ -4163,7 +7059,7 @@ local function DemoWindowColumns() ImGui.NextColumn() end ImGui.Columns(1) - if DCS.h_borders then + if s.h_borders then ImGui.Separator() end ImGui.TreePop() @@ -4181,13 +7077,13 @@ local function DemoWindowColumns() ImGui.Text("ImGui") ImGui.Button("Apple") - DCS.foo = ImGui.InputFloat("red", DCS.foo, 0.05, 0, "%.3f") + s.foo = ImGui.InputFloat("red", s.foo, 0.05, 0, "%.3f") ImGui.Text("An extra line here.") ImGui.NextColumn() ImGui.Text("Sailor") ImGui.Button("Corniflower") - DCS.bar = ImGui.InputFloat("blue", DCS.bar, 0.05, 0, "%.3f") + s.bar = ImGui.InputFloat("blue", s.bar, 0.05, 0, "%.3f") ImGui.NextColumn() if ImGui.CollapsingHeader("Category A") then ImGui.Text("Blah blah blah") end ImGui.NextColumn() @@ -4272,104 +7168,1045 @@ local function DemoWindowColumns() ImGui.TreePop() end -local tables_sections = { - { "Basic", Tables_Basic }, - { "Borders, background", Tables_BordersBackground }, - { "Resizable, stretch", Tables_ResizableStretch }, - { "Resizable, fixed", Tables_ResizableFixed }, - { "Resizable, mixed", Tables_ResizableMixed }, - { "Reorderable, hideable, with headers", Tables_Reorderable }, - { "Padding", Tables_Padding }, - { "Sizing policies", Tables_SizingPolicies }, - { "Vertical scrolling, with clipping", Tables_VerticalScrolling }, - { "Horizontal scrolling", Tables_HorizontalScrolling }, - { "Columns flags", Tables_ColumnsFlags }, - { "Columns widths", Tables_ColumnsWidths }, - { "Nested tables", Tables_Nested }, - { "Row height", Tables_RowHeight }, - { "Outer size", Tables_OuterSize }, - { "Background color", Tables_BackgroundColor }, - { "Tree view", Tables_TreeView }, - { "Item width", Tables_ItemWidth }, - { "Custom headers", Tables_CustomHeaders }, - { "Angled headers", Tables_AngledHeaders }, - { "Context menus", Tables_ContextMenus }, - { "Synced instances", Tables_SyncedInstances }, - { "Sorting", Tables_Sorting }, - { "Advanced", Tables_Advanced }, +------------------------------------------------------------------------------- +-- [SECTION] DemoWindowInputs() +------------------------------------------------------------------------------- + +S.DemoWindowInputs = { + funcs = { IsLegacyNativeDupe = function(key) return false end }, -- struct funcs (hoisted to avoid a per-frame closure) -- [Port] + capture_override_mouse = -1, + capture_override_keyboard = -1, + route_options = ImGuiInputFlags.Repeat, + route_type = ImGuiInputFlags.RouteFocused, + f = 0.5, + tabbing_buf = ImGui.NewTextBuffer("hello", 32), + focus_buf = ImGui.NewTextBuffer("click on a button to set focus", 128), + f3 = { 0.0, 0.0, 0.0 }, } +S.DemoWindowInputs.mouse_cursors_names = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "Wait", "Progress", "NotAllowed" } +function DemoWindowInputs() + local s = S.DemoWindowInputs + if ImGui.CollapsingHeader("Inputs & Focus") then + local io = ImGui.GetIO() -function DemoWindowTables() - --ImGui.SetNextItemOpen(true, ImGuiCond.Once) - if not ImGui.CollapsingHeader("Tables & Columns") then - return - end + -- Display inputs submitted to ImGuiIO + ImGui.SetNextItemOpen(true, ImGuiCond.Once) + local inputs_opened = ImGui.TreeNode("Inputs") + ImGui.SameLine() + HelpMarker( + "This is a simplified view. See more detailed input state:\n" .. + "- in 'Tools->Metrics/Debugger->Inputs'.\n" .. + "- in 'Tools->Debug Log->IO'.") + if inputs_opened then + IMGUI_DEMO_MARKER("Inputs & Focus/Inputs") + if ImGui.IsMousePosValid() then + ImGui.Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y) + else + ImGui.Text("Mouse pos: ") + end + ImGui.Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y) + ImGui.Text("Mouse down:") + for i = 0, 2 do if ImGui.IsMouseDown(i) then ImGui.SameLine(); ImGui.Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]) end end -- IM_COUNTOF(io.MouseDown) == 3, 0-based + ImGui.Text("Mouse wheel: %.1f", io.MouseWheel) + ImGui.Text("Mouse clicked count:") + for i = 0, 2 do if io.MouseClickedCount[i] > 0 then ImGui.SameLine(); ImGui.Text("b%d: %d", i, io.MouseClickedCount[i]) end end - -- Using those as a base value to create width/height that are factor of the size of our font - TEXT_BASE_WIDTH = ImGui.CalcTextSize("A").x - TEXT_BASE_HEIGHT = ImGui.GetTextLineHeightWithSpacing() + -- We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows + -- displaying the data for old/new backends. + -- User code should never have to go through such hoops! + -- You can generally iterate between ImGuiKey.NamedKey_BEGIN and ImGuiKey.NamedKey_END. + local funcs = s.funcs + local start_key = ImGuiKey.NamedKey_BEGIN + ImGui.Text("Keys down:") for key = start_key, ImGuiKey.NamedKey_END - 1 do repeat if funcs.IsLegacyNativeDupe(key) or not ImGui.IsKeyDown(key) then break end ImGui.SameLine(); if key < ImGuiKey.NamedKey_BEGIN then ImGui.Text("\"%s\"", ImGui.GetKeyName(key)) else ImGui.Text("\"%s\" %d", ImGui.GetKeyName(key), key) end until true end + ImGui.Text("Keys mods: %s%s%s%s", io.KeyCtrl and "CTRL " or "", io.KeyShift and "SHIFT " or "", io.KeyAlt and "ALT " or "", io.KeySuper and "SUPER " or "") + ImGui.Text("Chars queue:") for i = 0, io.InputQueueCharacters.Size - 1 do local c = io.InputQueueCharacters.Data[i + 1]; ImGui.SameLine(); ImGui.Text("\'%s\' (0x%04X)", (c > 32 and c <= 255) and string.char(c) or '?', c) end -- FIXME: We should convert 'c' to UTF-8 here but the functions are not public. - ImGui.PushID("Tables") - - local open_action = -1 - if ImGui.Button("Expand all") then - open_action = 1 - end - ImGui.SameLine() - if ImGui.Button("Collapse all") then - open_action = 0 - end - ImGui.SameLine() - - -- Options - _, ST.disable_indent = ImGui.Checkbox("Disable tree indentation", ST.disable_indent or false) - ImGui.SameLine() - DemoHelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.") - ImGui.Separator() - local disable_indent = ST.disable_indent - if disable_indent then - ImGui.PushStyleVar(ImGuiStyleVar.IndentSpacing, 0.0) - end - - -- About Styling of tables - -- Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs. - -- There are however a few settings that a shared and part of the ImGuiStyle structure: - -- style.CellPadding -- Padding within each cell - -- style.Colors[ImGuiCol.TableHeaderBg] -- Table header background - -- style.Colors[ImGuiCol.TableBorderStrong] -- Table outer and header borders - -- style.Colors[ImGuiCol.TableBorderLight] -- Table inner borders - -- style.Colors[ImGuiCol.TableRowBg] -- Table row background when ImGuiTableFlags_RowBg is enabled (even rows) - -- style.Colors[ImGuiCol.TableRowBgAlt] -- Table row background when ImGuiTableFlags_RowBg is enabled (odds rows) - - -- Demos - for _, sec in ipairs(tables_sections) do - if open_action ~= -1 then - ImGui.SetNextItemOpen(open_action ~= 0) + ImGui.TreePop() end - if ImGui.TreeNode(sec[1]) then - sec[2]() + + -- Display ImGuiIO output flags + ImGui.SetNextItemOpen(true, ImGuiCond.Once) + local outputs_opened = ImGui.TreeNode("Outputs") + ImGui.SameLine() + HelpMarker( + "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui " .. + "to instruct your application of how to route inputs. Typically, when a value is true, it means " .. + "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n" .. + "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, " .. + "and underlying application should ignore mouse inputs (in practice there are many and more subtle " .. + "rules leading to how those flags are set).") + if outputs_opened then + IMGUI_DEMO_MARKER("Inputs & Focus/Outputs") + ImGui.Text("io.WantCaptureMouse: %d", io.WantCaptureMouse and 1 or 0) + ImGui.Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose and 1 or 0) + ImGui.Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard and 1 or 0) + ImGui.Text("io.WantTextInput: %d", io.WantTextInput and 1 or 0) + ImGui.Text("io.WantSetMousePos: %d", io.WantSetMousePos and 1 or 0) + ImGui.Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive and 1 or 0, io.NavVisible and 1 or 0) + + IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override") + if ImGui.TreeNode("WantCapture override") then + HelpMarker( + "Hovering the colored canvas will override io.WantCaptureXXX fields.\n" .. + "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering " .. + "and true when clicking.") + local capture_override_desc = { "None", "Set to false", "Set to true" } + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 15) + s.capture_override_mouse = ImGui.SliderInt("SetNextFrameWantCaptureMouse() on hover", s.capture_override_mouse, -1, 1, capture_override_desc[s.capture_override_mouse + 2], ImGuiSliderFlags.AlwaysClamp) + ImGui.SetNextItemWidth(ImGui.GetFontSize() * 15) + s.capture_override_keyboard = ImGui.SliderInt("SetNextFrameWantCaptureKeyboard() on hover", s.capture_override_keyboard, -1, 1, capture_override_desc[s.capture_override_keyboard + 2], ImGuiSliderFlags.AlwaysClamp) + + ImGui.ColorButton("##panel", ImVec4(0.7, 0.1, 0.7, 1.0), bit32.bor(ImGuiColorEditFlags.NoTooltip, ImGuiColorEditFlags.NoDragDrop), ImVec2(128.0, 96.0)) -- Dummy item + if ImGui.IsItemHovered() and s.capture_override_mouse ~= -1 then + ImGui.SetNextFrameWantCaptureMouse(s.capture_override_mouse == 1) + end + if ImGui.IsItemHovered() and s.capture_override_keyboard ~= -1 then + ImGui.SetNextFrameWantCaptureKeyboard(s.capture_override_keyboard == 1) + end + + ImGui.TreePop() + end + ImGui.TreePop() + end + + -- Demonstrate using Shortcut() and Routing Policies. + -- The general flow is: + -- - Code interested in a chord (e.g. "Ctrl+A") declares their intent. + -- - Multiple locations may be interested in same chord! Routing helps find a winner. + -- - Every frame, we resolve all claims and assign one owner if the modifiers are matching. + -- - The lower-level function is 'bool SetShortcutRouting()', returns true when caller got the route. + -- - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing flags. + -- - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags.RouteFocused. + -- TL;DR: Most uses will simply be: + -- - Shortcut(ImGuiMod_Ctrl | ImGuiKey.A); -- Use ImGuiInputFlags.RouteFocused policy. + if ImGui.TreeNode("Shortcuts") then + IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts") + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_Repeat", s.route_options, ImGuiInputFlags.Repeat) + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteActive", s.route_type, ImGuiInputFlags.RouteActive) + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteFocused (default)", s.route_type, ImGuiInputFlags.RouteFocused) + ImGui.Indent() + ImGui.BeginDisabled(s.route_type ~= ImGuiInputFlags.RouteFocused) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteOverActive##0", s.route_options, ImGuiInputFlags.RouteOverActive) + ImGui.EndDisabled() + ImGui.Unindent() + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteGlobal", s.route_type, ImGuiInputFlags.RouteGlobal) + ImGui.Indent() + ImGui.BeginDisabled(s.route_type ~= ImGuiInputFlags.RouteGlobal) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteOverFocused", s.route_options, ImGuiInputFlags.RouteOverFocused) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteOverActive", s.route_options, ImGuiInputFlags.RouteOverActive) + _, s.route_options = ImGui.CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", s.route_options, ImGuiInputFlags.RouteUnlessBgFocused) + ImGui.EndDisabled() + ImGui.Unindent() + _, s.route_type = ImGui.RadioButton("ImGuiInputFlags_RouteAlways", s.route_type, ImGuiInputFlags.RouteAlways) + local flags = bit32.bor(s.route_type, s.route_options) -- Merged flags + if s.route_type ~= ImGuiInputFlags.RouteGlobal then + flags = bit32.band(flags, bit32.bnot(bit32.bor(ImGuiInputFlags.RouteOverFocused, ImGuiInputFlags.RouteOverActive, ImGuiInputFlags.RouteUnlessBgFocused))) + end + + ImGui.SeparatorText("Using SetNextItemShortcut()") + ImGui.Text("Ctrl+S") + ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.S), bit32.bor(flags, ImGuiInputFlags.Tooltip)) + ImGui.Button("Save") + ImGui.Text("Alt+F") + ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Alt, ImGuiKey.F), bit32.bor(flags, ImGuiInputFlags.Tooltip)) + s.f = ImGui.SliderFloat("Factor", s.f, 0.0, 1.0) + + ImGui.SeparatorText("Using Shortcut()") + local line_height = ImGui.GetTextLineHeightWithSpacing() + local key_chord = bit32.bor(ImGuiMod_Ctrl, ImGuiKey.A) + + -- [Port] ImGui.Shortcut() has no owner_id default (upstream public overload passes ImGuiKeyOwner_Any): pass it explicitly. + ImGui.Text("Ctrl+A") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, ImGuiKeyOwner_Any) and "PRESSED" or "...") + + ImGui.PushStyleColor(ImGuiCol.ChildBg, ImVec4(1.0, 0.0, 1.0, 0.1)) + + ImGui.BeginChild("WindowA", ImVec2(-FLT_MIN, line_height * 14), true) + ImGui.Text("Press Ctrl+A and see who receives it!") + ImGui.Separator() + + -- 1: Window polling for Ctrl+A + ImGui.Text("(in WindowA)") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, ImGuiKeyOwner_Any) and "PRESSED" or "...") + + -- 2: InputText also polling for Ctrl+A: it always uses _RouteFocused internally (gets priority when active) + -- (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h) + --char str[16] = "Press Ctrl+A"; + --ImGui.Spacing(); + --ImGui.InputText("InputTextB", str, IM_COUNTOF(str), ImGuiInputTextFlags.ReadOnly); + --ImGuiID item_id = ImGui.GetItemID(); + --ImGui.SameLine(); HelpMarker("Internal widgets always use _RouteFocused"); + --ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused(), ImGui.Shortcut(key_chord, flags, item_id) ? "PRESSED" : "..."); + + -- 3: Dummy child is not claiming the route: focusing them shouldn't steal route away from WindowA + ImGui.BeginChild("ChildD", ImVec2(-FLT_MIN, line_height * 4), true) + ImGui.Text("(in ChildD: not using same Shortcut)") + ImGui.Text("IsWindowFocused: %d", ImGui.IsWindowFocused() and 1 or 0) + ImGui.EndChild() + + -- 4: Child window polling for Ctrl+A. It is deeper than WindowA and gets priority when focused. + ImGui.BeginChild("ChildE", ImVec2(-FLT_MIN, line_height * 4), true) + ImGui.Text("(in ChildE: using same Shortcut)") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, ImGuiKeyOwner_Any) and "PRESSED" or "...") + ImGui.EndChild() + + -- 5: In a popup + if ImGui.Button("Open Popup") then + ImGui.OpenPopup("PopupF") + end + if ImGui.BeginPopup("PopupF") then + ImGui.Text("(in PopupF)") + ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused() and 1 or 0, ImGui.Shortcut(key_chord, flags, ImGuiKeyOwner_Any) and "PRESSED" or "...") + -- (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h) + --ImGui.InputText("InputTextG", str, IM_COUNTOF(str), ImGuiInputTextFlags.ReadOnly); + --ImGui.Text("IsWindowFocused: %d, Shortcut: %s", ImGui.IsWindowFocused(), ImGui.Shortcut(key_chord, flags, ImGui.GetItemID()) ? "PRESSED" : "..."); + ImGui.EndPopup() + end + ImGui.EndChild() + ImGui.PopStyleColor() + + ImGui.TreePop() + end + + -- Display mouse cursors + if ImGui.TreeNode("Mouse Cursors") then + IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors") + local mouse_cursors_names = s.mouse_cursors_names -- 1-based + IM_ASSERT(#mouse_cursors_names == ImGuiMouseCursor.COUNT) + + local current = ImGui.GetMouseCursor() + local cursor_name = "N/A" + if (current >= ImGuiMouseCursor.Arrow) and (current < ImGuiMouseCursor.COUNT) then cursor_name = mouse_cursors_names[current + 1] end + ImGui.Text("Current mouse cursor = %d: %s", current, cursor_name) + ImGui.BeginDisabled(true) + _, io.BackendFlags = ImGui.CheckboxFlags("io.BackendFlags: HasMouseCursors", io.BackendFlags, ImGuiBackendFlags.HasMouseCursors) + ImGui.EndDisabled() + + ImGui.Text("Hover to see mouse cursors:") + ImGui.SameLine(); HelpMarker( + "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " .. + "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " .. + "otherwise your backend needs to handle it.") + for i = 0, ImGuiMouseCursor.COUNT - 1 do + local label = string.format("Mouse cursor %d: %s", i, mouse_cursors_names[i + 1]) + ImGui.Bullet(); ImGui.Selectable(label, false) + if ImGui.IsItemHovered() then + ImGui.SetMouseCursor(i) + end + end + ImGui.TreePop() + end + + if ImGui.TreeNode("Tabbing") then + IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing") + ImGui.Text("Use Tab/Shift+Tab to cycle through keyboard editable fields.") + local buf = s.tabbing_buf + ImGui.InputText("1", buf, 32) + ImGui.InputText("2", buf, 32) + ImGui.InputText("3", buf, 32) + ImGui.PushItemFlag(ImGuiItemFlags.NoTabStop, true) + ImGui.InputText("4 (tab skip)", buf, 32) + ImGui.SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.") + ImGui.PopItemFlag() + ImGui.InputText("5", buf, 32) + ImGui.TreePop() + end + + if ImGui.TreeNode("Focus from code") then + IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code") + local focus_1 = ImGui.Button("Focus on 1"); ImGui.SameLine() + local focus_2 = ImGui.Button("Focus on 2"); ImGui.SameLine() + local focus_3 = ImGui.Button("Focus on 3") + local has_focus = 0 + local buf = s.focus_buf + + if focus_1 then ImGui.SetKeyboardFocusHere() end + ImGui.InputText("1", buf, 128) + if ImGui.IsItemActive() then has_focus = 1 end + + if focus_2 then ImGui.SetKeyboardFocusHere() end + ImGui.InputText("2", buf, 128) + if ImGui.IsItemActive() then has_focus = 2 end + + ImGui.PushItemFlag(ImGuiItemFlags.NoTabStop, true) + if focus_3 then ImGui.SetKeyboardFocusHere() end + ImGui.InputText("3 (tab skip)", buf, 128) + if ImGui.IsItemActive() then has_focus = 3 end + ImGui.SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.") + ImGui.PopItemFlag() + + if has_focus ~= 0 then + ImGui.Text("Item with focus: %d", has_focus) + else + ImGui.Text("Item with focus: ") + end + + -- Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item + local f3 = s.f3 + local focus_ahead = -1 + if ImGui.Button("Focus on X") then focus_ahead = 0 end ImGui.SameLine() + if ImGui.Button("Focus on Y") then focus_ahead = 1 end ImGui.SameLine() + if ImGui.Button("Focus on Z") then focus_ahead = 2 end + if focus_ahead ~= -1 then ImGui.SetKeyboardFocusHere(focus_ahead) end + ImGui.SliderFloat3("Float3", f3, 0.0, 1.0) + + ImGui.TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.") + ImGui.TreePop() + end + + if ImGui.TreeNode("Dragging") then + IMGUI_DEMO_MARKER("Inputs & Focus/Dragging") + ImGui.TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.") + for button = 0, 2 do + ImGui.Text("IsMouseDragging(%d):", button) + ImGui.Text(" w/ default threshold: %d,", ImGui.IsMouseDragging(button) and 1 or 0) + ImGui.Text(" w/ zero threshold: %d,", ImGui.IsMouseDragging(button, 0.0) and 1 or 0) + ImGui.Text(" w/ large threshold: %d,", ImGui.IsMouseDragging(button, 20.0) and 1 or 0) + end + + ImGui.Button("Drag Me") + if ImGui.IsItemActive() then + ImGui.GetForegroundDrawList():AddLine(io.MouseClickedPos[0], io.MousePos, ImGui.GetColorU32(ImGuiCol.Button), 4.0) -- Draw a line between the button and the mouse cursor + end + + -- Drag operations gets "unlocked" when the mouse has moved past a certain threshold + -- (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher + -- threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta(). + local value_raw = ImGui.GetMouseDragDelta(0, 0.0) + local value_with_lock_threshold = ImGui.GetMouseDragDelta(0) + local mouse_delta = io.MouseDelta + ImGui.Text("GetMouseDragDelta(0):") + ImGui.Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y) + ImGui.Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y) + ImGui.Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y) ImGui.TreePop() end end +end - ImGui.PopID() +------------------------------------------------------------------------------- +-- [SECTION] About Window / ShowAboutWindow() +-- Access from Dear ImGui Demo -> Tools -> About +------------------------------------------------------------------------------- - DemoWindowColumns() +S.ShowAboutWindow = { + show_config_info = false, +} +function ImGui.ShowAboutWindow(p_open) + local s = S.ShowAboutWindow + local _, visible + p_open, visible = ImGui.Begin("About Dear ImGui", p_open, ImGuiWindowFlags.AlwaysAutoResize) + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Tools/About Dear ImGui") + ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM) - if disable_indent then - ImGui.PopStyleVar() + ImGui.TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui") + ImGui.SameLine() + ImGui.TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Extensions", "https://github.com/ocornut/imgui/wiki/Useful-Extensions") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases") + ImGui.SameLine() + ImGui.TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding") + + ImGui.Separator() + ImGui.Text("(c) 2014-2026 Omar Cornut") + ImGui.Text("Developed by Omar Cornut and all Dear ImGui contributors.") + ImGui.Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.") + ImGui.Text("If your company uses this, please consider funding the project.") + + _, s.show_config_info = ImGui.Checkbox("Config/Build Information", s.show_config_info) + if s.show_config_info then + local io = ImGui.GetIO() + local style = ImGui.GetStyle() + + local copy_to_clipboard = ImGui.Button("Copy to clipboard") + local child_size = ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 18) + ImGui.BeginChild(ImGui.GetID("cfg_infos"), child_size, ImGuiChildFlags.FrameStyle) + if copy_to_clipboard then + ImGui.LogToClipboard() + ImGui.LogText("// (Copy from the next line. Keep the ``` markers for formatting.)\n") + ImGui.LogText("```cpp\n") -- Back quotes will make text appears without formatting when pasting on GitHub + end + + ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM) + ImGui.Separator() + -- [Port] no sizeof()/__cplusplus/compiler/OS #defines in Lua: report the Lua runtime instead + ImGui.Text("runtime: %s", tostring(_VERSION)) + ImGui.Text("define: IMGUI_HAS_VIEWPORT") + ImGui.Text("define: IMGUI_HAS_DOCK") + + -- Heuristic to detect no-op IM_ASSERT() macros + -- - This is designed so people opening bug reports would convey and notice that they have disabled asserts for Dear ImGui code. + -- - 16 is > strlen("((void)(_EXPR))") which we suggested in our imconfig.h template as a possible way to disable. + local assert_runs_expression = 0 + IM_ASSERT((function() assert_runs_expression = assert_runs_expression + 1; return assert_runs_expression end)()) -- [Port] no ++ in expressions + local assert_expand_len = 17 -- [Port] IM_ASSERT is a function, not a macro: nothing to stringify, it cannot be expanded to a no-op + local assert_maybe_disabled = (assert_runs_expression == 0 or assert_expand_len <= 16) + ImGui.Text("IM_ASSERT: runs expression: %s. expand size: %s%s", + (assert_runs_expression ~= 0) and "OK" or "KO", (assert_expand_len > 16) and "OK" or "KO", assert_maybe_disabled and " (MAYBE DISABLED?!)" or "") + if assert_maybe_disabled then + ImGui.SameLine() + HelpMarker("IM_ASSERT() calls assert() by default. Compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes!") + end + + ImGui.Separator() + ImGui.Text("io.BackendPlatformName: %s", io.BackendPlatformName or "NULL") + ImGui.Text("io.BackendRendererName: %s", io.BackendRendererName or "NULL") + ImGui.Text("io.ConfigFlags: 0x%08X", io.ConfigFlags) + if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard) ~= 0 then ImGui.Text(" NavEnableKeyboard") end + if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NavEnableGamepad) ~= 0 then ImGui.Text(" NavEnableGamepad") end + if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NoMouse) ~= 0 then ImGui.Text(" NoMouse") end + if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NoMouseCursorChange) ~= 0 then ImGui.Text(" NoMouseCursorChange") end + if bit32.band(io.ConfigFlags, ImGuiConfigFlags.NoKeyboard) ~= 0 then ImGui.Text(" NoKeyboard") end + if bit32.band(io.ConfigFlags, ImGuiConfigFlags.DockingEnable) ~= 0 then ImGui.Text(" DockingEnable") end + if bit32.band(io.ConfigFlags, ImGuiConfigFlags.ViewportsEnable) ~= 0 then ImGui.Text(" ViewportsEnable") end + if io.MouseDrawCursor then ImGui.Text("io.MouseDrawCursor") end + if io.ConfigDpiScaleFonts then ImGui.Text("io.ConfigDpiScaleFonts") end + if io.ConfigDpiScaleViewports then ImGui.Text("io.ConfigDpiScaleViewports") end + if io.ConfigViewportsNoAutoMerge then ImGui.Text("io.ConfigViewportsNoAutoMerge") end + if io.ConfigViewportsNoTaskBarIcon then ImGui.Text("io.ConfigViewportsNoTaskBarIcon") end + if io.ConfigViewportsNoDecoration then ImGui.Text("io.ConfigViewportsNoDecoration") end + if io.ConfigViewportsNoDefaultParent then ImGui.Text("io.ConfigViewportsNoDefaultParent") end + if io.ConfigDockingNoSplit then ImGui.Text("io.ConfigDockingNoSplit") end + if io.ConfigDockingNoDockingOver then ImGui.Text("io.ConfigDockingNoDockingOver") end + if io.ConfigDockingWithShift then ImGui.Text("io.ConfigDockingWithShift") end + if io.ConfigDockingAlwaysTabBar then ImGui.Text("io.ConfigDockingAlwaysTabBar") end + if io.ConfigDockingTransparentPayload then ImGui.Text("io.ConfigDockingTransparentPayload") end + if io.ConfigMacOSXBehaviors then ImGui.Text("io.ConfigMacOSXBehaviors") end + if io.ConfigNavMoveSetMousePos then ImGui.Text("io.ConfigNavMoveSetMousePos") end + if io.ConfigNavCaptureKeyboard then ImGui.Text("io.ConfigNavCaptureKeyboard") end + if io.ConfigInputTextCursorBlink then ImGui.Text("io.ConfigInputTextCursorBlink") end + if io.ConfigWindowsResizeFromEdges then ImGui.Text("io.ConfigWindowsResizeFromEdges") end + if io.ConfigWindowsMoveFromTitleBarOnly then ImGui.Text("io.ConfigWindowsMoveFromTitleBarOnly") end + if io.ConfigMemoryCompactTimer >= 0.0 then ImGui.Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer) end + ImGui.Text("io.BackendFlags: 0x%08X", io.BackendFlags) + if bit32.band(io.BackendFlags, ImGuiBackendFlags.HasGamepad) ~= 0 then ImGui.Text(" HasGamepad") end + if bit32.band(io.BackendFlags, ImGuiBackendFlags.HasMouseCursors) ~= 0 then ImGui.Text(" HasMouseCursors") end + if bit32.band(io.BackendFlags, ImGuiBackendFlags.HasSetMousePos) ~= 0 then ImGui.Text(" HasSetMousePos") end + if bit32.band(io.BackendFlags, ImGuiBackendFlags.PlatformHasViewports) ~= 0 then ImGui.Text(" PlatformHasViewports") end + if bit32.band(io.BackendFlags, ImGuiBackendFlags.HasMouseHoveredViewport) ~= 0 then ImGui.Text(" HasMouseHoveredViewport") end + if bit32.band(io.BackendFlags, ImGuiBackendFlags.HasParentViewport) ~= 0 then ImGui.Text(" HasParentViewport") end + if bit32.band(io.BackendFlags, ImGuiBackendFlags.RendererHasVtxOffset) ~= 0 then ImGui.Text(" RendererHasVtxOffset") end + if bit32.band(io.BackendFlags, ImGuiBackendFlags.RendererHasTextures) ~= 0 then ImGui.Text(" RendererHasTextures") end + if bit32.band(io.BackendFlags, ImGuiBackendFlags.RendererHasViewports) ~= 0 then ImGui.Text(" RendererHasViewports") end + ImGui.Separator() + ImGui.Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts.Fonts.Size, io.Fonts.Flags, io.Fonts.TexData.Width, io.Fonts.TexData.Height) + ImGui.Text("io.Fonts->FontLoaderName: %s", io.Fonts.FontLoaderName or "NULL") + ImGui.Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y) + ImGui.Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y) + ImGui.Separator() + ImGui.Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y) + ImGui.Text("style.WindowBorderSize: %.2f", style.WindowBorderSize) + ImGui.Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y) + ImGui.Text("style.FrameRounding: %.2f", style.FrameRounding) + ImGui.Text("style.FrameBorderSize: %.2f", style.FrameBorderSize) + ImGui.Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y) + ImGui.Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y) + + if copy_to_clipboard then + ImGui.LogText("\n```\n") + ImGui.LogFinish() + end + ImGui.EndChild() + end + ImGui.End() + return p_open +end + +------------------------------------------------------------------------------- +-- [SECTION] Style Editor / ShowStyleEditor() +------------------------------------------------------------------------------- +-- - ShowStyleSelector() +-- - ShowStyleEditor() +------------------------------------------------------------------------------- + +-- [Port] C++ copies ImGuiStyle by value (`dst = src`). Copy fields in place so ImVec2/ImVec4 objects of `dst` keep +-- their identity (the live style's vectors may be referenced elsewhere) and are never aliased with `src`. +function ImGuiStyle_Copy(dst, src) + for k, v in pairs(src) do + if k == "Colors" then + local dst_colors = dst.Colors + for i, col in pairs(v) do + if dst_colors[i] then ImVec4_Copy(dst_colors[i], col) else dst_colors[i] = ImVec4(col.x, col.y, col.z, col.w) end + end + elseif type(v) == "table" then -- ImVec2 + if dst[k] then ImVec2_Copy(dst[k], v) else dst[k] = ImVec2(v.x, v.y) end + else + dst[k] = v + end + end + return dst +end + +S.ShowStyleSelector = { + style_idx = -1, +} +-- Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. +function ImGui.ShowStyleSelector(label) + -- FIXME: This is a bit tricky to get right as style are functions, they don't register a name nor the fact that one is active. + -- So we keep track of last active one among our limited selection. + local s = S.ShowStyleSelector + local style_names = { "Dark", "Light", "Classic" } + local ret = false + if ImGui.BeginCombo(label, (s.style_idx >= 0 and s.style_idx < #style_names) and style_names[s.style_idx + 1] or "") then + for n = 0, #style_names - 1 do + if ImGui.Selectable(style_names[n + 1], s.style_idx == n, ImGuiSelectableFlags.SelectOnNav) then + s.style_idx = n + ret = true + if s.style_idx == 0 then ImGui.StyleColorsDark() + elseif s.style_idx == 1 then ImGui.StyleColorsLight() + elseif s.style_idx == 2 then ImGui.StyleColorsClassic() + end + elseif s.style_idx == n then + ImGui.SetItemDefaultFocus() + end + end + ImGui.EndCombo() + end + return ret +end + +function GetTreeLinesFlagsName(flags) + if flags == ImGuiTreeNodeFlags.DrawLinesNone then return "DrawLinesNone" end + if flags == ImGuiTreeNodeFlags.DrawLinesFull then return "DrawLinesFull" end + if flags == ImGuiTreeNodeFlags.DrawLinesToNodes then return "DrawLinesToNodes" end + return "" +end + +S.ShowStyleEditor = { + ref_saved_style = nil, -- static ImGuiStyle ref_saved_style; (created lazily) + init = true, + output_dest = 0, + output_only_modified = true, + alpha_flags = 0, + filter = nil, -- static ImGuiTextFilter filter; (created lazily) +} +-- We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code. +-- [Port] Lua has no `using namespace`: calls keep the ImGui. prefix +function ImGui.ShowStyleEditor(ref) + local s = S.ShowStyleEditor + local _, changed + IMGUI_DEMO_MARKER("Tools/Style Editor") + -- You can pass in a reference ImGuiStyle structure to compare to, revert to and save to + -- (without a reference style pointer, we will use one compared locally as a reference) + local style = ImGui.GetStyle() + if s.ref_saved_style == nil then s.ref_saved_style = ImGuiStyle() end + + -- Default to using internal storage as reference + if s.init and ref == nil then + ImGuiStyle_Copy(s.ref_saved_style, style) + end + s.init = false + if ref == nil then + ref = s.ref_saved_style + end + + -- The logic behind dynamically changing 'max_border_size' is to not encourage people to increase border size too much: it'll likely reveal lots of subtle rendering artifacts and this isn't a priority right now. + -- Note that _MainScale is currently internal PLEASE DO NOT USE IN YOUR CODE. + local default_border_size = math.floor(style._MainScale) + local max_border_size = ImMax(default_border_size, 2.0) + + ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50) + + do + -- General + ImGui.SeparatorText("General") + if bit32.band(ImGui.GetIO().BackendFlags, ImGuiBackendFlags.RendererHasTextures) == 0 then + ImGui.BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!") + ImGui.BulletText("For instructions, see:") + ImGui.SameLine() + ImGui.TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md") + end + + if ImGui.ShowStyleSelector("Colors##Selector") then + ImGuiStyle_Copy(s.ref_saved_style, style) + end + ImGui.ShowFontSelector("Fonts##Selector") + style.FontSizeBase, changed = ImGui.DragFloat("FontSizeBase", style.FontSizeBase, 0.20, 5.0, 100.0, "%.0f") + if changed then + style._NextFrameFontSizeBase = style.FontSizeBase -- FIXME: Temporary hack until we finish remaining work. + end + ImGui.SameLine(0.0, 0.0); ImGui.Text(" (out %.2f)", ImGui.GetFontSize()) + style.FontScaleMain = ImGui.DragFloat("FontScaleMain", style.FontScaleMain, 0.02, 0.5, 4.0) + ImGui.BeginDisabled(ImGui.GetIO().ConfigDpiScaleFonts == true) -- [Port] field is nil in the port's ImGuiIO (nil would mean "disabled") + style.FontScaleDpi = ImGui.DragFloat("FontScaleDpi", style.FontScaleDpi, 0.02, 0.5, 4.0) + ImGui.SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.") + ImGui.EndDisabled() + + -- Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) + style.FrameRounding, changed = ImGui.SliderFloat("FrameRounding", style.FrameRounding, 0.0, 12.0, "%.0f") + if changed then + style.GrabRounding = style.FrameRounding -- Make GrabRounding always the same value as FrameRounding + end + do local pressed, border = ImGui.Checkbox("WindowBorder", style.WindowBorderSize > 0.0); if pressed then if border then style.WindowBorderSize = default_border_size else style.WindowBorderSize = 0.0 end end end + ImGui.SameLine() + do local pressed, border = ImGui.Checkbox("FrameBorder", style.FrameBorderSize > 0.0); if pressed then if border then style.FrameBorderSize = default_border_size else style.FrameBorderSize = 0.0 end end end + ImGui.SameLine() + do local pressed, border = ImGui.Checkbox("PopupBorder", style.PopupBorderSize > 0.0); if pressed then if border then style.PopupBorderSize = default_border_size else style.PopupBorderSize = 0.0 end end end + end + + -- Save/Revert button + if ImGui.Button("Save Ref") then + ImGuiStyle_Copy(ref, ImGuiStyle_Copy(s.ref_saved_style, style)) + end + ImGui.SameLine() + if ImGui.Button("Revert Ref") then + ImGuiStyle_Copy(style, ref) + end + ImGui.SameLine() + HelpMarker( + "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " .. + "Use \"Export\" below to save them somewhere.") + + ImGui.SeparatorText("Details") + if ImGui.BeginTabBar("##tabs", ImGuiTabBarFlags.None) then + if ImGui.BeginTabItem("Sizes") then + ImGui.SeparatorText("Main") + ImGui.SliderFloat2("WindowPadding", style.WindowPadding, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("FramePadding", style.FramePadding, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("ItemSpacing", style.ItemSpacing, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("ItemInnerSpacing", style.ItemInnerSpacing, 0.0, 20.0, "%.0f") + ImGui.SliderFloat2("TouchExtraPadding", style.TouchExtraPadding, 0.0, 10.0, "%.0f") + style.IndentSpacing = ImGui.SliderFloat("IndentSpacing", style.IndentSpacing, 0.0, 30.0, "%.0f") + style.GrabMinSize = ImGui.SliderFloat("GrabMinSize", style.GrabMinSize, 1.0, 20.0, "%.0f") + + ImGui.SeparatorText("Borders") + style.WindowBorderSize = ImGui.SliderFloat("WindowBorderSize", style.WindowBorderSize, 0.0, max_border_size, "%.0f") + style.ChildBorderSize = ImGui.SliderFloat("ChildBorderSize", style.ChildBorderSize, 0.0, max_border_size, "%.0f") + style.PopupBorderSize = ImGui.SliderFloat("PopupBorderSize", style.PopupBorderSize, 0.0, max_border_size, "%.0f") + style.FrameBorderSize = ImGui.SliderFloat("FrameBorderSize", style.FrameBorderSize, 0.0, max_border_size, "%.0f") + + ImGui.SeparatorText("Rounding") + style.WindowRounding = ImGui.SliderFloat("WindowRounding", style.WindowRounding, 0.0, 12.0, "%.0f") + style.ChildRounding = ImGui.SliderFloat("ChildRounding", style.ChildRounding, 0.0, 12.0, "%.0f") + style.FrameRounding = ImGui.SliderFloat("FrameRounding", style.FrameRounding, 0.0, 12.0, "%.0f") + style.PopupRounding = ImGui.SliderFloat("PopupRounding", style.PopupRounding, 0.0, 12.0, "%.0f") + style.GrabRounding = ImGui.SliderFloat("GrabRounding", style.GrabRounding, 0.0, 12.0, "%.0f") + style.MenuItemRounding = ImGui.SliderFloat("MenuItemRounding", style.MenuItemRounding, 0.0, 12.0, "%.0f") + -- NB: SelectableRounding is intentionally NOT made visible here. We don't want to encourage people using that. + + ImGui.SeparatorText("Scrollbar") + style.ScrollbarSize = ImGui.SliderFloat("ScrollbarSize", style.ScrollbarSize, 1.0, 20.0, "%.0f") + style.ScrollbarRounding = ImGui.SliderFloat("ScrollbarRounding", style.ScrollbarRounding, 0.0, 12.0, "%.0f") + style.ScrollbarPadding = ImGui.SliderFloat("ScrollbarPadding", style.ScrollbarPadding, 0.0, 10.0, "%.0f") + + ImGui.SeparatorText("Tabs") + style.TabBorderSize = ImGui.SliderFloat("TabBorderSize", style.TabBorderSize, 0.0, max_border_size, "%.0f") + style.TabBarBorderSize = ImGui.SliderFloat("TabBarBorderSize", style.TabBarBorderSize, 0.0, max_border_size, "%.0f") + style.TabBarOverlineSize = ImGui.SliderFloat("TabBarOverlineSize", style.TabBarOverlineSize, 0.0, ImMax(3.0, max_border_size), "%.0f") + ImGui.SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.") + style.TabMinWidthBase = ImGui.DragFloat("TabMinWidthBase", style.TabMinWidthBase, 0.5, 1.0, 500.0, "%.0f") + style.TabMinWidthShrink = ImGui.DragFloat("TabMinWidthShrink", style.TabMinWidthShrink, 0.5, 1.0, 500.0, "%0.f") + style.TabCloseButtonMinWidthSelected = ImGui.DragFloat("TabCloseButtonMinWidthSelected", style.TabCloseButtonMinWidthSelected, 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthSelected < 0.0) and "%.0f (Always)" or "%.0f") + style.TabCloseButtonMinWidthUnselected = ImGui.DragFloat("TabCloseButtonMinWidthUnselected", style.TabCloseButtonMinWidthUnselected, 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthUnselected < 0.0) and "%.0f (Always)" or "%.0f") + style.TabRounding = ImGui.SliderFloat("TabRounding", style.TabRounding, 0.0, 12.0, "%.0f") + + ImGui.SeparatorText("Tables") + ImGui.SliderFloat2("CellPadding", style.CellPadding, 0.0, 20.0, "%.0f") + style.TableAngledHeadersAngle = ImGui.SliderAngle("TableAngledHeadersAngle", style.TableAngledHeadersAngle, -50.0, 50.0) + ImGui.SliderFloat2("TableAngledHeadersTextAlign", style.TableAngledHeadersTextAlign, 0.0, 1.0, "%.2f") + + ImGui.SeparatorText("Trees") + local combo_open = ImGui.BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)) + ImGui.SameLine() + HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode.") + if combo_open then + local options = { ImGuiTreeNodeFlags.DrawLinesNone, ImGuiTreeNodeFlags.DrawLinesFull, ImGuiTreeNodeFlags.DrawLinesToNodes } + for _, option in ipairs(options) do + if ImGui.Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option) then + style.TreeLinesFlags = option + end + end + ImGui.EndCombo() + end + style.TreeLinesSize = ImGui.SliderFloat("TreeLinesSize", style.TreeLinesSize, 0.0, max_border_size, "%.0f") + style.TreeLinesRounding = ImGui.SliderFloat("TreeLinesRounding", style.TreeLinesRounding, 0.0, 12.0, "%.0f") + + ImGui.SeparatorText("Windows") + ImGui.SliderFloat2("WindowTitleAlign", style.WindowTitleAlign, 0.0, 1.0, "%.2f") + style.WindowBorderHoverPadding = ImGui.SliderFloat("WindowBorderHoverPadding", style.WindowBorderHoverPadding, 1.0, 20.0, "%.0f") + local window_menu_button_position = style.WindowMenuButtonPosition + 1 + window_menu_button_position, changed = ImGui.Combo("WindowMenuButtonPosition", window_menu_button_position, "None\0Left\0Right\0") + if changed then + style.WindowMenuButtonPosition = window_menu_button_position - 1 + end + + ImGui.SeparatorText("Widgets") + style.ColorMarkerSize = ImGui.SliderFloat("ColorMarkerSize", style.ColorMarkerSize, 0.0, 8.0, "%.0f") + style.ColorButtonPosition = ImGui.Combo("ColorButtonPosition", style.ColorButtonPosition, "Left\0Right\0") + ImGui.SliderFloat2("ButtonTextAlign", style.ButtonTextAlign, 0.0, 1.0, "%.2f") + ImGui.SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.") + ImGui.SliderFloat2("SelectableTextAlign", style.SelectableTextAlign, 0.0, 1.0, "%.2f") + ImGui.SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.") + style.SeparatorSize = ImGui.SliderFloat("SeparatorSize", style.SeparatorSize, 0.0, 10.0, "%.0f") + style.SeparatorTextBorderSize = ImGui.SliderFloat("SeparatorTextBorderSize", style.SeparatorTextBorderSize, 0.0, 10.0, "%.0f") + ImGui.SliderFloat2("SeparatorTextAlign", style.SeparatorTextAlign, 0.0, 1.0, "%.2f") + ImGui.SliderFloat2("SeparatorTextPadding", style.SeparatorTextPadding, 0.0, 40.0, "%.0f") + style.LogSliderDeadzone = ImGui.SliderFloat("LogSliderDeadzone", style.LogSliderDeadzone, 0.0, 12.0, "%.0f") + style.ImageRounding = ImGui.SliderFloat("ImageRounding", style.ImageRounding, 0.0, 12.0, "%.0f") + style.ImageBorderSize = ImGui.SliderFloat("ImageBorderSize", style.ImageBorderSize, 0.0, max_border_size, "%.0f") + + ImGui.SeparatorText("Docking") + --SetCursorPosX(GetCursorPosX() + CalcItemWidth() - GetFrameHeight()); + _, style.DockingNodeHasCloseButton = ImGui.Checkbox("DockingNodeHasCloseButton", style.DockingNodeHasCloseButton) + style.DockingSeparatorSize = ImGui.SliderFloat("DockingSeparatorSize", style.DockingSeparatorSize, 0.0, 12.0, "%.0f") + + ImGui.SeparatorText("Tooltips") + for n = 0, 1 do + if ImGui.TreeNodeEx(n == 0 and "HoverFlagsForTooltipMouse" or "HoverFlagsForTooltipNav") then + local p = (n == 0) and "HoverFlagsForTooltipMouse" or "HoverFlagsForTooltipNav" -- [Port] pointer -> field name + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_DelayNone", style[p], ImGuiHoveredFlags.DelayNone) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_DelayShort", style[p], ImGuiHoveredFlags.DelayShort) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_DelayNormal", style[p], ImGuiHoveredFlags.DelayNormal) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_Stationary", style[p], ImGuiHoveredFlags.Stationary) + _, style[p] = ImGui.CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", style[p], ImGuiHoveredFlags.NoSharedDelay) + ImGui.TreePop() + end + end + + ImGui.SeparatorText("Misc") + ImGui.SliderFloat2("DisplayWindowPadding", style.DisplayWindowPadding, 0.0, 30.0, "%.0f"); ImGui.SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.") + ImGui.SliderFloat2("DisplaySafeAreaPadding", style.DisplaySafeAreaPadding, 0.0, 30.0, "%.0f"); ImGui.SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).") + + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Colors") then + if ImGui.Button("Export") then + if s.output_dest == 0 then + ImGui.LogToClipboard() + else + ImGui.LogToTTY() + end + ImGui.LogText("ImVec4* colors = GetStyle().Colors;" .. "\n") -- [Port] IM_NEWLINE == "\n" + for i = 0, ImGuiCol.COUNT - 1 do + local col = style.Colors[i] + local name = ImGui.GetStyleColorName(i) + if not s.output_only_modified or col ~= ref.Colors[i] then -- [Port] memcmp -> ImVec4 __eq + ImGui.LogText("colors[ImGuiCol_%s]%s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" .. "\n", + name, string.rep(" ", 23 - #name), col.x, col.y, col.z, col.w) -- [Port] "%*s" -> string.rep + end + end + ImGui.LogFinish() + end + ImGui.SameLine(); ImGui.SetNextItemWidth(ImGui.GetFontSize() * 10); s.output_dest = ImGui.Combo("##output_type", s.output_dest, "To Clipboard\0To TTY\0") + ImGui.SameLine(); _, s.output_only_modified = ImGui.Checkbox("Only Modified Colors", s.output_only_modified) + + -- [Port] RadioButton(label, bool active) overload is RadioButtonEx() in the port + if ImGui.RadioButtonEx("Opaque", s.alpha_flags == ImGuiColorEditFlags.AlphaOpaque) then s.alpha_flags = ImGuiColorEditFlags.AlphaOpaque end ImGui.SameLine() + if ImGui.RadioButtonEx("Alpha", s.alpha_flags == ImGuiColorEditFlags.None) then s.alpha_flags = ImGuiColorEditFlags.None end ImGui.SameLine() + if ImGui.RadioButtonEx("Both", s.alpha_flags == ImGuiColorEditFlags.AlphaPreviewHalf) then s.alpha_flags = ImGuiColorEditFlags.AlphaPreviewHalf end ImGui.SameLine() + HelpMarker( + "In the color list:\n" .. + "Left-click on color square to open color picker,\n" .. + "Right-click to open edit options menu.") + + if s.filter == nil then s.filter = ImGuiTextFilter() end + ImGui.SetNextItemWidth(-FLT_MIN) + s.filter:DrawWithHint("##FilterColors", "Filter Colors (incl -excl)") + + ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX)) + ImGui.BeginChild("##colors", ImVec2(0, 0), bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.NavFlattened), bit32.bor(ImGuiWindowFlags.AlwaysVerticalScrollbar, ImGuiWindowFlags.AlwaysHorizontalScrollbar)) + ImGui.PushItemWidth(ImGui.GetFontSize() * -12) + for i = 0, ImGuiCol.COUNT - 1 do repeat + local name = ImGui.GetStyleColorName(i) + if not s.filter:PassFilter(name) then + break -- continue + end + ImGui.PushID(i) + if ImGui.Button("?") then + if ImGui.DebugFlashStyleColor then ImGui.DebugFlashStyleColor(i) end -- [Port] DebugFlashStyleColor() is not in the library yet + end + ImGui.SetItemTooltip("Flash given color to identify places where it is used.") + ImGui.SameLine() + ImGui.ColorEdit4("##color", style.Colors[i], bit32.bor(ImGuiColorEditFlags.AlphaBar, s.alpha_flags)) + if style.Colors[i] ~= ref.Colors[i] then -- [Port] memcmp -> ImVec4 __eq + -- Tips: in a real user application, you may want to merge and use an icon font into the main font, + -- so instead of "Save"/"Revert" you'd use icons! + -- Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! + ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Save") then ImVec4_Copy(ref.Colors[i], style.Colors[i]) end + ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Revert") then ImVec4_Copy(style.Colors[i], ref.Colors[i]) end + end + ImGui.SameLine(0.0, style.ItemInnerSpacing.x) + ImGui.TextUnformatted(name) + ImGui.PopID() + until true end + ImGui.PopItemWidth() + ImGui.EndChild() + + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Fonts") then + local io = ImGui.GetIO() + local atlas = io.Fonts + ImGui.ShowFontAtlas(atlas) + + -- Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. + -- (we enforce hard clamping manually as by default DragFloat/SliderFloat allows Ctrl+Click text to get out of bounds). + --[[ + SeparatorText("Legacy Scaling"); + const float MIN_SCALE = 0.3f; + const float MAX_SCALE = 2.0f; + HelpMarker( + "Those are old settings provided for convenience.\n" + "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, " + "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" + "Using those settings here will give you poor quality results."); + PushItemWidth(GetFontSize() * 8); + DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything + //static float window_scale = 1.0f; + //if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window + // SetWindowFontScale(window_scale); + PopItemWidth(); + ]] + + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Rendering") then + _, style.AntiAliasedLines = ImGui.Checkbox("Anti-aliased lines", style.AntiAliasedLines) + ImGui.SameLine() + HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.") + ImGui.BeginDisabled(style.AntiAliasedLines == false) + _, style.AntiAliasedLineEnds = ImGui.Checkbox("Anti-aliased line ends", style.AntiAliasedLineEnds) + ImGui.EndDisabled() + + ImGui.BeginDisabled() + _, style.AntiAliasedLinesUseTex = ImGui.Checkbox("Anti-aliased lines use texture", style.AntiAliasedLinesUseTex) + ImGui.SameLine() + HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).") + ImGui.EndDisabled() + + _, style.AntiAliasedFill = ImGui.Checkbox("Anti-aliased fill", style.AntiAliasedFill) + local io = ImGui.GetIO() + _, io.ConfigDebugDrawListDefaultsToStrokeLegacy = ImGui.Checkbox("Debug: DrawList Defaults to _StrokeLegacy", io.ConfigDebugDrawListDefaultsToStrokeLegacy == true) -- [Port] field not declared in the port's ImGuiIO + + ImGui.PushItemWidth(ImGui.GetFontSize() * 8) + -- [Port] the library still stores the older style.CurveTessellationTol (== MaxError * MaxError) instead of style.CurveTessellationMaxError + local curve_tessellation_max_error + curve_tessellation_max_error, changed = ImGui.DragFloat("Curve Tessellation Max Error", math.sqrt(style.CurveTessellationTol), 0.02, 0.10, 10.0, "%.2f") + if curve_tessellation_max_error < 0.10 then + curve_tessellation_max_error = 0.10 + changed = true + end + if changed then style.CurveTessellationTol = curve_tessellation_max_error * curve_tessellation_max_error end -- [Port] only write back on change (sqrt/square round-trip is not exact) + + -- When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. + style.CircleTessellationMaxError = ImGui.DragFloat("Circle Tessellation Max Error", style.CircleTessellationMaxError, 0.005, 0.10, 5.0, "%.2f", ImGuiSliderFlags.AlwaysClamp) + local show_samples = ImGui.IsItemActive() + if show_samples then + ImGui.SetNextWindowPos(ImGui.GetCursorScreenPos()) + end + if show_samples and ImGui.BeginTooltip() then + ImGui.TextUnformatted("(R = radius, N = approx number of segments)") + ImGui.Spacing() + local draw_list = ImGui.GetWindowDrawList() + local min_widget_width = ImGui.CalcTextSize("R: MMM\nN: MMM").x + for n = 0, 7 do + local RAD_MIN = 5.0 + local RAD_MAX = 70.0 + local rad = RAD_MIN + (RAD_MAX - RAD_MIN) * n / (8.0 - 1.0) + + ImGui.BeginGroup() + + -- N is not always exact here due to how PathArcTo() function work internally + ImGui.Text("R: %.f\nN: %d", rad, draw_list:_CalcCircleAutoSegmentCount(rad)) + + local canvas_width = ImMax(min_widget_width, rad * 2.0) + local offset_x = math.floor(canvas_width * 0.5) + local offset_y = math.floor(RAD_MAX) + + local p1 = ImGui.GetCursorScreenPos() + draw_list:AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui.GetColorU32(ImGuiCol.Text)) + ImGui.Dummy(ImVec2(canvas_width, RAD_MAX * 2)) + + --[[ + const ImVec2 p2 = GetCursorScreenPos(); + draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, GetColorU32(ImGuiCol_Text)); + Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + ]] + + ImGui.EndGroup() + ImGui.SameLine() + end + ImGui.EndTooltip() + end + ImGui.SameLine() + HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically.") + + style.Alpha = ImGui.DragFloat("Global Alpha", style.Alpha, 0.005, 0.20, 1.0, "%.2f") -- Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. + style.DisabledAlpha = ImGui.DragFloat("Disabled Alpha", style.DisabledAlpha, 0.005, 0.0, 1.0, "%.2f"); ImGui.SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).") + ImGui.PopItemWidth() + + ImGui.EndTabItem() + end + + ImGui.EndTabBar() + end + ImGui.PopItemWidth() +end + +------------------------------------------------------------------------------- +-- [SECTION] User Guide / ShowUserGuide() +------------------------------------------------------------------------------- + +-- We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code. +function ImGui.ShowUserGuide() + local io = ImGui.GetIO() + ImGui.BulletText("Double-click on title bar to collapse window.") + ImGui.BulletText( + "Click and drag on lower corner or border to resize window.\n" .. + "(double-click to auto fit window to its contents)") + ImGui.BulletText("Ctrl+Click on a slider or drag box to input value as text.") + ImGui.BulletText("Tab/Shift+Tab to cycle through keyboard editable fields.") + ImGui.BulletText("Ctrl+Tab/Ctrl+Shift+Tab to focus windows.") + if io.FontAllowUserScaling then + ImGui.BulletText("Ctrl+Mouse Wheel to zoom window contents.") + end + ImGui.BulletText("While inputting text:\n") + ImGui.Indent() + ImGui.BulletText("Ctrl+Left/Right to word jump.") + ImGui.BulletText("Ctrl+A or double-click to select all.") + ImGui.BulletText("Ctrl+X/C/V to use clipboard cut/copy/paste.") + ImGui.BulletText("Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.") + ImGui.BulletText("Escape to revert.") + ImGui.Unindent() + ImGui.BulletText("With Keyboard controls enabled:") + ImGui.Indent() + ImGui.BulletText("Arrow keys or Home/End/PageUp/PageDown to navigate.") + ImGui.BulletText("Space to activate a widget.") + ImGui.BulletText("Return to input text into a widget.") + ImGui.BulletText("Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus.") + ImGui.BulletText("Alt to jump to the menu layer of a window.") + ImGui.BulletText("Menu or Shift+F10 to open a context menu.") + ImGui.Unindent() + ImGui.BulletText("With Gamepad controls enabled:") + ImGui.Indent() + ImGui.BulletText("D-Pad: Navigate / Tweak / Resize (in Windowing mode).") + ImGui.BulletText("%s Face button: Activate / Open / Toggle. Hold: activate with text input.", io.ConfigNavSwapGamepadButtons and "East" or "South") + ImGui.BulletText("%s Face button: Cancel / Close / Exit.", io.ConfigNavSwapGamepadButtons and "South" or "East") + ImGui.BulletText("West Face button: Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows).") + ImGui.BulletText("North Face button: Open Context Menu.") + ImGui.BulletText("L1/R1: Tweak Slower/Faster, Focus Previous/Next (in Windowing Mode).") + ImGui.Unindent() +end + +------------------------------------------------------------------------------- +-- [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +------------------------------------------------------------------------------- +-- - ShowExampleAppMainMenuBar() +-- - ShowExampleMenuFile() +------------------------------------------------------------------------------- + +-- Demonstrate creating a "main" fullscreen menu bar and populating it. +-- Note the difference between BeginMainMenuBar() and BeginMenuBar(): +-- - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags.MenuBar flag!) +-- - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. +function ShowExampleAppMainMenuBar() + if ImGui.BeginMainMenuBar() then + if ImGui.BeginMenu("File") then + IMGUI_DEMO_MARKER("Menu/File") + ShowExampleMenuFile() + ImGui.EndMenu() + end + if ImGui.BeginMenu("Edit") then + IMGUI_DEMO_MARKER("Menu/Edit") + if ImGui.MenuItem("Undo", "Ctrl+Z") then end + if ImGui.MenuItem("Redo", "Ctrl+Y", false, false) then end -- Disabled item + ImGui.Separator() + if ImGui.MenuItem("Cut", "Ctrl+X") then end + if ImGui.MenuItem("Copy", "Ctrl+C") then end + if ImGui.MenuItem("Paste", "Ctrl+V") then end + ImGui.EndMenu() + end + ImGui.EndMainMenuBar() end end -end --[[ imgui_demo_2.lua ]] -do --[[ imgui_demo_apps.lua ]] --- Demo: Example apps (port of imgui_demo.cpp "Example App" sections). Each ShowExampleAppXXX(p_open) returns the new p_open. -local _ -local Buf, BufStr = DemoBuf, DemoBufStr +-- Note that shortcuts are currently provided for display only +-- (future version will add explicit flags to BeginMenu() to request processing shortcuts) +S.ShowExampleMenuFile = { + enabled = true, + f = 0.5, + n = 0, + b = true, +} +function ShowExampleMenuFile() + local s = S.ShowExampleMenuFile + IMGUI_DEMO_MARKER("Examples/Menu") + ImGui.MenuItem("(demo menu)", nil, false, false) + if ImGui.MenuItem("New") then end + if ImGui.MenuItem("Open", "Ctrl+O") then end + if ImGui.BeginMenu("Open Recent") then + ImGui.MenuItem("fish_hat.c") + ImGui.MenuItem("fish_hat.inl") + ImGui.MenuItem("fish_hat.h") + if ImGui.BeginMenu("More..") then + ImGui.MenuItem("Hello") + ImGui.MenuItem("Sailor") + if ImGui.BeginMenu("Recurse..") then + ShowExampleMenuFile() + ImGui.EndMenu() + end + ImGui.EndMenu() + end + ImGui.EndMenu() + end + if ImGui.MenuItem("Save", "Ctrl+S") then end + if ImGui.MenuItem("Save As..") then end -local function BufSet(buf, str) - for i = 1, #str do buf[i] = string.byte(str, i) end - buf[#str + 1] = 0 + ImGui.Separator() + if ImGui.BeginMenu("Options") then + IMGUI_DEMO_MARKER("Examples/Menu/Options") + _, s.enabled = ImGui.MenuItem("Enabled", "", s.enabled) + ImGui.BeginChild("child", ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 5.0), ImGuiChildFlags.Borders) + for i = 0, 10 - 1 do + ImGui.Text("Scrolling Text %d", i) + end + ImGui.EndChild() + s.f = ImGui.SliderFloat("Value", s.f, 0.0, 1.0) + s.f = ImGui.InputFloat("Input", s.f, 0.1) + s.n = ImGui.Combo("Combo", s.n, "Yes\0No\0Maybe\0\0") + ImGui.EndMenu() + end + + if ImGui.BeginMenu("Colors") then + IMGUI_DEMO_MARKER("Examples/Menu/Colors") + local sz = ImGui.GetTextLineHeight() + for i = 0, ImGuiCol.COUNT - 1 do + local name = ImGui.GetStyleColorName(i) + local p = ImGui.GetCursorScreenPos() + ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui.GetColorU32(i)) + ImGui.Dummy(ImVec2(sz, sz)) + ImGui.SameLine() + ImGui.MenuItem(name) + end + ImGui.EndMenu() + end + + -- Here we demonstrate appending again to the "Options" menu (which we already created above) + -- Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. + -- In a real code-base using it would make senses to use this feature from very different code locations. + if ImGui.BeginMenu("Options") then -- <-- Append! + IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu") + _, s.b = ImGui.Checkbox("SomeOption", s.b) + ImGui.EndMenu() + end + + if ImGui.BeginMenu("Disabled", false) then -- Disabled + IM_ASSERT(false) + end + if ImGui.MenuItem("Checked", nil, true) then end + ImGui.Separator() + if ImGui.MenuItem("Quit", "Alt+F4") then end end ------------------------------------------------------------------------------- @@ -4378,245 +8215,383 @@ end -- Demonstrate creating a simple console window, with scrolling, filtering, completion and history. -- For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. -local Console = nil -local function ConsoleNew() - -- HistoryPos: -1: new line, 0..#History-1 browsing history. +ExampleAppConsoleMT = {} +ExampleAppConsoleMT.__index = ExampleAppConsoleMT +function ExampleAppConsole() + local self = setmetatable({}, ExampleAppConsoleMT) + self.InputBuf = nil -- char InputBuf[256] + self.Items = ImVector() -- ImVector + self.Commands = ImVector() -- ImVector + self.History = ImVector() -- ImVector + self.HistoryPos = 0 -- -1: new line, 0..History.Size-1 browsing history. + self.Filter = ImGuiTextFilter() + self.AutoScroll = false + self.ScrollToBottom = false + + self:ClearLog() + self.InputBuf = ImGui.NewTextBuffer("", 256) -- memset(InputBuf, 0, sizeof(InputBuf)) + self.HistoryPos = -1 + -- "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches. - local c = { InputBuf = Buf("", 256), Items = {}, Commands = { "HELP", "HISTORY", "CLEAR", "CLASSIFY" }, History = {}, - HistoryPos = -1, Filter = ImGuiTextFilter(), AutoScroll = true, ScrollToBottom = false } - function c:ClearLog() self.Items = {} end - function c:AddLog(fmt, ...) - -- FIXME-OPT - local s = (select("#", ...) > 0) and string.format(fmt, ...) or fmt - self.Items[#self.Items + 1] = s - end - function c:ExecCommand(command_line) - self:AddLog("# %s\n", command_line) + self.Commands:push_back("HELP") + self.Commands:push_back("HISTORY") + self.Commands:push_back("CLEAR") + self.Commands:push_back("CLASSIFY") + self.AutoScroll = true + self.ScrollToBottom = false + self:AddLog("Welcome to Dear ImGui!") + return self +end +-- [Port] ~ExampleAppConsole(): nothing to free (GC) - -- Insert into history. First find match and delete it so it can be pushed to the back. - -- This isn't trying to be smart or optimal. - self.HistoryPos = -1 - for i = #self.History, 1, -1 do - if string.upper(self.History[i]) == string.upper(command_line) then table.remove(self.History, i); break end - end - self.History[#self.History + 1] = command_line +-- Portable helpers +do + local function toupper(c) if c >= 97 and c <= 122 then return c - 32 end return c end -- [Port] C toupper() on bytes + function ExampleAppConsoleMT.Stricmp(s1, s2) local i = 1; local d; while true do local c1 = string.byte(s1, i) or 0; d = toupper(string.byte(s2, i) or 0) - toupper(c1); if d ~= 0 or c1 == 0 then break end; i = i + 1 end; return d end + function ExampleAppConsoleMT.Strnicmp(s1, s2, n) local i = 1; local d = 0; while n > 0 do local c1 = string.byte(s1, i) or 0; d = toupper(string.byte(s2, i) or 0) - toupper(c1); if d ~= 0 or c1 == 0 then break end; i = i + 1; n = n - 1 end; return d end + function ExampleAppConsoleMT.Strdup(s) IM_ASSERT(s); return s end -- [Port] Lua strings are immutable values + function ExampleAppConsoleMT.Strtrimblanks(s) local str_end = 0; while s[str_end + 1] ~= nil and s[str_end + 1] ~= 0 do str_end = str_end + 1 end; while str_end > 0 and s[str_end] == 32 do str_end = str_end - 1 end; s[str_end + 1] = 0 end + ExampleAppConsoleMT.toupper = toupper -- [Port] used by TextEditCallback() +end - -- Process command - local cmd = string.upper(command_line) - if cmd == "CLEAR" then - self:ClearLog() - elseif cmd == "HELP" then - self:AddLog("Commands:") - for i = 1, #self.Commands do self:AddLog("- %s", self.Commands[i]) end - elseif cmd == "HISTORY" then - local first = #self.History - 10 - for i = math.max(first, 0), #self.History - 1 do self:AddLog("%3d: %s\n", i, self.History[i + 1]) end - else - self:AddLog("Unknown command: '%s'\n", command_line) - end +function ExampleAppConsoleMT:ClearLog() + -- [Port] ImGui::MemFree(Items[i]) not needed (GC) + self.Items:clear() +end - -- On command input, we scroll to bottom even if AutoScroll==false - self.ScrollToBottom = true - end - function c:TextEditCallback(data) - --self:AddLog("cursor: %d, selection: %d-%d", data.CursorPos, data.SelectionStart, data.SelectionEnd) - if data.EventFlag == ImGuiInputTextFlags.CallbackCompletion then - -- Example of TEXT COMPLETION +function ExampleAppConsoleMT:AddLog(fmt, ...) + -- FIXME-OPT + local buf = string.format(fmt, ...) + buf = string.sub(buf, 1, 1024 - 1) -- [Port] vsnprintf() into char buf[1024] + self.Items:push_back(ExampleAppConsoleMT.Strdup(buf)) +end - -- Locate beginning of current word (positions are 0-based offsets into data.Buf) - local word_end = data.CursorPos - local word_start = word_end - while word_start > 0 do - local ch = data.Buf[word_start] - if ch == 32 or ch == 9 or ch == 44 or ch == 59 then break end - word_start = word_start - 1 - end - local word = "" - for i = word_start + 1, word_end do word = word .. string.char(data.Buf[i]) end - - -- Build a list of candidates - local candidates = {} - for i = 1, #self.Commands do - if string.upper(string.sub(self.Commands[i], 1, #word)) == string.upper(word) then candidates[#candidates + 1] = self.Commands[i] end - end - if #candidates == 0 then - -- No match - self:AddLog("No match for \"%s\"!\n", word) - elseif #candidates == 1 then - -- Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. - data:DeleteChars(word_start, word_end - word_start) - data:InsertChars(data.CursorPos, candidates[1]) - data:InsertChars(data.CursorPos, " ") - else - -- Multiple matches. Complete as much as we can.. - -- So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. - local match_len = word_end - word_start - while true do - local ch, all_match = nil, true - for i = 1, #candidates do - local cc = string.upper(string.sub(candidates[i], match_len + 1, match_len + 1)) - if i == 1 then ch = cc elseif ch == "" or ch ~= cc then all_match = false; break end - end - if not all_match or ch == "" then break end - match_len = match_len + 1 - end - if match_len > 0 then - data:DeleteChars(word_start, word_end - word_start) - data:InsertChars(data.CursorPos, string.sub(candidates[1], 1, match_len)) - end - - -- List matches - self:AddLog("Possible matches:\n") - for i = 1, #candidates do self:AddLog("- %s\n", candidates[i]) end - end - elseif data.EventFlag == ImGuiInputTextFlags.CallbackHistory then - -- Example of HISTORY - local prev_history_pos = self.HistoryPos - if data.EventKey == ImGuiKey.UpArrow then - if self.HistoryPos == -1 then self.HistoryPos = #self.History - 1 - elseif self.HistoryPos > 0 then self.HistoryPos = self.HistoryPos - 1 end - elseif data.EventKey == ImGuiKey.DownArrow then - if self.HistoryPos ~= -1 then - self.HistoryPos = self.HistoryPos + 1 - if self.HistoryPos >= #self.History then self.HistoryPos = -1 end - end - end - - -- A better implementation would preserve the data on the current input line along with cursor position. - if prev_history_pos ~= self.HistoryPos then - local history_str = (self.HistoryPos >= 0) and self.History[self.HistoryPos + 1] or "" - data:DeleteChars(0, data.BufTextLen) - data:InsertChars(0, history_str) - end - end - return 0 - end - function c:Draw(title, p_open) - ImGui.SetNextWindowSize(ImVec2(520, 600), ImGuiCond.FirstUseEver) - local visible - p_open, visible = ImGui.Begin(title, p_open) - if not visible then ImGui.End(); return p_open end - - -- As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. - -- So e.g. IsItemHovered() will return true when hovering the title bar. - -- Here we create a context menu only available from the title bar. - if ImGui.BeginPopupContextItem() then - if ImGui.MenuItem("Close Console") then p_open = false end - ImGui.EndPopup() - end - ImGui.TextWrapped("This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc.") - ImGui.TextWrapped("Enter 'HELP' for help.") - - -- TODO: display items starting from the bottom - - if ImGui.SmallButton("Add Debug Text") then self:AddLog("%d some text", #self.Items); self:AddLog("some more text"); self:AddLog("display very important message here!") end - ImGui.SameLine() - if ImGui.SmallButton("Add Debug Error") then self:AddLog("[error] something went wrong") end - ImGui.SameLine() - if ImGui.SmallButton("Clear") then self:ClearLog() end - ImGui.SameLine() - local copy_to_clipboard = ImGui.SmallButton("Copy") - --local t = 0.0; if ImGui.GetTime() - t > 0.02 then t = ImGui.GetTime(); self:AddLog("Spam %f", t) end - - ImGui.Separator() - - -- Options menu - if ImGui.BeginPopup("Options") then - _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) - ImGui.EndPopup() - end - - -- Options, Filter - ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.O), ImGuiInputFlags.Tooltip) - if ImGui.Button("Options") then ImGui.OpenPopup("Options") end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.F), ImGuiInputFlags.Tooltip) - ImGui.SetNextItemWidth(-FLT_MIN) - self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") - ImGui.Separator() - - -- Reserve enough left-over height for 1 separator + 1 input text - local style = ImGui.GetStyle() - local footer_height_to_reserve = (style.SeparatorSize or 1.0) + style.ItemSpacing.y + ImGui.GetFrameHeightWithSpacing() - if ImGui.BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags.NavFlattened, ImGuiWindowFlags.HorizontalScrollbar) then - if ImGui.BeginPopupContextWindow() then - if ImGui.Selectable("Clear") then self:ClearLog() end - ImGui.EndPopup() - end - - -- Display every line as a separate entry so we can change their color or add custom widgets. - -- If you only want raw text you can use ImGui.TextUnformatted(log.begin(), log.end()) - -- NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping - -- to only process visible items. The clipper will automatically measure the height of your first item and then - -- "seek" to display only items in the visible area. - -- To use the clipper we can replace your standard loop: - -- for i = 1, #Items do - -- With: - -- local clipper = ImGuiListClipper() - -- clipper:Begin(#Items) - -- while clipper:Step() do - -- for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do - -- - That your items are evenly spaced (same height) - -- - That you have cheap random access to your elements (you can access them given their index, - -- without processing all the ones before) - -- You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. - -- We would need random-access on the post-filtered list. - -- A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices - -- or offsets of items that passed the filtering test, recomputing this array when user changes the filter, - -- and appending newly elements as they are inserted. This is left as a task to the user until we can manage - -- to improve this example code! - -- If your items are of variable height: - -- - Split them into same height items would be simpler and facilitate random-seeking into your list. - -- - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(4, 1)) -- Tighten spacing - if copy_to_clipboard then ImGui.LogToClipboard() end - for _, item in ipairs(self.Items) do - if self.Filter:PassFilter(item) then - -- Normally you would store more information in your item than just a string. - -- (e.g. make Items[] an array of structure, store color/type etc.) - local color - if string.find(item, "[error]", 1, true) then color = ImVec4(1.0, 0.4, 0.4, 1.0) - elseif string.sub(item, 1, 2) == "# " then color = ImVec4(1.0, 0.8, 0.6, 1.0) end - if color then ImGui.PushStyleColor(ImGuiCol.Text, color) end - ImGui.TextUnformatted(item) - if color then ImGui.PopStyleColor() end - end - end - if copy_to_clipboard then ImGui.LogFinish() end - - -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. - -- Using a scrollbar or mouse-wheel will take away from the bottom edge. - if self.ScrollToBottom or (self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY()) then ImGui.SetScrollHereY(1.0) end - self.ScrollToBottom = false - ImGui.PopStyleVar() - end - ImGui.EndChild() - ImGui.Separator() - - -- Command-line - local reclaim_focus = false - local IT = ImGuiInputTextFlags - local input_text_flags = bit32.bor(IT.EnterReturnsTrue, IT.EscapeClearsAll, IT.CallbackCompletion, IT.CallbackHistory) - if ImGui.InputText("Input", self.InputBuf, 256, input_text_flags, function(data) return self:TextEditCallback(data) end) then - local s = string.gsub(BufStr(self.InputBuf), " +$", "") - if s ~= "" then self:ExecCommand(s) end - self.InputBuf[1] = 0 - reclaim_focus = true - end - - -- Auto-focus on window apparition - ImGui.SetItemDefaultFocus() - if reclaim_focus then ImGui.SetKeyboardFocusHere(-1) end -- Auto focus previous widget +function ExampleAppConsoleMT:Draw(title, p_open) + ImGui.SetNextWindowSize(ImVec2(520, 600), ImGuiCond.FirstUseEver) + local visible + p_open, visible = ImGui.Begin(title, p_open) + if not visible then ImGui.End() return p_open end - c:AddLog("Welcome to Dear ImGui!") - return c + IMGUI_DEMO_MARKER("Examples/Console") + + -- As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. + -- So e.g. IsItemHovered() will return true when hovering the title bar. + -- Here we create a context menu only available from the title bar. + if ImGui.BeginPopupContextItem() then + if ImGui.MenuItem("Close Console") then + p_open = false + end + ImGui.EndPopup() + end + + ImGui.TextWrapped( + "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " .. + "implementation may want to store entries along with extra data such as timestamp, emitter, etc.") + ImGui.TextWrapped("Enter 'HELP' for help.") + + -- TODO: display items starting from the bottom + + if ImGui.SmallButton("Add Debug Text") then self:AddLog("%d some text", self.Items.Size); self:AddLog("some more text"); self:AddLog("display very important message here!") end + ImGui.SameLine() + if ImGui.SmallButton("Add Debug Error") then self:AddLog("[error] something went wrong") end + ImGui.SameLine() + if ImGui.SmallButton("Clear") then self:ClearLog() end + ImGui.SameLine() + local copy_to_clipboard = ImGui.SmallButton("Copy") + --static float t = 0.0f; if (ImGui.GetTime() - t > 0.02f) { t = ImGui.GetTime(); AddLog("Spam %f", t); } + + ImGui.Separator() + + -- Options menu + if ImGui.BeginPopup("Options") then + _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) + ImGui.EndPopup() + end + + -- Options, Filter + ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.O), ImGuiInputFlags.Tooltip) + if ImGui.Button("Options") then + ImGui.OpenPopup("Options") + end + ImGui.SameLine() + + ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.F), ImGuiInputFlags.Tooltip) + ImGui.SetNextItemWidth(-FLT_MIN) + self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") + ImGui.Separator() + + -- Reserve enough left-over height for 1 separator + 1 input text + local style = ImGui.GetStyle() + local footer_height_to_reserve = style.SeparatorSize + style.ItemSpacing.y + ImGui.GetFrameHeightWithSpacing() + if ImGui.BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags.NavFlattened, ImGuiWindowFlags.HorizontalScrollbar) then + if ImGui.BeginPopupContextWindow() then + if ImGui.Selectable("Clear") then self:ClearLog() end + ImGui.EndPopup() + end + + -- Display every line as a separate entry so we can change their color or add custom widgets. + -- If you only want raw text you can use ImGui.TextUnformatted(log.begin(), log.end()); + -- NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping + -- to only process visible items. The clipper will automatically measure the height of your first item and then + -- "seek" to display only items in the visible area. + -- To use the clipper we can replace your standard loop: + -- for (int i = 0; i < Items.Size; i++) + -- With: + -- ImGuiListClipper clipper; + -- clipper.Begin(Items.Size); + -- while (clipper.Step()) + -- for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + -- - That your items are evenly spaced (same height) + -- - That you have cheap random access to your elements (you can access them given their index, + -- without processing all the ones before) + -- You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. + -- We would need random-access on the post-filtered list. + -- A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices + -- or offsets of items that passed the filtering test, recomputing this array when user changes the filter, + -- and appending newly elements as they are inserted. This is left as a task to the user until we can manage + -- to improve this example code! + -- If your items are of variable height: + -- - Split them into same height items would be simpler and facilitate random-seeking into your list. + -- - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(4, 1)) -- Tighten spacing + if copy_to_clipboard then + ImGui.LogToClipboard() + end + for _, item in self.Items:iter() do repeat + if not self.Filter:PassFilter(item) then + break -- continue + end + + -- Normally you would store more information in your item than just a string. + -- (e.g. make Items[] an array of structure, store color/type etc.) + local color + local has_color = false + if string.find(item, "[error]", 1, true) then color = ImVec4(1.0, 0.4, 0.4, 1.0); has_color = true + elseif string.sub(item, 1, 2) == "# " then color = ImVec4(1.0, 0.8, 0.6, 1.0); has_color = true end + if has_color then + ImGui.PushStyleColor(ImGuiCol.Text, color) + end + ImGui.TextUnformatted(item) + if has_color then + ImGui.PopStyleColor() + end + until true end + if copy_to_clipboard then + ImGui.LogFinish() + end + + -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. + -- Using a scrollbar or mouse-wheel will take away from the bottom edge. + if self.ScrollToBottom or (self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY()) then + ImGui.SetScrollHereY(1.0) + end + self.ScrollToBottom = false + + ImGui.PopStyleVar() + end + ImGui.EndChild() + ImGui.Separator() + + -- Command-line + local reclaim_focus = false + local input_text_flags = bit32.bor(ImGuiInputTextFlags.EnterReturnsTrue, ImGuiInputTextFlags.EscapeClearsAll, ImGuiInputTextFlags.CallbackCompletion, ImGuiInputTextFlags.CallbackHistory) + if ImGui.InputText("Input", self.InputBuf, 256, input_text_flags, ExampleAppConsoleMT.TextEditCallbackStub, self) then + local s = self.InputBuf + ExampleAppConsoleMT.Strtrimblanks(s) + if s[1] ~= 0 then + self:ExecCommand(ImGui.TextBufferToString(s)) + end + s[1] = 0 + reclaim_focus = true + end + + -- Auto-focus on window apparition + ImGui.SetItemDefaultFocus() + if reclaim_focus then + ImGui.SetKeyboardFocusHere(-1) -- Auto focus previous widget + end + + ImGui.End() + return p_open end +function ExampleAppConsoleMT:ExecCommand(command_line) + local Stricmp = ExampleAppConsoleMT.Stricmp + self:AddLog("# %s\n", command_line) + + -- Insert into history. First find match and delete it so it can be pushed to the back. + -- This isn't trying to be smart or optimal. + self.HistoryPos = -1 + for i = self.History.Size - 1, 0, -1 do + if Stricmp(self.History.Data[i + 1], command_line) == 0 then + self.History:erase(i + 1) + break + end + end + self.History:push_back(ExampleAppConsoleMT.Strdup(command_line)) + + -- Process command + if Stricmp(command_line, "CLEAR") == 0 then + self:ClearLog() + elseif Stricmp(command_line, "HELP") == 0 then + self:AddLog("Commands:") + for i = 0, self.Commands.Size - 1 do + self:AddLog("- %s", self.Commands.Data[i + 1]) + end + elseif Stricmp(command_line, "HISTORY") == 0 then + local first = self.History.Size - 10 + for i = (first > 0) and first or 0, self.History.Size - 1 do + self:AddLog("%3d: %s\n", i, self.History.Data[i + 1]) + end + else + self:AddLog("Unknown command: '%s'\n", command_line) + end + + -- On command input, we scroll to bottom even if AutoScroll==false + self.ScrollToBottom = true +end + +-- In C++11 you'd be better off using lambdas for this sort of forwarding callbacks +function ExampleAppConsoleMT.TextEditCallbackStub(data) + local console = data.UserData + return console:TextEditCallback(data) +end + +-- [Port] data.Buf is a 1-based byte table; positions (CursorPos, word_start, word_end) are 0-based offsets like upstream. +function ExampleAppConsoleMT:TextEditCallback(data) + local toupper = ExampleAppConsoleMT.toupper + --AddLog("cursor: %d, selection: %d-%d", data.CursorPos, data.SelectionStart, data.SelectionEnd) + if data.EventFlag == ImGuiInputTextFlags.CallbackCompletion then + -- Example of TEXT COMPLETION + + -- Locate beginning of current word + local word_end = data.CursorPos + local word_start = word_end + while word_start > 0 do + local c = data.Buf[word_start] -- word_start[-1] + if c == 32 or c == 9 or c == 44 or c == 59 then -- ' ', '\t', ',', ';' + break + end + word_start = word_start - 1 + end + local word = string.char(table.unpack(data.Buf, word_start + 1, word_end)) -- [Port] word_start..word_end as a string + + -- Build a list of candidates + local candidates = ImVector() + for i = 0, self.Commands.Size - 1 do + if ExampleAppConsoleMT.Strnicmp(self.Commands.Data[i + 1], word, word_end - word_start) == 0 then + candidates:push_back(self.Commands.Data[i + 1]) + end + end + + if candidates.Size == 0 then + -- No match + self:AddLog("No match for \"%s\"!\n", word) -- [Port] "%.*s" -> "%s" + elseif candidates.Size == 1 then + -- Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. + data:DeleteChars(word_start, word_end - word_start) + data:InsertChars(data.CursorPos, candidates.Data[1]) + data:InsertChars(data.CursorPos, " ") + else + -- Multiple matches. Complete as much as we can.. + -- So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. + local match_len = word_end - word_start + while true do + local c = 0 + local all_candidates_matches = true + local i = 0 + while i < candidates.Size and all_candidates_matches do + if i == 0 then + c = toupper(string.byte(candidates.Data[i + 1], match_len + 1) or 0) + elseif c == 0 or c ~= toupper(string.byte(candidates.Data[i + 1], match_len + 1) or 0) then + all_candidates_matches = false + end + i = i + 1 + end + if not all_candidates_matches then + break + end + match_len = match_len + 1 + end + + if match_len > 0 then + data:DeleteChars(word_start, word_end - word_start) + data:InsertChars(data.CursorPos, string.sub(candidates.Data[1], 1, match_len)) -- [Port] InsertChars() has no text_end parameter + end + + -- List matches + self:AddLog("Possible matches:\n") + for i = 0, candidates.Size - 1 do + self:AddLog("- %s\n", candidates.Data[i + 1]) + end + end + + elseif data.EventFlag == ImGuiInputTextFlags.CallbackHistory then + -- Example of HISTORY + local prev_history_pos = self.HistoryPos + if data.EventKey == ImGuiKey.UpArrow then + if self.HistoryPos == -1 then + self.HistoryPos = self.History.Size - 1 + elseif self.HistoryPos > 0 then + self.HistoryPos = self.HistoryPos - 1 + end + elseif data.EventKey == ImGuiKey.DownArrow then + if self.HistoryPos ~= -1 then + self.HistoryPos = self.HistoryPos + 1 + if self.HistoryPos >= self.History.Size then + self.HistoryPos = -1 + end + end + end + + -- A better implementation would preserve the data on the current input line along with cursor position. + if prev_history_pos ~= self.HistoryPos then + local history_str = "" + if self.HistoryPos >= 0 then history_str = self.History.Data[self.HistoryPos + 1] end + data:DeleteChars(0, data.BufTextLen) + data:InsertChars(0, history_str) + end + end + return 0 +end + +S.ShowExampleAppConsole = { + console = nil, -- ExampleAppConsole, created on first use +} function ShowExampleAppConsole(p_open) - Console = Console or ConsoleNew() - return Console:Draw("Example: Console", p_open) + local s = S.ShowExampleAppConsole + if s.console == nil then s.console = ExampleAppConsole() end + return s.console:Draw("Example: Console", p_open) +end + +------------------------------------------------------------------------------- +-- [SECTION] Example App: Image Viewer / ShowExampleAppImageViewer() +------------------------------------------------------------------------------- + +S.ShowExampleAppImageViewer = { + image_viewer = nil, -- ExampleImageViewerData, created on first use +} +function ShowExampleAppImageViewer(p_open) + local s = S.ShowExampleAppImageViewer + local atlas = ImGui.GetIO().Fonts + local tex_ref = atlas.TexRef -- We don't have access to other textures in this demo! + local tex_w = atlas.TexData.Width + local tex_h = atlas.TexData.Height + local visible + p_open, visible = ImGui.Begin("Example: Image Viewer", p_open) + if visible then + if s.image_viewer == nil then s.image_viewer = ExampleImageViewerData() end + ExampleImageViewer_DrawOptions(s.image_viewer) + local canvas_size = ImGui.GetContentRegionAvail() + local canvas_min_size + if ImGui.IsWindowAppearing() then canvas_min_size = ImVec2(3.0 * tex_w, 4.0 * tex_h) else canvas_min_size = ImVec2(1.0, 1.0) end + canvas_size = ImVec2(ImMax(canvas_size.x, canvas_min_size.x), ImMax(canvas_size.y, canvas_min_size.y)) + ExampleImageViewer_DrawCanvas(s.image_viewer, canvas_size, tex_ref, tex_w, tex_h) + end + ImGui.End() + return p_open end ------------------------------------------------------------------------------- @@ -4624,115 +8599,166 @@ end ------------------------------------------------------------------------------- -- Usage: --- local my_log = ExampleAppLog() --- my_log:AddLog("Hello %d world\n", 123) --- my_log:Draw("title") --- Lines are stored as a Lua array (equivalent of Buf + LineOffsets) -local function ExampleAppLog() - local l = { Lines = { "" }, Filter = ImGuiTextFilter(), AutoScroll = true } -- AutoScroll: Keep scrolling if already at the bottom. - function l:Clear() self.Lines = { "" } end - function l:AddLog(fmt, ...) - local s = (select("#", ...) > 0) and string.format(fmt, ...) or fmt - local lines = self.Lines - for part, nl in string.gmatch(s, "([^\n]*)(\n?)") do - lines[#lines] = lines[#lines] .. part - if nl ~= "" then lines[#lines + 1] = "" end - if part == "" and nl == "" then break end +-- static ExampleAppLog my_log; +-- my_log.AddLog("Hello %d world\n", 123); +-- my_log.Draw("title"); +ExampleAppLogMT = {} +ExampleAppLogMT.__index = ExampleAppLogMT +function ExampleAppLog() + local self = setmetatable({}, ExampleAppLogMT) + self.Buf = ImGuiTextBuffer() + self.Filter = ImGuiTextFilter() + self.LineOffsets = ImVector() -- Index to lines offset. We maintain this with AddLog() calls. + self.AutoScroll = false -- Keep scrolling if already at the bottom. + + self.AutoScroll = true + self:Clear() + return self +end + +function ExampleAppLogMT:Clear() + self.Buf:clear() + self.LineOffsets:clear() + self.LineOffsets:push_back(0) +end + +function ExampleAppLogMT:AddLog(fmt, ...) + local old_size = self.Buf:size() + self.Buf:appendf(fmt, ...) + local buf = self.Buf:c_str() -- [Port] Buf[] byte access + local new_size = #buf + while old_size < new_size do + if string.byte(buf, old_size + 1) == 10 then -- '\n' + self.LineOffsets:push_back(old_size + 1) end + old_size = old_size + 1 end - function l:Draw(title, p_open) - local visible - p_open, visible = ImGui.Begin(title, p_open) - if not visible then ImGui.End(); return p_open end +end - -- Options menu - if ImGui.BeginPopup("Options") then - _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) - ImGui.EndPopup() - end - - -- Main window - if ImGui.Button("Options") then ImGui.OpenPopup("Options") end - ImGui.SameLine() - local clear = ImGui.Button("Clear") - ImGui.SameLine() - local copy = ImGui.Button("Copy") - ImGui.SameLine() - ImGui.SetNextItemWidth(-FLT_MIN) - self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") - ImGui.Separator() - if ImGui.BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags.None, ImGuiWindowFlags.HorizontalScrollbar) then - if clear then self:Clear() end - if copy then ImGui.LogToClipboard() end - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(0, 0)) - local lines = self.Lines - if self.Filter:IsActive() then - -- In this example we don't use the clipper when Filter is enabled. - -- This is because we don't have random access to the result of our filter. - -- A real application processing logs with ten of thousands of entries may want to store the result of - -- search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). - for line_no = 1, #lines do - if self.Filter:PassFilter(lines[line_no]) then ImGui.TextUnformatted(lines[line_no]) end - end - else - -- The simplest and easy way to display the entire buffer: - -- ImGui.TextUnformatted(buf_begin, buf_end) - -- And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward - -- to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are - -- within the visible area. - -- If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them - -- on your side is recommended. Using ImGuiListClipper requires - -- - A) random access into your data - -- - B) items all being the same height, - -- both of which we can handle since we have an array pointing to the beginning of each line of text. - -- When using the filter (in the block of code above) we don't have random access into the data to display - -- anymore, which is why we don't use the clipper. Storing or skimming through the search result would make - -- it possible (and would be recommended if you want to search through tens of thousands of entries). - local clipper = ImGuiListClipper() - clipper:Begin(#lines) - while clipper:Step() do - for line_no = clipper.DisplayStart, clipper.DisplayEnd - 1 do ImGui.TextUnformatted(lines[line_no + 1]) end - end - clipper:End() - end - ImGui.PopStyleVar() - if copy then ImGui.LogFinish() end - - -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. - -- Using a scrollbar or mouse-wheel will take away from the bottom edge. - if self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY() then ImGui.SetScrollHereY(1.0) end - end - ImGui.EndChild() +-- [Port] line offsets are 0-based like upstream; a line is string.sub(buf, line_start + 1, line_end) (TextUnformatted()/PassFilter() have no text_begin) +function ExampleAppLogMT:Draw(title, p_open) + local visible + p_open, visible = ImGui.Begin(title, p_open) + if not visible then ImGui.End() return p_open end - return l + + -- Options menu + if ImGui.BeginPopup("Options") then + _, self.AutoScroll = ImGui.Checkbox("Auto-scroll", self.AutoScroll) + ImGui.EndPopup() + end + + -- Main window + if ImGui.Button("Options") then + ImGui.OpenPopup("Options") + end + ImGui.SameLine() + local clear = ImGui.Button("Clear") + ImGui.SameLine() + local copy = ImGui.Button("Copy") + ImGui.SameLine() + ImGui.SetNextItemWidth(-FLT_MIN) + self.Filter:DrawWithHint("##Filter", "Filter (incl -excl)") + + ImGui.Separator() + + if ImGui.BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags.None, ImGuiWindowFlags.HorizontalScrollbar) then + if clear then + self:Clear() + end + if copy then + ImGui.LogToClipboard() + end + + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(0, 0)) + local buf = self.Buf:c_str() + local buf_end = #buf + local LineOffsets = self.LineOffsets + if self.Filter:IsActive() then + -- In this example we don't use the clipper when Filter is enabled. + -- This is because we don't have random access to the result of our filter. + -- A real application processing logs with ten of thousands of entries may want to store the result of + -- search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). + for line_no = 0, LineOffsets.Size - 1 do + local line_start = LineOffsets.Data[line_no + 1] + local line_end + if line_no + 1 < LineOffsets.Size then line_end = LineOffsets.Data[line_no + 2] - 1 else line_end = buf_end end + local line = string.sub(buf, line_start + 1, line_end) + if self.Filter:PassFilter(line) then + ImGui.TextUnformatted(line) + end + end + else + -- The simplest and easy way to display the entire buffer: + -- ImGui.TextUnformatted(buf_begin, buf_end); + -- And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward + -- to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are + -- within the visible area. + -- If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them + -- on your side is recommended. Using ImGuiListClipper requires + -- - A) random access into your data + -- - B) items all being the same height, + -- both of which we can handle since we have an array pointing to the beginning of each line of text. + -- When using the filter (in the block of code above) we don't have random access into the data to display + -- anymore, which is why we don't use the clipper. Storing or skimming through the search result would make + -- it possible (and would be recommended if you want to search through tens of thousands of entries). + local clipper = ImGuiListClipper() + clipper:Begin(LineOffsets.Size) + while clipper:Step() do + for line_no = clipper.DisplayStart, clipper.DisplayEnd - 1 do + local line_start = LineOffsets.Data[line_no + 1] + local line_end + if line_no + 1 < LineOffsets.Size then line_end = LineOffsets.Data[line_no + 2] - 1 else line_end = buf_end end + ImGui.TextUnformatted(string.sub(buf, line_start + 1, line_end)) + end + end + clipper:End() + end + ImGui.PopStyleVar() + + -- Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. + -- Using a scrollbar or mouse-wheel will take away from the bottom edge. + if self.AutoScroll and ImGui.GetScrollY() >= ImGui.GetScrollMaxY() then + ImGui.SetScrollHereY(1.0) + end + end + ImGui.EndChild() + ImGui.End() + return p_open end -- Demonstrate creating a simple log window with basic filtering. -local AppLog, AppLogCounter = nil, 0 +S.ShowExampleAppLog = { + log = nil, -- ExampleAppLog, created on first use + counter = 0, +} function ShowExampleAppLog(p_open) - AppLog = AppLog or ExampleAppLog() + local s = S.ShowExampleAppLog + if s.log == nil then s.log = ExampleAppLog() end -- For the demo: add a debug button _BEFORE_ the normal log window contents -- We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. - -- Most of the contents of the window will be added by the log:Draw() call. + -- Most of the contents of the window will be added by the log.Draw() call. ImGui.SetNextWindowSize(ImVec2(500, 400), ImGuiCond.FirstUseEver) p_open = ImGui.Begin("Example: Log", p_open) + IMGUI_DEMO_MARKER("Examples/Log") if ImGui.SmallButton("[Debug] Add 5 entries") then local categories = { "info", "warn", "error" } local words = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" } - for _ = 1, 5 do - local category = categories[AppLogCounter % #categories + 1] - local word = words[AppLogCounter % #words + 1] - AppLog:AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", ImGui.GetFrameCount(), category, ImGui.GetTime(), word) - AppLogCounter = AppLogCounter + 1 + for n = 0, 5 - 1 do + local category = categories[s.counter % #categories + 1] + local word = words[s.counter % #words + 1] + s.log:AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", + ImGui.GetFrameCount(), category, ImGui.GetTime(), word) + s.counter = s.counter + 1 end end ImGui.End() -- Actually call in the regular Log helper (which will Begin() into the same window as we just did) - return AppLog:Draw("Example: Log", p_open) + return s.log:Draw("Example: Log", p_open) end ------------------------------------------------------------------------------- @@ -4740,12 +8766,16 @@ end ------------------------------------------------------------------------------- -- Demonstrate create a window with multiple child windows. -local LayoutSelected = 0 +S.ShowExampleAppLayout = { + selected = 0, +} function ShowExampleAppLayout(p_open) + local s = S.ShowExampleAppLayout ImGui.SetNextWindowSize(ImVec2(500, 440), ImGuiCond.FirstUseEver) local visible p_open, visible = ImGui.Begin("Example: Simple layout", p_open, ImGuiWindowFlags.MenuBar) if visible then + IMGUI_DEMO_MARKER("Examples/Simple layout") if ImGui.BeginMenuBar() then if ImGui.BeginMenu("File") then if ImGui.MenuItem("Close", "Ctrl+W") then p_open = false end @@ -4755,34 +8785,41 @@ function ShowExampleAppLayout(p_open) end -- Left - ImGui.BeginChild("left pane", ImVec2(150, 0), bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.ResizeX)) - for i = 0, 99 do - if ImGui.Selectable(string.format("MyObject %d", i), LayoutSelected == i, ImGuiSelectableFlags.SelectOnNav) then LayoutSelected = i end + do + ImGui.BeginChild("left pane", ImVec2(150, 0), bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.ResizeX)) + for i = 0, 100 - 1 do + local label = string.format("MyObject %d", i) + if ImGui.Selectable(label, s.selected == i, ImGuiSelectableFlags.SelectOnNav) then + s.selected = i + end + end + ImGui.EndChild() end - ImGui.EndChild() ImGui.SameLine() -- Right - ImGui.BeginGroup() - ImGui.BeginChild("item view", ImVec2(0, -ImGui.GetFrameHeightWithSpacing())) -- Leave room for 1 line below us - ImGui.Text("MyObject: %d", LayoutSelected) - ImGui.Separator() - if ImGui.BeginTabBar("##Tabs", ImGuiTabBarFlags.None) then - if ImGui.BeginTabItem("Description") then - ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ") - ImGui.EndTabItem() + do + ImGui.BeginGroup() + ImGui.BeginChild("item view", ImVec2(0, -ImGui.GetFrameHeightWithSpacing())) -- Leave room for 1 line below us + ImGui.Text("MyObject: %d", s.selected) + ImGui.Separator() + if ImGui.BeginTabBar("##Tabs", ImGuiTabBarFlags.None) then + if ImGui.BeginTabItem("Description") then + ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ") + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("Details") then + ImGui.Text("ID: 0123456789") + ImGui.EndTabItem() + end + ImGui.EndTabBar() end - if ImGui.BeginTabItem("Details") then - ImGui.Text("ID: 0123456789") - ImGui.EndTabItem() - end - ImGui.EndTabBar() + ImGui.EndChild() + if ImGui.Button("Revert") then end + ImGui.SameLine() + if ImGui.Button("Save") then end + ImGui.EndGroup() end - ImGui.EndChild() - if ImGui.Button("Revert") then end - ImGui.SameLine() - if ImGui.Button("Save") then end - ImGui.EndGroup() end ImGui.End() return p_open @@ -4797,121 +8834,20 @@ end -- - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties. ------------------------------------------------------------------------------- --- ExampleMemberInfo equivalent: field name, data type, component count -local ExampleTreeNodeMemberInfos = { - { Name = "MyName", DataType = ImGuiDataType.String, DataCount = 1, Field = "Name" }, - { Name = "MyBool", DataType = ImGuiDataType.Bool, DataCount = 1, Field = "DataMyBool" }, - { Name = "MyInt", DataType = ImGuiDataType.S32, DataCount = 1, Field = "DataMyInt" }, - { Name = "MyVec2", DataType = ImGuiDataType.Float, DataCount = 2, Field = "DataMyVec2" }, -} - -local PropEd = { Filter = nil, SelectedNode = nil, UseClipper = false, NameBufs = setmetatable({}, { __mode = "k" }) } - --- Custom search filter --- - Here we apply on root node only. --- - This does a case insensitive stristr which is pretty heavy. In a real large-scale app you would likely store a filtered list which in turns would be trivial to linearize. -function PropEd:IsNodePassingFilter(node) - return node.Parent.Parent ~= nil or self.Filter:PassFilter(node.Name) +ExampleAppPropertyEditorMT = {} +ExampleAppPropertyEditorMT.__index = ExampleAppPropertyEditorMT +function ExampleAppPropertyEditor() + local self = setmetatable({}, ExampleAppPropertyEditorMT) + self.Filter = ImGuiTextFilter() + self.SelectedNode = nil + self.UseClipper = false + self.StringBufs = setmetatable({}, { __mode = "k" }) -- [Port] node -> 28-byte edit buffer for ImGuiDataType.String fields (node.Name is a Lua string) + return self end --- To support node with same name we incorporate node.UID into the item ID. --- (this would more naturally be done using PushID(node.UID) + TreeNodeEx(node.Name, tree_flags), --- but it would require in DrawClippedTreeNodeAndAdvanceToNext() to add PushID() before TreePush(), and PopID() after TreePop(), --- so instead we use TreeNodeEx(node.UID, tree_flags, "%s", node.Name) here) -function PropEd:DrawTreeNode(node) - local TN = ImGuiTreeNodeFlags - ImGui.TableNextRow() - ImGui.TableNextColumn() - -- OpenOnArrow | OpenOnDoubleClick: Standard opening mode as we are likely to want to add selection afterwards - -- NavLeftJumpsToParent: Left arrow support - -- SpanFullWidth: Span full width for easier mouse reach - -- DrawLinesToNodes: Always draw hierarchy outlines - local tree_flags = bit32.bor(TN.OpenOnArrow, TN.OpenOnDoubleClick, TN.NavLeftJumpsToParent, TN.SpanFullWidth, TN.DrawLinesToNodes) - if node == self.SelectedNode then tree_flags = bit32.bor(tree_flags, TN.Selected) end -- Draw selection highlight - if #node.Childs == 0 then tree_flags = bit32.bor(tree_flags, TN.Leaf, TN.Bullet, TN.NoTreePushOnOpen) end -- Use _NoTreePushOnOpen + set is_open=false to avoid unnecessarily push/pop on leaves. - if node.DataMyBool == false then ImGui.PushStyleColor(ImGuiCol.Text, ImGui.GetStyle().Colors[ImGuiCol.TextDisabled]) end - ImGui.SetNextItemStorageID(node.UID) -- Use node.UID as storage id - local is_open = ImGui.TreeNodeEx(node.UID, tree_flags, "%s", node.Name) - if #node.Childs == 0 then is_open = false end - if node.DataMyBool == false then ImGui.PopStyleColor() end - if ImGui.IsItemFocused() then self.SelectedNode = node end - return is_open -end +function ExampleAppPropertyEditorMT:Draw(root_node) + IMGUI_DEMO_MARKER("Examples/Property editor") --- Basic version, recursive. This is how you would generally draw a tree. --- - Simple but going to be noticeably costly if you have a large amount of nodes as DrawTreeNode() is called for all of them. --- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~1.2 ms --- - Unlike arrays or grids which are very easy to clip, trees are currently more difficult to clip. -function PropEd:DrawTree(node) - for _, child in ipairs(node.Childs) do - if self:IsNodePassingFilter(child) and self:DrawTreeNode(child) then - self:DrawTree(child) - ImGui.TreePop() - end - end -end - -function PropEd:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) - if self:IsNodePassingFilter(node) then - -- Draw node if within visible range - local is_open - if clipper.UserIndex >= clipper.DisplayStart and clipper.UserIndex < clipper.DisplayEnd then - is_open = self:DrawTreeNode(node) - else - is_open = (#node.Childs > 0 and ImGui.TreeNodeGetOpen(node.UID)) - if is_open then ImGui.TreePush(node.Name) end - end - clipper.UserIndex = clipper.UserIndex + 1 - - -- Next node: recurse into childs - if is_open then return node.Childs[1] end - end - - -- Next node: next sibling, otherwise move back to parent - while node ~= nil do - if node.IndexInParent + 1 < #node.Parent.Childs then - return node.Parent.Childs[node.IndexInParent + 2] - end - node = node.Parent - if node.Parent == nil then break end - ImGui.TreePop() - end - return nil -end - --- More advanced version. Use a alternative clipping technique: fast-forwarding through non-visible chunks. --- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~0.1 ms --- (in ExampleTree_CreateDemoTree(), change 'ROOT_ITEMS_COUNT = 10000' to try with this amount of root nodes). --- - 1. Use clipper with indeterminate count (items_count = INT_MAX): we need to call SeekCursorForItem() at the end once we know the count. --- - 2. Use SetNextItemStorageID() to specify ID used for open/close storage, making it easy to call TreeNodeGetOpen() on any arbitrary node. --- - 3. Linearize tree during traversal: our tree data structure makes it easy to access sibling and parents. --- - Unlike clipping for a regular array or grid which may be done using random access limited to visible areas, --- this technique requires traversing most accessible nodes. This could be made more optimal with extra work, --- but this is a decent simplicity<>speed trade-off. --- See https://github.com/ocornut/imgui/issues/3823 for discussions about this. -function PropEd:DrawClippedTree(root_node) - local node = root_node.Childs[1] -- First node - local clipper = ImGuiListClipper() - clipper:Begin(INT_MAX) - while clipper:Step() do - while clipper.UserIndex < clipper.DisplayEnd and node ~= nil do - node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) - end - end - - -- Keep going to count nodes and submit final count so we have a reliable scrollbar. - -- - One could consider caching this value and only refreshing it occasionally e.g. window is focused and an action occurs. - -- - Incorrect but cheap approximation would be to use 'clipper_current_idx = IM_MAX(clipper_current_idx, #root_node.Childs)' instead. - -- - If either of those is implemented, the general cost will approach zero when scrolling is at the top of the tree. - while node ~= nil do - node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) - end - --clipper.UserIndex = math.max(clipper.UserIndex, #root_node.Childs) -- <-- Cheap approximation instead of while() loop above. - clipper:SeekCursorForItem(clipper.UserIndex) -end - -function PropEd:Draw(root_node) - self.Filter = self.Filter or ImGuiTextFilter() -- Left side: draw tree -- - Currently using a table to benefit from RowBg feature -- - Our tree node are all of equal height, facilitating the use of a clipper. @@ -4926,8 +8862,13 @@ function PropEd:Draw(root_node) self.Filter:Build() end ImGui.PopItemFlag() + if ImGui.BeginTable("##list", 1, ImGuiTableFlags.RowBg) then - if self.UseClipper then self:DrawClippedTree(root_node) else self:DrawTree(root_node) end + if self.UseClipper then + self:DrawClippedTree(root_node) + else + self:DrawTree(root_node) + end ImGui.EndTable() end end @@ -4958,19 +8899,26 @@ function PropEd:Draw(root_node) ImGui.AlignTextToFramePadding() ImGui.TextUnformatted(field_desc.Name) ImGui.TableNextColumn() - local DT = ImGuiDataType - if field_desc.DataType == DT.Bool then - _, node[field_desc.Field] = ImGui.Checkbox("##Editor", node[field_desc.Field]) - elseif field_desc.DataType == DT.S32 then + local field_ptr = field_desc.Offset -- [Port] Offset is the field name inside ExampleTreeNode + if field_desc.DataType == ImGuiDataType.Bool then + IM_ASSERT(field_desc.DataCount == 1) + _, node[field_ptr] = ImGui.Checkbox("##Editor", node[field_ptr]) + elseif field_desc.DataType == ImGuiDataType.S32 then + local v_min, v_max = INT_MIN, INT_MAX ImGui.SetNextItemWidth(-FLT_MIN) - node[field_desc.Field] = ImGui.DragScalar("##Editor", DT.S32, node[field_desc.Field], 1.0, INT_MIN or -2147483648, INT_MAX) - elseif field_desc.DataType == DT.Float then + if field_desc.DataCount == 1 then -- [Port] scalar fields are plain Lua values: DragScalar() returns the new value + node[field_ptr] = ImGui.DragScalar("##Editor", field_desc.DataType, node[field_ptr], 1.0, v_min, v_max) + else + ImGui.DragScalarN("##Editor", field_desc.DataType, node[field_ptr], field_desc.DataCount, 1.0, v_min, v_max) + end + elseif field_desc.DataType == ImGuiDataType.Float then + local v_min, v_max = 0.0, 1.0 ImGui.SetNextItemWidth(-FLT_MIN) - ImGui.SliderScalarN("##Editor", DT.Float, node[field_desc.Field], field_desc.DataCount, 0.0, 1.0) - elseif field_desc.DataType == DT.String then - local b = self.NameBufs[node] - if b == nil then b = Buf(node.Name, 28); self.NameBufs[node] = b end - if ImGui.InputText("##Editor", b, 28) then node.Name = BufStr(b) end + ImGui.SliderScalarN("##Editor", field_desc.DataType, node[field_ptr], field_desc.DataCount, v_min, v_max) + elseif field_desc.DataType == ImGuiDataType.String then + local buf = self.StringBufs[node] -- [Port] edit the Lua string through a 28-byte buffer + if buf == nil then buf = ImGui.NewTextBuffer(node[field_ptr], 28); self.StringBufs[node] = buf end + if ImGui.InputText("##Editor", buf, 28) then node[field_ptr] = ImGui.TextBufferToString(buf) end end ImGui.PopID() end @@ -4982,16 +8930,152 @@ function PropEd:Draw(root_node) ImGui.EndGroup() end +-- Custom search filter +-- - Here we apply on root node only. +-- - This does a case insensitive stristr which is pretty heavy. In a real large-scale app you would likely store a filtered list which in turns would be trivial to linearize. +function ExampleAppPropertyEditorMT:IsNodePassingFilter(node) + return node.Parent.Parent ~= nil or self.Filter:PassFilter(node.Name) +end + +-- Basic version, recursive. This is how you would generally draw a tree. +-- - Simple but going to be noticeably costly if you have a large amount of nodes as DrawTreeNode() is called for all of them. +-- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~1.2 ms +-- - Unlike arrays or grids which are very easy to clip, trees are currently more difficult to clip. +function ExampleAppPropertyEditorMT:DrawTree(node) + for _, child in ipairs(node.Childs) do + if self:IsNodePassingFilter(child) and self:DrawTreeNode(child) then + self:DrawTree(child) + ImGui.TreePop() + end + end +end + +-- More advanced version. Use a alternative clipping technique: fast-forwarding through non-visible chunks. +-- - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~0.1 ms +-- (in ExampleTree_CreateDemoTree(), change 'int ROOT_ITEMS_COUNT = 10000' to try with this amount of root nodes). +-- - 1. Use clipper with indeterminate count (items_count = INT_MAX): we need to call SeekCursorForItem() at the end once we know the count. +-- - 2. Use SetNextItemStorageID() to specify ID used for open/close storage, making it easy to call TreeNodeGetOpen() on any arbitrary node. +-- - 3. Linearize tree during traversal: our tree data structure makes it easy to access sibling and parents. +-- - Unlike clipping for a regular array or grid which may be done using random access limited to visible areas, +-- this technique requires traversing most accessible nodes. This could be made more optimal with extra work, +-- but this is a decent simplicity<>speed trade-off. +-- See https://github.com/ocornut/imgui/issues/3823 for discussions about this. +function ExampleAppPropertyEditorMT:DrawClippedTree(root_node) + local node = root_node.Childs[1] -- First node + local clipper = ImGuiListClipper() + clipper:Begin(INT_MAX) + while clipper:Step() do + while clipper.UserIndex < clipper.DisplayEnd and node ~= nil do + node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) + end + end + + -- Keep going to count nodes and submit final count so we have a reliable scrollbar. + -- - One could consider caching this value and only refreshing it occasionally e.g. window is focused and an action occurs. + -- - Incorrect but cheap approximation would be to use 'clipper_current_idx = IM_MAX(clipper_current_idx, root_node.Childs.Size)' instead. + -- - If either of those is implemented, the general cost will approach zero when scrolling is at the top of the tree. + while node ~= nil do + node = self:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) + end + --clipper.UserIndex = IM_MAX(clipper.UserIndex, root_node.Childs.Size); // <-- Cheap approximation instead of while() loop above. + clipper:SeekCursorForItem(clipper.UserIndex) +end + +function ExampleAppPropertyEditorMT:DrawClippedTreeNodeAndAdvanceToNext(clipper, node) + if self:IsNodePassingFilter(node) then + -- Draw node if within visible range + local is_open = false + if clipper.UserIndex >= clipper.DisplayStart and clipper.UserIndex < clipper.DisplayEnd then + is_open = self:DrawTreeNode(node) + else + is_open = (#node.Childs > 0 and ImGui.TreeNodeGetOpen(node.UID)) + if is_open then + ImGui.TreePush(node.Name) + end + end + clipper.UserIndex = clipper.UserIndex + 1 + + -- Next node: recurse into childs + if is_open then + return node.Childs[1] + end + end + + -- Next node: next sibling, otherwise move back to parent + while node ~= nil do + if node.IndexInParent + 1 < #node.Parent.Childs then + return node.Parent.Childs[node.IndexInParent + 1 + 1] -- [Port] Childs is 1-based, IndexInParent 0-based + end + node = node.Parent + if node.Parent == nil then + break + end + ImGui.TreePop() + end + return nil +end + +-- To support node with same name we incorporate node.UID into the item ID. +-- (this would more naturally be done using PushID(node.UID) + TreeNodeEx(node.Name, tree_flags), +-- but it would require in DrawClippedTreeNodeAndAdvanceToNext() to add PushID() before TreePush(), and PopID() after TreePop(), +-- so instead we use TreeNodeEx(node.UID, tree_flags, "%s", node.Name) here) +function ExampleAppPropertyEditorMT:DrawTreeNode(node) + ImGui.TableNextRow() + ImGui.TableNextColumn() + local tree_flags = ImGuiTreeNodeFlags.None + tree_flags = bit32.bor(tree_flags, ImGuiTreeNodeFlags.OpenOnArrow, ImGuiTreeNodeFlags.OpenOnDoubleClick) -- Standard opening mode as we are likely to want to add selection afterwards + tree_flags = bit32.bor(tree_flags, ImGuiTreeNodeFlags.NavLeftJumpsToParent) -- Left arrow support + tree_flags = bit32.bor(tree_flags, ImGuiTreeNodeFlags.SpanFullWidth) -- Span full width for easier mouse reach + tree_flags = bit32.bor(tree_flags, ImGuiTreeNodeFlags.DrawLinesToNodes) -- Always draw hierarchy outlines + if node == self.SelectedNode then + tree_flags = bit32.bor(tree_flags, ImGuiTreeNodeFlags.Selected) -- Draw selection highlight + end + if #node.Childs == 0 then + tree_flags = bit32.bor(tree_flags, ImGuiTreeNodeFlags.Leaf, ImGuiTreeNodeFlags.Bullet, ImGuiTreeNodeFlags.NoTreePushOnOpen) -- Use _NoTreePushOnOpen + set is_open=false to avoid unnecessarily push/pop on leaves. + end + if node.DataMyBool == false then + ImGui.PushStyleColor(ImGuiCol.Text, ImGui.GetStyle().Colors[ImGuiCol.TextDisabled]) + end + ImGui.SetNextItemStorageID(node.UID) -- Use node.UID as storage id + local is_open = ImGui.TreeNodeEx(node.UID, tree_flags, "%s", node.Name) + if #node.Childs == 0 then + is_open = false + end + if node.DataMyBool == false then + ImGui.PopStyleColor() + end + if ImGui.IsItemFocused() then + self.SelectedNode = node + end + return is_open +end + -- Demonstrate creating a simple property editor. -local DemoTree = nil +S.ShowExampleAppPropertyEditor = { + property_editor = nil, -- ExampleAppPropertyEditor, created on first use + demo_data = nil, -- [Port] fallback when called without demo_data +} function ShowExampleAppPropertyEditor(p_open, demo_data) + local s = S.ShowExampleAppPropertyEditor ImGui.SetNextWindowSize(ImVec2(430, 450), ImGuiCond.FirstUseEver) local visible p_open, visible = ImGui.Begin("Example: Property editor", p_open) - if not visible then ImGui.End(); return p_open end - if demo_data and demo_data.DemoTree == nil then demo_data.DemoTree = ExampleTree_CreateDemoTree() end - DemoTree = (demo_data and demo_data.DemoTree) or DemoTree or ExampleTree_CreateDemoTree() - PropEd:Draw(DemoTree) + if not visible then + ImGui.End() + return p_open + end + + IMGUI_DEMO_MARKER("Examples/Property Editor") + if s.property_editor == nil then s.property_editor = ExampleAppPropertyEditor() end + if demo_data == nil then -- [Port] tolerate callers without demo_data (test harness) + if s.demo_data == nil then s.demo_data = {} end + demo_data = s.demo_data + end + if demo_data.DemoTree == nil then + demo_data.DemoTree = ExampleTree_CreateDemoTree() + end + s.property_editor:Draw(demo_data.DemoTree) + ImGui.End() return p_open end @@ -5001,44 +9085,57 @@ end ------------------------------------------------------------------------------- -- Demonstrate/test rendering huge amount of text, and the incidence of clipping. -local LT = { test_type = 0, log = {}, lines = 0, bytes = 0 } +S.ShowExampleAppLongText = { + test_type = 0, + log = ImGuiTextBuffer(), + lines = 0, +} function ShowExampleAppLongText(p_open) + local s = S.ShowExampleAppLongText ImGui.SetNextWindowSize(ImVec2(520, 600), ImGuiCond.FirstUseEver) local visible p_open, visible = ImGui.Begin("Example: Long text display", p_open) - if not visible then ImGui.End(); return p_open end + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Examples/Long text display") + ImGui.Text("Printing unusually long amount of text.") - LT.test_type = ImGui.Combo("Test type", LT.test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped\0Multiple calls to Text(), not clipped (slow)\0") - ImGui.Text("Buffer contents: %d lines, %d bytes", LT.lines, LT.bytes) - if ImGui.Button("Clear") then LT.log = {}; LT.lines = 0; LT.bytes = 0; LT.text = nil end + s.test_type = ImGui.Combo("Test type", s.test_type, + "Single call to TextUnformatted()\0" .. + "Multiple calls to Text(), clipped\0" .. + "Multiple calls to Text(), not clipped (slow)\0") + ImGui.Text("Buffer contents: %d lines, %d bytes", s.lines, s.log:size()) + if ImGui.Button("Clear") then s.log:clear(); s.lines = 0 end ImGui.SameLine() if ImGui.Button("Add 1000 lines") then - for i = 0, 999 do - local line = string.format("%i The quick brown fox jumps over the lazy dog\n", LT.lines + i) - LT.log[#LT.log + 1] = line - LT.bytes = LT.bytes + #line + for i = 0, 1000 - 1 do + s.log:appendf("%i The quick brown fox jumps over the lazy dog\n", s.lines + i) end - LT.lines = LT.lines + 1000 - LT.text = nil + s.lines = s.lines + 1000 end ImGui.BeginChild("Log") - if LT.test_type == 0 then + if s.test_type == 0 then -- Single call to TextUnformatted() with a big buffer - LT.text = LT.text or table.concat(LT.log) - ImGui.TextUnformatted(LT.text) - elseif LT.test_type == 1 then + ImGui.TextUnformatted(s.log:c_str()) -- [Port] ImGuiTextBuffer is a chunk list: c_str() instead of begin()/end() + elseif s.test_type == 1 then -- Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(0, 0)) local clipper = ImGuiListClipper() - clipper:Begin(LT.lines) + clipper:Begin(s.lines) while clipper:Step() do - for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) end + for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do + ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) + end end ImGui.PopStyleVar() - else + elseif s.test_type == 2 then -- Multiple calls to Text(), not clipped (slow) ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(0, 0)) - for i = 0, LT.lines - 1 do ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) end + for i = 0, s.lines - 1 do + ImGui.Text("%i The quick brown fox jumps over the lazy dog", i) + end ImGui.PopStyleVar() end ImGui.EndChild() @@ -5051,14 +9148,27 @@ end ------------------------------------------------------------------------------- -- Demonstrate creating a window which gets auto-resized according to its content. -local AutoResizeLines = 10 +S.ShowExampleAppAutoResize = { + lines = 10, +} function ShowExampleAppAutoResize(p_open) + local s = S.ShowExampleAppAutoResize local visible p_open, visible = ImGui.Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags.AlwaysAutoResize) - if not visible then ImGui.End(); return p_open end - ImGui.TextUnformatted("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop.") - AutoResizeLines = ImGui.SliderInt("Number of lines", AutoResizeLines, 1, 20) - for i = 0, AutoResizeLines - 1 do ImGui.Text("%sThis is line %d", string.rep(" ", i * 4), i) end -- Pad with space to extend size horizontally + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Examples/Auto-resizing window") + + ImGui.TextUnformatted( + "Window will resize every-frame to the size of its content.\n" .. + "Note that you probably don't want to query the window size to\n" .. + "output your content because that would create a feedback loop.") + s.lines = ImGui.SliderInt("Number of lines", s.lines, 1, 20) + for i = 0, s.lines - 1 do + ImGui.Text("%sThis is line %d", string.rep(" ", i * 4), i) -- Pad with space to extend size horizontally -- [Port] "%*s" -> string.rep + end ImGui.End() return p_open end @@ -5069,38 +9179,69 @@ end -- Demonstrate creating a window with custom resize constraints. -- Note that size constraints currently don't work on a docked window (when in 'docking' branch) --- Options -local CR = { auto_resize = false, window_padding = true, type = 6, display_lines = 10 } -- type 6: Aspect Ratio +CustomConstraints = {} +-- Helper functions to demonstrate programmatic constraints +-- FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier. +-- FIXME: None of the three demos works consistently when resizing from borders. +function CustomConstraints.AspectRatio(data) + local aspect_ratio = data.UserData -- [Port] UserData is the number itself (no float*) + data.DesiredSize.y = math.floor(data.DesiredSize.x / aspect_ratio) +end +function CustomConstraints.Square(data) + local m = ImMax(data.DesiredSize.x, data.DesiredSize.y) -- [Port] IM_MAX -> ImMax + data.DesiredSize.x = m; data.DesiredSize.y = m +end +function CustomConstraints.Step(data) + local step = data.UserData + data.DesiredSize = ImVec2(math.floor(data.DesiredSize.x / step + 0.5) * step, math.floor(data.DesiredSize.y / step + 0.5) * step) +end + +S.ShowExampleAppConstrainedResize = { + -- Options + auto_resize = false, + window_padding = true, + type = 6, -- Aspect Ratio + display_lines = 10, +} function ShowExampleAppConstrainedResize(p_open) - -- Helper functions to demonstrate programmatic constraints - -- FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier. - -- FIXME: None of the three demos works consistently when resizing from borders. - local function AspectRatio(data) data.DesiredSize.y = math.floor(data.DesiredSize.x / data.UserData) end - local function Square(data) local m = math.max(data.DesiredSize.x, data.DesiredSize.y); data.DesiredSize.x = m; data.DesiredSize.y = m end - local function Step(data) - local step = data.UserData - data.DesiredSize = ImVec2(math.floor(data.DesiredSize.x / step + 0.5) * step, math.floor(data.DesiredSize.y / step + 0.5) * step) - end - local test_desc = { "Between 100x100 and 500x500", "At least 100x100", "Resize vertical + lock current width", "Resize horizontal + lock current height", - "Width Between 400 and 500", "Height at least 400", "Custom: Aspect Ratio 16:9", "Custom: Always Square", "Custom: Fixed Steps (100)" } + local s = S.ShowExampleAppConstrainedResize + local test_desc = + { + "Between 100x100 and 500x500", + "At least 100x100", + "Resize vertical + lock current width", + "Resize horizontal + lock current height", + "Width Between 400 and 500", + "Height at least 400", + "Custom: Aspect Ratio 16:9", + "Custom: Always Square", + "Custom: Fixed Steps (100)", + } + -- Submit constraint - local t = CR.type - if t == 0 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)) end -- Between 100x100 and 500x500 - if t == 1 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)) end -- Width > 100, Height > 100 - if t == 2 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)) end -- Resize vertical + lock current width - if t == 3 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)) end -- Resize horizontal + lock current height - if t == 4 then ImGui.SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)) end -- Width Between and 400 and 500 - if t == 5 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, FLT_MAX)) end -- Height at least 400 - if t == 6 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), AspectRatio, 16.0 / 9.0) end -- Aspect ratio - if t == 7 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), Square) end -- Always Square - if t == 8 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), Step, 100.0) end -- Fixed Step + local aspect_ratio = 16.0 / 9.0 + local fixed_step = 100.0 + if s.type == 0 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)) end -- Between 100x100 and 500x500 + if s.type == 1 then ImGui.SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)) end -- Width > 100, Height > 100 + if s.type == 2 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)) end -- Resize vertical + lock current width + if s.type == 3 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)) end -- Resize horizontal + lock current height + if s.type == 4 then ImGui.SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)) end -- Width Between and 400 and 500 + if s.type == 5 then ImGui.SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, FLT_MAX)) end -- Height at least 400 + if s.type == 6 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints.AspectRatio, aspect_ratio) end -- Aspect ratio + if s.type == 7 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints.Square) end -- Always Square + if s.type == 8 then ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints.Step, fixed_step) end -- Fixed Step -- Submit window - if not CR.window_padding then ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0.0, 0.0)) end - local window_flags = CR.auto_resize and ImGuiWindowFlags.AlwaysAutoResize or 0 + if not s.window_padding then + ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0.0, 0.0)) + end + local window_flags = s.auto_resize and ImGuiWindowFlags.AlwaysAutoResize or 0 local window_open p_open, window_open = ImGui.Begin("Example: Constrained Resize", p_open, window_flags) - if not CR.window_padding then ImGui.PopStyleVar() end + if not s.window_padding then + ImGui.PopStyleVar() + end + IMGUI_DEMO_MARKER("Examples/Constrained Resizing window") if window_open then if ImGui.GetIO().KeyShift then -- Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture) @@ -5111,17 +9252,21 @@ function ShowExampleAppConstrainedResize(p_open) ImGui.Text("%.2f x %.2f", avail_size.x, avail_size.y) else ImGui.Text("(Hold Shift to display a dummy viewport)") - if ImGui.IsWindowDocked() then ImGui.Text("Warning: Sizing Constraints won't work if the window is docked!") end + if ImGui.IsWindowDocked() then + ImGui.Text("Warning: Sizing Constraints won't work if the window is docked!") + end if ImGui.Button("Set 200x200") then ImGui.SetWindowSize(ImVec2(200, 200)) end ImGui.SameLine() if ImGui.Button("Set 500x500") then ImGui.SetWindowSize(ImVec2(500, 500)) end ImGui.SameLine() if ImGui.Button("Set 800x200") then ImGui.SetWindowSize(ImVec2(800, 200)) end ImGui.SetNextItemWidth(ImGui.GetFontSize() * 20) - CR.type = ImGui.Combo("Constraint", CR.type, test_desc, #test_desc) + s.type = ImGui.Combo("Constraint", s.type, test_desc, #test_desc) ImGui.SetNextItemWidth(ImGui.GetFontSize() * 20) - CR.display_lines = ImGui.DragInt("Lines", CR.display_lines, 0.2, 1, 100) - _, CR.auto_resize = ImGui.Checkbox("Auto-resize", CR.auto_resize) - _, CR.window_padding = ImGui.Checkbox("Window padding", CR.window_padding) - for i = 0, CR.display_lines - 1 do ImGui.Text("%sHello, sailor! Making this line long enough for the example.", string.rep(" ", i * 4)) end + s.display_lines = ImGui.DragInt("Lines", s.display_lines, 0.2, 1, 100) + _, s.auto_resize = ImGui.Checkbox("Auto-resize", s.auto_resize) + _, s.window_padding = ImGui.Checkbox("Window padding", s.window_padding) + for i = 0, s.display_lines - 1 do + ImGui.Text("%sHello, sailor! Making this line long enough for the example.", string.rep(" ", i * 4)) -- [Port] "%*s" -> string.rep + end end end ImGui.End() @@ -5134,40 +9279,50 @@ end -- Demonstrate creating a simple static window with no decoration -- + a context-menu to choose which corner of the screen to use. -local OverlayLocation = 0 +S.ShowExampleAppSimpleOverlay = { + location = 0, +} function ShowExampleAppSimpleOverlay(p_open) + local s = S.ShowExampleAppSimpleOverlay local io = ImGui.GetIO() - local W = ImGuiWindowFlags - local window_flags = bit32.bor(W.NoDecoration, W.NoDocking, W.AlwaysAutoResize, W.NoSavedSettings, W.NoFocusOnAppearing, W.NoNav) - if OverlayLocation >= 0 then + local window_flags = bit32.bor(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoDocking, ImGuiWindowFlags.AlwaysAutoResize, ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.NoFocusOnAppearing, ImGuiWindowFlags.NoNav) + if s.location >= 0 then local PAD = 10.0 local viewport = ImGui.GetMainViewport() - local work_pos, work_size = viewport.WorkPos, viewport.WorkSize -- Use work area to avoid menu-bar/task-bar, if any! - local right, bottom = OverlayLocation % 2 == 1, OverlayLocation >= 2 - local window_pos = ImVec2(right and (work_pos.x + work_size.x - PAD) or (work_pos.x + PAD), bottom and (work_pos.y + work_size.y - PAD) or (work_pos.y + PAD)) - local window_pos_pivot = ImVec2(right and 1.0 or 0.0, bottom and 1.0 or 0.0) + local work_pos = viewport.WorkPos -- Use work area to avoid menu-bar/task-bar, if any! + local work_size = viewport.WorkSize + local window_pos, window_pos_pivot = ImVec2(), ImVec2() + window_pos.x = (bit32.band(s.location, 1) ~= 0) and (work_pos.x + work_size.x - PAD) or (work_pos.x + PAD) + window_pos.y = (bit32.band(s.location, 2) ~= 0) and (work_pos.y + work_size.y - PAD) or (work_pos.y + PAD) + window_pos_pivot.x = (bit32.band(s.location, 1) ~= 0) and 1.0 or 0.0 + window_pos_pivot.y = (bit32.band(s.location, 2) ~= 0) and 1.0 or 0.0 ImGui.SetNextWindowPos(window_pos, ImGuiCond.Always, window_pos_pivot) ImGui.SetNextWindowViewport(viewport.ID) - window_flags = bit32.bor(window_flags, W.NoMove) - elseif OverlayLocation == -2 then + window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoMove) + elseif s.location == -2 then -- Center window ImGui.SetNextWindowPos(ImGui.GetMainViewport():GetCenter(), ImGuiCond.Always, ImVec2(0.5, 0.5)) - window_flags = bit32.bor(window_flags, W.NoMove) + window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoMove) end ImGui.SetNextWindowBgAlpha(0.35) -- Transparent background local visible p_open, visible = ImGui.Begin("Example: Simple overlay", p_open, window_flags) if visible then - ImGui.Text("Simple overlay\n(right-click to change position)") + IMGUI_DEMO_MARKER("Examples/Simple overlay") -- Scroll up to the beginning of this function to see overlay flags + ImGui.Text("Simple overlay\n" .. "(right-click to change position)") ImGui.Separator() - if ImGui.IsMousePosValid() then ImGui.Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y) else ImGui.Text("Mouse Position: ") end + if ImGui.IsMousePosValid() then + ImGui.Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y) + else + ImGui.Text("Mouse Position: ") + end if ImGui.BeginPopupContextWindow() then - if ImGui.MenuItem("Custom", nil, OverlayLocation == -1) then OverlayLocation = -1 end - if ImGui.MenuItem("Center", nil, OverlayLocation == -2) then OverlayLocation = -2 end - if ImGui.MenuItem("Top-left", nil, OverlayLocation == 0) then OverlayLocation = 0 end - if ImGui.MenuItem("Top-right", nil, OverlayLocation == 1) then OverlayLocation = 1 end - if ImGui.MenuItem("Bottom-left", nil, OverlayLocation == 2) then OverlayLocation = 2 end - if ImGui.MenuItem("Bottom-right", nil, OverlayLocation == 3) then OverlayLocation = 3 end + if ImGui.MenuItem("Custom", nil, s.location == -1) then s.location = -1 end + if ImGui.MenuItem("Center", nil, s.location == -2) then s.location = -2 end + if ImGui.MenuItem("Top-left", nil, s.location == 0) then s.location = 0 end + if ImGui.MenuItem("Top-right", nil, s.location == 1) then s.location = 1 end + if ImGui.MenuItem("Bottom-left", nil, s.location == 2) then s.location = 2 end + if ImGui.MenuItem("Bottom-right", nil, s.location == 3) then s.location = 3 end if p_open ~= nil and ImGui.MenuItem("Close") then p_open = false end ImGui.EndPopup() end @@ -5181,28 +9336,38 @@ end ------------------------------------------------------------------------------- -- Demonstrate creating a window covering the entire screen/viewport -local FS = { use_work_area = true, flags = bit32.bor(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings) } +S.ShowExampleAppFullscreen = { + use_work_area = true, + flags = bit32.bor(ImGuiWindowFlags.NoDecoration, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoSavedSettings), +} function ShowExampleAppFullscreen(p_open) + local s = S.ShowExampleAppFullscreen + -- We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.) -- Based on your use case you may want one or the other. local viewport = ImGui.GetMainViewport() - ImGui.SetNextWindowPos(FS.use_work_area and viewport.WorkPos or viewport.Pos) - ImGui.SetNextWindowSize(FS.use_work_area and viewport.WorkSize or viewport.Size) + ImGui.SetNextWindowPos(s.use_work_area and viewport.WorkPos or viewport.Pos) + ImGui.SetNextWindowSize(s.use_work_area and viewport.WorkSize or viewport.Size) + local visible - p_open, visible = ImGui.Begin("Example: Fullscreen window", p_open, FS.flags) + p_open, visible = ImGui.Begin("Example: Fullscreen window", p_open, s.flags) if visible then - _, FS.use_work_area = ImGui.Checkbox("Use work area instead of main area", FS.use_work_area) + IMGUI_DEMO_MARKER("Examples/Fullscreen window") + _, s.use_work_area = ImGui.Checkbox("Use work area instead of main area", s.use_work_area) ImGui.SameLine() HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference.") - local W = ImGuiWindowFlags - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoBackground", FS.flags, W.NoBackground) - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoDecoration", FS.flags, W.NoDecoration) + + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoBackground", s.flags, ImGuiWindowFlags.NoBackground) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoDecoration", s.flags, ImGuiWindowFlags.NoDecoration) ImGui.Indent() - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoTitleBar", FS.flags, W.NoTitleBar) - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoCollapse", FS.flags, W.NoCollapse) - _, FS.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoScrollbar", FS.flags, W.NoScrollbar) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoTitleBar", s.flags, ImGuiWindowFlags.NoTitleBar) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoCollapse", s.flags, ImGuiWindowFlags.NoCollapse) + _, s.flags = ImGui.CheckboxFlags("ImGuiWindowFlags_NoScrollbar", s.flags, ImGuiWindowFlags.NoScrollbar) ImGui.Unindent() - if p_open ~= nil and ImGui.Button("Close this window") then p_open = false end + + if p_open ~= nil and ImGui.Button("Close this window") then + p_open = false + end end ImGui.End() return p_open @@ -5225,19 +9390,22 @@ function ShowExampleAppWindowTitles(p_open) -- Using "##" to display same title but have unique identifier. ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond.FirstUseEver) ImGui.Begin("Same title as another window##1") + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##1") ImGui.Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.") ImGui.End() + ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond.FirstUseEver) ImGui.Begin("Same title as another window##2") + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##2") ImGui.Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.") ImGui.End() -- Using "###" to display a changing title but keep a static identifier "AnimatedTitle" - local spin = "|/-\\" - local k = math.floor(ImGui.GetTime() / 0.25) % 4 + 1 - local buf = string.format("Animated title %s %d###AnimatedTitle", string.sub(spin, k, k), ImGui.GetFrameCount()) + local spin_i = bit32.band(math.floor(ImGui.GetTime() / 0.25), 3) + 1 + local buf = string.format("Animated title %s %d###AnimatedTitle", string.sub("|/-\\", spin_i, spin_i), ImGui.GetFrameCount()) ImGui.SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond.FirstUseEver) ImGui.Begin(buf) + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##3") ImGui.Text("This window has a changing title.") ImGui.End() return p_open @@ -5252,297 +9420,406 @@ end -- - Pixel Perfect Anti-aliased Rendering: https://github.com/ocornut/imgui/wiki/Pixel-Perfect-Rendering -- - How Anti-aliased Polyline Rendering is Implemented: https://github.com/ocornut/imgui/wiki/Polyline-Rendering -local CRS = { sz = 42.0, base_rounding = 8.0, base_thickness = 3.0, animate_rounding = false, animate_thickness = false, ngon_segments = 6, - circle_override = false, circle_override_v = 12, curve_override = false, curve_override_v = 8, - colf_stroke = ImVec4(1.000, 0.384, 0.169, 1.000), colf_fill = ImVec4(0.416, 0.378, 0.420, 1.000), - points = {}, scrolling = ImVec2(0.0, 0.0), opt_enable_grid = true, opt_enable_context_menu = true, adding_line = false, - draw_bg = true, draw_fg = true } - -local function CustomRenderingPrimitives() - local s = CRS - ImGui.PushItemWidth(-ImGui.GetFontSize() * 15) - ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInput, true) - local draw_list = ImGui.GetWindowDrawList() - - -- Draw gradients - -- (note that those are currently exacerbating our sRGB/Linear issues) - -- Calling ImGui.GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. - ImGui.Text("Gradients") - local gradient_size = ImVec2(ImGui.CalcItemWidth(), ImGui.GetFrameHeight()) - ImGui.InvisibleButton("##gradient1", gradient_size) - local col_a, col_b = ImGui.GetColorU32(IM_COL32(0, 0, 0, 255), nil, true), ImGui.GetColorU32(IM_COL32(255, 255, 255, 255), nil, true) - draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) - ImGui.InvisibleButton("##gradient2", gradient_size) - col_a, col_b = ImGui.GetColorU32(IM_COL32(0, 255, 0, 255), nil, true), ImGui.GetColorU32(IM_COL32(255, 0, 0, 255), nil, true) - draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) - - -- Draw a bunch of primitives - ImGui.Text("All primitives") - s.sz = ImGui.DragFloat("Size", s.sz, 0.2, 0.2, 100.0, "%.0f") - local t = ImGui.GetTime() - local rounding_wave = 1.0 - math.abs((t % 3.0) * (2.0 / 3.0) - 1.0) - local rounding = s.animate_rounding and (math.floor(rounding_wave * s.base_rounding * 10.0) / 10.0) or s.base_rounding -- Sub-integer rounding works but has discontinuities in small values, so best disable we - s.base_rounding = ImGui.DragFloat("Rounding", s.base_rounding, 0.02, 0.0, 32.0, "%.1f"); ImGui.SameLine() - _, s.animate_rounding = ImGui.Checkbox("Animate##rounding", s.animate_rounding); ImGui.SameLine() - ImGui.Text("%.2f", rounding) - local thickness_wave = 1.0 - math.abs((t % 5.0) * (2.0 / 5.0) - 1.0) - local thickness = s.animate_thickness and (thickness_wave * s.base_thickness) or s.base_thickness - s.base_thickness = ImGui.DragFloat("Thickness", s.base_thickness, 0.02, 0.0, 32.0, "%.02f"); ImGui.SameLine() - _, s.animate_thickness = ImGui.Checkbox("Animate##thickness", s.animate_thickness); ImGui.SameLine() - ImGui.Text("%.2f", thickness) - s.ngon_segments = ImGui.SliderInt("N-gon sides", s.ngon_segments, 3, 12) - local changed - _, s.circle_override = ImGui.Checkbox("##CircleSegmentOverride", s.circle_override) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - s.circle_override_v, changed = ImGui.SliderInt("Circle segments override", s.circle_override_v, 3, 30) - s.circle_override = s.circle_override or changed - _, s.curve_override = ImGui.Checkbox("##CurvesSegmentOverride", s.curve_override) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - s.curve_override_v, changed = ImGui.SliderInt("Curves segments override", s.curve_override_v, 3, 30) - s.curve_override = s.curve_override or changed - ImGui.ColorEdit4("Stroke Color", s.colf_stroke) - ImGui.ColorEdit4("Fill Color", s.colf_fill) - ImGui.SeparatorText("Per primitive flags (AddXXX functions)") - ImGui.TextDisabled("(stroke placement/AA flags: not ported, this port uses the 1.92 stroker)") - ImGui.Spacing() - - local sz = s.sz - local start_pos = ImGui.GetCursorScreenPos() - local pi = 3.141592 - local step = sz + 10.0 - local corners_tl_br = bit32.bor(ImDrawFlags.RoundCornersTopLeft, ImDrawFlags.RoundCornersBottomRight) - local half_sz = sz * 0.5 - local circle_segments = s.circle_override and s.circle_override_v or 0 - local curve_segments = s.curve_override and s.curve_override_v or 0 - local cp3 = { ImVec2(0.0, sz * 0.6), ImVec2(sz * 0.5, -sz * 0.4), ImVec2(sz, sz) } -- Control points for curves - local cp4 = { ImVec2(0.0, 0.0), ImVec2(sz * 1.3, sz * 0.3), ImVec2(sz - sz * 1.3, sz - sz * 0.3), ImVec2(sz, sz) } - local concave_shape = { { 0.0, 0.0 }, { 0.3, 0.0 }, { 0.3, 0.7 }, { 0.7, 0.7 }, { 0.7, 0.0 }, { 1.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 1.0 } } -- |_| looking shape. Normalized. - local zigzag_shape = { { 0.0, 0.0 }, { 0.9, 0.0 }, { 1.0, 0.1 }, { 1.0, 0.9 }, { 0.9, 1.0 }, { 0.3, 1.0 }, { 0.3, 0.4 }, { 0.9, 0.4 } } - local rotating_square = {} - for side = 0, 3 do - local a = t * 0.1 + side * pi * 0.5 - rotating_square[side + 1] = ImVec2(math.cos(a) * half_sz, math.sin(a) * half_sz) - end - local function Shape(shape, x, y) - for _, p in ipairs(shape) do draw_list:PathLineTo(ImVec2(x + math.floor(sz * p[1]), y + math.floor(sz * p[2]))) end - end - - local y = start_pos.y - for row = 0, 3 do - local x = start_pos.x - local draw_fill = (row == 2 or row == 3) - local draw_strokes = (row == 0 or row == 1 or row == 3) - if draw_fill then - -- FILLED SHAPES - local col = ImGui.ColorConvertFloat4ToU32(s.colf_fill) - draw_list:AddNgonFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments); x = x + step -- N-gon - draw_list:AddCircleFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments); x = x + step -- Circle - draw_list:AddEllipseFilled(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments); x = x + step -- Ellipse - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x = x + step -- Square - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding); x = x + step -- Square with all rounded corners - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br); x = x + step -- Square with two rounded corners - draw_list:AddTriangleFilled(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col); x = x + step -- Triangle - draw_list:AddTriangleFilled(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col); x = x + step - math.floor(sz * 0.6) -- Thin triangle - - -- Concave shape: U - Shape(concave_shape, x, y); draw_list:PathFillConcave(col); x = x + step - - -- Concave shape: Zig-Zag with sharp angles - Shape(zigzag_shape, x, y); draw_list:PathFillConcave(col); x = x + step - - -- Horizontal/Vertical lines - -- (here for consistency with the strokes section. AddRectFilled() is roughly close to AddLineH(), AddLineV() - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x = x + step - draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x = x + step - math.floor(half_sz) - if not (draw_fill and draw_strokes) then - local block_sz, off = 1, 0 - while block_sz < 16 and off + block_sz <= sz do - draw_list:AddRectFilled(ImVec2(x, y + off), ImVec2(x + block_sz, y + off + block_sz), col) - off = off + block_sz + 1 - block_sz = block_sz + 1 - end - end - x = x + step - math.floor(half_sz) - - -- Rotating square - for n = 1, 4 do draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y)) end - draw_list:PathFillConvex(col); x = x + step - - -- Path - draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) - draw_list:PathFillConvex(col); x = x + step - - -- Quadratic Bezier Curve (3 control points) - draw_list:PathLineTo(ImVec2(x + cp3[1].x, y + cp3[1].y)) - draw_list:PathBezierQuadraticCurveTo(ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), curve_segments) - draw_list:PathFillConvex(col); x = x + step - if not (draw_fill and draw_strokes) then - draw_list:AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)) - x = x + step - end - end - if draw_fill and draw_strokes then x = start_pos.x end - if draw_strokes then - -- STROKES - -- First row uses a thickness of 1.0f, second row uses the configurable thickness - local col = ImGui.ColorConvertFloat4ToU32(s.colf_stroke) - local th = (row == 0) and 1.0 or thickness - draw_list:AddNgon(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments, th); x = x + step -- N-gon - draw_list:AddCircle(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments, th); x = x + step -- Circle - draw_list:AddEllipse(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments, th); x = x + step -- Ellipse - draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, th); x = x + step -- Square - draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th); x = x + step -- Square with all rounded corners - draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, corners_tl_br); x = x + step -- Square with two rounded corners - draw_list:AddTriangle(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col, th); x = x + step -- Triangle - draw_list:AddTriangle(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col, th); x = x + step - math.floor(sz * 0.6) -- Thin triangle - - -- Concave shape: U - Shape(concave_shape, x, y); draw_list:PathStroke(col, th, ImDrawFlags.Closed); x = x + step - - -- Concave shape: Zig-Zag with sharp angles - Shape(zigzag_shape, x, y); draw_list:PathStroke(col, th, ImDrawFlags.Closed); x = x + step - - -- Horizontal/Vertical/Diagonal lines - local off = math.floor(sz * 0.4) - draw_list:AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th) - draw_list:AddLine(ImVec2(x, y + off), ImVec2(x + sz, y + off), col, th); x = x + step - draw_list:AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th) - draw_list:AddLine(ImVec2(x + off, y + sz), ImVec2(x + off, y), col, th); x = x + step - math.floor(half_sz) - if not (draw_fill and draw_strokes) then - draw_list:AddLine(ImVec2(x, y), ImVec2(x + half_sz, y + sz), col, th) - draw_list:AddLine(ImVec2(x, y + sz), ImVec2(x + half_sz, y), col, th) - end - x = x + step - math.floor(half_sz) - - -- Rotating square - for n = 1, 4 do draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y)) end - draw_list:PathStroke(col, th, ImDrawFlags.Closed); x = x + step - - -- Path - draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) - draw_list:PathStroke(col, th); x = x + step - - -- Quadratic Bezier Curve (3 control points) - draw_list:AddBezierQuadratic(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), col, th, curve_segments); x = x + step - - -- Cubic Bezier Curve (4 control points) - if not (draw_fill and draw_strokes) then - draw_list:AddBezierCubic(ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), ImVec2(x + cp4[4].x, y + cp4[4].y), col, th, curve_segments) - x = x + step - end - end - y = y + step - end - ImGui.Dummy(ImVec2(step * 15.5, step * 4.0)) - ImGui.Text("ImDrawList Vector Rendering Reference:") - ImGui.TextLinkOpenURL("https://github.com/ocornut/imgui/wiki/Draw-List") - ImGui.PopItemFlag() - ImGui.PopItemWidth() -end - -local function CustomRenderingCanvas() - local s = CRS - _, s.opt_enable_grid = ImGui.Checkbox("Enable grid", s.opt_enable_grid) - _, s.opt_enable_context_menu = ImGui.Checkbox("Enable context menu", s.opt_enable_context_menu) - ImGui.Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.") - - -- Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. - -- Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. - -- To use a child window instead we could use, e.g: - -- ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0, 0)) -- Disable padding - -- ImGui.PushStyleColor(ImGuiCol.ChildBg, IM_COL32(50, 50, 50, 255)) -- Set a background color - -- ImGui.BeginChild("canvas", ImVec2(0.0, 0.0), ImGuiChildFlags.Borders, ImGuiWindowFlags.NoMove) - -- ImGui.PopStyleColor() - -- ImGui.PopStyleVar() - -- [...] - -- ImGui.EndChild() - - -- Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() - local canvas_p0 = ImGui.GetCursorScreenPos() -- ImDrawList API uses screen coordinates! - local canvas_sz = ImGui.GetContentRegionAvail() -- Resize canvas to what's available - if canvas_sz.x < 50.0 then canvas_sz.x = 50.0 end - if canvas_sz.y < 50.0 then canvas_sz.y = 50.0 end - local canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y) - - -- Draw border and background color - local io = ImGui.GetIO() - local draw_list = ImGui.GetWindowDrawList() - draw_list:AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)) - draw_list:AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)) - - -- This will catch our interactions - ImGui.InvisibleButton("canvas", canvas_sz, bit32.bor(ImGuiButtonFlags.MouseButtonLeft, ImGuiButtonFlags.MouseButtonRight)) - local is_hovered = ImGui.IsItemHovered() -- Hovered - local is_active = ImGui.IsItemActive() -- Held - local origin = ImVec2(canvas_p0.x + s.scrolling.x, canvas_p0.y + s.scrolling.y) -- Lock scrolled origin - local mouse_pos_in_canvas = ImVec2(io.MousePos.x - origin.x, io.MousePos.y - origin.y) - local points = s.points - - -- Add first and second point - if is_hovered and not s.adding_line and ImGui.IsMouseClicked(ImGuiMouseButton.Left) then - points[#points + 1] = ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y) - points[#points + 1] = ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y) - s.adding_line = true - end - if s.adding_line then - points[#points] = ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y) - if not ImGui.IsMouseDown(ImGuiMouseButton.Left) then s.adding_line = false end - end - - -- Pan (we use a zero mouse threshold when there's no context menu) - -- You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. - local mouse_threshold_for_pan = s.opt_enable_context_menu and -1.0 or 0.0 - if is_active and ImGui.IsMouseDragging(ImGuiMouseButton.Right, mouse_threshold_for_pan) then - s.scrolling.x = s.scrolling.x + io.MouseDelta.x - s.scrolling.y = s.scrolling.y + io.MouseDelta.y - end - - -- Context menu (under default mouse threshold) - local drag_delta = ImGui.GetMouseDragDelta(ImGuiMouseButton.Right) - if s.opt_enable_context_menu and drag_delta.x == 0.0 and drag_delta.y == 0.0 then - ImGui.OpenPopupOnItemClick("context", ImGuiPopupFlags.MouseButtonRight) - end - if ImGui.BeginPopup("context") then - if s.adding_line then points[#points] = nil; points[#points] = nil end - s.adding_line = false - if ImGui.MenuItem("Remove one", nil, false, #points > 0) then points[#points] = nil; points[#points] = nil end - if ImGui.MenuItem("Remove all", nil, false, #points > 0) then table.clear(points) end - ImGui.EndPopup() - end - - -- Draw grid + all lines in the canvas - draw_list:PushClipRect(canvas_p0, canvas_p1, true) - if s.opt_enable_grid then - local GRID_STEP = 64.0 - local x = math.fmod(s.scrolling.x, GRID_STEP) - while x < canvas_sz.x do draw_list:AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40)); x = x + GRID_STEP end - local y = math.fmod(s.scrolling.y, GRID_STEP) - while y < canvas_sz.y do draw_list:AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40)); y = y + GRID_STEP end - end - for n = 1, #points - 1, 2 do - draw_list:AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0) - end - draw_list:PopClipRect() -end - -- Demonstrate using the low-level ImDrawList to draw custom shapes. +S.ShowExampleAppCustomRendering = { + -- Primitives + sz = 42.0, + base_rounding = 8.0, + base_thickness = 3.0, + animate_rounding = false, + animate_thickness = false, + ngon_segments = 6, + circle_segments_override = false, + circle_segments_override_v = 12, + curve_segments_override = false, + curve_segments_override_v = 8, + colf_stroke = ImVec4(1.000, 0.384, 0.169, 1.000), + colf_fill = ImVec4(0.416, 0.378, 0.420, 1.000), + -- Canvas + points = ImVector(), + scrolling = ImVec2(0.0, 0.0), + opt_enable_grid = true, + opt_enable_context_menu = true, + adding_line = false, + -- BG/FG draw lists + draw_bg = true, + draw_fg = true, +} function ShowExampleAppCustomRendering(p_open) + local s = S.ShowExampleAppCustomRendering local visible p_open, visible = ImGui.Begin("Example: Custom rendering", p_open) - if not visible then ImGui.End(); return p_open end - local s = CRS + if not visible then + ImGui.End() + return p_open + end + IMGUI_DEMO_MARKER("Examples/Custom rendering") + + -- Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of + -- overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your + -- types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not + -- exposed outside (to avoid messing with your types) In this example we are not using the maths operators! + if ImGui.BeginTabBar("##TabBar") then - if ImGui.BeginTabItem("Primitives") then CustomRenderingPrimitives(); ImGui.EndTabItem() end - if ImGui.BeginTabItem("Canvas") then CustomRenderingCanvas(); ImGui.EndTabItem() end + if ImGui.BeginTabItem("Primitives") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/Primitives") + ImGui.PushItemWidth(-ImGui.GetFontSize() * 15) + ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInput, true) + local draw_list = ImGui.GetWindowDrawList() + + -- Draw gradients + -- (note that those are currently exacerbating our sRGB/Linear issues) + -- Calling ImGui.GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. + -- [Port] GetColorU32(u32, nil, true): the ImU32 overload is selected explicitly + ImGui.Text("Gradients") + local gradient_size = ImVec2(ImGui.CalcItemWidth(), ImGui.GetFrameHeight()) + do + ImGui.InvisibleButton("##gradient1", gradient_size) + local col_a = ImGui.GetColorU32(IM_COL32(0, 0, 0, 255), nil, true) + local col_b = ImGui.GetColorU32(IM_COL32(255, 255, 255, 255), nil, true) + draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) + end + do + ImGui.InvisibleButton("##gradient2", gradient_size) + local col_a = ImGui.GetColorU32(IM_COL32(0, 255, 0, 255), nil, true) + local col_b = ImGui.GetColorU32(IM_COL32(255, 0, 0, 255), nil, true) + draw_list:AddRectFilledMultiColor(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), col_a, col_b, col_b, col_a) + end + + -- Draw a bunch of primitives + ImGui.Text("All primitives") + + s.sz = ImGui.DragFloat("Size", s.sz, 0.2, 0.2, 100.0, "%.0f") + + local rounding_anim_period = 3.0 + local rounding_wave = 1.0 - math.abs(math.fmod(ImGui.GetTime(), rounding_anim_period) * (2.0 / rounding_anim_period) - 1.0) + local rounding = s.animate_rounding and math.floor(rounding_wave * s.base_rounding * 10.0) / 10.0 or s.base_rounding -- Sub-integer rounding works but has discontinuities in small values, so best disable we + s.base_rounding = ImGui.DragFloat("Rounding", s.base_rounding, 0.02, 0.0, 32.0, "%.1f"); ImGui.SameLine() + _, s.animate_rounding = ImGui.Checkbox("Animate##rounding", s.animate_rounding); ImGui.SameLine() + ImGui.Text("%.2f", rounding) + + local thickness_anim_period = 5.0 + local thickness_wave = 1.0 - math.abs(math.fmod(ImGui.GetTime(), thickness_anim_period) * (2.0 / thickness_anim_period) - 1.0) + local thickness = s.animate_thickness and thickness_wave * s.base_thickness or s.base_thickness + s.base_thickness = ImGui.DragFloat("Thickness", s.base_thickness, 0.02, 0.0, 32.0, "%.02f"); ImGui.SameLine() + _, s.animate_thickness = ImGui.Checkbox("Animate##thickness", s.animate_thickness); ImGui.SameLine() + ImGui.Text("%.2f", thickness) + + local changed + s.ngon_segments = ImGui.SliderInt("N-gon sides", s.ngon_segments, 3, 12) + _, s.circle_segments_override = ImGui.Checkbox("##CircleSegmentOverride", s.circle_segments_override) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + s.circle_segments_override_v, changed = ImGui.SliderInt("Circle segments override", s.circle_segments_override_v, 3, 30) + s.circle_segments_override = s.circle_segments_override or changed + _, s.curve_segments_override = ImGui.Checkbox("##CurvesSegmentOverride", s.curve_segments_override) + ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) + s.curve_segments_override_v, changed = ImGui.SliderInt("Curves segments override", s.curve_segments_override_v, 3, 30) + s.curve_segments_override = s.curve_segments_override or changed + ImGui.ColorEdit4("Stroke Color", s.colf_stroke) + ImGui.ColorEdit4("Fill Color", s.colf_fill) + + -- [Port] ImDrawFlags_StrokeInside/StrokeCenter/StrokeCenterBiased/StrokeOutside/StrokeLegacy, AAFill/AALines/AALineEnds, + -- [Port] JoinMiter/CapSquare, AllowInPushScope_ and ImDrawList::PushDrawFlag()/PopDrawFlag() don't exist in this port + -- [Port] (1.92 stroker): prim_stroke_flags/prim_other_flags/scope_flags and their widgets are not ported, flags = None. + ImGui.SeparatorText("Per primitive flags (AddXXX functions)") + ImGui.TextDisabled("(not supported by this port)") -- [Port] + --ImGui.CheckboxFlags("UseTexForRoundCorners", &prim_other_flags, ImDrawFlags_UseTexForRoundCorners); + + ImGui.SeparatorText("Current ImDrawList flags (e.g. PushDrawFlag function)") + ImGui.PushID("ScopeFlags") + ImGui.TextDisabled("(not supported by this port)") -- [Port] + --ImGui.CheckboxFlags("UseTexForRoundCorners", &scope_flags, ImDrawFlags_UseTexForRoundCorners); + ImGui.PopID() + ImGui.Spacing() + + -- [Port] draw_list->PushDrawFlag(ImDrawFlags_AllowInPushScope_, false); // Reset all existing (very unusual: done for this demo) + -- [Port] draw_list->PushDrawFlag(scope_flags, true); + local flags = ImDrawFlags.None -- [Port] prim_stroke_flags | prim_other_flags + + -- [Port] In this port AddNgon/AddCircle/AddEllipse/AddTriangle/AddLine*/AddBezier*/PathFillConvex take no flags argument (dropped below). + local sz = s.sz + local start_pos = ImGui.GetCursorScreenPos() + local pi = 3.141592 + local step = sz + 10.0 + local corners_tl_br = bit32.bor(ImDrawFlags.RoundCornersTopLeft, ImDrawFlags.RoundCornersBottomRight) -- [Port] 1.92 names (upstream ImDrawFlags_RoundTopLeft/RoundBottomRight) + local half_sz = sz * 0.5 + local circle_segments = s.circle_segments_override and s.circle_segments_override_v or 0 + local curve_segments = s.curve_segments_override and s.curve_segments_override_v or 0 + local cp3 = { ImVec2(0.0, sz * 0.6), ImVec2(sz * 0.5, -sz * 0.4), ImVec2(sz, sz) } -- Control points for curves + local cp4 = { ImVec2(0.0, 0.0), ImVec2(sz * 1.3, sz * 0.3), ImVec2(sz - sz * 1.3, sz - sz * 0.3), ImVec2(sz, sz) } + local concave_shape = { ImVec2(0.0, 0.0), ImVec2(0.3, 0.0), ImVec2(0.3, 0.7), ImVec2(0.7, 0.7), ImVec2(0.7, 0.0), ImVec2(1.0, 0.0), ImVec2(1.0, 1.0), ImVec2(0.0, 1.0) } -- |_| looking shape. Normalized. + local zigzag_shape = { ImVec2(0.0, 0.0), ImVec2(0.9, 0.0), ImVec2(1.0, 0.1), ImVec2(1.0, 0.9), ImVec2(0.9, 1.0), ImVec2(0.3, 1.0), ImVec2(0.3, 0.4), ImVec2(0.9, 0.4) } + local rotating_square = {} -- 1-based + for side = 0, 4 - 1 do + local t = ImGui.GetTime() * 0.1 + side * pi * 0.5 + rotating_square[side + 1] = ImVec2(math.cos(t) * half_sz, math.sin(t) * half_sz) + end + + local x = start_pos.x + local y = start_pos.y + for row = 0, 4 - 1 do + x = start_pos.x + local draw_fill = (row == 2 or row == 3) + local draw_strokes = (row == 0 or row == 1 or row == 3) + if draw_fill then + -- FILLED SHAPES + local col = ImColor(s.colf_fill):U32() + draw_list:AddNgonFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments); x = x + step -- N-gon + draw_list:AddCircleFilled(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments); x = x + step -- Circle + draw_list:AddEllipseFilled(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments); x = x + step -- Ellipse + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, flags); x = x + step -- Square + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, flags); x = x + step -- Square with all rounded corners + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, bit32.bor(flags, corners_tl_br)); x = x + step -- Square with two rounded corners + draw_list:AddTriangleFilled(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col); x = x + step -- Triangle + draw_list:AddTriangleFilled(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col); x = x + step - math.floor(sz * 0.6) -- Thin triangle + + -- Concave shape: U + for _, p in ipairs(concave_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathFillConcave(col) + x = x + step + + -- Concave shape: Zig-Zag with sharp angles (see difference with/without JoinMiter) + for _, p in ipairs(zigzag_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathFillConcave(col) + x = x + step + + -- Horizontal/Vertical lines + -- (here for consistency with the strokes section. AddRectFilled() is roughly close to AddLineH(), AddLineV() + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x = x + step + draw_list:AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x = x + step - math.floor(half_sz) + if not (draw_fill and draw_strokes) then -- -V560 + local block_sz, off = 1, 0 + while block_sz < 16 and off + block_sz <= sz do + draw_list:AddRectFilled(ImVec2(x, y + off), ImVec2(x + block_sz, y + off + block_sz), col) + off = off + block_sz + 1; block_sz = block_sz + 1 + end + end + x = x + step - math.floor(half_sz) + + -- Rotating square + for n = 0, 4 - 1 do + draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n + 1].x, y + half_sz + rotating_square[n + 1].y)) + end + draw_list:PathFillConvex(col) -- [Port] no flags argument + x = x + step + + -- Path + draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) + draw_list:PathFillConvex(col) + x = x + step + + -- Quadratic Bezier Curve (3 control points) + draw_list:PathLineTo(ImVec2(x + cp3[1].x, y + cp3[1].y)) + draw_list:PathBezierQuadraticCurveTo(ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), curve_segments) + draw_list:PathFillConvex(col) + x = x + step + + if not (draw_fill and draw_strokes) then -- -V560 + draw_list:AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)) + x = x + step + end + end + if draw_fill and draw_strokes then + x = start_pos.x + end + if draw_strokes then + -- STROKES + -- First row uses a thickness of 1.0f, second row uses the configurable thickness + local col = ImColor(s.colf_stroke):U32() + local th = (row == 0) and 1.0 or thickness + draw_list:AddNgon(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments, th); x = x + step -- N-gon + draw_list:AddCircle(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments, th); x = x + step -- Circle + draw_list:AddEllipse(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments, th); x = x + step -- Ellipse + draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, th, flags); x = x + step -- Square + draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, flags); x = x + step -- Square with all rounded corners + draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, bit32.bor(flags, corners_tl_br)); x = x + step -- Square with two rounded corners + draw_list:AddTriangle(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col, th); x = x + step -- Triangle + draw_list:AddTriangle(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col, th); x = x + step - math.floor(sz * 0.6) -- Thin triangle + + -- Concave shape: U + for _, p in ipairs(concave_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathStroke(col, th, bit32.bor(flags, ImDrawFlags.Closed)) + x = x + step + + -- Concave shape: Zig-Zag with sharp angles (see difference with/without JoinMiter) + for _, p in ipairs(zigzag_shape) do + draw_list:PathLineTo(ImVec2(x + math.floor(sz * p.x), y + math.floor(sz * p.y))) + end + draw_list:PathStroke(col, th, bit32.bor(flags, ImDrawFlags.Closed)) + x = x + step + + -- Horizontal/Vertical/Diagonal lines + local off = math.floor(sz * 0.4) + draw_list:AddLineH(x, x + sz, y, col, th) + draw_list:AddLine(ImVec2(x, y + off), ImVec2(x + sz, y + off), col, th) + x = x + step + draw_list:AddLineV(x, y, y + sz, col, th) + draw_list:AddLine(ImVec2(x + off, y + sz), ImVec2(x + off, y), col, th) + x = x + step - math.floor(half_sz) + if not (draw_fill and draw_strokes) then -- -V560 + draw_list:AddLine(ImVec2(x, y), ImVec2(x + half_sz, y + sz), col, th) + draw_list:AddLine(ImVec2(x, y + sz), ImVec2(x + half_sz, y), col, th) + end + x = x + step - math.floor(half_sz) + + -- Rotating square + for n = 0, 4 - 1 do + draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n + 1].x, y + half_sz + rotating_square[n + 1].y)) + end + draw_list:PathStroke(col, th, bit32.bor(flags, ImDrawFlags.Closed)) + --for (int n = 0; n < 4; n++) // ...made of individual line + -- draw_list->AddLine({ x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y }, { x + half_sz + rotating_square[(n + 1) & 3].x, y + half_sz + rotating_square[(n + 1) & 3].y }, col, th, flags); + x = x + step + + -- Path + draw_list:PathArcTo(ImVec2(x + half_sz, y + half_sz), half_sz, pi * -0.5, pi * 1.1) + draw_list:PathStroke(col, th, flags) + x = x + step + + -- Quadratic Bezier Curve (3 control points) + draw_list:AddBezierQuadratic(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), col, th, curve_segments) + x = x + step + + -- Cubic Bezier Curve (4 control points) + if not (draw_fill and draw_strokes) then -- -V560 + draw_list:AddBezierCubic(ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), ImVec2(x + cp4[4].x, y + cp4[4].y), col, th, curve_segments) + x = x + step + end + end + y = y + step + end + + ImGui.Dummy(ImVec2(step * 15.5, step * 4.0)) + -- [Port] draw_list->PopDrawFlag(); x2 + + ImGui.Text("ImDrawList Vector Rendering Reference:") + ImGui.TextLinkOpenURL("https://github.com/ocornut/imgui/wiki/Draw-List") + + ImGui.PopItemFlag() + ImGui.PopItemWidth() + ImGui.EndTabItem() + end + + if ImGui.BeginTabItem("Canvas") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/Canvas") + local points = s.points + local scrolling = s.scrolling + + _, s.opt_enable_grid = ImGui.Checkbox("Enable grid", s.opt_enable_grid) + _, s.opt_enable_context_menu = ImGui.Checkbox("Enable context menu", s.opt_enable_context_menu) + ImGui.Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.") + + -- Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. + -- Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. + -- To use a child window instead we could use, e.g: + -- ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0, 0)) -- Disable padding + -- ImGui.PushStyleColor(ImGuiCol.ChildBg, IM_COL32(50, 50, 50, 255)) -- Set a background color + -- ImGui.BeginChild("canvas", ImVec2(0.0, 0.0), ImGuiChildFlags.Borders, ImGuiWindowFlags.NoMove) + -- ImGui.PopStyleColor() + -- ImGui.PopStyleVar() + -- [...] + -- ImGui.EndChild() + + -- Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() + local canvas_p0 = ImGui.GetCursorScreenPos() -- ImDrawList API uses screen coordinates! + local canvas_sz = ImGui.GetContentRegionAvail() -- Resize canvas to what's available + if canvas_sz.x < 50.0 then canvas_sz.x = 50.0 end + if canvas_sz.y < 50.0 then canvas_sz.y = 50.0 end + local canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y) + + -- Draw border and background color + local io = ImGui.GetIO() + local draw_list = ImGui.GetWindowDrawList() + draw_list:AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)) + draw_list:AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)) + + -- This will catch our interactions + ImGui.InvisibleButton("canvas", canvas_sz, bit32.bor(ImGuiButtonFlags.MouseButtonLeft, ImGuiButtonFlags.MouseButtonRight)) + local is_hovered = ImGui.IsItemHovered() -- Hovered + local is_active = ImGui.IsItemActive() -- Held + local origin = ImVec2(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y) -- Lock scrolled origin + local mouse_pos_in_canvas = ImVec2(io.MousePos.x - origin.x, io.MousePos.y - origin.y) + + -- Add first and second point + if is_hovered and not s.adding_line and ImGui.IsMouseClicked(ImGuiMouseButton.Left) then + points:push_back(ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y)) -- [Port] copies: ImVector stores references + points:push_back(ImVec2(mouse_pos_in_canvas.x, mouse_pos_in_canvas.y)) + s.adding_line = true + end + if s.adding_line then + ImVec2_Copy(points:back(), mouse_pos_in_canvas) + if not ImGui.IsMouseDown(ImGuiMouseButton.Left) then + s.adding_line = false + end + end + + -- Pan (we use a zero mouse threshold when there's no context menu) + -- You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. + local mouse_threshold_for_pan = s.opt_enable_context_menu and -1.0 or 0.0 + if is_active and ImGui.IsMouseDragging(ImGuiMouseButton.Right, mouse_threshold_for_pan) then + scrolling.x = scrolling.x + io.MouseDelta.x + scrolling.y = scrolling.y + io.MouseDelta.y + end + + -- Context menu (under default mouse threshold) + local drag_delta = ImGui.GetMouseDragDelta(ImGuiMouseButton.Right) + if s.opt_enable_context_menu and drag_delta.x == 0.0 and drag_delta.y == 0.0 then + ImGui.OpenPopupOnItemClick("context", ImGuiPopupFlags.MouseButtonRight) + end + if ImGui.BeginPopup("context") then + if s.adding_line then + points:resize(points.Size - 2) + end + s.adding_line = false + if ImGui.MenuItem("Remove one", nil, false, points.Size > 0) then points:resize(points.Size - 2) end + if ImGui.MenuItem("Remove all", nil, false, points.Size > 0) then points:clear() end + ImGui.EndPopup() + end + + -- Draw grid + all lines in the canvas + draw_list:PushClipRect(canvas_p0, canvas_p1, true) + if s.opt_enable_grid then + local GRID_STEP = 64.0 + local x = math.fmod(scrolling.x, GRID_STEP) + while x < canvas_sz.x do + draw_list:AddLineV(canvas_p0.x + x, canvas_p0.y, canvas_p1.y, IM_COL32(200, 200, 200, 40)) + x = x + GRID_STEP + end + local y = math.fmod(scrolling.y, GRID_STEP) + while y < canvas_sz.y do + draw_list:AddLineH(canvas_p0.x, canvas_p1.x, canvas_p0.y + y, IM_COL32(200, 200, 200, 40)) + y = y + GRID_STEP + end + end + for n = 0, points.Size - 1, 2 do + draw_list:AddLine(ImVec2(origin.x + points.Data[n + 1].x, origin.y + points.Data[n + 1].y), ImVec2(origin.x + points.Data[n + 2].x, origin.y + points.Data[n + 2].y), IM_COL32(255, 255, 0, 255), 2.0) + end + draw_list:PopClipRect() + + ImGui.EndTabItem() + end + if ImGui.BeginTabItem("BG/FG draw lists") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/BG & FG draw lists") _, s.draw_bg = ImGui.Checkbox("Draw in Background draw list", s.draw_bg) ImGui.SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.") _, s.draw_fg = ImGui.Checkbox("Draw in Foreground draw list", s.draw_fg) ImGui.SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.") - local window_pos, window_size = ImGui.GetWindowPos(), ImGui.GetWindowSize() + local window_pos = ImGui.GetWindowPos() + local window_size = ImGui.GetWindowSize() local window_center = ImVec2(window_pos.x + window_size.x * 0.5, window_pos.y + window_size.y * 0.5) - if s.draw_bg then ImGui.GetBackgroundDrawList():AddCircle(window_center, window_size.x * 0.6, IM_COL32(255, 0, 0, 200), 0, 10 + 4) end - if s.draw_fg then ImGui.GetForegroundDrawList():AddCircle(window_center, window_size.y * 0.6, IM_COL32(0, 255, 0, 200), 0, 10) end + if s.draw_bg then + ImGui.GetBackgroundDrawList():AddCircle(window_center, window_size.x * 0.6, IM_COL32(255, 0, 0, 200), 0, 10 + 4) + end + if s.draw_fg then + ImGui.GetForegroundDrawList():AddCircle(window_center, window_size.y * 0.6, IM_COL32(0, 255, 0, 200), 0, 10) + end ImGui.EndTabItem() end @@ -5550,35 +9827,42 @@ function ShowExampleAppCustomRendering(p_open) -- We use functions in ImDrawList as each draw list contains a convenience splitter, -- but you can also instantiate your own ImDrawListSplitter if you need to nest them. if ImGui.BeginTabItem("Draw Channels") then + IMGUI_DEMO_MARKER("Examples/Custom rendering/Draw Channels") local draw_list = ImGui.GetWindowDrawList() - ImGui.Text("Blue shape is drawn first: appears in back") - ImGui.Text("Red shape is drawn after: appears in front") - local p0 = ImGui.GetCursorScreenPos() - draw_list:AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue - draw_list:AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)) -- Red - ImGui.Dummy(ImVec2(75, 75)) + do + ImGui.Text("Blue shape is drawn first: appears in back") + ImGui.Text("Red shape is drawn after: appears in front") + local p0 = ImGui.GetCursorScreenPos() + draw_list:AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue + draw_list:AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)) -- Red + ImGui.Dummy(ImVec2(75, 75)) + end ImGui.Separator() - ImGui.Text("Blue shape is drawn first, into channel 1: appears in front") - ImGui.Text("Red shape is drawn after, into channel 0: appears in back") - local p1 = ImGui.GetCursorScreenPos() + do + ImGui.Text("Blue shape is drawn first, into channel 1: appears in front") + ImGui.Text("Red shape is drawn after, into channel 0: appears in back") + local p1 = ImGui.GetCursorScreenPos() - -- Create 2 channels and draw a Blue shape THEN a Red shape. - -- You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls. - draw_list:ChannelsSplit(2) - draw_list:ChannelsSetCurrent(1) - draw_list:AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue - draw_list:ChannelsSetCurrent(0) - draw_list:AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)) -- Red + -- Create 2 channels and draw a Blue shape THEN a Red shape. + -- You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls. + draw_list:ChannelsSplit(2) + draw_list:ChannelsSetCurrent(1) + draw_list:AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)) -- Blue + draw_list:ChannelsSetCurrent(0) + draw_list:AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)) -- Red - -- Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1. - -- This works by copying draw indices only (vertices are not copied). - draw_list:ChannelsMerge() - ImGui.Dummy(ImVec2(75, 75)) - ImGui.Text("After reordering, contents of channel 0 appears below channel 1.") + -- Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1. + -- This works by copying draw indices only (vertices are not copied). + draw_list:ChannelsMerge() + ImGui.Dummy(ImVec2(75, 75)) + ImGui.Text("After reordering, contents of channel 0 appears below channel 1.") + end ImGui.EndTabItem() end + ImGui.EndTabBar() end + ImGui.End() return p_open end @@ -5587,14 +9871,19 @@ end -- [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() ------------------------------------------------------------------------------- --- KeepWindowPadding: Keep WindowPadding to help understand that DockSpace() is a widget inside the window. -local DSA = { IsFullscreen = true, KeepWindowPadding = false, DockSpaceFlags = 0, opt_demo_mode = 0, opt_demo_mode_changed = false } +function ImGuiDemoDockspaceArgs() + return { + IsFullscreen = true, + KeepWindowPadding = false, -- Keep WindowPadding to help understand that DockSpace() is a widget inside the window. + DockSpaceFlags = ImGuiDockNodeFlags.None, + } +end -- THIS IS A DEMO FOR ADVANCED USAGE OF DockSpace(). -- MOST REGULAR APPLICATIONS WANTING TO ALLOW DOCKING WINDOWS ON THE EDGE OF YOUR SCREEN CAN SIMPLY USE: --- ImGui.NewFrame() + ImGui.DockSpaceOverViewport() -- Create a dockspace in main viewport +-- ImGui.NewFrame(); + ImGui.DockSpaceOverViewport(); -- Create a dockspace in main viewport -- OR: --- ImGui.NewFrame() + ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode) -- Create a dockspace in main viewport, where central node is transparent. +-- ImGui.NewFrame(); + ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode); -- Create a dockspace in main viewport, where central node is transparent. -- Demonstrate using DockSpace() to create an explicit docking node within an existing window, with various options. -- Read https://github.com/ocornut/imgui/wiki/Docking for details. -- The reasons we do not use DockSpaceOverViewport() in this demo is because: @@ -5603,22 +9892,23 @@ local DSA = { IsFullscreen = true, KeepWindowPadding = false, DockSpaceFlags = 0 -- Also see 'Demo->Examples->Documents' for a less abstract version of this. -- - (2) we allow the host window to have padding (when args.UsePadding == true) -- - (3) we expose variety of other flags. -local function ShowExampleAppDockSpaceAdvanced(args, p_open) +function ShowExampleAppDockSpaceAdvanced(args, p_open) local dockspace_flags = args.DockSpaceFlags - -- We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, + -- We are using the ImGuiWindowFlags.NoDocking flag to make the parent window not dockable into, -- because it would be confusing to have two docking targets within each others. - local W = ImGuiWindowFlags - local window_flags = W.NoDocking + local window_flags = ImGuiWindowFlags.NoDocking if args.IsFullscreen then - -- Fullscreen dockspace: practically the same as calling DockSpaceOverViewport() + -- Fullscreen dockspace: practically the same as calling DockSpaceOverViewport(); local viewport = ImGui.GetMainViewport() ImGui.SetNextWindowPos(viewport.WorkPos) ImGui.SetNextWindowSize(viewport.WorkSize) ImGui.SetNextWindowViewport(viewport.ID) ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0.0) ImGui.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 0.0) - window_flags = bit32.bor(window_flags, W.NoTitleBar, W.NoCollapse, W.NoResize, W.NoMove, W.NoBringToFrontOnFocus, W.NoNavFocus, W.NoBackground) + window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoTitleBar, ImGuiWindowFlags.NoCollapse, ImGuiWindowFlags.NoResize, ImGuiWindowFlags.NoMove) + window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoBringToFrontOnFocus, ImGuiWindowFlags.NoNavFocus) + window_flags = bit32.bor(window_flags, ImGuiWindowFlags.NoBackground) else -- Floating dockspace dockspace_flags = bit32.band(dockspace_flags, bit32.bnot(ImGuiDockNodeFlags.PassthruCentralNode)) @@ -5629,70 +9919,102 @@ local function ShowExampleAppDockSpaceAdvanced(args, p_open) -- all active windows docked into it will lose their parent and become undocked. -- We cannot preserve the docking relationship between an active window and an inactive docking, otherwise -- any change of dockspace/settings would lead to windows being stuck in limbo and never being visible. - if not args.KeepWindowPadding then ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0.0, 0.0)) end + if not args.KeepWindowPadding then + ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, ImVec2(0.0, 0.0)) + end p_open = ImGui.Begin("Window with a DockSpace", p_open, window_flags) - if not args.KeepWindowPadding then ImGui.PopStyleVar() end + if not args.KeepWindowPadding then + ImGui.PopStyleVar() + end - if args.IsFullscreen then ImGui.PopStyleVar(2) end + if args.IsFullscreen then + ImGui.PopStyleVar(2) + end -- Submit the DockSpace widget inside our window -- - Note that the id here is different from the one used by DockSpaceOverViewport(), so docking state won't get transfered between "Basic" and "Advanced" demos. -- - If we made the ShowExampleAppDockSpaceBasic() calculate its own ID and pass it to DockSpaceOverViewport() the ID could easily match. local dockspace_id = ImGui.GetID("MyDockSpace") ImGui.DockSpace(dockspace_id, ImVec2(0.0, 0.0), dockspace_flags) + ImGui.End() return p_open end +function ShowExampleAppDockSpaceBasic(flags) + -- Basic version which you can use in many apps: + -- e.g: + -- ImGui.DockSpaceOverViewport(); + -- or: + -- ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode); -- Central node will be transparent + -- or: + -- local viewport = ImGui.GetMainViewport(); + -- ImGui.DockSpaceOverViewport(0, viewport, ImGuiDockNodeFlags.None); + + ImGui.DockSpaceOverViewport(0, nil, flags) +end + +S.ShowExampleAppDockSpace = { + opt_demo_mode = 0, + opt_demo_mode_changed = false, + args = ImGuiDemoDockspaceArgs(), +} function ShowExampleAppDockSpace(p_open) - local args = DSA - if args.opt_demo_mode == 0 then - -- Basic version which you can use in many apps: - -- e.g: - -- ImGui.DockSpaceOverViewport() - -- or: - -- ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode) -- Central node will be transparent - -- or: - -- local viewport = ImGui.GetMainViewport() - -- ImGui.DockSpaceOverViewport(0, viewport, ImGuiDockNodeFlags.None) - ImGui.DockSpaceOverViewport(0, nil, args.DockSpaceFlags) + local s = S.ShowExampleAppDockSpace + local args = s.args + + if s.opt_demo_mode == 0 then + ShowExampleAppDockSpaceBasic(args.DockSpaceFlags) else p_open = ShowExampleAppDockSpaceAdvanced(args, p_open) end -- Refocus our window to minimize perceived loss of focus when changing mode (caused by the fact that each use a different window, which would not happen in a real app) - if args.opt_demo_mode_changed then ImGui.SetNextWindowFocus() end + if s.opt_demo_mode_changed then + ImGui.SetNextWindowFocus() + end p_open = ImGui.Begin("Examples: Dockspace", p_open, ImGuiWindowFlags.MenuBar) - local c1, c2 - c1, args.opt_demo_mode = ImGui.RadioButton("Basic demo mode", args.opt_demo_mode, 0) - c2, args.opt_demo_mode = ImGui.RadioButton("Advanced demo mode", args.opt_demo_mode, 1) - args.opt_demo_mode_changed = c1 or c2 + s.opt_demo_mode_changed = false + local pressed + pressed, s.opt_demo_mode = ImGui.RadioButton("Basic demo mode", s.opt_demo_mode, 0) + s.opt_demo_mode_changed = s.opt_demo_mode_changed or pressed + pressed, s.opt_demo_mode = ImGui.RadioButton("Advanced demo mode", s.opt_demo_mode, 1) + s.opt_demo_mode_changed = s.opt_demo_mode_changed or pressed + ImGui.SeparatorText("Options") - local D = ImGuiDockNodeFlags + if bit32.band(ImGui.GetIO().ConfigFlags, ImGuiConfigFlags.DockingEnable) == 0 then ShowDockingDisabledMessage() - elseif args.opt_demo_mode == 0 then - args.DockSpaceFlags = bit32.band(args.DockSpaceFlags, D.PassthruCentralNode) -- Allowed flags - _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, D.PassthruCentralNode) - else + elseif s.opt_demo_mode == 0 then + args.DockSpaceFlags = bit32.band(args.DockSpaceFlags, ImGuiDockNodeFlags.PassthruCentralNode) -- Allowed flags + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, ImGuiDockNodeFlags.PassthruCentralNode) + elseif s.opt_demo_mode == 1 then _, args.IsFullscreen = ImGui.Checkbox("Fullscreen", args.IsFullscreen) _, args.KeepWindowPadding = ImGui.Checkbox("Keep Window Padding", args.KeepWindowPadding) ImGui.SameLine() HelpMarker("This is mostly exposed to facilitate understanding that a DockSpace() is _inside_ a window.") ImGui.BeginDisabled(args.IsFullscreen == false) - _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, D.PassthruCentralNode) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: PassthruCentralNode", args.DockSpaceFlags, ImGuiDockNodeFlags.PassthruCentralNode) ImGui.EndDisabled() - for _, n in ipairs({ "NoDockingOverCentralNode", "NoDockingSplit", "NoUndocking", "NoResize", "AutoHideTabBar" }) do - if D[n] then _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: " .. n, args.DockSpaceFlags, D[n]) end - end + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoDockingOverCentralNode", args.DockSpaceFlags, ImGuiDockNodeFlags.NoDockingOverCentralNode) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoDockingSplit", args.DockSpaceFlags, ImGuiDockNodeFlags.NoDockingSplit) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoUndocking", args.DockSpaceFlags, ImGuiDockNodeFlags.NoUndocking) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: NoResize", args.DockSpaceFlags, ImGuiDockNodeFlags.NoResize) + _, args.DockSpaceFlags = ImGui.CheckboxFlags("Flag: AutoHideTabBar", args.DockSpaceFlags, ImGuiDockNodeFlags.AutoHideTabBar) end -- Show demo options and help if ImGui.BeginMenuBar() then if ImGui.BeginMenu("Help") then - ImGui.TextUnformatted("This demonstrates the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window.\nThe \"Basic\" version uses the ImGui::DockSpaceOverViewport() helper. Most applications can probably use this.") + ImGui.TextUnformatted( + "This demonstrates the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window." .. "\n" .. + "The \"Basic\" version uses the ImGui::DockSpaceOverViewport() helper. Most applications can probably use this.") ImGui.Separator() - ImGui.TextUnformatted("When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!\n- Drag from window title bar or their tab to dock/undock.\n- Drag from window menu button (upper-left button) to undock an entire node (all windows).\n- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)\n- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)") + ImGui.TextUnformatted("When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" .. "\n" .. + "- Drag from window title bar or their tab to dock/undock." .. "\n" .. + "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." .. "\n" .. + "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" .. "\n" .. + "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)") ImGui.Separator() ImGui.TextUnformatted("More details:"); ImGui.Bullet(); ImGui.SameLine(); ImGui.TextLinkOpenURL("Docking Wiki page", "https://github.com/ocornut/imgui/wiki/Docking") ImGui.BulletText("Read comments in ShowExampleAppDockSpace()") @@ -5700,6 +10022,7 @@ function ShowExampleAppDockSpace(p_open) end ImGui.EndMenuBar() end + ImGui.End() return p_open end @@ -5709,93 +10032,139 @@ end ------------------------------------------------------------------------------- -- Simplified structure to mimic a Document model --- NameBuf: Document title --- UID: Unique ID (necessary as we can change title) --- Open: Set when open (we keep an array of all available documents to simplify demo code!) --- OpenPrev: Copy of Open from last update. --- Dirty: Set when the document has been modified --- Color: An arbitrary variable associated to the document -local function MyDocument(uid, name, open, color) +-- Name Document title -- [Port] char[32] text buffer, read with ImGui.TextBufferToString() +-- UID Unique ID (necessary as we can change title) +-- Open Set when open (we keep an array of all available documents to simplify demo code!) +-- OpenPrev Copy of Open from last update. +-- Dirty Set when the document has been modified +-- Color An arbitrary variable associated to the document +local MyDocumentMT = {} +MyDocumentMT.__index = MyDocumentMT +function MyDocument(uid, name, open, color) if open == nil then open = true end - local d = { UID = uid, NameBuf = Buf(name, 32), Open = open, OpenPrev = open, Dirty = false, Color = color or ImVec4(1.0, 1.0, 1.0, 1.0) } - function d:Name() return BufStr(self.NameBuf) end - function d:DoOpen() self.Open = true end - function d:DoForceClose() self.Open = false; self.Dirty = false end - function d:DoSave() self.Dirty = false end - return d + if color == nil then color = ImVec4(1.0, 1.0, 1.0, 1.0) end + local self = setmetatable({}, MyDocumentMT) + self.UID = uid + self.Name = ImGui.NewTextBuffer(name, 32) + self.Open = open; self.OpenPrev = open + self.Dirty = false + self.Color = color + return self +end +function MyDocumentMT:DoOpen() self.Open = true end +function MyDocumentMT:DoForceClose() self.Open = false; self.Dirty = false end +function MyDocumentMT:DoSave() self.Dirty = false end + +local ExampleAppDocumentsMT = {} +ExampleAppDocumentsMT.__index = ExampleAppDocumentsMT +function ExampleAppDocuments() + local self = setmetatable({}, ExampleAppDocumentsMT) + self.Documents = ImVector() + self.CloseQueue = ImVector() + self.RenamingDoc = nil + self.RenamingStarted = false + + self.Documents:push_back(MyDocument(0, "Lettuce", true, ImVec4(0.4, 0.8, 0.4, 1.0))) + self.Documents:push_back(MyDocument(1, "Eggplant", true, ImVec4(0.8, 0.5, 1.0, 1.0))) + self.Documents:push_back(MyDocument(2, "Carrot", true, ImVec4(1.0, 0.8, 0.5, 1.0))) + self.Documents:push_back(MyDocument(3, "Tomato", false, ImVec4(1.0, 0.3, 0.4, 1.0))) + self.Documents:push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4, 0.8, 0.8, 1.0))) + self.Documents:push_back(MyDocument(5, "Some Document", false, ImVec4(0.8, 0.8, 1.0, 1.0))) + return self end -local Docs = nil -local function DocsInit() - local app = { Documents = { - MyDocument(0, "Lettuce", true, ImVec4(0.4, 0.8, 0.4, 1.0)), - MyDocument(1, "Eggplant", true, ImVec4(0.8, 0.5, 1.0, 1.0)), - MyDocument(2, "Carrot", true, ImVec4(1.0, 0.8, 0.5, 1.0)), - MyDocument(3, "Tomato", false, ImVec4(1.0, 0.3, 0.4, 1.0)), - MyDocument(4, "A Rather Long Title", false, ImVec4(0.4, 0.8, 0.8, 1.0)), - MyDocument(5, "Some Document", false, ImVec4(0.8, 0.8, 1.0, 1.0)), - }, CloseQueue = {}, RenamingDoc = nil, RenamingStarted = false, - opt_target = 1, opt_reorderable = true, opt_fitting_flags = ImGuiTabBarFlags.FittingPolicyDefault_ } - function app:QueueClose(doc) - for _, d in ipairs(self.CloseQueue) do if d == doc then return end end - self.CloseQueue[#self.CloseQueue + 1] = doc - end - -- As we allow to change document name, we append a never-changing document ID so tabs are stable - function app:GetTabName(doc) return string.format("%s###doc%d", doc:Name(), doc.UID) end - -- Display placeholder contents for the Document - function app:DisplayDocContents(doc) - ImGui.PushID("doc" .. doc.UID) - ImGui.Text("Document \"%s\"", doc:Name()) - ImGui.PushStyleColor(ImGuiCol.Text, doc.Color) - ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") - ImGui.PopStyleColor() +-- As we allow to change document name, we append a never-changing document ID so tabs are stable +function ExampleAppDocumentsMT:GetTabName(doc) -- [Port] returns the string instead of filling out_buf + return string.format("%s###doc%d", ImGui.TextBufferToString(doc.Name), doc.UID) +end - ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.R), ImGuiInputFlags.Tooltip) - if ImGui.Button("Rename..") then self.RenamingDoc = doc; self.RenamingStarted = true end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.M), ImGuiInputFlags.Tooltip) - if ImGui.Button("Modify") then doc.Dirty = true end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.S), ImGuiInputFlags.Tooltip) - if ImGui.Button("Save") then doc:DoSave() end - ImGui.SameLine() - ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.W), ImGuiInputFlags.Tooltip) - if ImGui.Button("Close") then self:QueueClose(doc) end - ImGui.ColorEdit3("color", doc.Color) -- Useful to test drag and drop and hold-dragged-to-open-tab behavior. - ImGui.PopID() +-- Display placeholder contents for the Document +function ExampleAppDocumentsMT:DisplayDocContents(doc) + ImGui.PushID(doc.UID) -- [Port] PushID(doc): no pointer IDs, UID is unique + ImGui.Text("Document \"%s\"", ImGui.TextBufferToString(doc.Name)) + ImGui.PushStyleColor(ImGuiCol.Text, doc.Color) + ImGui.TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") + ImGui.PopStyleColor() + + ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.R), ImGuiInputFlags.Tooltip) + if ImGui.Button("Rename..") then + self.RenamingDoc = doc + self.RenamingStarted = true end - -- Display context menu for the Document - function app:DisplayDocContextMenu(doc) - if not ImGui.BeginPopupContextItem() then return end - if ImGui.MenuItem("Save " .. doc:Name(), "Ctrl+S", false, doc.Open) then doc:DoSave() end - if ImGui.MenuItem("Rename...", "Ctrl+R", false, doc.Open) then self.RenamingDoc = doc end - if ImGui.MenuItem("Close", "Ctrl+W", false, doc.Open) then self:QueueClose(doc) end - ImGui.EndPopup() + ImGui.SameLine() + + ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.M), ImGuiInputFlags.Tooltip) + if ImGui.Button("Modify") then + doc.Dirty = true end - -- [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. - -- If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, - -- as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for - -- the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has - -- disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively - -- give the impression of a flicker for one frame. - -- We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. - -- Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags.Reorderable flag. - function app:NotifyOfDocumentsClosedElsewhere() - for _, doc in ipairs(self.Documents) do - if not doc.Open and doc.OpenPrev then ImGui.SetTabItemClosed(doc:Name()) end - doc.OpenPrev = doc.Open + + ImGui.SameLine() + ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.S), ImGuiInputFlags.Tooltip) + if ImGui.Button("Save") then + doc:DoSave() + end + + ImGui.SameLine() + ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.W), ImGuiInputFlags.Tooltip) + if ImGui.Button("Close") then + self.CloseQueue:push_back(doc) + end + ImGui.ColorEdit3("color", doc.Color) -- Useful to test drag and drop and hold-dragged-to-open-tab behavior. + ImGui.PopID() +end + +-- Display context menu for the Document +function ExampleAppDocumentsMT:DisplayDocContextMenu(doc) + if not ImGui.BeginPopupContextItem() then + return + end + + local buf = string.format("Save %s", ImGui.TextBufferToString(doc.Name)) + if ImGui.MenuItem(buf, "Ctrl+S", false, doc.Open) then + doc:DoSave() + end + if ImGui.MenuItem("Rename...", "Ctrl+R", false, doc.Open) then + self.RenamingDoc = doc + end + if ImGui.MenuItem("Close", "Ctrl+W", false, doc.Open) then + self.CloseQueue:push_back(doc) + end + ImGui.EndPopup() +end + +-- [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. +-- If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, +-- as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for +-- the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has +-- disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively +-- give the impression of a flicker for one frame. +-- We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. +-- Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags.Reorderable flag. +function ExampleAppDocumentsMT:NotifyOfDocumentsClosedElsewhere() + for _, doc in self.Documents:iter() do + if not doc.Open and doc.OpenPrev then + ImGui.SetTabItemClosed(ImGui.TextBufferToString(doc.Name)) end + doc.OpenPrev = doc.Open end - return app end +S.ShowExampleAppDocuments = { + app = ExampleAppDocuments(), + opt_target = nil, -- set below to Target_Tab + opt_reorderable = true, + opt_fitting_flags = nil, -- set below to ImGuiTabBarFlags.FittingPolicyDefault_ +} function ShowExampleAppDocuments(p_open) - Docs = Docs or DocsInit() - local app = Docs + local s = S.ShowExampleAppDocuments + local app = s.app + -- Options - -- Target_Tab: Create documents as local tab into a local tab bar - -- Target_DockSpaceAndWindow: Create documents as regular windows, and create an embedded dockspace - local Target_Tab, Target_DockSpaceAndWindow = 1, 2 + local Target_None = 0 + local Target_Tab = 1 -- Create documents as local tab into a local tab bar + local Target_DockSpaceAndWindow = 2 -- Create documents as regular windows, and create an embedded dockspace + if s.opt_target == nil then s.opt_target = Target_Tab end + if s.opt_fitting_flags == nil then s.opt_fitting_flags = ImGuiTabBarFlags.FittingPolicyDefault_ end -- When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant") -- that we emit gets docked into the same spot as the parent window ("Example: Documents"). @@ -5806,46 +10175,64 @@ function ShowExampleAppDocuments(p_open) local window_contents_visible p_open, window_contents_visible = ImGui.Begin("Example: Documents", p_open, ImGuiWindowFlags.MenuBar) - if not window_contents_visible and app.opt_target ~= Target_DockSpaceAndWindow then + if not window_contents_visible and s.opt_target ~= Target_DockSpaceAndWindow then ImGui.End() return p_open end + IMGUI_DEMO_MARKER("Examples/Documents") -- Menu if ImGui.BeginMenuBar() then if ImGui.BeginMenu("File") then local open_count = 0 - for _, doc in ipairs(app.Documents) do if doc.Open then open_count = open_count + 1 end end - if ImGui.BeginMenu("Open", open_count < #app.Documents) then - for _, doc in ipairs(app.Documents) do - if not doc.Open and ImGui.MenuItem(doc:Name()) then doc:DoOpen() end + for _, doc in app.Documents:iter() do + open_count = open_count + (doc.Open and 1 or 0) + end + + if ImGui.BeginMenu("Open", open_count < app.Documents.Size) then + for _, doc in app.Documents:iter() do + if not doc.Open and ImGui.MenuItem(ImGui.TextBufferToString(doc.Name)) then + doc:DoOpen() + end end ImGui.EndMenu() end if ImGui.MenuItem("Close All Documents", nil, false, open_count > 0) then - for _, doc in ipairs(app.Documents) do app:QueueClose(doc) end + for _, doc in app.Documents:iter() do + app.CloseQueue:push_back(doc) + end + end + if ImGui.MenuItem("Exit") and p_open ~= nil then + p_open = false end - if ImGui.MenuItem("Exit") and p_open ~= nil then p_open = false end ImGui.EndMenu() end ImGui.EndMenuBar() end -- [Debug] List documents with one checkbox for each - for doc_n, doc in ipairs(app.Documents) do - if doc_n > 1 then ImGui.SameLine() end - ImGui.PushID("doc" .. doc.UID) + for doc_n = 0, app.Documents.Size - 1 do + local doc = app.Documents.Data[doc_n + 1] + if doc_n > 0 then + ImGui.SameLine() + end + ImGui.PushID(doc.UID) -- [Port] PushID(&doc): no pointer IDs, UID is unique local pressed - pressed, doc.Open = ImGui.Checkbox(doc:Name(), doc.Open) - if pressed and not doc.Open then doc:DoForceClose() end + pressed, doc.Open = ImGui.Checkbox(ImGui.TextBufferToString(doc.Name), doc.Open) + if pressed then + if not doc.Open then + doc:DoForceClose() + end + end ImGui.PopID() end ImGui.PushItemWidth(ImGui.GetFontSize() * 12) - app.opt_target = ImGui.Combo("Output", app.opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0") + s.opt_target = ImGui.Combo("Output", s.opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0") ImGui.PopItemWidth() local redock_all = false - if app.opt_target == Target_Tab then ImGui.SameLine(); _, app.opt_reorderable = ImGui.Checkbox("Reorderable Tabs", app.opt_reorderable) end - if app.opt_target == Target_DockSpaceAndWindow then ImGui.SameLine(); redock_all = ImGui.Button("Redock all") end + if s.opt_target == Target_Tab then ImGui.SameLine(); _, s.opt_reorderable = ImGui.Checkbox("Reorderable Tabs", s.opt_reorderable) end + if s.opt_target == Target_DockSpaceAndWindow then ImGui.SameLine(); redock_all = ImGui.Button("Redock all") end + ImGui.Separator() -- About the ImGuiWindowFlags.UnsavedDocument / ImGuiTabItemFlags.UnsavedDocument flags. @@ -5859,34 +10246,46 @@ function ShowExampleAppDocuments(p_open) -- The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole. -- Tabs - if app.opt_target == Target_Tab then - local tab_bar_flags = bit32.bor(app.opt_fitting_flags, app.opt_reorderable and ImGuiTabBarFlags.Reorderable or 0, ImGuiTabBarFlags.DrawSelectedOverline) + if s.opt_target == Target_Tab then + local tab_bar_flags = bit32.bor(s.opt_fitting_flags, s.opt_reorderable and ImGuiTabBarFlags.Reorderable or 0) + tab_bar_flags = bit32.bor(tab_bar_flags, ImGuiTabBarFlags.DrawSelectedOverline) if ImGui.BeginTabBar("##tabs", tab_bar_flags) then - if app.opt_reorderable then app:NotifyOfDocumentsClosedElsewhere() end + if s.opt_reorderable then + app:NotifyOfDocumentsClosedElsewhere() + end + + -- [DEBUG] Stress tests + --if ((ImGui.GetFrameCount() % 30) == 0) docs[1].Open ^= 1; -- [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. + --if (ImGui.GetIO().KeyCtrl) ImGui.SetTabItemSelected(docs[1].Name); -- [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. -- Submit Tabs - for _, doc in ipairs(app.Documents) do - if doc.Open then - -- As we allow to change document name, we append a never-changing document id so tabs are stable - local tab_flags = doc.Dirty and ImGuiTabItemFlags.UnsavedDocument or 0 - local visible - visible, doc.Open = ImGui.BeginTabItem(app:GetTabName(doc), doc.Open, tab_flags) - - -- Cancel attempt to close when unsaved add to save queue so we can display a popup. - if not doc.Open and doc.Dirty then - doc.Open = true - app:QueueClose(doc) - end - app:DisplayDocContextMenu(doc) - if visible then - app:DisplayDocContents(doc) - ImGui.EndTabItem() - end + for _, doc in app.Documents:iter() do repeat + if not doc.Open then + break -- continue end - end + + -- As we allow to change document name, we append a never-changing document id so tabs are stable + local doc_name_buf = app:GetTabName(doc) + local tab_flags = (doc.Dirty and ImGuiTabItemFlags.UnsavedDocument or 0) + local visible + visible, doc.Open = ImGui.BeginTabItem(doc_name_buf, doc.Open, tab_flags) + + -- Cancel attempt to close when unsaved add to save queue so we can display a popup. + if not doc.Open and doc.Dirty then + doc.Open = true + app.CloseQueue:push_back(doc) + end + + app:DisplayDocContextMenu(doc) + if visible then + app:DisplayDocContents(doc) + ImGui.EndTabItem() + end + until true end + ImGui.EndTabBar() end - elseif app.opt_target == Target_DockSpaceAndWindow then + elseif s.opt_target == Target_DockSpaceAndWindow then if bit32.band(ImGui.GetIO().ConfigFlags, ImGuiConfigFlags.DockingEnable) ~= 0 then app:NotifyOfDocumentsClosedElsewhere() @@ -5895,23 +10294,30 @@ function ShowExampleAppDocuments(p_open) ImGui.DockSpace(dockspace_id) -- Create Windows - for _, doc in ipairs(app.Documents) do - if doc.Open then - ImGui.SetNextWindowDockID(dockspace_id, redock_all and ImGuiCond.Always or ImGuiCond.FirstUseEver) - local window_flags = doc.Dirty and ImGuiWindowFlags.UnsavedDocument or 0 - local visible - doc.Open, visible = ImGui.Begin(doc:Name(), doc.Open, window_flags) - - -- Cancel attempt to close when unsaved add to save queue so we can display a popup. - if not doc.Open and doc.Dirty then - doc.Open = true - app:QueueClose(doc) - end - app:DisplayDocContextMenu(doc) - if visible then app:DisplayDocContents(doc) end - ImGui.End() + for doc_n = 0, app.Documents.Size - 1 do repeat + local doc = app.Documents.Data[doc_n + 1] + if not doc.Open then + break -- continue end - end + + ImGui.SetNextWindowDockID(dockspace_id, redock_all and ImGuiCond.Always or ImGuiCond.FirstUseEver) + local window_flags = (doc.Dirty and ImGuiWindowFlags.UnsavedDocument or 0) + local visible + doc.Open, visible = ImGui.Begin(ImGui.TextBufferToString(doc.Name), doc.Open, window_flags) + + -- Cancel attempt to close when unsaved add to save queue so we can display a popup. + if not doc.Open and doc.Dirty then + doc.Open = true + app.CloseQueue:push_back(doc) + end + + app:DisplayDocContextMenu(doc) + if visible then + app:DisplayDocContents(doc) + end + + ImGui.End() + until true end else ShowDockingDisabledMessage() end @@ -5925,14 +10331,18 @@ function ShowExampleAppDocuments(p_open) -- Display renaming UI if app.RenamingDoc ~= nil then - if app.RenamingStarted then ImGui.OpenPopup("Rename") end + if app.RenamingStarted then + ImGui.OpenPopup("Rename") + end if ImGui.BeginPopup("Rename") then ImGui.SetNextItemWidth(ImGui.GetFontSize() * 30) - if ImGui.InputText("###Name", app.RenamingDoc.NameBuf, 32, ImGuiInputTextFlags.EnterReturnsTrue) then + if ImGui.InputText("###Name", app.RenamingDoc.Name, 32, ImGuiInputTextFlags.EnterReturnsTrue) then ImGui.CloseCurrentPopup() app.RenamingDoc = nil end - if app.RenamingStarted then ImGui.SetKeyboardFocusHere(-1) end + if app.RenamingStarted then + ImGui.SetKeyboardFocusHere(-1) + end ImGui.EndPopup() else app.RenamingDoc = nil @@ -5941,2475 +10351,80 @@ function ShowExampleAppDocuments(p_open) end -- Display closing confirmation UI - if #app.CloseQueue > 0 then + if not app.CloseQueue:empty() then local close_queue_unsaved_documents = 0 - for _, doc in ipairs(app.CloseQueue) do if doc.Dirty then close_queue_unsaved_documents = close_queue_unsaved_documents + 1 end end + for n = 0, app.CloseQueue.Size - 1 do + if app.CloseQueue.Data[n + 1].Dirty then + close_queue_unsaved_documents = close_queue_unsaved_documents + 1 + end + end + if close_queue_unsaved_documents == 0 then -- Close documents when all are unsaved - for _, doc in ipairs(app.CloseQueue) do doc:DoForceClose() end - app.CloseQueue = {} + for n = 0, app.CloseQueue.Size - 1 do + app.CloseQueue.Data[n + 1]:DoForceClose() + end + app.CloseQueue:clear() else - if not ImGui.IsPopupOpen("Save?") then ImGui.OpenPopup("Save?") end + if not ImGui.IsPopupOpen("Save?") then + ImGui.OpenPopup("Save?") + end if ImGui.BeginPopupModal("Save?", nil, ImGuiWindowFlags.AlwaysAutoResize) then ImGui.Text("Save change to the following items?") local item_height = ImGui.GetTextLineHeightWithSpacing() if ImGui.BeginChild(ImGui.GetID("frame"), ImVec2(-FLT_MIN, 6.25 * item_height), ImGuiChildFlags.FrameStyle) then - for _, doc in ipairs(app.CloseQueue) do if doc.Dirty then ImGui.Text("%s", doc:Name()) end end + for _, doc in app.CloseQueue:iter() do + if doc.Dirty then + ImGui.Text("%s", ImGui.TextBufferToString(doc.Name)) + end + end end ImGui.EndChild() + local button_size = ImVec2(ImGui.GetFontSize() * 7.0, 0.0) if ImGui.Button("Yes", button_size) then - for _, doc in ipairs(app.CloseQueue) do - if doc.Dirty then doc:DoSave() end + for _, doc in app.CloseQueue:iter() do + if doc.Dirty then + doc:DoSave() + end doc:DoForceClose() end - app.CloseQueue = {} + app.CloseQueue:clear() ImGui.CloseCurrentPopup() end ImGui.SameLine() if ImGui.Button("No", button_size) then - for _, doc in ipairs(app.CloseQueue) do doc:DoForceClose() end - app.CloseQueue = {} + for _, doc in app.CloseQueue:iter() do + doc:DoForceClose() + end + app.CloseQueue:clear() ImGui.CloseCurrentPopup() end ImGui.SameLine() if ImGui.Button("Cancel", button_size) then - app.CloseQueue = {} + app.CloseQueue:clear() ImGui.CloseCurrentPopup() end ImGui.EndPopup() end end end + ImGui.End() return p_open end -end --[[ imgui_demo_apps.lua ]] - -do --[[ imgui_demo_widgets.lua ]] --- Demo: DemoWindowWidgets*() sections (port of imgui_demo.cpp). Globals picked up by DemoWindowWidgets() in imgui_demo.lua. -local _ -local function HSV(h, s, v, a) local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v) return ImVec4(r, g, b, a or 1.0) end -local Buf, BufStr = DemoBuf, DemoBufStr -local S = {} -- statics, one subtable per section - -local ExampleNames = { - "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper", - "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava", - "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber" } ------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsBasic() +-- [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser() ------------------------------------------------------------------------------- -S.basic = { clicked = 0, check = true, e = 0, counter = 0, str0 = Buf("Hello, world!", 128), str1 = Buf("", 128), - i0 = 123, f0 = 0.001, d0 = 999999.00000001, f1 = 1.e10, vec4a = { 0.10, 0.20, 0.30, 0.44 }, - di1 = 50, di2 = 42, di3 = 128, df1 = 1.0, df2 = 0.0067, si1 = 0, sf1 = 0.123, sf2 = 0.0, angle = 0.0, elem = 0, - col1 = { 1.0, 0.0, 0.2 }, col2 = { 0.4, 0.7, 0.0, 0.5 }, combo = 0, listbox = 1 } - -function DemoWindowWidgetsBasic() - if not ImGui.TreeNode("Basic") then return end - local s = S.basic - ImGui.SeparatorText("General") - if ImGui.Button("Button") then s.clicked = s.clicked + 1 end - if s.clicked % 2 == 1 then ImGui.SameLine(); ImGui.Text("Thanks for clicking me!") end - _, s.check = ImGui.Checkbox("checkbox", s.check) - _, s.e = ImGui.RadioButton("radio a", s.e, 0); ImGui.SameLine() - _, s.e = ImGui.RadioButton("radio b", s.e, 1); ImGui.SameLine() - _, s.e = ImGui.RadioButton("radio c", s.e, 2) - ImGui.AlignTextToFramePadding() - ImGui.TextLinkOpenURL("Hyperlink", "https://github.com/ocornut/imgui/wiki/Error-Handling") - - -- Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. - for i = 0, 6 do - if i > 0 then ImGui.SameLine() end - ImGui.PushID(i) - ImGui.PushStyleColor(ImGuiCol.Button, HSV(i / 7.0, 0.6, 0.6)) - ImGui.PushStyleColor(ImGuiCol.ButtonHovered, HSV(i / 7.0, 0.7, 0.7)) - ImGui.PushStyleColor(ImGuiCol.ButtonActive, HSV(i / 7.0, 0.8, 0.8)) - ImGui.Button("Click") - ImGui.PopStyleColor(3) - ImGui.PopID() - end - - -- Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements - -- (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) - -- See 'Demo->Layout->Text Baseline Alignment' for details. - ImGui.AlignTextToFramePadding() - ImGui.Text("Hold to repeat:") - ImGui.SameLine() - - -- Arrow buttons with Repeater - local spacing = ImGui.GetStyle().ItemInnerSpacing.x - ImGui.PushItemFlag(ImGuiItemFlags.ButtonRepeat, true) - if ImGui.ArrowButton("##left", ImGuiDir.Left) then s.counter = s.counter - 1 end - ImGui.SameLine(0.0, spacing) - if ImGui.ArrowButton("##right", ImGuiDir.Right) then s.counter = s.counter + 1 end - ImGui.PopItemFlag() - ImGui.SameLine() - ImGui.Text("%d", s.counter) - ImGui.Button("Tooltip") - ImGui.SetItemTooltip("I am a tooltip") - ImGui.LabelText("label", "Value") - - ImGui.SeparatorText("Inputs") - ImGui.InputText("input text", s.str0, 128) - ImGui.SameLine(); HelpMarker("USER:\nHold Shift or use mouse to select text.\nCtrl+Left/Right to word jump.\nCtrl+A or Double-Click to select all.\nCtrl+X,Ctrl+C,Ctrl+V for clipboard.\nCtrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.\nEscape to revert.") - ImGui.InputTextWithHint("input text (w/ hint)", "enter text here", s.str1, 128) - s.i0 = ImGui.InputInt("input int", s.i0) - s.f0 = ImGui.InputFloat("input float", s.f0, 0.01, 1.0, "%.3f") - s.d0 = ImGui.InputDouble("input double", s.d0, 0.01, 1.0, "%.8f") - s.f1 = ImGui.InputFloat("input scientific", s.f1, 0.0, 0.0, "%e") - ImGui.SameLine(); HelpMarker("You can input value using the scientific notation,\n e.g. \"1e+8\" becomes \"100000000\".") - ImGui.InputFloat3("input float3", s.vec4a) - - ImGui.SeparatorText("Drags") - s.di1 = ImGui.DragInt("drag int", s.di1, 1) - ImGui.SameLine(); HelpMarker("Click and drag to edit value.\nHold Shift/Alt for faster/slower edit.\nDouble-Click or Ctrl+Click to input value.") - s.di2 = ImGui.DragInt("drag int 0..100", s.di2, 1, 0, 100, "%d%%", ImGuiSliderFlags.AlwaysClamp) - s.di3 = ImGui.DragInt("drag int wrap 100..200", s.di3, 1, 100, 200, "%d", ImGuiSliderFlags.WrapAround) - s.df1 = ImGui.DragFloat("drag float", s.df1, 0.005) - s.df2 = ImGui.DragFloat("drag small float", s.df2, 0.0001, 0.0, 0.0, "%.06f ns") - -- ImGui.DragFloat("drag wrap -1..1", f3, 0.005, -1.0, 1.0, nil, ImGuiSliderFlags.WrapAround) - - ImGui.SeparatorText("Sliders") - s.si1 = ImGui.SliderInt("slider int", s.si1, -1, 3) - ImGui.SameLine(); HelpMarker("Ctrl+Click to input value.") - s.sf1 = ImGui.SliderFloat("slider float", s.sf1, 0.0, 1.0, "ratio = %.3f") - s.sf2 = ImGui.SliderFloat("slider float (log)", s.sf2, -10.0, 10.0, "%.4f", ImGuiSliderFlags.Logarithmic) - s.angle = ImGui.SliderAngle("slider angle", s.angle) - - -- Using the format string to display a name instead of an integer. - -- Here we completely omit '%d' from the format string, so it'll only display a name. - -- This technique can also be used with DragInt(). - local elems_names = { "Fire", "Earth", "Air", "Water" } - local elem_name = elems_names[s.elem + 1] or "Unknown" - s.elem = ImGui.SliderInt("slider enum", s.elem, 0, 3, elem_name) -- Use ImGuiSliderFlags.NoInput flag to disable Ctrl+Click here. - ImGui.SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.") - - ImGui.SeparatorText("Selectors/Pickers") - ImGui.ColorEdit3("color 1", s.col1) - ImGui.SameLine(); HelpMarker("Click on the color square to open a color picker.\nClick and hold to use drag and drop.\nRight-Click on the color square to show options.\nCtrl+Click on individual component to input value.\n") - ImGui.ColorEdit4("color 2", s.col2) - - -- Using the _simplified_ one-liner Combo() api here - -- See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. - s.combo = ImGui.Combo("combo", s.combo, { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }) - ImGui.SameLine(); HelpMarker("Using the simplified one-liner Combo API here.") - - -- Using the _simplified_ one-liner ListBox() api here - -- See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. - s.listbox = ImGui.ListBox("listbox", s.listbox, { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }, 9, 4) - ImGui.SameLine(); HelpMarker("Using the simplified one-liner ListBox API here.") - ImGui.TreePop() -end - -S.chdr = { closable_group = true } - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsBullets() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsBullets() - if not ImGui.TreeNode("Bullets") then return end - ImGui.BulletText("Bullet point 1") - ImGui.BulletText("Bullet point 2\nOn multiple lines") - if ImGui.TreeNode("Tree node") then ImGui.BulletText("Another bullet point"); ImGui.TreePop() end - ImGui.Bullet(); ImGui.Text("Bullet point 3 (two calls)") - ImGui.Bullet(); ImGui.SmallButton("Button") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsCollapsingHeaders() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsCollapsingHeaders() - if not ImGui.TreeNode("Collapsing Headers") then return end - local s = S.chdr - _, s.closable_group = ImGui.Checkbox("Show 2nd header", s.closable_group) - if ImGui.CollapsingHeader("Header", ImGuiTreeNodeFlags.None) then - ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) - for i = 0, 4 do ImGui.Text("Some content %d", i) end - end - local open - open, s.closable_group = ImGui.CollapsingHeader("Header with a close button", s.closable_group) - if open then - ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered() and 1 or 0) - for i = 0, 4 do ImGui.Text("More content %d", i) end - end - -- if ImGui.CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags.Bullet) then - -- ImGui.Text("IsItemHovered: %d", ImGui.IsItemHovered()) - -- end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsColorAndPickers() -------------------------------------------------------------------------------- - -IMGUI_PAYLOAD_TYPE_COLOR_3F = IMGUI_PAYLOAD_TYPE_COLOR_3F or "_COL3F" -IMGUI_PAYLOAD_TYPE_COLOR_4F = IMGUI_PAYLOAD_TYPE_COLOR_4F or "_COL4F" - -S.color = { color = ImVec4(114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 200.0 / 255.0), base_flags = 0, palette = nil, - backup = ImVec4(), no_border = false, ref_color = false, ref_color_v = ImVec4(1.0, 0.0, 1.0, 0.5), picker_mode = 0, - display_mode = 0, picker_flags = ImGuiColorEditFlags.AlphaBar, hsv = ImVec4(0.23, 1.0, 1.0, 1.0) } - -function DemoWindowWidgetsColorAndPickers() - if not ImGui.TreeNode("Color/Picker Widgets") then return end - local s = S.color - local CE = ImGuiColorEditFlags - local color = s.color - - ImGui.SeparatorText("Options") - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.base_flags, CE.NoAlpha) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", s.base_flags, CE.AlphaOpaque) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", s.base_flags, CE.AlphaNoBg) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", s.base_flags, CE.AlphaPreviewHalf) - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoOptions", s.base_flags, CE.NoOptions); ImGui.SameLine(); HelpMarker("Right-click on the individual color widget to show options.") - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", s.base_flags, CE.NoDragDrop) - if CE.NoColorMarkers then _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoColorMarkers", s.base_flags, CE.NoColorMarkers) end - _, s.base_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_HDR", s.base_flags, CE.HDR); ImGui.SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.") - local base_flags = s.base_flags - - ImGui.SeparatorText("Inline color editor") - ImGui.Text("Color widget:") - ImGui.SameLine(); HelpMarker("Click on the color square to open a color picker.\nCtrl+Click on individual component to input value.\n") - ImGui.ColorEdit3("MyColor##1", color, base_flags) - ImGui.Text("Color widget HSV with Alpha:") - ImGui.ColorEdit4("MyColor##2", color, bit32.bor(CE.DisplayHSV, base_flags)) - ImGui.Text("Color widget with Float Display:") - ImGui.ColorEdit4("MyColor##2f", color, bit32.bor(CE.Float, base_flags)) - ImGui.Text("Color button with Picker:") - ImGui.SameLine(); HelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup.") - ImGui.ColorEdit4("MyColor##3", color, bit32.bor(CE.NoInputs, CE.NoLabel, base_flags)) - - ImGui.Text("Color button with Custom Picker Popup:") - - -- Generate a default palette. The palette will persist and can be edited. - if s.palette == nil then - s.palette = {} - for n = 0, 31 do s.palette[n] = HSV(n / 31.0, 0.8, 0.8, 1.0) end -- Alpha = 1.0 - end - local open_popup = ImGui.ColorButton("MyColor##3b", color, base_flags) - ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.x) - open_popup = ImGui.Button("Palette") or open_popup - if open_popup then - ImGui.OpenPopup("mypicker") - ImVec4_Copy(s.backup, color) - end - if ImGui.BeginPopup("mypicker") then - ImGui.Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!") - ImGui.Separator() - ImGui.ColorPicker4("##picker", color, bit32.bor(base_flags, CE.NoSidePreview, CE.NoSmallPreview)) - ImGui.SameLine() - ImGui.BeginGroup() -- Lock X position - ImGui.Text("Current") - ImGui.ColorButton("##current", color, bit32.bor(CE.NoPicker, CE.AlphaPreviewHalf), ImVec2(60, 40)) - ImGui.Text("Previous") - if ImGui.ColorButton("##previous", s.backup, bit32.bor(CE.NoPicker, CE.AlphaPreviewHalf), ImVec2(60, 40)) then - ImVec4_Copy(color, s.backup) - end - ImGui.Separator() - ImGui.Text("Palette") - for n = 0, 31 do - ImGui.PushID(n) - if n % 8 ~= 0 then ImGui.SameLine(0.0, ImGui.GetStyle().ItemSpacing.y) end - local pal = s.palette[n] - if ImGui.ColorButton("##palette", pal, bit32.bor(CE.NoAlpha, CE.NoPicker, CE.NoTooltip), ImVec2(20, 20)) then - color.x = pal.x; color.y = pal.y; color.z = pal.z -- Preserve alpha! - end - - -- Allow user to drop colors into each palette entry. Note that ColorButton() is already a - -- drag source by default, unless specifying the ImGuiColorEditFlags.NoDragDrop flag. - if ImGui.BeginDragDropTarget() then - local payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F) - if payload and payload.Data then pal.x, pal.y, pal.z = payload.Data[1], payload.Data[2], payload.Data[3] end - payload = ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F) - if payload and payload.Data then pal.x, pal.y, pal.z, pal.w = payload.Data[1], payload.Data[2], payload.Data[3], payload.Data[4] end - ImGui.EndDragDropTarget() - end - ImGui.PopID() - end - ImGui.EndGroup() - ImGui.EndPopup() - end - - ImGui.Text("Color button only:") - _, s.no_border = ImGui.Checkbox("ImGuiColorEditFlags_NoBorder", s.no_border) - ImGui.ColorButton("MyColor##3c", color, bit32.bor(base_flags, s.no_border and CE.NoBorder or 0), ImVec2(80, 80)) - - ImGui.SeparatorText("Color picker") - ImGui.PushID("Color picker") - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoAlpha", s.picker_flags, CE.NoAlpha) - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_AlphaBar", s.picker_flags, CE.AlphaBar) - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", s.picker_flags, CE.NoSidePreview) - if bit32.band(s.picker_flags, CE.NoSidePreview) ~= 0 then - ImGui.SameLine() - _, s.ref_color = ImGui.Checkbox("With Ref Color", s.ref_color) - if s.ref_color then - ImGui.SameLine() - ImGui.ColorEdit4("##RefColor", s.ref_color_v, bit32.bor(CE.NoInputs, base_flags)) - end - end - _, s.picker_flags = ImGui.CheckboxFlags("ImGuiColorEditFlags_PickerNoRotate", s.picker_flags, CE.PickerNoRotate) - s.picker_mode = ImGui.Combo("Picker Mode", s.picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0") - ImGui.SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode.") - s.display_mode = ImGui.Combo("Display Mode", s.display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0") - ImGui.SameLine(); HelpMarker("ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex if you don't specify a display mode.\n\nYou can change the defaults using io.ConfigColorEditFlags.") - local flags = bit32.bor(base_flags, s.picker_flags) - if s.picker_mode == 1 then flags = bit32.bor(flags, CE.PickerHueBar) end - if s.picker_mode == 2 then flags = bit32.bor(flags, CE.PickerHueWheel) end - if s.display_mode == 1 then flags = bit32.bor(flags, CE.NoInputs) end -- Disable all RGB/HSV/Hex displays - if s.display_mode == 2 then flags = bit32.bor(flags, CE.DisplayRGB) end -- Override display mode - if s.display_mode == 3 then flags = bit32.bor(flags, CE.DisplayHSV) end - if s.display_mode == 4 then flags = bit32.bor(flags, CE.DisplayHex) end - ImGui.ColorPicker4("MyColor##4", color, flags, s.ref_color and s.ref_color_v or nil) - - ImGui.Text("Set defaults in code:") - ImGui.SameLine(); HelpMarker("io.ConfigColorEditFlags is designed to allow you to set boot-time default.") - if ImGui.Button("Overwrite default: Uint8 + HSV + Hue Bar") then - ImGui.GetIO().ConfigColorEditFlags = bit32.bor(CE.Uint8, CE.DisplayHSV, CE.PickerHueBar, CE.InputRGB) -- [port] + InputRGB: upstream omits it and then trips its own InputMask_ assert - end - if ImGui.Button("Overwrite default: Float + HDR + Hue Wheel") then - ImGui.GetIO().ConfigColorEditFlags = bit32.bor(CE.Float, CE.HDR, CE.PickerHueWheel, CE.DisplayRGB, CE.InputRGB) - end - - -- Always display a small version of both types of pickers - -- (that's in order to make it more visible in the demo to people who are skimming quickly through it) - ImGui.Text("Both types:") - local w = (ImGui.GetContentRegionAvail().x - ImGui.GetStyle().ItemSpacing.y) * 0.40 - ImGui.SetNextItemWidth(w) - ImGui.ColorPicker3("##MyColor##5", color, bit32.bor(CE.PickerHueBar, CE.NoSidePreview, CE.NoInputs, CE.NoAlpha)) - ImGui.SameLine() - ImGui.SetNextItemWidth(w) - ImGui.ColorPicker3("##MyColor##6", color, bit32.bor(CE.PickerHueWheel, CE.NoSidePreview, CE.NoInputs, CE.NoAlpha)) - ImGui.PopID() - - -- HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) - -- (s.hsv is stored as HSV!) - ImGui.Spacing() - ImGui.Text("HSV encoded colors") - ImGui.SameLine(); HelpMarker("By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV.") - ImGui.Text("Color widget with InputHSV:") - ImGui.ColorEdit4("HSV shown as RGB##1", s.hsv, bit32.bor(CE.DisplayRGB, CE.InputHSV, CE.Float)) - ImGui.ColorEdit4("HSV shown as HSV##1", s.hsv, bit32.bor(CE.DisplayHSV, CE.InputHSV, CE.Float)) - ImGui.DragFloat4("Raw HSV values", s.hsv, 0.01, 0.0, 1.0) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsComboBoxes() -------------------------------------------------------------------------------- - -S.combo = { flags = 0, sel = 0, filter = nil, c2 = 0, c3 = -1, c4 = 0 } -- sel: Here we store our selection data as an index. -function DemoWindowWidgetsComboBoxes() - if not ImGui.TreeNode("Combo") then return end - local s = S.combo - local CF = ImGuiComboFlags - local p - -- Combo Boxes are also called "Dropdown" in other systems - -- Expose flags as checkbox for the demo - _, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", s.flags, CF.PopupAlignLeft) - ImGui.SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo") - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoArrowButton", s.flags, CF.NoArrowButton) - if p then s.flags = bit32.band(s.flags, bit32.bnot(CF.NoPreview)) end -- Clear incompatible flags - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_NoPreview", s.flags, CF.NoPreview) - if p then s.flags = bit32.band(s.flags, bit32.bnot(bit32.bor(CF.NoArrowButton, CF.WidthFitPreview))) end -- Clear incompatible flags - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_WidthFitPreview", s.flags, CF.WidthFitPreview) - if p then s.flags = bit32.band(s.flags, bit32.bnot(CF.NoPreview)) end - - -- Override default popup height - for _, h in ipairs({ "HeightSmall", "HeightRegular", "HeightLargest" }) do - p, s.flags = ImGui.CheckboxFlags("ImGuiComboFlags_" .. h, s.flags, CF[h]) - if p then s.flags = bit32.band(s.flags, bit32.bnot(bit32.band(CF.HeightMask_, bit32.bnot(CF[h])))) end - end - - -- Using the generic BeginCombo() API, you have full control over how to display the combo contents. - -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively - -- stored in the object itself, etc.) - local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } - - -- Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) - local combo_preview_value = items[s.sel + 1] - if ImGui.BeginCombo("combo 1", combo_preview_value, s.flags) then - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - if ImGui.Selectable(items[n + 1], is_selected) then s.sel = n end - - -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndCombo() - end - - -- Show case embedding a filter using a simple trick: displaying the filter inside combo contents. - -- See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives. - if ImGui.BeginCombo("combo 2 (w/ filter)", combo_preview_value, s.flags) then - s.filter = s.filter or ImGuiTextFilter() - if ImGui.IsWindowAppearing() then - ImGui.SetKeyboardFocusHere() - s.filter:Clear() - end - ImGui.SetNextItemShortcut(bit32.bor(ImGuiMod_Ctrl, ImGuiKey.F)) - ImGui.SetNextItemWidth(-FLT_MIN) - s.filter:DrawWithHint("##Filter", "Filter (incl -excl)") - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - if s.filter:PassFilter(items[n + 1]) then - if ImGui.Selectable(items[n + 1], is_selected) then s.sel = n end - end - end - ImGui.EndCombo() - end - - ImGui.Spacing() - ImGui.SeparatorText("One-liner variants") - HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section.") - - -- Simplified one-liner Combo() API, using values packed in a single constant string - -- This is a convenience for when the selection set is small and known at compile-time. - s.c2 = ImGui.Combo("combo 3 (one-liner)", s.c2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0") - - -- Simplified one-liner Combo() using an array of strings - -- This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. - s.c3 = ImGui.Combo("combo 4 (array)", s.c3, items, #items) -- If the selection isn't within 0..count, Combo won't display a preview - - -- Simplified one-liner Combo() using an accessor function - s.c4 = ImGui.Combo("combo 5 (function)", s.c4, function(data, n) return data[n + 1] end, items, #items) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDataTypes() -------------------------------------------------------------------------------- - -S.dt = { s8 = 127, u8 = 255, s16 = 32767, u16 = 65535, s32 = -1, u32 = 0xFFFFFFFF, s64 = -1, u64 = 0, f32 = 0.123, f64 = 90000.01234567890123456789, - drag_clamp = false, inputs_step = true, flags = 0 } -function DemoWindowWidgetsDataTypes() - if not ImGui.TreeNode("Data Types") then return end - local s = S.dt - local DT = ImGuiDataType - -- DragScalar/InputScalar/SliderScalar functions allow various data types - -- - signed/unsigned - -- - 8/16/32/64-bits - -- - integer/float/double - -- To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum - -- to pass the type. - -- In practice, if you frequently use a given type that is not covered by the normal API entry points, - -- you can wrap it yourself inside a 1 line function which can take typed argument as value, - -- and then pass them to the generic function. For example: - -- local function MySliderU32(label, value, min, max, format) - -- return ImGui.SliderScalar(label, ImGuiDataType.U32, value, min or 0, max or 0, format or "%u") - -- end - - -- ponytail: Luau numbers are doubles, so S64/U64 are shown with S32/Double here (no 64-bit integer type) - -- Setup limits - -- Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. - local s32_min, s32_max = math.floor(-2147483648 / 2), math.floor(2147483647 / 2) - local u32_max = math.floor(4294967295 / 2) - local drag_speed = 0.2 - ImGui.SeparatorText("Drags") - _, s.drag_clamp = ImGui.Checkbox("Clamp integers to 0..50", s.drag_clamp) - ImGui.SameLine(); HelpMarker("As with every widget in dear imgui, we never modify values unless there is a user interaction.\nYou can override the clamping limits by using Ctrl+Click to input a value.") - local lo, hi = s.drag_clamp and 0 or nil, s.drag_clamp and 50 or nil - s.s8 = ImGui.DragScalar("drag s8", DT.S8, s.s8, drag_speed, lo, hi) - s.u8 = ImGui.DragScalar("drag u8", DT.U8, s.u8, drag_speed, lo, hi, "%u ms") - s.s16 = ImGui.DragScalar("drag s16", DT.S16, s.s16, drag_speed, lo, hi) - s.u16 = ImGui.DragScalar("drag u16", DT.U16, s.u16, drag_speed, lo, hi, "%u ms") - s.s32 = ImGui.DragScalar("drag s32", DT.S32, s.s32, drag_speed, lo, hi) - s.s32 = ImGui.DragScalar("drag s32 hex", DT.S32, s.s32, drag_speed, lo, hi, "0x%08X") - s.u32 = ImGui.DragScalar("drag u32", DT.U32, s.u32, drag_speed, lo, hi, "%u ms") - s.f32 = ImGui.DragScalar("drag float", DT.Float, s.f32, 0.005, 0.0, 1.0, "%f") - s.f32 = ImGui.DragScalar("drag float log", DT.Float, s.f32, 0.005, 0.0, 1.0, "%f", ImGuiSliderFlags.Logarithmic) - s.f64 = ImGui.DragScalar("drag double", DT.Double, s.f64, 0.0005, 0.0, nil, "%.10f grams") - s.f64 = ImGui.DragScalar("drag double log",DT.Double, s.f64, 0.0005, 0.0, 1.0, "0 < %.10f < 1", ImGuiSliderFlags.Logarithmic) - - ImGui.SeparatorText("Sliders") - s.s8 = ImGui.SliderScalar("slider s8 full", DT.S8, s.s8, -128, 127, "%d") - s.u8 = ImGui.SliderScalar("slider u8 full", DT.U8, s.u8, 0, 255, "%u") - s.s16 = ImGui.SliderScalar("slider s16 full", DT.S16, s.s16, -32768, 32767, "%d") - s.u16 = ImGui.SliderScalar("slider u16 full", DT.U16, s.u16, 0, 65535, "%u") - s.s32 = ImGui.SliderScalar("slider s32 low", DT.S32, s.s32, 0, 50, "%d") - s.s32 = ImGui.SliderScalar("slider s32 high", DT.S32, s.s32, s32_max - 100, s32_max, "%d") - s.s32 = ImGui.SliderScalar("slider s32 full", DT.S32, s.s32, s32_min, s32_max, "%d") - s.s32 = ImGui.SliderScalar("slider s32 hex", DT.S32, s.s32, 0, 50, "0x%04X") - s.u32 = ImGui.SliderScalar("slider u32 low", DT.U32, s.u32, 0, 50, "%u") - s.u32 = ImGui.SliderScalar("slider u32 high", DT.U32, s.u32, u32_max - 100, u32_max, "%u") - s.u32 = ImGui.SliderScalar("slider u32 full", DT.U32, s.u32, 0, u32_max, "%u") - s.f32 = ImGui.SliderScalar("slider float low", DT.Float, s.f32, 0.0, 1.0) - s.f32 = ImGui.SliderScalar("slider float low log", DT.Float, s.f32, 0.0, 1.0, "%.10f", ImGuiSliderFlags.Logarithmic) - s.f32 = ImGui.SliderScalar("slider float high", DT.Float, s.f32, -10000000000.0, 10000000000.0, "%e") - s.f64 = ImGui.SliderScalar("slider double low", DT.Double, s.f64, 0.0, 1.0, "%.10f grams") - s.f64 = ImGui.SliderScalar("slider double low log", DT.Double, s.f64, 0.0, 1.0, "%.10f", ImGuiSliderFlags.Logarithmic) - s.f64 = ImGui.SliderScalar("slider double high", DT.Double, s.f64, -1000000000000000.0, 1000000000000000.0, "%e grams") - - ImGui.SeparatorText("Sliders (reverse)") - s.s8 = ImGui.SliderScalar("slider s8 reverse", DT.S8, s.s8, 127, -128, "%d") - s.u8 = ImGui.SliderScalar("slider u8 reverse", DT.U8, s.u8, 255, 0, "%u") - s.s32 = ImGui.SliderScalar("slider s32 reverse", DT.S32, s.s32, 50, 0, "%d") - s.u32 = ImGui.SliderScalar("slider u32 reverse", DT.U32, s.u32, 50, 0, "%u") - - ImGui.SeparatorText("Inputs") - _, s.inputs_step = ImGui.Checkbox("Show step buttons", s.inputs_step) - _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ReadOnly", s.flags, ImGuiInputTextFlags.ReadOnly) - if ImGuiInputTextFlags.ParseEmptyRefVal then _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", s.flags, ImGuiInputTextFlags.ParseEmptyRefVal) end - if ImGuiInputTextFlags.DisplayEmptyRefVal then _, s.flags = ImGui.CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", s.flags, ImGuiInputTextFlags.DisplayEmptyRefVal) end - local one = s.inputs_step and 1 or nil - s.s8 = ImGui.InputScalar("input s8", DT.S8, s.s8, one, nil, "%d", s.flags) - s.u8 = ImGui.InputScalar("input u8", DT.U8, s.u8, one, nil, "%u", s.flags) - s.s16 = ImGui.InputScalar("input s16", DT.S16, s.s16, one, nil, "%d", s.flags) - s.u16 = ImGui.InputScalar("input u16", DT.U16, s.u16, one, nil, "%u", s.flags) - s.s32 = ImGui.InputScalar("input s32", DT.S32, s.s32, one, nil, "%d", s.flags) - s.s32 = ImGui.InputScalar("input s32 hex", DT.S32, s.s32, one, nil, "%04X", s.flags) - s.u32 = ImGui.InputScalar("input u32", DT.U32, s.u32, one, nil, "%u", s.flags) - s.u32 = ImGui.InputScalar("input u32 hex", DT.U32, s.u32, one, nil, "%08X", s.flags) - s.f32 = ImGui.InputScalar("input float", DT.Float, s.f32, s.inputs_step and 1.0 or nil, nil, nil, s.flags) - s.f64 = ImGui.InputScalar("input double", DT.Double, s.f64, s.inputs_step and 1.0 or nil, nil, nil, s.flags) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDisableBlocks() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsDisableBlocks(demo_data) - if not ImGui.TreeNode("Disable Blocks") then return end - _, demo_data.DisableSections = ImGui.Checkbox("Disable entire section above", demo_data.DisableSections) - ImGui.SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections.") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDragAndDrop() -------------------------------------------------------------------------------- - -S.dnd = { col1 = { 1.0, 0.0, 0.2 }, col2 = { 0.4, 0.7, 0.0, 0.5 }, mode = 0, - names = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" }, - item_names = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }, col4 = ImVec4(1.0, 0.0, 0.2, 1.0) } -function DemoWindowWidgetsDragAndDrop() - if not ImGui.TreeNode("Drag and Drop") then return end - local s = S.dnd - if ImGui.TreeNode("Drag and drop in standard widgets") then - -- ColorEdit widgets automatically act as drag source and drag target. - -- They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F - -- to allow your own widgets to use colors in their drag and drop interaction. - -- Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. - HelpMarker("You can drag from the color squares.") - ImGui.ColorEdit3("color 1", s.col1) - ImGui.ColorEdit4("color 2", s.col2) - ImGui.TreePop() - end - - if ImGui.TreeNode("Drag and drop to copy/swap items") then - local Mode_Copy, Mode_Move, Mode_Swap = 0, 1, 2 - if ImGui.RadioButtonEx("Copy", s.mode == Mode_Copy) then s.mode = Mode_Copy end ImGui.SameLine() - if ImGui.RadioButtonEx("Move", s.mode == Mode_Move) then s.mode = Mode_Move end ImGui.SameLine() - if ImGui.RadioButtonEx("Swap", s.mode == Mode_Swap) then s.mode = Mode_Swap end - local names = s.names - for n = 0, #names - 1 do - ImGui.PushID(n) - if n % 3 ~= 0 then ImGui.SameLine() end - ImGui.Button(names[n + 1], ImVec2(60, 60)) - - -- Our buttons are both drag sources and drag targets here! - if ImGui.BeginDragDropSource(ImGuiDragDropFlags.None) then - -- Set payload to carry the index of our item (could be anything) - ImGui.SetDragDropPayload("DND_DEMO_CELL", n, 4) - - -- Display preview (could be anything, e.g. when dragging an image we could decide to display - -- the filename and a small preview of the image, etc.) - if s.mode == Mode_Copy then ImGui.Text("Copy %s", names[n + 1]) end - if s.mode == Mode_Move then ImGui.Text("Move %s", names[n + 1]) end - if s.mode == Mode_Swap then ImGui.Text("Swap %s", names[n + 1]) end - ImGui.EndDragDropSource() - end - if ImGui.BeginDragDropTarget() then - local payload = ImGui.AcceptDragDropPayload("DND_DEMO_CELL") - if payload then - local payload_n = payload.Data - if s.mode == Mode_Copy then names[n + 1] = names[payload_n + 1] end - if s.mode == Mode_Move then names[n + 1] = names[payload_n + 1]; names[payload_n + 1] = "" end - if s.mode == Mode_Swap then names[n + 1], names[payload_n + 1] = names[payload_n + 1], names[n + 1] end - end - ImGui.EndDragDropTarget() - end - ImGui.PopID() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Drag to reorder items (simple)") then - -- FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. - -- This code was always slightly faulty but in a way which was not easily noticeable. - -- Until we fix this, enable ImGuiItemFlags.AllowDuplicateId to disable detecting the issue. - ImGui.PushItemFlag(ImGuiItemFlags.AllowDuplicateId, true) - - -- Simple reordering - HelpMarker("We don't use the drag and drop api at all here! Instead we query when the item is held but not hovered, and order items accordingly.") - local item_names = s.item_names - for n = 1, #item_names do - local item = item_names[n] - ImGui.Selectable(item) - if ImGui.IsItemActive() and not ImGui.IsItemHovered() then - local n_next = n + ((ImGui.GetMouseDragDelta(0).y < 0.0) and -1 or 1) - if n_next >= 1 and n_next <= #item_names then - item_names[n] = item_names[n_next] - item_names[n_next] = item - ImGui.ResetMouseDragDelta() - end - end - end - ImGui.PopItemFlag() - ImGui.TreePop() - end - - if ImGui.TreeNode("Tooltip at target location") then - for n = 0, 1 do - -- Drop targets - ImGui.Button((n == 1) and "drop here##1" or "drop here##0") - if ImGui.BeginDragDropTarget() then - local drop_target_flags = bit32.bor(ImGuiDragDropFlags.AcceptBeforeDelivery, ImGuiDragDropFlags.AcceptNoPreviewTooltip) - if ImGui.AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags) then - ImGui.SetMouseCursor(ImGuiMouseCursor.NotAllowed) - ImGui.SetTooltip("Cannot drop here!") - end - ImGui.EndDragDropTarget() - end - - -- Drop source - if n == 0 then ImGui.ColorButton("drag me", s.col4) end - end - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsDragsAndSliders() -------------------------------------------------------------------------------- - -S.ds = { flags = 0, drag_f = 0.5, drag_f4 = { 0, 0, 0, 0 }, drag_i = 50, slider_f = 0.5, slider_f4 = { 0, 0, 0, 0 }, slider_i = 50 } -function DemoWindowWidgetsDragsAndSliders() - if not ImGui.TreeNode("Drag/Slider Flags") then return end - -- Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! - local s = S.ds - local SF = ImGuiSliderFlags - local function F(name, help) - if SF[name] == nil then return end - _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_" .. name, s.flags, SF[name]) - if help then ImGui.SameLine(); HelpMarker(help) end - end - F("AlwaysClamp") - F("ClampOnInput", "Clamp value to min/max bounds when input manually with Ctrl+Click. By default Ctrl+Click allows going out of bounds.") - F("ClampZeroRange", "Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.") - F("Logarithmic", "Enable logarithmic editing (more precision for small values).") - F("NoRoundToFormat", "Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).") - F("NoInput", "Disable Ctrl+Click or Enter key allowing to input text directly into the widget.") - F("NoSpeedTweaks", "Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.") - F("WrapAround", "Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)") - F("ColorMarkers") - local flags = s.flags - - -- Drags - ImGui.Text("Underlying float value: %f", s.drag_f) - s.drag_f = ImGui.DragFloat("DragFloat (0 -> 1)", s.drag_f, 0.005, 0.0, 1.0, "%.3f", flags) - s.drag_f = ImGui.DragFloat("DragFloat (0 -> +inf)", s.drag_f, 0.005, 0.0, FLT_MAX, "%.3f", flags) - s.drag_f = ImGui.DragFloat("DragFloat (-inf -> 1)", s.drag_f, 0.005, -FLT_MAX, 1.0, "%.3f", flags) - s.drag_f = ImGui.DragFloat("DragFloat (-inf -> +inf)", s.drag_f, 0.005, -FLT_MAX, FLT_MAX, "%.3f", flags) - -- ImGui.DragFloat("DragFloat (0 -> 0)", drag_f, 0.005, 0.0, 0.0, "%.3f", flags) -- To test ClampZeroRange - -- ImGui.DragFloat("DragFloat (100 -> 100)", drag_f, 0.005, 100.0, 100.0, "%.3f", flags) - s.drag_i = ImGui.DragInt("DragInt (0 -> 100)", s.drag_i, 0.5, 0, 100, "%d", flags) - ImGui.DragFloat4("DragFloat4 (0 -> 1)", s.drag_f4, 0.005, 0.0, 1.0, "%.3f", flags) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags.ColorMarkers. - - -- Sliders - local flags_for_sliders = bit32.band(flags, bit32.bnot(SF.WrapAround)) - ImGui.Text("Underlying float value: %f", s.slider_f) - s.slider_f = ImGui.SliderFloat("SliderFloat (0 -> 1)", s.slider_f, 0.0, 1.0, "%.3f", flags_for_sliders) - s.slider_i = ImGui.SliderInt("SliderInt (0 -> 100)", s.slider_i, 0, 100, "%d", flags_for_sliders) - ImGui.SliderFloat4("SliderFloat4 (0 -> 1)", s.slider_f4, 0.0, 1.0, "%.3f", flags_for_sliders) -- Multi-component item, mostly here to document the effect of ImGuiSliderFlags.ColorMarkers. - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsFonts() -------------------------------------------------------------------------------- - -function DemoWindowWidgetsFonts() - if not ImGui.TreeNode("Fonts") then return end - if ImGui.ShowFontAtlas then ImGui.ShowFontAtlas(ImGui.GetIO().Fonts) else DemoNotPorted("ShowFontAtlas") end - -- FIXME-NEWATLAS: Provide a demo to add/create a procedural font? - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsImages() -------------------------------------------------------------------------------- - -S.img = { viewer = nil, pressed_count = 0 } -function DemoWindowWidgetsImages() - if not ImGui.TreeNode("Images") then return end - local s = S.img - local io = ImGui.GetIO() - ImGui.TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!") - - -- Below we are displaying the font texture because it is the only texture we have access to inside the demo! - -- Read description about ImTextureID/ImTextureRef and FAQ for details about texture identifiers. - -- - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, - -- it will help you debug issues if you are confused about it. - -- - Consider using the lower-level ImDrawList:AddImage() API, via ImGui.GetWindowDrawList():AddImage(). - -- - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md - -- - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - - -- Grab the current texture identifier used by the font atlas. - local atlas = io.Fonts - local my_tex_id = atlas.TexRef - local my_tex_w = atlas.TexData and atlas.TexData.Width or 0 -- Regular user code should never have to care about TexData fields, but since we want to display the entire texture here, we pull Width/Height from it. - local my_tex_h = atlas.TexData and atlas.TexData.Height or 0 - ImGui.Text("%.0fx%.0f", my_tex_w, my_tex_h) - - -- Basic drawing - ImGui.SeparatorText("Image()/ImageWithBg() function") - ImGui.PushStyleVar(ImGuiStyleVar.ImageBorderSize, math.max(1.0, ImGui.GetStyle().ImageBorderSize)) - ImGui.ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0.0, 0.0), ImVec2(1.0, 1.0), ImVec4(0.0, 0.0, 0.0, 1.0)) -- uv_min: Top-left, uv_max: Lower-right - ImGui.PopStyleVar() - - -- Fancy widget - ImGui.SeparatorText("Interactive Image Viewer") - s.viewer = s.viewer or ExampleImageViewerData() - local canvas_size = ImVec2(ImGui.GetContentRegionAvail().x, my_tex_h * 2.0) - ExampleImageViewer_DrawOptions(s.viewer) - ExampleImageViewer_DrawCanvas(s.viewer, canvas_size, my_tex_id, my_tex_w, my_tex_h) - - ImGui.SeparatorText("Textured Buttons") - ImGui.TextWrapped("And now some textured buttons..") - for i = 0, 7 do - -- UV coordinates are often (0.0, 0.0) and (1.0, 1.0) to display an entire textures. - -- Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation. - -- Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - ImGui.PushID(i) - if i > 0 then ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(i - 1.0, i - 1.0)) end - local size = ImVec2(32.0, 32.0) -- Size of the image we want to make visible - local uv0 = ImVec2(0.0, 0.0) -- UV coordinates for lower-left - local uv1 = ImVec2(32.0 / my_tex_w, 32.0 / my_tex_h) -- UV coordinates for (32,32) in our texture - -- bg_col: Black background, tint_col: No tint - if ImGui.ImageButton("", my_tex_id, size, uv0, uv1, ImVec4(0.0, 0.0, 0.0, 1.0), ImVec4(1.0, 1.0, 1.0, 1.0)) then - s.pressed_count = s.pressed_count + 1 - end - if i > 0 then ImGui.PopStyleVar() end - ImGui.PopID() - ImGui.SameLine() - end - ImGui.NewLine() - ImGui.Text("Pressed %d times.", s.pressed_count) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsListBoxes() -------------------------------------------------------------------------------- - -S.lb = { sel = 0, highlight = false } -- sel: Here we store our selected data as an index. -function DemoWindowWidgetsListBoxes() - if not ImGui.TreeNode("List Boxes") then return end - -- BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() - -- using the ImGuiChildFlags.FrameStyle flag for stylistic changes + displaying a label. - -- You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild() - -- to always be called (inconsistent with BeginListBox()/EndListBox()). - - -- Using the generic BeginListBox() API, you have full control over how to display the combo contents. - -- (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively - -- stored in the object itself, etc.) - local s = S.lb - local items = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" } - local item_highlighted_idx = -1 -- Here we store our highlighted data as an index. - _, s.highlight = ImGui.Checkbox("Highlight hovered item in second listbox", s.highlight) - if ImGui.BeginListBox("listbox 1") then - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - if ImGui.Selectable(items[n + 1], is_selected) then s.sel = n end - if s.highlight and ImGui.IsItemHovered() then item_highlighted_idx = n end - -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndListBox() - end - ImGui.SameLine(); HelpMarker("Here we are sharing selection state between both boxes.") - - -- Custom size: use all width, 5 items tall - ImGui.Text("Full-width:") - if ImGui.BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui.GetTextLineHeightWithSpacing())) then - for n = 0, #items - 1 do - local is_selected = (s.sel == n) - local flags = (item_highlighted_idx == n) and ImGuiSelectableFlags.Highlight or 0 - if ImGui.Selectable(items[n + 1], is_selected, flags) then s.sel = n end - -- Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if is_selected then ImGui.SetItemDefaultFocus() end - end - ImGui.EndListBox() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsLiveEdit() -------------------------------------------------------------------------------- - -S.le = { str = Buf("", 32), i = 0, f = 0.0 } -function DemoWindowWidgetsLiveEdit(demo_data) - if not ImGui.TreeNode("Live Edit Flags") then return end - local s = S.le - ImGui.TextWrapped("Select whether to apply keyboard edits to backing variables _while_ typing.") - _, demo_data.LiveEditOverride = ImGui.Checkbox("Override Live Edit Flags in Demo Window", demo_data.LiveEditOverride) - if not demo_data.LiveEditOverride then demo_data.LiveEditFlags = ImGui.GetItemFlags() end - ImGui.BeginDisabled(demo_data.LiveEditOverride == false) - ImGui.Indent() - _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputText", demo_data.LiveEditFlags, ImGuiItemFlags.LiveEditOnInputText) - _, demo_data.LiveEditFlags = ImGui.CheckboxFlags("ImGuiItemFlags_LiveEditOnInputScalar", demo_data.LiveEditFlags, ImGuiItemFlags.LiveEditOnInputScalar) - ImGui.Unindent() - ImGui.EndDisabled() - ImGui.Text("Try typing '123' and seeing effect on backing value:") - ImGui.InputText("str", s.str, 32) - ImGui.Text("Backing value: \"%s\"", BufStr(s.str)) - s.i = ImGui.InputInt("int", s.i, 0, 0) - ImGui.Text("Backing value: %d", s.i) - s.f = ImGui.SliderFloat("float", s.f, 0.0, 100.0) - ImGui.Text("Backing value: %f", s.f) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsMixedValues() -------------------------------------------------------------------------------- - -S.mv = { use_liveedit = false, items = { 12.0, 0.0, 0.0 } } -function DemoWindowWidgetsMixedValues() - if not ImGui.TreeNode("Mixed Values") then return end - local s = S.mv - local items = s.items - -- This is designed for advanced property editors which are generally reusable and data-driven. - HelpMarker("Using ImGuiItemFlags_MixedValue.") - _, s.use_liveedit = ImGui.Checkbox("ImGuiItemFlags_LiveEditOnInput", s.use_liveedit) - ImGui.SeparatorText("Scalar/Text Widgets") - local is_mixed = items[1] ~= items[2] or items[1] ~= items[3] - - -- Demonstrate Drags, Sliders, Inputs - ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInput, s.use_liveedit) - ImGui.PushItemFlag(ImGuiItemFlags.MixedValue, is_mixed) - local edited, e = false, false - items[1], e = ImGui.DragFloat("DragFloat", items[1]); edited = edited or e - items[1], e = ImGui.SliderFloat("SliderFloat", items[1], 0.0, 100.0); edited = edited or e - items[1], e = ImGui.InputFloat("InputFloat", items[1], 1.0); edited = edited or e - if edited then items[2] = items[1]; items[3] = items[1] end - ImGui.PopItemFlag() - ImGui.Text("Underlying data:") - items[1] = ImGui.InputFloat("item 0 (ref)", items[1]) - items[2] = ImGui.InputFloat("item 1", items[2]) - items[3] = ImGui.InputFloat("item 2", items[3]) - ImGui.PopItemFlag() - - -- Demonstrate Checkbox(), RadioButton(), Combo(), ColorEdit4() - ImGui.SeparatorText("Others Widgets") - ImGui.Text("(note: edits are not applied in this demo)") -- <-- Would need more state tracking. - ImGui.Checkbox("Checkbox On", true) - ImGui.Checkbox("Checkbox Off", false) - ImGui.PushItemFlag(ImGuiItemFlags.MixedValue, true) - ImGui.Checkbox("Checkbox Mixed", false) - ImGui.RadioButtonEx("RadioButton Mixed", true) - ImGui.SameLine() - ImGui.RadioButtonEx("RadioButton Mixed##2", true) -- Showing 2 radio buttons makes the example more clear - ImGui.Combo("Combo", 0, "One\0Two\0Three\0") - ImGui.ColorEdit4("ColorEdit4", ImVec4(0.5, 0.5, 0.5, 0.5)) - ImGui.PopItemFlag() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsMultiComponents() -------------------------------------------------------------------------------- - -S.mc = { vec4f = { 0.10, 0.20, 0.30, 0.44 }, vec4i = { 1, 5, 100, 255 }, flags = 0, b = 10, e = 90, bi = 100, ei = 1000 } -function DemoWindowWidgetsMultiComponents() - if not ImGui.TreeNode("Multi-component Widgets") then return end - local s = S.mc - local f, i = s.vec4f, s.vec4i - if ImGuiSliderFlags.ColorMarkers then _, s.flags = ImGui.CheckboxFlags("ImGuiSliderFlags_ColorMarkers", s.flags, ImGuiSliderFlags.ColorMarkers) end -- Only passing this to Drag/Sliders - local flags = s.flags - for _, n in ipairs({ 2, 3, 4 }) do - ImGui.SeparatorText(n .. "-wide") - ImGui["InputFloat" .. n]("input float" .. n, f) - ImGui["InputInt" .. n]("input int" .. n, i) - ImGui["DragFloat" .. n]("drag float" .. n, f, 0.01, 0.0, 1.0, nil, flags) - ImGui["DragInt" .. n]("drag int" .. n, i, 1, 0, 255, nil, flags) - ImGui["SliderFloat" .. n]("slider float" .. n, f, 0.0, 1.0, nil, flags) - ImGui["SliderInt" .. n]("slider int" .. n, i, 0, 255, nil, flags) - end - ImGui.SeparatorText("Ranges") - s.b, s.e = ImGui.DragFloatRange2("range float", s.b, s.e, 0.25, 0.0, 100.0, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags.AlwaysClamp) - s.bi, s.ei = ImGui.DragIntRange2("range int", s.bi, s.ei, 5, 0, 1000, "Min: %d units", "Max: %d units") - s.bi, s.ei = ImGui.DragIntRange2("range int (no bounds)", s.bi, s.ei, 5, 0, 0, "Min: %d units", "Max: %d units") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsPlotting() -------------------------------------------------------------------------------- - --- Plot/Graph widgets are not very good. --- Consider using a third-party library such as ImPlot: https://github.com/epezent/implot --- (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) -S.plot = { animate = true, arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, values = {}, values_offset = 0, refresh_time = 0.0, phase = 0.0, - func_type = 0, display_count = 70 } -for n = 1, 90 do S.plot.values[n] = 0.0 end -function DemoWindowWidgetsPlotting() - if not ImGui.TreeNode("Plotting") then return end - local s = S.plot - ImGui.Text("Need better plotting and graphing? Consider using ImPlot:") - ImGui.TextLinkOpenURL("https://github.com/epezent/implot") - ImGui.Separator() - _, s.animate = ImGui.Checkbox("Animate", s.animate) - - -- Plot as lines and plot as histogram - ImGui.PlotLines("Frame Times", s.arr, nil, #s.arr) - ImGui.PlotHistogram("Histogram", s.arr, nil, #s.arr, 0, nil, 0.0, 1.0, ImVec2(0, 80.0)) - -- ImGui.SameLine(); HelpMarker("Consider using ImPlot instead!") - - -- Fill an array of contiguous float values to plot - local values = s.values - if not s.animate or s.refresh_time == 0.0 then s.refresh_time = ImGui.GetTime() end - while s.refresh_time < ImGui.GetTime() do -- Create data at fixed 60 Hz rate for the demo - values[s.values_offset + 1] = math.cos(s.phase) - s.values_offset = (s.values_offset + 1) % #values - s.phase = s.phase + 0.10 * s.values_offset - s.refresh_time = s.refresh_time + 1.0 / 60.0 - end - - -- Plots can display overlay texts - -- (in this example, we will display an average value) - local average = 0.0 - for n = 1, #values do average = average + values[n] end - average = average / #values - ImGui.PlotLines("Lines", values, nil, #values, s.values_offset, string.format("avg %f", average), -1.0, 1.0, ImVec2(0, 80.0)) - - -- Use functions to generate output - -- FIXME: This is actually VERY awkward because current plot API only pass in indices. - -- We probably want an API passing floats and user provide sample rate/count. - -- Getters receive a 1-based index in this port - local function Sin(_, i) return math.sin((i - 1) * 0.1) end - local function Saw(_, i) return ((i - 1) % 2 == 1) and 1.0 or -1.0 end - ImGui.SeparatorText("Functions") - ImGui.SetNextItemWidth(ImGui.GetFontSize() * 8) - s.func_type = ImGui.Combo("func", s.func_type, "Sin\0Saw\0") - ImGui.SameLine() - s.display_count = ImGui.SliderInt("Sample count", s.display_count, 1, 400) - local func = (s.func_type == 0) and Sin or Saw - ImGui.PlotLines("Lines##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) - ImGui.PlotHistogram("Histogram##2", func, nil, s.display_count, 0, nil, -1.0, 1.0, ImVec2(0, 80)) - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsProgressBars() -------------------------------------------------------------------------------- - -S.pb = { accum = 0.0, dir = 1.0 } -function DemoWindowWidgetsProgressBars() - if not ImGui.TreeNode("Progress Bars") then return end - -- Animate a simple progress bar - local s = S.pb - s.accum = s.accum + s.dir * 0.4 * ImGui.GetIO().DeltaTime - if s.accum >= 1.1 then s.accum = 1.1; s.dir = -s.dir end - if s.accum <= -0.1 then s.accum = -0.1; s.dir = -s.dir end - local progress = DemoClamp(s.accum, 0.0, 1.0) - - -- Typically we would use ImVec2(-1.0,0.0) or ImVec2(-FLT_MIN,0.0) to use all available width, - -- or ImVec2(width,0.0) for a specified width. ImVec2(0.0,0.0) uses ItemWidth. - ImGui.ProgressBar(progress, ImVec2(0.0, 0.0)) - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - ImGui.Text("Progress Bar") - ImGui.ProgressBar(progress, ImVec2(0.0, 0.0), string.format("%d/%d", math.floor(progress * 1753), 1753)) - - -- Pass an animated negative value, e.g. -1.0 * ImGui.GetTime() is the recommended value. - -- Adjust the factor if you want to adjust the animation speed. - ImGui.ProgressBar(-1.0 * ImGui.GetTime(), ImVec2(0.0, 0.0), "Searching..") - ImGui.SameLine(0.0, ImGui.GetStyle().ItemInnerSpacing.x) - ImGui.Text("Indeterminate") - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsQueryingStatuses() -------------------------------------------------------------------------------- - --- Selectable(label, bool* p_selected) overload: toggles on press -local function SelectableP(label, sel, flags, size) - local pressed = ImGui.Selectable(label, sel, flags, size) - if pressed then sel = not sel end - return pressed, sel -end - -local function B(v) return v and 1 or 0 end - -S.qs = { item_type = 4, item_disabled = false, item_mixedvalue = false, liveedit_override = false, liveedit_flags = 0, - b = false, col4f = { 1.0, 0.5, 0.0, 1.0 }, str = Buf("", 16), combo = 1, listbox = 1, unused = Buf("", 1), - embed = false, test_window = false } -function DemoWindowWidgetsQueryingStatuses() - local s = S.qs - if ImGui.TreeNode("Querying Item Status (Edited/Active/Hovered etc.)") then - -- Select an item type - local item_names = { "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", - "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" } - s.item_type = ImGui.Combo("Item Type", s.item_type, item_names, #item_names, #item_names) - ImGui.SameLine() - HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().") - _, s.item_disabled = ImGui.Checkbox("Item Disabled", s.item_disabled) - _, s.item_mixedvalue = ImGui.Checkbox("Item MixedValue", s.item_mixedvalue) - _, s.liveedit_override = ImGui.Checkbox("Override LiveEdit:", s.liveedit_override) - ImGui.SameLine() - if not s.liveedit_override then s.liveedit_flags = ImGui.GetItemFlags() end - ImGui.BeginDisabled(s.liveedit_override == false) - _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInput", s.liveedit_flags, ImGuiItemFlags.LiveEditOnInput) - ImGui.SameLine() - _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputText", s.liveedit_flags, ImGuiItemFlags.LiveEditOnInputText) - ImGui.SameLine() - _, s.liveedit_flags = ImGui.CheckboxFlags("_LiveEditOnInputScalar", s.liveedit_flags, ImGuiItemFlags.LiveEditOnInputScalar) - ImGui.EndDisabled() - if s.liveedit_override then - ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInputText, bit32.band(s.liveedit_flags, ImGuiItemFlags.LiveEditOnInputText) ~= 0) - ImGui.PushItemFlag(ImGuiItemFlags.LiveEditOnInputScalar, bit32.band(s.liveedit_flags, ImGuiItemFlags.LiveEditOnInputScalar) ~= 0) - end - - -- Submit selected items so we can query their status in the code following it. - local ret = false - local t = s.item_type - if s.item_disabled then ImGui.BeginDisabled(true) end - if s.item_mixedvalue then ImGui.PushItemFlag(ImGuiItemFlags.MixedValue, true) end - if t == 0 then ImGui.Text("ITEM: Text") end -- Testing text items with no identifier/interaction - if t == 1 then ret = ImGui.Button("ITEM: Button") end -- Testing button - if t == 2 then ImGui.PushItemFlag(ImGuiItemFlags.ButtonRepeat, true); ret = ImGui.Button("ITEM: Button"); ImGui.PopItemFlag() end -- Testing button (with repeater) - if t == 3 then ret, s.b = ImGui.Checkbox("ITEM: Checkbox", s.b) end -- Testing checkbox - if t == 4 then s.col4f[1], ret = ImGui.SliderFloat("ITEM: SliderFloat", s.col4f[1], 0.0, 1.0) end -- Testing basic item - if t == 5 then ret = ImGui.InputText("ITEM: InputText", s.str, 16) end -- Testing input text (which handles tabbing) - if t == 6 then ret = ImGui.InputTextMultiline("ITEM: InputTextMultiline", s.str, 16) end -- Testing input text (which uses a child window) - if t == 7 then s.col4f[1], ret = ImGui.InputFloat("ITEM: InputFloat", s.col4f[1], 1.0) end -- Testing +/- buttons on scalar input - if t == 8 then ret = ImGui.InputFloat3("ITEM: InputFloat3", s.col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) - if t == 9 then ret = ImGui.ColorEdit4("ITEM: ColorEdit4", s.col4f) end -- Testing multi-component items (IsItemXXX flags are reported merged) - if t == 10 then ret = ImGui.Selectable("ITEM: Selectable") end -- Testing selectable item - if t == 11 then ret = ImGui.MenuItem("ITEM: MenuItem") end -- Testing menu item (they use ImGuiButtonFlags.PressedOnRelease button policy) - if t == 12 then ret = ImGui.TreeNode("ITEM: TreeNode"); if ret then ImGui.TreePop() end end -- Testing tree node - if t == 13 then ret = ImGui.TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", bit32.bor(ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.NoTreePushOnOpen)) end -- Testing tree node with ImGuiButtonFlags.PressedOnDoubleClick button policy. - if t == 14 then s.combo, ret = ImGui.Combo("ITEM: Combo", s.combo, { "Apple", "Banana", "Cherry", "Kiwi" }) end - if t == 15 then s.listbox, ret = ImGui.ListBox("ITEM: ListBox", s.listbox, { "Apple", "Banana", "Cherry", "Kiwi" }, 4, 4) end - - local HF = ImGuiHoveredFlags - local hovered_delay_none = ImGui.IsItemHovered() - local hovered_delay_stationary = ImGui.IsItemHovered(HF.Stationary) - local hovered_delay_short = ImGui.IsItemHovered(HF.DelayShort) - local hovered_delay_normal = ImGui.IsItemHovered(HF.DelayNormal) - local hovered_delay_tooltip = ImGui.IsItemHovered(HF.ForTooltip) -- = Normal + Stationary - - -- Display the values of IsItemHovered() and other common item state functions. - -- Note that the ImGuiHoveredFlags.XXX flags can be combined. - -- Because BulletText is an item itself and that would affect the output of IsItemXXX functions, - -- we query every state in a single call to avoid storing them and to simplify the code. - local rmin, rmax, rsize = ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ImGui.GetItemRectSize() - ImGui.BulletText( - "Return value = %d\nIsItemFocused() = %d\nIsItemHovered() = %d\nIsItemHovered(_AllowWhenBlockedByPopup) = %d\n" .. - "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\nIsItemHovered(_AllowWhenOverlappedByItem) = %d\n" .. - "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\nIsItemHovered(_AllowWhenDisabled) = %d\nIsItemHovered(_RectOnly) = %d\n" .. - "IsItemActive() = %d\nIsItemEdited() = %d\nIsItemActivated() = %d\nIsItemDeactivated() = %d\nIsItemDeactivatedAfterEdit() = %d\n" .. - "IsItemVisible() = %d\nIsItemClicked() = %d\nIsItemToggledOpen() = %d\n" .. - "GetItemRectMin() = (%.1f, %.1f)\nGetItemRectMax() = (%.1f, %.1f)\nGetItemRectSize() = (%.1f, %.1f)", - B(ret), B(ImGui.IsItemFocused()), B(ImGui.IsItemHovered()), B(ImGui.IsItemHovered(HF.AllowWhenBlockedByPopup)), - B(ImGui.IsItemHovered(HF.AllowWhenBlockedByActiveItem)), B(ImGui.IsItemHovered(HF.AllowWhenOverlappedByItem)), - B(ImGui.IsItemHovered(HF.AllowWhenOverlappedByWindow)), B(ImGui.IsItemHovered(HF.AllowWhenDisabled)), B(ImGui.IsItemHovered(HF.RectOnly)), - B(ImGui.IsItemActive()), B(ImGui.IsItemEdited()), B(ImGui.IsItemActivated()), B(ImGui.IsItemDeactivated()), B(ImGui.IsItemDeactivatedAfterEdit()), - B(ImGui.IsItemVisible()), B(ImGui.IsItemClicked()), B(ImGui.IsItemToggledOpen()), - rmin.x, rmin.y, rmax.x, rmax.y, rsize.x, rsize.y) - ImGui.BulletText( - "with Hovering Delay or Stationary test:\nIsItemHovered() = %d\nIsItemHovered(_Stationary) = %d\nIsItemHovered(_DelayShort) = %d\nIsItemHovered(_DelayNormal) = %d\nIsItemHovered(_Tooltip) = %d", - B(hovered_delay_none), B(hovered_delay_stationary), B(hovered_delay_short), B(hovered_delay_normal), B(hovered_delay_tooltip)) - - if s.liveedit_override then ImGui.PopItemFlag(); ImGui.PopItemFlag() end - if s.item_mixedvalue then ImGui.PopItemFlag() end - if s.item_disabled then ImGui.EndDisabled() end - - ImGui.InputText("unused", s.unused, 1, ImGuiInputTextFlags.ReadOnly) - ImGui.SameLine() - HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.") - ImGui.TreePop() - end - - if ImGui.TreeNode("Querying Window Status (Focused/Hovered etc.)") then - _, s.embed = ImGui.Checkbox("Embed everything inside a child window for testing _RootWindow flag.", s.embed) - if s.embed then ImGui.BeginChild("outer_child", ImVec2(0, ImGui.GetFontSize() * 20.0), ImGuiChildFlags.Borders) end - local FF, HF = ImGuiFocusedFlags, ImGuiHoveredFlags - local bor = bit32.bor - -- Testing IsWindowFocused() function with its various flags. - ImGui.BulletText( - "IsWindowFocused() = %d\nIsWindowFocused(_ChildWindows) = %d\nIsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" .. - "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\nIsWindowFocused(_ChildWindows|_RootWindow) = %d\n" .. - "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\nIsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" .. - "IsWindowFocused(_RootWindow) = %d\nIsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\nIsWindowFocused(_RootWindow|_DockHierarchy) = %d\n" .. - "IsWindowFocused(_AnyWindow) = %d\n", - B(ImGui.IsWindowFocused()), B(ImGui.IsWindowFocused(FF.ChildWindows)), B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.NoPopupHierarchy))), - B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.DockHierarchy))), B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.RootWindow))), - B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.RootWindow, FF.NoPopupHierarchy))), B(ImGui.IsWindowFocused(bor(FF.ChildWindows, FF.RootWindow, FF.DockHierarchy))), - B(ImGui.IsWindowFocused(FF.RootWindow)), B(ImGui.IsWindowFocused(bor(FF.RootWindow, FF.NoPopupHierarchy))), B(ImGui.IsWindowFocused(bor(FF.RootWindow, FF.DockHierarchy))), - B(ImGui.IsWindowFocused(FF.AnyWindow))) - - -- Testing IsWindowHovered() function with its various flags. - ImGui.BulletText( - "IsWindowHovered() = %d\nIsWindowHovered(_AllowWhenBlockedByPopup) = %d\nIsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" .. - "IsWindowHovered(_ChildWindows) = %d\nIsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\nIsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n" .. - "IsWindowHovered(_ChildWindows|_RootWindow) = %d\nIsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" .. - "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\nIsWindowHovered(_RootWindow) = %d\nIsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" .. - "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\nIsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\nIsWindowHovered(_AnyWindow) = %d\n" .. - "IsWindowHovered(_Stationary) = %d\n", - B(ImGui.IsWindowHovered()), B(ImGui.IsWindowHovered(HF.AllowWhenBlockedByPopup)), B(ImGui.IsWindowHovered(HF.AllowWhenBlockedByActiveItem)), - B(ImGui.IsWindowHovered(HF.ChildWindows)), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.NoPopupHierarchy))), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.DockHierarchy))), - B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.RootWindow))), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.RootWindow, HF.NoPopupHierarchy))), - B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.RootWindow, HF.DockHierarchy))), B(ImGui.IsWindowHovered(HF.RootWindow)), B(ImGui.IsWindowHovered(bor(HF.RootWindow, HF.NoPopupHierarchy))), - B(ImGui.IsWindowHovered(bor(HF.RootWindow, HF.DockHierarchy))), B(ImGui.IsWindowHovered(bor(HF.ChildWindows, HF.AllowWhenBlockedByPopup))), B(ImGui.IsWindowHovered(HF.AnyWindow)), - B(ImGui.IsWindowHovered(HF.Stationary))) - ImGui.BeginChild("child", ImVec2(0, 50), ImGuiChildFlags.Borders) - ImGui.Text("This is another child window for testing the _ChildWindows flag.") - ImGui.EndChild() - if s.embed then ImGui.EndChild() end - - -- Calling IsItemHovered() after begin returns the hovered status of the title bar. - -- This is useful in particular if you want to create a context menu associated to the title bar of a window. - -- This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties). - _, s.test_window = ImGui.Checkbox("Hovered/Active tests after Begin() for title bar testing", s.test_window) - if s.test_window then - -- FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. - -- Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? - s.test_window = ImGui.Begin("Title bar Hovered/Active tests", s.test_window) - if ImGui.BeginPopupContextItem() then -- <-- This is using IsItemHovered() - if ImGui.MenuItem("Close") then s.test_window = false end - ImGui.EndPopup() - end - ImGui.Text("IsItemHovered() after begin = %d (== is title bar hovered)\nIsItemActive() after begin = %d (== is window being clicked/moved)\n", - B(ImGui.IsItemHovered()), B(ImGui.IsItemActive())) - ImGui.End() - end - ImGui.TreePop() - end -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsSelectables() -------------------------------------------------------------------------------- - -S.sel = { basic = { false, true, false, false }, multi = { false, false, false }, checked = { false, false, false, false, false }, selected_n = 0, - tables = {}, grid = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }, - align = { true, false, true, false, true, false, true, false, true } } -for i = 1, 10 do S.sel.tables[i] = false end -function DemoWindowWidgetsSelectables() - -- ImGui.SetNextItemOpen(true, ImGuiCond.Once) - if not ImGui.TreeNode("Selectables") then return end - local s = S.sel - -- Selectable() has 2 overloads: - -- - The one taking "bool selected" as a read-only selection information. - -- When Selectable() has been clicked it returns true and you can alter selection state accordingly. - -- - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) - -- (in this port: the SelectableP() helper above, which returns (pressed, selected)) - -- The earlier is more flexible, as in real application your selection may be stored in many different ways - -- and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). - if ImGui.TreeNode("Basic") then - local b = s.basic - _, b[1] = SelectableP("1. I am selectable", b[1]) - _, b[2] = SelectableP("2. I am selectable", b[2]) - _, b[3] = SelectableP("3. I am selectable", b[3]) - if ImGui.Selectable("4. I am double clickable", b[4], ImGuiSelectableFlags.AllowDoubleClick) then - if ImGui.IsMouseDoubleClicked(0) then b[4] = not b[4] end - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Multiple items on the same line") then - -- - Using SetNextItemAllowOverlap() - -- - Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. - local m = s.multi - ImGui.SetNextItemAllowOverlap(); _, m[1] = SelectableP("main.c", m[1]); ImGui.SameLine(); ImGui.SmallButton("Link 1") - ImGui.SetNextItemAllowOverlap(); _, m[2] = SelectableP("hello.cpp", m[2]); ImGui.SameLine(); ImGui.SmallButton("Link 2") - ImGui.SetNextItemAllowOverlap(); _, m[3] = SelectableP("hello.h", m[3]); ImGui.SameLine(); ImGui.SmallButton("Link 3") - - -- (2) - -- - Using ImGuiSelectableFlags.AllowOverlap is a shortcut for calling SetNextItemAllowOverlap() - -- - No visible label, display contents inside the selectable bounds. - -- - We don't maintain actual selection in this example to keep things simple. - ImGui.Spacing() - local color_marker_w = ImGui.CalcTextSize("x").x - for n = 0, 4 do - ImGui.PushID(n) - ImGui.AlignTextToFramePadding() - if ImGui.Selectable("##selectable", s.selected_n == n, ImGuiSelectableFlags.AllowOverlap) then s.selected_n = n end - ImGui.SameLine(0, 0) - _, s.checked[n + 1] = ImGui.Checkbox("##check", s.checked[n + 1]) - ImGui.SameLine() - local color = ImVec4((n % 2 == 1) and 1.0 or 0.2, (math.floor(n / 2) % 2 == 1) and 1.0 or 0.2, 0.2, 1.0) - ImGui.ColorButton("##color", color, ImGuiColorEditFlags.NoTooltip, ImVec2(color_marker_w, 0)) - ImGui.SameLine() - ImGui.Text("Some label") - ImGui.PopID() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("In Tables") then - local sel = s.tables - local TF = ImGuiTableFlags - if ImGui.BeginTable("split1", 3, bit32.bor(TF.Resizable, TF.NoSavedSettings, TF.Borders)) then - for i = 0, 9 do - ImGui.TableNextColumn() - _, sel[i + 1] = SelectableP(string.format("Item %d", i), sel[i + 1]) -- FIXME-TABLE: Selection overlap - end - ImGui.EndTable() - end - ImGui.Spacing() - if ImGui.BeginTable("split2", 3, bit32.bor(TF.Resizable, TF.NoSavedSettings, TF.Borders)) then - for i = 0, 9 do - ImGui.TableNextRow() - ImGui.TableNextColumn() - _, sel[i + 1] = SelectableP(string.format("Item %d", i), sel[i + 1], ImGuiSelectableFlags.SpanAllColumns) - ImGui.TableNextColumn() - ImGui.Text("Some other contents") - ImGui.TableNextColumn() - ImGui.Text("123456") - end - ImGui.EndTable() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Grid") then - local g = s.grid - - -- Add in a bit of silly fun... - local time = ImGui.GetTime() - local winning_state = true - for y = 1, 4 do for x = 1, 4 do if g[y][x] == 0 then winning_state = false end end end -- If all cells are selected... - if winning_state then - ImGui.PushStyleVar(ImGuiStyleVar.SelectableTextAlign, ImVec2(0.5 + 0.5 * math.cos(time * 2.0), 0.5 + 0.5 * math.sin(time * 3.0))) - end - local size = ImGui.CalcTextSize("Sailor").x - for y = 1, 4 do - for x = 1, 4 do - if x > 1 then ImGui.SameLine() end - ImGui.PushID((y - 1) * 4 + (x - 1)) - if ImGui.Selectable("Sailor", g[y][x] ~= 0, 0, ImVec2(size, size)) then - -- Toggle clicked cell + toggle neighbors - g[y][x] = 1 - g[y][x] - if x > 1 then g[y][x - 1] = 1 - g[y][x - 1] end - if x < 4 then g[y][x + 1] = 1 - g[y][x + 1] end - if y > 1 then g[y - 1][x] = 1 - g[y - 1][x] end - if y < 4 then g[y + 1][x] = 1 - g[y + 1][x] end - end - ImGui.PopID() - end - end - if winning_state then ImGui.PopStyleVar() end - ImGui.TreePop() - end - - if ImGui.TreeNode("Alignment") then - HelpMarker("By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item basis using PushStyleVar(). You'll probably want to always keep your default situation to left-align otherwise it becomes difficult to layout multiple items on a same line") - local size = ImGui.CalcTextSize("(1.0,1.0)").x - for y = 0, 2 do - for x = 0, 2 do - local alignment = ImVec2(x / 2.0, y / 2.0) - local name = string.format("(%.1f,%.1f)", alignment.x, alignment.y) - if x > 0 then ImGui.SameLine() end - ImGui.PushStyleVar(ImGuiStyleVar.SelectableTextAlign, alignment) - _, s.align[3 * y + x + 1] = SelectableP(name, s.align[3 * y + x + 1], ImGuiSelectableFlags.None, ImVec2(size, size)) - ImGui.PopStyleVar() - end - end - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTabs() -------------------------------------------------------------------------------- - -local function EditTabBarFittingPolicyFlags(flags) - local TB = ImGuiTabBarFlags - if bit32.band(flags, TB.FittingPolicyMask_) == 0 then flags = bit32.bor(flags, TB.FittingPolicyDefault_) end - for _, n in ipairs({ "FittingPolicyMixed", "FittingPolicyShrink", "FittingPolicyScroll" }) do - local p - p, flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_" .. n, flags, TB[n]) - if p then flags = bit32.band(flags, bit32.bnot(bit32.bxor(TB.FittingPolicyMask_, TB[n]))) end - end - return flags -end - -S.tabs = { adv_flags = ImGuiTabBarFlags.Reorderable, opened = { true, true, true, true }, active_tabs = {}, next_tab_id = 0, - show_leading = true, show_trailing = true, show_lt_tabs = false, - tib_flags = bit32.bor(ImGuiTabBarFlags.AutoSelectNewTabs, ImGuiTabBarFlags.Reorderable, ImGuiTabBarFlags.FittingPolicyMixed) } -function DemoWindowWidgetsTabs() - if not ImGui.TreeNode("Tabs") then return end - local s = S.tabs - local TB, TI = ImGuiTabBarFlags, ImGuiTabItemFlags - if ImGui.TreeNode("Basic") then - if ImGui.BeginTabBar("MyTabBar", TB.None) then - if ImGui.BeginTabItem("Avocado") then ImGui.Text("This is the Avocado tab!\nblah blah blah blah blah"); ImGui.EndTabItem() end - if ImGui.BeginTabItem("Broccoli") then ImGui.Text("This is the Broccoli tab!\nblah blah blah blah blah"); ImGui.EndTabItem() end - if ImGui.BeginTabItem("Cucumber") then ImGui.Text("This is the Cucumber tab!\nblah blah blah blah blah"); ImGui.EndTabItem() end - ImGui.EndTabBar() - end - ImGui.Separator() - ImGui.TreePop() - end - - if ImGui.TreeNode("Advanced & Close Button") then - -- Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). - for _, n in ipairs({ "Reorderable", "AutoSelectNewTabs", "TabListPopupButton", "NoCloseWithMiddleMouseButton", "DrawSelectedOverline" }) do - _, s.adv_flags = ImGui.CheckboxFlags("ImGuiTabBarFlags_" .. n, s.adv_flags, TB[n]) - end - s.adv_flags = EditTabBarFittingPolicyFlags(s.adv_flags) - - -- Tab Bar - ImGui.AlignTextToFramePadding() - ImGui.Text("Opened:") - local names = { "Artichoke", "Beetroot", "Celery", "Daikon" } - for n = 1, 4 do -- s.opened: Persistent user state - ImGui.SameLine() - _, s.opened[n] = ImGui.Checkbox(names[n], s.opened[n]) - end - - -- Passing an open flag to BeginTabItem() is similar to passing one to Begin(): - -- the returned open value will be false when the tab is closed. - if ImGui.BeginTabBar("MyTabBar", s.adv_flags) then - for n = 1, 4 do - if s.opened[n] then - local visible - visible, s.opened[n] = ImGui.BeginTabItem(names[n], s.opened[n], TI.None) - if visible then - ImGui.Text("This is the %s tab!", names[n]) - if (n - 1) % 2 == 1 then ImGui.Text("I am an odd tab.") end - ImGui.EndTabItem() - end - end - end - ImGui.EndTabBar() - end - ImGui.Separator() - ImGui.TreePop() - end - - if ImGui.TreeNode("TabItemButton & Leading/Trailing flags") then - if s.next_tab_id == 0 then -- Initialize with some default tabs - for _ = 1, 3 do s.active_tabs[#s.active_tabs + 1] = s.next_tab_id; s.next_tab_id = s.next_tab_id + 1 end - end - - -- TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. - -- (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... - -- but they tend to make more sense together) - _, s.show_leading = ImGui.Checkbox("Show Leading TabItemButton()", s.show_leading) - _, s.show_trailing = ImGui.Checkbox("Show Trailing TabItemButton()", s.show_trailing) - _, s.show_lt_tabs = ImGui.Checkbox("Show Leading+Trailing TabItem()", s.show_lt_tabs) - - -- Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs - s.tib_flags = EditTabBarFittingPolicyFlags(s.tib_flags) - - if ImGui.BeginTabBar("MyTabBar", s.tib_flags) then - -- Demo a Leading TabItemButton(): click the "?" button to open a menu - if s.show_leading then - if ImGui.TabItemButton("?", bit32.bor(TI.Leading, TI.NoTooltip)) then ImGui.OpenPopup("MyHelpMenu") end - end - if ImGui.BeginPopup("MyHelpMenu") then - ImGui.Selectable("Hello!") - ImGui.EndPopup() - end - - -- Demo Leading/Trailing Tabs - if s.show_lt_tabs then - if ImGui.BeginTabItem("Leading", nil, TI.Leading) then ImGui.EndTabItem() end - if ImGui.BeginTabItem("Trailing", nil, TI.Trailing) then ImGui.EndTabItem() end - end - - -- Demo Trailing Tabs: click the "+" button to add a new tab. - -- (In your app you may want to use a font icon instead of the "+") - -- We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags.Trailing flag it will always appear at the end. - if s.show_trailing then - if ImGui.TabItemButton("+", bit32.bor(TI.Trailing, TI.NoTooltip)) then - s.active_tabs[#s.active_tabs + 1] = s.next_tab_id; s.next_tab_id = s.next_tab_id + 1 -- Add new tab - end - end - - -- Submit our regular tabs - local n = 1 - while n <= #s.active_tabs do - local name = string.format("%04d", s.active_tabs[n]) - local visible, open = ImGui.BeginTabItem(name, true, TI.None) - if visible then - ImGui.Text("This is the %s tab!", name) - ImGui.EndTabItem() - end - if open == false then table.remove(s.active_tabs, n) else n = n + 1 end - end - ImGui.EndTabBar() - end - ImGui.Separator() - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsText() -------------------------------------------------------------------------------- - -S.text = { custom_size = 16.0, custom_scale = 1.0, wrap_width = 200.0, utf8 = Buf("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e", 32) } -function DemoWindowWidgetsText() - if not ImGui.TreeNode("Text") then return end - local s = S.text - if ImGui.TreeNode("Colorful Text") then - -- Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. - ImGui.TextColored(ImVec4(1.0, 0.0, 1.0, 1.0), "Pink") - ImGui.TextColored(ImVec4(1.0, 1.0, 0.0, 1.0), "Yellow") - ImGui.TextDisabled("Disabled") - ImGui.SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.") - ImGui.TreePop() - end - - if ImGui.TreeNode("Font Size") then - local style = ImGui.GetStyle() - local global_scale = style.FontScaleMain * style.FontScaleDpi - ImGui.Text("style.FontScaleMain = %0.2f", style.FontScaleMain) - ImGui.Text("style.FontScaleDpi = %0.2f", style.FontScaleDpi) - ImGui.Text("global_scale = ~%0.2f", global_scale) -- This is not technically accurate as internal scales may apply, but conceptually let's pretend it is. - ImGui.Text("FontSize = %0.2f", ImGui.GetFontSize()) - - ImGui.SeparatorText("") - s.custom_size = ImGui.SliderFloat("custom_size", s.custom_size, 10.0, 100.0, "%.0f") - ImGui.Text("ImGui::PushFont(nullptr, custom_size);") - ImGui.PushFont(nil, s.custom_size) - ImGui.Text("FontSize = %.2f (== %.2f * global_scale)", ImGui.GetFontSize(), s.custom_size) - ImGui.PopFont() - ImGui.SeparatorText("") - s.custom_scale = ImGui.SliderFloat("custom_scale", s.custom_scale, 0.5, 4.0, "%.2f") - ImGui.Text("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scale);") - ImGui.PushFont(nil, style.FontSizeBase * s.custom_scale) - ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), s.custom_scale) - ImGui.PopFont() - ImGui.SeparatorText("") - local scaling = 0.5 - while scaling <= 4.0 do - ImGui.PushFont(nil, style.FontSizeBase * scaling) - ImGui.Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui.GetFontSize(), scaling) - ImGui.PopFont() - scaling = scaling + 0.5 - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Word Wrapping") then - -- Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. - ImGui.TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages.") - ImGui.Spacing() - s.wrap_width = ImGui.SliderFloat("Wrap width", s.wrap_width, -20, 600, "%.0f") - local draw_list = ImGui.GetWindowDrawList() - for n = 0, 1 do - ImGui.Text("Test paragraph %d:", n) - local pos = ImGui.GetCursorScreenPos() - local marker_min = ImVec2(pos.x + s.wrap_width, pos.y) - local marker_max = ImVec2(pos.x + s.wrap_width + 10, pos.y + ImGui.GetTextLineHeight()) - ImGui.PushTextWrapPos(ImGui.GetCursorPos().x + s.wrap_width) - if n == 0 then - ImGui.Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", s.wrap_width) - else - ImGui.Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh") - end - - -- Draw actual text bounding box, following by marker of our expected limit (should not overlap!) - draw_list:AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), IM_COL32(255, 255, 0, 255)) - draw_list:AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)) - ImGui.PopTextWrapPos() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("UTF-8 Text") then - -- UTF-8 test with Japanese characters - -- (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) - -- - FOR THIS DEMO FILE ONLY, WE ARE *NOT* INCLUDING RAW UTF-8 - -- CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal escapes. - -- Note that characters values are preserved even by InputText() if the font cannot be displayed, - -- so you can safely copy & paste garbled characters into another application. - ImGui.TextWrapped("CJK text will only appear if the font was loaded with the appropriate CJK character ranges. Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. Read docs/FONTS.md for details.") - ImGui.Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)") - ImGui.Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)") - ImGui.InputText("UTF-8 input", s.utf8, 32) - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTextFilter() -------------------------------------------------------------------------------- - -S.tf = { filter = nil } -function DemoWindowWidgetsTextFilter() - if not ImGui.TreeNode("Text Filter") then return end - -- Helper class to easy setup a text filter. - -- You may want to implement a more feature-full filtering scheme in your own application. - S.tf.filter = S.tf.filter or ImGuiTextFilter() - local filter = S.tf.filter - HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.") - ImGui.Text("Filter usage:\n \"\" display all lines\n xxx display lines containing \"xxx\"\n xxx yyy display lines containing \"xxx\" and \"yyy\"\n \"xxx yyy\" display lines containing \"xxx yyy\"\n xxx,yyy display lines containing \"xxx\" or \"yyy\"\n -xxx hide lines containing \"xxx\"") - ImGui.SetNextItemWidth(-FLT_MIN) - filter:DrawWithHint("##Filter", "Filter (incl -excl)") - if ImGui.BeginChild("##items", ImVec2(-FLT_MIN, ImGui.GetTextLineHeightWithSpacing() * 15), ImGuiChildFlags.FrameStyle) then - for _, item in ipairs({ "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }) do - if filter:PassFilter(item) then ImGui.TextUnformatted(item) end - end - for _, item in ipairs(ExampleNames) do - if filter:PassFilter(item) then ImGui.TextUnformatted(item) end - end - end - ImGui.EndChild() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTextInput() -------------------------------------------------------------------------------- - -S.ti = { - text = Buf("/*\n The Pentium F00F bug, shorthand for F0 0F C7 C8,\n the hexadecimal encoding of one offending instruction,\n more formally, the invalid operand with locked CMPXCHG8B\n instruction bug, is a design flaw in the majority of\n Intel Pentium, Pentium MMX, and Pentium OverDrive\n processors (all in the P5 microarchitecture).\n*/\n\nlabel:\n\tlock cmpxchg8b eax\n", 1024 * 16), - ml_flags = ImGuiInputTextFlags.AllowTabInput, - f = { Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32), Buf("", 32) }, - password = Buf("password123", 64), cb1 = Buf("", 64), cb2 = Buf("", 64), cb3 = Buf("", 64), edit_count = { 0 }, - rs_flags = 0, rs = Buf("", 1024), - elide = Buf("/path/to/some/folder/with/long/filename.cpp", 128), elide_flags = ImGuiInputTextFlags.ElideLeft, - misc = Buf("", 16), misc_flags = ImGuiInputTextFlags.EscapeClearsAll } -function DemoWindowWidgetsTextInput() - if not ImGui.TreeNode("Text Input") then return end - local s = S.ti - local IT = ImGuiInputTextFlags - local function FlagBox(key, name) - if IT[name] then _, s[key] = ImGui.CheckboxFlags("ImGuiInputTextFlags_" .. name, s[key], IT[name]) end - end - if ImGui.TreeNode("Multi-line Text Input") then - -- WE ARE USING A FIXED-SIZE BUFFER FOR SIMPLICITY HERE. - HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type.") - FlagBox("ml_flags", "ReadOnly") - FlagBox("ml_flags", "WordWrap") - ImGui.SameLine(); HelpMarker("Feature is currently in Beta. Please read comments in imgui.h") - FlagBox("ml_flags", "AllowTabInput") - ImGui.SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets.") - FlagBox("ml_flags", "CtrlEnterForNewLine") - ImGui.InputTextMultiline("##source", s.text, 1024 * 16, ImVec2(-FLT_MIN, ImGui.GetTextLineHeight() * 16), s.ml_flags) - ImGui.TreePop() - end - - if ImGui.TreeNode("Filtered Text Input") then - local a, z, A, Z = string.byte("a"), string.byte("z"), string.byte("A"), string.byte("Z") - -- Modify character input by altering 'data.EventChar' (ImGuiInputTextFlags.CallbackCharFilter callback) - local function FilterCasingSwap(data) - local c = data.EventChar - if c >= a and c <= z then data.EventChar = c - (a - A) -- Lowercase becomes uppercase - elseif c >= A and c <= Z then data.EventChar = c + (a - A) end -- Uppercase becomes lowercase - return 0 - end - -- Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) - local function FilterImGuiLetters(data) - local c = data.EventChar - if c < 256 and string.find("imgui", string.char(c), 1, true) then return 0 end - return 1 - end - local f = s.f - ImGui.InputText("default", f[1], 32) - ImGui.InputText("decimal", f[2], 32, IT.CharsDecimal) - ImGui.InputText("hexadecimal", f[3], 32, bit32.bor(IT.CharsHexadecimal, IT.CharsUppercase)) - ImGui.InputText("uppercase", f[4], 32, IT.CharsUppercase) - ImGui.InputText("no blank", f[5], 32, IT.CharsNoBlank) - ImGui.InputText("casing swap", f[6], 32, IT.CallbackCharFilter, FilterCasingSwap) -- Use CharFilter callback to replace characters. - ImGui.InputText("\"imgui\"", f[7], 32, IT.CallbackCharFilter, FilterImGuiLetters) -- Use CharFilter callback to disable some characters. - ImGui.TreePop() - end - - if ImGui.TreeNode("Password Input") then - ImGui.InputText("password", s.password, 64, IT.Password) - ImGui.SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n") - ImGui.InputTextWithHint("password (w/ hint)", "", s.password, 64, IT.Password) - ImGui.InputText("password (clear)", s.password, 64) - ImGui.TreePop() - end - - if ImGui.TreeNode("Completion, History, Edit Callbacks") then - local function MyCallback(data) - if data.EventFlag == IT.CallbackCompletion then - data:InsertChars(data.CursorPos, "..") - elseif data.EventFlag == IT.CallbackHistory then - if data.EventKey == ImGuiKey.UpArrow then - data:DeleteChars(0, data.BufTextLen) - data:InsertChars(0, "Pressed Up!") - data:SelectAll() - elseif data.EventKey == ImGuiKey.DownArrow then - data:DeleteChars(0, data.BufTextLen) - data:InsertChars(0, "Pressed Down!") - data:SelectAll() - end - elseif data.EventFlag == IT.CallbackEdit then - -- Toggle casing of first character - local c = data.Buf[1] - if (c >= 97 and c <= 122) or (c >= 65 and c <= 90) then data.Buf[1] = bit32.bxor(c, 32) end - data.BufDirty = true - - -- Increment a counter - local p_int = data.UserData - p_int[1] = p_int[1] + 1 - end - return 0 - end - ImGui.InputText("Completion", s.cb1, 64, IT.CallbackCompletion, MyCallback) - ImGui.SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.") - ImGui.InputText("History", s.cb2, 64, IT.CallbackHistory, MyCallback) - ImGui.SameLine(); HelpMarker("Here we replace and select text each time Up/Down are pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.") - ImGui.InputText("Edit", s.cb3, 64, IT.CallbackEdit, MyCallback, s.edit_count) - ImGui.SameLine(); HelpMarker("Here we toggle the casing of the first character on every edit + count edits.") - ImGui.SameLine(); ImGui.Text("(%d)", s.edit_count[1]) - ImGui.TreePop() - end - - if ImGui.TreeNode("Resize Callback") then - HelpMarker("Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n(Lua port: fixed 1024 byte buffer, CallbackResize growth not supported)") - FlagBox("rs_flags", "WordWrap") - ImGui.InputTextMultiline("##MyStr", s.rs, 1024, ImVec2(-FLT_MIN, ImGui.GetTextLineHeight() * 16), s.rs_flags) - ImGui.Text("Size: %d\nCapacity: %d", #BufStr(s.rs) + 1, 1024) - ImGui.TreePop() - end - - if ImGui.TreeNode("Eliding, Alignment") then - FlagBox("elide_flags", "ElideLeft") - ImGui.InputText("Path", s.elide, 128, s.elide_flags) - ImGui.TreePop() - end - - if ImGui.TreeNode("Miscellaneous") then - FlagBox("misc_flags", "EscapeClearsAll") - FlagBox("misc_flags", "ReadOnly") - FlagBox("misc_flags", "NoUndoRedo") - ImGui.InputText("Hello", s.misc, 16, s.misc_flags) - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTooltips() -------------------------------------------------------------------------------- - -S.tt = { arr = { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }, always_on = 0 } -function DemoWindowWidgetsTooltips() - if not ImGui.TreeNode("Tooltips") then return end - local s = S.tt - local HF = ImGuiHoveredFlags - -- Tooltips are windows following the mouse. They do not take focus away. - ImGui.SeparatorText("General") - - -- Typical use cases: - -- - Short-form (text only): SetItemTooltip("Hello") - -- - Short-form (any contents): if BeginItemTooltip() then Text("Hello"); EndTooltip() end - - -- - Full-form (text only): if IsItemHovered(...) then SetTooltip("Hello") end - -- - Full-form (any contents): if IsItemHovered(...) and BeginTooltip() then Text("Hello"); EndTooltip() end - - HelpMarker("Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\nWe provide a helper SetItemTooltip() function to perform the two with standards flags.") - local sz = ImVec2(-FLT_MIN, 0.0) - ImGui.Button("Basic", sz) - ImGui.SetItemTooltip("I am a tooltip") - ImGui.Button("Fancy", sz) - if ImGui.BeginItemTooltip() then - ImGui.Text("I am a fancy tooltip") - ImGui.PlotLines("Curve", s.arr, nil, #s.arr) - ImGui.Text("Sin(time) = %f", math.sin(ImGui.GetTime())) - ImGui.EndTooltip() - end - - ImGui.SeparatorText("Always On") - - -- Showcase NOT relying on a IsItemHovered() to emit a tooltip. - -- Here the tooltip is always emitted when 'always_on == true'. - _, s.always_on = ImGui.RadioButton("Off", s.always_on, 0) - ImGui.SameLine() - _, s.always_on = ImGui.RadioButton("Always On (Simple)", s.always_on, 1) - ImGui.SameLine() - _, s.always_on = ImGui.RadioButton("Always On (Advanced)", s.always_on, 2) - if s.always_on == 1 then - ImGui.SetTooltip("I am following you around.") - elseif s.always_on == 2 and ImGui.BeginTooltip() then - ImGui.ProgressBar(math.sin(ImGui.GetTime()) * 0.5 + 0.5, ImVec2(ImGui.GetFontSize() * 25, 0.0)) - ImGui.EndTooltip() - end - - ImGui.SeparatorText("Custom") - HelpMarker("Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize tooltip activation details across your application. You may however decide to use custom flags for a specific tooltip instance.") - - -- The following examples are passed for documentation purpose but may not be useful to most users. - -- Passing ImGuiHoveredFlags.ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from - -- 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. - -- With default settings, ImGuiHoveredFlags.ForTooltip is equivalent to ImGuiHoveredFlags.DelayShort + ImGuiHoveredFlags.Stationary. - ImGui.Button("Manual", sz) - if ImGui.IsItemHovered(HF.ForTooltip) then ImGui.SetTooltip("I am a manually emitted tooltip.") end - ImGui.Button("DelayNone", sz) - if ImGui.IsItemHovered(HF.DelayNone) then ImGui.SetTooltip("I am a tooltip with no delay.") end - ImGui.Button("DelayShort", sz) - if ImGui.IsItemHovered(bit32.bor(HF.DelayShort, HF.NoSharedDelay)) then ImGui.SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui.GetStyle().HoverDelayShort) end - ImGui.Button("DelayLong", sz) - if ImGui.IsItemHovered(bit32.bor(HF.DelayNormal, HF.NoSharedDelay)) then ImGui.SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui.GetStyle().HoverDelayNormal) end - ImGui.Button("Stationary", sz) - if ImGui.IsItemHovered(HF.Stationary) then ImGui.SetTooltip("I am a tooltip requiring mouse to be stationary before activating.") end - - -- Using ImGuiHoveredFlags.ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav', - -- which default value include the ImGuiHoveredFlags.AllowWhenDisabled flag. - ImGui.BeginDisabled() - ImGui.Button("Disabled item", sz) - if ImGui.IsItemHovered(HF.ForTooltip) then ImGui.SetTooltip("I am a tooltip for a disabled item.") end - ImGui.EndDisabled() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsTreeNodes() -------------------------------------------------------------------------------- - -S.tn = { lines_flags = bit32.bor(ImGuiTreeNodeFlags.DrawLinesFull, ImGuiTreeNodeFlags.DefaultOpen), selection_mask = 0, - adv_flags = bit32.bor(ImGuiTreeNodeFlags.OpenOnArrow, ImGuiTreeNodeFlags.OpenOnDoubleClick, ImGuiTreeNodeFlags.SpanAvailWidth), - align_label = false, use_dnd = false } -function DemoWindowWidgetsTreeNodes() - if not ImGui.TreeNode("Tree Nodes") then return end - local s = S.tn - local TN = ImGuiTreeNodeFlags - -- See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree. - if ImGui.TreeNode("Basic Trees") then - for i = 0, 4 do - -- Use SetNextItemOpen() so set the default state of a node to be open. We could - -- also use TreeNodeEx() with the ImGuiTreeNodeFlags.DefaultOpen flag to achieve the same thing! - if i == 0 then ImGui.SetNextItemOpen(true, ImGuiCond.Once) end - - -- Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict. - -- An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode(i, ...)', - -- aka pass a number value to be hashed. The demo below uses that technique. Both are fine. - ImGui.PushID(i) - if ImGui.TreeNode("", "Child %d", i) then - ImGui.Text("blah blah") - ImGui.SameLine() - if ImGui.SmallButton("button") then end - ImGui.TreePop() - end - ImGui.PopID() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Hierarchy Lines") then - HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") - _, s.lines_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", s.lines_flags, TN.DrawLinesNone) - _, s.lines_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", s.lines_flags, TN.DrawLinesFull) - _, s.lines_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", s.lines_flags, TN.DrawLinesToNodes) - local f = s.lines_flags - if ImGui.TreeNodeEx("Parent", f) then - if ImGui.TreeNodeEx("Child 1", f) then ImGui.Button("Button for Child 1"); ImGui.TreePop() end - if ImGui.TreeNodeEx("Child 2", f) then ImGui.Button("Button for Child 2"); ImGui.TreePop() end - ImGui.Text("Remaining contents") - ImGui.Text("Remaining contents") - ImGui.TreePop() - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Clipping Large Trees") then - ImGui.TextWrapped("- Using ImGuiListClipper with trees is a less easy than on arrays or grids.\n- Refer to 'Demo->Examples->Property Editor' for an example of how to do that.\n- Discuss in #3823") - ImGui.TreePop() - end - - if ImGui.TreeNode("Selectable Nodes") then - HelpMarker("Manually implemented selectable nodes.\nClick to select, Ctrl+Click to toggle, click on arrows or double-click to open.") - - -- Hold in 'selection_mask' a simple representation of what may be user-side selection state. - -- - You may retain selection state inside or outside your objects in whatever format you see fit. - -- You may use ImGuiSelectionBasicStorage which is conceptually close to a set<> of identifiers. - -- - We record which node was clicked and then apply selection at the end of the loop. - -- - This is a manual and simplified reimplementation of multi-selection, which the full - -- BeginMultiSelect() API implements better, but which is not trivial to wire for trees. - local node_clicked_idx = -1 - for node_n = 0, 5 do - -- Disable the default "open on single-click behavior" + set Selected flag according to our selection. - -- To alter selection we use if 'IsItemClicked() and not IsItemToggledOpen()', so clicking on an arrow doesn't alter selection. - -- In a BeginMultiSelect()/EndMultiSelect() we could use IsItemToggledSelection() but here we reimplement and use our own logic. - local flags = bit32.bor(TN.OpenOnArrow, TN.OpenOnDoubleClick, TN.SpanAvailWidth) - if bit32.band(s.selection_mask, bit32.lshift(1, node_n)) ~= 0 then flags = bit32.bor(flags, TN.Selected) end - local is_open = ImGui.TreeNodeEx(node_n, flags, "Selectable Node %d", node_n) - if ImGui.IsItemClicked() and not ImGui.IsItemToggledOpen() then node_clicked_idx = node_n end - if is_open then - ImGui.BulletText("") - ImGui.TreePop() - end - end - if node_clicked_idx ~= -1 then - -- Update selection state (process outside of tree loop to avoid visual inconsistencies during the clicking frame) - if ImGui.GetIO().KeyCtrl then - s.selection_mask = bit32.bxor(s.selection_mask, bit32.lshift(1, node_clicked_idx)) -- Ctrl+Click to toggle - else -- if not (selection_mask & (1 << node_clicked_idx)) -- Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection - s.selection_mask = bit32.lshift(1, node_clicked_idx) -- Click to single-select - end - end - ImGui.TreePop() - end - - if ImGui.TreeNode("Advanced") then - local function FB(name, help) - _, s.adv_flags = ImGui.CheckboxFlags("ImGuiTreeNodeFlags_" .. name, s.adv_flags, TN[name]) - if help then ImGui.SameLine(); HelpMarker(help) end - end - FB("OpenOnArrow"); FB("OpenOnDoubleClick") - FB("SpanAvailWidth", "Extend hit area to all available width instead of allowing more items to be laid out after the node.") - FB("SpanFullWidth") - FB("SpanLabelWidth", "Reduce hit area to the text label and a bit of margin.") - FB("SpanAllColumns", "For use in Tables only.") - FB("AllowOverlap") - FB("Framed", "Draw frame with background (e.g. for CollapsingHeader)") - FB("FramePadding"); FB("NavLeftJumpsToParent") - HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags") - FB("DrawLinesNone"); FB("DrawLinesFull"); FB("DrawLinesToNodes") - _, s.align_label = ImGui.Checkbox("Align label with current X position", s.align_label) - _, s.use_dnd = ImGui.Checkbox("Make Tree Nodes as drag & drop sources", s.use_dnd) - if s.align_label then ImGui.Unindent(ImGui.GetTreeNodeToLabelSpacing()) end - for node_n = 0, 5 do - local node_flags = s.adv_flags - if node_n < 3 then - -- Items 0..2 are Tree Node - local is_open = ImGui.TreeNodeEx(node_n, node_flags, "Selectable Node %d", node_n) - if s.use_dnd and ImGui.BeginDragDropSource() then - ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) - ImGui.Text("This is a drag and drop source") - ImGui.EndDragDropSource() - end - if node_n == 2 and bit32.band(s.adv_flags, TN.SpanLabelWidth) ~= 0 then - -- Item 2 has an additional inline button to help demonstrate SpanLabelWidth. - ImGui.SameLine() - if ImGui.SmallButton("button") then end - end - if is_open then - ImGui.BulletText("Blah blah\nBlah Blah") - ImGui.SameLine() - ImGui.SmallButton("Button") - ImGui.TreePop() - end - else - -- Items 3..5 are Tree Leaves - -- The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can - -- use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). - node_flags = bit32.bor(node_flags, TN.Leaf, TN.NoTreePushOnOpen) -- ImGuiTreeNodeFlags.Bullet - ImGui.TreeNodeEx(node_n, node_flags, "Selectable Leaf %d", node_n) - if s.use_dnd and ImGui.BeginDragDropSource() then - ImGui.SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", nil, 0) - ImGui.Text("This is a drag and drop source") - ImGui.EndDragDropSource() - end - end - end - if s.align_label then ImGui.Indent(ImGui.GetTreeNodeToLabelSpacing()) end - ImGui.TreePop() - end - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] DemoWindowWidgetsVerticalSliders() -------------------------------------------------------------------------------- - -S.vs = { int_value = 0, values = { 0.0, 0.60, 0.35, 0.9, 0.70, 0.20, 0.0 }, values2 = { 0.20, 0.80, 0.40, 0.25 } } -function DemoWindowWidgetsVerticalSliders() - if not ImGui.TreeNode("Vertical Sliders") then return end - local s = S.vs - local spacing = 4 - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ImVec2(spacing, spacing)) - s.int_value = ImGui.VSliderInt("##int", ImVec2(18, 160), s.int_value, 0, 5) - ImGui.SameLine() - local values = s.values - ImGui.PushID("set1") - for i = 0, 6 do - if i > 0 then ImGui.SameLine() end - ImGui.PushID(i) - ImGui.PushStyleColor(ImGuiCol.FrameBg, HSV(i / 7.0, 0.5, 0.5)) - ImGui.PushStyleColor(ImGuiCol.FrameBgHovered, HSV(i / 7.0, 0.6, 0.5)) - ImGui.PushStyleColor(ImGuiCol.FrameBgActive, HSV(i / 7.0, 0.7, 0.5)) - ImGui.PushStyleColor(ImGuiCol.SliderGrab, HSV(i / 7.0, 0.9, 0.9)) - values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(18, 160), values[i + 1], 0.0, 1.0, "") - if ImGui.IsItemActive() or ImGui.IsItemHovered() then ImGui.SetTooltip("%.3f", values[i + 1]) end - ImGui.PopStyleColor(4) - ImGui.PopID() - end - ImGui.PopID() - - ImGui.SameLine() - ImGui.PushID("set2") - local rows = 3 - local small_slider_size = ImVec2(18, math.floor((160.0 - (rows - 1) * spacing) / rows)) - for nx = 0, 3 do - if nx > 0 then ImGui.SameLine() end - ImGui.BeginGroup() - for ny = 0, rows - 1 do - ImGui.PushID(nx * rows + ny) - s.values2[nx + 1] = ImGui.VSliderFloat("##v", small_slider_size, s.values2[nx + 1], 0.0, 1.0, "") - if ImGui.IsItemActive() or ImGui.IsItemHovered() then ImGui.SetTooltip("%.3f", s.values2[nx + 1]) end - ImGui.PopID() - end - ImGui.EndGroup() - end - ImGui.PopID() - - ImGui.SameLine() - ImGui.PushID("set3") - for i = 0, 3 do - if i > 0 then ImGui.SameLine() end - ImGui.PushID(i) - ImGui.PushStyleVar(ImGuiStyleVar.GrabMinSize, 40) - values[i + 1] = ImGui.VSliderFloat("##v", ImVec2(40, 160), values[i + 1], 0.0, 1.0, "%.2f\nsec") - ImGui.PopStyleVar() - ImGui.PopID() - end - ImGui.PopID() - ImGui.PopStyleVar() - ImGui.TreePop() -end - -------------------------------------------------------------------------------- --- [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() -------------------------------------------------------------------------------- --- - ShowExampleAppMainMenuBar() --- - ShowExampleMenuFile() -------------------------------------------------------------------------------- - -S.menu = { enabled = true, f = 0.5, n = 0, b = true } --- Note that shortcuts are currently provided for display only --- (future version will add explicit flags to BeginMenu() to request processing shortcuts) -function ShowExampleMenuFile() - local s = S.menu - ImGui.MenuItem("(demo menu)", nil, false, false) - if ImGui.MenuItem("New") then end - if ImGui.MenuItem("Open", "Ctrl+O") then end - if ImGui.BeginMenu("Open Recent") then - ImGui.MenuItem("fish_hat.c") - ImGui.MenuItem("fish_hat.inl") - ImGui.MenuItem("fish_hat.h") - if ImGui.BeginMenu("More..") then - ImGui.MenuItem("Hello") - ImGui.MenuItem("Sailor") - if ImGui.BeginMenu("Recurse..") then - ShowExampleMenuFile() - ImGui.EndMenu() - end - ImGui.EndMenu() - end - ImGui.EndMenu() - end - if ImGui.MenuItem("Save", "Ctrl+S") then end - if ImGui.MenuItem("Save As..") then end - - ImGui.Separator() - if ImGui.BeginMenu("Options") then - _, s.enabled = ImGui.MenuItem("Enabled", "", s.enabled) - ImGui.BeginChild("child", ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 5.0), ImGuiChildFlags.Borders) - for i = 0, 9 do ImGui.Text("Scrolling Text %d", i) end - ImGui.EndChild() - s.f = ImGui.SliderFloat("Value", s.f, 0.0, 1.0) - s.f = ImGui.InputFloat("Input", s.f, 0.1) - s.n = ImGui.Combo("Combo", s.n, "Yes\0No\0Maybe\0\0") - ImGui.EndMenu() - end - - if ImGui.BeginMenu("Colors") then - local sz = ImGui.GetTextLineHeight() - for i = 0, ImGuiCol.COUNT - 1 do - local name = ImGui.GetStyleColorName(i) - local p = ImGui.GetCursorScreenPos() - ImGui.GetWindowDrawList():AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui.GetColorU32(i)) - ImGui.Dummy(ImVec2(sz, sz)) - ImGui.SameLine() - ImGui.MenuItem(name) - end - ImGui.EndMenu() - end - - -- Here we demonstrate appending again to the "Options" menu (which we already created above) - -- Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. - -- In a real code-base using it would make senses to use this feature from very different code locations. - if ImGui.BeginMenu("Options") then -- <-- Append! - _, s.b = ImGui.Checkbox("SomeOption", s.b) - ImGui.EndMenu() - end - - if ImGui.BeginMenu("Disabled", false) then -- Disabled - IM_ASSERT(false) - end - if ImGui.MenuItem("Checked", nil, true) then end - ImGui.Separator() - if ImGui.MenuItem("Quit", "Alt+F4") then end -end - --- Demonstrate creating a "main" fullscreen menu bar and populating it. --- Note the difference between BeginMainMenuBar() and BeginMenuBar(): --- - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags.MenuBar flag!) --- - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. -function ShowExampleAppMainMenuBar() - if ImGui.BeginMainMenuBar() then - if ImGui.BeginMenu("File") then - ShowExampleMenuFile() - ImGui.EndMenu() - end - if ImGui.BeginMenu("Edit") then - if ImGui.MenuItem("Undo", "Ctrl+Z") then end - if ImGui.MenuItem("Redo", "Ctrl+Y", false, false) then end -- Disabled item - ImGui.Separator() - if ImGui.MenuItem("Cut", "Ctrl+X") then end - if ImGui.MenuItem("Copy", "Ctrl+C") then end - if ImGui.MenuItem("Paste", "Ctrl+V") then end - ImGui.EndMenu() - end - ImGui.EndMainMenuBar() - end -end - -------------------------------------------------------------------------------- --- [SECTION] Style Editor / ShowStyleEditor() -------------------------------------------------------------------------------- --- - ShowStyleSelector() --- - ShowStyleEditor() -------------------------------------------------------------------------------- - --- Deep copy of an ImGuiStyle (ImVec2/ImVec4 fields and Colors[] are copied by value) -local function StyleCopy(dst, src) - for k, v in pairs(src) do - if k == "Colors" then - dst.Colors = dst.Colors or {} - for i, c in pairs(v) do - if type(c) == "table" then dst.Colors[i] = dst.Colors[i] or ImVec4(); ImVec4_Copy(dst.Colors[i], c) else dst.Colors[i] = c end - end - elseif type(v) == "table" and getmetatable(v) ~= nil and type(v[1]) == "number" then - local c = dst[k] - if type(c) ~= "table" then c = setmetatable({}, getmetatable(v)); dst[k] = c end - for _, key in ipairs({ "x", "y", "z", "w" }) do if rawget(v, key) ~= nil then rawset(c, key, rawget(v, key)) end end - else - dst[k] = v - end - end - if getmetatable(dst) == nil then setmetatable(dst, getmetatable(src)) end - return dst -end - -local function ColorsEqual(a, b) return a[1] == b[1] and a[2] == b[2] and a[3] == b[3] and a[4] == b[4] end - -S.ss = { style_idx = -1 } --- Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. -function ImGui.ShowStyleSelector(label) - -- FIXME: This is a bit tricky to get right as style are functions, they don't register a name nor the fact that one is active. - -- So we keep track of last active one among our limited selection. - local s = S.ss - local style_names = { "Dark", "Light", "Classic" } - local ret = false - if ImGui.BeginCombo(label, style_names[s.style_idx + 1] or "") then - for n = 0, 2 do - if ImGui.Selectable(style_names[n + 1], s.style_idx == n, ImGuiSelectableFlags.SelectOnNav) then - s.style_idx = n - ret = true - if n == 0 then ImGui.StyleColorsDark() elseif n == 1 then ImGui.StyleColorsLight() else ImGui.StyleColorsClassic() end - elseif s.style_idx == n then - ImGui.SetItemDefaultFocus() - end - end - ImGui.EndCombo() - end - return ret -end - -local function GetTreeLinesFlagsName(flags) - local TN = ImGuiTreeNodeFlags - if flags == TN.DrawLinesNone then return "DrawLinesNone" end - if flags == TN.DrawLinesFull then return "DrawLinesFull" end - if flags == TN.DrawLinesToNodes then return "DrawLinesToNodes" end - return "" -end - -S.se = { ref_saved_style = nil, init = true, output_dest = 0, output_only_modified = true, alpha_flags = 0, filter = nil } -function ImGui.ShowStyleEditor(ref) - -- You can pass in a reference ImGuiStyle structure to compare to, revert to and save to - -- (without a reference style, we will use one compared locally as a reference) - local se = S.se - local style = ImGui.GetStyle() - if se.ref_saved_style == nil then se.ref_saved_style = {} end - - -- Default to using internal storage as reference - if se.init and ref == nil then StyleCopy(se.ref_saved_style, style) end - se.init = false - if ref == nil then ref = se.ref_saved_style end - - -- The logic behind dynamically changing 'max_border_size' is to not encourage people to increase border size too much: it'll likely reveal lots of subtle rendering artifacts and this isn't a priority right now. - -- Note that _MainScale is currently internal PLEASE DO NOT USE IN YOUR CODE. - local default_border_size = math.floor(style._MainScale or 1.0) - local max_border_size = math.max(default_border_size, 2.0) - local function SF(name, mn, mx, fmt) if style[name] ~= nil then style[name] = ImGui.SliderFloat(name, style[name], mn, mx, fmt or "%.0f") end end - local function SF2(name, mn, mx, fmt) if style[name] ~= nil then ImGui.SliderFloat2(name, style[name], mn, mx, fmt or "%.0f") end end - local function DF(name, speed, mn, mx, fmt, flags) if style[name] ~= nil then style[name] = ImGui.DragFloat(name, style[name], speed, mn, mx, fmt or "%.0f", flags) end end - - ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50) - - -- General - ImGui.SeparatorText("General") - if bit32.band(ImGui.GetIO().BackendFlags, ImGuiBackendFlags.RendererHasTextures) == 0 then - ImGui.BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!") - ImGui.BulletText("For instructions, see:") - ImGui.SameLine() - ImGui.TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md") - end - if ImGui.ShowStyleSelector("Colors##Selector") then StyleCopy(se.ref_saved_style, style) end - if ImGui.ShowFontSelector then ImGui.ShowFontSelector("Fonts##Selector") end - local changed - style.FontSizeBase, changed = ImGui.DragFloat("FontSizeBase", style.FontSizeBase, 0.20, 5.0, 100.0, "%.0f") - if changed then style._NextFrameFontSizeBase = style.FontSizeBase end -- FIXME: Temporary hack until we finish remaining work. - ImGui.SameLine(0.0, 0.0); ImGui.Text(" (out %.2f)", ImGui.GetFontSize()) - style.FontScaleMain = ImGui.DragFloat("FontScaleMain", style.FontScaleMain, 0.02, 0.5, 4.0) - ImGui.BeginDisabled(ImGui.GetIO().ConfigDpiScaleFonts == true) - style.FontScaleDpi = ImGui.DragFloat("FontScaleDpi", style.FontScaleDpi, 0.02, 0.5, 4.0) - ImGui.SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.") - ImGui.EndDisabled() - - -- Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0 or 1.0) - style.FrameRounding, changed = ImGui.SliderFloat("FrameRounding", style.FrameRounding, 0.0, 12.0, "%.0f") - if changed then style.GrabRounding = style.FrameRounding end -- Make GrabRounding always the same value as FrameRounding - local p, border - p, border = ImGui.Checkbox("WindowBorder", style.WindowBorderSize > 0.0); if p then style.WindowBorderSize = border and default_border_size or 0.0 end - ImGui.SameLine() - p, border = ImGui.Checkbox("FrameBorder", style.FrameBorderSize > 0.0); if p then style.FrameBorderSize = border and default_border_size or 0.0 end - ImGui.SameLine() - p, border = ImGui.Checkbox("PopupBorder", style.PopupBorderSize > 0.0); if p then style.PopupBorderSize = border and default_border_size or 0.0 end - - -- Save/Revert button - if ImGui.Button("Save Ref") then StyleCopy(se.ref_saved_style, style); if ref ~= se.ref_saved_style then StyleCopy(ref, style) end end - ImGui.SameLine() - if ImGui.Button("Revert Ref") then StyleCopy(style, ref) end - ImGui.SameLine() - HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export\" below to save them somewhere.") - - ImGui.SeparatorText("Details") - if ImGui.BeginTabBar("##tabs", ImGuiTabBarFlags.None) then - if ImGui.BeginTabItem("Sizes") then - ImGui.SeparatorText("Main") - SF2("WindowPadding", 0.0, 20.0); SF2("FramePadding", 0.0, 20.0); SF2("ItemSpacing", 0.0, 20.0) - SF2("ItemInnerSpacing", 0.0, 20.0); SF2("TouchExtraPadding", 0.0, 10.0) - SF("IndentSpacing", 0.0, 30.0); SF("GrabMinSize", 1.0, 20.0) - - ImGui.SeparatorText("Borders") - SF("WindowBorderSize", 0.0, max_border_size); SF("ChildBorderSize", 0.0, max_border_size) - SF("PopupBorderSize", 0.0, max_border_size); SF("FrameBorderSize", 0.0, max_border_size) - - ImGui.SeparatorText("Rounding") - SF("WindowRounding", 0.0, 12.0); SF("ChildRounding", 0.0, 12.0); SF("FrameRounding", 0.0, 12.0) - SF("PopupRounding", 0.0, 12.0); SF("GrabRounding", 0.0, 12.0); SF("MenuItemRounding", 0.0, 12.0) - -- NB: SelectableRounding is intentionally NOT made visible here. We don't want to encourage people using that. - - ImGui.SeparatorText("Scrollbar") - SF("ScrollbarSize", 1.0, 20.0); SF("ScrollbarRounding", 0.0, 12.0); SF("ScrollbarPadding", 0.0, 10.0) - - ImGui.SeparatorText("Tabs") - SF("TabBorderSize", 0.0, max_border_size); SF("TabBarBorderSize", 0.0, max_border_size) - SF("TabBarOverlineSize", 0.0, math.max(3.0, max_border_size)) - ImGui.SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.") - DF("TabMinWidthBase", 0.5, 1.0, 500.0); DF("TabMinWidthShrink", 0.5, 1.0, 500.0, "%0.f") - if style.TabCloseButtonMinWidthSelected ~= nil then - DF("TabCloseButtonMinWidthSelected", 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthSelected < 0.0) and "%.0f (Always)" or "%.0f") - DF("TabCloseButtonMinWidthUnselected", 0.5, -1.0, 100.0, (style.TabCloseButtonMinWidthUnselected < 0.0) and "%.0f (Always)" or "%.0f") - end - SF("TabRounding", 0.0, 12.0) - - ImGui.SeparatorText("Tables") - SF2("CellPadding", 0.0, 20.0) - style.TableAngledHeadersAngle = ImGui.SliderAngle("TableAngledHeadersAngle", style.TableAngledHeadersAngle, -50.0, 50.0) - SF2("TableAngledHeadersTextAlign", 0.0, 1.0, "%.2f") - - ImGui.SeparatorText("Trees") - local combo_open = ImGui.BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)) - ImGui.SameLine() - HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode.") - if combo_open then - local TN = ImGuiTreeNodeFlags - for _, option in ipairs({ TN.DrawLinesNone, TN.DrawLinesFull, TN.DrawLinesToNodes }) do - if ImGui.Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option) then style.TreeLinesFlags = option end - end - ImGui.EndCombo() - end - SF("TreeLinesSize", 0.0, max_border_size); SF("TreeLinesRounding", 0.0, 12.0) - - ImGui.SeparatorText("Windows") - SF2("WindowTitleAlign", 0.0, 1.0, "%.2f"); SF("WindowBorderHoverPadding", 1.0, 20.0) - local window_menu_button_position = style.WindowMenuButtonPosition + 1 - window_menu_button_position, changed = ImGui.Combo("WindowMenuButtonPosition", window_menu_button_position, "None\0Left\0Right\0") - if changed then style.WindowMenuButtonPosition = window_menu_button_position - 1 end - - ImGui.SeparatorText("Widgets") - SF("ColorMarkerSize", 0.0, 8.0) - style.ColorButtonPosition = ImGui.Combo("ColorButtonPosition", style.ColorButtonPosition, "Left\0Right\0") - SF2("ButtonTextAlign", 0.0, 1.0, "%.2f") - ImGui.SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.") - SF2("SelectableTextAlign", 0.0, 1.0, "%.2f") - ImGui.SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.") - SF("SeparatorSize", 0.0, 10.0); SF("SeparatorTextBorderSize", 0.0, 10.0) - SF2("SeparatorTextAlign", 0.0, 1.0, "%.2f"); SF2("SeparatorTextPadding", 0.0, 40.0) - SF("LogSliderDeadzone", 0.0, 12.0); SF("ImageRounding", 0.0, 12.0); SF("ImageBorderSize", 0.0, max_border_size) - - ImGui.SeparatorText("Docking") - -- SetCursorPosX(GetCursorPosX() + CalcItemWidth() - GetFrameHeight()) - _, style.DockingNodeHasCloseButton = ImGui.Checkbox("DockingNodeHasCloseButton", style.DockingNodeHasCloseButton) - SF("DockingSeparatorSize", 0.0, 12.0) - - ImGui.SeparatorText("Tooltips") - for n = 0, 1 do - local key = (n == 0) and "HoverFlagsForTooltipMouse" or "HoverFlagsForTooltipNav" - if ImGui.TreeNodeEx(key) then - for _, f in ipairs({ "DelayNone", "DelayShort", "DelayNormal", "Stationary", "NoSharedDelay" }) do - _, style[key] = ImGui.CheckboxFlags("ImGuiHoveredFlags_" .. f, style[key], ImGuiHoveredFlags[f]) - end - ImGui.TreePop() - end - end - - ImGui.SeparatorText("Misc") - SF2("DisplayWindowPadding", 0.0, 30.0); ImGui.SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.") - SF2("DisplaySafeAreaPadding", 0.0, 30.0); ImGui.SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).") - ImGui.EndTabItem() - end - - if ImGui.BeginTabItem("Colors") then - if ImGui.Button("Export") then - if se.output_dest == 0 then ImGui.LogToClipboard() else ImGui.LogToTTY() end - ImGui.LogText("ImVec4* colors = GetStyle().Colors;\n") - for i = 0, ImGuiCol.COUNT - 1 do - local col = style.Colors[i] - local name = ImGui.GetStyleColorName(i) - if not se.output_only_modified or not ColorsEqual(col, ref.Colors[i]) then - ImGui.LogText("colors[ImGuiCol_%s]%s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);\n", name, string.rep(" ", math.max(0, 23 - #name)), col.x, col.y, col.z, col.w) - end - end - ImGui.LogFinish() - end - ImGui.SameLine(); ImGui.SetNextItemWidth(ImGui.GetFontSize() * 10) - se.output_dest = ImGui.Combo("##output_type", se.output_dest, "To Clipboard\0To TTY\0") - ImGui.SameLine(); _, se.output_only_modified = ImGui.Checkbox("Only Modified Colors", se.output_only_modified) - - local CE = ImGuiColorEditFlags - if ImGui.RadioButtonEx("Opaque", se.alpha_flags == CE.AlphaOpaque) then se.alpha_flags = CE.AlphaOpaque end ImGui.SameLine() - if ImGui.RadioButtonEx("Alpha", se.alpha_flags == CE.None) then se.alpha_flags = CE.None end ImGui.SameLine() - if ImGui.RadioButtonEx("Both", se.alpha_flags == CE.AlphaPreviewHalf) then se.alpha_flags = CE.AlphaPreviewHalf end ImGui.SameLine() - HelpMarker("In the color list:\nLeft-click on color square to open color picker,\nRight-click to open edit options menu.") - - se.filter = se.filter or ImGuiTextFilter() - ImGui.SetNextItemWidth(-FLT_MIN) - se.filter:DrawWithHint("##FilterColors", "Filter Colors (incl -excl)") - - ImGui.SetNextWindowSizeConstraints(ImVec2(0.0, ImGui.GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX)) - ImGui.BeginChild("##colors", ImVec2(0, 0), bit32.bor(ImGuiChildFlags.Borders, ImGuiChildFlags.NavFlattened), bit32.bor(ImGuiWindowFlags.AlwaysVerticalScrollbar, ImGuiWindowFlags.AlwaysHorizontalScrollbar)) - ImGui.PushItemWidth(ImGui.GetFontSize() * -12) - -- [Luau] clipped: only visible rows are submitted (upstream submits every color) - local visible_cols = {} - for i = 0, ImGuiCol.COUNT - 1 do - if se.filter:PassFilter(ImGui.GetStyleColorName(i)) then visible_cols[#visible_cols + 1] = i end - end - local clipper = ImGuiListClipper() - clipper:Begin(#visible_cols) - while clipper:Step() do for row = clipper.DisplayStart, clipper.DisplayEnd - 1 do - local i = visible_cols[row + 1] - local name = ImGui.GetStyleColorName(i) - do - ImGui.PushID(i) - if ImGui.DebugFlashStyleColor then - if ImGui.Button("?") then ImGui.DebugFlashStyleColor(i) end - ImGui.SetItemTooltip("Flash given color to identify places where it is used.") - ImGui.SameLine() - end - ImGui.ColorEdit4("##color", style.Colors[i], bit32.bor(CE.AlphaBar, se.alpha_flags)) - if not ColorsEqual(style.Colors[i], ref.Colors[i]) then - -- Tips: in a real user application, you may want to merge and use an icon font into the main font, - -- so instead of "Save"/"Revert" you'd use icons! - -- Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! - ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Save") then ImVec4_Copy(ref.Colors[i], style.Colors[i]) end - ImGui.SameLine(0.0, style.ItemInnerSpacing.x); if ImGui.Button("Revert") then ImVec4_Copy(style.Colors[i], ref.Colors[i]) end - end - ImGui.SameLine(0.0, style.ItemInnerSpacing.x) - ImGui.TextUnformatted(name) - ImGui.PopID() - end - end end - clipper:End() - ImGui.PopItemWidth() - ImGui.EndChild() - ImGui.EndTabItem() - end - - if ImGui.BeginTabItem("Fonts") then - if ImGui.ShowFontAtlas then ImGui.ShowFontAtlas(ImGui.GetIO().Fonts) else DemoNotPorted("ShowFontAtlas") end - ImGui.EndTabItem() - end - - if ImGui.BeginTabItem("Rendering") then - _, style.AntiAliasedLines = ImGui.Checkbox("Anti-aliased lines", style.AntiAliasedLines) - ImGui.SameLine() - HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.") - ImGui.BeginDisabled(style.AntiAliasedLines == false) - _, style.AntiAliasedLineEnds = ImGui.Checkbox("Anti-aliased line ends", style.AntiAliasedLineEnds) - ImGui.EndDisabled() - _, style.AntiAliasedFill = ImGui.Checkbox("Anti-aliased fill", style.AntiAliasedFill) - local io = ImGui.GetIO() - _, io.ConfigDebugDrawListDefaultsToStrokeLegacy = ImGui.Checkbox("Debug: DrawList Defaults to _StrokeLegacy", io.ConfigDebugDrawListDefaultsToStrokeLegacy == true) - - ImGui.PushItemWidth(ImGui.GetFontSize() * 8) - -- [port] library still stores the pre-1.93 CurveTessellationTol (== MaxError * MaxError) - local curve_err = ImGui.DragFloat("Curve Tessellation Max Error", math.sqrt(style.CurveTessellationTol), 0.02, 0.10, 10.0, "%.2f") - if curve_err < 0.10 then curve_err = 0.10 end - style.CurveTessellationTol = curve_err * curve_err - - -- When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. - style.CircleTessellationMaxError = ImGui.DragFloat("Circle Tessellation Max Error", style.CircleTessellationMaxError, 0.005, 0.10, 5.0, "%.2f", ImGuiSliderFlags.AlwaysClamp) - local show_samples = ImGui.IsItemActive() - if show_samples then ImGui.SetNextWindowPos(ImGui.GetCursorScreenPos()) end - if show_samples and ImGui.BeginTooltip() then - ImGui.TextUnformatted("(R = radius, N = approx number of segments)") - ImGui.Spacing() - local draw_list = ImGui.GetWindowDrawList() - local min_widget_width = ImGui.CalcTextSize("R: MMM\nN: MMM").x - for n = 0, 7 do - local RAD_MIN, RAD_MAX = 5.0, 70.0 - local rad = RAD_MIN + (RAD_MAX - RAD_MIN) * n / (8.0 - 1.0) - ImGui.BeginGroup() - - -- N is not always exact here due to how PathArcTo() function work internally - ImGui.Text("R: %.f\nN: %d", rad, draw_list:_CalcCircleAutoSegmentCount(rad)) - local canvas_width = math.max(min_widget_width, rad * 2.0) - local offset_x = math.floor(canvas_width * 0.5) - local offset_y = math.floor(RAD_MAX) - local p1 = ImGui.GetCursorScreenPos() - draw_list:AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui.GetColorU32(ImGuiCol.Text)) - ImGui.Dummy(ImVec2(canvas_width, RAD_MAX * 2)) - - -- local p2 = ImGui.GetCursorScreenPos() - -- draw_list:AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui.GetColorU32(ImGuiCol.Text)) - -- ImGui.Dummy(ImVec2(canvas_width, RAD_MAX * 2)) - - ImGui.EndGroup() - ImGui.SameLine() - end - ImGui.EndTooltip() - end - ImGui.SameLine() - HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically.") - style.Alpha = ImGui.DragFloat("Global Alpha", style.Alpha, 0.005, 0.20, 1.0, "%.2f") -- Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. - style.DisabledAlpha = ImGui.DragFloat("Disabled Alpha", style.DisabledAlpha, 0.005, 0.0, 1.0, "%.2f") - ImGui.SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).") - ImGui.PopItemWidth() - ImGui.EndTabItem() - end - ImGui.EndTabBar() - end - ImGui.PopItemWidth() -end -end --[[ imgui_demo_widgets.lua ]] - -do --[[ About window ]] --- Demo tools: ShowAboutWindow(), ShowFontAtlas(), ShowFontSelector(), ShowDebugLogWindow(), ShowIDStackToolWindow() -local _ - -------------------------------------------------------------------------------- --- [SECTION] About Window / ShowAboutWindow() --- Access from Dear ImGui Demo -> Tools -> About -------------------------------------------------------------------------------- - -local show_config_info = false -function ImGui.ShowAboutWindow(p_open) - local visible - p_open, visible = ImGui.Begin("About Dear ImGui", p_open, ImGuiWindowFlags.AlwaysAutoResize) - if not visible then ImGui.End(); return p_open end - ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM) - ImGui.TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui"); ImGui.SameLine() - ImGui.TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Extensions", "https://github.com/ocornut/imgui/wiki/Useful-Extensions"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases"); ImGui.SameLine() - ImGui.TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding") - ImGui.Separator() - ImGui.Text("(c) 2014-2026 Omar Cornut") - ImGui.Text("Developed by Omar Cornut and all Dear ImGui contributors.") - ImGui.Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.") - ImGui.Text("If your company uses this, please consider funding the project.") - ImGui.Text("Luau/Roblox port: imgui_impl_roblox (software rasterizer into EditableImage tiles).") - - _, show_config_info = ImGui.Checkbox("Config/Build Information", show_config_info) - if show_config_info then - local io = ImGui.GetIO() - local style = ImGui.GetStyle() - local copy_to_clipboard = ImGui.Button("Copy to clipboard") - local child_size = ImVec2(0, ImGui.GetTextLineHeightWithSpacing() * 18) - ImGui.BeginChild(ImGui.GetID("cfg_infos"), child_size, ImGuiChildFlags.FrameStyle) - if copy_to_clipboard then - ImGui.LogToClipboard() - ImGui.LogText("// (Copy from the next line. Keep the ``` markers for formatting.)\n") - ImGui.LogText("```cpp\n") -- Back quotes will make text appears without formatting when pasting on GitHub - end - ImGui.Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM) - ImGui.Separator() - ImGui.Text("define: IMGUI_HAS_VIEWPORT") - ImGui.Text("define: IMGUI_HAS_DOCK") - ImGui.Text("runtime: Luau (%s)", _VERSION or "?") - ImGui.Separator() - ImGui.Text("io.BackendPlatformName: %s", io.BackendPlatformName or "NULL") - ImGui.Text("io.BackendRendererName: %s", io.BackendRendererName or "NULL") - ImGui.Text("io.ConfigFlags: 0x%08X", io.ConfigFlags) - local CF = ImGuiConfigFlags - for _, n in ipairs({ "NavEnableKeyboard", "NavEnableGamepad", "NoMouse", "NoMouseCursorChange", "NoKeyboard", "DockingEnable", "ViewportsEnable" }) do - if CF[n] and bit32.band(io.ConfigFlags, CF[n]) ~= 0 then ImGui.Text(" %s", n) end - end - for _, n in ipairs({ "MouseDrawCursor", "ConfigDpiScaleFonts", "ConfigDpiScaleViewports", "ConfigViewportsNoAutoMerge", "ConfigViewportsNoTaskBarIcon", - "ConfigViewportsNoDecoration", "ConfigViewportsNoDefaultParent", "ConfigDockingNoSplit", "ConfigDockingNoDockingOver", "ConfigDockingWithShift", - "ConfigDockingAlwaysTabBar", "ConfigDockingTransparentPayload", "ConfigMacOSXBehaviors", "ConfigNavMoveSetMousePos", "ConfigNavCaptureKeyboard", - "ConfigInputTextCursorBlink", "ConfigWindowsResizeFromEdges", "ConfigWindowsMoveFromTitleBarOnly" }) do - if io[n] == true then ImGui.Text("io.%s", n) end - end - if (io.ConfigMemoryCompactTimer or -1) >= 0.0 then ImGui.Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer) end - ImGui.Text("io.BackendFlags: 0x%08X", io.BackendFlags) - local BF = ImGuiBackendFlags - for _, n in ipairs({ "HasGamepad", "HasMouseCursors", "HasSetMousePos", "PlatformHasViewports", "HasMouseHoveredViewport", "HasParentViewport", - "RendererHasVtxOffset", "RendererHasTextures", "RendererHasViewports" }) do - if BF[n] and bit32.band(io.BackendFlags, BF[n]) ~= 0 then ImGui.Text(" %s", n) end - end - ImGui.Separator() - local atlas = io.Fonts - ImGui.Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", atlas.Fonts.Size, atlas.Flags or 0, atlas.TexData and atlas.TexData.Width or 0, atlas.TexData and atlas.TexData.Height or 0) - ImGui.Text("io.Fonts->FontLoaderName: %s", atlas.FontLoaderName or "NULL") - ImGui.Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y) - ImGui.Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y) - ImGui.Separator() - ImGui.Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y) - ImGui.Text("style.WindowBorderSize: %.2f", style.WindowBorderSize) - ImGui.Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y) - ImGui.Text("style.FrameRounding: %.2f", style.FrameRounding) - ImGui.Text("style.FrameBorderSize: %.2f", style.FrameBorderSize) - ImGui.Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y) - ImGui.Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y) - if copy_to_clipboard then - ImGui.LogText("\n```\n") - ImGui.LogFinish() - end - ImGui.EndChild() - end +function ShowExampleAppAssetsBrowser(p_open) + IMGUI_DEMO_MARKER("Examples/Assets Browser") + -- [Port] TODO: ExampleAssetsBrowser needs BeginMultiSelect()/box-select + local open, visible = ImGui.Begin("Example: Assets Browser", p_open) + if visible then ImGui.TextDisabled("(multi-select API not ported yet)") end ImGui.End() - return p_open + return open end -end --[[ About window ]] return true diff --git a/imgui_h.lua b/imgui_h.lua index 3018c9f..13154cd 100644 --- a/imgui_h.lua +++ b/imgui_h.lua @@ -2653,6 +2653,32 @@ function ImGuiTextBufferMT:appendf(fmt, ...) self.Buf[#self.Buf + 1] = string.fo function ImGuiTextBufferMT:c_str() return table.concat(self.Buf) end function ImGuiTextBufferMT:size() return #self:c_str() end +-- Helpers: ImColor() implicitly converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float) +-- Prefer using IM_COL32() macros. Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. +-- **None of the ImGui API are using ImColor directly but you can use it as a convenience to pass colors in either ImU32 or ImVec4 formats. Explicitly cast to ImU32 or ImVec4 if needed. +-- [Luau] no implicit conversions: use :U32() / .Value (ImVec4). Overloads: ImColor(), ImColor(r, g, b, a) floats, +-- ImColor(ImVec4), ImColor(ImU32). The C++ int (0-255) overload can't be told apart from floats: use ImColor(IM_COL32(r, g, b, a)). +--- @class ImColor +local ImColorMT = {} +ImColorMT.__index = ImColorMT +ImColor = setmetatable({}, { __call = function(_, r, g, b, a) + local self = setmetatable({ Value = ImVec4() }, ImColorMT) + if type(r) == "table" then + ImVec4_Copy(self.Value, r) + elseif r ~= nil and g == nil then + local s = 1.0 / 255.0 + self.Value.x = bit32.band(bit32.rshift(r, IM_COL32_R_SHIFT), 0xFF) * s; self.Value.y = bit32.band(bit32.rshift(r, IM_COL32_G_SHIFT), 0xFF) * s + self.Value.z = bit32.band(bit32.rshift(r, IM_COL32_B_SHIFT), 0xFF) * s; self.Value.w = bit32.band(bit32.rshift(r, IM_COL32_A_SHIFT), 0xFF) * s + elseif r ~= nil then + self.Value.x = r; self.Value.y = g; self.Value.z = b; self.Value.w = a or 1.0 + end + return self +end }) +function ImColorMT:U32() return ImGui.ColorConvertFloat4ToU32(self.Value) end +-- FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. +function ImColorMT:SetHSV(h, s, v, a) self.Value.x, self.Value.y, self.Value.z = ImGui.ColorConvertHSVtoRGB(h, s, v); self.Value.w = a or 1.0 end +function ImColor.HSV(h, s, v, a) local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v); return ImColor(r, g, b, a or 1.0) end + --- @class ImGuiSettingsHandler --- Fns take (ctx, handler, ...) like upstream. ReadOpenFn(ctx, handler, name) returns entry; ReadLineFn(ctx, handler, entry, line); --- WriteAllFn(ctx, handler, buf: ImGuiTextBuffer) diff --git a/tools/test/love/run.sh b/tools/test/love/run.sh index f63778c..718e21e 100755 --- a/tools/test/love/run.sh +++ b/tools/test/love/run.sh @@ -4,4 +4,4 @@ set -e cd "$(dirname "$0")/../../.." python3 tools/bundle.py --target love >/dev/null nix-shell -p luajit --run "luajit tools/test/love/t_drawhash.lua 150 Widgets,Basic && luajit tools/test/love/t_drawhash.lua 150 all && luajit tools/test/love/t_examples.lua" -echo "expected (Luau, tools/test/scripts/t_drawhash.luau): 1385106188 / 1292122782" +echo "expected (Luau, tools/test/scripts/t_drawhash.luau): 379637274 / 1789163281" diff --git a/tools/test/scripts/t_apps.luau b/tools/test/scripts/t_apps.luau index 3bfb2d8..34a57c7 100644 --- a/tools/test/scripts/t_apps.luau +++ b/tools/test/scripts/t_apps.luau @@ -7,7 +7,7 @@ io.ConfigFlags = bit32.bor(io.ConfigFlags, G.ImGuiConfigFlags.DockingEnable) G.ImGui_ImplRoblox.Init() local names = { "ShowExampleAppConsole", "ShowExampleAppLog", "ShowExampleAppLayout", "ShowExampleAppPropertyEditor", "ShowExampleAppLongText", "ShowExampleAppAutoResize", "ShowExampleAppConstrainedResize", "ShowExampleAppSimpleOverlay", "ShowExampleAppWindowTitles", - "ShowExampleAppCustomRendering", "ShowExampleAppDocuments", "ShowExampleAppDockSpace", "ShowExampleAppFullscreen", "ShowExampleAppAssetsBrowser", "ShowExampleAppMainMenuBar" } + "ShowExampleAppCustomRendering", "ShowExampleAppDocuments", "ShowExampleAppDockSpace", "ShowExampleAppFullscreen", "ShowExampleAppAssetsBrowser", "ShowExampleAppMainMenuBar", "ShowExampleAppImageViewer" } local tools = { "ShowMetricsWindow", "ShowDebugLogWindow", "ShowIDStackToolWindow", "ShowAboutWindow" } local open = {} local frame = 0